bling/module/tabbed.lua

178 lines
6.2 KiB
Lua
Raw Normal View History

2020-11-07 18:16:16 +01:00
--[[
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")
2020-11-07 18:16:16 +01:00
local wibox = require("wibox")
local gears = require("gears")
local beautiful = require("beautiful")
local helpers = require(tostring(...):match(".*bling.module") .. ".helpers")
2020-11-22 10:18:39 +01:00
local bar_style = beautiful.tabbar_style or "default"
local bar = require(tostring(...):match(".*bling") .. ".widget.tabbar." ..
bar_style)
2020-11-07 18:16:16 +01:00
local function copy_size(c, parent_client)
if not c or not parent_client then return end
if not c.valid or not parent_client.valid then return end
2020-11-07 18:16:16 +01:00
c.floating = parent_client.floating
c.x = parent_client.x
c.y = parent_client.y
c.width = parent_client.width
c.height = parent_client.height
end
tabbed = {}
2020-11-09 15:59:36 +01:00
-- used to change focused tab relative to the currently focused one
2020-11-07 18:16:16 +01:00
tabbed.iter = function(idx)
2020-11-09 15:59:36 +01:00
if not idx then idx = 1 end
if not client.focus.bling_tabbed then return end
2020-11-07 18:16:16 +01:00
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
2020-11-07 18:16:16 +01:00
tabbed.switch_to(tabobj, new_idx)
end
2020-11-07 18:16:16 +01:00
2020-11-09 15:59:36 +01:00
-- removes a given client from its tab object
tabbed.remove = function(c)
2020-11-09 15:59:36 +01:00
if not c.bling_tabbed then return end
local tabobj = c.bling_tabbed
table.remove(tabobj.clients, tabobj.focused_idx)
2020-11-15 10:05:56 +01:00
awful.titlebar.hide(c, bar.position)
2020-11-09 15:59:36 +01:00
c.bling_tabbed = nil
2020-11-07 18:16:16 +01:00
tabbed.switch_to(tabobj, 1)
2020-11-09 15:59:36 +01:00
end
-- removes the currently focused client from the tab object
tabbed.pop = function()
if not client.focus.bling_tabbed then return end
tabbed.remove(client.focus)
end
2020-11-07 18:16:16 +01:00
2020-11-09 15:59:36 +01:00
-- adds a client to a given tabobj
tabbed.add = function(c, tabobj)
if c.bling_tabbed then return end
copy_size(c, tabobj.clients[tabobj.focused_idx])
tabobj.clients[#tabobj.clients + 1] = c
2020-11-09 15:59:36 +01:00
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)
tabbed.switch_to(tabobj, #tabobj.clients)
end
-- use xprop to select one client and make it tab in the currently focused tab
tabbed.pick = function()
if not client.focus.bling_tabbed then tabbed.init(client.focus) end
2020-11-07 18:16:16 +01:00
local tabobj = client.focus.bling_tabbed
-- this function uses xprop to grab a client pid which is then
-- compared to all other client process ids
-- io.popen is normally discouraged. Works fine for now
local handle = io.popen("xprop _NET_WM_PID | cut -d' ' -f3")
local output = handle:read("*a")
handle:close()
2020-11-09 15:59:36 +01:00
-- search the client that was picked
for _, c in ipairs(client.get()) do
if tonumber(c.pid) == tonumber(output) then tabbed.add(c, tabobj) end
end
2020-11-07 18:16:16 +01:00
end
2020-11-09 15:59:36 +01:00
-- update everything about one tab object
tabbed.update = function(tabobj)
2020-11-07 18:16:16 +01:00
local currently_focused_c = tabobj.clients[tabobj.focused_idx]
2020-11-09 15:59:36 +01:00
-- update tabobj of each client and other things
for idx, c in ipairs(tabobj.clients) do
if c.valid then
2020-11-09 15:59:36 +01:00
c.bling_tabbed = tabobj
copy_size(c, currently_focused_c)
-- the following handles killing a client while the client is tabbed
-- the killed client has to be removed from the tabobj table and
-- a new tabbed client has to appear (otherwise accessing other tabbed clients
-- is impossible)
c:connect_signal("unmanage", function(c)
if not c.bling_tabbed then return end
local old_tabobj = c.bling_tabbed
local tabobj = {clients = {}, focused_idx = 1}
for _, c_temp in ipairs(old_tabobj.clients) do
2020-11-09 15:59:36 +01:00
if c_temp.window ~= c.window then
tabobj.clients[#tabobj.clients + 1] = c_temp
2020-11-09 15:59:36 +01:00
end
end
2020-11-09 15:59:36 +01:00
tabbed.update(tabobj)
tabbed.switch_to(tabobj, 1)
end)
end
end
2020-11-07 18:16:16 +01:00
tabbed.update_tabbar(tabobj)
end
2020-11-09 15:59:36 +01:00
-- change docused tab by absolute index
2020-11-07 18:16:16 +01:00
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
2020-11-07 18:16:16 +01:00
helpers.turn_off(c)
else
2020-11-07 18:16:16 +01:00
helpers.turn_on(c)
c:raise()
if old_focused_c and old_focused_c.valid then
2020-11-09 15:59:36 +01:00
c:swap(old_focused_c)
end
2020-11-07 18:16:16 +01:00
copy_size(c, old_focused_c)
2020-11-09 15:59:36 +01:00
end
end
2020-11-07 18:16:16 +01:00
tabbed.update(tabobj)
end
tabbed.update_tabbar = function(tabobj)
2020-11-09 15:59:36 +01:00
local flexlist = bar.layout()
2020-11-07 18:16:16 +01:00
-- 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))
wid_temp = bar.create(c, (idx == tabobj.focused_idx), buttons)
2020-11-07 18:16:16 +01:00
flexlist:add(wid_temp)
end
2020-11-07 18:16:16 +01:00
-- add tabbar to each tabbed client (clients will be hided anyway)
for _, c in ipairs(tabobj.clients) do
2020-11-07 18:16:16 +01:00
local titlebar = awful.titlebar(c, {
bg = bar.bg_normal,
2020-11-15 10:05:56 +01:00
size = bar.size,
2020-11-09 15:59:36 +01:00
position = bar.position
2020-11-07 18:16:16 +01:00
})
titlebar:setup{layout = wibox.layout.flex.horizontal, flexlist}
end
end
2020-11-07 18:16:16 +01:00
tabbed.init = function(c)
2020-11-09 15:59:36 +01:00
local tabobj = {}
tabobj.clients = {c}
tabobj.focused_idx = 1
tabbed.update(tabobj)
2020-11-07 18:16:16 +01:00
end
if beautiful.tabbed_spawn_in_tab then
2020-11-15 10:05:56 +01:00
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
2020-11-15 10:05:56 +01:00
tabbed.add(c, previous_client.bling_tabbed)
end
end)
end
2020-11-07 18:16:16 +01:00
return tabbed