summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon TURNEY <jon.turney@dronecode.org.uk>2012-11-20 22:24:25 +0000
committerJon TURNEY <jon.turney@dronecode.org.uk>2012-11-21 14:03:22 +0000
commit3b81d8ddba7e613ef25517318679794448c00b8d (patch)
treeadb01c35830bc3581ef4ad74434840b129cfe74d
parente2da6dc727e3098e1d5ae1463f3dc679f9f90146 (diff)
Handle shaped windows
-rw-r--r--include/xcwm/event.h1
-rw-r--r--include/xcwm/window.h8
-rw-r--r--src/libxcwm/context.c2
-rw-r--r--src/libxcwm/event_loop.c18
-rw-r--r--src/libxcwm/init.c24
-rw-r--r--src/libxcwm/window.c68
-rw-r--r--src/libxcwm/xcwm_internal.h16
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