Skip to content

Commit 17f062e

Browse files
committed
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.
1 parent 1239cdf commit 17f062e

File tree

9 files changed

+237
-152
lines changed

9 files changed

+237
-152
lines changed

event.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -830,8 +830,14 @@ event_handle_maprequest(xcb_map_request_event_t *ev)
830830
luaA_object_push(L, c);
831831
client_set_minimized(L, -1, false);
832832
lua_pop(L, 1);
833-
/* it will be raised, so just update ourself */
834-
client_raise(c);
833+
834+
lua_pushstring(L, "maprequest");
835+
lua_newtable(L);
836+
lua_pushstring(L, "client");
837+
luaA_object_push(L, c);
838+
lua_rawset(L, -3);
839+
840+
luaA_object_emit_signal(L, -3, "request::raise", 2);
835841
}
836842
}
837843
else

event.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ awesome_refresh(void)
4646
drawin_refresh();
4747
client_refresh();
4848
banning_refresh();
49-
stack_refresh();
5049
client_destroy_later();
5150
return xcb_flush(globalconf.connection);
5251
}

lib/awful/layout/init.lua

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@
3434
local ipairs = ipairs
3535
local type = type
3636
local capi = {
37-
screen = screen,
38-
mouse = mouse,
37+
screen = screen,
38+
mouse = mouse,
3939
awesome = awesome,
40-
client = client,
41-
tag = tag
40+
client = client,
41+
drawin = drawin,
42+
tag = tag,
43+
root = root,
4244
}
4345
local tag = require("awful.tag")
4446
local client = require("awful.client")
@@ -55,6 +57,9 @@ end
5557

5658
local layout = {}
5759

60+
-- Avoid restacking the clients and drawins too often.
61+
local need_restack = true
62+
5863
-- Support `table.insert()` to avoid breaking old code.
5964
local default_layouts = setmetatable({}, {
6065
__newindex = function(self, key, value)
@@ -64,6 +69,17 @@ local default_layouts = setmetatable({}, {
6469
end
6570
})
6671

72+
local x11_layers_ordered, x11_layers_keys = {
73+
"WINDOW_LAYER_IGNORE",
74+
"WINDOW_LAYER_DESKTOP",
75+
"WINDOW_LAYER_BELOW",
76+
"WINDOW_LAYER_NORMAL",
77+
"WINDOW_LAYER_ABOVE",
78+
"WINDOW_LAYER_FULLSCREEN",
79+
"WINDOW_LAYER_ONTOP"
80+
}, {}
81+
82+
for k, v in ipairs(x11_layers_ordered) do x11_layers_keys[v] = k end
6783

6884
layout.suit = require("awful.layout.suit")
6985

@@ -108,6 +124,27 @@ local arrange_lock = false
108124
-- Delay one arrange call per screen.
109125
local delayed_arrange = {}
110126

127+
local function client_to_layer(o)
128+
if o.type == "desktop" then
129+
return x11_layers_keys.WINDOW_LAYER_DESKTOP
130+
elseif o.ontop then
131+
-- first deal with user set attributes
132+
return x11_layers_keys.WINDOW_LAYER_ONTOP;
133+
elseif o.fullscreen and capi.client.focus == o then
134+
-- Fullscreen windows only get their own layer when they have the focus
135+
return x11_layers_keys.WINDOW_LAYER_FULLSCREEN;
136+
elseif o.above then
137+
return x11_layers_keys.WINDOW_LAYER_ABOVE;
138+
elseif o.below then
139+
return x11_layers_keys.WINDOW_LAYER_BELOW;
140+
elseif o.transient_for then
141+
-- check for transient attr
142+
return x11_layers_keys.WINDOW_LAYER_IGNORE;
143+
else
144+
return x11_layers_keys.WINDOW_LAYER_NORMAL
145+
end
146+
end
147+
111148
--- Get the current layout.
112149
-- @tparam screen screen The screen.
113150
-- @return The layout function.
@@ -237,6 +274,7 @@ end
237274
-- @tparam screen screen The screen to arrange.
238275
-- @noreturn
239276
-- @staticfct awful.layout.arrange
277+
-- @see restack
240278
function layout.arrange(screen)
241279
screen = get_screen(screen)
242280
if not screen or delayed_arrange[screen] then return end
@@ -417,8 +455,78 @@ function layout.move_handler(c, context, hints) --luacheck: no unused args
417455
end
418456
end
419457

458+
-- [UNDOCUMENTED] Handler for `request::restack`.
459+
--
460+
-- @signalhandler awful.layout.move_handler
461+
-- @tparam string context The context
462+
-- @tparam table hints Additional hints
463+
-- @tparam[opt=nil] client|nil hints.client The client
464+
-- @tparam[opt=nil] drawin|nil hints.drawin Additional hints
465+
function layout._restack_handler(context, hints) -- luacheck: no unused args
466+
--TODO Support permissions
467+
need_restack = true
468+
end
469+
470+
--- Arrange the clients on the Z axis.
471+
-- @staticfct awful.layout.restack
472+
-- @noreturn
473+
-- @see arrange
474+
function layout.restack()
475+
476+
local layers = {}
477+
478+
local function append(o)
479+
local layer = client_to_layer(o)
480+
layers[layer] = layers[layer] or {}
481+
table.insert(layers[layer], 1, o.drawin and o.drawin or o)
482+
end
483+
484+
for _, c in ipairs(capi.client.get(nil, true)) do append(c) end
485+
486+
for _, d in ipairs(capi.drawin.get()) do
487+
append(d.get_wibox())
488+
end
489+
490+
local result = {}
491+
492+
for i=#x11_layers_ordered, 1, -1 do
493+
if layers[i] then
494+
for _, v in ipairs(layers[i] or {}) do
495+
table.insert(result, v)
496+
end
497+
end
498+
end
499+
500+
capi.root.set_stacking_order(result)
501+
end
502+
420503
capi.client.connect_signal("request::geometry", layout.move_handler)
421504

505+
-- Translate the `request::raise`, which will trigger a `"request::restack"`.
506+
capi.client.connect_signal("request::raise", function(c, context, hints) --luacheck: no unused args
507+
hints.client:raise()
508+
end)
509+
510+
capi.client.connect_signal("request::restack", layout._restack_handler)
511+
512+
-- Check if the type is `"desktop"`, which goes below everything.
513+
for _, class in ipairs(capi.client, capi.drawin) do
514+
class.connect_signal("property::type", function(o)
515+
capi.client.emit_signal("request::restack", "type", {
516+
client = o.modal ~= nil and o or nil,
517+
drawin = o.modal == nil and o or nil,
518+
})
519+
end)
520+
end
521+
522+
-- Place the clients and drawin on top of each other.
523+
capi.awesome.connect_signal("refresh", function()
524+
if need_restack then
525+
layout.restack()
526+
need_restack = false
527+
end
528+
end)
529+
422530
-- When a screen is moved, make (floating) clients follow it
423531
capi.screen.connect_signal("property::geometry", function(s, old_geom)
424532
local geom = s.geometry

objects/client.c

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2241,7 +2241,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, xcb_get_window_at
22412241
ewmh_client_check_hints(c);
22422242

22432243
/* Push client in stack */
2244-
stack_client_push(c);
2244+
stack_client_push(L, c, "manage");
22452245

22462246
/* Request our response */
22472247
xcb_get_property_reply_t *reply =
@@ -2717,7 +2717,7 @@ client_set_fullscreen(lua_State *L, int cidx, bool s)
27172717
luaA_object_emit_signal(L, abs_cidx, "property::fullscreen", 0);
27182718
/* Force a client resize, so that titlebars get shown/hidden */
27192719
client_resize_do(c, c->geometry);
2720-
stack_windows();
2720+
stack_windows(L, "fullscreen", c, NULL);
27212721
}
27222722
}
27232723

@@ -2768,7 +2768,7 @@ client_set_maximized_common(lua_State *L, int cidx, bool s, const char* type, co
27682768
if(max_before != c->maximized)
27692769
luaA_object_emit_signal(L, abs_cidx, "property::maximized", 0);
27702770

2771-
stack_windows();
2771+
stack_windows(L, "maximized", c, NULL);
27722772
}
27732773
}
27742774

@@ -2816,7 +2816,7 @@ client_set_above(lua_State *L, int cidx, bool s)
28162816
client_set_fullscreen(L, cidx, false);
28172817
}
28182818
c->above = s;
2819-
stack_windows();
2819+
stack_windows(L, "above", c, NULL);
28202820
luaA_object_emit_signal(L, cidx, "property::above", 0);
28212821
}
28222822
}
@@ -2841,7 +2841,7 @@ client_set_below(lua_State *L, int cidx, bool s)
28412841
client_set_fullscreen(L, cidx, false);
28422842
}
28432843
c->below = s;
2844-
stack_windows();
2844+
stack_windows(L, "below", c, NULL);
28452845
luaA_object_emit_signal(L, cidx, "property::below", 0);
28462846
}
28472847
}
@@ -2859,7 +2859,7 @@ client_set_modal(lua_State *L, int cidx, bool s)
28592859
if(c->modal != s)
28602860
{
28612861
c->modal = s;
2862-
stack_windows();
2862+
stack_windows(L, "modal", c, NULL);
28632863
luaA_object_emit_signal(L, cidx, "property::modal", 0);
28642864
}
28652865
}
@@ -2884,7 +2884,7 @@ client_set_ontop(lua_State *L, int cidx, bool s)
28842884
client_set_fullscreen(L, cidx, false);
28852885
}
28862886
c->ontop = s;
2887-
stack_windows();
2887+
stack_windows(L, "ontop", c, NULL);
28882888
luaA_object_emit_signal(L, cidx, "property::ontop", 0);
28892889
}
28902890
}
@@ -2942,7 +2942,7 @@ client_unmanage(client_t *c, client_unmanage_t reason)
29422942
client_array_remove(&globalconf.clients, elem);
29432943
break;
29442944
}
2945-
stack_client_remove(c);
2945+
stack_client_remove(L, c, false, "unmanage");
29462946
for(int i = 0; i < globalconf.tags.len; i++)
29472947
untag_client(c, globalconf.tags.tab[i]);
29482948

@@ -3402,7 +3402,29 @@ luaA_client_raise(lua_State *L)
34023402
)
34033403
return 0;
34043404

3405-
client_raise(c);
3405+
client_t *tc = c;
3406+
int counter = 0;
3407+
3408+
/* Find number of transient layers. */
3409+
for(counter = 0; tc->transient_for; counter++)
3410+
tc = tc->transient_for;
3411+
3412+
/* Push them in reverse order. */
3413+
for(; counter > 0; counter--)
3414+
{
3415+
tc = c;
3416+
for(int i = 0; i < counter; i++)
3417+
tc = tc->transient_for;
3418+
stack_client_append(L, tc, "raise");
3419+
}
3420+
3421+
/* Push c on top of the stack. */
3422+
stack_client_append(L, c, "raise");
3423+
3424+
/* Notify the listeners */
3425+
luaA_object_push(L, c);
3426+
luaA_object_emit_signal(L, -1, "raised", 0);
3427+
lua_pop(L, 1);
34063428

34073429
return 0;
34083430
}
@@ -3426,11 +3448,11 @@ luaA_client_lower(lua_State *L)
34263448
if (globalconf.stack.len && globalconf.stack.tab[0] == c)
34273449
return 0;
34283450

3429-
stack_client_push(c);
3451+
stack_client_push(L, c, "lower");
34303452

34313453
/* Traverse all transient layers. */
34323454
for(client_t *tc = c->transient_for; tc; tc = tc->transient_for)
3433-
stack_client_push(tc);
3455+
stack_client_push(L, tc, "lower");
34343456

34353457
/* Notify the listeners */
34363458
luaA_object_push(L, c);

objects/client.h

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -258,38 +258,6 @@ drawable_t *client_get_drawable(client_t *, int, int);
258258
drawable_t *client_get_drawable_offset(client_t *, int *, int *);
259259
area_t client_get_undecorated_geometry(client_t *);
260260

261-
/** Put client on top of the stack.
262-
* \param c The client to raise.
263-
*/
264-
static inline void
265-
client_raise(client_t *c)
266-
{
267-
client_t *tc = c;
268-
int counter = 0;
269-
270-
/* Find number of transient layers. */
271-
for(counter = 0; tc->transient_for; counter++)
272-
tc = tc->transient_for;
273-
274-
/* Push them in reverse order. */
275-
for(; counter > 0; counter--)
276-
{
277-
tc = c;
278-
for(int i = 0; i < counter; i++)
279-
tc = tc->transient_for;
280-
stack_client_append(tc);
281-
}
282-
283-
/* Push c on top of the stack. */
284-
stack_client_append(c);
285-
286-
/* Notify the listeners */
287-
lua_State *L = globalconf_get_lua_State();
288-
luaA_object_push(L, c);
289-
luaA_object_emit_signal(L, -1, "raised", 0);
290-
lua_pop(L, 1);
291-
}
292-
293261
/** Check if a client has fixed size.
294262
* \param c A client.
295263
* \return A boolean value, true if the client has a fixed size.

objects/drawin.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ drawin_map(lua_State *L, int widx)
336336
/* Deactivate BMA */
337337
client_restore_enterleave_events();
338338
/* Stack this drawin correctly */
339-
stack_windows();
339+
stack_windows(L, "append", NULL, drawin);
340340
/* Add it to the list of visible drawins */
341341
drawin_array_append(&globalconf.drawins, drawin);
342342
/* Make sure it has a surface */
@@ -591,7 +591,7 @@ luaA_drawin_set_ontop(lua_State *L, drawin_t *drawin)
591591
if(b != drawin->ontop)
592592
{
593593
drawin->ontop = b;
594-
stack_windows();
594+
stack_windows(L, "ontop", NULL, drawin);
595595
luaA_object_emit_signal(L, -3, "property::ontop", 0);
596596
}
597597
return 0;

root.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "objects/button.h"
4343
#include "common/luaclass.h"
4444
#include "xwindow.h"
45+
#include "stack.h"
4546

4647
#include "math.h"
4748

@@ -653,6 +654,7 @@ const struct luaL_Reg awesome_root_methods[] =
653654
{ "tags", luaA_root_tags },
654655
{ "__index", luaA_root_index },
655656
{ "__newindex", luaA_root_newindex },
657+
{ "set_stacking_order", luaA_set_stacking_order},
656658
{ "set_index_miss_handler", luaA_root_set_index_miss_handler},
657659
{ "set_call_handler", luaA_root_set_call_handler},
658660
{ "set_newindex_miss_handler", luaA_root_set_newindex_miss_handler},

0 commit comments

Comments
 (0)