client: Rewrite the client stacking code in Lua.
This adds 2 new requests: * request::raise: Helps to decouple ewmh and client class internally plus allow some focus stealing policies. * reqest::restack: Send *why* something is restacked to Lua. It allows to do things like sending a client to the back of a layout rather than use the master area. This is mostly a 1:1 port of the C code. The idea is to use this as a starting point to have a stack per `tag` rather than something global. It also paves the way for stacking wibox among clients in a predictable way. None of that is exposed in the public API as part of this commit. The point is to get enough going so the wibox desktop layer PR can be implemented on top of this.
This commit is contained in:
parent
1239cdf4bc
commit
c6a9148d0b
10
event.c
10
event.c
|
@ -830,8 +830,14 @@ event_handle_maprequest(xcb_map_request_event_t *ev)
|
||||||
luaA_object_push(L, c);
|
luaA_object_push(L, c);
|
||||||
client_set_minimized(L, -1, false);
|
client_set_minimized(L, -1, false);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
/* it will be raised, so just update ourself */
|
|
||||||
client_raise(c);
|
lua_pushstring(L, "maprequest");
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushstring(L, "client");
|
||||||
|
luaA_object_push(L, c);
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
|
||||||
|
luaA_object_emit_signal(L, -3, "request::raise", 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
1
event.h
1
event.h
|
@ -46,7 +46,6 @@ awesome_refresh(void)
|
||||||
drawin_refresh();
|
drawin_refresh();
|
||||||
client_refresh();
|
client_refresh();
|
||||||
banning_refresh();
|
banning_refresh();
|
||||||
stack_refresh();
|
|
||||||
client_destroy_later();
|
client_destroy_later();
|
||||||
return xcb_flush(globalconf.connection);
|
return xcb_flush(globalconf.connection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,9 @@ local capi = {
|
||||||
mouse = mouse,
|
mouse = mouse,
|
||||||
awesome = awesome,
|
awesome = awesome,
|
||||||
client = client,
|
client = client,
|
||||||
tag = tag
|
drawin = drawin,
|
||||||
|
tag = tag,
|
||||||
|
root = root,
|
||||||
}
|
}
|
||||||
local tag = require("awful.tag")
|
local tag = require("awful.tag")
|
||||||
local client = require("awful.client")
|
local client = require("awful.client")
|
||||||
|
@ -55,6 +57,9 @@ end
|
||||||
|
|
||||||
local layout = {}
|
local layout = {}
|
||||||
|
|
||||||
|
-- Avoid restacking the clients and drawins too often.
|
||||||
|
local need_restack = true
|
||||||
|
|
||||||
-- Support `table.insert()` to avoid breaking old code.
|
-- Support `table.insert()` to avoid breaking old code.
|
||||||
local default_layouts = setmetatable({}, {
|
local default_layouts = setmetatable({}, {
|
||||||
__newindex = function(self, key, value)
|
__newindex = function(self, key, value)
|
||||||
|
@ -64,6 +69,17 @@ local default_layouts = setmetatable({}, {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local x11_layers_ordered, x11_layers_keys = {
|
||||||
|
"WINDOW_LAYER_IGNORE",
|
||||||
|
"WINDOW_LAYER_DESKTOP",
|
||||||
|
"WINDOW_LAYER_BELOW",
|
||||||
|
"WINDOW_LAYER_NORMAL",
|
||||||
|
"WINDOW_LAYER_ABOVE",
|
||||||
|
"WINDOW_LAYER_FULLSCREEN",
|
||||||
|
"WINDOW_LAYER_ONTOP"
|
||||||
|
}, {}
|
||||||
|
|
||||||
|
for k, v in ipairs(x11_layers_ordered) do x11_layers_keys[v] = k end
|
||||||
|
|
||||||
layout.suit = require("awful.layout.suit")
|
layout.suit = require("awful.layout.suit")
|
||||||
|
|
||||||
|
@ -108,6 +124,27 @@ local arrange_lock = false
|
||||||
-- Delay one arrange call per screen.
|
-- Delay one arrange call per screen.
|
||||||
local delayed_arrange = {}
|
local delayed_arrange = {}
|
||||||
|
|
||||||
|
local function client_to_layer(o)
|
||||||
|
if o.type == "desktop" then
|
||||||
|
return x11_layers_keys.WINDOW_LAYER_DESKTOP
|
||||||
|
elseif o.ontop then
|
||||||
|
-- first deal with user set attributes
|
||||||
|
return x11_layers_keys.WINDOW_LAYER_ONTOP;
|
||||||
|
elseif o.fullscreen and capi.client.focus == o then
|
||||||
|
-- Fullscreen windows only get their own layer when they have the focus
|
||||||
|
return x11_layers_keys.WINDOW_LAYER_FULLSCREEN;
|
||||||
|
elseif o.above then
|
||||||
|
return x11_layers_keys.WINDOW_LAYER_ABOVE;
|
||||||
|
elseif o.below then
|
||||||
|
return x11_layers_keys.WINDOW_LAYER_BELOW;
|
||||||
|
elseif o.transient_for then
|
||||||
|
-- check for transient attr
|
||||||
|
return x11_layers_keys.WINDOW_LAYER_IGNORE;
|
||||||
|
else
|
||||||
|
return x11_layers_keys.WINDOW_LAYER_NORMAL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Get the current layout.
|
--- Get the current layout.
|
||||||
-- @tparam screen screen The screen.
|
-- @tparam screen screen The screen.
|
||||||
-- @return The layout function.
|
-- @return The layout function.
|
||||||
|
@ -237,6 +274,7 @@ end
|
||||||
-- @tparam screen screen The screen to arrange.
|
-- @tparam screen screen The screen to arrange.
|
||||||
-- @noreturn
|
-- @noreturn
|
||||||
-- @staticfct awful.layout.arrange
|
-- @staticfct awful.layout.arrange
|
||||||
|
-- @see restack
|
||||||
function layout.arrange(screen)
|
function layout.arrange(screen)
|
||||||
screen = get_screen(screen)
|
screen = get_screen(screen)
|
||||||
if not screen or delayed_arrange[screen] then return end
|
if not screen or delayed_arrange[screen] then return end
|
||||||
|
@ -417,8 +455,77 @@ function layout.move_handler(c, context, hints) --luacheck: no unused args
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- [UNDOCUMENTED] Handler for `request::restack`.
|
||||||
|
--
|
||||||
|
-- @signalhandler awful.layout.move_handler
|
||||||
|
-- @tparam string context The context
|
||||||
|
-- @tparam table hints Additional hints
|
||||||
|
-- @tparam[opt=nil] client|nil hints.client The client
|
||||||
|
-- @tparam[opt=nil] drawin|nil hints.drawin Additional hints
|
||||||
|
function layout._restack_handler(context, hints) -- luacheck: no unused args
|
||||||
|
--TODO Support permissions
|
||||||
|
need_restack = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Arrange the clients on the Z axis.
|
||||||
|
-- @staticfct awful.layout.restack
|
||||||
|
-- @noreturn
|
||||||
|
-- @see arrange
|
||||||
|
function layout.restack()
|
||||||
|
|
||||||
|
local layers = {}
|
||||||
|
|
||||||
|
local function append(o)
|
||||||
|
local layer = client_to_layer(o)
|
||||||
|
layers[layer] = layers[layer] or {}
|
||||||
|
table.insert(layers[layer], 1, o.drawin and o.drawin or o)
|
||||||
|
end
|
||||||
|
|
||||||
|
local drawins, clients = capi.drawin.get(), capi.client.get(nil, true)
|
||||||
|
|
||||||
|
for _, c in ipairs(clients) do append(c) end
|
||||||
|
for i=#drawins, 1, -1 do append(drawins[i].get_wibox()) end
|
||||||
|
|
||||||
|
local result = {}
|
||||||
|
|
||||||
|
for i = 1, #x11_layers_ordered do
|
||||||
|
if layers[i] then
|
||||||
|
for _, v in ipairs(layers[i] or {}) do
|
||||||
|
table.insert(result, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
capi.root.set_stacking_order(result)
|
||||||
|
end
|
||||||
|
|
||||||
capi.client.connect_signal("request::geometry", layout.move_handler)
|
capi.client.connect_signal("request::geometry", layout.move_handler)
|
||||||
|
|
||||||
|
-- Translate the `request::raise`, which will trigger a `"request::restack"`.
|
||||||
|
capi.client.connect_signal("request::raise", function(c, context, hints) --luacheck: no unused args
|
||||||
|
hints.client:raise()
|
||||||
|
end)
|
||||||
|
|
||||||
|
capi.client.connect_signal("request::restack", layout._restack_handler)
|
||||||
|
|
||||||
|
-- Check if the type is `"desktop"`, which goes below everything.
|
||||||
|
for _, class in ipairs(capi.client, capi.drawin) do
|
||||||
|
class.connect_signal("property::type", function(o)
|
||||||
|
capi.client.emit_signal("request::restack", "type", {
|
||||||
|
client = o.modal ~= nil and o or nil,
|
||||||
|
drawin = o.modal == nil and o or nil,
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Place the clients and drawin on top of each other.
|
||||||
|
capi.awesome.connect_signal("refresh", function()
|
||||||
|
if need_restack then
|
||||||
|
layout.restack()
|
||||||
|
need_restack = false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
-- When a screen is moved, make (floating) clients follow it
|
-- When a screen is moved, make (floating) clients follow it
|
||||||
capi.screen.connect_signal("property::geometry", function(s, old_geom)
|
capi.screen.connect_signal("property::geometry", function(s, old_geom)
|
||||||
local geom = s.geometry
|
local geom = s.geometry
|
||||||
|
|
|
@ -2241,7 +2241,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, xcb_get_window_at
|
||||||
ewmh_client_check_hints(c);
|
ewmh_client_check_hints(c);
|
||||||
|
|
||||||
/* Push client in stack */
|
/* Push client in stack */
|
||||||
stack_client_push(c);
|
stack_client_push(L, c, "manage");
|
||||||
|
|
||||||
/* Request our response */
|
/* Request our response */
|
||||||
xcb_get_property_reply_t *reply =
|
xcb_get_property_reply_t *reply =
|
||||||
|
@ -2717,7 +2717,7 @@ client_set_fullscreen(lua_State *L, int cidx, bool s)
|
||||||
luaA_object_emit_signal(L, abs_cidx, "property::fullscreen", 0);
|
luaA_object_emit_signal(L, abs_cidx, "property::fullscreen", 0);
|
||||||
/* Force a client resize, so that titlebars get shown/hidden */
|
/* Force a client resize, so that titlebars get shown/hidden */
|
||||||
client_resize_do(c, c->geometry);
|
client_resize_do(c, c->geometry);
|
||||||
stack_windows();
|
stack_windows(L, "fullscreen", c, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +2768,7 @@ client_set_maximized_common(lua_State *L, int cidx, bool s, const char* type, co
|
||||||
if(max_before != c->maximized)
|
if(max_before != c->maximized)
|
||||||
luaA_object_emit_signal(L, abs_cidx, "property::maximized", 0);
|
luaA_object_emit_signal(L, abs_cidx, "property::maximized", 0);
|
||||||
|
|
||||||
stack_windows();
|
stack_windows(L, "maximized", c, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2816,7 +2816,7 @@ client_set_above(lua_State *L, int cidx, bool s)
|
||||||
client_set_fullscreen(L, cidx, false);
|
client_set_fullscreen(L, cidx, false);
|
||||||
}
|
}
|
||||||
c->above = s;
|
c->above = s;
|
||||||
stack_windows();
|
stack_windows(L, "above", c, NULL);
|
||||||
luaA_object_emit_signal(L, cidx, "property::above", 0);
|
luaA_object_emit_signal(L, cidx, "property::above", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2841,7 +2841,7 @@ client_set_below(lua_State *L, int cidx, bool s)
|
||||||
client_set_fullscreen(L, cidx, false);
|
client_set_fullscreen(L, cidx, false);
|
||||||
}
|
}
|
||||||
c->below = s;
|
c->below = s;
|
||||||
stack_windows();
|
stack_windows(L, "below", c, NULL);
|
||||||
luaA_object_emit_signal(L, cidx, "property::below", 0);
|
luaA_object_emit_signal(L, cidx, "property::below", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2859,7 +2859,7 @@ client_set_modal(lua_State *L, int cidx, bool s)
|
||||||
if(c->modal != s)
|
if(c->modal != s)
|
||||||
{
|
{
|
||||||
c->modal = s;
|
c->modal = s;
|
||||||
stack_windows();
|
stack_windows(L, "modal", c, NULL);
|
||||||
luaA_object_emit_signal(L, cidx, "property::modal", 0);
|
luaA_object_emit_signal(L, cidx, "property::modal", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2884,7 +2884,7 @@ client_set_ontop(lua_State *L, int cidx, bool s)
|
||||||
client_set_fullscreen(L, cidx, false);
|
client_set_fullscreen(L, cidx, false);
|
||||||
}
|
}
|
||||||
c->ontop = s;
|
c->ontop = s;
|
||||||
stack_windows();
|
stack_windows(L, "ontop", c, NULL);
|
||||||
luaA_object_emit_signal(L, cidx, "property::ontop", 0);
|
luaA_object_emit_signal(L, cidx, "property::ontop", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2942,7 +2942,7 @@ client_unmanage(client_t *c, client_unmanage_t reason)
|
||||||
client_array_remove(&globalconf.clients, elem);
|
client_array_remove(&globalconf.clients, elem);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
stack_client_remove(c);
|
stack_client_remove(L, c, false, "unmanage");
|
||||||
for(int i = 0; i < globalconf.tags.len; i++)
|
for(int i = 0; i < globalconf.tags.len; i++)
|
||||||
untag_client(c, globalconf.tags.tab[i]);
|
untag_client(c, globalconf.tags.tab[i]);
|
||||||
|
|
||||||
|
@ -3402,7 +3402,29 @@ luaA_client_raise(lua_State *L)
|
||||||
)
|
)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
client_raise(c);
|
client_t *tc = c;
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
/* Find number of transient layers. */
|
||||||
|
for(counter = 0; tc->transient_for; counter++)
|
||||||
|
tc = tc->transient_for;
|
||||||
|
|
||||||
|
/* Push them in reverse order. */
|
||||||
|
for(; counter > 0; counter--)
|
||||||
|
{
|
||||||
|
tc = c;
|
||||||
|
for(int i = 0; i < counter; i++)
|
||||||
|
tc = tc->transient_for;
|
||||||
|
stack_client_append(L, tc, "raise");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push c on top of the stack. */
|
||||||
|
stack_client_append(L, c, "raise");
|
||||||
|
|
||||||
|
/* Notify the listeners */
|
||||||
|
luaA_object_push(L, c);
|
||||||
|
luaA_object_emit_signal(L, -1, "raised", 0);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3426,11 +3448,11 @@ luaA_client_lower(lua_State *L)
|
||||||
if (globalconf.stack.len && globalconf.stack.tab[0] == c)
|
if (globalconf.stack.len && globalconf.stack.tab[0] == c)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
stack_client_push(c);
|
stack_client_push(L, c, "lower");
|
||||||
|
|
||||||
/* Traverse all transient layers. */
|
/* Traverse all transient layers. */
|
||||||
for(client_t *tc = c->transient_for; tc; tc = tc->transient_for)
|
for(client_t *tc = c->transient_for; tc; tc = tc->transient_for)
|
||||||
stack_client_push(tc);
|
stack_client_push(L, tc, "lower");
|
||||||
|
|
||||||
/* Notify the listeners */
|
/* Notify the listeners */
|
||||||
luaA_object_push(L, c);
|
luaA_object_push(L, c);
|
||||||
|
|
|
@ -258,38 +258,6 @@ drawable_t *client_get_drawable(client_t *, int, int);
|
||||||
drawable_t *client_get_drawable_offset(client_t *, int *, int *);
|
drawable_t *client_get_drawable_offset(client_t *, int *, int *);
|
||||||
area_t client_get_undecorated_geometry(client_t *);
|
area_t client_get_undecorated_geometry(client_t *);
|
||||||
|
|
||||||
/** Put client on top of the stack.
|
|
||||||
* \param c The client to raise.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
client_raise(client_t *c)
|
|
||||||
{
|
|
||||||
client_t *tc = c;
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
/* Find number of transient layers. */
|
|
||||||
for(counter = 0; tc->transient_for; counter++)
|
|
||||||
tc = tc->transient_for;
|
|
||||||
|
|
||||||
/* Push them in reverse order. */
|
|
||||||
for(; counter > 0; counter--)
|
|
||||||
{
|
|
||||||
tc = c;
|
|
||||||
for(int i = 0; i < counter; i++)
|
|
||||||
tc = tc->transient_for;
|
|
||||||
stack_client_append(tc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Push c on top of the stack. */
|
|
||||||
stack_client_append(c);
|
|
||||||
|
|
||||||
/* Notify the listeners */
|
|
||||||
lua_State *L = globalconf_get_lua_State();
|
|
||||||
luaA_object_push(L, c);
|
|
||||||
luaA_object_emit_signal(L, -1, "raised", 0);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if a client has fixed size.
|
/** Check if a client has fixed size.
|
||||||
* \param c A client.
|
* \param c A client.
|
||||||
* \return A boolean value, true if the client has a fixed size.
|
* \return A boolean value, true if the client has a fixed size.
|
||||||
|
|
|
@ -336,7 +336,7 @@ drawin_map(lua_State *L, int widx)
|
||||||
/* Deactivate BMA */
|
/* Deactivate BMA */
|
||||||
client_restore_enterleave_events();
|
client_restore_enterleave_events();
|
||||||
/* Stack this drawin correctly */
|
/* Stack this drawin correctly */
|
||||||
stack_windows();
|
stack_windows(L, "append", NULL, drawin);
|
||||||
/* Add it to the list of visible drawins */
|
/* Add it to the list of visible drawins */
|
||||||
drawin_array_append(&globalconf.drawins, drawin);
|
drawin_array_append(&globalconf.drawins, drawin);
|
||||||
/* Make sure it has a surface */
|
/* Make sure it has a surface */
|
||||||
|
@ -591,7 +591,7 @@ luaA_drawin_set_ontop(lua_State *L, drawin_t *drawin)
|
||||||
if(b != drawin->ontop)
|
if(b != drawin->ontop)
|
||||||
{
|
{
|
||||||
drawin->ontop = b;
|
drawin->ontop = b;
|
||||||
stack_windows();
|
stack_windows(L, "ontop", NULL, drawin);
|
||||||
luaA_object_emit_signal(L, -3, "property::ontop", 0);
|
luaA_object_emit_signal(L, -3, "property::ontop", 0);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
2
root.c
2
root.c
|
@ -42,6 +42,7 @@
|
||||||
#include "objects/button.h"
|
#include "objects/button.h"
|
||||||
#include "common/luaclass.h"
|
#include "common/luaclass.h"
|
||||||
#include "xwindow.h"
|
#include "xwindow.h"
|
||||||
|
#include "stack.h"
|
||||||
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
|
@ -653,6 +654,7 @@ const struct luaL_Reg awesome_root_methods[] =
|
||||||
{ "tags", luaA_root_tags },
|
{ "tags", luaA_root_tags },
|
||||||
{ "__index", luaA_root_index },
|
{ "__index", luaA_root_index },
|
||||||
{ "__newindex", luaA_root_newindex },
|
{ "__newindex", luaA_root_newindex },
|
||||||
|
{ "set_stacking_order", luaA_set_stacking_order},
|
||||||
{ "set_index_miss_handler", luaA_root_set_index_miss_handler},
|
{ "set_index_miss_handler", luaA_root_set_index_miss_handler},
|
||||||
{ "set_call_handler", luaA_root_set_call_handler},
|
{ "set_call_handler", luaA_root_set_call_handler},
|
||||||
{ "set_newindex_miss_handler", luaA_root_set_newindex_miss_handler},
|
{ "set_newindex_miss_handler", luaA_root_set_newindex_miss_handler},
|
||||||
|
|
167
stack.c
167
stack.c
|
@ -21,11 +21,9 @@
|
||||||
|
|
||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
#include "ewmh.h"
|
#include "ewmh.h"
|
||||||
#include "objects/client.h"
|
|
||||||
#include "objects/drawin.h"
|
|
||||||
|
|
||||||
void
|
void
|
||||||
stack_client_remove(client_t *c)
|
stack_client_remove(lua_State *L, client_t *c, bool silent, const char *context)
|
||||||
{
|
{
|
||||||
foreach(client, globalconf.stack)
|
foreach(client, globalconf.stack)
|
||||||
if(*client == c)
|
if(*client == c)
|
||||||
|
@ -34,39 +32,65 @@ stack_client_remove(client_t *c)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ewmh_update_net_client_list_stacking();
|
ewmh_update_net_client_list_stacking();
|
||||||
stack_windows();
|
|
||||||
|
if (!silent)
|
||||||
|
stack_windows(L, context, c, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Push the client at the beginning of the client stack.
|
/** Push the client at the beginning of the client stack.
|
||||||
|
* \param L The Lua context.
|
||||||
* \param c The client to push.
|
* \param c The client to push.
|
||||||
|
* \param context An human readable reason of why this was done.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
stack_client_push(client_t *c)
|
stack_client_push(lua_State *L, client_t *c, const char *context)
|
||||||
{
|
{
|
||||||
stack_client_remove(c);
|
stack_client_remove(L, c, true, "");
|
||||||
client_array_push(&globalconf.stack, c);
|
client_array_push(&globalconf.stack, c);
|
||||||
ewmh_update_net_client_list_stacking();
|
ewmh_update_net_client_list_stacking();
|
||||||
stack_windows();
|
stack_windows(L, context, c, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Push the client at the end of the client stack.
|
/** Push the client at the end of the client stack.
|
||||||
|
* \param L The Lua context.
|
||||||
* \param c The client to push.
|
* \param c The client to push.
|
||||||
|
* \param context An human readable reason of why this was done.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
stack_client_append(client_t *c)
|
stack_client_append(lua_State *L, client_t *c, const char *context)
|
||||||
{
|
{
|
||||||
stack_client_remove(c);
|
stack_client_remove(L, c, true, "");
|
||||||
client_array_append(&globalconf.stack, c);
|
client_array_append(&globalconf.stack, c);
|
||||||
ewmh_update_net_client_list_stacking();
|
ewmh_update_net_client_list_stacking();
|
||||||
stack_windows();
|
stack_windows(L, context, c, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool need_stack_refresh = false;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
stack_windows(void)
|
stack_windows(lua_State *L, const char *context, client_t *c, drawin_t *d)
|
||||||
{
|
{
|
||||||
need_stack_refresh = true;
|
/* Context */
|
||||||
|
lua_pushstring(L, context);
|
||||||
|
|
||||||
|
/* Create hints table */
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
lua_pushstring(L, "client");
|
||||||
|
if (c)
|
||||||
|
luaA_object_push(L, c);
|
||||||
|
else
|
||||||
|
lua_pushnil(L);
|
||||||
|
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "drawin");
|
||||||
|
if (d)
|
||||||
|
luaA_object_push(L, d);
|
||||||
|
else
|
||||||
|
lua_pushnil(L);
|
||||||
|
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
luaA_class_emit_signal(L, &client_class, "request::restack", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stack a window above another window, without causing errors.
|
/** Stack a window above another window, without causing errors.
|
||||||
|
@ -107,95 +131,48 @@ stack_client_above(client_t *c, xcb_window_t previous)
|
||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stacking layout layers */
|
/**
|
||||||
typedef enum
|
* Allow Lua to define the stacking order of clients and wiboxes.
|
||||||
{
|
*
|
||||||
/** This one is a special layer */
|
* The table must contain `client` and `wibox` object. Index `1` is the closest
|
||||||
WINDOW_LAYER_IGNORE,
|
* to the root (wallpaper) and the last index is the closest to the top.
|
||||||
WINDOW_LAYER_DESKTOP,
|
*
|
||||||
WINDOW_LAYER_BELOW,
|
* @staticfct root.set_stacking_order
|
||||||
WINDOW_LAYER_NORMAL,
|
* @tparam table stacking_order
|
||||||
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
|
int
|
||||||
client_layer_translator(client_t *c)
|
luaA_set_stacking_order(lua_State *L) {
|
||||||
{
|
|
||||||
/* first deal with user set attributes */
|
|
||||||
if(c->ontop)
|
|
||||||
return WINDOW_LAYER_ONTOP;
|
|
||||||
/* Fullscreen windows only get their own layer when they have the focus */
|
|
||||||
else if(c->fullscreen && globalconf.focus.client == c)
|
|
||||||
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;
|
xcb_window_t next = XCB_NONE;
|
||||||
|
|
||||||
/* stack desktop windows */
|
if(lua_gettop(L) == 1)
|
||||||
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 drawin window */
|
|
||||||
foreach(drawin, globalconf.drawins)
|
|
||||||
if(!(*drawin)->ontop)
|
|
||||||
{
|
{
|
||||||
stack_window_above((*drawin)->window, next);
|
luaA_checktable(L, 1);
|
||||||
next = (*drawin)->window;
|
|
||||||
|
lua_pushnil(L);
|
||||||
|
|
||||||
|
while(lua_next(L, 1))
|
||||||
|
{
|
||||||
|
if (luaA_class_get(L, -1) == &client_class)
|
||||||
|
{
|
||||||
|
client_t *c = luaA_object_ref_class(L, -1, &client_class);
|
||||||
|
next = stack_client_above(c, next);
|
||||||
|
luaA_object_unref(L, c);
|
||||||
|
}
|
||||||
|
else if (luaA_class_get(L, -1) == &drawin_class)
|
||||||
|
{
|
||||||
|
drawin_t *d = luaA_object_ref_class(L, -1, &drawin_class);
|
||||||
|
stack_window_above(d->window, next);
|
||||||
|
next = d->window;
|
||||||
|
luaA_object_unref(L, d);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return luaL_error(L, "set_stacking_order only works on clients and drawins");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* then stack clients */
|
lua_pop(L, 1);
|
||||||
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 drawin window */
|
|
||||||
foreach(drawin, globalconf.drawins)
|
|
||||||
if((*drawin)->ontop)
|
|
||||||
{
|
|
||||||
stack_window_above((*drawin)->window, next);
|
|
||||||
next = (*drawin)->window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
need_stack_refresh = false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
13
stack.h
13
stack.h
|
@ -21,14 +21,17 @@
|
||||||
|
|
||||||
#ifndef AWESOME_STACK_H
|
#ifndef AWESOME_STACK_H
|
||||||
#define AWESOME_STACK_H
|
#define AWESOME_STACK_H
|
||||||
|
#include "luaa.h"
|
||||||
|
#include "objects/client.h"
|
||||||
|
#include "objects/drawin.h"
|
||||||
|
|
||||||
typedef struct client_t client_t;
|
typedef struct client_t client_t;
|
||||||
|
|
||||||
void stack_client_remove(client_t *);
|
void stack_client_remove(lua_State *, client_t *, bool, const char *);
|
||||||
void stack_client_push(client_t *);
|
void stack_client_push(lua_State *, client_t *, const char *);
|
||||||
void stack_client_append(client_t *);
|
void stack_client_append(lua_State *, client_t *, const char *);
|
||||||
void stack_windows(void);
|
void stack_windows(lua_State *, const char *, client_t *, drawin_t *);
|
||||||
void stack_refresh(void);
|
int luaA_set_stacking_order(lua_State *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
Loading…
Reference in New Issue