diff --git a/i3lock.c b/i3lock.c index 27144cb..a32d5b5 100644 --- a/i3lock.c +++ b/i3lock.c @@ -48,7 +48,6 @@ static bool beep = false; #ifndef NOLIBCAIRO static cairo_surface_t *img = NULL; -static cairo_t *ctx = NULL; static bool tile = false; #endif @@ -71,31 +70,6 @@ static void input_done() { } } -/* - * Called when we should draw the image (if any). - * - */ -static void handle_expose_event() { -#ifndef NOLIBCAIRO - if (!ctx) - return; - - if (tile) { - /* create a pattern and fill a rectangle as big as the screen */ - cairo_pattern_t *pattern; - pattern = cairo_pattern_create_for_surface(img); - cairo_set_source(ctx, pattern); - cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - cairo_rectangle(ctx, 0, 0, scr->width_in_pixels, scr->height_in_pixels); - cairo_fill(ctx); - } else { - /* otherwise, just paint the image */ - cairo_paint(ctx); - } -#endif - xcb_flush(conn); -} - /* * Called when the user releases a key. We need to leave the Mode_switch * state when the user releases the Mode_switch key. @@ -388,10 +362,39 @@ int main(int argc, char *argv[]) { scr = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; vistype = get_root_visual_type(scr); - /* open the fullscreen window and flush immediately afterwards so that X11 - * can generate an expose event while we load the PNG file (so that we are - * ready to handle the expose event immediately afterwards) */ - win = open_fullscreen_window(conn, scr, color); + /* Pixmap on which the image is rendered to (if any) */ + xcb_pixmap_t bg_pixmap = XCB_NONE; + +#ifndef NOLIBCAIRO + if (image_path) { + bg_pixmap = create_bg_pixmap(conn, scr, color); + /* Create a pixmap to render on, fill it with the background color */ + img = cairo_image_surface_create_from_png(image_path); + } + + if (img) { + /* Initialize cairo */ + cairo_surface_t *output; + output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, + scr->width_in_pixels, scr->height_in_pixels); + cairo_t *ctx = cairo_create(output); + if (!tile) { + cairo_set_source_surface(ctx, img, 0, 0); + cairo_paint(ctx); + } else { + /* create a pattern and fill a rectangle as big as the screen */ + cairo_pattern_t *pattern; + pattern = cairo_pattern_create_for_surface(img); + cairo_set_source(ctx, pattern); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + cairo_rectangle(ctx, 0, 0, scr->width_in_pixels, scr->height_in_pixels); + cairo_fill(ctx); + } + } +#endif + + /* open the fullscreen window, already with the correct pixmap in place */ + win = open_fullscreen_window(conn, scr, color, bg_pixmap); cursor = create_cursor(conn, scr, win, curs_choice); @@ -401,23 +404,6 @@ int main(int argc, char *argv[]) { modeswitchmask = get_mod_mask(conn, symbols, XK_Mode_switch); numlockmask = get_mod_mask(conn, symbols, XK_Num_Lock); -#ifndef NOLIBCAIRO - if (image_path) - img = cairo_image_surface_create_from_png(image_path); - - if (img) { - /* Initialize cairo */ - cairo_surface_t *output; - output = cairo_xcb_surface_create(conn, win, vistype, - scr->width_in_pixels, scr->height_in_pixels); - ctx = cairo_create(output); - if (!tile) - cairo_set_source_surface(ctx, img, 0, 0); - - handle_expose_event(); - } -#endif - if (dpms) dpms_turn_off_screen(conn); @@ -428,11 +414,6 @@ int main(int argc, char *argv[]) { /* Strip off the highest bit (set if the event is generated) */ int type = (event->response_type & 0x7F); - if (type == XCB_EXPOSE) { - handle_expose_event(); - continue; - } - if (type == XCB_KEY_PRESS) { handle_key_press((xcb_key_press_event_t*)event); continue; diff --git a/xcb.c b/xcb.c index 32077e1..818bf75 100644 --- a/xcb.c +++ b/xcb.c @@ -78,13 +78,34 @@ xcb_visualtype_t *get_root_visual_type(xcb_screen_t *screen) { return NULL; } -xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color) { +xcb_pixmap_t create_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, char *color) { + xcb_pixmap_t bg_pixmap = xcb_generate_id(conn); + xcb_create_pixmap(conn, scr->root_depth, bg_pixmap, scr->root, + scr->width_in_pixels, scr->height_in_pixels); + + /* Generate a Graphics Context and fill the pixmap with background color + * (for images that are smaller than your screen) */ + xcb_gcontext_t gc = xcb_generate_id(conn); + uint32_t values[] = { get_colorpixel(color) }; + xcb_create_gc(conn, gc, bg_pixmap, XCB_GC_FOREGROUND, values); + xcb_rectangle_t rect = { 0, 0, scr->width_in_pixels, scr->height_in_pixels }; + xcb_poly_fill_rectangle(conn, bg_pixmap, gc, 1, &rect); + + return bg_pixmap; +} + +xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color, xcb_pixmap_t pixmap) { uint32_t mask = 0; uint32_t values[3]; xcb_window_t win = xcb_generate_id(conn); - mask |= XCB_CW_BACK_PIXEL; - values[0] = get_colorpixel(color); + if (pixmap == XCB_NONE) { + mask |= XCB_CW_BACK_PIXEL; + values[0] = get_colorpixel(color); + } else { + mask |= XCB_CW_BACK_PIXMAP; + values[0] = pixmap; + } mask |= XCB_CW_OVERRIDE_REDIRECT; values[1] = 1; diff --git a/xcb.h b/xcb.h index bae51b2..3c6469e 100644 --- a/xcb.h +++ b/xcb.h @@ -4,7 +4,8 @@ #include xcb_visualtype_t *get_root_visual_type(xcb_screen_t *s); -xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color); +xcb_pixmap_t create_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, char *color); +xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color, xcb_pixmap_t pixmap); void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb_cursor_t cursor); uint32_t get_mod_mask(xcb_connection_t *conn, xcb_key_symbols_t *symbols, uint32_t keycode); void dpms_turn_off_screen(xcb_connection_t *conn);