diff --git a/event.h b/event.h index 9a865030..04bfbf10 100644 --- a/event.h +++ b/event.h @@ -30,7 +30,7 @@ awesome_refresh(void) { banning_refresh(); wibox_refresh(); - client_stack_refresh(); + stack_refresh(); return xcb_flush(globalconf.connection); } diff --git a/objects/client.c b/objects/client.c index 1fd39c88..c2adbb8a 100644 --- a/objects/client.c +++ b/objects/client.c @@ -405,142 +405,6 @@ client_focus(client_t *c) client_set_focus(c, !c->nofocus); } -/** Stack a window below. - * \param c The client. - * \param previous The previous window on the stack. - * \return The next-previous! - */ -static xcb_window_t -client_stack_above(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_ABOVE; - - xcb_configure_window(globalconf.connection, c->window, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, - config_win_vals); - - previous = config_win_vals[0] = c->window; - - /* stack transient window on top of their parents */ - foreach(node, globalconf.stack) - if((*node)->transient_for == c) - previous = client_stack_above(*node, previous); - - return previous; -} - -/** Stacking layout layers */ -typedef enum -{ - /** This one is a special layer */ - LAYER_IGNORE, - LAYER_DESKTOP, - LAYER_BELOW, - LAYER_NORMAL, - LAYER_ABOVE, - LAYER_FULLSCREEN, - LAYER_ONTOP, - /** This one only used for counting and is not a real layer */ - LAYER_COUNT -} layer_t; - -/** 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) -{ - /* first deal with user set attributes */ - if(c->ontop) - return LAYER_ONTOP; - else if(c->fullscreen) - return LAYER_FULLSCREEN; - else if(c->above) - return LAYER_ABOVE; - else if(c->below) - return LAYER_BELOW; - - /* check for transient attr */ - if(c->transient_for) - return LAYER_IGNORE; - - /* then deal with windows type */ - switch(c->type) - { - case WINDOW_TYPE_DESKTOP: - return LAYER_DESKTOP; - default: - break; - } - - return LAYER_NORMAL; -} - -/** Restack clients. - * \todo It might be worth stopping to restack everyone and only stack `c' - * relatively to the first matching in the list. - */ -void -client_stack_refresh() -{ - uint32_t config_win_vals[2]; - layer_t layer; - - if (!client_need_stack_refresh) - return; - - client_need_stack_refresh = false; - - config_win_vals[0] = XCB_NONE; - config_win_vals[1] = XCB_STACK_MODE_ABOVE; - - /* stack desktop windows */ - for(layer = LAYER_DESKTOP; layer < LAYER_BELOW; layer++) - foreach(node, globalconf.stack) - if(client_layer_translator(*node) == layer) - config_win_vals[0] = client_stack_above(*node, - config_win_vals[0]); - - /* first stack not ontop wibox window */ - foreach(_sb, globalconf.wiboxes) - { - wibox_t *sb = *_sb; - if(!sb->ontop) - { - xcb_configure_window(globalconf.connection, - sb->window, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, - config_win_vals); - config_win_vals[0] = sb->window; - } - } - - /* then stack clients */ - for(layer = LAYER_BELOW; layer < LAYER_COUNT; layer++) - foreach(node, globalconf.stack) - if(client_layer_translator(*node) == layer) - config_win_vals[0] = client_stack_above(*node, - config_win_vals[0]); - - /* then stack ontop wibox window */ - foreach(_sb, globalconf.wiboxes) - { - wibox_t *sb = *_sb; - if(sb->ontop) - { - xcb_configure_window(globalconf.connection, - sb->window, - XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, - config_win_vals); - config_win_vals[0] = sb->window; - } - } -} - /** Manage a new client. * \param w The window. * \param wgeom Window geometry. @@ -938,7 +802,7 @@ client_set_fullscreen(lua_State *L, int cidx, bool s) client_set_border_width(L, cidx, c->border_width_fs); } client_resize(c, geometry, false); - client_stack(); + stack_windows(); ewmh_client_update_hints(c); luaA_object_emit_signal(L, cidx, "property::fullscreen", 0); } @@ -977,7 +841,7 @@ client_set_maximized_horizontal(lua_State *L, int cidx, bool s) } client_resize(c, geometry, c->size_hints_honor); - client_stack(); + stack_windows(); ewmh_client_update_hints(c); luaA_object_emit_signal(L, cidx, "property::maximized_horizontal", 0); } @@ -1016,7 +880,7 @@ client_set_maximized_vertical(lua_State *L, int cidx, bool s) } client_resize(c, geometry, c->size_hints_honor); - client_stack(); + stack_windows(); ewmh_client_update_hints(c); luaA_object_emit_signal(L, cidx, "property::maximized_vertical", 0); } @@ -1042,7 +906,7 @@ client_set_above(lua_State *L, int cidx, bool s) client_set_fullscreen(L, cidx, false); } c->above = s; - client_stack(); + stack_windows(); ewmh_client_update_hints(c); luaA_object_emit_signal(L, cidx, "property::above", 0); } @@ -1068,7 +932,7 @@ client_set_below(lua_State *L, int cidx, bool s) client_set_fullscreen(L, cidx, false); } c->below = s; - client_stack(); + stack_windows(); ewmh_client_update_hints(c); luaA_object_emit_signal(L, cidx, "property::below", 0); } @@ -1087,7 +951,7 @@ client_set_modal(lua_State *L, int cidx, bool s) if(c->modal != s) { c->modal = s; - client_stack(); + stack_windows(); ewmh_client_update_hints(c); luaA_object_emit_signal(L, cidx, "property::modal", 0); } @@ -1113,7 +977,7 @@ client_set_ontop(lua_State *L, int cidx, bool s) client_set_fullscreen(L, cidx, false); } c->ontop = s; - client_stack(); + stack_windows(); luaA_object_emit_signal(L, cidx, "property::ontop", 0); } } @@ -1448,7 +1312,7 @@ luaA_client_lower(lua_State *L) for(client_t *tc = c->transient_for; tc; tc = tc->transient_for) stack_client_push(tc); - client_stack(); + stack_windows(); return 0; } diff --git a/objects/client.h b/objects/client.h index 2a07372d..6ac75703 100644 --- a/objects/client.h +++ b/objects/client.h @@ -183,20 +183,12 @@ void client_focus(client_t *); void client_focus_update(client_t *); void client_unfocus(client_t *); void client_unfocus_update(client_t *); -void client_stack_refresh(void); bool client_hasproto(client_t *, xcb_atom_t); void client_set_focus(client_t *, bool); void client_ignore_enterleave_events(void); void client_restore_enterleave_events(void); void client_class_setup(lua_State *); -bool client_need_stack_refresh; -static inline void -client_stack(void) -{ - client_need_stack_refresh = true; -} - /** Put client on top of the stack. * \param c The client to raise. */ @@ -223,7 +215,7 @@ client_raise(client_t *c) /* Push c on top of the stack. */ stack_client_append(c); - client_stack(); + stack_windows(); } /** Check if a client has fixed size. diff --git a/objects/wibox.c b/objects/wibox.c index b286c38b..abece00d 100644 --- a/objects/wibox.c +++ b/objects/wibox.c @@ -380,7 +380,7 @@ wibox_map(wibox_t *wibox) /* We must make sure the wibox does not display garbage */ wibox_need_update(wibox); /* Stack this wibox correctly */ - client_stack(); + stack_windows(); } /** Kick out systray windows. @@ -1036,7 +1036,7 @@ luaA_wibox_set_ontop(lua_State *L, wibox_t *wibox) if(b != wibox->ontop) { wibox->ontop = b; - client_stack(); + stack_windows(); luaA_object_emit_signal(L, -3, "property::ontop", 0); } return 0; diff --git a/stack.c b/stack.c index 39ced952..0e5a63e9 100644 --- a/stack.c +++ b/stack.c @@ -22,6 +22,7 @@ #include "ewmh.h" #include "stack.h" #include "objects/client.h" +#include "objects/wibox.h" void stack_client_remove(client_t *c) @@ -57,4 +58,131 @@ stack_client_append(client_t *c) ewmh_update_net_client_list_stacking(c->phys_screen); } +static bool need_stack_refresh = false; + +void +stack_windows(void) +{ + need_stack_refresh = true; +} + +/** Stack a client above. + * \param client The client. + * \param previous The previous client on the stack. + * \return The next-previous! + */ +static xcb_window_t +stack_client_above(client_t *c, xcb_window_t previous) +{ + xcb_configure_window(globalconf.connection, c->window, + XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, + (uint32_t[]) { previous, XCB_STACK_MODE_ABOVE }); + + previous = c->window; + + /* stack transient window on top of their parents */ + foreach(node, globalconf.stack) + if((*node)->transient_for == c) + previous = stack_client_above(*node, previous); + + return previous; +} + +/** Stacking layout layers */ +typedef enum +{ + /** This one is a special layer */ + WINDOW_LAYER_IGNORE, + WINDOW_LAYER_DESKTOP, + WINDOW_LAYER_BELOW, + WINDOW_LAYER_NORMAL, + WINDOW_LAYER_ABOVE, + WINDOW_LAYER_FULLSCREEN, + WINDOW_LAYER_ONTOP, + /** This one only used for counting and is not a real layer */ + WINDOW_LAYER_COUNT +} window_layer_t; + +/** Get the real layer of a client according to its attribute (fullscreen, …) + * \param c The client. + * \return The real layer. + */ +static window_layer_t +client_layer_translator(client_t *c) +{ + /* first deal with user set attributes */ + if(c->ontop) + return WINDOW_LAYER_ONTOP; + else if(c->fullscreen) + return WINDOW_LAYER_FULLSCREEN; + else if(c->above) + return WINDOW_LAYER_ABOVE; + else if(c->below) + return WINDOW_LAYER_BELOW; + /* check for transient attr */ + else if(c->transient_for) + return WINDOW_LAYER_IGNORE; + + /* then deal with windows type */ + switch(c->type) + { + case WINDOW_TYPE_DESKTOP: + return WINDOW_LAYER_DESKTOP; + default: + break; + } + + return WINDOW_LAYER_NORMAL; +} + +/** Restack clients. + * \todo It might be worth stopping to restack everyone and only stack `c' + * relatively to the first matching in the list. + */ +void +stack_refresh() +{ + if(!need_stack_refresh) + return; + + xcb_window_t next = XCB_NONE; + + /* stack desktop windows */ + for(window_layer_t layer = WINDOW_LAYER_DESKTOP; layer < WINDOW_LAYER_BELOW; layer++) + foreach(node, globalconf.stack) + if(client_layer_translator(*node) == layer) + next = stack_client_above(*node, next); + + /* first stack not ontop wibox window */ + foreach(wibox, globalconf.wiboxes) + if(!(*wibox)->ontop) + { + xcb_configure_window(globalconf.connection, + (*wibox)->window, + XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, + (uint32_t[]) { next, XCB_STACK_MODE_ABOVE }); + next = (*wibox)->window; + } + + /* then stack clients */ + for(window_layer_t layer = WINDOW_LAYER_BELOW; layer < WINDOW_LAYER_COUNT; layer++) + foreach(node, globalconf.stack) + if(client_layer_translator(*node) == layer) + next = stack_client_above(*node, next); + + /* then stack ontop wibox window */ + foreach(wibox, globalconf.wiboxes) + if((*wibox)->ontop) + { + xcb_configure_window(globalconf.connection, + (*wibox)->window, + XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, + (uint32_t[]) { next, XCB_STACK_MODE_ABOVE }); + next = (*wibox)->window; + } + + need_stack_refresh = false; +} + + // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/stack.h b/stack.h index 3d221bee..c45288bf 100644 --- a/stack.h +++ b/stack.h @@ -27,6 +27,8 @@ void stack_client_remove(client_t *); void stack_client_push(client_t *); void stack_client_append(client_t *); +void stack_windows(void); +void stack_refresh(void); #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80