diff --git a/i3lock.1 b/i3lock.1 index e97ad15..41b2b92 100644 --- a/i3lock.1 +++ b/i3lock.1 @@ -108,9 +108,9 @@ You can also use it to resize images to the screen ratio: Note that $(xdpyinfo | grep dimensions | sed -r 's/^[^0-9]*([0-9]+x[0-9]+).*$/\1/') gets you the current screen dimensions in the wxh (e.g. 1920x1080) format. .TP -.BI \-c\ rrggbb \fR,\ \fB\-\-color= rrggbb -Turn the screen into the given color instead of white. Color must be given in 3-byte -format: rrggbb (i.e. ff0000 is red). +.BI \-c\ rrggbbaa \fR,\ \fB\-\-color= rrggbbaa +Turn the screen into the given color instead of white. Color must be given in 4-byte +format: rrggbbaa (i.e. ff0000ff is opaque red). .TP .B \-t, \-\-tiling diff --git a/i3lock.c b/i3lock.c index 1059e1f..38b5f90 100644 --- a/i3lock.c +++ b/i3lock.c @@ -70,7 +70,7 @@ typedef void (*ev_callback_t)(EV_P_ ev_timer *w, int revents); static void input_done(void); -char color[7] = "ffffff"; +char color[9] = "ffffffff"; /* options for unlock indicator colors */ char insidevercolor[9] = "006effbf"; @@ -1497,6 +1497,13 @@ int main(int argc, char *argv[]) { char *optstring = "hvnbdc:p:ui:teI:frsS:kB:m"; char *arg = NULL; int opt = 0; + +#define parse_color(acolor)\ + arg = optarg;\ + if (arg[0] == '#') arg++;\ + if (strlen(arg) != 8 || sscanf(arg, "%08[0-9a-fA-F]", acolor) != 1)\ + errx(1, #acolor " is invalid, color must be given in 4-byte format: rrggbbaa\n"); + while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) { switch (o) { case 'v': @@ -1514,18 +1521,6 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Inactivity timeout only makes sense with DPMS, which was removed. Please see the manpage i3lock(1).\n"); break; } - case 'c': { - arg = optarg; - - /* Skip # if present */ - if (arg[0] == '#') - arg++; - - if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1) - errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb"); - - break; - } case 'u': unlock_indicator = false; break; @@ -1575,11 +1570,9 @@ int main(int argc, char *argv[]) { break; // Begin colors - #define parse_color(color)\ - arg = optarg;\ - if (arg[0] == '#') arg++;\ - if (strlen(arg) != 8 || sscanf(arg, "%08[0-9a-fA-F]", color) != 1)\ - errx(1, #color " is invalid, color must be given in 4-byte format: rrggbbaa\n"); + case 'c': + parse_color(color); + break; case 300: parse_color(insidevercolor); break; @@ -2206,14 +2199,16 @@ int main(int argc, char *argv[]) { cairo_surface_destroy(xcb_img); } - /* Pixmap on which the image is rendered to (if any) */ - xcb_pixmap_t bg_pixmap = draw_image(last_resolution); - xcb_window_t stolen_focus = find_focused_window(conn, screen->root); /* 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); + win = open_fullscreen_window(conn, screen, color); + + xcb_pixmap_t pixmap = create_bg_pixmap(conn, win, last_resolution, color); + draw_image(last_resolution, pixmap); + xcb_change_window_attributes(conn, win, XCB_CW_BACK_PIXMAP, (uint32_t[]){pixmap}); + + xcb_free_pixmap(conn, pixmap); if (blur_pixmap) { xcb_free_pixmap(conn, *blur_pixmap); free(blur_pixmap); diff --git a/unlock_indicator.c b/unlock_indicator.c index 73bf7da..6124358 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -71,7 +71,7 @@ unsigned long lastCheck; /* Whether the image should be tiled. */ extern bool tile; /* The background color to use (in hex). */ -extern char color[7]; +extern char color[9]; /* indicator color options */ extern char insidevercolor[9]; extern char insidewrongcolor[9]; @@ -675,7 +675,7 @@ static void draw_elements(cairo_t *const ctx, DrawData const *const draw_data) { * resolution and returns it. * */ -xcb_pixmap_t draw_image(uint32_t *resolution) { +void draw_image(uint32_t *resolution, xcb_drawable_t drawable) { const double scaling_factor = get_dpi_value() / 96.0; xcb_pixmap_t bg_pixmap = XCB_NONE; int button_diameter_physical = ceil(scaling_factor * BUTTON_DIAMETER); @@ -683,7 +683,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { scaling_factor, button_diameter_physical); if (!vistype) - vistype = get_root_visual_type(screen); + vistype = get_visualtype_by_depth(32, screen); bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); /* Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, @@ -696,7 +696,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { // cairo_set_font_face(ctx, get_font_face(0)); - cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); + cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, drawable, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); /*update image according to the slideshow_interval*/ @@ -1073,12 +1073,11 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { */ void redraw_screen(void) { DEBUG("redraw_screen(unlock_state = %d, auth_state = %d) @ [%lu]\n", unlock_state, auth_state, (unsigned long)time(NULL)); - xcb_pixmap_t bg_pixmap = draw_image(last_resolution); - xcb_change_window_attributes(conn, win, XCB_CW_BACK_PIXMAP, (uint32_t[1]){bg_pixmap}); - /* XXX: Possible optimization: Only update the area in the middle of the - * screen instead of the whole screen. */ + xcb_pixmap_t pixmap = create_bg_pixmap(conn, win, last_resolution, color); + draw_image(last_resolution, pixmap); + xcb_change_window_attributes(conn, win, XCB_CW_BACK_PIXMAP, (uint32_t[1]){pixmap}); xcb_clear_area(conn, 0, win, 0, 0, last_resolution[0], last_resolution[1]); - xcb_free_pixmap(conn, bg_pixmap); + xcb_free_pixmap(conn, pixmap); xcb_flush(conn); } diff --git a/unlock_indicator.h b/unlock_indicator.h index 885e951..05851d5 100644 --- a/unlock_indicator.h +++ b/unlock_indicator.h @@ -38,7 +38,7 @@ typedef struct { double bar_offset; } DrawData; -xcb_pixmap_t draw_image(uint32_t* resolution); +void draw_image(uint32_t* resolution, xcb_drawable_t drawable); void init_colors_once(void); void redraw_screen(void); void clear_indicator(void); diff --git a/xcb.c b/xcb.c index 4f2390c..9117cb5 100644 --- a/xcb.c +++ b/xcb.c @@ -82,16 +82,37 @@ static unsigned char mask_windows_bits[] = { 0x80, 0x01}; static uint32_t get_colorpixel(char *hex) { - char strgroups[3][3] = {{hex[0], hex[1], '\0'}, + char strgroups[4][3] = {{hex[0], hex[1], '\0'}, {hex[2], hex[3], '\0'}, - {hex[4], hex[5], '\0'}}; - uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), + {hex[4], hex[5], '\0'}, + {hex[6], hex[4], '\0'}}; + uint32_t rgb16[4] = {(strtol(strgroups[0], NULL, 16)), (strtol(strgroups[1], NULL, 16)), - (strtol(strgroups[2], NULL, 16))}; + (strtol(strgroups[2], NULL, 16)), + (strtol(strgroups[3], NULL, 16))}; - return (rgb16[0] << 16) + (rgb16[1] << 8) + rgb16[2]; + return (rgb16[3] << 24) + (rgb16[0] << 16) + (rgb16[1] << 8) + rgb16[2]; } +xcb_visualtype_t *get_visualtype_by_depth(uint16_t depth, xcb_screen_t *root_screen) { + xcb_depth_iterator_t depth_iter; + + depth_iter = xcb_screen_allowed_depths_iterator(root_screen); + for (; depth_iter.rem; xcb_depth_next(&depth_iter)) { + if (depth_iter.data->depth != depth) + continue; + + xcb_visualtype_iterator_t visual_iter; + + visual_iter = xcb_depth_visuals_iterator(depth_iter.data); + if (!visual_iter.rem) + continue; + return visual_iter.data; + } + return NULL; +} + + xcb_visualtype_t *get_root_visual_type(xcb_screen_t *screen) { xcb_visualtype_t *visual_type = NULL; xcb_depth_iterator_t depth_iter; @@ -114,10 +135,9 @@ xcb_visualtype_t *get_root_visual_type(xcb_screen_t *screen) { return NULL; } -xcb_pixmap_t create_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, u_int32_t *resolution, char *color) { +xcb_pixmap_t create_bg_pixmap(xcb_connection_t *conn, xcb_drawable_t win, u_int32_t *resolution, char *color) { 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_create_pixmap(conn, 32, bg_pixmap, win, resolution[0], resolution[1]); /* Generate a Graphics Context and fill the pixmap with background color * (for images that are smaller than your screen) */ @@ -131,9 +151,9 @@ xcb_pixmap_t create_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, u_int32 return bg_pixmap; } -xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color, xcb_pixmap_t pixmap) { +xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color) { uint32_t mask = 0; - uint32_t values[3]; + uint32_t values[5]; xcb_window_t win = xcb_generate_id(conn); xcb_window_t parent_win = scr->root; @@ -161,26 +181,32 @@ xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, c } } - if (pixmap == XCB_NONE) { - mask |= XCB_CW_BACK_PIXEL; - values[0] = get_colorpixel(color); - } else { - mask |= XCB_CW_BACK_PIXMAP; - values[0] = pixmap; - } + + xcb_visualid_t visual = get_visualtype_by_depth(32, scr)->visual_id; + xcb_colormap_t win_colormap = xcb_generate_id(conn); + xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, win_colormap, scr->root, visual); + + mask |= XCB_CW_BACK_PIXEL; + values[0] = get_colorpixel(color); + + mask |= XCB_CW_BORDER_PIXEL; + values[1] = 0x00000000; mask |= XCB_CW_OVERRIDE_REDIRECT; - values[1] = 1; + values[2] = 1; mask |= XCB_CW_EVENT_MASK; - values[2] = XCB_EVENT_MASK_EXPOSURE | + values[3] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_VISIBILITY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY; + mask |= XCB_CW_COLORMAP; + values[4] = win_colormap; + xcb_create_window(conn, - XCB_COPY_FROM_PARENT, + 32, win, /* the window id */ parent_win, 0, 0, @@ -188,7 +214,7 @@ xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, c scr->height_in_pixels, /* dimensions */ 0, /* border = 0, we draw our own */ XCB_WINDOW_CLASS_INPUT_OUTPUT, - XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ + visual, /* copy visual from parent */ mask, values); diff --git a/xcb.h b/xcb.h index a219aae..e127914 100644 --- a/xcb.h +++ b/xcb.h @@ -24,8 +24,9 @@ extern xcb_connection_t *conn; extern xcb_screen_t *screen; xcb_visualtype_t *get_root_visual_type(xcb_screen_t *s); -xcb_pixmap_t create_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, u_int32_t *resolution, char *color); -xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color, xcb_pixmap_t pixmap); +xcb_visualtype_t* get_visualtype_by_depth(uint16_t depth, xcb_screen_t* root_screen); +xcb_pixmap_t create_bg_pixmap(xcb_connection_t *conn, xcb_drawable_t drawable, u_int32_t *resolution, char *color); +xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color); bool grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb_cursor_t cursor, int tries); xcb_cursor_t create_cursor(xcb_connection_t *conn, xcb_screen_t *screen, xcb_window_t win, int choice); xcb_window_t find_focused_window(xcb_connection_t *conn, const xcb_window_t root);