mirror of
https://github.com/elenapan/dotfiles.git
synced 2025-12-27 15:54:57 +08:00
Implement window switcher
This commit is contained in:
parent
a6b7c069a2
commit
dfd34f11bc
3 changed files with 290 additions and 18 deletions
274
config/awesome/elemental/window_switcher.lua
Normal file
274
config/awesome/elemental/window_switcher.lua
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
local awful = require("awful")
|
||||
local wibox = require("wibox")
|
||||
local beautiful = require("beautiful")
|
||||
local helpers = require("helpers")
|
||||
local keys = require("keys")
|
||||
|
||||
-- TODO ability to switch to minimized clients:
|
||||
-- Might need to ditch the "easy" tasklist approach for something manual
|
||||
|
||||
local window_switcher_margin = dpi(10)
|
||||
local item_size = dpi(50)
|
||||
|
||||
-- Set up text symbols and colors to be used instead of awful.widget.clienticon
|
||||
-- Based on the client's `class` property
|
||||
local class_icons = {
|
||||
-- Terminals
|
||||
['kitty'] = { symbol = "", color = x.color5 },
|
||||
['Alacritty'] = { symbol = "", color = x.color5 },
|
||||
['Termite'] = { symbol = "", color = x.color5 },
|
||||
['URxvt'] = { symbol = "", color = x.color5 },
|
||||
['st'] = { symbol = "", color = x.color5 },
|
||||
['st-256color'] = { symbol = "", color = x.color5 },
|
||||
|
||||
-- Image viewers
|
||||
['feh'] = { symbol = "", color = x.color1 },
|
||||
['Sxiv'] = { symbol = "", color = x.color1 },
|
||||
|
||||
-- General
|
||||
['TelegramDesktop'] = { symbol = "", color = x.color4 },
|
||||
['Firefox'] = { symbol = "", color = x.color3 },
|
||||
['Chromium'] = { symbol = "", color = x.color4 },
|
||||
['Chromium-browser'] = { symbol = "", color = x.color4 },
|
||||
['Steam'] = { symbol = "", color = x.color2 },
|
||||
['Lutris'] = { symbol = "", color = x.color6 },
|
||||
['editor'] = { symbol = "", color = x.color5 },
|
||||
['Emacs'] = { symbol = "", color = x.color5 },
|
||||
['email'] = { symbol = "", color = x.color6 },
|
||||
['music'] = { symbol = "", color = x.color6 },
|
||||
['mpv'] = { symbol = "", color = x.color6 },
|
||||
['KeePassXC'] = { symbol = "", color = x.color1 },
|
||||
['Gucharmap'] = { symbol = "", color = x.color6 },
|
||||
['Pavucontrol'] = { symbol = "", color = x.color4 },
|
||||
['htop'] = { symbol = "", color = x.color2 },
|
||||
['Screenruler'] = { symbol = "", color = x.color3 },
|
||||
['Galculator'] = { symbol = "", color = x.color2 },
|
||||
|
||||
-- File managers
|
||||
['Thunar'] = { symbol = "", color = x.color3 },
|
||||
['Nemo'] = { symbol = "", color = x.color3 },
|
||||
|
||||
['Gimp'] = { symbol = "", color = x.color4 },
|
||||
['Inkscape'] = { symbol = "", color = x.color2 },
|
||||
['Gpick'] = { symbol = "", color = x.color6 },
|
||||
|
||||
-- Default
|
||||
['_'] = { symbol = "", color = x.color7.."99" }
|
||||
}
|
||||
|
||||
awful.screen.connect_for_each_screen(function(s)
|
||||
s.window_switcher = wibox({
|
||||
width = dpi(500),
|
||||
height = dpi(100), -- Will change dynamically
|
||||
visible = false,
|
||||
ontop = true,
|
||||
screen = s,
|
||||
bg = "#00000000",
|
||||
fg = x.foreground
|
||||
})
|
||||
awful.placement.centered(s.window_switcher, { honor_workarea = true, honor_padding = true })
|
||||
|
||||
-- Tasklist
|
||||
s.window_switcher_tasklist = awful.widget.tasklist {
|
||||
screen = s,
|
||||
filter = awful.widget.tasklist.filter.currenttags,
|
||||
buttons = keys.tasklist_buttons,
|
||||
style = {
|
||||
font = beautiful.tasklist_font,
|
||||
-- font = "sans 10 medium",
|
||||
bg = x.color0,
|
||||
},
|
||||
layout = {
|
||||
layout = wibox.layout.fixed.vertical
|
||||
},
|
||||
widget_template = {
|
||||
{
|
||||
-- Standard icon (from beautiful.icon_theme)
|
||||
-- {
|
||||
-- awful.widget.clienticon,
|
||||
-- margins = 5,
|
||||
-- widget = wibox.container.margin
|
||||
-- },
|
||||
-- Text icon
|
||||
{
|
||||
id = 'text_icon',
|
||||
font = 'icomoon 25',
|
||||
forced_width = dpi(50),
|
||||
align = "center",
|
||||
valign = "center",
|
||||
widget = wibox.widget.textbox,
|
||||
},
|
||||
{
|
||||
{
|
||||
id = 'text_role',
|
||||
align = "center",
|
||||
widget = wibox.widget.textbox,
|
||||
},
|
||||
left = dpi(6),
|
||||
right = dpi(14),
|
||||
-- Add margins to top and bottom in order to force the
|
||||
-- text to be on a single line, if needed. Might need
|
||||
-- to adjust them according to font size.
|
||||
top = dpi(14),
|
||||
bottom = dpi(14),
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
layout = wibox.layout.fixed.horizontal
|
||||
},
|
||||
forced_height = item_size,
|
||||
id = "bg_role",
|
||||
widget = wibox.container.background,
|
||||
create_callback = function(self, c, _, __)
|
||||
local i
|
||||
if class_icons[c.class] then
|
||||
i = c.class
|
||||
else
|
||||
i = '_'
|
||||
end
|
||||
self:get_children_by_id('text_icon')[1].markup = helpers.colorize_text(class_icons[i].symbol, class_icons[i].color)
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
s.window_switcher:setup {
|
||||
{
|
||||
s.window_switcher_tasklist,
|
||||
margins = window_switcher_margin,
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
bg = x.color0,
|
||||
shape = helpers.rrect(beautiful.border_radius),
|
||||
widget = wibox.container.background
|
||||
}
|
||||
end)
|
||||
|
||||
-- Keygrabber configuration
|
||||
local window_switcher_grabber
|
||||
local function window_switcher_hide()
|
||||
-- Add currently focused client to history
|
||||
if client.focus then
|
||||
awful.client.focus.history.add(client.focus)
|
||||
client.focus:raise()
|
||||
end
|
||||
-- Resume recording focus history
|
||||
awful.client.focus.history.enable_tracking()
|
||||
-- Stop and hide window_switcher
|
||||
local s = awful.screen.focused()
|
||||
awful.keygrabber.stop(window_switcher_grabber)
|
||||
s.window_switcher.visible = false
|
||||
end
|
||||
|
||||
-- Helper functions for keybinds
|
||||
local window_search = function()
|
||||
window_switcher_hide()
|
||||
awful.spawn.with_shell("rofi -show windowcd")
|
||||
end
|
||||
|
||||
local function get_num_clients(s)
|
||||
local clients = s.selected_tag:clients()
|
||||
local num_clients = 0
|
||||
for _, c in pairs(clients) do
|
||||
if not c.skip_taskbar then
|
||||
num_clients = num_clients + 1
|
||||
end
|
||||
end
|
||||
|
||||
return num_clients
|
||||
end
|
||||
|
||||
local close = function()
|
||||
if client.focus then
|
||||
client.focus:kill()
|
||||
local s = awful.screen.focused()
|
||||
local num_clients = get_num_clients(s)
|
||||
-- Hide or adjust size and position if needed
|
||||
if num_clients > 1 then
|
||||
s.window_switcher.height = s.window_switcher.height - item_size
|
||||
awful.placement.centered(s.window_switcher, { honor_workarea = true, honor_padding = true })
|
||||
else
|
||||
window_switcher_hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local unminimize = function()
|
||||
local c = awful.client.restore()
|
||||
-- Focus restored client
|
||||
if c then
|
||||
client.focus = c
|
||||
c:raise()
|
||||
end
|
||||
end
|
||||
|
||||
local cycle = function(direction)
|
||||
awful.client.focus.byidx(direction)
|
||||
if client.focus then
|
||||
client.focus:raise()
|
||||
end
|
||||
end
|
||||
|
||||
-- Set up keybinds
|
||||
-- Single keys only
|
||||
local keybinds = {
|
||||
['Escape'] = window_switcher_hide,
|
||||
['Tab'] = function() cycle(1) end,
|
||||
-- (Un)Minimize
|
||||
['n'] = function() if client.focus then client.focus.minimized = true end end,
|
||||
['N'] = unminimize,
|
||||
['u'] = unminimize, -- `u` for up
|
||||
-- Close
|
||||
['d'] = close,
|
||||
['q'] = close,
|
||||
-- Move with vim keys
|
||||
['j'] = function() cycle(1) end,
|
||||
['k'] = function() cycle(-1) end,
|
||||
-- Move with arrow keys
|
||||
['Down'] = function() cycle(1) end,
|
||||
['Up'] = function() cycle(-1) end,
|
||||
-- Space
|
||||
[' '] = window_search
|
||||
}
|
||||
|
||||
function window_switcher_show(s)
|
||||
local num_clients = get_num_clients(s)
|
||||
|
||||
if num_clients == 0 or (num_clients == 1 and client.focus) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Adjust size and position
|
||||
s.window_switcher.height = num_clients * item_size + window_switcher_margin * 2
|
||||
awful.placement.centered(s.window_switcher, { honor_workarea = true, honor_padding = true })
|
||||
|
||||
-- Go to previously focused client (in the tag)
|
||||
awful.client.focus.history.previous()
|
||||
if client.focus then
|
||||
client.focus:raise()
|
||||
end
|
||||
|
||||
-- Stop recording focus history
|
||||
awful.client.focus.history.disable_tracking()
|
||||
|
||||
-- Start the keygrabber
|
||||
window_switcher_grabber = awful.keygrabber.run(function(modifiers, 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()
|
||||
end
|
||||
-- Do nothing
|
||||
return
|
||||
end
|
||||
|
||||
-- Run function attached to key, if it exists
|
||||
if keybinds[key] then
|
||||
keybinds[key]()
|
||||
end
|
||||
end)
|
||||
|
||||
-- Finally make the window switcher wibox visible
|
||||
s.window_switcher.visible = true
|
||||
end
|
||||
|
||||
|
|
@ -131,19 +131,25 @@ keys.globalkeys = gears.table.join(
|
|||
end,
|
||||
{description = "focus right", group = "client"}),
|
||||
|
||||
-- Focus client by index (cycle through clients)
|
||||
-- Window switcher
|
||||
awful.key({ superkey }, "Tab",
|
||||
function ()
|
||||
awful.client.focus.byidx( 1)
|
||||
window_switcher_show(awful.screen.focused())
|
||||
end,
|
||||
{description = "focus next by index", group = "client"}
|
||||
),
|
||||
awful.key({ superkey, shiftkey }, "Tab",
|
||||
{description = "activate window switcher", group = "client"}),
|
||||
|
||||
-- Focus client by index (cycle through clients)
|
||||
awful.key({ superkey }, "z",
|
||||
function ()
|
||||
awful.client.focus.byidx(1)
|
||||
end,
|
||||
{description = "focus next by index", group = "client"}),
|
||||
|
||||
awful.key({ superkey, shiftkey }, "z",
|
||||
function ()
|
||||
awful.client.focus.byidx(-1)
|
||||
end,
|
||||
{description = "focus previous by index", group = "client"}
|
||||
),
|
||||
{description = "focus next by index", group = "client"}),
|
||||
|
||||
-- Gaps
|
||||
awful.key({ superkey, shiftkey }, "minus",
|
||||
|
|
@ -217,14 +223,6 @@ keys.globalkeys = gears.table.join(
|
|||
end,
|
||||
{description = "jump to urgent client", group = "client"}),
|
||||
|
||||
awful.key({ superkey, }, "z",
|
||||
function ()
|
||||
awful.client.focus.history.previous()
|
||||
if client.focus then
|
||||
client.focus:raise()
|
||||
end
|
||||
end,
|
||||
{description = "go back", group = "client"}),
|
||||
awful.key({ superkey, }, "x",
|
||||
function ()
|
||||
awful.tag.history.restore()
|
||||
|
|
@ -727,10 +725,8 @@ keys.clientkeys = gears.table.join(
|
|||
-- Minimize
|
||||
awful.key({ superkey, }, "n",
|
||||
function (c)
|
||||
-- The client currently has the input focus, so it cannot be
|
||||
-- minimized, since minimized clients can't have the focus.
|
||||
c.minimized = true
|
||||
end ,
|
||||
end,
|
||||
{description = "minimize", group = "client"}),
|
||||
|
||||
-- Maximize
|
||||
|
|
|
|||
|
|
@ -202,6 +202,8 @@ require("elemental.dashboard")
|
|||
require("elemental.lock_screen")
|
||||
-- App drawer
|
||||
require("elemental.app_drawer")
|
||||
-- Window switcher
|
||||
require("elemental.window_switcher")
|
||||
|
||||
-- >> Daemons
|
||||
-- Most widgets that display system/external info depend on evil.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue