Add a window switcher widget (#84)
This commit is contained in:
parent
3fc80c7dfd
commit
ae0a999e1b
|
@ -5,4 +5,5 @@ The following developers have contributed major code to bling:
|
|||
* [Grumph](https://github.com/Grumph)
|
||||
* [Bysmutheye](https://github.com/Bysmutheye)
|
||||
* [HumblePresent](https://github.com/HumblePresent)
|
||||
* [Kasper24](https://github.com/Kasper24)
|
||||
* [undefinedDarkness](https://github.com/undefinedDarkness)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
return {
|
||||
tag_preview = require(... .. ".tag_preview"),
|
||||
task_preview = require(... .. ".task_preview"),
|
||||
window_switcher = require(... .. ".window_switcher"),
|
||||
tabbed_misc = require(... .. ".tabbed_misc"),
|
||||
}
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
local cairo = require("lgi").cairo
|
||||
local awful = require("awful")
|
||||
local gears = require("gears")
|
||||
local wibox = require("wibox")
|
||||
local beautiful = require("beautiful")
|
||||
local helpers = require(tostring(...):match(".*bling") .. ".helpers")
|
||||
local dpi = beautiful.xresources.apply_dpi
|
||||
|
||||
local window_switcher_first_client -- The client that was focused when the window_switcher was activated
|
||||
local window_switcher_minimized_clients = {} -- The clients that were minimized when the window switcher was activated
|
||||
local window_switcher_grabber
|
||||
|
||||
local get_num_clients = function()
|
||||
local minimized_clients_in_tag = 0
|
||||
local matcher = function (c)
|
||||
return awful.rules.match(c, { minimized = true, skip_taskbar = false, hidden = false, first_tag = awful.screen.focused().selected_tag })
|
||||
end
|
||||
for c in awful.client.iterate(matcher) do
|
||||
minimized_clients_in_tag = minimized_clients_in_tag + 1
|
||||
end
|
||||
return minimized_clients_in_tag + #awful.screen.focused().clients
|
||||
end
|
||||
|
||||
local window_switcher_hide = function(window_switcher_box)
|
||||
-- Add currently focused client to history
|
||||
if client.focus then
|
||||
local window_switcher_last_client = client.focus
|
||||
awful.client.focus.history.add(window_switcher_last_client)
|
||||
-- Raise client that was focused originally
|
||||
-- Then raise last focused client
|
||||
if window_switcher_first_client and window_switcher_first_client.valid then
|
||||
window_switcher_first_client:raise()
|
||||
window_switcher_last_client:raise()
|
||||
end
|
||||
end
|
||||
|
||||
-- Minimize originally minimized clients
|
||||
local s = awful.screen.focused()
|
||||
for _, c in pairs(window_switcher_minimized_clients) do
|
||||
if c and c.valid and not (client.focus and client.focus == c) then
|
||||
c.minimized = true
|
||||
end
|
||||
end
|
||||
-- Reset helper table
|
||||
window_switcher_minimized_clients = {}
|
||||
|
||||
-- Resume recording focus history
|
||||
awful.client.focus.history.enable_tracking()
|
||||
-- Stop and hide window_switcher
|
||||
awful.keygrabber.stop(window_switcher_grabber)
|
||||
window_switcher_box.visible = false
|
||||
end
|
||||
|
||||
local function draw_widget(type, background, border_width, border_radius, border_color,
|
||||
clients_spacing, client_icon_horizontal_spacing, client_width, client_height,
|
||||
client_margins, thumbnail_margins, thumbnail_scale, name_margins, name_valign,
|
||||
name_forced_width, name_font, name_normal_color, name_focus_color,
|
||||
icon_valign, icon_width, mouse_keys)
|
||||
|
||||
local tasklist_widget = type == "thumbnail"
|
||||
and
|
||||
awful.widget.tasklist {
|
||||
screen = awful.screen.focused(),
|
||||
filter = awful.widget.tasklist.filter.currenttags,
|
||||
buttons = mouse_keys,
|
||||
style = { font = name_font, fg_normal = name_normal_color, fg_focus = name_focus_color },
|
||||
layout = { layout = wibox.layout.flex.horizontal, spacing = clients_spacing },
|
||||
widget_template =
|
||||
{
|
||||
widget = wibox.container.background,
|
||||
id = "bg_role",
|
||||
forced_width = client_width,
|
||||
forced_height = client_height,
|
||||
create_callback = function(self, c, _, __)
|
||||
local content = gears.surface(c.content)
|
||||
local cr = cairo.Context(content)
|
||||
local x, y, w, h = cr:clip_extents()
|
||||
local img = cairo.ImageSurface.create(cairo.Format.ARGB32, w - x, h - y)
|
||||
cr = cairo.Context(img)
|
||||
cr:set_source_surface(content, 0, 0)
|
||||
cr.operator = cairo.Operator.SOURCE
|
||||
cr:paint()
|
||||
self:get_children_by_id("thumbnail")[1].image = gears.surface.load(img)
|
||||
end,
|
||||
{
|
||||
{
|
||||
{
|
||||
horizontal_fit_policy = thumbnail_scale == true and "fit" or "auto",
|
||||
vertical_fit_policy = thumbnail_scale == true and "fit" or "auto",
|
||||
id = "thumbnail",
|
||||
widget = wibox.widget.imagebox
|
||||
},
|
||||
margins = thumbnail_margins,
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
{
|
||||
{
|
||||
{
|
||||
id = "icon_role",
|
||||
widget = wibox.widget.imagebox
|
||||
},
|
||||
forced_width = icon_width,
|
||||
valign = icon_valign,
|
||||
widget = wibox.container.place
|
||||
},
|
||||
{
|
||||
{
|
||||
forced_width = name_forced_width,
|
||||
valign = name_valign,
|
||||
id = "text_role",
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
margins = name_margins,
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
spacing = client_icon_horizontal_spacing,
|
||||
layout = wibox.layout.fixed.horizontal
|
||||
},
|
||||
layout = wibox.layout.flex.vertical
|
||||
}
|
||||
}
|
||||
}
|
||||
or
|
||||
awful.widget.tasklist {
|
||||
screen = awful.screen.focused(),
|
||||
filter = awful.widget.tasklist.filter.currenttags,
|
||||
buttons = mouse_keys,
|
||||
style = { font = name_font, fg_normal = name_normal_color, fg_focus = name_focus_color },
|
||||
layout = { layout = wibox.layout.fixed.vertical, spacing = clients_spacing },
|
||||
widget_template =
|
||||
{
|
||||
widget = wibox.container.background,
|
||||
id = "bg_role",
|
||||
forced_width = client_width,
|
||||
forced_height = client_height,
|
||||
{
|
||||
{
|
||||
{
|
||||
id = "icon_role",
|
||||
widget = wibox.widget.imagebox
|
||||
},
|
||||
forced_width = icon_width,
|
||||
valign = icon_valign,
|
||||
widget = wibox.container.place
|
||||
},
|
||||
{
|
||||
{
|
||||
forced_width = name_forced_width,
|
||||
valign = name_valign,
|
||||
id = "text_role",
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
margins = name_margins,
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
spacing = client_icon_horizontal_spacing,
|
||||
layout = wibox.layout.fixed.horizontal
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return wibox.widget
|
||||
{
|
||||
{
|
||||
tasklist_widget,
|
||||
margins = client_margins,
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
shape_border_width = border_width,
|
||||
shape_border_color = border_color,
|
||||
bg = background,
|
||||
shape = helpers.shape.rrect(border_radius),
|
||||
widget = wibox.container.background
|
||||
}
|
||||
end
|
||||
|
||||
local enable = function(opts)
|
||||
local opts = opts or {}
|
||||
|
||||
local type = opts.type or "thumbnail"
|
||||
local background = beautiful.window_switcher_widget_bg or "#000000"
|
||||
local border_width = beautiful.window_switcher_widget_border_width or dpi(3)
|
||||
local border_radius = beautiful.window_switcher_widget_border_radius or dpi(0)
|
||||
local border_color = beautiful.window_switcher_widget_border_color or "#ffffff"
|
||||
local clients_spacing = beautiful.window_switcher_clients_spacing or dpi(20)
|
||||
local client_icon_horizontal_spacing = beautiful.window_switcher_client_icon_horizontal_spacing or dpi(5)
|
||||
local client_width = beautiful.window_switcher_client_width or dpi(type == "thumbnail" and 150 or 500)
|
||||
local client_height = beautiful.window_switcher_client_height or dpi(type == "thumbnail" and 250 or 50)
|
||||
local client_margins = beautiful.window_switcher_client_margins or dpi(10)
|
||||
local thumbnail_margins = beautiful.window_switcher_thumbnail_margins or dpi(5)
|
||||
local thumbnail_scale = beautiful.thumbnail_scale or false
|
||||
local name_margins = beautiful.window_switcher_name_margins or dpi(10)
|
||||
local name_valign = beautiful.window_switcher_name_valign or "center"
|
||||
local name_forced_width = beautiful.window_switcher_name_forced_width or dpi(type == "thumbnail" and 200 or 550)
|
||||
local name_font = beautiful.window_switcher_name_font or beautiful.font
|
||||
local name_normal_color = beautiful.window_switcher_name_normal_color or "#FFFFFF"
|
||||
local name_focus_color = beautiful.window_switcher_name_focus_color or "#FF0000"
|
||||
local icon_valign = beautiful.window_switcher_icon_valign or "center"
|
||||
local icon_width = beautiful.window_switcher_icon_width or dpi(40)
|
||||
|
||||
local hide_window_switcher_key = opts.hide_window_switcher_key or "Escape"
|
||||
|
||||
local select_client_key = opts.select_client_key or 1
|
||||
local minimize_key = opts.minimize_key or "n"
|
||||
local unminimize_key = opts.unminimize_key or "N"
|
||||
local kill_client_key = opts.kill_client_key or "q"
|
||||
|
||||
local cycle_key = opts.cycle_key or "Tab"
|
||||
|
||||
local previous_key = opts.previous_key or "Left"
|
||||
local next_key = opts.next_key or "Right"
|
||||
|
||||
local vim_previous_key = opts.vim_previous_key or "h"
|
||||
local vim_next_key = opts.vim_next_key or "l"
|
||||
|
||||
local scroll_previous_key = opts.scroll_previous_key or 4
|
||||
local scroll_next_key = opts.scroll_next_key or 5
|
||||
|
||||
local window_switcher_box = awful.popup
|
||||
({
|
||||
bg = "#00000000",
|
||||
visible = false,
|
||||
ontop = true,
|
||||
placement = awful.placement.centered,
|
||||
screen = awful.screen.focused(),
|
||||
widget = wibox.container.background, -- A dummy widget to make awful.popup not scream
|
||||
widget =
|
||||
{
|
||||
{
|
||||
draw_widget(),
|
||||
margins = client_margins,
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
shape_border_width = border_width,
|
||||
shape_border_color = border_color,
|
||||
bg = background,
|
||||
shape = helpers.shape.rrect(border_radius),
|
||||
widget = wibox.container.background
|
||||
}
|
||||
})
|
||||
|
||||
local mouse_keys = gears.table.join
|
||||
(
|
||||
awful.button
|
||||
{
|
||||
modifiers = { "Any" },
|
||||
button = select_client_key,
|
||||
on_press = function(c)
|
||||
client.focus = c
|
||||
end,
|
||||
},
|
||||
|
||||
awful.button
|
||||
{
|
||||
modifiers = { "Any" },
|
||||
button = scroll_previous_key,
|
||||
on_press = function()
|
||||
awful.client.focus.byidx(-1)
|
||||
end,
|
||||
},
|
||||
|
||||
awful.button
|
||||
{
|
||||
modifiers = { "Any" },
|
||||
button = scroll_next_key,
|
||||
on_press = function()
|
||||
awful.client.focus.byidx(1)
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
local keyboard_keys =
|
||||
{
|
||||
[hide_window_switcher_key] = function() window_switcher_hide(window_switcher_box) end,
|
||||
|
||||
[minimize_key] = function() if client.focus then client.focus.minimized = true end end,
|
||||
[unminimize_key] = function() if awful.client.restore() then client.focus = awful.client.restore() end end,
|
||||
[kill_client_key] = function() if client.focus then client.focus:kill() end end,
|
||||
|
||||
[cycle_key] = function() awful.client.focus.byidx(1) end,
|
||||
|
||||
[previous_key] = function() awful.client.focus.byidx(1) end,
|
||||
[next_key] = function() awful.client.focus.byidx(-1) end,
|
||||
|
||||
[vim_previous_key] = function() awful.client.focus.byidx(1) end,
|
||||
[vim_next_key] = function() awful.client.focus.byidx(-1) end,
|
||||
}
|
||||
|
||||
window_switcher_box:connect_signal("property::width", function()
|
||||
if window_switcher_box.visible and get_num_clients() == 0 then
|
||||
window_switcher_hide(window_switcher_box)
|
||||
end
|
||||
end)
|
||||
|
||||
window_switcher_box:connect_signal("property::height", function()
|
||||
if window_switcher_box.visible and get_num_clients() == 0 then
|
||||
window_switcher_hide(window_switcher_box)
|
||||
end
|
||||
end)
|
||||
|
||||
awesome.connect_signal("bling::window_switcher::turn_on", function()
|
||||
local number_of_clients = get_num_clients()
|
||||
if number_of_clients == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Store client that is focused in a variable
|
||||
window_switcher_first_client = client.focus
|
||||
|
||||
-- Stop recording focus history
|
||||
awful.client.focus.history.disable_tracking()
|
||||
|
||||
-- Go to previously focused client (in the tag)
|
||||
awful.client.focus.history.previous()
|
||||
|
||||
-- Track minimized clients
|
||||
-- Unminimize them
|
||||
-- Lower them so that they are always below other
|
||||
-- originally unminimized windows
|
||||
local clients = awful.screen.focused().selected_tag:clients()
|
||||
for _, c in pairs(clients) do
|
||||
if c.minimized then
|
||||
table.insert(window_switcher_minimized_clients, c)
|
||||
c.minimized = false
|
||||
c:lower()
|
||||
end
|
||||
end
|
||||
|
||||
-- Start the keygrabber
|
||||
window_switcher_grabber = awful.keygrabber.run(function(_, key, event)
|
||||
if event == "release" then
|
||||
-- Hide if the modifier was released
|
||||
-- We try to match Super or Alt or Control since we do not know which keybind is
|
||||
-- used to activate the window switcher (the keybind is set by the user in keys.lua)
|
||||
if key:match("Super") or key:match("Alt") or key:match("Control") then
|
||||
window_switcher_hide(window_switcher_box)
|
||||
end
|
||||
-- Do nothing
|
||||
return
|
||||
end
|
||||
|
||||
-- Run function attached to key, if it exists
|
||||
if keyboard_keys[key] then
|
||||
keyboard_keys[key]()
|
||||
end
|
||||
end)
|
||||
|
||||
window_switcher_box.widget = draw_widget(type, background, border_width,
|
||||
border_radius, border_color, clients_spacing, client_icon_horizontal_spacing,
|
||||
client_width, client_height, client_margins, thumbnail_margins, thumbnail_scale,
|
||||
name_margins, name_valign, name_forced_width, name_font, name_normal_color,
|
||||
name_focus_color, icon_valign, icon_width, mouse_keys)
|
||||
window_switcher_box.visible = true
|
||||
end)
|
||||
end
|
||||
|
||||
return {enable = enable}
|
Loading…
Reference in New Issue