From abb497fa5601c5785583757ad2eaf6dfeed0edc7 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Thu, 21 Aug 2008 17:52:44 +0200 Subject: [PATCH] client: rework all stacking stuff - Stacking is now per attribute - Fullscreen does not imply isfloating Signed-off-by: Julien Danjou --- client.c | 233 +++++++++++++++++++++++++++++++----------- client.h | 19 +++- common/tokenize.gperf | 1 + event.c | 4 +- ewmh.c | 59 ++--------- layouts/fibonacci.c | 1 - layouts/floating.c | 2 +- mouse.c | 9 +- screen.c | 2 +- structs.h | 17 ++- tag.h | 2 +- 11 files changed, 221 insertions(+), 128 deletions(-) diff --git a/client.c b/client.c index 6f1a48c0..e57dbc91 100644 --- a/client.c +++ b/client.c @@ -33,7 +33,6 @@ #include "screen.h" #include "titlebar.h" #include "lua.h" -#include "stack.h" #include "mouse.h" #include "systray.h" #include "layouts/floating.h" @@ -269,6 +268,57 @@ client_focus(client_t *c) widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); } +/** Stack a window below. + * \param c The client. + * \param previous The previous window on the stack. + * \param return The next-previous! + */ +static xcb_window_t +client_stack_below(client_t *c, xcb_window_t previous) +{ + uint32_t config_win_vals[2]; + + config_win_vals[0] = previous; + config_win_vals[1] = XCB_STACK_MODE_BELOW; + + if(c->titlebar + && c->titlebar->sw + && c->titlebar->position) + { + xcb_configure_window(globalconf.connection, + c->titlebar->sw->window, + XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, + config_win_vals); + config_win_vals[0] = c->titlebar->sw->window; + } + xcb_configure_window(globalconf.connection, c->win, + XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, + config_win_vals); + config_win_vals[0] = c->win; + + return c->win; +} + +/** Get the real layer of a client according to its attribute (fullscreen, …) + * \param c The client. + * \return The real layer. + */ +static layer_t +client_layer_translator(client_t *c) +{ + if(c->isontop) + return LAYER_ONTOP; + else if(c->ismodal) + return LAYER_MODAL; + else if(c->isfullscreen) + return LAYER_FULLSCREEN; + else if(c->isabove) + return LAYER_ABOVE; + else if(c->isfloating) + return LAYER_FLOAT; + return c->layer; +} + /** Restack clients. * \todo It might be worth stopping to restack everyone and only stack `c' * relatively to the first matching in the list. @@ -285,26 +335,11 @@ client_stack(void) config_win_vals[0] = XCB_NONE; config_win_vals[1] = XCB_STACK_MODE_BELOW; - /* first stack fullscreen and modal windows */ + /* first stack modal and fullscreen windows */ for(layer = LAYER_OUTOFSPACE - 1; layer >= LAYER_FULLSCREEN; layer--) for(node = globalconf.stack; node; node = node->next) - if(node->client->layer == layer) - { - if(node->client->titlebar - && node->client->titlebar->sw - && node->client->titlebar->position) - { - xcb_configure_window(globalconf.connection, - node->client->titlebar->sw->window, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, - config_win_vals); - config_win_vals[0] = node->client->titlebar->sw->window; - } - xcb_configure_window(globalconf.connection, node->client->win, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, - config_win_vals); - config_win_vals[0] = node->client->win; - } + if(client_layer_translator(node->client) == layer) + config_win_vals[0] = client_stack_below(node->client, config_win_vals[0]); /* then stack statusbar window */ for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) @@ -321,34 +356,8 @@ client_stack(void) /* finally stack everything else */ for(layer = LAYER_FULLSCREEN - 1; layer >= LAYER_DESKTOP; layer--) for(node = globalconf.stack; node; node = node->next) - if(node->client->layer == layer) - { - if(node->client->titlebar - && node->client->titlebar->sw - && node->client->titlebar->position) - { - xcb_configure_window(globalconf.connection, - node->client->titlebar->sw->window, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, - config_win_vals); - config_win_vals[0] = node->client->titlebar->sw->window; - } - xcb_configure_window(globalconf.connection, node->client->win, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, - config_win_vals); - config_win_vals[0] = node->client->win; - } -} - -/** Put client on top of the stack - * \param c The client to raise. - */ -void -client_raise(client_t *c) -{ - /* Push c on top of the stack. */ - stack_client_push(c); - client_stack(); + if(client_layer_translator(node->client) == layer) + config_win_vals[0] = client_stack_below(node->client, config_win_vals[0]); } /** Manage a new client. @@ -396,7 +405,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen) c->geometry.y = c->f_geometry.y = c->m_geometry.y = wgeom->y; c->geometry.width = c->f_geometry.width = c->m_geometry.width = wgeom->width; c->geometry.height = c->f_geometry.height = c->m_geometry.height = wgeom->height; - c->layer = c->oldlayer = LAYER_TILE; + c->layer = LAYER_TILE; client_setborder(c, wgeom->border_width); c->icon = ewmh_window_icon_get_reply(ewmh_icon_cookie); @@ -526,7 +535,7 @@ client_resize(client_t *c, area_t geometry, bool hints) * stored according to 'value_mask' */ uint32_t values[5]; - if(c->titlebar && !c->ismoving && !c->isfloating && layout != layout_floating) + if(c->titlebar && !c->ismoving && !c->isfloating && !c->isfullscreen && layout != layout_floating) geometry = titlebar_geometry_remove(c->titlebar, c->border, geometry); if(hints) @@ -566,7 +575,7 @@ client_resize(client_t *c, area_t geometry, bool hints) || layout_get_current(new_screen) == layout_floating) { titlebar_update_geometry_floating(c); - if(!c->ismax) + if(!c->isfullscreen) c->f_geometry = geometry; } @@ -615,21 +624,16 @@ client_setfloating(client_t *c, bool floating) { if((c->isfloating = floating)) { - client_setlayer(c, MAX(c->layer, LAYER_FLOAT)); - client_resize(c, c->f_geometry, false); - titlebar_update_geometry_floating(c); + if(!c->isfullscreen) + { + client_resize(c, c->f_geometry, false); + titlebar_update_geometry_floating(c); + } } - else if(c->ismax) - { - c->ismax = false; - client_setlayer(c, c->oldlayer); - client_resize(c, c->m_geometry, false); - } - else - client_setlayer(c, c->oldlayer); client_need_arrange(c); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); client_saveprops(c); + client_stack(); } } @@ -648,6 +652,106 @@ client_setsticky(client_t *c, bool s) } } +/** Set a client fullscreen, or not. + * \param c The client. + * \param s Set or not the client fullscreen. + */ +void +client_setfullscreen(client_t *c, bool s) +{ + if(c->isfullscreen != s) + { + area_t geometry; + + /* become fullscreen! */ + if((c->isfullscreen = s)) + { + /* disable titlebar and borders */ + if(c->titlebar && c->titlebar->sw && (c->titlebar->oldposition = c->titlebar->position)) + { + xcb_unmap_window(globalconf.connection, c->titlebar->sw->window); + c->titlebar->position = Off; + } + geometry = screen_area_get(&globalconf.screens[c->screen].geometry, + NULL, + &globalconf.screens[c->screen].padding); + c->m_geometry = c->geometry; + c->oldborder = c->border; + client_setborder(c, 0); + c->noborder = true; + } + else + { + /* restore borders and titlebar */ + if(c->titlebar && c->titlebar->sw && (c->titlebar->position = c->titlebar->oldposition)) + xcb_map_window(globalconf.connection, c->titlebar->sw->window); + geometry = c->m_geometry; + c->noborder = false; + client_setborder(c, c->oldborder); + client_resize(c, c->m_geometry, false); + } + client_resize(c, geometry, false); + client_need_arrange(c); + client_stack(); + } +} + +/** Set a client above, or not. + * \param c The client. + * \param s Set or not the client above. + */ +void +client_setabove(client_t *c, bool s) +{ + if(c->isabove != s) + { + c->isabove = s; + client_stack(); + } +} + +/** Set a client below, or not. + * \param c The client. + * \param s Set or not the client below. + */ +void +client_setbelow(client_t *c, bool s) +{ + if(c->isbelow != s) + { + c->isbelow = s; + client_stack(); + } +} + +/** Set a client modal, or not. + * \param c The client. + * \param s Set or not the client moda. + */ +void +client_setmodal(client_t *c, bool s) +{ + if(c->ismodal != s) + { + c->ismodal = s; + client_stack(); + } +} + +/** Set a client ontop, or not. + * \param c The client. + * \param s Set or not the client moda. + */ +void +client_setontop(client_t *c, bool s) +{ + if(c->isontop != s) + { + c->isontop = s; + client_stack(); + } +} + /** Save client properties as an X property. * \param c The client. */ @@ -1207,6 +1311,9 @@ luaA_client_newindex(lua_State *L) case A_TK_BORDER_WIDTH: client_setborder(*c, luaL_checknumber(L, 3)); break; + case A_TK_ONTOP: + client_setontop(*c, luaA_checkboolean(L, 3)); + break; case A_TK_BORDER_COLOR: if((buf = luaL_checklstring(L, 3, &len)) && xcolor_init_reply(globalconf.connection, @@ -1272,6 +1379,7 @@ luaA_client_newindex(lua_State *L) * \lfield urgent The client urgent state. * \lfield focus The focused client. * \lfield opacity The client opacity between 0 and 1. + * \lfield ontop The client is on top of every other windows. */ static int luaA_client_index(lua_State *L) @@ -1371,6 +1479,9 @@ luaA_client_index(lua_State *L) case A_TK_FLOATING: lua_pushboolean(L, (*c)->isfloating); break; + case A_TK_ONTOP: + lua_pushboolean(L, (*c)->isontop); + break; case A_TK_STICKY: lua_pushboolean(L, (*c)->issticky); break; diff --git a/client.h b/client.h index 056f9d79..858def8c 100644 --- a/client.h +++ b/client.h @@ -25,6 +25,7 @@ #include #include "structs.h" +#include "stack.h" #define client_need_arrange(c) \ do { \ @@ -38,7 +39,6 @@ bool client_isvisible(client_t *, int); client_t * client_getbywin(xcb_window_t); void client_setlayer(client_t *, layer_t); void client_stack(void); -void client_raise(client_t *); void client_ban(client_t *); void client_unban(client_t *); void client_manage(xcb_window_t, xcb_get_geometry_reply_t *, int); @@ -52,6 +52,11 @@ void client_saveprops(client_t *); void client_kill(client_t *); void client_setfloating(client_t *, bool); void client_setsticky(client_t *, bool); +void client_setabove(client_t *, bool); +void client_setbelow(client_t *, bool); +void client_setmodal(client_t *, bool); +void client_setontop(client_t *, bool); +void client_setfullscreen(client_t *, bool); void client_setborder(client_t *, int); int luaA_client_newindex(lua_State *); @@ -60,5 +65,17 @@ int luaA_client_userdata_new(lua_State *, client_t *); DO_SLIST(client_t, client, client_unref) +/** Put client on top of the stack + * \param c The client to raise. + */ +static inline void +client_raise(client_t *c) +{ + /* Push c on top of the stack. */ + stack_client_push(c); + client_stack(); +} + + #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/common/tokenize.gperf b/common/tokenize.gperf index 06ae2146..63bae7e2 100644 --- a/common/tokenize.gperf +++ b/common/tokenize.gperf @@ -39,6 +39,7 @@ ncol nmaster name on +ontop opacity pid plot_data_add diff --git a/event.c b/event.c index a5cccfd3..f8a8f671 100644 --- a/event.c +++ b/event.c @@ -214,7 +214,7 @@ event_handle_configurerequest(void *data __attribute__ ((unused)), if(geometry.x != c->geometry.x || geometry.y != c->geometry.y || geometry.width != c->geometry.width || geometry.height != c->geometry.height) { - if(c->isfloating || layout_get_current(c->screen) == layout_floating) + if(c->isfloating || c->isfullscreen || layout_get_current(c->screen) == layout_floating) { client_resize(c, geometry, false); titlebar_draw(c); @@ -542,7 +542,7 @@ event_handle_propertynotify(void *data __attribute__ ((unused)), { if(ev->atom == WM_TRANSIENT_FOR) { - if(!c->isfloating) + if(!c->isfloating && !c->isfullscreen) { xcb_window_t trans; xcb_get_wm_transient_for_reply(connection, diff --git a/ewmh.c b/ewmh.c index 54be79ae..bcca6b0d 100644 --- a/ewmh.c +++ b/ewmh.c @@ -266,74 +266,31 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) } else if(state == _NET_WM_STATE_FULLSCREEN) { - area_t geometry = c->geometry; if(set == _NET_WM_STATE_REMOVE) - { - /* restore geometry */ - geometry = c->m_geometry; - /* restore borders and titlebar */ - if(c->titlebar && c->titlebar->sw && (c->titlebar->position = c->titlebar->oldposition)) - xcb_map_window(globalconf.connection, c->titlebar->sw->window); - c->noborder = false; - c->ismax = false; - client_setlayer(c, c->oldlayer); - client_setborder(c, c->oldborder); - client_setfloating(c, c->wasfloating); - } + client_setfullscreen(c, false); else if(set == _NET_WM_STATE_ADD) - { - geometry = screen_area_get(&globalconf.screens[c->screen].geometry, - NULL, - &globalconf.screens[c->screen].padding); - /* save geometry */ - c->m_geometry = c->geometry; - c->wasfloating = c->isfloating; - /* disable titlebar and borders */ - if(c->titlebar && c->titlebar->sw && (c->titlebar->oldposition = c->titlebar->position)) - { - xcb_unmap_window(globalconf.connection, c->titlebar->sw->window); - c->titlebar->position = Off; - } - c->ismax = true; - c->oldborder = c->border; - client_setborder(c, 0); - c->noborder = true; - c->oldlayer = c->layer; - client_setlayer(c, LAYER_FULLSCREEN); - client_setfloating(c, true); - } - widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); - client_resize(c, geometry, false); + client_setfullscreen(c, true); } else if(state == _NET_WM_STATE_ABOVE) { if(set == _NET_WM_STATE_REMOVE) - client_setlayer(c, c->oldlayer); + client_setabove(c, false); else if(set == _NET_WM_STATE_ADD) - { - c->oldlayer = c->layer; - client_setlayer(c, LAYER_ABOVE); - } + client_setabove(c, true); } else if(state == _NET_WM_STATE_BELOW) { if(set == _NET_WM_STATE_REMOVE) - client_setlayer(c, c->oldlayer); + client_setbelow(c, false); else if(set == _NET_WM_STATE_ADD) - { - c->oldlayer = c->layer; - client_setlayer(c, LAYER_BELOW); - } + client_setbelow(c, true); } else if(state == _NET_WM_STATE_MODAL) { if(set == _NET_WM_STATE_REMOVE) - client_setlayer(c, c->oldlayer); + client_setmodal(c, false); else if(set == _NET_WM_STATE_ADD) - { - c->oldlayer = c->layer; - client_setlayer(c, LAYER_MODAL); - } + client_setmodal(c, true); } else if(state == _NET_WM_STATE_HIDDEN) { diff --git a/layouts/fibonacci.c b/layouts/fibonacci.c index f206c635..a59a91c9 100644 --- a/layouts/fibonacci.c +++ b/layouts/fibonacci.c @@ -42,7 +42,6 @@ layout_fibonacci(int screen, int shape) for(c = globalconf.clients; c; c = c->next) if(IS_TILED(c, screen)) { - c->ismax = false; if((i % 2 && geometry.height / 2 > 2 * c->border) || (!(i % 2) && geometry.width / 2 > 2 * c->border)) { diff --git a/layouts/floating.c b/layouts/floating.c index 678149bd..77565c18 100644 --- a/layouts/floating.c +++ b/layouts/floating.c @@ -31,7 +31,7 @@ layout_floating(int screen) client_t *c; for(c = globalconf.clients; c; c = c->next) - if(client_isvisible(c, screen) && !c->ismax) + if(client_isvisible(c, screen) && !c->isfullscreen) client_resize(c, c->f_geometry, false); } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/mouse.c b/mouse.c index a4f3535f..1fd3e51c 100644 --- a/mouse.c +++ b/mouse.c @@ -507,11 +507,9 @@ mouse_client_move(client_t *c, int snap, bool infobox) mouse_query_pointer(root, &last_x, &last_y, NULL); /* grab pointer */ - if(!mouse_grab_pointer(root, CurMove)) + if(c->isfullscreen || !mouse_grab_pointer(root, CurMove)) return; - c->ismax = false; - if(infobox && (c->isfloating || layout == layout_floating)) sw = mouse_infobox_new(c->phys_screen, c->border, c->geometry, &ctx); @@ -956,6 +954,9 @@ mouse_client_resize(client_t *c, corner_t corner, bool infobox) layout_t *layout; xcb_screen_t *s; + if(c->isfullscreen) + return; + curtags = tags_get_current(c->screen); layout = curtags[0]->layout; s = xutil_screen_get(globalconf.connection, c->phys_screen); @@ -966,7 +967,7 @@ mouse_client_resize(client_t *c, corner_t corner, bool infobox) if(c->isfixed) goto bailout; - c->ismax = false; + client_setfullscreen(c, false); mouse_client_resize_floating(c, corner, infobox); } diff --git a/screen.c b/screen.c index ce6daa68..e1cb035f 100644 --- a/screen.c +++ b/screen.c @@ -170,7 +170,7 @@ screen_client_moveto(client_t *c, int new_screen, bool doresize) if(new_f_geometry.y + new_f_geometry.height >= to.y + to.height) new_f_geometry.y = to.y + to.height - new_f_geometry.height - 2 * c->border; - if(c->ismax) + if(c->isfullscreen) { new_geometry = c->geometry; diff --git a/structs.h b/structs.h index ec02bbe0..ba5b5345 100644 --- a/structs.h +++ b/structs.h @@ -44,6 +44,7 @@ typedef enum LAYER_ABOVE, LAYER_FULLSCREEN, LAYER_MODAL, + LAYER_ONTOP, LAYER_OUTOFSPACE } layer_t; @@ -273,18 +274,24 @@ struct client_t bool issticky; /** Has urgency hint */ bool isurgent; - /** Store previous floating state before maximizing */ - bool wasfloating; /** true if the window is floating */ bool isfloating; /** true if the window is fixed */ bool isfixed; - /** true if the window is maximized */ - bool ismax; /** true if the client is moving */ bool ismoving; /** True if the client is hidden */ bool ishidden; + /** True if the client is fullscreen */ + bool isfullscreen; + /** True if the client is above others */ + bool isabove; + /** True if the client is below others */ + bool isbelow; + /** True if the client is modal */ + bool ismodal; + /** True if the client is on top */ + bool isontop; /** true if the client must be skipped from task bar client list */ bool skiptb; /** Window of the client */ @@ -294,7 +301,7 @@ struct client_t /** Client physical screen */ int phys_screen; /** Layer in the stacking order */ - layer_t layer, oldlayer; + layer_t layer; /** Path to an icon */ char *icon_path; /** Titlebar */ diff --git a/tag.h b/tag.h index 87335f1b..6f2f7ed2 100644 --- a/tag.h +++ b/tag.h @@ -26,7 +26,7 @@ #include "common/refcount.h" /** Check if a client is tiled */ -#define IS_TILED(client, screen) (client && !client->isfloating && !client->ismax && client_isvisible(client, screen)) +#define IS_TILED(client, screen) (client && !client->isfloating && !client->isfullscreen && client_isvisible(client, screen)) /* Contructor, destructor and referencors */ tag_t *tag_new(const char *, ssize_t, layout_t *, double, int, int);