Skip to content

Commit

Permalink
client: Rewrite the client stacking code in Lua.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Elv13 committed Dec 12, 2022
1 parent 1239cdf commit fac155d
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 152 deletions.
10 changes: 8 additions & 2 deletions event.c
Original file line number Diff line number Diff line change
Expand Up @@ -830,8 +830,14 @@ event_handle_maprequest(xcb_map_request_event_t *ev)
luaA_object_push(L, c);
client_set_minimized(L, -1, false);
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
Expand Down
1 change: 0 additions & 1 deletion event.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ awesome_refresh(void)
drawin_refresh();
client_refresh();
banning_refresh();
stack_refresh();
client_destroy_later();
return xcb_flush(globalconf.connection);
}
Expand Down
120 changes: 116 additions & 4 deletions lib/awful/layout/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@
local ipairs = ipairs
local type = type
local capi = {
screen = screen,
mouse = mouse,
screen = screen,
mouse = mouse,
awesome = awesome,
client = client,
tag = tag
client = client,
drawin = drawin,
tag = tag,
root = root,
}
local tag = require("awful.tag")
local client = require("awful.client")
Expand All @@ -55,6 +57,9 @@ end

local layout = {}

-- Avoid restacking the clients and drawins too often.
local need_restack = true

-- Support `table.insert()` to avoid breaking old code.
local default_layouts = setmetatable({}, {
__newindex = function(self, key, value)
Expand All @@ -64,6 +69,17 @@ local default_layouts = setmetatable({}, {
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")

Expand Down Expand Up @@ -108,6 +124,27 @@ local arrange_lock = false
-- Delay one arrange call per screen.
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.
-- @tparam screen screen The screen.
-- @return The layout function.
Expand Down Expand Up @@ -237,6 +274,7 @@ end
-- @tparam screen screen The screen to arrange.
-- @noreturn
-- @staticfct awful.layout.arrange
-- @see restack
function layout.arrange(screen)
screen = get_screen(screen)
if not screen or delayed_arrange[screen] then return end
Expand Down Expand Up @@ -417,8 +455,82 @@ function layout.move_handler(c, context, hints) --luacheck: no unused args
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, drawin)
local layer = client_to_layer(o)
layers[layer] = layers[layer] or {}
if drawin then
table.insert(layers[layer], o.drawin)
else
table.insert(layers[layer], 1, o)
end
end

for _, c in ipairs(capi.client.get(nil, true)) do append(c) end

for _, d in ipairs(capi.drawin.get()) do
append(d.get_wibox(), true)
end

local result = {}

for i=#x11_layers_ordered, 1, -1 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)

-- 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
capi.screen.connect_signal("property::geometry", function(s, old_geom)
local geom = s.geometry
Expand Down
44 changes: 33 additions & 11 deletions objects/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/* Push client in stack */
stack_client_push(c);
stack_client_push(L, c, "manage");

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

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

stack_windows();
stack_windows(L, "maximized", c, NULL);
}
}

Expand Down Expand Up @@ -2816,7 +2816,7 @@ client_set_above(lua_State *L, int cidx, bool s)
client_set_fullscreen(L, cidx, false);
}
c->above = s;
stack_windows();
stack_windows(L, "above", c, NULL);
luaA_object_emit_signal(L, cidx, "property::above", 0);
}
}
Expand All @@ -2841,7 +2841,7 @@ client_set_below(lua_State *L, int cidx, bool s)
client_set_fullscreen(L, cidx, false);
}
c->below = s;
stack_windows();
stack_windows(L, "below", c, NULL);
luaA_object_emit_signal(L, cidx, "property::below", 0);
}
}
Expand All @@ -2859,7 +2859,7 @@ client_set_modal(lua_State *L, int cidx, bool s)
if(c->modal != s)
{
c->modal = s;
stack_windows();
stack_windows(L, "modal", c, NULL);
luaA_object_emit_signal(L, cidx, "property::modal", 0);
}
}
Expand All @@ -2884,7 +2884,7 @@ client_set_ontop(lua_State *L, int cidx, bool s)
client_set_fullscreen(L, cidx, false);
}
c->ontop = s;
stack_windows();
stack_windows(L, "ontop", c, NULL);
luaA_object_emit_signal(L, cidx, "property::ontop", 0);
}
}
Expand Down Expand Up @@ -2942,7 +2942,7 @@ client_unmanage(client_t *c, client_unmanage_t reason)
client_array_remove(&globalconf.clients, elem);
break;
}
stack_client_remove(c);
stack_client_remove(L, c, false, "unmanage");
for(int i = 0; i < globalconf.tags.len; i++)
untag_client(c, globalconf.tags.tab[i]);

Expand Down Expand Up @@ -3402,7 +3402,29 @@ luaA_client_raise(lua_State *L)
)
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;
}
Expand All @@ -3426,11 +3448,11 @@ luaA_client_lower(lua_State *L)
if (globalconf.stack.len && globalconf.stack.tab[0] == c)
return 0;

stack_client_push(c);
stack_client_push(L, c, "lower");

/* Traverse all transient layers. */
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 */
luaA_object_push(L, c);
Expand Down
32 changes: 0 additions & 32 deletions objects/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,38 +258,6 @@ drawable_t *client_get_drawable(client_t *, int, int);
drawable_t *client_get_drawable_offset(client_t *, int *, int *);
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.
* \param c A client.
* \return A boolean value, true if the client has a fixed size.
Expand Down
4 changes: 2 additions & 2 deletions objects/drawin.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ drawin_map(lua_State *L, int widx)
/* Deactivate BMA */
client_restore_enterleave_events();
/* Stack this drawin correctly */
stack_windows();
stack_windows(L, "append", NULL, drawin);
/* Add it to the list of visible drawins */
drawin_array_append(&globalconf.drawins, drawin);
/* Make sure it has a surface */
Expand Down Expand Up @@ -591,7 +591,7 @@ luaA_drawin_set_ontop(lua_State *L, drawin_t *drawin)
if(b != drawin->ontop)
{
drawin->ontop = b;
stack_windows();
stack_windows(L, "ontop", NULL, drawin);
luaA_object_emit_signal(L, -3, "property::ontop", 0);
}
return 0;
Expand Down
2 changes: 2 additions & 0 deletions root.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "objects/button.h"
#include "common/luaclass.h"
#include "xwindow.h"
#include "stack.h"

#include "math.h"

Expand Down Expand Up @@ -653,6 +654,7 @@ const struct luaL_Reg awesome_root_methods[] =
{ "tags", luaA_root_tags },
{ "__index", luaA_root_index },
{ "__newindex", luaA_root_newindex },
{ "set_stacking_order", luaA_set_stacking_order},
{ "set_index_miss_handler", luaA_root_set_index_miss_handler},
{ "set_call_handler", luaA_root_set_call_handler},
{ "set_newindex_miss_handler", luaA_root_set_newindex_miss_handler},
Expand Down
Loading

0 comments on commit fac155d

Please sign in to comment.