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:
| A | blur.c | | | 143 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | blur.h | | | 7 | +++++++ |
| M | i3lock.c | | | 34 | +++++++++++++++++++++++++++++++++- |
| M | lock.sh | | | 4 | +++- |
| M | xcb.c | | | 14 | ++++++++++++++ |
| M | xcb.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