diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2012-11-20 22:24:25 +0000 |
---|---|---|
committer | Jon TURNEY <jon.turney@dronecode.org.uk> | 2012-11-21 14:03:22 +0000 |
commit | 3b81d8ddba7e613ef25517318679794448c00b8d (patch) | |
tree | adb01c35830bc3581ef4ad74434840b129cfe74d | |
parent | e2da6dc727e3098e1d5ae1463f3dc679f9f90146 (diff) |
Handle shaped windows
-rw-r--r-- | include/xcwm/event.h | 1 | ||||
-rw-r--r-- | include/xcwm/window.h | 8 | ||||
-rw-r--r-- | src/libxcwm/context.c | 2 | ||||
-rw-r--r-- | src/libxcwm/event_loop.c | 18 | ||||
-rw-r--r-- | src/libxcwm/init.c | 24 | ||||
-rw-r--r-- | src/libxcwm/window.c | 68 | ||||
-rw-r--r-- | src/libxcwm/xcwm_internal.h | 16 |
7 files changed, 134 insertions, 3 deletions
diff --git a/include/xcwm/event.h b/include/xcwm/event.h index b146037..b18cf69 100644 --- a/include/xcwm/event.h +++ b/include/xcwm/event.h @@ -44,6 +44,7 @@ typedef enum xcwm_event_type_t { XCWM_EVENT_WINDOW_DESTROY, XCWM_EVENT_WINDOW_NAME, XCWM_EVENT_WINDOW_APPEARANCE, + XCWM_EVENT_WINDOW_SHAPE, } xcwm_event_type_t; /** diff --git a/include/xcwm/window.h b/include/xcwm/window.h index b476cb8..bd61944 100644 --- a/include/xcwm/window.h +++ b/include/xcwm/window.h @@ -253,4 +253,12 @@ xcwm_window_deiconify(xcwm_window_t *window); unsigned int xcwm_window_get_opacity(xcwm_window_t const *window); +/** + * Get the shape of the window. + * @param window The window to get shape data for. + * @return The window shape, or 0 if unshaped + */ +xcb_rectangle_iterator_t +xcwm_window_get_shape(xcwm_window_t const *window); + #endif /* _XCWM_WINDOW_H_ */ diff --git a/src/libxcwm/context.c b/src/libxcwm/context.c index 88d2c32..4a80a25 100644 --- a/src/libxcwm/context.c +++ b/src/libxcwm/context.c @@ -101,6 +101,8 @@ xcwm_context_open(char *display) _xcwm_init_xfixes(root_context); + _xcwm_init_shape(root_context); + /* Add the root window to our list of windows being managed */ _xcwm_add_window(root_context->root_window); diff --git a/src/libxcwm/event_loop.c b/src/libxcwm/event_loop.c index fb480ab..4c1887f 100644 --- a/src/libxcwm/event_loop.c +++ b/src/libxcwm/event_loop.c @@ -195,7 +195,8 @@ run_event_loop(void *thread_arg_struct) xcb_flush(event_conn); while ((evt = xcb_wait_for_event(event_conn))) { - if ((evt->response_type & ~0x80) == context->damage_event_mask) { + uint8_t response_type = evt->response_type & ~0x80; + if (response_type == context->damage_event_mask) { xcb_damage_notify_event_t *dmgevnt = (xcb_damage_notify_event_t *)evt; @@ -271,8 +272,21 @@ run_event_loop(void *thread_arg_struct) callback_ptr(&return_evt); } + else if (response_type == context->shape_event) { + xcb_shape_notify_event_t *shapeevnt = + (xcb_shape_notify_event_t *)evt; + + if (shapeevnt->shape_kind == XCB_SHAPE_SK_BOUNDING) { + xcwm_window_t *window = _xcwm_get_window_node_by_window_id(shapeevnt->affected_window); + _xcwm_window_set_shape(window, shapeevnt->shaped); + + return_evt.event_type = XCWM_EVENT_WINDOW_SHAPE; + return_evt.window = window; + callback_ptr(&return_evt); + } + } else { - switch (evt->response_type & ~0x80) { + switch (response_type) { case 0: { /* Error case. Something very bad has happened. Spit diff --git a/src/libxcwm/init.c b/src/libxcwm/init.c index d5cd604..bc6a113 100644 --- a/src/libxcwm/init.c +++ b/src/libxcwm/init.c @@ -118,12 +118,34 @@ _xcwm_init_composite(xcwm_context_t *contxt) void _xcwm_init_xfixes(xcwm_context_t *contxt) { + xcb_query_extension_reply_t *reply = + _xcwm_init_extension(contxt->conn, "XFIXES"); + xcb_xfixes_query_version_cookie_t cookie = xcb_xfixes_query_version(contxt->conn, 4, 0); - xcb_xfixes_query_version_reply_t *reply = + xcb_xfixes_query_version_reply_t *version_reply = xcb_xfixes_query_version_reply(contxt->conn, cookie, NULL); + free(version_reply); + free(reply); +} + +void +_xcwm_init_shape(xcwm_context_t *contxt) +{ + xcb_query_extension_reply_t *reply = + _xcwm_init_extension(contxt->conn, "SHAPE"); + + xcb_shape_query_version_cookie_t cookie = + xcb_shape_query_version(contxt->conn); + + xcb_shape_query_version_reply_t *version_reply = + xcb_shape_query_version_reply(contxt->conn, cookie, NULL); + + contxt->shape_event = reply->first_event + XCB_SHAPE_NOTIFY; + + free(version_reply); free(reply); } diff --git a/src/libxcwm/window.c b/src/libxcwm/window.c index 58e3ca4..d923330 100644 --- a/src/libxcwm/window.c +++ b/src/libxcwm/window.c @@ -47,6 +47,10 @@ set_wm_size_hints_for_window(xcb_connection_t *conn, xcwm_window_t *window); void init_damage_on_window(xcb_connection_t *conn, xcwm_window_t *window); +/* Initialize reshape on a window */ +static void +init_shape_on_window(xcb_connection_t *conn, xcwm_window_t *window); + /* Set window to the top of the stack */ void xcwm_window_set_to_top(xcwm_window_t *window) @@ -116,6 +120,7 @@ _xcwm_window_create(xcwm_context_t *context, xcb_window_t new_window, window->opacity = ~0; window->composite_pixmap_id = 0; window->local_data = 0; + window->shape = 0; /* Find and set the parent */ window->parent = _xcwm_get_window_node_by_window_id(parent); @@ -142,6 +147,10 @@ _xcwm_window_create(xcwm_context_t *context, xcb_window_t new_window, /* register for damage */ init_damage_on_window(context->conn, window); + /* note the shape, and register for re-shape */ + _xcwm_window_set_shape(window, 1); + init_shape_on_window(context->conn, window); + /* add window to window list for this context */ window = _xcwm_add_window(window); @@ -269,6 +278,9 @@ _xcwm_window_release(xcwm_window_t *window) return; } + if (window->shape) + free(window->shape); + if (window->name) { free(window->name); } @@ -366,6 +378,16 @@ xcwm_window_get_sizing(xcwm_window_t const *window) return &window->size_hints; } +xcb_rectangle_iterator_t +xcwm_window_get_shape(xcwm_window_t const *window) +{ + if (window->shape) + return xcb_shape_get_rectangles_rectangles_iterator(window->shape); + + xcb_rectangle_iterator_t empty_iterator = {0,0,0}; + return empty_iterator; +} + void xcwm_window_constrain_sizing(xcwm_window_t const *window, int *widthp, int *heightp) { @@ -576,3 +598,49 @@ init_damage_on_window(xcb_connection_t *conn, xcwm_window_t *window) window->dmg_bounds.width = 0; window->dmg_bounds.height = 0; } + +void +init_shape_on_window(xcb_connection_t *conn, xcwm_window_t *window) +{ + xcb_void_cookie_t cookie = xcb_shape_select_input(conn, window->window_id, 1 /* ShapeNotify */); + + _xcwm_request_check(conn, cookie, + "Could not select shape events on window"); +} + +void +_xcwm_window_set_shape(xcwm_window_t *window, uint8_t shaped) +{ + if (window->shape) + free(window->shape); + + /* If shaped == FALSE, window is unshaped and we don't need to ask to find shaped region */ + if (shaped) + { + xcb_shape_get_rectangles_cookie_t cookie = xcb_shape_get_rectangles(window->context->conn, + window->window_id, + XCB_SHAPE_SK_BOUNDING); + + xcb_shape_get_rectangles_reply_t *reply = xcb_shape_get_rectangles_reply(window->context->conn, + cookie, + NULL); + + /* ... but unfortunately, there is no way to ask if a window is shaped initially, so + we have to check if we got exactly 1 rectangle which is the same as the window bounds + and treat that as unshaped, as well */ + xcb_rectangle_iterator_t ri = xcb_shape_get_rectangles_rectangles_iterator(reply); + if ((ri.rem == 0) || + ((ri.rem == 1) && (ri.data->x <= 0) && (ri.data->y <= 0) + && (ri.data->width >= window->bounds.width) && (ri.data->height >= window->bounds.height))) { + printf("window 0x%08x is actually unshaped\n", window->window_id); + window->shape = 0; + free(reply); + } else + { + window->shape = reply; + } + } else + { + window->shape = 0; + } +} diff --git a/src/libxcwm/xcwm_internal.h b/src/libxcwm/xcwm_internal.h index cc183f8..3f9ca82 100644 --- a/src/libxcwm/xcwm_internal.h +++ b/src/libxcwm/xcwm_internal.h @@ -66,6 +66,7 @@ struct xcwm_context_t { int conn_screen; xcwm_window_t *root_window; int damage_event_mask; + int shape_event; xcb_window_t wm_cm_window; xcwm_wm_atoms_t atoms; }; @@ -90,6 +91,7 @@ struct xcwm_window_t { void *local_data; /* Area for data client cares about */ unsigned int opacity; xcb_pixmap_t composite_pixmap_id; + xcb_shape_get_rectangles_reply_t *shape; }; /** @@ -187,6 +189,13 @@ _xcwm_init_composite(xcwm_context_t *contxt); void _xcwm_init_xfixes(xcwm_context_t *contxt); +/** + * Initialize the shape extension. + * @param contxt The context + */ +void +_xcwm_init_shape(xcwm_context_t *contxt); + /**************** * event_loop.c ****************/ @@ -289,6 +298,13 @@ void _xcwm_resize_window(xcb_connection_t *conn, xcb_window_t window, int x, int y, int width, int height); +/** + * Update the window shape + * @param window The id of window to resize + * @param shaped TRUE if the window is shaped + */ +void +_xcwm_window_set_shape(xcwm_window_t *window, uint8_t shaped); /**************** * atoms.c |