2019-07-06 17:35:12 +02:00
|
|
|
local api = {
|
2019-07-07 19:05:42 +02:00
|
|
|
client = client,
|
2019-07-06 17:35:12 +02:00
|
|
|
beautiful = require("beautiful"),
|
|
|
|
wibox = require("wibox"),
|
|
|
|
awful = require("awful"),
|
|
|
|
screen = require("awful.screen"),
|
|
|
|
layout = require("awful.layout"),
|
|
|
|
keygrabber = require("awful.keygrabber"),
|
|
|
|
naughty = require("naughty"),
|
|
|
|
gears = require("gears"),
|
2019-07-06 23:06:14 +02:00
|
|
|
lgi = require("lgi"),
|
2019-07-06 17:35:12 +02:00
|
|
|
dpi = require("beautiful.xresources").apply_dpi,
|
|
|
|
}
|
|
|
|
|
2019-07-07 19:05:42 +02:00
|
|
|
-- -- Seems not needed?
|
|
|
|
-- local focus_timer = 0
|
|
|
|
-- api.client.connect_signal(
|
|
|
|
-- "focus",
|
|
|
|
-- function (c)
|
|
|
|
-- if c.focus_timer == nil or c.focus_timer < focus_timer then
|
|
|
|
-- c.focus_timer = focus_timer
|
|
|
|
-- end
|
|
|
|
-- focus_timer = c.focus_timer + 1
|
|
|
|
-- c.focus_timer = focus_timer
|
|
|
|
-- end
|
|
|
|
-- )
|
|
|
|
|
2019-07-07 23:36:48 +02:00
|
|
|
local function min(a, b)
|
|
|
|
if a < b then return a else return b end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function max(a, b)
|
|
|
|
if a < b then return b else return a end
|
|
|
|
end
|
|
|
|
|
2019-07-06 23:06:14 +02:00
|
|
|
local function with_alpha(col, alpha)
|
|
|
|
_, r, g, b, a = col:get_rgba()
|
|
|
|
return api.lgi.cairo.SolidPattern.create_rgba(r, g, b, alpha)
|
|
|
|
end
|
|
|
|
|
2019-07-08 13:36:06 +02:00
|
|
|
|
|
|
|
local tablist_font_desc = api.beautiful.get_merged_font(
|
2019-07-08 22:12:38 +02:00
|
|
|
api.beautiful.mono_font or api.beautiful.font, api.dpi(10))
|
2019-07-07 23:18:10 +02:00
|
|
|
local font_color = with_alpha(api.gears.color(api.beautiful.fg_normal), 1)
|
2019-07-06 17:35:12 +02:00
|
|
|
local label_size = api.dpi(30)
|
2019-07-06 23:06:14 +02:00
|
|
|
local border_color = with_alpha(api.gears.color(api.beautiful.border_focus), 0.75)
|
|
|
|
local fill_color = with_alpha(api.gears.color(api.beautiful.bg_normal), 0.5)
|
2019-07-07 23:18:10 +02:00
|
|
|
local fill_color_hl = with_alpha(api.gears.color(api.beautiful.bg_focus), 1)
|
2019-07-06 18:22:19 +02:00
|
|
|
-- for comparing floats
|
|
|
|
local threshold = 0.1
|
2019-07-07 23:36:48 +02:00
|
|
|
local traverse_radius = api.dpi(5)
|
2019-07-06 17:35:12 +02:00
|
|
|
|
|
|
|
local function start(c)
|
|
|
|
local screen = c.screen
|
2019-07-08 19:15:05 +02:00
|
|
|
local screen_x = screen.geometry.x
|
|
|
|
local screen_y = screen.geometry.y
|
|
|
|
|
2019-07-06 17:35:12 +02:00
|
|
|
local layout = api.layout.get(screen)
|
|
|
|
if c.floating or layout.get_regions == nil then return end
|
|
|
|
|
2019-07-06 18:22:19 +02:00
|
|
|
local regions = layout.get_regions()
|
|
|
|
|
2019-07-06 17:35:12 +02:00
|
|
|
local infobox = api.wibox({
|
2019-07-06 18:22:19 +02:00
|
|
|
screen = screen,
|
2019-07-06 17:35:12 +02:00
|
|
|
x = screen.workarea.x,
|
|
|
|
y = screen.workarea.y,
|
|
|
|
width = screen.workarea.width,
|
|
|
|
height = screen.workarea.height,
|
|
|
|
bg = "#ffffff00",
|
|
|
|
opacity = 1,
|
|
|
|
ontop = true
|
|
|
|
})
|
|
|
|
infobox.visible = true
|
|
|
|
|
2019-07-07 19:30:05 +02:00
|
|
|
local tablist = nil
|
|
|
|
local tablist_index = nil
|
|
|
|
|
2019-07-07 23:36:48 +02:00
|
|
|
local traverse_x = c.x + traverse_radius
|
|
|
|
local traverse_y = c.y + traverse_radius
|
2019-07-06 18:22:19 +02:00
|
|
|
|
2019-07-06 17:35:12 +02:00
|
|
|
local function draw_info(context, cr, width, height)
|
|
|
|
cr:set_source_rgba(0, 0, 0, 0)
|
|
|
|
cr:rectangle(0, 0, width, height)
|
|
|
|
cr:fill()
|
|
|
|
|
|
|
|
local msg, ext
|
|
|
|
for i, a in ipairs(regions) do
|
2019-07-08 19:15:05 +02:00
|
|
|
cr:rectangle(a.x - screen_x, a.y - screen_y, a.width, a.height)
|
2019-07-06 23:06:14 +02:00
|
|
|
cr:clip()
|
2019-07-07 23:18:10 +02:00
|
|
|
|
|
|
|
if i == c.machi_region and tablist ~= nil then
|
|
|
|
|
2019-07-08 13:36:06 +02:00
|
|
|
local pl = api.lgi.Pango.Layout.create(cr)
|
|
|
|
pl:set_font_description(tablist_font_desc)
|
2019-07-08 16:03:49 +02:00
|
|
|
|
|
|
|
local vpadding = api.dpi(10)
|
|
|
|
local height = vpadding
|
|
|
|
local exts = {}
|
2019-07-07 23:18:10 +02:00
|
|
|
|
|
|
|
for index, tc in ipairs(tablist) do
|
|
|
|
local label = tc.name
|
2019-07-08 13:36:06 +02:00
|
|
|
pl:set_text(label)
|
|
|
|
local w, h
|
|
|
|
w, h = pl:get_size()
|
|
|
|
w = w / api.lgi.Pango.SCALE
|
|
|
|
h = h / api.lgi.Pango.SCALE
|
|
|
|
local ext = { width = w, height = h, x_bearing = 0, y_bearing = 0 }
|
2019-07-08 16:03:49 +02:00
|
|
|
exts[#exts + 1] = ext
|
|
|
|
height = height + ext.height + vpadding
|
|
|
|
end
|
|
|
|
|
2019-07-08 19:15:05 +02:00
|
|
|
local x_offset = a.x + a.width / 2 - screen_x
|
|
|
|
local y_offset = a.y + a.height / 2 - height / 2 + vpadding - screen_y
|
2019-07-08 16:03:49 +02:00
|
|
|
|
2019-07-08 19:15:05 +02:00
|
|
|
cr:rectangle(a.x - screen_x, y_offset - vpadding - screen_y, a.width, height)
|
2019-07-08 16:03:49 +02:00
|
|
|
cr:set_source(fill_color)
|
|
|
|
cr:fill()
|
|
|
|
|
|
|
|
for index, tc in ipairs(tablist) do
|
|
|
|
local label = tc.name
|
|
|
|
local ext = exts[index]
|
2019-07-07 23:18:10 +02:00
|
|
|
if index == tablist_index then
|
2019-07-08 16:03:49 +02:00
|
|
|
cr:rectangle(x_offset - ext.width / 2 - vpadding / 2, y_offset - vpadding / 2, ext.width + vpadding, ext.height + vpadding)
|
2019-07-07 23:18:10 +02:00
|
|
|
cr:set_source(fill_color_hl)
|
2019-07-08 16:03:49 +02:00
|
|
|
cr:fill()
|
2019-07-07 23:18:10 +02:00
|
|
|
end
|
2019-07-08 13:36:06 +02:00
|
|
|
pl:set_text(label)
|
2019-07-08 16:03:49 +02:00
|
|
|
cr:move_to(x_offset - ext.width / 2 - ext.x_bearing, y_offset - ext.y_bearing)
|
2019-07-07 23:18:10 +02:00
|
|
|
cr:set_source(font_color)
|
2019-07-08 13:36:06 +02:00
|
|
|
cr:show_layout(pl)
|
2019-07-07 23:18:10 +02:00
|
|
|
|
2019-07-08 16:03:49 +02:00
|
|
|
y_offset = y_offset + ext.height + vpadding
|
2019-07-07 23:18:10 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-06 23:06:14 +02:00
|
|
|
-- cr:set_source(fill_color)
|
|
|
|
-- cr:rectangle(a.x, a.y, a.width, a.height)
|
|
|
|
-- cr:fill()
|
|
|
|
cr:set_source(border_color)
|
2019-07-08 19:15:05 +02:00
|
|
|
cr:rectangle(a.x - screen_x, a.y - screen_y, a.width, a.height)
|
2019-07-06 23:06:14 +02:00
|
|
|
cr:set_line_width(10.0)
|
|
|
|
cr:stroke()
|
|
|
|
cr:reset_clip()
|
2019-07-06 17:35:12 +02:00
|
|
|
end
|
2019-07-06 18:22:19 +02:00
|
|
|
|
2019-07-06 23:06:14 +02:00
|
|
|
-- show the traverse point
|
2019-07-08 19:15:05 +02:00
|
|
|
cr:rectangle(traverse_x - screen_x - traverse_radius, traverse_y - screen_y - traverse_radius, traverse_radius * 2, traverse_radius * 2)
|
2019-07-06 23:06:14 +02:00
|
|
|
cr:set_source_rgba(1, 1, 1, 1)
|
|
|
|
cr:fill()
|
2019-07-06 17:35:12 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
infobox.bgimage = draw_info
|
|
|
|
|
|
|
|
local kg
|
|
|
|
kg = keygrabber.run(
|
|
|
|
function (mod, key, event)
|
|
|
|
if event == "release" then return end
|
2019-07-07 19:30:05 +02:00
|
|
|
if key == "Tab" then
|
|
|
|
if tablist == nil then
|
|
|
|
tablist = {}
|
|
|
|
for _, tc in ipairs(screen.tiled_clients) do
|
|
|
|
if tc.machi_region == c.machi_region then
|
|
|
|
tablist[#tablist + 1] = tc
|
|
|
|
end
|
|
|
|
end
|
2019-07-06 17:35:12 +02:00
|
|
|
|
2019-07-07 19:30:05 +02:00
|
|
|
tablist_index = 1
|
|
|
|
end
|
|
|
|
|
|
|
|
if #tablist > 0 then
|
|
|
|
tablist_index = tablist_index % #tablist + 1
|
|
|
|
c = tablist[tablist_index]
|
|
|
|
c:emit_signal("request::activate", "mouse.move", {raise=false})
|
|
|
|
c:raise()
|
2019-07-07 23:18:10 +02:00
|
|
|
|
|
|
|
infobox.bgimage = draw_info
|
2019-07-07 19:30:05 +02:00
|
|
|
end
|
|
|
|
elseif key == "Up" or key == "Down" or key == "Left" or key == "Right" then
|
2019-07-06 18:22:19 +02:00
|
|
|
local choice = nil
|
|
|
|
local choice_value
|
|
|
|
|
|
|
|
for i, a in ipairs(regions) do
|
|
|
|
local v
|
|
|
|
if key == "Up" then
|
|
|
|
if a.x < traverse_x + threshold
|
|
|
|
and traverse_x < a.x + a.width + threshold then
|
|
|
|
v = traverse_y - a.y - a.height
|
|
|
|
else
|
|
|
|
v = -1
|
|
|
|
end
|
|
|
|
elseif key == "Down" then
|
|
|
|
if a.x < traverse_x + threshold
|
|
|
|
and traverse_x < a.x + a.width + threshold then
|
|
|
|
v = a.y - traverse_y
|
|
|
|
else
|
|
|
|
v = -1
|
|
|
|
end
|
|
|
|
elseif key == "Left" then
|
|
|
|
if a.y < traverse_y + threshold
|
|
|
|
and traverse_y < a.y + a.height + threshold then
|
|
|
|
v = traverse_x - a.x - a.width
|
|
|
|
else
|
|
|
|
v = -1
|
|
|
|
end
|
|
|
|
elseif key == "Right" then
|
|
|
|
if a.y < traverse_y + threshold
|
|
|
|
and traverse_y < a.y + a.height + threshold then
|
|
|
|
v = a.x - traverse_x
|
|
|
|
else
|
|
|
|
v = -1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if (v > threshold) and (choice_value == nil or choice_value > v) then
|
|
|
|
choice = i
|
|
|
|
choice_value = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if choice ~= nil and choice_value > threshold then
|
2019-07-07 19:05:42 +02:00
|
|
|
local shift = false
|
|
|
|
for i, m in ipairs(mod) do
|
|
|
|
if m == "Shift" then shift = true end
|
|
|
|
end
|
|
|
|
|
|
|
|
local move_traverse = false
|
|
|
|
|
|
|
|
if shift then
|
|
|
|
-- move the window
|
|
|
|
c.machi_region = choice
|
|
|
|
api.layout.arrange(screen)
|
|
|
|
move_traverse = true
|
|
|
|
else
|
|
|
|
-- move the focus
|
|
|
|
for _, tc in ipairs(screen.tiled_clients) do
|
|
|
|
if tc.machi_region == choice then
|
2019-07-07 19:30:05 +02:00
|
|
|
c = tc
|
|
|
|
api.client.focus = c
|
2019-07-07 19:05:42 +02:00
|
|
|
move_traverse = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-07-06 18:22:19 +02:00
|
|
|
|
2019-07-07 19:05:42 +02:00
|
|
|
if move_traverse then
|
2019-07-07 23:36:48 +02:00
|
|
|
traverse_x = max(regions[choice].x + traverse_radius, min(regions[choice].x + regions[choice].width - traverse_radius, traverse_x))
|
|
|
|
traverse_y = max(regions[choice].y + traverse_radius, min(regions[choice].y + regions[choice].height - traverse_radius, traverse_y))
|
2019-07-07 19:30:05 +02:00
|
|
|
tablist = nil
|
2019-07-07 19:05:42 +02:00
|
|
|
end
|
2019-07-06 18:22:19 +02:00
|
|
|
|
|
|
|
infobox.bgimage = draw_info
|
|
|
|
end
|
2019-07-06 18:23:58 +02:00
|
|
|
elseif key == "Escape" or key == "Return" then
|
2019-07-06 17:35:12 +02:00
|
|
|
infobox.visible = false
|
2019-07-06 18:22:19 +02:00
|
|
|
keygrabber.stop(kg)
|
2019-07-07 19:30:05 +02:00
|
|
|
else
|
|
|
|
print("Unhandled key " .. key)
|
2019-07-06 17:35:12 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
return {
|
|
|
|
start = start,
|
|
|
|
}
|