i3lock-color

The world's most popular non-default computer lockscreen.
Index Commits Files Refs README LICENSE
commit c3a95b86d6d89bd00e526214a85855629d92521e
parent ef003b76c22c7c99602c1cd5fe71317fb4605697
Author: Chris Guillott <chris@techfo.xyz>
Date:   Fri, 14 Oct 2016 22:06:43 -0400

add initial blur support

thanks to https://github.com/shiver/i3lock

Diffstat:
Ablur.c | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ablur.h | 7+++++++
Mi3lock.c | 34+++++++++++++++++++++++++++++++++-
Mlock.sh | 4+++-
Mxcb.c | 14++++++++++++++
Mxcb.h | 1+
6 files changed, 201 insertions(+), 2 deletions(-)
diff --git a/blur.c b/blur.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <cairo.h>
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+/* Performs a simple 2D Gaussian blur of radius @radius on surface @surface. */
+void
+blur_image_surface (cairo_surface_t *surface, int radius)
+{
+    cairo_surface_t *tmp;
+    int width, height;
+    int src_stride, dst_stride;
+    int x, y, z, w;
+    uint8_t *src, *dst;
+    uint32_t *s, *d, a, p;
+    int i, j, k;
+    uint8_t kernel[17];
+    const int size = ARRAY_LENGTH (kernel);
+    const int half = size / 2;
+
+    if (cairo_surface_status (surface))
+    return;
+
+    width = cairo_image_surface_get_width (surface);
+    height = cairo_image_surface_get_height (surface);
+
+    switch (cairo_image_surface_get_format (surface)) {
+    case CAIRO_FORMAT_A1:
+    default:
+    /* Don't even think about it! */
+    return;
+
+    case CAIRO_FORMAT_A8:
+    /* Handle a8 surfaces by effectively unrolling the loops by a
+     * factor of 4 - this is safe since we know that stride has to be a
+     * multiple of uint32_t. */
+    width /= 4;
+    break;
+
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_ARGB32:
+    break;
+    }
+
+    tmp = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+    if (cairo_surface_status (tmp))
+    return;
+
+    src = cairo_image_surface_get_data (surface);
+    src_stride = cairo_image_surface_get_stride (surface);
+
+    dst = cairo_image_surface_get_data (tmp);
+    dst_stride = cairo_image_surface_get_stride (tmp);
+
+    a = 0;
+    for (i = 0; i < size; i++) {
+    double f = i - half;
+    a += kernel[i] = exp (- f * f / 30.0) * 80;
+    }
+
+    /* Horizontally blur from surface -> tmp */
+    for (i = 0; i < height; i++) {
+    s = (uint32_t *) (src + i * src_stride);
+    d = (uint32_t *) (dst + i * dst_stride);
+    for (j = 0; j < width; j++) {
+        if (radius < j && j < width - radius) {
+        d[j] = s[j];
+        continue;
+        }
+
+        x = y = z = w = 0;
+        for (k = 0; k < size; k++) {
+        if (j - half + k < 0 || j - half + k >= width)
+            continue;
+
+        p = s[j - half + k];
+
+        x += ((p >> 24) & 0xff) * kernel[k];
+        y += ((p >> 16) & 0xff) * kernel[k];
+        z += ((p >>  8) & 0xff) * kernel[k];
+        w += ((p >>  0) & 0xff) * kernel[k];
+        }
+        d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
+    }
+    }
+
+    /* Then vertically blur from tmp -> surface */
+    for (i = 0; i < height; i++) {
+    s = (uint32_t *) (dst + i * dst_stride);
+    d = (uint32_t *) (src + i * src_stride);
+    for (j = 0; j < width; j++) {
+        if (radius <= i && i < height - radius) {
+        d[j] = s[j];
+        continue;
+        }
+
+        x = y = z = w = 0;
+        for (k = 0; k < size; k++) {
+        if (i - half + k < 0 || i - half + k >= height)
+            continue;
+
+        s = (uint32_t *) (dst + (i - half + k) * dst_stride);
+        p = s[j];
+
+        x += ((p >> 24) & 0xff) * kernel[k];
+        y += ((p >> 16) & 0xff) * kernel[k];
+        z += ((p >>  8) & 0xff) * kernel[k];
+        w += ((p >>  0) & 0xff) * kernel[k];
+        }
+        d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
+    }
+    }
+
+    cairo_surface_destroy (tmp);
+    cairo_surface_flush (surface);
+    cairo_surface_mark_dirty (surface);
+}
+
diff --git a/blur.h b/blur.h
@@ -0,0 +1,7 @@
+#ifndef _BLUR_H
+#define _BLUR_H
+
+void blur_image_surface (cairo_surface_t *surface, int radius);
+
+#endif
+
diff --git a/i3lock.c b/i3lock.c
@@ -36,6 +36,7 @@
 #include "cursors.h"
 #include "unlock_indicator.h"
 #include "xinerama.h"
+#include "blur.h"
 
 #define TSTAMP_N_SECS(n) (n * 1.0)
 #define TSTAMP_N_MINS(n) (60 * TSTAMP_N_SECS(n))
@@ -75,6 +76,10 @@ bool show_clock = false;
 char time_format[32] = "%H:%M:%S\0";
 char date_format[32] = "%A, %m %Y\0";
 
+/* opts for blurring */
+bool blur = false;
+bool step_blur = false;
+int blur_radius = 5;
 
 uint32_t last_resolution[2];
 xcb_window_t win;
@@ -861,6 +866,8 @@ int main(int argc, char *argv[]) {
         {"timestr", required_argument, NULL, 0},
         {"datestr", required_argument, NULL, 0},
 
+        {"blur", no_argument, NULL, 'B'},
+
         {"ignore-empty-password", no_argument, NULL, 'e'},
         {"inactivity-timeout", required_argument, NULL, 'I'},
         {"show-failed-attempts", no_argument, NULL, 'f'},
@@ -871,7 +878,7 @@ int main(int argc, char *argv[]) {
     if ((username = pw->pw_name) == NULL)
         errx(EXIT_FAILURE, "pw->pw_name is NULL.\n");
 
-    char *optstring = "hvnbdc:p:ui:teI:frsS:k";
+    char *optstring = "hvnbdc:p:ui:teI:frsS:kB";
     while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) {
         switch (o) {
             case 'v':
@@ -941,6 +948,9 @@ int main(int argc, char *argv[]) {
             case 'k':
                 show_clock = true;
                 break;
+            case 'B':
+                blur = true;
+                break;
             case 0:
                 if (strcmp(longopts[optind].name, "debug") == 0)
                     debug_mode = true;
@@ -1182,12 +1192,34 @@ int main(int argc, char *argv[]) {
         free(image_path);
     }
 
+    xcb_pixmap_t blur_pixmap;
+    if (blur) {
+        if(!img) {
+            xcb_visualtype_t *vistype = get_root_visual_type(screen);
+            blur_pixmap = capture_bg_pixmap(conn, screen, last_resolution);
+            cairo_surface_t *xcb_img = cairo_xcb_surface_create(conn, blur_pixmap, vistype, last_resolution[0], last_resolution[1]);
+
+            img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, last_resolution[0], last_resolution[1]);
+            cairo_t *ctx = cairo_create(img);
+            cairo_set_source_surface(ctx, xcb_img, 0, 0);
+            cairo_paint(ctx);
+
+            cairo_destroy(ctx);
+            cairo_surface_destroy(xcb_img);
+        }
+        blur_image_surface(img, 10000);
+    }
+
     /* Pixmap on which the image is rendered to (if any) */
     xcb_pixmap_t bg_pixmap = draw_image(last_resolution);
 
     /* Open the fullscreen window, already with the correct pixmap in place */
     win = open_fullscreen_window(conn, screen, color, bg_pixmap);
     xcb_free_pixmap(conn, bg_pixmap);
+    if (blur_pixmap) {
+        xcb_free_pixmap(conn, blur_pixmap);
+    }
+
 
     cursor = create_cursor(conn, screen, win, curs_choice);
 
diff --git a/lock.sh b/lock.sh
@@ -35,4 +35,6 @@ V='#bb00bbbb'  # verifying
 --screen 0            \
 --clock               \
 --timestr="%H:%M:%S"  \
---datestr="%A, %m %Y" 
+--datestr="%A, %m %Y" \
+-B                    \
+
diff --git a/xcb.c b/xcb.c
@@ -307,3 +307,17 @@ xcb_cursor_t create_cursor(xcb_connection_t *conn, xcb_screen_t *screen, xcb_win
 
     return cursor;
 }
+
+xcb_pixmap_t capture_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, u_int32_t * resolution) {
+    xcb_pixmap_t bg_pixmap = xcb_generate_id(conn);
+    xcb_create_pixmap(conn, scr->root_depth, bg_pixmap, scr->root, resolution[0], resolution[1]);
+    xcb_gcontext_t gc = xcb_generate_id(conn);
+    uint32_t values[] = { scr->black_pixel, 1};
+    xcb_create_gc(conn, gc, bg_pixmap, XCB_GC_FOREGROUND | XCB_GC_SUBWINDOW_MODE, values);
+    xcb_rectangle_t rect = { 0, 0, resolution[0], resolution[1] };
+    xcb_poly_fill_rectangle(conn, bg_pixmap, gc, 1, &rect);
+    xcb_copy_area(conn, scr->root, bg_pixmap, gc, 0, 0, 0, 0, resolution[0], resolution[1]);
+    xcb_flush(conn);
+    xcb_free_gc(conn, gc);
+    return bg_pixmap;
+}
diff --git a/xcb.h b/xcb.h
@@ -13,5 +13,6 @@ xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, c
 void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb_cursor_t cursor);
 void dpms_set_mode(xcb_connection_t *conn, xcb_dpms_dpms_mode_t mode);
 xcb_cursor_t create_cursor(xcb_connection_t *conn, xcb_screen_t *screen, xcb_window_t win, int choice);
+xcb_pixmap_t capture_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, u_int32_t* resolution);
 
 #endif