Improved swallowing (#140)

* Make swallowing more robust

Changed the flags for the pstree command so it is a single line with all
ancestors.
Removed usage of sed, grep and tr so the iopopen call should be faster.
Find and match of parent pid in the ancestors string is done in lua so
should be faster.

* Improved swallow filter

Now you cna filter window swallowing with 2 tables, one for clients that
cannot be swallowed (dont_swallow_classname_list) and one for clients
that cannot swallow their parents (cant_swallow_classname_list).

* remove occurences of res var

* renamed functions and theme vars more descriptive

* updated module documentation

* check functions combined, is_in_table  1 return

* add old theme vars for compatibility

* short swallow logic and robust filter assignment

* ignore splash and dialog parents

this prevents krita and similar missbehaving programs from swallowing their
splash window.

* consistent docs formatting

* convert module to use an async function

* removed undefined error() function call
this was probably an error handling/logging on the code i used as template for
the async function and it's callback.

* deal with corner case: parent exits before client

if the parent is destroyed "on background" then awesome will show a warning.

* added meself to authors

i don't see my additions as substantial enough to justify this but... ¯\_(ツ)_/¯
This commit is contained in:
eylles 2022-01-04 04:14:12 -06:00 committed by GitHub
parent e0423796b0
commit 7542251b72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 27 deletions

View File

@ -7,3 +7,4 @@ The following developers have contributed major code to bling:
* [HumblePresent](https://github.com/HumblePresent)
* [Kasper24](https://github.com/Kasper24)
* [undefinedDarkness](https://github.com/undefinedDarkness)
* [eylles](https://github.com/eylles)

View File

@ -13,8 +13,9 @@ bling.module.window_swallowing.toggle() -- toggles window swallowing
### Theme Variables
```lua
theme.dont_swallow_classname_list = {"firefox", "Gimp"} -- list of class names that should not be swallowed
theme.dont_swallow_filter_activated = true -- whether the filter above should be active
theme.parent_filter_list = {"firefox", "Gimp"} -- class names list of parents that should not be swallowed
theme.child_filter_list = { "Dragon" } -- class names list that should not swallow their parents
theme.swallowing_filter = true -- whether the filters above should be active
```
### Preview

View File

@ -11,53 +11,93 @@ local helpers = require(tostring(...):match(".*bling") .. ".helpers")
local window_swallowing_activated = false
-- you might want to add or remove applications here
local dont_swallow_classname_list = beautiful.dont_swallow_classname_list
local parent_filter_list = beautiful.parent_filter_list
or beautiful.dont_swallow_classname_list
or { "firefox", "Gimp", "Google-chrome" }
local activate_dont_swallow_filter = beautiful.dont_swallow_filter_activated
or true
local child_filter_list = beautiful.child_filter_list
or beautiful.dont_swallow_classname_list or { }
-- checks if client classname matches with any entry of the dont-swallow-list
local function check_if_swallow(c)
if not activate_dont_swallow_filter then
return true
end
for _, classname in ipairs(dont_swallow_classname_list) do
if classname == c.class then
return false
-- for boolean values the or chain way to set the values breaks with 2 vars
-- and always defaults to true so i had to do this to se the right value...
local swallowing_filter = true
local filter_vars = { beautiful.swallowing_filter, beautiful.dont_swallow_filter_activated }
for _, var in pairs(filter_vars) do
swallowing_filter = var
end
-- check if element exist in table
-- returns true if it is
local function is_in_table(element, table)
local res = false
for _, value in pairs(table) do
if element:match(value) then
res = true
break
end
end
return true
return res
end
-- if the swallowing filter is active checks the child and parent classes
-- against their filters
local function check_swallow(parent, child)
local res = true
if swallowing_filter then
local prnt = not is_in_table(parent, parent_filter_list)
local chld = not is_in_table(child, child_filter_list)
res = ( prnt and chld )
end
return res
end
-- async function to get the parent's pid
-- recieves a child process pid and a callback function
-- parent_pid in format "init(1)---ancestorA(pidA)---ancestorB(pidB)...---process(pid)"
function get_parent_pid(child_ppid, callback)
local ppid_cmd = string.format("pstree -A -p -s %s", child_ppid)
awful.spawn.easy_async(ppid_cmd, function(stdout, stderr, reason, exit_code)
-- primitive error checking
if stderr and stderr ~= "" then
callback(stderr)
return
end
local ppid = stdout
callback(nil, ppid)
end)
end
-- the function that will be connected to / disconnected from the spawn client signal
local function manage_clientspawn(c)
-- get the last focused window to check if it is a parent window
local parent_client = awful.client.focus.history.get(c.screen, 1)
if not parent_client then
return
elseif parent_client.type == "dialog" or parent_client.type == "splash" then
return
end
-- io.popen is normally discouraged. Should probably be changed
local handle = io.popen(
[[pstree -T -p -a -s ]]
.. tostring(c.pid)
.. [[ | sed '2q;d' | grep -o '[0-9]*$' | tr -d '\n']]
)
local parent_pid = handle:read("*a")
handle:close()
get_parent_pid(c.pid, function(err, ppid)
if err then
return
end
parent_pid = ppid
if
(tostring(parent_pid) == tostring(parent_client.pid))
and check_if_swallow(c)
-- will search for "(parent_client.pid)" inside the parent_pid string
( tostring(parent_pid):find("("..tostring(parent_client.pid)..")") )
and check_swallow(parent_client.class, c.class)
then
c:connect_signal("unmanage", function()
helpers.client.turn_on(parent_client)
helpers.client.sync(parent_client, c)
if parent_client then
helpers.client.turn_on(parent_client)
helpers.client.sync(parent_client, c)
end
end)
helpers.client.sync(c, parent_client)
helpers.client.turn_off(parent_client)
end
end)
end
-- without the following functions that module would be autoloaded by require("bling")