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 <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2010-07-30 20:54:20 +02:00
parent 5d0a81c8bf
commit 102063dbbd
6 changed files with 67 additions and 18 deletions

View File

@ -737,8 +737,8 @@ event_handle_mappingnotify(xcb_mapping_notify_event_t *ev)
foreach(_c, globalconf.clients) foreach(_c, globalconf.clients)
{ {
client_t *c = *_c; client_t *c = *_c;
xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->window, XCB_BUTTON_MASK_ANY); xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->frame_window, XCB_BUTTON_MASK_ANY);
xwindow_grabkeys(c->window, &c->keys); xwindow_grabkeys(c->frame_window, &c->keys);
} }
} }
} }
@ -747,6 +747,8 @@ static void
event_handle_reparentnotify(xcb_reparent_notify_event_t *ev) event_handle_reparentnotify(xcb_reparent_notify_event_t *ev)
{ {
client_t *c; client_t *c;
#warning ugly, gotta do this properly
return 0;
if((c = client_getbywin(ev->window))) if((c = client_getbywin(ev->window)))
client_unmanage(c); client_unmanage(c);

View File

@ -227,7 +227,7 @@ client_t *
client_getbywin(xcb_window_t w) client_getbywin(xcb_window_t w)
{ {
foreach(c, globalconf.clients) foreach(c, globalconf.clients)
if((*c)->window == w) if((*c)->window == w || (*c)->frame_window == w)
return *c; return *c;
return NULL; return NULL;
@ -313,7 +313,7 @@ client_ban(client_t *c)
{ {
if(!c->isbanned) if(!c->isbanned)
{ {
xcb_unmap_window(globalconf.connection, c->window); xcb_unmap_window(globalconf.connection, c->frame_window);
c->isbanned = true; c->isbanned = true;
@ -328,20 +328,32 @@ void
client_ignore_enterleave_events(void) client_ignore_enterleave_events(void)
{ {
foreach(c, globalconf.clients) foreach(c, globalconf.clients)
{
xcb_change_window_attributes(globalconf.connection, xcb_change_window_attributes(globalconf.connection,
(*c)->window, (*c)->window,
XCB_CW_EVENT_MASK, XCB_CW_EVENT_MASK,
(const uint32_t []) { CLIENT_SELECT_INPUT_EVENT_MASK & ~(XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW) }); (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 void
client_restore_enterleave_events(void) client_restore_enterleave_events(void)
{ {
foreach(c, globalconf.clients) foreach(c, globalconf.clients)
{
xcb_change_window_attributes(globalconf.connection, xcb_change_window_attributes(globalconf.connection,
(*c)->window, (*c)->window,
XCB_CW_EVENT_MASK, XCB_CW_EVENT_MASK,
(const uint32_t []) { CLIENT_SELECT_INPUT_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. /** 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}); (uint32_t[]) { XCB_STACK_MODE_BELOW});
client_t *c = client_new(globalconf.L); client_t *c = client_new(globalconf.L);
xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
/* This cannot change, ever. */ /* This cannot change, ever. */
c->phys_screen = phys_screen; 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; c->isbanned = true;
/* Store window */ /* Store window */
c->window = w; 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); luaA_object_emit_signal(globalconf.L, -1, "property::window", 0);
/* Duplicate client and push it in client list */ /* 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(); client_ignore_enterleave_events();
xcb_configure_window(globalconf.connection, c->window, xcb_configure_window(globalconf.connection, c->window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
| XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, (uint32_t[]) { geometry.width, geometry.height });
(uint32_t[]) { geometry.x, geometry.y, 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(); client_restore_enterleave_events();
@ -934,7 +966,7 @@ client_unban(client_t *c)
{ {
if(c->isbanned) if(c->isbanned)
{ {
xcb_map_window(globalconf.connection, c->window); xcb_map_window(globalconf.connection, c->frame_window);
c->isbanned = false; c->isbanned = false;
} }
@ -989,6 +1021,8 @@ client_unmanage(client_t *c)
* after a restart anymore. */ * after a restart anymore. */
xcb_change_save_set(globalconf.connection, XCB_SET_MODE_DELETE, c->window); xcb_change_save_set(globalconf.connection, XCB_SET_MODE_DELETE, c->window);
xcb_destroy_window(globalconf.connection, c->frame_window);
/* set client as invalid */ /* set client as invalid */
c->invalid = true; c->invalid = true;
@ -1651,8 +1685,8 @@ luaA_client_keys(lua_State *L)
{ {
luaA_key_array_set(L, 1, 2, keys); luaA_key_array_set(L, 1, 2, keys);
luaA_object_emit_signal(L, 1, "property::keys", 0); luaA_object_emit_signal(L, 1, "property::keys", 0);
xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->window, XCB_BUTTON_MASK_ANY); xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->frame_window, XCB_BUTTON_MASK_ANY);
xwindow_grabkeys(c->window, keys); xwindow_grabkeys(c->frame_window, keys);
} }
return luaA_key_array_get(L, 1, keys); return luaA_key_array_get(L, 1, keys);

View File

@ -31,10 +31,13 @@
#define CLIENT_SELECT_INPUT_EVENT_MASK (XCB_EVENT_MASK_STRUCTURE_NOTIFY \ #define CLIENT_SELECT_INPUT_EVENT_MASK (XCB_EVENT_MASK_STRUCTURE_NOTIFY \
| XCB_EVENT_MASK_PROPERTY_CHANGE \ | XCB_EVENT_MASK_PROPERTY_CHANGE \
| XCB_EVENT_MASK_ENTER_WINDOW \
| XCB_EVENT_MASK_LEAVE_WINDOW \
| XCB_EVENT_MASK_FOCUS_CHANGE) | 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 */ /** Windows type */
typedef enum typedef enum
{ {

View File

@ -28,6 +28,14 @@
LUA_CLASS_FUNCS(window, window_class) 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 static void
window_wipe(window_t *window) 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_button_array_set(L, 1, 2, &window->buttons);
luaA_object_emit_signal(L, 1, "property::buttons", 0); 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); 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) if(window->opacity != opacity)
{ {
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); 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 && if(color_name &&
xcolor_init_reply(xcolor_init_unchecked(&window->border_color, color_name, len))) 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); 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; return;
if(window->window) if(window->window)
xcb_configure_window(globalconf.connection, window->window, xcb_configure_window(globalconf.connection, window_get(window),
XCB_CONFIG_WINDOW_BORDER_WIDTH, XCB_CONFIG_WINDOW_BORDER_WIDTH,
(uint32_t[]) { width }); (uint32_t[]) { width });

View File

@ -30,6 +30,8 @@
LUA_OBJECT_HEADER \ LUA_OBJECT_HEADER \
/** The X window number */ \ /** The X window number */ \
xcb_window_t window; \ xcb_window_t window; \
/** The frame window, might be XCB_NONE */ \
xcb_window_t frame_window; \
/** Opacity */ \ /** Opacity */ \
double opacity; \ double opacity; \
/** Strut */ \ /** Strut */ \

View File

@ -96,9 +96,9 @@ stack_window_above(xcb_window_t w, xcb_window_t previous)
static xcb_window_t static xcb_window_t
stack_client_above(client_t *c, xcb_window_t previous) 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 */ /* stack transient window on top of their parents */
foreach(node, globalconf.stack) foreach(node, globalconf.stack)