-- ██╗ ██╗███████╗██╗ ██╗███████╗ -- ██║ ██╔╝██╔════╝╚██╗ ██╔╝██╔════╝ -- █████╔╝ █████╗ ╚████╔╝ ███████╗ -- ██╔═██╗ ██╔══╝ ╚██╔╝ ╚════██║ -- ██║ ██╗███████╗ ██║ ███████║ -- ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝ -- =================================================================== -- Initialization -- =================================================================== local awful = require("awful") local gears = require("gears") local naughty = require("naughty") local beautiful = require("beautiful") local volume_widget = require("widgets.volume-widget.volume") local dpi = beautiful.xresources.apply_dpi local modkey = "Mod4" -- define module table local keys = {} -- AwesomeWM Vim Tmux Navigator local function get_first_nonempty_tag() local screen = awful.screen.focused() local tags = screen.tags local first_empty = nil for _, t in ipairs(tags) do if #t:clients() > 0 then first_empty = nil elseif first_empty == nil then first_empty = t end end return first_empty end local focus_bydirection = function(direction) awful.client.focus.global_bydirection(direction) if client.focus then -- focus on the client client.focus:raise() end -- BUG: focus across screens is wonky when there are no clients on the destination screen -- https://github.com/awesomeWM/awesome/issues/3638 -- Workaround: manually unfocus client after moving focus to an empty screen local is_empty_destination = #awful.screen.focused().clients < 1 if is_empty_destination then -- manually unfocus the current focused client client.focus = nil end end require("awesomewm-vim-tmux-navigator") { up = {"Up", "k"}, down = {"Down", "j"}, left = {"Left", "h"}, right = {"Right", "l"}, mod = "Mod4", mod_keysym = "Super_L", experimental = true, focus = focus_bydirection } -- =================================================================== -- Movement Functions (Called by some keybinds) -- =================================================================== local function get_screen(s) return s and screen[s] end -- Move given client to given direction local function move_client(sel, dir) sel = sel or awful.client.focus if sel then -- move focus awful.client.focus.global_bydirection(dir, sel) local c = client.focus -- swapping inside a screen if get_screen(sel.screen) == get_screen(c.screen) and sel ~= c then c:swap(sel) client.focus = sel sel:raise() -- swapping to an empty screen elseif sel == c then sel:move_to_screen(awful.screen.focused()) -- swapping to a nonempty screen elseif get_screen(sel.screen) ~= get_screen(c.screen) and sel ~= c then sel:move_to_screen(c.screen) client.focus = sel sel:raise() end end end -- Resize client in given direction local floating_resize_amount = dpi(20) local tiling_resize_factor = 0.01 local function resize_client(c, direction) if awful.layout.get(mouse.screen) == awful.layout.suit.floating or (c and c.floating) then if direction == "up" then c:relative_move(0, 0, 0, -floating_resize_amount) elseif direction == "down" then c:relative_move(0, 0, 0, floating_resize_amount) elseif direction == "left" then c:relative_move(0, 0, -floating_resize_amount, 0) elseif direction == "right" then c:relative_move(0, 0, floating_resize_amount, 0) end else if direction == "up" then awful.client.incwfact(-tiling_resize_factor) elseif direction == "down" then awful.client.incwfact(tiling_resize_factor) elseif direction == "left" then awful.tag.incmwfact(-tiling_resize_factor) elseif direction == "right" then awful.tag.incmwfact(tiling_resize_factor) end end end -- =================================================================== -- Mouse bindings -- =================================================================== -- Mouse buttons on the desktop keys.desktopbuttons = gears.table.join( -- left click on desktop to hide notification awful.button({}, 1, function () naughty.destroy_all_notifications() end ), awful.button({}, 7, function() volume_widget:inc(5) end), awful.button({}, 6, function() volume_widget:dec(5) end) ) -- Mouse buttons on the client keys.clientbuttons = gears.table.join( -- Raise client awful.button({}, 1, function(c) client.focus = c c:raise() end ), -- Move and Resize Client awful.button({modkey}, 1, awful.mouse.client.move), awful.button({modkey}, 3, awful.mouse.client.resize), awful.button({}, 7, function() volume_widget:inc(5) end), awful.button({}, 6, function() volume_widget:dec(5) end) ) -- =================================================================== -- Desktop Key bindings -- =================================================================== keys.globalkeys = gears.table.join( -- ========================================= -- SPAWN APPLICATION KEY BINDINGS -- ========================================= -- Spawn terminal awful.key({modkey}, "Return", function() local c = client.focus if c and c.class == "Alacritty" then awful.spawn(string.format(os.getenv("XDG_CONFIG_HOME") .. "/awesome/scripts/launch_alacritty.sh %d", c.pid)) else awful.spawn(apps.terminal) end end, {description = "open a terminal", group = "launcher"} ), -- Spawn browser awful.key({modkey}, "b", function() awful.spawn("firefox") end, {description = "Open Firefox", group = "launcher"} ), -- Lock the screen awful.key({"Control", "Mod1"}, "l", function() awful.spawn('bash -c "i3lockr --blur 25"') end, {description = "Open lock", group = "launcher"} ), -- Generate IMEC TOTP awful.key({modkey}, "i", function() awful.spawn.with_shell("ykman oath accounts code \"Microsoft (IMEC)\" | cut -d ' ' -f 4 | xsel --clipboard") end, {description = "Generate IMEC TOTP", group = "launcher"} ), -- Spawn file manager awful.key({modkey}, "a", function() awful.spawn("nautilus") end, {description = "Open Nautilus", group = "launcher"} ), -- launch rofi awful.key({modkey}, "XF86Launch5", function() awful.spawn(os.getenv("XDG_CONFIG_HOME") .. "/awesome/scripts/toggle_rofi.sh") end, {description = "application launcher", group = "launcher"} ), -- launch rofi awful.key({modkey}, "d", function() awful.spawn(os.getenv("XDG_CONFIG_HOME") .. "/awesome/scripts/toggle_rofi.sh") end, {description = "application launcher", group = "launcher"} ), -- launch clipman awful.key({modkey}, "c", function() awful.spawn.with_shell('CM_LAUNCHER=rofi-script rofi -modi "clipmenu:/usr/bin/clipmenu" -show clipmenu') end, {description = "Clipboard manager", group = "launcher"} ), -- Go to sleep awful.key({"Control", "Mod2", "Mod4"}, "q", function() awful.spawn.with_shell('systemctl suspend') end, {description = "Clipboard manager", group = "launcher"} ), -- Quake awful.key({ }, "F9", function () awful.screen.focused().quake:toggle() end), -- ========================================= -- FUNCTION KEYS -- ========================================= -- Brightness awful.key({}, "XF86MonBrightnessUp", function() awful.spawn("xbacklight -inc 10", false) end, {description = "+10%", group = "hotkeys"} ), awful.key({}, "XF86MonBrightnessDown", function() awful.spawn("xbacklight -dec 10", false) end, {description = "-10%", group = "hotkeys"} ), -- Brightness awful.key({ }, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 15") end), awful.key({ }, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 15") end), -- ALSA volume control awful.key({}, "XF86AudioRaiseVolume", function() volume_widget:inc(5) end, {description = "volume up", group = "hotkeys"} ), awful.key({}, "XF86AudioLowerVolume", function() volume_widget:dec(5) end, {description = "volume down", group = "hotkeys"} ), awful.key({}, "XF86AudioMute", function() volume_widget:toggle() end, {description = "toggle mute", group = "hotkeys"} ), awful.key({}, "XF86AudioNext", function() awful.spawn("playerctl next", false) end, {description = "next music", group = "hotkeys"} ), awful.key({}, "XF86AudioPrev", function() awful.spawn("playerctl previous", false) end, {description = "previous music", group = "hotkeys"} ), awful.key({}, "XF86AudioPlay", function() awful.spawn("playerctl play-pause", false) end, {description = "play/pause music", group = "hotkeys"} ), awful.key({modkey}, "XF86AudioMute", function() awful.spawn("playerctl play-pause", false) end, {description = "play/pause music", group = "hotkeys"} ), awful.key({modkey}, "XF86AudioRaiseVolume", function() awful.spawn("playerctl next", false) end, {description = "volume up", group = "hotkeys"} ), awful.key({modkey}, "XF86AudioLowerVolume", function() awful.spawn("playerctl previous", false) end, {description = "volume down", group = "hotkeys"} ), -- Screenshot on prtscn using scrot awful.key({}, "Print", function() awful.spawn(apps.screenshot, false) end ), -- ========================================= -- RELOAD / QUIT AWESOME -- ========================================= -- Reload Awesome awful.key({modkey, "Shift"}, "r", awesome.restart, {description = "reload awesome", group = "awesome"} ), -- Quit Awesome awful.key({modkey}, "Escape", function() -- emit signal to show the exit screen awful.spawn("rofi -show power-menu -modi power-menu:" .. os.getenv("XDG_CONFIG_HOME") .. "/awesome/scripts/rofi-power-menu") end, {description = "toggle exit screen", group = "hotkeys"} ), awful.key({}, "XF86PowerOff", function() -- emit signal to show the exit screen awful.spawn("rofi -show power-menu -modi power-menu:~/.config/awesome/scripts/rofi-power-menu") end, {description = "toggle exit screen", group = "hotkeys"} ), awful.key({}, "XF86Calculator", function() awful.spawn("rofi -show calc -modi calc -no-show-match -no-sort -calc-command \"echo -n '{result}' | xsel --clipboard\"") end, {description = "Launch the calculator", group = "hotkeys"} ), -- Focus client by index (cycle through clients) awful.key({modkey}, "Tab", function() local screen = awful.screen.focused() local tags = screen.tags local current_tag = screen.selected_tag local used_tags = {} for _, t in ipairs(tags) do if t == current_tag or #t:clients() > 0 then table.insert(used_tags, t) end end local found = false for _, t in ipairs(used_tags) do if found then t:view_only() return elseif t == current_tag then found = true end end used_tags[1]:view_only() end, {description = "Switch to next tag", group = "client"} ), awful.key({modkey, "Shift"}, "Tab", function() local tags = root.tags() local current_tag = awful.screen.focused().selected_tag local used_tags = {} for _, t in ipairs(tags) do if t == current_tag or #t:clients() > 0 then table.insert(used_tags, t) end end local found = false for _, t in ipairs(used_tags) do if found then awful.screen.focus(t.screen.index) t:view_only() return elseif t == current_tag then found = true end end used_tags[1]:view_only() end, {description = "Switch to next tag", group = "client"} ), awful.key({modkey}, "t", function() local first_empty = get_first_nonempty_tag() if first_empty ~= nil then first_empty:view_only() end end, {description = "Switch to next tag", group = "client"} ), awful.key({modkey, "Shift"}, "t", function() local first_empty = get_first_nonempty_tag() if first_empty ~= nil then client.focus:move_to_tag(first_empty) first_empty:view_only() end end, {description = "Switch to next tag", group = "client"} ), -- ========================================= -- SCREEN FOCUSING -- ========================================= -- Focus screen by index (cycle through screens) awful.key({modkey}, "s", function() awful.screen.focus_relative(-1) end ), -- ========================================= -- CLIENT RESIZING -- ========================================= awful.key({modkey, "Control"}, "Down", function(_) resize_client(client.focus, "down") end ), awful.key({modkey, "Control"}, "Up", function(_) resize_client(client.focus, "up") end ), awful.key({modkey, "Control"}, "Left", function(_) resize_client(client.focus, "left") end ), awful.key({modkey, "Control"}, "Right", function(_) resize_client(client.focus, "right") end ), awful.key({modkey, "Control"}, "j", function(_) resize_client(client.focus, "down") end ), awful.key({ modkey, "Control" }, "k", function(_) resize_client(client.focus, "up") end ), awful.key({modkey, "Control"}, "h", function(_) resize_client(client.focus, "left") end ), awful.key({modkey, "Control"}, "l", function(_) resize_client(client.focus, "right") end ), -- ========================================= -- GAP CONTROL -- ========================================= -- Gap control -- awful.key({modkey, :Shift"}, "minus", -- function() -- awful.tag.incgap(5, nil) -- end, -- {description = "increment gaps size for the current tag", group = "gaps"} -- ), -- awful.key({modkey}, "minus", -- function() -- awful.tag.incgap(-5, nil) -- end, -- {description = "decrement gap size for the current tag", group = "gaps"} -- ), awful.key({ modkey }, "=", function () awful.tag.incncol( 1, nil, true) end, {description = "increase the number of columns", group = "layout"} ), awful.key({ modkey }, "minus", function () awful.tag.incncol(-1, nil, true) end, {description = "decrease the number of columns", group = "layout"} ), -- ========================================= -- LAYOUT SELECTION -- ========================================= -- select next layout awful.key({modkey}, "space", function() awful.layout.inc(1) end, {description = "select next", group = "layout"} ), -- select previous layout awful.key({modkey, "Shift"}, "space", function() awful.layout.inc(-1) end, {description = "select previous", group = "layout"} ), -- ========================================= -- CLIENT MINIMIZATION -- ========================================= -- restore minimized client awful.key({modkey, "Shift"}, "n", function() local c = awful.client.restore() -- Focus restored client if c then client.focus = c c:raise() end end, {description = "restore minimized", group = "client"} ) ) -- =================================================================== -- Client Key bindings -- =================================================================== keys.clientkeys = gears.table.join( -- Move to edge or swap by direction awful.key({modkey, "Shift"}, "Down", function(c) move_client(c, "down") end ), awful.key({modkey, "Shift"}, "Up", function(c) move_client(c, "up") end ), awful.key({modkey, "Shift"}, "Left", function(c) move_client(c, "left") end ), awful.key({modkey, "Shift"}, "Right", function(c) move_client(c, "right") end ), awful.key({modkey, "Shift"}, "j", function(c) move_client(c, "down") end ), awful.key({modkey, "Shift"}, "k", function(c) move_client(c, "up") end ), awful.key({modkey, "Shift"}, "h", function(c) move_client(c, "left") end ), awful.key({modkey, "Shift"}, "l", function(c) move_client(c, "right") end ), -- close client awful.key({modkey}, "q", function(c) c:kill() for _, i in ipairs(client.get()) do i.minimized = false end end, {description = "close", group = "client"} ), -- float client awful.key({modkey}, "f", function(c) awful.client.floating.toggle(c) end, {description = "float", group = "client"} ), -- Minimize awful.key({modkey}, "n", function(c) c.minimized = true end, {description = "minimize", group = "client"} ), -- Maximize awful.key({modkey}, "m", function(c) c.maximized = not c.maximized c:raise() end, {description = "(un)maximize", group = "client"} ) ) local function register_tag(tag) keys.globalkeys = gears.table.join(keys.globalkeys, -- Switch to tag awful.key({modkey}, "#" .. tag + 9, function() local screen = awful.screen.focused() local t = screen.tags[tag] if t then t:view_only() end end, {description = "view tag #"..tag, group = "tag"} ), -- Move client to tag awful.key({modkey, "Shift"}, "#" .. tag + 9, function() if client.focus then local t= client.focus.screen.tags[tag] if t then client.focus:move_to_tag(t) t:view_only() end end end, {description = "move focused client to tag #"..tag, group = "tag"} ) ) end -- Bind all key numbers to tags for i = 1, 10 do register_tag(i) end return keys