Fuxx
This commit is contained in:
parent
8268fba83d
commit
7ed2a6e110
9565 changed files with 1315332 additions and 90 deletions
39
home/.config/awesome/lib/bling/module/flash_focus.lua
Normal file
39
home/.config/awesome/lib/bling/module/flash_focus.lua
Normal file
|
@ -0,0 +1,39 @@
|
|||
local gears = require("gears")
|
||||
local beautiful = require("beautiful")
|
||||
|
||||
local op = beautiful.flash_focus_start_opacity or 0.6
|
||||
local stp = beautiful.flash_focus_step or 0.01
|
||||
|
||||
local flashfocus = function(c)
|
||||
if c and #c.screen.clients > 1 then
|
||||
c.opacity = op
|
||||
local q = op
|
||||
local g = gears.timer({
|
||||
timeout = stp,
|
||||
call_now = false,
|
||||
autostart = true,
|
||||
})
|
||||
|
||||
g:connect_signal("timeout", function()
|
||||
if not c.valid then
|
||||
return
|
||||
end
|
||||
if q >= 1 then
|
||||
c.opacity = 1
|
||||
g:stop()
|
||||
else
|
||||
c.opacity = q
|
||||
q = q + stp
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local enable = function()
|
||||
client.connect_signal("focus", flashfocus)
|
||||
end
|
||||
local disable = function()
|
||||
client.disconnect_signal("focus", flashfocus)
|
||||
end
|
||||
|
||||
return { enable = enable, disable = disable, flashfocus = flashfocus }
|
8
home/.config/awesome/lib/bling/module/init.lua
Normal file
8
home/.config/awesome/lib/bling/module/init.lua
Normal file
|
@ -0,0 +1,8 @@
|
|||
return {
|
||||
window_swallowing = require(... .. ".window_swallowing"),
|
||||
tiled_wallpaper = require(... .. ".tiled_wallpaper"),
|
||||
wallpaper = require(... .. ".wallpaper"),
|
||||
flash_focus = require(... .. ".flash_focus"),
|
||||
tabbed = require(... .. ".tabbed"),
|
||||
scratchpad = require(... .. ".scratchpad"),
|
||||
}
|
374
home/.config/awesome/lib/bling/module/scratchpad.lua
Normal file
374
home/.config/awesome/lib/bling/module/scratchpad.lua
Normal file
|
@ -0,0 +1,374 @@
|
|||
local awful = require("awful")
|
||||
local gears = require("gears")
|
||||
local naughty = require("naughty")
|
||||
local helpers = require(tostring(...):match(".*bling") .. ".helpers")
|
||||
local capi = { awesome = awesome, client = client }
|
||||
local ruled = capi.awesome.version ~= "v4.3" and require("ruled") or nil
|
||||
local pairs = pairs
|
||||
|
||||
local Scratchpad = { mt = {} }
|
||||
|
||||
--- Called when the turn off animation has ended
|
||||
local function on_animate_turn_off_end(self, tag)
|
||||
-- When toggling off a scratchpad that's present on multiple tags
|
||||
-- depsite still being unminizmied on the other tags it will become invisible
|
||||
-- as it's position could be outside the screen from the animation
|
||||
self.client:geometry({
|
||||
x = self.geometry.x + self.client.screen.geometry.x,
|
||||
y = self.geometry.y + self.client.screen.geometry.y,
|
||||
width = self.geometry.width,
|
||||
height = self.geometry.height,
|
||||
})
|
||||
|
||||
helpers.client.turn_off(self.client, tag)
|
||||
|
||||
self.turning_off = false
|
||||
|
||||
self:emit_signal("turn_off", self.client)
|
||||
end
|
||||
|
||||
--- The turn off animation
|
||||
local function animate_turn_off(self, anim, axis)
|
||||
self.screen_on_toggled_scratchpad = self.client.screen
|
||||
self.tag_on_toggled_scratchpad = self.screen_on_toggled_scratchpad.selected_tag
|
||||
|
||||
if self.client.floating == false then
|
||||
-- Save the client geometry before floating it
|
||||
local non_floating_x = self.client.x
|
||||
local non_floating_y = self.client.y
|
||||
local non_floating_width = self.client.width
|
||||
local non_floating_height = self.client.height
|
||||
|
||||
-- Can't animate non floating clients
|
||||
self.client.floating = true
|
||||
|
||||
-- Set the client geometry back to what it was before floating it
|
||||
self.client:geometry({
|
||||
x = non_floating_x,
|
||||
y = non_floating_y,
|
||||
width = non_floating_width,
|
||||
height = non_floating_height,
|
||||
})
|
||||
end
|
||||
|
||||
if axis == "x" then
|
||||
anim.pos = self.client.x
|
||||
else
|
||||
anim.pos = self.client.y
|
||||
end
|
||||
|
||||
anim:set(anim:initial())
|
||||
end
|
||||
|
||||
-- Handles changing tag mid animation
|
||||
local function abort_if_tag_was_switched(self)
|
||||
-- Check for the following scenerio:
|
||||
-- Toggle on scratchpad at tag 1
|
||||
-- Toggle on scratchpad at tag 2
|
||||
-- Toggle off scratchpad at tag 1
|
||||
-- Switch to tag 2
|
||||
-- Outcome: The client will remain on tag 1 and will instead be removed from tag 2
|
||||
if (self.turning_off) and (self.screen_on_toggled_scratchpad and
|
||||
self.screen_on_toggled_scratchpad.selected_tag) ~= self.tag_on_toggled_scratchpad
|
||||
then
|
||||
if self.rubato.x then
|
||||
self.rubato.x:abort()
|
||||
end
|
||||
if self.rubato.y then
|
||||
self.rubato.y:abort()
|
||||
end
|
||||
on_animate_turn_off_end(self, self.tag_on_toggled_scratchpad)
|
||||
self.screen_on_toggled_scratchpad.selected_tag = nil
|
||||
self.tag_on_toggled_scratchpad = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- The turn on animation
|
||||
local function animate_turn_on(self, anim, axis)
|
||||
-- Check for the following scenerio:
|
||||
-- Toggle on scratchpad at tag 1
|
||||
-- Toggle on scratchpad at tag 2
|
||||
-- The animation will instantly end
|
||||
-- as the timer pos is already at the on position
|
||||
-- from toggling on the scratchpad at tag 1
|
||||
if axis == "x" and anim.pos == self.geometry.x then
|
||||
anim.pos = anim:initial()
|
||||
else
|
||||
if anim.pos == self.geometry.y then
|
||||
anim.pos = anim:initial()
|
||||
end
|
||||
end
|
||||
|
||||
if axis == "x" then
|
||||
anim:set(self.geometry.x)
|
||||
else
|
||||
anim:set(self.geometry.y)
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a new scratchpad object based on the argument
|
||||
--
|
||||
-- @param args A table of possible arguments
|
||||
-- @return The new scratchpad object
|
||||
function Scratchpad:new(args)
|
||||
args = args or {}
|
||||
if args.awestore then
|
||||
naughty.notify({
|
||||
title = "Bling Error",
|
||||
text = "Awestore is no longer supported! Please take a look at the scratchpad documentation and use rubato for animations instead.",
|
||||
})
|
||||
end
|
||||
|
||||
args.rubato = args.rubato or {}
|
||||
|
||||
local ret = gears.object{}
|
||||
gears.table.crush(ret, Scratchpad)
|
||||
gears.table.crush(ret, args)
|
||||
|
||||
if ret.rubato.x then
|
||||
ret.rubato.x:subscribe(function(pos)
|
||||
if ret.client and ret.client.valid then
|
||||
ret.client.x = pos
|
||||
end
|
||||
abort_if_tag_was_switched(ret)
|
||||
end)
|
||||
|
||||
ret.rubato.x.ended:subscribe(function()
|
||||
if ((ret.rubato.y and ret.rubato.y.state == false) or (ret.rubato.y == nil)) and ret.turning_off == true then
|
||||
on_animate_turn_off_end(ret)
|
||||
end
|
||||
end)
|
||||
end
|
||||
if ret.rubato.y then
|
||||
ret.rubato.y:subscribe(function(pos)
|
||||
if ret.client and ret.client.valid then
|
||||
ret.client.y = pos
|
||||
end
|
||||
abort_if_tag_was_switched(ret)
|
||||
end)
|
||||
|
||||
ret.rubato.y.ended:subscribe(function()
|
||||
if ((ret.rubato.x and ret.rubato.x.state == false) or (ret.rubato.x == nil)) and ret.turning_off == true then
|
||||
on_animate_turn_off_end(ret)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Find all clients that satisfy the the rule
|
||||
--
|
||||
-- @return A list of all clients that satisfy the rule
|
||||
function Scratchpad:find()
|
||||
return helpers.client.find(self.rule)
|
||||
end
|
||||
|
||||
--- Applies the objects scratchpad properties to a given client
|
||||
--
|
||||
-- @param c A client to which to apply the properties
|
||||
function Scratchpad:apply(c)
|
||||
if not c or not c.valid then
|
||||
return
|
||||
end
|
||||
c.floating = self.floating
|
||||
c.sticky = self.sticky
|
||||
c.fullscreen = false
|
||||
c.maximized = false
|
||||
c:geometry({
|
||||
x = self.geometry.x + awful.screen.focused().geometry.x,
|
||||
y = self.geometry.y + awful.screen.focused().geometry.y,
|
||||
width = self.geometry.width,
|
||||
height = self.geometry.height,
|
||||
})
|
||||
|
||||
if self.autoclose then
|
||||
c:connect_signal("unfocus", function(c1)
|
||||
c1.sticky = false -- client won't turn off if sticky
|
||||
helpers.client.turn_off(c1)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
--- Turns the scratchpad on
|
||||
function Scratchpad:turn_on()
|
||||
self.client = self:find()[1]
|
||||
|
||||
local anim_x = self.rubato.x
|
||||
local anim_y = self.rubato.y
|
||||
|
||||
local in_anim = false
|
||||
if (anim_x and anim_x.state == true) or (anim_y and anim_y.state == true) then
|
||||
in_anim = true
|
||||
end
|
||||
|
||||
if self.client and not in_anim and self.client.first_tag and self.client.first_tag.selected then
|
||||
self.client:raise()
|
||||
capi.client.focus = self.client
|
||||
return
|
||||
end
|
||||
if self.client and not in_anim then
|
||||
-- if a client was found, turn it on
|
||||
if self.reapply then
|
||||
self:apply(self.client)
|
||||
end
|
||||
-- c.sticky was set to false in turn_off so it has to be reapplied anyway
|
||||
self.client.sticky = self.sticky
|
||||
|
||||
if anim_x then
|
||||
animate_turn_on(self, anim_x, "x")
|
||||
end
|
||||
if anim_y then
|
||||
animate_turn_on(self, anim_y, "y")
|
||||
end
|
||||
|
||||
helpers.client.turn_on(self.client)
|
||||
self:emit_signal("turn_on", self.client)
|
||||
|
||||
return
|
||||
end
|
||||
if not self.client then
|
||||
-- if no client was found, spawn one, find the corresponding window,
|
||||
-- apply the properties only once (until the next closing)
|
||||
local pid = awful.spawn.with_shell(self.command)
|
||||
if capi.awesome.version ~= "v4.3" then
|
||||
ruled.client.append_rule({
|
||||
id = "scratchpad",
|
||||
rule = self.rule,
|
||||
properties = {
|
||||
-- If a scratchpad is opened it should spawn at the current tag
|
||||
-- the same way it will behave if the client was already open
|
||||
tag = awful.screen.focused().selected_tag,
|
||||
switch_to_tags = false,
|
||||
-- Hide the client until the gemoetry rules are applied
|
||||
hidden = true,
|
||||
minimized = true,
|
||||
},
|
||||
callback = function(c)
|
||||
-- For a reason I can't quite get the gemotery rules will fail to apply unless we use this timer
|
||||
gears.timer({
|
||||
timeout = 0.15,
|
||||
autostart = true,
|
||||
single_shot = true,
|
||||
callback = function()
|
||||
self.client = c
|
||||
|
||||
self:apply(c)
|
||||
c.hidden = false
|
||||
c.minimized = false
|
||||
-- Some clients fail to gain focus
|
||||
c:activate({})
|
||||
|
||||
if anim_x then
|
||||
animate_turn_on(self, anim_x, "x")
|
||||
end
|
||||
if anim_y then
|
||||
animate_turn_on(self, anim_y, "y")
|
||||
end
|
||||
|
||||
self:emit_signal("inital_apply", c)
|
||||
|
||||
-- Discord spawns 2 windows, so keep the rule until the 2nd window shows
|
||||
if c.name ~= "Discord Updater" then
|
||||
ruled.client.remove_rule("scratchpad")
|
||||
end
|
||||
-- In a case Discord is killed before the second window spawns
|
||||
c:connect_signal("request::unmanage", function()
|
||||
ruled.client.remove_rule("scratchpad")
|
||||
end)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
})
|
||||
else
|
||||
local function inital_apply(c1)
|
||||
if helpers.client.is_child_of(c1, pid) then
|
||||
self.client = c1
|
||||
|
||||
self:apply(c1)
|
||||
if anim_x then
|
||||
animate_turn_on(self, anim_x, "x")
|
||||
end
|
||||
if anim_y then
|
||||
animate_turn_on(self, anim_y, "y")
|
||||
end
|
||||
self:emit_signal("inital_apply", c1)
|
||||
client.disconnect_signal("manage", inital_apply)
|
||||
end
|
||||
end
|
||||
client.connect_signal("manage", inital_apply)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Turns the scratchpad off
|
||||
function Scratchpad:turn_off()
|
||||
self.client = self:find()[1]
|
||||
|
||||
-- Get the tweens
|
||||
local anim_x = self.rubato.x
|
||||
local anim_y = self.rubato.y
|
||||
|
||||
local in_anim = false
|
||||
if (anim_x and anim_x.state == true) or (anim_y and anim_y.state == true) then
|
||||
in_anim = true
|
||||
end
|
||||
|
||||
if self.client and not in_anim then
|
||||
if anim_x then
|
||||
self.turning_off = true
|
||||
animate_turn_off(self, anim_x, "x")
|
||||
end
|
||||
if anim_y then
|
||||
self.turning_off = true
|
||||
animate_turn_off(self, anim_y, "y")
|
||||
end
|
||||
|
||||
if not anim_x and not anim_y then
|
||||
helpers.client.turn_off(self.client)
|
||||
self:emit_signal("turn_off", self.client)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Turns the scratchpad off if it is focused otherwise it raises the scratchpad
|
||||
function Scratchpad:toggle()
|
||||
local is_turn_off = false
|
||||
local c = self:find()[1]
|
||||
if self.dont_focus_before_close then
|
||||
if c then
|
||||
if c.sticky and #c:tags() > 0 then
|
||||
is_turn_off = true
|
||||
else
|
||||
local current_tag = c.screen.selected_tag
|
||||
for k, tag in pairs(c:tags()) do
|
||||
if tag == current_tag then
|
||||
is_turn_off = true
|
||||
break
|
||||
else
|
||||
is_turn_off = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
is_turn_off = capi.client.focus
|
||||
and awful.rules.match(capi.client.focus, self.rule)
|
||||
end
|
||||
|
||||
if is_turn_off then
|
||||
self:turn_off()
|
||||
else
|
||||
self:turn_on()
|
||||
end
|
||||
end
|
||||
|
||||
--- Make the module callable without putting a `:new` at the end of it
|
||||
--
|
||||
-- @param args A table of possible arguments
|
||||
-- @return The new scratchpad object
|
||||
function Scratchpad.mt:__call(...)
|
||||
return Scratchpad:new(...)
|
||||
end
|
||||
|
||||
return setmetatable(Scratchpad, Scratchpad.mt)
|
276
home/.config/awesome/lib/bling/module/tabbed.lua
Normal file
276
home/.config/awesome/lib/bling/module/tabbed.lua
Normal file
|
@ -0,0 +1,276 @@
|
|||
--[[
|
||||
|
||||
This module currently works by adding a new property to each client that is tabbed.
|
||||
That new property is called bling_tabbed.
|
||||
So each client in a tabbed state has the property "bling_tabbed" which is a table.
|
||||
Each client that is not tabbed doesn't have that property.
|
||||
In the function themselves, the same object is refered to as "tabobj" which is why
|
||||
you will often see something like: "local tabobj = some_client.bling_tabbed" at the beginning
|
||||
of a function.
|
||||
|
||||
--]]
|
||||
|
||||
local awful = require("awful")
|
||||
local wibox = require("wibox")
|
||||
local gears = require("gears")
|
||||
local beautiful = require("beautiful")
|
||||
local helpers = require(tostring(...):match(".*bling") .. ".helpers")
|
||||
|
||||
local bar_style = beautiful.tabbar_style or "default"
|
||||
local bar = require(
|
||||
tostring(...):match(".*bling") .. ".widget.tabbar." .. bar_style
|
||||
)
|
||||
|
||||
tabbed = {}
|
||||
|
||||
-- helper function to connect to the (un)focus signals
|
||||
local function update_tabbar_from(c)
|
||||
if not c or not c.bling_tabbed then
|
||||
return
|
||||
end
|
||||
tabbed.update_tabbar(c.bling_tabbed)
|
||||
end
|
||||
|
||||
-- used to change focused tab relative to the currently focused one
|
||||
tabbed.iter = function(idx)
|
||||
if not idx then
|
||||
idx = 1
|
||||
end
|
||||
if not client.focus or not client.focus.bling_tabbed then
|
||||
return
|
||||
end
|
||||
local tabobj = client.focus.bling_tabbed
|
||||
local new_idx = (tabobj.focused_idx + idx) % #tabobj.clients
|
||||
if new_idx == 0 then
|
||||
new_idx = #tabobj.clients
|
||||
end
|
||||
tabbed.switch_to(tabobj, new_idx)
|
||||
end
|
||||
|
||||
-- removes a given client from its tab object
|
||||
tabbed.remove = function(c)
|
||||
if not c or not c.bling_tabbed then
|
||||
return
|
||||
end
|
||||
local tabobj = c.bling_tabbed
|
||||
table.remove(tabobj.clients, tabobj.focused_idx)
|
||||
if not beautiful.tabbar_disable then
|
||||
awful.titlebar.hide(c, bar.position)
|
||||
end
|
||||
c.bling_tabbed = nil
|
||||
c:disconnect_signal("focus", update_tabbar_from)
|
||||
c:disconnect_signal("unfocus", update_tabbar_from)
|
||||
awesome.emit_signal("bling::tabbed::client_removed", tabobj, c)
|
||||
tabbed.switch_to(tabobj, 1)
|
||||
end
|
||||
|
||||
-- removes the currently focused client from the tab object
|
||||
tabbed.pop = function()
|
||||
if not client.focus or not client.focus.bling_tabbed then
|
||||
return
|
||||
end
|
||||
tabbed.remove(client.focus)
|
||||
end
|
||||
|
||||
-- adds a client to a given tabobj
|
||||
tabbed.add = function(c, tabobj)
|
||||
if c.bling_tabbed then
|
||||
tabbed.remove(c)
|
||||
end
|
||||
c:connect_signal("focus", update_tabbar_from)
|
||||
c:connect_signal("unfocus", update_tabbar_from)
|
||||
helpers.client.sync(c, tabobj.clients[tabobj.focused_idx])
|
||||
tabobj.clients[#tabobj.clients + 1] = c
|
||||
tabobj.focused_idx = #tabobj.clients
|
||||
-- calls update even though switch_to calls update again
|
||||
-- but the new client needs to have the tabobj property
|
||||
-- before a clean switch can happen
|
||||
tabbed.update(tabobj)
|
||||
awesome.emit_signal("bling::tabbed::client_added", tabobj, c)
|
||||
tabbed.switch_to(tabobj, #tabobj.clients)
|
||||
end
|
||||
|
||||
-- use xwininfo to select one client and make it tab in the currently focused tab
|
||||
tabbed.pick = function()
|
||||
if not client.focus then
|
||||
return
|
||||
end
|
||||
-- this function uses xwininfo to grab a client window id which is then
|
||||
-- compared to all other clients window ids
|
||||
|
||||
local xwininfo_cmd =
|
||||
[[ xwininfo | grep 'xwininfo: Window id:' | cut -d " " -f 4 ]]
|
||||
awful.spawn.easy_async_with_shell(xwininfo_cmd, function(output)
|
||||
for _, c in ipairs(client.get()) do
|
||||
if tonumber(c.window) == tonumber(output) then
|
||||
if not client.focus.bling_tabbed and not c.bling_tabbed then
|
||||
tabbed.init(client.focus)
|
||||
tabbed.add(c, client.focus.bling_tabbed)
|
||||
end
|
||||
if not client.focus.bling_tabbed and c.bling_tabbed then
|
||||
tabbed.add(client.focus, c.bling_tabbed)
|
||||
end
|
||||
if client.focus.bling_tabbed and not c.bling_tabbed then
|
||||
tabbed.add(c, client.focus.bling_tabbed)
|
||||
end
|
||||
-- TODO: Should also merge tabs when focus and picked
|
||||
-- both are tab groups
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- select a client by direction and make it tab in the currently focused tab
|
||||
tabbed.pick_by_direction = function(direction)
|
||||
local sel = client.focus
|
||||
if not sel then
|
||||
return
|
||||
end
|
||||
if not sel.bling_tabbed then
|
||||
tabbed.init(sel)
|
||||
end
|
||||
local c = helpers.client.get_by_direction(direction)
|
||||
if not c then
|
||||
return
|
||||
end
|
||||
tabbed.add(c, sel.bling_tabbed)
|
||||
end
|
||||
|
||||
-- use dmenu to select a client and make it tab in the currently focused tab
|
||||
tabbed.pick_with_dmenu = function(dmenu_command)
|
||||
if not client.focus then
|
||||
return
|
||||
end
|
||||
|
||||
if not dmenu_command then
|
||||
dmenu_command = "rofi -dmenu -i"
|
||||
end
|
||||
|
||||
-- get all clients from the current tag
|
||||
-- ignores the case where multiple tags are selected
|
||||
local t = awful.screen.focused().selected_tag
|
||||
local list_clients = {}
|
||||
local list_clients_string = ""
|
||||
for idx, c in ipairs(t:clients()) do
|
||||
if c.window ~= client.focus.window then
|
||||
list_clients[#list_clients + 1] = c
|
||||
if #list_clients ~= 1 then
|
||||
list_clients_string = list_clients_string .. "\\n"
|
||||
end
|
||||
list_clients_string = list_clients_string
|
||||
.. tostring(c.window)
|
||||
.. " "
|
||||
.. c.name
|
||||
end
|
||||
end
|
||||
|
||||
if #list_clients == 0 then
|
||||
return
|
||||
end
|
||||
-- calls the actual dmenu
|
||||
local xprop_cmd = [[ echo -e "]]
|
||||
.. list_clients_string
|
||||
.. [[" | ]]
|
||||
.. dmenu_command
|
||||
.. [[ | awk '{ print $1 }' ]]
|
||||
awful.spawn.easy_async_with_shell(xprop_cmd, function(output)
|
||||
for _, c in ipairs(list_clients) do
|
||||
if tonumber(c.window) == tonumber(output) then
|
||||
if not client.focus.bling_tabbed then
|
||||
tabbed.init(client.focus)
|
||||
end
|
||||
local tabobj = client.focus.bling_tabbed
|
||||
tabbed.add(c, tabobj)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- update everything about one tab object
|
||||
tabbed.update = function(tabobj)
|
||||
local currently_focused_c = tabobj.clients[tabobj.focused_idx]
|
||||
-- update tabobj of each client and other things
|
||||
for idx, c in ipairs(tabobj.clients) do
|
||||
if c.valid then
|
||||
c.bling_tabbed = tabobj
|
||||
helpers.client.sync(c, currently_focused_c)
|
||||
-- the following handles killing a client while the client is tabbed
|
||||
c:connect_signal("unmanage", function(c)
|
||||
tabbed.remove(c)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Maybe remove if I'm the only one using it?
|
||||
awesome.emit_signal("bling::tabbed::update", tabobj)
|
||||
if not beautiful.tabbar_disable then
|
||||
tabbed.update_tabbar(tabobj)
|
||||
end
|
||||
end
|
||||
|
||||
-- change focused tab by absolute index
|
||||
tabbed.switch_to = function(tabobj, new_idx)
|
||||
local old_focused_c = tabobj.clients[tabobj.focused_idx]
|
||||
tabobj.focused_idx = new_idx
|
||||
for idx, c in ipairs(tabobj.clients) do
|
||||
if idx ~= new_idx then
|
||||
helpers.client.turn_off(c)
|
||||
else
|
||||
helpers.client.turn_on(c)
|
||||
c:raise()
|
||||
if old_focused_c and old_focused_c.valid then
|
||||
c:swap(old_focused_c)
|
||||
end
|
||||
helpers.client.sync(c, old_focused_c)
|
||||
end
|
||||
end
|
||||
awesome.emit_signal("bling::tabbed::changed_focus", tabobj)
|
||||
tabbed.update(tabobj)
|
||||
end
|
||||
|
||||
tabbed.update_tabbar = function(tabobj)
|
||||
local flexlist = bar.layout()
|
||||
local tabobj_focused_client = tabobj.clients[tabobj.focused_idx]
|
||||
local tabobj_is_focused = (client.focus == tabobj_focused_client)
|
||||
-- itearte over all tabbed clients to create the widget tabbed list
|
||||
for idx, c in ipairs(tabobj.clients) do
|
||||
local buttons = gears.table.join(awful.button({}, 1, function()
|
||||
tabbed.switch_to(tabobj, idx)
|
||||
end))
|
||||
local wid_temp = bar.create(c, (idx == tabobj.focused_idx), buttons,
|
||||
not tabobj_is_focused)
|
||||
flexlist:add(wid_temp)
|
||||
end
|
||||
-- add tabbar to each tabbed client (clients will be hided anyway)
|
||||
if not beautiful.tabbar_disable then
|
||||
for _, c in ipairs(tabobj.clients) do
|
||||
local titlebar = awful.titlebar(c, {
|
||||
bg = bar.bg_normal,
|
||||
size = bar.size,
|
||||
position = bar.position,
|
||||
})
|
||||
titlebar:setup({ layout = wibox.layout.flex.horizontal, flexlist })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tabbed.init = function(c)
|
||||
local tabobj = {}
|
||||
tabobj.clients = { c }
|
||||
c:connect_signal("focus", update_tabbar_from)
|
||||
c:connect_signal("unfocus", update_tabbar_from)
|
||||
tabobj.focused_idx = 1
|
||||
tabbed.update(tabobj)
|
||||
end
|
||||
|
||||
if beautiful.tabbed_spawn_in_tab then
|
||||
client.connect_signal("manage", function(c)
|
||||
local s = awful.screen.focused()
|
||||
local previous_client = awful.client.focus.history.get(s, 1)
|
||||
if previous_client and previous_client.bling_tabbed then
|
||||
tabbed.add(c, previous_client.bling_tabbed)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return tabbed
|
56
home/.config/awesome/lib/bling/module/tiled_wallpaper.lua
Normal file
56
home/.config/awesome/lib/bling/module/tiled_wallpaper.lua
Normal file
|
@ -0,0 +1,56 @@
|
|||
--[[
|
||||
This module makes use of cairo surfaces
|
||||
For documentation take a look at the C docs:
|
||||
https://www.cairographics.org/
|
||||
They can be applied to lua by changing the naming conventions
|
||||
and adjusting for the missing namespaces (and classes)
|
||||
for example:
|
||||
cairo_rectangle(cr, 1, 1, 1, 1) in C would be written as
|
||||
cr:rectangle(1, 1, 1, 1) in lua
|
||||
and
|
||||
cairo_fill(cr) in C would be written as
|
||||
cr:fill() in lua
|
||||
--]]
|
||||
|
||||
local cairo = require("lgi").cairo
|
||||
local gears = require("gears")
|
||||
|
||||
function create_tiled_wallpaper(str, s, args_table)
|
||||
-- user input
|
||||
args_table = args_table or {}
|
||||
local fg = args_table.fg or "#ff0000"
|
||||
local bg = args_table.bg or "#00ffff"
|
||||
local offset_x = args_table.offset_x
|
||||
local offset_y = args_table.offset_y
|
||||
local font = args_table.font or "Hack"
|
||||
local font_size = tonumber(args_table.font_size) or 16
|
||||
local zickzack_bool = args_table.zickzack or false
|
||||
local padding = args_table.padding or 100
|
||||
|
||||
-- create cairo image wallpaper
|
||||
local img = cairo.ImageSurface(cairo.Format.RGB24, padding, padding)
|
||||
cr = cairo.Context(img)
|
||||
|
||||
cr:set_source(gears.color(bg))
|
||||
cr:paint()
|
||||
|
||||
cr:set_source(gears.color(fg))
|
||||
|
||||
cr:set_font_size(font_size)
|
||||
cr:select_font_face(font)
|
||||
|
||||
if zickzack_bool then
|
||||
cr:set_source(gears.color(fg))
|
||||
cr:move_to(padding / 2 + font_size, padding / 2 + font_size)
|
||||
cr:show_text(str)
|
||||
end
|
||||
|
||||
cr:set_source(gears.color(fg))
|
||||
cr:move_to(font_size, font_size)
|
||||
cr:show_text(str)
|
||||
|
||||
-- tile cairo image
|
||||
gears.wallpaper.tiled(img, s, { x = offset_x, y = offset_y })
|
||||
end
|
||||
|
||||
return create_tiled_wallpaper
|
362
home/.config/awesome/lib/bling/module/wallpaper.lua
Normal file
362
home/.config/awesome/lib/bling/module/wallpaper.lua
Normal file
|
@ -0,0 +1,362 @@
|
|||
---------------------------------------------------------------------------
|
||||
-- High-level declarative function for setting your wallpaper.
|
||||
--
|
||||
--
|
||||
-- An easy way to setup a complex wallpaper with slideshow, random, schedule, extensibility.
|
||||
--
|
||||
-- @usage
|
||||
-- local wallpaper = require("wallpaper")
|
||||
-- -- A silly example
|
||||
-- wallpaper.setup { -- I want a wallpaper
|
||||
-- change_timer = 500, -- changing every 5 minutes
|
||||
-- set_function = wallpaper.setters.random, -- in a random way
|
||||
-- wallpaper = {"#abcdef",
|
||||
-- "~/Pictures",
|
||||
-- wallpaper.setters.awesome}, -- from this list (a color, a directory with pictures and the Awesome wallpaper)
|
||||
-- recursive = false, -- do not read subfolders of "~/Pictures"
|
||||
-- position = "centered", -- center it on the screen (for pictures)
|
||||
-- scale = 2, -- 2 time bigger (for pictures)
|
||||
-- }
|
||||
--
|
||||
-- @author Grumph
|
||||
-- @copyright 2021 Grumph
|
||||
--
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local gears = require("gears")
|
||||
local helpers = require(tostring(...):match(".*bling") .. ".helpers")
|
||||
|
||||
local setters = {}
|
||||
|
||||
--- Apply a wallpaper.
|
||||
--
|
||||
-- This function is a helper that will apply a wallpaper_object,
|
||||
-- either using gears.wallpaper.set or gears.wallpaper.* higher level functions when applicable.
|
||||
-- @param wallpaper_object A wallpaper object, either
|
||||
-- a `pattern` (see `gears.wallpaper.set`)
|
||||
-- a `surf` (see `gears.wallpaper.centered`)
|
||||
-- a function that actually sets the wallpaper.
|
||||
-- @tparam table args The argument table containing any of the arguments below.
|
||||
-- @int[opt=nil] args.screen The screen to use (as used in `gears.wallpaper` functions)
|
||||
-- @string[opt=nil or "centered"] args.position The `gears.wallpaper` position function to use.
|
||||
-- Must be set when wallpaper is a file.
|
||||
-- It can be `"centered"`, `"fit"`, `"tiled"` or `"maximized"`.
|
||||
-- @string[opt=beautiful.bg_normal or "black"] args.background See `gears.wallpaper`.
|
||||
-- @bool[opt=false] args.ignore_aspect See `gears.wallpaper`.
|
||||
-- @tparam[opt={x=0,y=0}] table args.offset See `gears.wallpaper`.
|
||||
-- @int[opt=1] args.scale See `gears.wallpaper`.
|
||||
function apply(wallpaper_object, args)
|
||||
args.background = args.background or beautiful.bg_normal or "black"
|
||||
args.ignore_aspect = args.ignore_aspect or false -- false = keep aspect ratio
|
||||
args.offset = args.offset or { x = 0, y = 0 }
|
||||
args.scale = args.scale or 1
|
||||
local positions = {
|
||||
["centered"] = function(s)
|
||||
gears.wallpaper.centered(
|
||||
wallpaper_object,
|
||||
s,
|
||||
args.background,
|
||||
args.scale
|
||||
)
|
||||
end,
|
||||
["tiled"] = function(s)
|
||||
gears.wallpaper.tiled(wallpaper_object, s, args.offset)
|
||||
end,
|
||||
["maximized"] = function(s)
|
||||
gears.wallpaper.maximized(
|
||||
wallpaper_object,
|
||||
s,
|
||||
args.ignore_aspect,
|
||||
args.offset
|
||||
)
|
||||
end,
|
||||
["fit"] = function(s)
|
||||
gears.wallpaper.fit(wallpaper_object, s, args.background)
|
||||
end,
|
||||
}
|
||||
local call_func = nil
|
||||
if
|
||||
type(wallpaper_object) == "string"
|
||||
and gears.filesystem.file_readable(wallpaper_object)
|
||||
then
|
||||
-- path of an image file, we use a position function
|
||||
local p = args.position or "centered"
|
||||
call_func = positions[p]
|
||||
elseif type(wallpaper_object) == "function" then
|
||||
-- function
|
||||
wallpaper_object(args)
|
||||
elseif
|
||||
(not gears.color.ensure_pango_color(wallpaper_object, nil))
|
||||
and args.position
|
||||
then
|
||||
-- if the user sets a position function, wallpaper_object should be a cairo surface
|
||||
call_func = positions[args.position]
|
||||
else
|
||||
gears.wallpaper.set(wallpaper_object)
|
||||
end
|
||||
if call_func then
|
||||
call_func(args.screen)
|
||||
end
|
||||
end
|
||||
|
||||
--- Converts `args.wallpaper` to a list of `wallpaper_objects` readable by `apply` function).
|
||||
--
|
||||
-- @tparam table args The argument table containing the argument below.
|
||||
-- @param[opt=`beautiful.wallpaper_path` or `"black"`] args.wallpaper A wallpaper object.
|
||||
-- It can be a color or a cairo pattern (what `gears.wallpaper.set` understands),
|
||||
-- a cairo suface (set with gears.wallpaper.set if `args.position` is nil, or with
|
||||
-- `gears.wallpaper` position functions, see `args.position`),
|
||||
-- a function similar to args.set_function that will effectively set a wallpaper (usually
|
||||
-- with `gears.wallpaper` functions),
|
||||
-- a path to a file,
|
||||
-- path to a directory containing images,
|
||||
-- or a list with any of the previous choices.
|
||||
-- @tparam[opt=`{"jpg", "jpeg", "png", "bmp"}`] table args.image_formats A list of
|
||||
-- file extensions to filter when `args.wallpaper` is a directory.
|
||||
-- @bool[opt=true] args.recursive Either to recurse or not when `args.wallpaper` is a directory.
|
||||
-- @treturn table A list of `wallpaper_objects` (what `apply` can read).
|
||||
-- @see apply
|
||||
function prepare_list(args)
|
||||
args.image_formats = args.image_formats or { "jpg", "jpeg", "png", "bmp" }
|
||||
args.recursive = args.recursive or true
|
||||
|
||||
local wallpapers = (args.wallpaper or beautiful.wallpaper_path or "black")
|
||||
local res = {}
|
||||
if type(wallpapers) ~= "table" then
|
||||
wallpapers = { wallpapers }
|
||||
end
|
||||
for _, w in ipairs(wallpapers) do
|
||||
-- w is either:
|
||||
-- - a directory path (string)
|
||||
-- - an image path or a color (string)
|
||||
-- - a cairo surface or a cairo pattern
|
||||
-- - a function for setting the wallpaper
|
||||
if type(w) == "string" and gears.filesystem.dir_readable(w) then
|
||||
local file_list = helpers.filesystem.list_directory_files(
|
||||
w,
|
||||
args.image_formats,
|
||||
args.recursive
|
||||
)
|
||||
for _, f in ipairs(file_list) do
|
||||
res[#res + 1] = w .. "/" .. f
|
||||
end
|
||||
else
|
||||
res[#res + 1] = w
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local simple_index = 0
|
||||
--- Set the next wallpaper in a list.
|
||||
--
|
||||
-- @tparam table args See `prepare_list` and `apply` arguments
|
||||
-- @see apply
|
||||
-- @see prepare_list
|
||||
function setters.simple(args)
|
||||
local wallpapers = prepare_list(args)
|
||||
simple_index = (simple_index % #wallpapers) + 1
|
||||
if type(args.screen) == 'table' then
|
||||
for _,v in ipairs(args.screen) do
|
||||
args.screen = v
|
||||
apply(wallpapers[simple_index], args)
|
||||
args.screen = nil
|
||||
end
|
||||
else
|
||||
apply(wallpapers[simple_index], args)
|
||||
end
|
||||
end
|
||||
|
||||
--- Set a random wallpaper from a list.
|
||||
--
|
||||
-- @tparam table args See `prepare_list` and `apply` arguments
|
||||
-- @see apply
|
||||
-- @see prepare_list
|
||||
function setters.random(args)
|
||||
local wallpapers = prepare_list(args)
|
||||
if type(args.screen) == 'table' then
|
||||
for _,v in ipairs(args.screen) do
|
||||
args.screen = v
|
||||
apply(wallpapers[math.random(#wallpapers)], args)
|
||||
args.screen = nil
|
||||
end
|
||||
else
|
||||
apply(wallpapers[math.random(#wallpapers)], args)
|
||||
end
|
||||
end
|
||||
|
||||
local simple_schedule_object = nil
|
||||
--- A schedule setter.
|
||||
--
|
||||
-- This simple schedule setter was freely inspired by [dynamic-wallpaper](https://github.com/manilarome/awesome-glorious-widgets/blob/master/dynamic-wallpaper/init.lua).
|
||||
-- @tparam table args The argument table containing any of the arguments below.
|
||||
-- @tparam table args.wallpaper The schedule table, with the form
|
||||
-- {
|
||||
-- ["HH:MM:SS"] = wallpaper,
|
||||
-- ["HH:MM:SS"] = wallpaper2,
|
||||
-- }
|
||||
-- The wallpapers definition can be anything the `schedule_set_function` can read
|
||||
-- (what you would place in `args.wallpaper` for this function),
|
||||
-- @tparam[opt=`setters.simple`] function args.wallpaper_set_function The set_function used by default
|
||||
function setters.simple_schedule(args)
|
||||
local function update_wallpaper()
|
||||
local fake_args = gears.table.join(args, {
|
||||
wallpaper = args.wallpaper[simple_schedule_object.closest_lower_time],
|
||||
})
|
||||
simple_schedule_object.schedule_set_function(fake_args)
|
||||
end
|
||||
if not simple_schedule_object then
|
||||
simple_schedule_object = {}
|
||||
-- initialize the schedule object, so we don't do it for every call
|
||||
simple_schedule_object.schedule_set_function = args.schedule_set_function
|
||||
or setters.simple
|
||||
-- we get the sorted time keys
|
||||
simple_schedule_object.times = {}
|
||||
for k in pairs(args.wallpaper) do
|
||||
table.insert(simple_schedule_object.times, k)
|
||||
end
|
||||
table.sort(simple_schedule_object.times)
|
||||
-- now we get the closest time which is below current time (the current applicable period)
|
||||
local function update_timer()
|
||||
local current_time = os.date("%H:%M:%S")
|
||||
local next_time = simple_schedule_object.times[1]
|
||||
simple_schedule_object.closest_lower_time =
|
||||
simple_schedule_object.times[#simple_schedule_object.times]
|
||||
for _, k in ipairs(simple_schedule_object.times) do
|
||||
if k > current_time then
|
||||
next_time = k
|
||||
break
|
||||
end
|
||||
simple_schedule_object.closest_lower_time = k
|
||||
end
|
||||
simple_schedule_object.timer.timeout = helpers.time.time_diff(
|
||||
next_time,
|
||||
current_time
|
||||
)
|
||||
if simple_schedule_object.timer.timeout < 0 then
|
||||
-- the next_time is the day after, so we add 24 hours to the timer
|
||||
simple_schedule_object.timer.timeout = simple_schedule_object.timer.timeout
|
||||
+ 86400
|
||||
end
|
||||
simple_schedule_object.timer:again()
|
||||
update_wallpaper()
|
||||
end
|
||||
simple_schedule_object.timer = gears.timer({
|
||||
callback = update_timer,
|
||||
})
|
||||
update_timer()
|
||||
else
|
||||
-- if called again (usually when the change_timer is set), we just change the wallpaper depending on current parameters
|
||||
update_wallpaper()
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the AWESOME wallpaper.
|
||||
--
|
||||
-- @tparam table args The argument table containing the argument below.
|
||||
-- @param[opt=`beautiful.bg_normal`] args.colors.bg The bg color.
|
||||
-- If the default is used, the color is darkened if `beautiful.bg_normal` is light
|
||||
-- or lightned if `beautiful.bg_normal` is dark.
|
||||
-- @param[opt=`beautiful.fg_normal`] args.colors.fg The fg color.
|
||||
-- @param[opt=`beautiful.fg_focus`] args.colors.alt_fg The alt_fg color.
|
||||
--
|
||||
-- see beautiful.theme_assets.wallpaper
|
||||
function setters.awesome_wallpaper(args)
|
||||
local colors = {
|
||||
bg = beautiful.bg_normal,
|
||||
fg = beautiful.fg_normal,
|
||||
alt_fg = beautiful.bg_focus,
|
||||
}
|
||||
colors.bg = helpers.color.is_dark(beautiful.bg_normal)
|
||||
and helpers.color.lighten(colors.bg)
|
||||
or helpers.color.darken(colors.bg)
|
||||
if type(args.colors) == "table" then
|
||||
colors.bg = args.colors.bg or colors.bg
|
||||
colors.fg = args.colors.fg or colors.fg
|
||||
colors.alt_fg = args.colors.alt_fg or colors.alt_fg
|
||||
end
|
||||
-- Generate wallpaper:
|
||||
if not args.screen then
|
||||
for s in screen do
|
||||
gears.wallpaper.set(
|
||||
beautiful.theme_assets.wallpaper(
|
||||
colors.bg,
|
||||
colors.fg,
|
||||
colors.alt_fg,
|
||||
s
|
||||
)
|
||||
)
|
||||
end
|
||||
else
|
||||
gears.wallpaper.set(
|
||||
beautiful.theme_assets.wallpaper(
|
||||
colors.bg,
|
||||
colors.fg,
|
||||
colors.alt_fg,
|
||||
args.screen
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
--- Setup a wallpaper.
|
||||
--
|
||||
-- @tparam table args Parameters for the wallpaper. It may also contain all parameters your `args.set_function` needs
|
||||
-- @int[opt=nil] args.screen The screen to use (as used in `gears.wallpaper` functions)
|
||||
-- @int[opt=nil] args.change_timer Time in seconds for wallpaper changes
|
||||
-- @tparam[opt=`setters.awesome` or `setters.simple`] function args.set_function A function to set the wallpaper
|
||||
-- It takes args as parameter (the same args as the setup function).
|
||||
-- This function is called at `"request::wallpaper"` `screen` signals and at `args.change_timer` timeouts.
|
||||
-- There is no obligation, but for consistency, the function should use `args.wallpaper` as a feeder.
|
||||
-- If `args.wallpaper` is defined, the default function is `setters.simple`, else it will be `setters.awesome`.
|
||||
--
|
||||
-- @usage
|
||||
-- local wallpaper = require("wallpaper")
|
||||
-- wallpaper.setup {
|
||||
-- change_timer = 631, -- Prime number is better
|
||||
-- set_function = wallpaper.setters.random,
|
||||
-- -- parameters for the random setter
|
||||
-- wallpaper = '/data/pictures/wallpapers',
|
||||
-- position = "maximized",
|
||||
-- }
|
||||
--
|
||||
-- @see apply
|
||||
-- @see prepare_list
|
||||
-- @see setters.simple
|
||||
function setup(args)
|
||||
local config = args or {}
|
||||
config.set_function = config.set_function
|
||||
or (config.wallpaper and setters.simple or setters.awesome_wallpaper)
|
||||
local function set_wallpaper(s)
|
||||
if type(config.screen) ~= 'table' then
|
||||
if config.screen and s and config.screen ~= s then return end
|
||||
config.screen = s or config.screen
|
||||
end
|
||||
config.set_function(config)
|
||||
end
|
||||
|
||||
if config.change_timer and config.change_timer > 0 then
|
||||
gears.timer({
|
||||
timeout = config.change_timer,
|
||||
call_now = false,
|
||||
autostart = true,
|
||||
callback = function()
|
||||
set_wallpaper()
|
||||
end,
|
||||
})
|
||||
end
|
||||
if awesome.version == "v4.3" or awesome.version == "4.3" then
|
||||
awful.screen.connect_for_each_screen(set_wallpaper)
|
||||
else
|
||||
screen.connect_signal("request::wallpaper", set_wallpaper)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
setup = setup,
|
||||
setters = setters,
|
||||
apply = apply,
|
||||
prepare_list = prepare_list,
|
||||
}
|
128
home/.config/awesome/lib/bling/module/window_swallowing.lua
Normal file
128
home/.config/awesome/lib/bling/module/window_swallowing.lua
Normal file
|
@ -0,0 +1,128 @@
|
|||
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,
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue