From 146ec7f728861f5d7d4e0a05d7852849f00bd3c1 Mon Sep 17 00:00:00 2001 From: MobSenpai Date: Mon, 3 Jul 2023 22:38:45 +0530 Subject: [PATCH] feat: window switcher --- .../modules/desktop/wm/awesome/default.nix | 5 +- .../desktop/wm/awesome/default/theme.lua | 30 +- .../modules/desktop/wm/awesome/keys.lua | 4 +- .../wm/awesome/module/window_switcher.lua | 285 ++++++++++++++++++ .../yashraj/modules/desktop/wm/awesome/rc.lua | 11 +- 5 files changed, 313 insertions(+), 22 deletions(-) create mode 100644 home/yashraj/modules/desktop/wm/awesome/module/window_switcher.lua diff --git a/home/yashraj/modules/desktop/wm/awesome/default.nix b/home/yashraj/modules/desktop/wm/awesome/default.nix index 956c37e..2423d14 100644 --- a/home/yashraj/modules/desktop/wm/awesome/default.nix +++ b/home/yashraj/modules/desktop/wm/awesome/default.nix @@ -60,14 +60,15 @@ in { file = { # Setup - ".config/awesome/configuration/".source = ./. + "/${theme}"; + ".config/awesome/configuration".source = ./. + "/${theme}"; ".config/awesome/rc.lua".source = ./rc.lua; ".config/awesome/helpers.lua".source = ./helpers.lua; ".config/awesome/keys.lua".source = ./keys.lua; # Modules ".config/awesome/module/json.lua".source = ./module/json.lua; - ".config/awesome/module/lockscreen/".source = ./module/lockscreen; + ".config/awesome/module/lockscreen".source = ./module/lockscreen; + ".config/awesome/module/window_switcher.lua".source = ./module/window_switcher.lua; }; }; diff --git a/home/yashraj/modules/desktop/wm/awesome/default/theme.lua b/home/yashraj/modules/desktop/wm/awesome/default/theme.lua index 2d94508..4b84a89 100644 --- a/home/yashraj/modules/desktop/wm/awesome/default/theme.lua +++ b/home/yashraj/modules/desktop/wm/awesome/default/theme.lua @@ -61,15 +61,15 @@ theme.orange = "#d65d0e" -- Background Colors theme.bg_normal = theme.background -theme.bg_focus = theme.color0 -theme.bg_urgent = theme.color8 -theme.bg_minimize = theme.color8 +theme.bg_focus = theme.color4 .. 70 +theme.bg_urgent = theme.color3 +theme.bg_minimize = theme.background .. 55 -- Foreground Colors theme.fg_normal = theme.foreground -theme.fg_focus = theme.color5 -theme.fg_urgent = theme.color3 -theme.fg_minimize = theme.color8 +theme.fg_focus = theme.color7 +theme.fg_urgent = theme.color1 +theme.fg_minimize = theme.foreground .. 55 --- ░█░█░▀█▀░░░█▀▀░█░░░█▀▀░█▄█░█▀▀░█▀█░▀█▀░█▀▀ --- ░█░█░░█░░░░█▀▀░█░░░█▀▀░█░█░█▀▀░█░█░░█░░▀▀█ @@ -111,11 +111,11 @@ theme.tasklist_bg_focus = theme.color0 theme.tasklist_fg_focus = theme.color2 theme.tasklist_bg_normal = theme.color0 theme.tasklist_fg_normal = theme.foreground -theme.tasklist_bg_minimize = theme.color0 .. 55 -theme.tasklist_fg_minimize = theme.foreground .. 55 +theme.tasklist_bg_minimize = theme.bg_minimize +theme.tasklist_fg_minimize = theme.fg_minimize theme.tasklist_disable_task_name = false -theme.tasklist_bg_urgent = theme.color0 -theme.tasklist_fg_urgent = theme.color1 +theme.tasklist_bg_urgent = theme.bg_urgent +theme.tasklist_fg_urgent = theme.fg_urgent theme.tasklist_align = "center" --- Titlebar @@ -127,10 +127,10 @@ theme.titlebar_enabled = false -- =================================================================== theme.menu_height = dpi(30) theme.menu_width = dpi(150) -theme.menu_bg_normal = theme.background -theme.menu_fg_normal = theme.color7 -theme.menu_bg_focus = theme.color4 .. 70 -theme.menu_fg_focus = theme.color7 +theme.menu_bg_normal = theme.bg_normal +theme.menu_fg_normal = theme.fg_normal +theme.menu_bg_focus = theme.bg_focus +theme.menu_fg_focus = theme.fg_focus -- theme.menu_font = theme.font theme.menu_border_width = theme.border_width / 2 theme.menu_border_color = theme.color8 @@ -148,7 +148,7 @@ theme.wibar_position = "top" theme.wibar_height = dpi(25) theme.wibar_bg = theme.color0 -- theme.wibar_fg = ---theme.wibar_opacity = 0.7 +--theme.wibar_opacity = -- theme.wibar_border_color = theme.wibar_border_width = dpi(0) theme.wibar_border_radius = dpi(0) diff --git a/home/yashraj/modules/desktop/wm/awesome/keys.lua b/home/yashraj/modules/desktop/wm/awesome/keys.lua index a2ff56e..2d9ecc5 100644 --- a/home/yashraj/modules/desktop/wm/awesome/keys.lua +++ b/home/yashraj/modules/desktop/wm/awesome/keys.lua @@ -8,6 +8,7 @@ local awful = require("awful") local hotkeys_popup = require("awful.hotkeys_popup") local naughty = require("naughty") local helpers = require("helpers") + local keys = {} mod = "Mod4" alt = "Mod1" @@ -364,7 +365,8 @@ keys.clientkeys = gears.table.join( -- Switch clients awful.key({ alt }, "Tab", function() - awful.client.focus.byidx(1) + awesome.emit_signal("window_switcher::turn_on") + -- awful.client.focus.byidx(1) end, { description = "focus next by index", group = "client" }), -- Toggle floating diff --git a/home/yashraj/modules/desktop/wm/awesome/module/window_switcher.lua b/home/yashraj/modules/desktop/wm/awesome/module/window_switcher.lua new file mode 100644 index 0000000..b1ddf1c --- /dev/null +++ b/home/yashraj/modules/desktop/wm/awesome/module/window_switcher.lua @@ -0,0 +1,285 @@ +local awful = require("awful") +local gears = require("gears") +local wibox = require("wibox") +local beautiful = require("beautiful") +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 + window_switcher_box.widget = nil + collectgarbage("collect") +end + +local function draw_widget(mouse_keys) + local tasklist_widget = awful.widget.tasklist({ + screen = awful.screen.focused(), + filter = awful.widget.tasklist.filter.currenttags, + buttons = mouse_keys, + style = { + font = beautiful.font, + bg_normal = beautiful.bg_normal, + bg_focus = beautiful.bg_focus, + fg_normal = beautiful.fg_normal, + fg_focus = beautiful.fg_focus, + shape = gears.shape.rounded_rect, + }, + layout = { + layout = wibox.layout.fixed.horizontal, + }, + widget_template = { + { + { + { + awful.widget.clienticon, + forced_height = dpi(80), + forced_width = dpi(80), + halign = "center", + valign = "center", + widget = wibox.container.place, + }, + { + { + widget = wibox.container.scroll.horizontal, + step_function = wibox.container.scroll.step_functions.waiting_nonlinear_back_and_forth, + fps = 60, + speed = 75, + { + id = "text_role", + widget = wibox.widget.textbox, + }, + }, + halign = "center", + valign = "center", + widget = wibox.container.place, + }, + spacing = dpi(15), + layout = wibox.layout.fixed.vertical, + }, + margins = dpi(15), + widget = wibox.container.margin, + }, + forced_width = dpi(150), + forced_height = dpi(150), + id = "background_role", + widget = wibox.container.background, + }, + }) + + return wibox.widget({ + { + tasklist_widget, + margins = dpi(15), + widget = wibox.container.margin, + }, + bg = beautiful.background, + shape = gears.shape.rounded_rect, + widget = wibox.container.background, + }) +end + +local enable = function() + local hide_window_switcher_key = "Escape" + + local select_client_key = 1 + local minimize_key = "n" + local unminimize_key = "N" + local kill_client_key = "q" + + local cycle_key = "Tab" + + local previous_key = "Left" + local next_key = "Right" + + local vim_previous_key = "h" + local vim_next_key = "l" + + local scroll_previous_key = 4 + local scroll_next_key = 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(), + }) + + 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("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(mouse_keys) + window_switcher_box.visible = true + end) +end + +return { enable = enable } diff --git a/home/yashraj/modules/desktop/wm/awesome/rc.lua b/home/yashraj/modules/desktop/wm/awesome/rc.lua index 13e4481..4f8c835 100644 --- a/home/yashraj/modules/desktop/wm/awesome/rc.lua +++ b/home/yashraj/modules/desktop/wm/awesome/rc.lua @@ -92,6 +92,9 @@ local keys = require("keys") local lock_screen = require("module.lockscreen") lock_screen.init() +-- Window switcher +require("module.window_switcher").enable() + -- Get screen geometry -- I am using a single screen setup and I assume that screen geometry will not -- change during the session. @@ -673,10 +676,10 @@ awful.tag.attached_connect_signal(s, "property::selected", function() end) -- Enable sloppy focus, so that focus follows mouse. --- client.connect_signal("mouse::enter", function(c) --- c:activate { context = "mouse_enter", raise = false } --- end --- ) +client.connect_signal("mouse::enter", function(c) + c:activate { context = "mouse_enter", raise = false } +end +) -- Raise focused clients automatically client.connect_signal("focus", function(c)