local awful = require("awful") local gears = require("gears") local beautiful = require("beautiful") local helpers = require(tostring(...):match(".*bling") .. ".helpers") -- It might actually swallow too much, that's why there is a filter option by classname -- without the don't-swallow-list it would also swallow for example -- file pickers or new firefox windows spawned by an already existing one local window_swallowing_activated = false -- you might want to add or remove applications here local parent_filter_list = beautiful.parent_filter_list or beautiful.dont_swallow_classname_list or { "firefox", "Gimp", "Google-chrome" } local child_filter_list = beautiful.child_filter_list or beautiful.dont_swallow_classname_list or { } -- 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 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 get_parent_pid(c.pid, function(err, ppid) if err then return end parent_pid = ppid if -- 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() 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") -- a toggle window swallowing hotkey is also possible that way local function start() client.connect_signal("manage", manage_clientspawn) window_swallowing_activated = true end local function stop() client.disconnect_signal("manage", manage_clientspawn) window_swallowing_activated = false end local function toggle() if window_swallowing_activated then stop() else start() end end return { start = start, stop = stop, toggle = toggle, }