From 102063dbbdfb0bc9f43268d98f7dcb5269547395 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Fri, 30 Jul 2010 20:54:20 +0200 Subject: [PATCH] Turn this into a reparenting WM Each window is now reparented under a window created by awesome. This window is NOT visible, this commit should not cause any visible differences. Instead, this is done to work around problems with X11. The only alternative would be to ban windows by moving them offscreen which is ugly in itself and breaks pagers. Doing it like this seems to be the better solution. Signed-off-by: Uli Schlachter --- event.c | 6 ++++-- objects/client.c | 50 ++++++++++++++++++++++++++++++++++++++++-------- objects/client.h | 7 +++++-- objects/window.c | 16 ++++++++++++---- objects/window.h | 2 ++ stack.c | 4 ++-- 6 files changed, 67 insertions(+), 18 deletions(-) diff --git a/event.c b/event.c index 527a0f1a8..453654436 100644 --- a/event.c +++ b/event.c @@ -737,8 +737,8 @@ event_handle_mappingnotify(xcb_mapping_notify_event_t *ev) foreach(_c, globalconf.clients) { client_t *c = *_c; - xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->window, XCB_BUTTON_MASK_ANY); - xwindow_grabkeys(c->window, &c->keys); + xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->frame_window, XCB_BUTTON_MASK_ANY); + xwindow_grabkeys(c->frame_window, &c->keys); } } } @@ -747,6 +747,8 @@ static void event_handle_reparentnotify(xcb_reparent_notify_event_t *ev) { client_t *c; +#warning ugly, gotta do this properly + return 0; if((c = client_getbywin(ev->window))) client_unmanage(c); diff --git a/objects/client.c b/objects/client.c index c9e29b9cb..0af0c7aa5 100644 --- a/objects/client.c +++ b/objects/client.c @@ -227,7 +227,7 @@ client_t * client_getbywin(xcb_window_t w) { foreach(c, globalconf.clients) - if((*c)->window == w) + if((*c)->window == w || (*c)->frame_window == w) return *c; return NULL; @@ -313,7 +313,7 @@ client_ban(client_t *c) { if(!c->isbanned) { - xcb_unmap_window(globalconf.connection, c->window); + xcb_unmap_window(globalconf.connection, c->frame_window); c->isbanned = true; @@ -328,20 +328,32 @@ void client_ignore_enterleave_events(void) { foreach(c, globalconf.clients) + { xcb_change_window_attributes(globalconf.connection, (*c)->window, XCB_CW_EVENT_MASK, (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK & ~(XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW) }); + xcb_change_window_attributes(globalconf.connection, + (*c)->frame_window, + XCB_CW_EVENT_MASK, + (const uint32_t []) { FRAME_SELECT_INPUT_EVENT_MASK & ~(XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW) }); + } } void client_restore_enterleave_events(void) { foreach(c, globalconf.clients) + { xcb_change_window_attributes(globalconf.connection, (*c)->window, XCB_CW_EVENT_MASK, (const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK }); + xcb_change_window_attributes(globalconf.connection, + (*c)->frame_window, + XCB_CW_EVENT_MASK, + (const uint32_t []) { FRAME_SELECT_INPUT_EVENT_MASK }); + } } /** Record that a client got focus. @@ -439,6 +451,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int phys_screen, (uint32_t[]) { XCB_STACK_MODE_BELOW}); client_t *c = client_new(globalconf.L); + xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen); /* This cannot change, ever. */ c->phys_screen = phys_screen; @@ -446,6 +459,23 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int phys_screen, c->isbanned = true; /* Store window */ c->window = w; + c->frame_window = xcb_generate_id(globalconf.connection); + xcb_create_window(globalconf.connection, s->root_depth, c->frame_window, s->root, + wgeom->x, wgeom->y, wgeom->width, wgeom->height, + wgeom->border_width, XCB_COPY_FROM_PARENT, s->root_visual, + XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY + | XCB_CW_WIN_GRAVITY | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, + (const uint32_t []) + { + globalconf.colors.bg.pixel, + globalconf.colors.bg.pixel, + XCB_GRAVITY_NORTH_WEST, + XCB_GRAVITY_NORTH_WEST, + 1, + FRAME_SELECT_INPUT_EVENT_MASK + }); + xcb_reparent_window(globalconf.connection, w, c->frame_window, 0, 0); + xcb_map_window(globalconf.connection, w); luaA_object_emit_signal(globalconf.L, -1, "property::window", 0); /* Duplicate client and push it in client list */ @@ -693,9 +723,11 @@ client_resize(client_t *c, area_t geometry, bool hints) client_ignore_enterleave_events(); xcb_configure_window(globalconf.connection, c->window, - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y - | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - (uint32_t[]) { geometry.x, geometry.y, geometry.width, geometry.height }); + XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, + (uint32_t[]) { geometry.width, geometry.height }); + xcb_configure_window(globalconf.connection, c->frame_window, + XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, + (uint32_t[]) { geometry.x, geometry.y, geometry.width, geometry.height }); client_restore_enterleave_events(); @@ -934,7 +966,7 @@ client_unban(client_t *c) { if(c->isbanned) { - xcb_map_window(globalconf.connection, c->window); + xcb_map_window(globalconf.connection, c->frame_window); c->isbanned = false; } @@ -989,6 +1021,8 @@ client_unmanage(client_t *c) * after a restart anymore. */ xcb_change_save_set(globalconf.connection, XCB_SET_MODE_DELETE, c->window); + xcb_destroy_window(globalconf.connection, c->frame_window); + /* set client as invalid */ c->invalid = true; @@ -1651,8 +1685,8 @@ luaA_client_keys(lua_State *L) { luaA_key_array_set(L, 1, 2, keys); luaA_object_emit_signal(L, 1, "property::keys", 0); - xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->window, XCB_BUTTON_MASK_ANY); - xwindow_grabkeys(c->window, keys); + xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->frame_window, XCB_BUTTON_MASK_ANY); + xwindow_grabkeys(c->frame_window, keys); } return luaA_key_array_get(L, 1, keys); diff --git a/objects/client.h b/objects/client.h index 9baa2f86d..0f70f4cbc 100644 --- a/objects/client.h +++ b/objects/client.h @@ -31,10 +31,13 @@ #define CLIENT_SELECT_INPUT_EVENT_MASK (XCB_EVENT_MASK_STRUCTURE_NOTIFY \ | XCB_EVENT_MASK_PROPERTY_CHANGE \ - | XCB_EVENT_MASK_ENTER_WINDOW \ - | XCB_EVENT_MASK_LEAVE_WINDOW \ | XCB_EVENT_MASK_FOCUS_CHANGE) +#define FRAME_SELECT_INPUT_EVENT_MASK (XCB_EVENT_MASK_STRUCTURE_NOTIFY \ + | XCB_EVENT_MASK_ENTER_WINDOW \ + | XCB_EVENT_MASK_LEAVE_WINDOW \ + | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT) + /** Windows type */ typedef enum { diff --git a/objects/window.c b/objects/window.c index 78256165b..e24c1856d 100644 --- a/objects/window.c +++ b/objects/window.c @@ -28,6 +28,14 @@ LUA_CLASS_FUNCS(window, window_class) +static xcb_window_t +window_get(window_t *window) +{ + if (window->frame_window != XCB_NONE) + return window->frame_window; + return window->window; +} + static void window_wipe(window_t *window) { @@ -47,7 +55,7 @@ luaA_window_buttons(lua_State *L) { luaA_button_array_set(L, 1, 2, &window->buttons); luaA_object_emit_signal(L, 1, "property::buttons", 0); - xwindow_buttons_grab(window->window, &window->buttons); + xwindow_buttons_grab(window_get(window), &window->buttons); } return luaA_button_array_get(L, 1, &window->buttons); @@ -87,7 +95,7 @@ window_set_opacity(lua_State *L, int idx, double opacity) if(window->opacity != opacity) { window->opacity = opacity; - xwindow_set_opacity(window->window, opacity); + xwindow_set_opacity(window_get(window), opacity); luaA_object_emit_signal(L, idx, "property::opacity", 0); } } @@ -141,7 +149,7 @@ luaA_window_set_border_color(lua_State *L, window_t *window) if(color_name && xcolor_init_reply(xcolor_init_unchecked(&window->border_color, color_name, len))) { - xwindow_set_border_color(window->window, &window->border_color); + xwindow_set_border_color(window_get(window), &window->border_color); luaA_object_emit_signal(L, -3, "property::border_color", 0); } @@ -162,7 +170,7 @@ window_set_border_width(lua_State *L, int idx, int width) return; if(window->window) - xcb_configure_window(globalconf.connection, window->window, + xcb_configure_window(globalconf.connection, window_get(window), XCB_CONFIG_WINDOW_BORDER_WIDTH, (uint32_t[]) { width }); diff --git a/objects/window.h b/objects/window.h index 12a36d2e9..a409dd989 100644 --- a/objects/window.h +++ b/objects/window.h @@ -30,6 +30,8 @@ LUA_OBJECT_HEADER \ /** The X window number */ \ xcb_window_t window; \ + /** The frame window, might be XCB_NONE */ \ + xcb_window_t frame_window; \ /** Opacity */ \ double opacity; \ /** Strut */ \ diff --git a/stack.c b/stack.c index ed33b5ac0..0f3e218a1 100644 --- a/stack.c +++ b/stack.c @@ -96,9 +96,9 @@ stack_window_above(xcb_window_t w, xcb_window_t previous) static xcb_window_t stack_client_above(client_t *c, xcb_window_t previous) { - stack_window_above(c->window, previous); + stack_window_above(c->frame_window, previous); - previous = c->window; + previous = c->frame_window; /* stack transient window on top of their parents */ foreach(node, globalconf.stack)