experimental tabs

This commit is contained in:
anakha 2021-07-03 17:50:31 -04:00
parent 2f83e380b0
commit 33b5ea1f50
8 changed files with 1034 additions and 313 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ helpers
widget widget
module module
geometries geometries
outlines

27
backham.lua Normal file
View File

@ -0,0 +1,27 @@
--+ allows automatically focusing back to the previous client
--> on window close (unmanage) or minimize.
local get_client_info = require("machina.methods").get_client_info
-------------------------------------------------------------------> methods ;
function backham(c)
local s = awful.screen.focused()
local back_to = awful.client.focus.history.get(s, 0)
local active_region = get_client_info(c).active_region
if not (active_region and client.floating) and back_to then
client.focus = back_to
back_to:raise()
end
end
--------------------------------------------------------------------> signal ;
client.connect_signal("property::minimized", backham)
--+ attach to minimized state
client.connect_signal("unmanage", backham)
--+ attach to closed state

71
geoms.lua Normal file
View File

@ -0,0 +1,71 @@
local geoms = {}
geoms.crt43 = function ()
return {
x=awful.screen.focused().workarea.width - client.focus:geometry().width,
y=awful.screen.focused().workarea.height - client.focus:geometry().height + awful.screen.focused().workarea.y,
width=1280,
height=1024
}
end --|awful.screen.focused().workarea.y is required for
--|multiple monitors to relocate properly.
geoms.p1080 = function ()
return {
x=awful.screen.focused().workarea.width - client.focus:geometry().width,
y=awful.screen.focused().workarea.height - client.focus:geometry().height + awful.screen.focused().workarea.y,
width=awful.screen.focused().workarea.width * 0.65,
height=awful.screen.focused().workarea.height * 0.90
}
end
geoms.p720 = function ()
return {
x=awful.screen.focused().workarea.width - client.focus:geometry().width,
y=awful.screen.focused().workarea.height - client.focus:geometry().height + awful.screen.focused().workarea.y,
width=awful.screen.focused().workarea.width * 0.40,
height=awful.screen.focused().workarea.height * 0.45
}
end
geoms["center"] = function(useless_gap)
return {
x=awful.screen.focused().workarea.width/2 - client.focus.width/2,
y=awful.screen.focused().workarea.height/2 - client.focus.height/2 + awful.screen.focused().workarea.y
}
end
geoms["top-left"] = function(useless_gap)
return {
x=useless_gap,
y=useless_gap + awful.screen.focused().workarea.y
}
end
geoms["bottom-left"] = function(useless_gap)
return {
x=useless_gap,
y=awful.screen.focused().workarea.height - useless_gap - client.focus.height + awful.screen.focused().workarea.y
}
end
geoms["top-right"] = function(useless_gap)
return {
x=awful.screen.focused().workarea.width - useless_gap - client.focus.width,
y=useless_gap + awful.screen.focused().workarea.y
}
end
geoms["bottom-right"] = function(useless_gap)
return {
x=awful.screen.focused().workarea.width - useless_gap - client.focus.width,
y=awful.screen.focused().workarea.height - useless_gap - client.focus.height + awful.screen.focused().workarea.y
}
end
geoms.clients = {
Subl=geoms.p1080,
Byobu=geoms.p720,
}
return geoms

139
helpers.lua Normal file
View File

@ -0,0 +1,139 @@
local function old_shuffle(direction)
return function()
local tablist = region_tablist()
if direction == "backward" then
local prev_client = nil
for i = #tablist, 1, -1 do
prev_client = tablist[i]
prev_client:emit_signal("request::activate", "mouse_enter",{raise = true})
break --|activate previous client
end
return
end
if direction == "forward" then
local next_client = nil
for _, cc in ipairs(tablist) do
client.focus:lower()
next_client = tablist[_+1]
next_client:emit_signal("request::activate", "mouse_enter",{raise = true})
break --|activate next client
end
return
end
end
end --|
--|this uses the old hack that doesn't rely on
--|global_client_index. keeping it here for historical
--|reasons in case we need this again.
local function reload(m)
if package.loaded[m] then
local attrs = {}
for key,value in pairs(package.loaded[m]) do
attrs[key] = value
end
package.loaded[m] = nil
temp_module = require(tostring(m))
for key,value in pairs(attrs) do
temp_module[key] = value
end
else
temp_module = require(m)
end
return temp_module
end
local function getlowest(table)
local low = math.huge
local index
for i, v in pairs(table) do
if v < low then
low = v
index = i
end
end
return index
end
local function compare(a,b)
return a.v < b.v
end
local function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end --|return table length
local function set_contains(set, key)
return set[key] ~= nil
end --|tests table if key exists
local function get_client_ix(id, ids)
for i, c in ipairs(ids) do
if id == c.window then
return i
end
end
end --|finds out where id is located inside ids.
local function clear_tabbar(c, position)
if not c then return end
position = position or "bottom"
local titlebar = awful.titlebar(c, {size=3, position=position})
awful.titlebar(c, {size=0, position="left"})
awful.titlebar(c, {size=0, position="right"})
titlebar:setup{
layout=wibox.layout.flex.horizontal, nil
}
end --|clears bottom tabbar
-------------------------------------------------------------- exports -- ;
return {
set_contains = set_contains,
tablelength = tablelength,
compare = compare,
getlowest = getlowest,
get_client_ix = get_client_ix,
reload = reload,
clear_tabbar = clear_tabbar
}
-- d:connect_signal("focus", function(_)
-- local poo = awful.titlebar(d, {position="bottom", size="14"})
-- -- local dee = poo.get_all_children({"335544341"})
-- local dee = poo:get_children_by_id("335544341")
-- file = io.open("/tmp/lua.txt", "w")
-- io.output(file)
-- io.write(inspect(poo))
-- io.close(file)
-- naughty.notify({text=inspect(dee)})
-- end)
-- -- gears.timer.delayed_call(function (d)
-- -- -- local active_region = get_client_region(d)
-- -- naughty.notify({text="here"})
-- -- if active_region then
-- -- c.region = active_region
-- -- draw_tabbar(active_region)
-- -- end
-- -- end, c)

116
init.lua
View File

@ -1,21 +1,15 @@
---------------------------------------------------------- dependencies -- ; ---------------------------------------------------------- dependencies -- ;
-- local inspect = require('inspect')
local capi = {root=root} local capi = {root=root}
local gears = require("gears")
local naughty = require("naughty")
local awful = require("awful") local awful = require("awful")
local modkey = "Mod4" local modkey = "Mod4"
local machina = require('awesomewm-machina.methods') local machina = require("machina.methods")
local compare = machina.compare local backham = require("machina.backham")
local region_tablist = machina.region_tablist
local focus_by_direction = machina.focus_by_direction local focus_by_direction = machina.focus_by_direction
local get_active_regions = machina.get_active_regions
local shift_by_direction = machina.shift_by_direction local shift_by_direction = machina.shift_by_direction
local expand_horizontal = machina.expand_horizontal local expand_horizontal = machina.expand_horizontal
local geoms = machina.geoms
local shuffle = machina.shuffle local shuffle = machina.shuffle
local my_shifter = machina.my_shifter local my_shifter = machina.my_shifter
local expand_vertical = machina.expand_vertical local expand_vertical = machina.expand_vertical
@ -25,62 +19,90 @@ local toggle_always_on = machina.toggle_always_on
---------------------------------------------------------- key bindings -- ; ---------------------------------------------------------- key bindings -- ;
local bindings = { local bindings = {
awful.key({modkey}, "[", my_shifter("backward")),
awful.key({modkey}, "]", my_shifter("forward")),
--▨ move
awful.key({modkey, "Shift"}, "[", my_shifter("backward", "swap")),
awful.key({modkey, "Shift"}, "]", my_shifter("forward", "swap")),
--▨ swap
awful.key({modkey}, ";", shuffle("backward")), awful.key({modkey}, ";", shuffle("backward")),
awful.key({modkey}, "'", shuffle("forward")), awful.key({modkey}, "'", shuffle("forward")),
--▨ shuffle decks --▨ shuffle
awful.key({modkey}, "j", focus_by_direction("left")),
awful.key({modkey}, "k", focus_by_direction("down")),
awful.key({modkey}, "l", focus_by_direction("right")),
awful.key({modkey}, "i", focus_by_direction("up")),
--▨ focus
awful.key({modkey, "Shift"}, "j", shift_by_direction("left")), awful.key({modkey, "Shift"}, "j", shift_by_direction("left")),
awful.key({modkey, "Shift"}, "l", shift_by_direction("right")), awful.key({modkey, "Shift"}, "l", shift_by_direction("right")),
awful.key({modkey, "Shift"}, "k", shift_by_direction("down")), awful.key({modkey, "Shift"}, "k", shift_by_direction("down")),
awful.key({modkey, "Shift"}, "i", shift_by_direction("up")), awful.key({modkey, "Shift"}, "i", shift_by_direction("up")),
--▨ move (directional) --▨ move
awful.key({modkey}, "[", my_shifter("backward")), awful.key({modkey, "Control"}, "j", shift_by_direction("left", "swap")),
awful.key({modkey}, "]", my_shifter("forward")), awful.key({modkey, "Control"}, "l", shift_by_direction("right", "swap")),
--▨ move (clockwise) awful.key({modkey, "Control"}, "k", shift_by_direction("down", "swap")),
awful.key({modkey, "Control"}, "i", shift_by_direction("up","swap")),
--▨ swap
awful.key({modkey, "Shift"}, "Insert", move_to("top-left")), awful.key({modkey, "Shift"}, "Insert", expand_horizontal("left")),
awful.key({modkey, "Shift"}, "Page_Up", move_to("top-right")), awful.key({modkey, "Shift"}, "Page_Up", expand_horizontal("right")),
awful.key({modkey, "Shift"}, "Home", move_to("center")), awful.key({modkey, "Shift"}, "Page_Down", expand_vertical),
awful.key({modkey, "Shift"}, "End", toggle_always_on),
awful.key({modkey, "Shift"}, "Delete", move_to("bottom-left")),
awful.key({modkey, "Shift"}, "Page_Down", move_to("bottom-right")),
--▨ move (positional)
awful.key({modkey, "Shift" }, "[", shift_by_direction("left", true)),
awful.key({modkey, "Shift" }, "]", shift_by_direction("right", true)),
awful.key({modkey, "Control"}, "[", shift_by_direction("down", true)),
awful.key({modkey, "Control"}, "]", shift_by_direction("up", true)),
--▨ swap (directional)
awful.key({modkey}, "Insert", expand_horizontal("left")),
awful.key({modkey}, "Page_Up", expand_horizontal("right")),
awful.key({modkey}, "Home", expand_horizontal("center")),
awful.key({modkey}, "Page_Down", expand_vertical),
--▨ expand (neighbor) --▨ expand (neighbor)
awful.key({modkey}, "Insert", move_to("top-left")),
awful.key({modkey}, "Page_Up", move_to("top-right")),
awful.key({modkey}, "Delete", move_to("bottom-left")),
awful.key({modkey}, "Page_Down", move_to("bottom-right")),
--▨ move (positional)
awful.key({modkey}, "Home", expand_horizontal("center")),
awful.key({modkey}, "End", function() awful.key({modkey}, "End", function()
client.focus.maximized_vertical = false client.focus.maximized_vertical = false
client.focus.maximized_horizontal = false client.focus.maximized_horizontal = false
awful.client.floating.toggle() awful.client.floating.toggle()
end), --|toggle floating status end), --|toggle floating status
awful.key({modkey, "Shift"}, "End", toggle_always_on),
awful.key({modkey, "Shift"}, "Home", move_to("center")),
awful.key({modkey,}, "o", function ()
c = client.focus
if not c then return true end
if not c.floating then
c:geometry({width=300, height=300})
end --|to avoid machi's auto expansion
c:move_to_screen()
gears.timer.delayed_call(function ()
c:emit_signal("request::activate", "mouse_enter",{raise = true})
end)
end), --|client teleport to other screen
awful.key({modkey}, "Left", focus_by_direction("left")), awful.key({modkey}, "Left", focus_by_direction("left")),
awful.key({modkey}, "j", focus_by_direction("left")),
awful.key({modkey}, "Down", focus_by_direction("down")), awful.key({modkey}, "Down", focus_by_direction("down")),
awful.key({modkey}, "k", focus_by_direction("down")),
awful.key({modkey}, "Right", focus_by_direction("right")), awful.key({modkey}, "Right", focus_by_direction("right")),
awful.key({modkey}, "l", focus_by_direction("right")),
awful.key({modkey}, "Up", focus_by_direction("up")), awful.key({modkey}, "Up", focus_by_direction("up")),
awful.key({modkey}, "i", focus_by_direction("up"))
--▨ focus --▨ focus
} }
--------------------------------------------------------------- signals -- ; --------------------------------------------------------------- signals -- ;
client.connect_signal("manage", function(c)
c.maximized = false
c.maximized_horizontal = false
c.maximized_vertical = false
end) --|during reload maximized clients get messed up, as machi
--|also tries to best fit the windows. this resets the
--|maximized state during a reload problem is with our hack
--|to use maximized, we should look into using machi
--|resize_handler instead
client.connect_signal("request::activate", function(c) client.connect_signal("request::activate", function(c)
c.hidden = false c.hidden = false
c:raise() c:raise()
@ -89,6 +111,7 @@ end) --|this is needed to ensure floating stuff becomes
--|visible when invoked through run_or_raise. --|visible when invoked through run_or_raise.
client.connect_signal("focus", function(c) client.connect_signal("focus", function(c)
if not (c.bypass or c.always_on) then
if not c.floating then if not c.floating then
for _, tc in ipairs(screen[awful.screen.focused()].all_clients) do for _, tc in ipairs(screen[awful.screen.focused()].all_clients) do
if tc.floating and not tc.always_on then if tc.floating and not tc.always_on then
@ -106,9 +129,14 @@ client.connect_signal("focus", function(c)
end end
return return
end end
end) --|hide all floating windows when the user switches to a end
--|tiled client. this is handy when you have a floating end)
--|browser open. unless, client is set to always_on. --[[+]
hide all floating windows when the user switches to a tiled
client. This is handy when you have a floating browser
open. Unless, client is set to always_on or bypass through
rules. ]]
--------------------------------------------------------------- exports -- ; --------------------------------------------------------------- exports -- ;
@ -122,9 +150,3 @@ local function new(arg)
end end
return setmetatable(module, { __call = function(_,...) return new({...}) end }) return setmetatable(module, { __call = function(_,...) return new({...}) end })
-- return module
----------------╮
--▨ FOCUS ▨
----------------╯

View File

@ -1,86 +1,48 @@
--------------------------------------------------------- dependencies -- ;
local grect = require("gears.geometry").rectangle
local tabs = require("machina.tabs")
local geoms = require("machina.geoms")
local helpers = require("machina.helpers")
local get_client_ix = helpers.get_client_ix
local getlowest = helpers.getlowest
local compare = helpers.compare
local tablelength = helpers.tablelength
local set_contains = helpers.set_contains
local clear_tabbar = helpers.clear_tabbar
---------------------------------------------------------------- locals -- ; ---------------------------------------------------------------- locals -- ;
local grect = require("gears.geometry").rectangle local global_client_table = {}
local geoms = {} function get_global_clients()
return global_client_table
geoms.crt43 = function ()
return {
x=awful.screen.focused().workarea.width - client.focus:geometry().width,
y=awful.screen.focused().workarea.height - client.focus:geometry().height,
width=1280,
height=1024
}
end end
geoms.p1080 = function () function update_global_clients(c)
return { global_client_table[c.window] = c
x=awful.screen.focused().workarea.width - client.focus:geometry().width,
y=awful.screen.focused().workarea.height - client.focus:geometry().height,
width=awful.screen.focused().workarea.width * 0.65,
height=awful.screen.focused().workarea.height * 0.90
}
end end
geoms["center"] = function(useless_gap) ------------------------------------------------------------- go_edge() -- ;
return {
x=awful.screen.focused().workarea.width/2 - client.focus.width/2, local function go_edge(direction, regions, current_box)
y=awful.screen.focused().workarea.height/2 - client.focus.height/2 test_box = true
} edge_pos = nil
while test_box do
test_box = grect.get_in_direction(direction, regions, current_box)
if test_box then
current_box = regions[test_box]
edge_pos = test_box
end
end end
geoms["top-left"] = function(useless_gap) return edge_pos
return { end --|
x=useless_gap, --|figures out the beginning of each row on the layout.
y=useless_gap
}
end
geoms["bottom-left"] = function(useless_gap)
return {
x=useless_gap,
y=awful.screen.focused().workarea.height - useless_gap - client.focus.height
}
end
geoms["top-right"] = function(useless_gap)
return {
x=awful.screen.focused().workarea.width - useless_gap - client.focus.width,
y=useless_gap
}
end
geoms["bottom-right"] = function(useless_gap)
return {
x=awful.screen.focused().workarea.width - useless_gap - client.focus.width,
y=awful.screen.focused().workarea.height - useless_gap - client.focus.height
}
end
--------------------------------------------------------------- helpers -- ;
local function getlowest(table)
local low = math.huge
local index
for i, v in pairs(table) do
if v < low then
low = v
index = i
end
end
return index
end
local function compare(a,b)
return a.v < b.v
end
local function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
----------------------------------------------------------- always_on() -- ; ----------------------------------------------------------- always_on() -- ;
@ -89,16 +51,6 @@ local function toggle_always_on()
client.focus.always_on = not always_on client.focus.always_on = not always_on
end end
----------------------------------------- focus_by_direction(direction) -- ;
local function focus_by_direction(direction)
return function()
if not client.focus then return false end
awful.client.focus.bydirection(direction, nil,true)
client.focus:raise()
end
end
--------------------------------------------------------- screen_info() -- ; --------------------------------------------------------- screen_info() -- ;
local function screen_info() local function screen_info()
@ -108,7 +60,11 @@ local function screen_info()
local layout = awful.layout.get(focused_screen) or nil local layout = awful.layout.get(focused_screen) or nil
local focused_client = client.focus or nil local focused_client = client.focus or nil
return focused_screen, workarea, selectedtag, layout, focused_client return focused_screen,
workarea,
selected_tag,
layout,
focused_client
end end
--------------------------------------------------------- get_regions() -- ; --------------------------------------------------------- get_regions() -- ;
@ -132,7 +88,7 @@ local function get_regions()
if layout.machi_get_instance_data then if layout.machi_get_instance_data then
machi_fn = layout.machi_get_instance_data machi_fn = layout.machi_get_instance_data
machi_data = {machi_fn(focused_screen, selected_tag)} machi_data = {machi_fn(screen[focused_screen], selected_tag)}
machi_regions = machi_data[3] machi_regions = machi_data[3]
for i=#machi_regions,1,-1 do for i=#machi_regions,1,-1 do
@ -144,16 +100,9 @@ local function get_regions()
table.sort( table.sort(
machi_regions, machi_regions,
function (a1, a2) function (a1, a2)
local s1 = a1.width * a1.height return a1.id > a2.id
local s2 = a2.width * a2.height
if math.abs(s1 - s2) < 0.01 then
return (a1.x + a1.y) < (a2.x + a2.y)
else
return s1 > s2
end end
end ) --|v2 returns unordered region list and needs sorting.
) --|unlike v1, v2 returns unordered region list and
--|needs sorting
end --|version 2/NG end --|version 2/NG
return machi_regions, machi_fn return machi_regions, machi_fn
@ -178,27 +127,30 @@ local function move_to(location)
end end
end end
-------------------------------------------------- get_active_regions() -- ; ------------------------------------------------------- get_client_info -- ;
local function get_active_regions() local function get_client_info(c)
local active_region = nil local active_region = nil
local outofboundary = nil local outofboundary = nil
local proximity = {} local proximity = {}
local regions = get_regions() local regions = get_regions()
local source_client = c or client.focus or nil
if (not regions) then return {} end
if not regions then return {} end
--|flow control --|flow control
if not client.focus then return {} end if not source_client then return {} end
--|flow control --|flow control
if client.focus.x < 0 or client.focus.y < 0 if source_client.x < 0 or source_client.y < 0
then outofboundary = true then outofboundary = true
end --| negative coordinates always mean out of boundary end --| negative coordinates always mean out of boundary
for i, a in ipairs(regions) do for i, a in ipairs(regions) do
local px = a.x - client.focus.x local px = a.x - source_client.x
local py = a.y - client.focus.y local py = a.y - source_client.y
if px == 0 then px = 1 end if px == 0 then px = 1 end
if py == 0 then py = 1 end if py == 0 then py = 1 end
@ -215,13 +167,10 @@ local function get_active_regions()
if not active_region then if not active_region then
table.sort(proximity, compare) --| sort to get the smallest area table.sort(proximity, compare) --| sort to get the smallest area
active_region = proximity[1].index --| first item should be the right choice active_region = proximity[1].index --| first item should be the right choice
----┐
-- naughty.notify({preset = naughty.config.presets.critical, text=inspect(regions[active_region])})
-- naughty.notify({preset = naughty.config.presets.critical, text=tostring(client.focus.width .. " " .. client.focus.height)})
if client.focus.floating then if source_client.floating then
if regions[active_region].width - client.focus.width ~= 2 if regions[active_region].width - source_client.width ~= 0
or regions[active_region].height - client.focus.height ~= 2 or regions[active_region].height - source_client.height ~= 0
then then
outofboundary = true outofboundary = true
end end
@ -236,41 +185,67 @@ local function get_active_regions()
end --|at this point, we are out of options, set the index end --|at this point, we are out of options, set the index
--|to one and hope for the best. --|to one and hope for the best.
-- refactor
if active_region and source_client.width > regions[active_region].width then
outofboundary = true
end --|machi sometimes could auto expand the client, consider
--|that as out of boundary.
if active_region and source_client.height > regions[active_region].height then
outofboundary = true
end --|machi sometimes could auto expand the client, consider
--|that as out of boundary.
-- refactor
return { return {
active_region = active_region, active_region = active_region,
regions = regions, regions = regions,
outofboundary = outofboundary outofboundary = outofboundary
} }
end end
--|tablist order is adjusted by awesomewm and it will
--|always have the focused client as the first item. ----------------------------------------- focus_by_direction(direction) -- ;
local function focus_by_direction(direction)
return function()
if not client.focus then return false end
awful.client.focus.global_bydirection(direction, nil,true)
client.focus:raise()
end
end
------------------------------------------------------ region_tablist() -- ; ------------------------------------------------------ region_tablist() -- ;
local function region_tablist() local function region_tablist(region_ix, c)
local focused_screen = awful.screen.focused() local focused_screen = awful.screen.focused()
local workarea = awful.screen.focused().workarea local workarea = awful.screen.focused().workarea
local selected_tag = awful.screen.focused().selected_tag local selected_tag = awful.screen.focused().selected_tag
local tablist = {} local tablist = {}
local active_region = nil local active_region = region_ix or nil
local source_client = c or client.focus or nil
local regions = get_regions() local regions = get_regions()
if (not regions) then return {} end if not regions then return {} end
--|flow control --|flow control
if not client.focus then return {} end
------------------ CHECK FOR SIDE EFFECTS
-- if not source_client or source_client.floating then return {} end
--|flow control --|flow control
if client.floating then return {} end if not active_region then
for i, a in ipairs(regions) do for i, a in ipairs(regions) do
if a.x <= client.focus.x and client.focus.x < a.x + a.width and if a.x <= source_client.x and source_client.x < a.x + a.width and
a.y <= client.focus.y and client.focus.y < a.y + a.height a.y <= source_client.y and source_client.y < a.y + a.height
then then
active_region = i active_region = i
end end
end --|focused client's region end
end --|if no region index provided, find the region of the
--|focused_client.
for _, tc in ipairs(screen[focused_screen].tiled_clients) do for _, tc in ipairs(screen[focused_screen].tiled_clients) do
if not (tc.floating or tc.immobilized) then if not (tc.floating or tc.immobilized) then
@ -284,12 +259,6 @@ local function region_tablist()
end end
end --|tablist inside the active region end --|tablist inside the active region
if tablelength(tablist) == 1 then
return {}
end --|flow control: if there is only one client in the
--|region, there is nothing to shuffle. having this here
--|makes it easier to avoid if nesting later.
return tablist return tablist
end end
--|tablist order is adjusted by awesomewm and it will --|tablist order is adjusted by awesomewm and it will
@ -309,11 +278,14 @@ local function expand_horizontal(direction)
if c.direction == direction then if c.direction == direction then
c.direction = nil c.direction = nil
c.maximized_horizontal = false
c.maximized_vertical = false
draw_tabbar(c.region)
return return
end --|reset toggle when sending same shortcut end --|reset toggle when sending same shortcut
--|consequitively --|consequitively
local stuff = get_active_regions() local stuff = get_client_info()
local target = grect.get_in_direction(direction, stuff.regions, client.focus:geometry()) local target = grect.get_in_direction(direction, stuff.regions, client.focus:geometry())
if not target and direction ~= "center" then return end -- flow control if not target and direction ~= "center" then return end -- flow control
@ -322,7 +294,7 @@ local function expand_horizontal(direction)
if direction == "right" then if direction == "right" then
tobe = { tobe = {
x=c.x, x=c.x,
width=math.abs(stuff.regions[target].x + stuff.regions[target].width - c.x), width=math.abs(stuff.regions[target].x + stuff.regions[target].width - c.x - 5),
height=c.height, height=c.height,
y=c.y y=c.y
} }
@ -332,6 +304,8 @@ local function expand_horizontal(direction)
gears.timer.delayed_call(function () gears.timer.delayed_call(function ()
client.focus:geometry(tobe) client.focus:geometry(tobe)
draw_tabbar(c.region)
clear_tabbar(c)
end) end)
return return
end end
@ -350,6 +324,8 @@ local function expand_horizontal(direction)
gears.timer.delayed_call(function () gears.timer.delayed_call(function ()
client.focus:geometry(tobe) client.focus:geometry(tobe)
draw_tabbar(c.region)
clear_tabbar(c)
end) end)
return return
end end
@ -358,8 +334,10 @@ local function expand_horizontal(direction)
if direction == "center" then if direction == "center" then
c.maximized = false c.maximized = false
c.maximixed_vertical = false c.maximixed_vertical = false
fixedchoice = geoms.clients[c.class] or nil
if c.floating then if c.floating then
c.maximized_horizontal = false
geom = geoms.crt43() geom = geoms.crt43()
end end
@ -369,10 +347,17 @@ local function expand_horizontal(direction)
geom = geoms.p1080() geom = geoms.p1080()
end end
if fixedchoice then
c.direction = "center"
geom = fixedchoice()
end
gears.timer.delayed_call(function () gears.timer.delayed_call(function ()
client.focus:geometry(geom) client.focus:geometry(geom)
awful.placement.centered(client.focus) awful.placement.centered(client.focus)
client.focus:raise() client.focus:raise()
draw_tabbar(c.region)
clear_tabbar(c)
end) --|give it time in case maximize_horizontal is end) --|give it time in case maximize_horizontal is
--|adjusted before centering --|adjusted before centering
return return
@ -383,6 +368,9 @@ end
--|tiled clients require an internal maximized property to --|tiled clients require an internal maximized property to
--|be set, otherwise they won't budge. --|be set, otherwise they won't budge.
--|change the logic handling for the center layout to use
--|fixedchoices
----------------------------------------------------- expand_vertical() -- ; ----------------------------------------------------- expand_vertical() -- ;
local function expand_vertical() local function expand_vertical()
@ -394,7 +382,7 @@ local function expand_vertical()
return return
end --|reset toggle maximized state end --|reset toggle maximized state
local stuff = get_active_regions() local stuff = get_client_info()
local target = grect.get_in_direction("down", stuff.regions, client.focus:geometry()) local target = grect.get_in_direction("down", stuff.regions, client.focus:geometry())
if target and stuff.regions[target].x ~= c.x then if target and stuff.regions[target].x ~= c.x then
@ -440,179 +428,385 @@ local function expand_vertical()
return return
end end
---------------------------------------------------- shift_by_direction -- ;
local function shift_by_direction(direction, swap)
return function ()
local stuff = get_active_regions()
local cltbl = awful.client.visible(client.focus.screen, true)
local map = {}
for a,region in ipairs(stuff.regions) do
for i,c in ipairs(cltbl) do
if c.x == region.x and c.y == region.y then
map[a] = i
break --|avoid stacked regions
end
end
end --◸
--|client list order we obtain via cltbl changes in
--|each invokation, therfore we need to map the
--|client table onto the region_list from machi.
--|this will give us the region numbers of clients.
--|naughty.notify({text=inspect(map)})
--◺
local target = grect.get_in_direction(direction, stuff.regions, client.focus:geometry())
--| awesomewm magic function to find out what lies
--| ahead and beyond based on the direction
if not target then
target = stuff.active_region + 1
if target > #stuff.regions then
target = stuff.active_region - 1
end
end --◸
--|we bumped into an edge, try to locate region via
--|region_index and if that also fails, set back the
--|previous region as target clock wise.
--|naughty.notify({text=inspect(target)})
--|naughty.notify({text=inspect(map[target])})
--|naughty.notify({text=inspect(cltbl[map[target]])})
--◺
tobe = stuff.regions[target]
is = client.focus:geometry()
client.focus:geometry(tobe)
client.focus:raise()
--|relocate
swapee = cltbl[map[target]]
--|try to get client at target region
if swap and swapee then
swapee:geometry(is)
swapee:emit_signal("request::activate", "mouse_enter",{raise = true})
end
-- naughty.notify({text=inspect(cltbl[2]:geometry())})
-- --◹◿ naughty.notify({text=inspect(cltbl[2]:geometry())})
end
end
------------------------------------------------------------- shuffle() -- ; ------------------------------------------------------------- shuffle() -- ;
local function shuffle(direction) local function shuffle(direction)
return function() return function()
if direction == "backward" then local tablist = get_tiled_clients()
local tablist = region_tablist() --|this is the ordered list
local prev_client = nil
for i = #tablist, 1, -1 do if not #tablist then return end
prev_client = tablist[i] --▨ flow control
prev_client:emit_signal("request::activate", "mouse_enter",{raise = true})
break --|activate previous client if not client.focus then return end
end --▨ flow control
focused_client_ix = get_client_ix(client.focus.window, tablist)
--|find the index position of the focused client
if not focused_client_ix then return end
--▨ flow control
prev_ix = focused_client_ix - 1
next_ix = focused_client_ix + 1
--|calculate target indexes
if next_ix > #tablist then next_ix = 1 end
if prev_ix < 1 then prev_ix = #tablist end
--|check for validity of the index
if direction == "backward" then
tablist[prev_ix]:emit_signal("request::activate", "mouse_enter",{raise = true})
return return
end end
if direction == "forward" then if direction == "forward" then
local tablist = region_tablist() tablist[next_ix]:emit_signal("request::activate", "mouse_enter",{raise = true})
local next_client = nil
for _, cc in ipairs(tablist) do
client.focus:lower()
next_client = tablist[_+1]
next_client:emit_signal("request::activate", "mouse_enter",{raise = true})
break --|activate next client
end
return return
end end
end end
end end
local function my_shifter(direction) ---------------------------------------------------------- get_swapee() -- ;
local function get_swapee(target_region_ix)
local regions = get_regions()
--| all regions
local cltbl = awful.client.visible(client.focus.screen, true)
--| all visible clients on all regions
--| but we don't know which regions they are at
local swap_map = {}
for a,region in ipairs(regions) do
for i,c in ipairs(cltbl) do
if c.x == region.x and c.y == region.y then
swap_map[a] = i
break --|avoid stacked regions
end
end
end --|iterate over regions, and match the client objects in
--|each region.
local swapee = cltbl[swap_map[target_region_ix]]
return swapee
end
--[[
returns the client object at a specific region. we can
also use signals to keep track of this but we are trying
to avoid exessive use of signals.
--]]
---------------------------------------------------------- my_shifter() -- ;
local function my_shifter(direction, swap)
return function() return function()
if direction == "left" then direction = "backward" end
if direction == "right" then direction = "forward" end
local c = client.focus
local stuff = get_client_info()
local client_region_ix = stuff.active_region
local source_region
local target_region_ix
local target_region
if direction == "backward" then if direction == "backward" then
local next_client = nil if (client_region_ix + 1) > #stuff.regions then
local stuff = get_active_regions() target_region_ix = 1
local client_region = stuff.active_region
local next_region
if (client_region + 1 > #stuff.regions) then
next_region=stuff.regions[1]
else else
next_region=stuff.regions[client_region+1] target_region_ix = client_region_ix+1
end --|figure out the action
if stuff.outofboundary then
next_region=stuff.regions[client_region]
end --|ignore action, and push inside the boundary instead
client.focus:geometry({
x=next_region.x,
y=next_region.y,
width=next_region.width-2,
height=next_region.height-2
})
return
end end
end --|go next region by index,
--|if not reset to first
if direction == "forward" then if direction == "forward" then
if (client_region_ix - 1) < 1 then
local next_client = nil target_region_ix = #stuff.regions
local stuff = get_active_regions()
local client_region = stuff.active_region
local previous_region
if (client_region - 1 < 1) then
previous_region = stuff.regions[#stuff.regions]
else else
previous_region = stuff.regions[client_region-1] target_region_ix = client_region_ix - 1
end --|figure out the action end
end --|go previous region by index,
--|if not reset to last
if stuff.outofboundary then if stuff.outofboundary then
previous_region = stuff.regions[client_region] target_region_ix = client_region_ix
end --|ignore action, and push inside the boundary instead end --|ignore previous when out of boundary
--|probably floating or expanded client
--|push inside the boundary instead
client.focus:geometry({ source_region = stuff.regions[client_region_ix]
x=previous_region.x, target_region = stuff.regions[target_region_ix]
y=previous_region.y, --|target regions geometry
width=previous_region.width-2,
height=previous_region.height-2 local swapee = get_swapee(target_region_ix)
--|visible client at the target region
c:geometry(target_region)
--|relocate client
if not swap then c:raise() end
--|raise
if swap and swapee then
swapee:geometry(source_region)
swapee:emit_signal("request::activate", "mouse_enter",{raise = true})
end --|perform swap
draw_tabbar(target_region_ix)
--|update tabs in target region
draw_tabbar(client_region_ix)
--|update tabs in source region
end
end
---------------------------------------------------- shift_by_direction -- ;
local function shift_by_direction(direction, swap)
return function ()
local c = client.focus
local stuff = get_client_info()
local target_region_ix = nil
local client_region_ix = stuff.active_region
if stuff.outofboundary == true then
return my_shifter(direction)()
end --|my_shifter handles this situation better.
local candidate = {
up = grect.get_in_direction("up", stuff.regions, client.focus:geometry()),
down = grect.get_in_direction("down", stuff.regions, client.focus:geometry()),
left = grect.get_in_direction("left", stuff.regions, client.focus:geometry()),
right = grect.get_in_direction("right", stuff.regions, client.focus:geometry())
} --|awesomewm magic function to find out what lies
--|ahead and beyond based on the direction
target_region_ix = candidate[direction]
--|try to get a candidate region if possible
if not target_region_ix then
if direction == "right" then try = "left" end
if direction == "left" then try = "right" end
if direction == "down" then try = "up" end
if direction == "up" then try = "down" end
target_region_ix = go_edge(try, stuff.regions, client.focus:geometry())
end --|go the beginning or the end if there is no
--|candidate
source_region = stuff.regions[client_region_ix]
target_region = stuff.regions[target_region_ix]
local swapee = get_swapee(target_region_ix)
--|visible client at the target region
c:geometry(target_region)
--|relocate client
if not swap then c:raise() end
--|raise
if swap and swapee then
swapee:geometry(source_region)
swapee:emit_signal("request::activate", "mouse_enter",{raise = true})
end --|perform swap
draw_tabbar(target_region_ix)
--|update tabs in target region
draw_tabbar(client_region_ix)
--|update tabs in source region
end
end
----------------------------------------------------- get_tiled_clients -- ;
function get_tiled_clients(region_ix)
local tablist = region_tablist(region_ix)
local all_clients = get_global_clients()
local tiled_clients = {}
local myorder = {}
local window_ix = {}
for i,t in ipairs(tablist) do
window_ix[t.window] = true
end
local po = 1
for i,c in pairs(all_clients) do
if not c.floating and window_ix[c.window] then
tiled_clients[po] = c
po = po + 1
end
end
return tiled_clients
end
--[[+
global_client_index stores the ordered list of all clients
available and it is used as a blueprint to keep the order
of our tablist intact, without this, tabbars would go out
of order when user focuses via shortcuts (run_or_raise). ]]
-------------------------------------------------------- draw_tabbar() -- ;
function draw_tabbar(region_ix)
local flexlist = tabs.layout()
local tablist = get_tiled_clients(region_ix)
if tablelength(tablist) == 0 then
return
end --|this should only fire on an empty region
if tablelength(tablist) == 1 then
clear_tabbar(tablist[1])
return
end --|reset tabbar titlebar when only
--|one client is in the region.
for c_ix, c in ipairs(tablist) do
local flexlist = tabs.layout()
for cc_ix, cc in ipairs(tablist) do
local buttons = gears.table.join(awful.button({}, 1, function() end))
wid_temp = tabs.create(cc, (cc == c), buttons, c_ix)
flexlist:add(wid_temp)
end
local titlebar = awful.titlebar(c, {
bg = tabs.bg_normal,
size = tabs.size,
position = tabs.position,
}) })
titlebar:setup{layout = wibox.layout.flex.horizontal, flexlist}
awful.titlebar(c, {size=8, position = "top"})
awful.titlebar(c, {size=0, position = "left"})
awful.titlebar(c, {size=0, position = "right"})
end
end end
------------------------------------------------------ signal helpers -- ;
local function manage_signal(c)
if c then
global_client_table[c.window] = c
--|add window.id to global index
local active_region = get_client_info(c).active_region
if active_region then
c.region = active_region
draw_tabbar(active_region)
end --|in case new client appears tiled
--|we must update the regions tabbars.
end end
end end
local function unmanage_signal(c)
if c then
global_client_table[c.window] = nil
--|remove window.id to global index
if not c.floating then
local active_region = get_client_info(c).active_region
if active_region then
draw_tabbar(active_region) end
end
end
end
local function selected_tag_signal(t)
gears.timer.delayed_call(function()
local regions = get_regions()
if regions and #regions then
for i, region in ipairs(regions) do
draw_tabbar(i)
end
end
end)
end
local function floating_signal(c)
if c.floating then
if c.region then
clear_tabbar(c)
draw_tabbar(c.region)
end
end --|window became floating
if not c.floating then
local active_region = get_client_info(c).active_region
if active_region then
c.region = active_region
gears.timer.delayed_call(function(active_region)
draw_tabbar(active_region)
end, active_region)
end
end --|window became tiled
end
--------------------------------------------------------------- signals -- ;
client.connect_signal("property::minimized", function(c)
if c.minimized then unmanage_signal(c) end
if not c.minimized then manage_signal(c) end
end)
--[[+] manage minimized and not minimized ]]
client.connect_signal("property::floating", floating_signal)
--[[+]
when windows switch between float and tiled we must
perform necessary maintenance on the destination and
source regions. a delayed call was necessary when
clients become tiled to give awm enough time to draw the
widgets properly.]]
client.connect_signal("unmanage", unmanage_signal)
--[[+]
when removing a tiled client we must update the tabbars
of others. floating clients do not require any cleanup. ]]
client.connect_signal("manage", manage_signal)
--[[+]
global_client_table is the milestone the tabbars rely on.
whenever a new client appears we must add to it, and
when a client is killed we must make sure it is removed. ]]
tag.connect_signal("property::selected", selected_tag_signal)
--[[+]
property::selected gets called the last, by the time we
are here, we already have the global_client_list to draw
tabbars. This may appear redundant here, but it's good
to have this fire up in case the user switches tags. ]]
--------------------------------------------------------------- exports -- ; --------------------------------------------------------------- exports -- ;
module = { module = {
region_tablist = region_tablist,
focus_by_direction = focus_by_direction, focus_by_direction = focus_by_direction,
compare = compare, get_active_regions = get_client_info,
get_active_regions = get_active_regions,
shift_by_direction = shift_by_direction, shift_by_direction = shift_by_direction,
expand_horizontal = expand_horizontal, expand_horizontal = expand_horizontal,
geoms = geoms,
shuffle = shuffle, shuffle = shuffle,
old_shuffle = old_shuffle,
my_shifter = my_shifter, my_shifter = my_shifter,
expand_vertical = expand_vertical, expand_vertical = expand_vertical,
move_to = move_to, move_to = move_to,
toggle_always_on = toggle_always_on get_regions = get_regions,
toggle_always_on = toggle_always_on,
draw_tabbar = draw_tabbar,
get_global_clients = get_global_clients,
update_global_clients = update_global_clients,
get_client_info = get_client_info,
} }
return module return module
-- naughty.notify({preset = naughty.config.presets.critical,text=inspect(client.focus:geometry())})
-- naughty.notify({preset = naughty.config.presets.critical,text=inspect(regions)})
-- naughty.notify({preset = naughty.config.presets.critical,text=inspect(proximity)})

61
tabs.lua Normal file
View File

@ -0,0 +1,61 @@
--------------------------------------------- widget.tabbar.default.lua -- ;
local gears = require("gears")
local wibox = require("wibox")
local beautiful = require("beautiful")
local bg_normal = beautiful.tabbar_bg_normal or beautiful.bg_normal or "#1a1a1a"
local fg_normal = beautiful.tabbar_fg_normal or beautiful.fg_normal or "#595959"
local bg_focus = beautiful.tabbar_bg_focus or beautiful.bg_focus or "#292929"
local bg_active = "#43417a"
-- local bg_active = "#394037"
local fg_focus = beautiful.tabbar_fg_focus or beautiful.fg_focus or "#ffffff"
local font = beautiful.tabbar_font or beautiful.font or "Recursive Sans Casual Static 8"
local size = beautiful.tabbar_size or 14
local position = beautiful.tabbar_position or "bottom"
local function create(c, focused_bool, buttons, idx)
local flexlist = wibox.layout.flex.horizontal
local title_temp = string.lower(c.class) or c.name or "-"
local bg_temp = bg_normal
local fg_temp = fg_normal
if focused_bool then
bg_temp = bg_active
fg_temp = fg_focus
end
local text_temp = wibox.widget.textbox()
text_temp.align = "center"
text_temp.valign = "center"
text_temp.wrap = "word"
text_temp.font = font
text_temp.focused = false
text_temp.markup = "<span foreground='" .. fg_temp .. "'>" .. title_temp.. "</span>"
if focused_bool then text_temp.focused = true end
local wid_temp = wibox.widget({
id = c.window..idx,
text_temp,
buttons = buttons,
bg = bg_temp,
widget = wibox.container.background()
})
return wid_temp
end
return {
layout = wibox.layout.flex.horizontal,
create = create,
create_focused = create_focused,
position = position,
size = size,
bg_normal = bg_normal,
bg_focus = bg_focus,
}

206
tabs_modern.lua Normal file
View File

@ -0,0 +1,206 @@
--------------------------------------------- widget.tabbar.default.lua -- ;
local awful = require("awful")
local gears = require("gears")
local wibox = require("wibox")
local beautiful = require("beautiful")
local xresources = require("beautiful.xresources")
local dpi = xresources.apply_dpi
local helpers = require("bling.helpers")
local bg_normal = beautiful.tabbar_bg_normal or beautiful.bg_normal or "#ffffff"
local fg_normal = beautiful.tabbar_fg_normal or beautiful.fg_normal or "#000000"
local bg_focus = beautiful.tabbar_bg_focus or beautiful.bg_focus or "#000000"
local fg_focus = beautiful.tabbar_fg_focus or beautiful.fg_focus or "#ffffff"
local font = beautiful.tabbar_font or beautiful.font or "Recursive Sans Casual Static 9"
local size = beautiful.tabbar_size or 30 or dpi(40)
local border_radius =
beautiful.mstab_border_radius or beautiful.border_radius or 4
local position = beautiful.tabbar_position or "bottom"
local close_color = beautiful.tabbar_color_close or beautiful.xcolor1 or
"#f9929b"
local min_color = beautiful.tabbar_color_min or beautiful.xcolor3 or "#fbdf90"
local float_color = beautiful.tabbar_color_float or beautiful.xcolor5 or
"#ccaced"
-- Helper to create buttons
local function create_title_button(c, color_focus, color_unfocus)
local tb_color = wibox.widget {
wibox.widget.textbox(),
forced_width = dpi(8),
forced_height = dpi(8),
bg = color_focus,
shape = gears.shape.circle,
widget = wibox.container.background
}
local tb = wibox.widget {
tb_color,
width = dpi(25),
height = dpi(25),
strategy = "min",
layout = wibox.layout.constraint
}
local function update()
if client.focus == c then
tb_color.bg = color_focus
else
tb_color.bg = color_unfocus
end
end
update()
c:connect_signal("focus", update)
c:connect_signal("unfocus", update)
tb:connect_signal("mouse::enter",
function() tb_color.bg = color_focus .. "70" end)
tb:connect_signal("mouse::leave", function() tb_color.bg = color_focus end)
tb.visible = true
return tb
end
local function create(c, focused_bool, buttons)
-- local flexlist = wibox.layout.flex.horizontal()
local title_temp = c.class or c.name or "-"
local bg_temp = bg_normal
local fg_temp = fg_normal
if focused_bool then
bg_temp = bg_focus
fg_temp = fg_focus
end
local text_temp = wibox.widget.textbox()
text_temp.align = "center"
text_temp.valign = "center"
text_temp.font = font
text_temp.markup = "<span foreground='" .. fg_temp .. "'>" .. title_temp ..
"</span>"
c:connect_signal("property::name", function(_)
local title_temp = c.name or c.class or "-"
text_temp.markup =
"<span foreground='" .. fg_temp .. "'>" .. title_temp .. "</span>"
end)
local tab_content = wibox.widget {
{
awful.widget.clienticon(c),
top = dpi(6),
left = dpi(15),
bottom = dpi(6),
widget = wibox.container.margin
},
text_temp,
nill,
expand = "none",
layout = wibox.layout.align.horizontal
}
if focused_bool then
tab_content = wibox.widget {
{
awful.widget.clienticon(c),
top = dpi(6),
left = dpi(15),
bottom = dpi(6),
widget = wibox.container.margin
},
text_temp,
nil,
expand = "none",
layout = wibox.layout.align.horizontal
}
end
local main_content = nil
local left_shape = nil
local right_shape = nil
if position == "top" then
main_content = wibox.widget {
{
tab_content,
bg = bg_temp,
shape = helpers.shape.prrect(border_radius, true, true, false,
false),
widget = wibox.container.background
},
top = dpi(8),
widget = wibox.container.margin
}
left_shape = helpers.shape.prrect(border_radius, false, false, true,
false)
right_shape = helpers.shape.prrect(border_radius, false, false, false,
true)
else
main_content = wibox.widget {
{
tab_content,
bg = bg_temp,
shape = helpers.shape.prrect(border_radius, false, false, true,
true),
widget = wibox.container.background
},
bottom = dpi(8),
widget = wibox.container.margin
}
left_shape = helpers.shape.prrect(border_radius, false, true, false,
false)
right_shape = helpers.shape.prrect(border_radius, true, false, false,
false)
end
local wid_temp = wibox.widget({
buttons = buttons,
{
{
{
wibox.widget.textbox(),
bg = bg_normal,
shape = left_shape,
widget = wibox.container.background
},
bg = bg_temp,
shape = gears.rectangle,
widget = wibox.container.background
},
width = border_radius + (border_radius / 2),
height = size,
strategy = "exact",
layout = wibox.layout.constraint
},
main_content,
{
{
{
wibox.widget.textbox(),
bg = bg_normal,
shape = right_shape,
widget = wibox.container.background
},
bg = bg_temp,
shape = gears.rectangle,
widget = wibox.container.background
},
width = border_radius + (border_radius / 2),
height = size,
strategy = "exact",
layout = wibox.layout.constraint
},
layout = wibox.layout.align.horizontal
})
return wid_temp
end
return {
layout = wibox.layout.flex.horizontal,
create = create,
position = position,
size = size,
bg_normal = bg_normal,
bg_focus = bg_focus
}