]> git.sur5r.net Git - i3/i3lock/commitdiff
optimization: render to pixmap which is used as background for the window
authorMichael Stapelberg <michael@stapelberg.de>
Sat, 2 Apr 2011 17:49:38 +0000 (19:49 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sat, 2 Apr 2011 17:49:38 +0000 (19:49 +0200)
Before this commit, the background color (white by default) was visible for
about 100ms until the image was drawn. This flickering is now eliminated.

Also, we don’t need to handle Expose-events anymore, as X11 will use the
window’s background pixmap automatically.

i3lock.c
xcb.c
xcb.h

index 27144cb3cc5f833540786735f6f1b2c7bcf1fb3a..a32d5b5d96dc4ccbb77cc8cb96b7b8dea238edb8 100644 (file)
--- 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,36 +362,48 @@ 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);
-
-    cursor = create_cursor(conn, scr, win, curs_choice);
-
-    grab_pointer_and_keyboard(conn, scr, cursor);
-
-    symbols = xcb_key_symbols_alloc(conn);
-    modeswitchmask = get_mod_mask(conn, symbols, XK_Mode_switch);
-    numlockmask = get_mod_mask(conn, symbols, XK_Num_Lock);
+    /* Pixmap on which the image is rendered to (if any) */
+    xcb_pixmap_t bg_pixmap = XCB_NONE;
 
 #ifndef NOLIBCAIRO
-    if (image_path)
+    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, win, vistype,
+        output = cairo_xcb_surface_create(conn, bg_pixmap, vistype,
                  scr->width_in_pixels, scr->height_in_pixels);
-        ctx = cairo_create(output);
-        if (!tile)
+        cairo_t *ctx = cairo_create(output);
+        if (!tile) {
             cairo_set_source_surface(ctx, img, 0, 0);
-
-        handle_expose_event();
+            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);
+
+    grab_pointer_and_keyboard(conn, scr, cursor);
+
+    symbols = xcb_key_symbols_alloc(conn);
+    modeswitchmask = get_mod_mask(conn, symbols, XK_Mode_switch);
+    numlockmask = get_mod_mask(conn, symbols, XK_Num_Lock);
+
     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 32077e133b0285f0bb4d5f822643ef5590750b4d..818bf757d2f3bd9d52632a518014cc9c26a322db 100644 (file)
--- 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 bae51b212714dd65fd79b0514a8732c1c6c396ad..3c6469e011d699f1d6b537ad119cbce5b7ead7ac 100644 (file)
--- a/xcb.h
+++ b/xcb.h
@@ -4,7 +4,8 @@
 #include <xcb/xcb.h>
 
 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);