diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2013-06-30 11:58:54 +0100 |
---|---|---|
committer | Jon TURNEY <jon.turney@dronecode.org.uk> | 2013-07-26 18:00:15 +0100 |
commit | 05f3ae2e4ea9baee072d6a1471988053d8267228 (patch) | |
tree | 88a4cf26f633854e1eab90398f7498981bcaa844 | |
parent | 4a6b65ede25174200a3ef8a19da905650b7a704c (diff) |
Get window image using SHM, if possible
If MIT-SHM extension is available, maintain a SHM segment appropriately sized to
hold the window image (i.e. with the same lifetime as the composite pixmap)
Try to get window image by copying it to a SHM image, before falling back to
copying it to a normal image (for which the image data must be read over the
socket from the server)
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/libxcwm/context.c | 3 | ||||
-rw-r--r-- | src/libxcwm/event_loop.c | 58 | ||||
-rw-r--r-- | src/libxcwm/image.c | 59 | ||||
-rw-r--r-- | src/libxcwm/window.c | 3 | ||||
-rw-r--r-- | src/libxcwm/xcwm_internal.h | 3 |
6 files changed, 113 insertions, 15 deletions
diff --git a/configure.ac b/configure.ac index b848f5b..e20af3d 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ AC_PROG_OBJC AC_PROG_INSTALL # Checks for libraries. -NEEDED="xcb-damage xcb-composite xcb-event xcb-xtest xcb-image xcb-keysyms xcb-icccm >= 0.3.9 xcb-atom xcb-ewmh" +NEEDED="xcb-damage xcb-composite xcb-event xcb-xtest xcb-image xcb-keysyms xcb-icccm >= 0.3.9 xcb-atom xcb-ewmh xcb-shm" PKG_CHECK_MODULES(XCB, $NEEDED) AC_SUBST(NEEDED) diff --git a/src/libxcwm/context.c b/src/libxcwm/context.c index e092fab..57b3460 100644 --- a/src/libxcwm/context.c +++ b/src/libxcwm/context.c @@ -119,6 +119,9 @@ xcwm_context_open(char *display) if (!_xcwm_init_extension(conn, "XKEYBOARD")) goto fail; + context->has_shm = (_xcwm_init_extension(conn, "MIT-SHM") != NULL); + context->depth = xcb_aux_get_depth(conn, root_screen); + _xcwm_atoms_init(context); /* Select for XFIXES cursor notify events */ diff --git a/src/libxcwm/event_loop.c b/src/libxcwm/event_loop.c index 702d6ae..b6769fe 100644 --- a/src/libxcwm/event_loop.c +++ b/src/libxcwm/event_loop.c @@ -28,6 +28,8 @@ #endif #include <pthread.h> +#include <sys/shm.h> + #include <xcwm/xcwm.h> #include <xcb/composite.h> #include "xcwm_internal.h" @@ -105,19 +107,65 @@ _xcwm_event_stop_loop(void) static void _xcwm_window_composite_pixmap_release(xcwm_window_t *window) { - if (window->composite_pixmap_id) - { + /* Release composite pixmap */ + if (window->composite_pixmap_id) { xcb_free_pixmap(window->context->conn, window->composite_pixmap_id); window->composite_pixmap_id = 0; } + + /* Release SHM resources */ + if (window->context->has_shm) { + if (window->shminfo.shmseg) { + xcb_shm_detach(window->context->conn, window->shminfo.shmseg); + window->shminfo.shmseg = 0; + } + + if (window->shminfo.shmaddr != (void *)-1) { + shmdt(window->shminfo.shmaddr); + window->shminfo.shmaddr = (void *)-1; + } + + if (window->shminfo.shmid != -1) { + shmctl(window->shminfo.shmid, IPC_RMID, 0); + window->shminfo.shmid = -1; + } + } } static void _xcwm_window_composite_pixmap_update(xcwm_window_t *window) { - _xcwm_window_composite_pixmap_release(window); - window->composite_pixmap_id = xcb_generate_id(window->context->conn); - xcb_composite_name_window_pixmap(window->context->conn, window->window_id, window->composite_pixmap_id); + _xcwm_window_composite_pixmap_release(window); + + /* Assign a pixmap XID to the composite pixmap */ + window->composite_pixmap_id = xcb_generate_id(window->context->conn); + xcb_composite_name_window_pixmap(window->context->conn, window->window_id, window->composite_pixmap_id); + + if (window->context->has_shm) + { + /* Pre-compute the size of image data needed for this window */ + xcb_image_t *image = xcb_image_create_native(window->context->conn, + window->bounds.width, + window->bounds.height, + XCB_IMAGE_FORMAT_Z_PIXMAP, + window->context->depth, + NULL, ~0, NULL); + size_t image_size = image->size; + xcb_image_destroy(image); + printf("window 0x%08x requires %d bytes of SHM\n", window->window_id, image_size); + + /* Allocate SHM resources */ + window->shminfo.shmid = shmget(IPC_PRIVATE, image_size, IPC_CREAT | 0777); + if (window->shminfo.shmid < 0) + fprintf(stderr, "shmget failed\n"); + + window->shminfo.shmaddr = shmat(window->shminfo.shmid, 0, 0); + if (window->shminfo.shmaddr < 0) + fprintf(stderr, "shmget failed\n"); + + window->shminfo.shmseg = xcb_generate_id(window->context->conn); + xcb_shm_attach(window->context->conn, window->shminfo.shmseg, window->shminfo.shmid, 0); + } } /* diff --git a/src/libxcwm/image.c b/src/libxcwm/image.c index cb5ca26..34069d4 100644 --- a/src/libxcwm/image.c +++ b/src/libxcwm/image.c @@ -36,7 +36,7 @@ xcwm_image_t * xcwm_image_copy_partial(xcwm_window_t *window, xcwm_rect_t *area) { - xcb_image_t *image; + xcb_image_t *image = NULL; /* Return null if image is 0 by 0 */ if (area->width == 0 || area->height == 0) { @@ -44,14 +44,55 @@ xcwm_image_copy_partial(xcwm_window_t *window, xcwm_rect_t *area) } /* Get the image of the specified area of the window */ - image = xcb_image_get(window->context->conn, - window->composite_pixmap_id, - area->x, - area->y, - area->width, - area->height, - (unsigned int)~0L, - XCB_IMAGE_FORMAT_Z_PIXMAP); + + if (window->context->has_shm && window->shminfo.shmaddr) { + /* + A composite pixmap cannot be a shm pixmap, so we must use + xcb_image_shm_get to copy the image from the window's composite + pixmap to a shm image. + + Rather than creating it every-time, we keep a shared memory + segment around which is of the right size for the window image. + */ + + /* Create an xcb_image_t for which we manage the data */ + image = xcb_image_create_native(window->context->conn, + area->width, + area->height, + XCB_IMAGE_FORMAT_Z_PIXMAP, + window->context->depth, + NULL, ~0, NULL); + if (image) { + /* data is the shared memory */ + image->data = window->shminfo.shmaddr; + + /* Read image data from the composite pixmap into the shm image */ + if (!xcb_image_shm_get(window->context->conn, + window->composite_pixmap_id, + image, + window->shminfo, + area->x, + area->y, + (unsigned int)~0L)) { + xcb_image_destroy(image); + image = NULL; + } + } + } + + if (!image && window->context->has_shm) + printf("has_shm, but falling back to socket image\n"); + + /* If shm not available, or failed, use xcb_image_get() */ + if (!image) + image = xcb_image_get(window->context->conn, + window->composite_pixmap_id, + area->x, + area->y, + area->width, + area->height, + (unsigned int)~0L, + XCB_IMAGE_FORMAT_Z_PIXMAP); /* Failed to get a valid image, return null */ if (!image) { diff --git a/src/libxcwm/window.c b/src/libxcwm/window.c index 0b227de..eafda92 100644 --- a/src/libxcwm/window.c +++ b/src/libxcwm/window.c @@ -120,6 +120,9 @@ _xcwm_window_create(xcwm_context_t *context, xcb_window_t new_window, window->notified_bounds = window->bounds; window->opacity = ~0; window->composite_pixmap_id = 0; + window->shminfo.shmseg = 0; + window->shminfo.shmaddr = (void *)-1; + window->shminfo.shmid = -1; window->local_data = 0; window->shape = 0; diff --git a/src/libxcwm/xcwm_internal.h b/src/libxcwm/xcwm_internal.h index 9e3b993..99c6e00 100644 --- a/src/libxcwm/xcwm_internal.h +++ b/src/libxcwm/xcwm_internal.h @@ -69,6 +69,8 @@ struct xcwm_context_t { int fixes_event_base; xcb_window_t wm_cm_window; xcwm_wm_atoms_t atoms; + int has_shm; + int depth; }; /** @@ -92,6 +94,7 @@ struct xcwm_window_t { void *local_data; /* Area for data client cares about */ unsigned int opacity; xcb_pixmap_t composite_pixmap_id; + xcb_shm_segment_info_t shminfo; xcb_shape_get_rectangles_reply_t *shape; }; |