From e1c3745f3bda5c3fda6a54d6235064a8061549b0 Mon Sep 17 00:00:00 2001 From: Jason Hilder Date: Thu, 2 Jul 2026 07:44:28 +0200 Subject: [PATCH] Awesomewm config into modules. --- config/awesome/config/bar.lua | 82 +++++ config/awesome/config/colors.lua | 12 + config/awesome/config/keys.lua | 88 +++++ config/awesome/config/rules.lua | 20 ++ config/awesome/config/signals.lua | 26 ++ config/awesome/config/theme.lua | 46 +++ config/awesome/config/widgets.lua | 84 +++++ config/awesome/rc.lua | 515 +++--------------------------- config/fish/config.fish | 2 +- config/rofi/config.rasi | 2 +- 10 files changed, 396 insertions(+), 481 deletions(-) create mode 100644 config/awesome/config/bar.lua create mode 100644 config/awesome/config/colors.lua create mode 100644 config/awesome/config/keys.lua create mode 100644 config/awesome/config/rules.lua create mode 100644 config/awesome/config/signals.lua create mode 100644 config/awesome/config/theme.lua create mode 100644 config/awesome/config/widgets.lua diff --git a/config/awesome/config/bar.lua b/config/awesome/config/bar.lua new file mode 100644 index 0000000..bf5d4d2 --- /dev/null +++ b/config/awesome/config/bar.lua @@ -0,0 +1,82 @@ +local awful = require("awful") +local gears = require("gears") +local wibox = require("wibox") +local beautiful = require("beautiful") +local colors = require("config.colors") +local widgets = require("config.widgets") + +local M = {} + +local taglist_buttons = gears.table.join( + awful.button({ }, 1, function(t) t:view_only() end), + awful.button({ modkey }, 1, function(t) if client.focus then client.focus:move_to_tag(t) end end), + awful.button({ }, 3, awful.tag.viewtoggle) +) + +local function set_wallpaper(s) + if beautiful.wallpaper then + local wp = beautiful.wallpaper + if type(wp) == "function" then wp = wp(s) end + gears.wallpaper.maximized(wp, s, true) + end +end +screen.connect_signal("property::geometry", set_wallpaper) + +function M.setup() + awful.screen.connect_for_each_screen(function(s) + set_wallpaper(s) + awful.tag({ "1", "2", "3", "4", "5" }, s, awful.layout.layouts[1]) + + s.mypromptbox = awful.widget.prompt() + s.mylayoutbox = awful.widget.layoutbox(s) + s.mylayoutbox:buttons(gears.table.join( + awful.button({ }, 1, function() awful.layout.inc(1) end), + awful.button({ }, 3, function() awful.layout.inc(-1) end) + )) + + s.mytaglist = awful.widget.taglist { + screen = s, filter = awful.widget.taglist.filter.all, buttons = taglist_buttons, + style = { shape = function(cr, w, h) gears.shape.rounded_rect(cr, w, h, 4) end }, + layout = { spacing = 4, layout = wibox.layout.fixed.horizontal }, + widget_template = { + { { id = "text_role", widget = wibox.widget.textbox }, left = 10, right = 10, top = 4, bottom = 4, widget = wibox.container.margin }, + id = "background_role", widget = wibox.container.background, + }, + } + + -- Per-screen monitor widgets (created here so multi-monitor stays valid) + local title = widgets.make_title() + local vol = widgets.make_vol() + local cpu = widgets.make_cpu() + local clock = wibox.widget.textclock("%Y-%m-%d %H:%M") + + local right = wibox.layout.fixed.horizontal() + local function push(w) right:add(widgets.padded(w, 4, 4)) end + push(wibox.widget.systray()); right:add(widgets.sep()) + push(vol); right:add(widgets.sep()) + push(cpu); right:add(widgets.sep()) + push(clock); right:add(widgets.sep()) + push(s.mylayoutbox) + + s.mywibox = awful.wibar { + position = "top", screen = s, height = 45, bg = colors.background, fg = colors.foreground, + shape = function(cr, w, h) gears.shape.rounded_rect(cr, w, h, 0) end, + } + + s.mywibox:setup { + layout = wibox.container.margin, left = 8, right = 8, top = 10, bottom = 10, + { + layout = wibox.layout.align.horizontal, + { -- Left: workspaces + focused window title + layout = wibox.layout.fixed.horizontal, + widgets.padded(s.mytaglist, 8, 4), s.mypromptbox, + { title, left = 18, widget = wibox.container.margin }, + }, + nil, -- empty center + widgets.padded(right, 4, 12), + } + } + end) +end + +return M diff --git a/config/awesome/config/colors.lua b/config/awesome/config/colors.lua new file mode 100644 index 0000000..c197acd --- /dev/null +++ b/config/awesome/config/colors.lua @@ -0,0 +1,12 @@ +return { + background = "#111111", + background_alt = "#1a1a1a", + foreground = "#d3dae3", + accent = "#6e6e6e", + accent_alt = "#6ba0e8", + red = "#e35b5b", + green = "#98c379", + yellow = "#e5c07b", + disabled = "#707880", + white = "#ffffff", +} diff --git a/config/awesome/config/keys.lua b/config/awesome/config/keys.lua new file mode 100644 index 0000000..bc79227 --- /dev/null +++ b/config/awesome/config/keys.lua @@ -0,0 +1,88 @@ +local awful = require("awful") +local gears = require("gears") +local hotkeys_popup = require("awful.hotkeys_popup") +local menubar = require("menubar") + +local M = {} + +-- Prefer rofi, fall back to built-in menubar +local function launcher() + awful.spawn.easy_async_with_shell("command -v rofi", function(out) + if out and out:match("%S") then awful.spawn("rofi -show drun") else menubar.show() end + end) +end + +M.globalkeys = gears.table.join( + awful.key({ modkey }, "s", hotkeys_popup.show_help, { description = "show help", group = "awesome" }), + + -- Directional focus (vim keys) + awful.key({ modkey }, "h", function() awful.client.focus.bydirection("left") end, { description = "focus left", group = "client" }), + awful.key({ modkey }, "j", function() awful.client.focus.bydirection("down") end, { description = "focus down", group = "client" }), + awful.key({ modkey }, "k", function() awful.client.focus.bydirection("up") end, { description = "focus up", group = "client" }), + awful.key({ modkey }, "l", function() awful.client.focus.bydirection("right") end, { description = "focus right", group = "client" }), + + -- Directional move (swap clients in the tiling layout) + awful.key({ modkey, "Shift" }, "h", function() awful.client.swap.bydirection("left") end, { description = "move left", group = "client" }), + awful.key({ modkey, "Shift" }, "j", function() awful.client.swap.bydirection("down") end, { description = "move down", group = "client" }), + awful.key({ modkey, "Shift" }, "k", function() awful.client.swap.bydirection("up") end, { description = "move up", group = "client" }), + awful.key({ modkey, "Shift" }, "l", function() awful.client.swap.bydirection("right") end, { description = "move right", group = "client" }), + + -- Resize the master/other split + awful.key({ modkey, "Control" }, "h", function() awful.tag.incmwfact(-0.05) end, { description = "shrink master", group = "layout" }), + awful.key({ modkey, "Control" }, "l", function() awful.tag.incmwfact( 0.05) end, { description = "grow master", group = "layout" }), + + -- Launching / layout + awful.key({ modkey }, "Return", function() awful.spawn(terminal) end, { description = "open a terminal", group = "launcher" }), + awful.key({ modkey }, "space", launcher, { description = "application launcher", group = "launcher" }), + awful.key({ modkey }, "e", function() awful.spawn("thunar") end, { description = "Filemanager", group = "system" }), + awful.key({ modkey }, "b", function() awful.spawn("chromium") end, { description = "Browser", group = "internet" }), + awful.key({ modkey }, "t", function() awful.layout.inc(1) end, { description = "next layout", group = "layout" }), + awful.key({ modkey }, "p", function() awful.spawn("xfce4-screenshooter") end, { description = "screenshot", group = "system" }), + + -- Alt tab only in max mode + awful.key({ "Mod1" }, "Tab", function() awful.client.focus.byidx(1) end), + + -- Media keys + awful.key({ }, "XF86AudioRaiseVolume", function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" +2%']]) end, { description = "volume up", group = "media" }), + awful.key({ }, "XF86AudioLowerVolume", function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" -2%']]) end, { description = "volume down", group = "media" }), + awful.key({ }, "XF86AudioMute", function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-mute "$(pactl get-default-sink)" toggle']]) end, { description = "toggle mute", group = "media" }), + + -- rofi menus + awful.key({ modkey }, "a", function() awful.spawn("/home/jason/.local/bin/audioswitch") end, { description = "audio output", group = "system" }), + awful.key({ modkey }, "`", function() awful.spawn("/home/jason/.local/bin/powermenu") end, { description = "power menu", group = "system" }), + + -- Awesome control + awful.key({ modkey, "Shift" }, "r", awesome.restart, { description = "reload awesome", group = "awesome" }) +) + +-- Workspace keys 1..5: Alt+N view, Alt+Shift+N move client to tag +for i = 1, 5 do + M.globalkeys = gears.table.join(M.globalkeys, + awful.key({ modkey }, "#" .. i + 9, function() + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then tag:view_only() end + end, { description = "view tag #" .. i, group = "tag" }), + awful.key({ modkey, "Shift" }, "#" .. i + 9, function() + if client.focus then + local tag = client.focus.screen.tags[i] + if tag then client.focus:move_to_tag(tag) end + end + end, { description = "move focused client to tag #" .. i, group = "tag" }) + ) +end + +M.clientkeys = gears.table.join( + awful.key({ modkey }, "q", function(c) c:kill() end, { description = "kill window", group = "client" }), + awful.key({ modkey }, "f", function(c) c.fullscreen = not c.fullscreen; c:raise() end, { description = "toggle fullscreen", group = "client" }), + awful.key({ modkey }, "m", function(c) c:swap(awful.client.getmaster()) end, { description = "make master", group = "client" }), + awful.key({ modkey, "Shift" }, "space", awful.client.floating.toggle, { description = "toggle floating", group = "client" }) +) + +M.clientbuttons = gears.table.join( + awful.button({ }, 1, function(c) c:emit_signal("request::activate", "mouse_click", { raise = true }) end), + awful.button({ modkey }, 1, function(c) c:emit_signal("request::activate", "mouse_click", { raise = true }); awful.mouse.client.move(c) end), + awful.button({ modkey }, 3, function(c) c:emit_signal("request::activate", "mouse_click", { raise = true }); awful.mouse.client.resize(c) end) +) + +return M diff --git a/config/awesome/config/rules.lua b/config/awesome/config/rules.lua new file mode 100644 index 0000000..f4bd644 --- /dev/null +++ b/config/awesome/config/rules.lua @@ -0,0 +1,20 @@ +local awful = require("awful") +local beautiful = require("beautiful") +local keys = require("config.keys") + +return { + { rule = { }, properties = { + border_width = beautiful.border_width, border_color = beautiful.border_normal, + focus = awful.client.focus.filter, raise = true, + keys = keys.clientkeys, buttons = keys.clientbuttons, + screen = awful.screen.preferred, + placement = awful.placement.no_overlap + awful.placement.no_offscreen, + }}, + + { rule_any = { + instance = { "pinentry" }, + class = { "Arandr", "Blueman-manager", "Gpick", "Pavucontrol" }, + name = { "Event Tester" }, + role = { "AlarmWindow", "pop-up" }, + }, properties = { floating = true }}, +} diff --git a/config/awesome/config/signals.lua b/config/awesome/config/signals.lua new file mode 100644 index 0000000..3563e0a --- /dev/null +++ b/config/awesome/config/signals.lua @@ -0,0 +1,26 @@ +local gears = require("gears") +local awful = require("awful") +local beautiful = require("beautiful") + +client.connect_signal("manage", function(c) + if awesome.startup and not c.size_hints.user_position and not c.size_hints.program_position then + awful.placement.no_offscreen(c) + end + -- New windows open into the stack (to the right); first window becomes master. + if not awesome.startup then awful.client.setslave(c) end + c.shape = function(cr, width, height) gears.shape.rounded_rect(cr, width, height, 13) end -- 13 = corner radius +end) + +client.connect_signal("property::floating", function(c) + if c.floating and c.type ~= "notification" then awful.placement.centered(c, { honor_workarea = true }) end +end) + +client.connect_signal("manage", function(c) + if c.floating and c.type ~= "notification" then awful.placement.centered(c, { honor_workarea = true }) end +end) + +-- Focus follows mouse (i3-like). Comment out for click-to-focus only. +client.connect_signal("mouse::enter", function(c) c:emit_signal("request::activate", "mouse_enter", { raise = false }) end) + +client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end) +client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end) diff --git a/config/awesome/config/theme.lua b/config/awesome/config/theme.lua new file mode 100644 index 0000000..096c705 --- /dev/null +++ b/config/awesome/config/theme.lua @@ -0,0 +1,46 @@ +local gears = require("gears") +local beautiful = require("beautiful") +local naughty = require("naughty") +local colors = require("config.colors") + +beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua") + +beautiful.useless_gap = 8 +beautiful.gap_single_client = true +beautiful.font = "JetBrainsMono Nerd Font 11" +beautiful.border_width = 4 +beautiful.border_normal = colors.background_alt +beautiful.border_focus = colors.accent + +beautiful.taglist_bg_focus = colors.accent +beautiful.taglist_fg_focus = colors.background +beautiful.taglist_fg_occupied = colors.white +beautiful.taglist_bg_occupied = colors.background +beautiful.taglist_fg_empty = colors.disabled +beautiful.taglist_bg_empty = colors.background +beautiful.taglist_bg_urgent = colors.red +beautiful.taglist_fg_urgent = colors.background + +beautiful.bg_systray = colors.background +beautiful.systray_icon_spacing = 4 + +-- Notifications, styled to match the wibar/client theme +naughty.config.defaults.position = "top_right" +naughty.config.defaults.timeout = 5 +naughty.config.padding = 12 +naughty.config.defaults.margin = 12 +naughty.config.defaults.spacing = 8 +naughty.config.defaults.icon_size = 48 +naughty.config.defaults.border_width = 3 +naughty.config.defaults.font = "JetBrainsMono Nerd Font 11" +naughty.config.defaults.shape = function(cr, w, h) gears.shape.rounded_rect(cr, w, h, 13) end + +naughty.config.presets.normal = { + bg = colors.background, fg = colors.foreground, border_color = colors.background_alt, + border_width = 3, font = "JetBrainsMono Nerd Font 11", timeout = 5, +} +naughty.config.presets.low = naughty.config.presets.normal +naughty.config.presets.critical = { + bg = colors.background, fg = colors.red, border_color = colors.red, + border_width = 3, font = "JetBrainsMono Nerd Font 11", timeout = 0, -- stays until dismissed +} diff --git a/config/awesome/config/widgets.lua b/config/awesome/config/widgets.lua new file mode 100644 index 0000000..7f4231f --- /dev/null +++ b/config/awesome/config/widgets.lua @@ -0,0 +1,84 @@ +local awful = require("awful") +local gears = require("gears") +local wibox = require("wibox") +local colors = require("config.colors") + +local M = {} + +-- "ICON value" with ICON tinted accent, like polybar's *-prefix-foreground. +function M.label(icon, val) + return string.format("%s %s", colors.accent, icon, val or "") +end + +-- A slim separator in the disabled color, like polybar's separator. +function M.sep() + local w = wibox.widget.textbox() + w.markup = string.format(" ", colors.disabled) + return w +end + +-- Wrap a widget in a small margin so bar modules aren't crammed together. +function M.padded(w, left, right) + return wibox.container.margin(w, left or 8, right or 8) +end + +-- Focused window title (polybar xwindow / %title%) +function M.make_title() + local t = wibox.widget.textbox() + local function update() + local c = client.focus + t.markup = c and string.format("%s", colors.white, gears.string.xml_escape(c.name or "")) or "" + end + client.connect_signal("focus", update) + client.connect_signal("unfocus", update) + client.connect_signal("property::name", update) + return t +end + +-- CPU usage % (two top samples so the reading is accurate) +function M.make_cpu() + return awful.widget.watch( + { "bash", "-c", [[LANG=C top -bn2 -d0.3 | grep -m2 '^%Cpu' | tail -1 | awk '{printf "%.0f", 100 - $8}']] }, + 3, function(w, out) w.markup = M.label("CPU", out:gsub("%s+$", "") .. "%") end) +end + +-- Volume: click to mute, scroll to adjust, right-click for the mixer. +-- Keeps its own refresh() so button presses update instantly instead of +-- waiting on the polling timer. +function M.make_vol() + local w = wibox.widget.textbox() + + local vol_script = [[ + sink=$(LANG=C pactl get-default-sink 2>/dev/null) + m=$(LANG=C pactl get-sink-mute "$sink" 2>/dev/null | grep -oE 'yes|no') + v=$(LANG=C pactl get-sink-volume "$sink" 2>/dev/null | grep -oE '[0-9]+%' | head -n1) + echo "$m $v" + ]] + local function shell_quote(s) return "'" .. s:gsub("'", "'\\''") .. "'" end + local vol_cmd = "sh -c " .. shell_quote(vol_script) + + local function refresh() + awful.spawn.easy_async_with_shell(vol_cmd, function(out) + local muted, pct = out:match("(%a+)%s+(%d+)%%") + if muted == nil and pct == nil then + w.markup = string.format("VOL n/a", colors.disabled) + return + end + muted = muted == "yes" + pct = pct or "0" + w.markup = muted and string.format("MUTE", colors.disabled) or M.label("VOL", pct .. "%") + end) + end + + w:buttons(gears.table.join( + awful.button({ }, 1, function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-mute "$(pactl get-default-sink)" toggle']], function() refresh() end) end), + awful.button({ }, 3, function() awful.spawn("/home/jason/.local/bin/audioswitch") end), + awful.button({ }, 4, function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" +2%']], function() refresh() end) end), + awful.button({ }, 5, function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" -2%']], function() refresh() end) end) + )) + + gears.timer { timeout = 2, call_now = true, autostart = true, callback = refresh } + return w +end + +return M diff --git a/config/awesome/rc.lua b/config/awesome/rc.lua index c4d9f12..f6f3b89 100644 --- a/config/awesome/rc.lua +++ b/config/awesome/rc.lua @@ -1,495 +1,52 @@ pcall(require, "luarocks.loader") -local gears = require("gears") -local awful = require("awful") +local gears = require("gears") +local awful = require("awful") require("awful.autofocus") -local wibox = require("wibox") -local beautiful = require("beautiful") -local bling = require("bling") -local naughty = require("naughty") -local menubar = require("menubar") -local hotkeys_popup = require("awful.hotkeys_popup") - --- Kill xfce4-notifyd on awesome startup (with a short delay + retry, --- in case xfce4-notifyd hasn't started yet at this point in the session) -awful.spawn.easy_async_with_shell("pkill xfce4-notifyd", function() end) -gears.timer.start_new(3, function() - awful.spawn.easy_async_with_shell("pkill xfce4-notifyd", function() end) - return false -- don't repeat -end) - --- {{{ Error handling -if awesome.startup_errors then - naughty.notify({ preset = naughty.config.presets.critical, - title = "Error during startup", - text = awesome.startup_errors }) -end -do - local in_error = false - awesome.connect_signal("debug::error", function (err) - if in_error then return end - in_error = true - naughty.notify({ preset = naughty.config.presets.critical, - title = "An error happened", - text = tostring(err) }) - in_error = false - end) -end --- }}} - --- {{{ Variable definitions -beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua") - --- Gaps -beautiful.useless_gap = 8 -beautiful.gap_single_client = true - --- ---- Qogir / polybar-matched palette ------------------------------------ -local colors = { - background = "#111111", - background_alt = "#1a1a1a", - foreground = "#d3dae3", - accent = "#6e6e6e", - accent_alt = "#6ba0e8", - red = "#e35b5b", - green = "#98c379", - yellow = "#e5c07b", - disabled = "#707880", - white = "#ffffff", -} - --- {{{ Naughty (notifications) — styled to match wibar/client theme -naughty.config.defaults.position = "top_right" -naughty.config.defaults.timeout = 5 -naughty.config.padding = 12 -naughty.config.defaults.margin = 12 -naughty.config.defaults.spacing = 8 -naughty.config.defaults.icon_size = 48 -naughty.config.defaults.border_width = 3 -naughty.config.defaults.font = "JetBrainsMono Nerd Font 12" -naughty.config.defaults.shape = function(cr, w, h) gears.shape.rounded_rect(cr, w, h, 13) end - --- Base look, matches wibar/border palette -naughty.config.presets.normal = { - bg = colors.background, - fg = colors.foreground, - border_color = colors.background_alt, - border_width = 3, - font = "JetBrainsMono Nerd Font 12", - timeout = 5, -} -naughty.config.presets.low = naughty.config.presets.normal - -naughty.config.presets.critical = { - bg = colors.background, - fg = colors.red, - border_color = colors.red, - border_width = 3, - font = "JetBrainsMono Nerd Font 12", - timeout = 0, -- stays until dismissed -} --- }}} - --- Bar font (matches your polybar JetBrainsMono Nerd Font; bump the number to 14 --- if you want it as large as polybar's size=14). -beautiful.font = "JetBrainsMono Nerd Font 12" - --- Window borders -beautiful.border_width = 4 -beautiful.border_normal = colors.background_alt -beautiful.border_focus = colors.accent - --- Taglist colors to mirror polybar's xworkspaces module -beautiful.taglist_bg_focus = colors.accent -beautiful.taglist_fg_focus = colors.background -beautiful.taglist_fg_occupied = colors.white -beautiful.taglist_bg_occupied = colors.background -beautiful.taglist_fg_empty = colors.disabled -beautiful.taglist_bg_empty = colors.background -beautiful.taglist_bg_urgent = colors.red -beautiful.taglist_fg_urgent = colors.background - --- Systray styling -beautiful.bg_systray = colors.background -beautiful.systray_icon_spacing = 4 +local naughty = require("naughty") +local bling = require("bling") +-- Global config +modkey = "Mod1" -- Alt. Use "Mod4" for the Super/Windows key. terminal = "alacritty" editor = os.getenv("EDITOR") or "nano" --- THE modkey. "Mod1" = Alt. Use "Mod4" for the Super/Windows key. -modkey = "Mod1" - -- Layouts: suit.tile = master column LEFT, stack column RIGHT. -awful.layout.layouts = { - awful.layout.suit.tile, - awful.layout.suit.max, - awful.layout.suit.floating, -} --- }}} --- -naughty.config.defaults.position = "top_right" +awful.layout.layouts = { awful.layout.suit.tile, awful.layout.suit.max, awful.layout.suit.floating } --- {{{ Bar helpers --------------------------------------------------------- - --- "ICON value" with ICON tinted accent, like polybar's *-prefix-foreground. -local function label(icon, val) - return string.format("%s %s", - colors.accent, icon, val or "") -end - --- A slim "|" separator in the disabled color, like polybar's separator. -local function sep() - local w = wibox.widget.textbox() - w.markup = string.format(" ", colors.disabled) - return w -end - --- Wrap a widget in a small margin so bar modules aren't crammed together. -local function padded(w, left, right) - return wibox.container.margin(w, left or 8, right or 8) -end - --- Focused window title (polybar xwindow / %title%) -local function make_title() - local t = wibox.widget.textbox() - local function update() - local c = client.focus - t.markup = c and string.format("%s", colors.white, gears.string.xml_escape(c.name or "")) or "" - end - client.connect_signal("focus", update) - client.connect_signal("unfocus", update) - client.connect_signal("property::name", update) - return t -end - --- CPU usage % (two top samples so the reading is accurate) -local function make_cpu() - return awful.widget.watch( - { "bash", "-c", - [[LANG=C top -bn2 -d0.3 | grep -m2 '^%Cpu' | tail -1 | awk '{printf "%.0f", 100 - $8}']] }, - 3, - function(w, out) w.markup = label("CPU", out:gsub("%s+$","") .. "%") end) -end - --- Volume: click to mute, scroll to adjust, right-click for the mixer. --- Keeps its own refresh() so button presses update instantly instead of --- waiting on the polling timer. -local function make_vol() - local w = wibox.widget.textbox() - - local vol_script = [[ - sink=$(LANG=C pactl get-default-sink 2>/dev/null) - m=$(LANG=C pactl get-sink-mute "$sink" 2>/dev/null | grep -oE 'yes|no') - v=$(LANG=C pactl get-sink-volume "$sink" 2>/dev/null | grep -oE '[0-9]+%' | head -n1) - echo "$m $v" - ]] - - local function shell_quote(s) - return "'" .. s:gsub("'", "'\\''") .. "'" - end - local vol_cmd = "sh -c " .. shell_quote(vol_script) - - local function refresh() - awful.spawn.easy_async_with_shell(vol_cmd, function(out) - local muted, pct = out:match("(%a+)%s+(%d+)%%") - if muted == nil and pct == nil then - -- Command failed entirely (no sink found / pactl error). - w.markup = string.format("VOL n/a", colors.disabled) - return - end - muted = muted == "yes" - pct = pct or "0" - if muted then - w.markup = string.format("MUTE", colors.disabled) - else - w.markup = label("VOL", pct .. "%") - end - end) - end - - w:buttons(gears.table.join( - -- left click: toggle mute - awful.button({ }, 1, function () awful.spawn.easy_async_with_shell( [[sh -c 'pactl set-sink-mute "$(pactl get-default-sink)" toggle']], function() refresh() end) end), - -- right click: open the mixer - awful.button({ }, 3, function () awful.spawn("/home/jason/.local/bin/audioswitch") end), - -- scroll up: +2% - awful.button({ }, 4, function () awful.spawn.easy_async_with_shell( [[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" +2%']], function() refresh() end) end), - -- scroll down: -2% - awful.button({ }, 5, function () awful.spawn.easy_async_with_shell( [[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" -2%']], function() refresh() end) end) - )) - - -- Poll too, in case volume changes elsewhere (media keys, another app). - gears.timer { - timeout = 2, - call_now = true, - autostart = true, - callback = refresh, - } - - return w -end - --- {{{ Wibar widgets -local mytextclock = wibox.widget.textclock("%Y-%m-%d %H:%M") - -local taglist_buttons = gears.table.join( - awful.button({ }, 1, function(t) t:view_only() end), - awful.button({ modkey }, 1, function(t) - if client.focus then client.focus:move_to_tag(t) end - end), - awful.button({ }, 3, awful.tag.viewtoggle) -) - -local function set_wallpaper(s) - if beautiful.wallpaper then - local wp = beautiful.wallpaper - if type(wp) == "function" then wp = wp(s) end - gears.wallpaper.maximized(wp, s, true) - end -end -screen.connect_signal("property::geometry", set_wallpaper) - -awful.screen.connect_for_each_screen(function(s) - set_wallpaper(s) - - -- Workspaces 1..5 - awful.tag({ "1", "2", "3", "4", "5" }, s, awful.layout.layouts[1]) - - s.mypromptbox = awful.widget.prompt() - s.mylayoutbox = awful.widget.layoutbox(s) - s.mylayoutbox:buttons(gears.table.join( - awful.button({ }, 1, function () awful.layout.inc( 1) end), - awful.button({ }, 3, function () awful.layout.inc(-1) end) - )) - - s.mytaglist = awful.widget.taglist { - screen = s, - filter = awful.widget.taglist.filter.all, - buttons = taglist_buttons, - style = { - shape = function(cr, w, h) gears.shape.rounded_rect(cr, w, h, 4) end, - }, - layout = { - spacing = 4, - layout = wibox.layout.fixed.horizontal, - }, - widget_template = { - { - { - id = "text_role", - widget = wibox.widget.textbox, - }, - left = 10, - right = 10, - top = 4, - bottom = 4, - widget = wibox.container.margin, - }, - id = "background_role", - widget = wibox.container.background, - }, - } - - -- Per-screen monitor widgets (created here so multi-monitor stays valid) - local title = make_title() - local vol = make_vol() - local cpu = make_cpu() - - local right = wibox.layout.fixed.horizontal() - local function push(w) right:add(padded(w, 4, 4)) end - push(vol); right:add(sep()) - push(cpu); right:add(sep()) - push(mytextclock) - right:add(sep()) - push(wibox.widget.systray()) - right:add(sep()) - push(s.mylayoutbox) - - s.mywibox = awful.wibar({ - position = "top", - screen = s, - height = 36, - bg = colors.background, - fg = colors.foreground, - shape = function(cr, w, h) gears.shape.rounded_rect(cr, w, h, 0) end, - }) - - s.mywibox:setup { - layout = wibox.layout.align.horizontal, - { -- Left: workspaces + focused window title - layout = wibox.layout.fixed.horizontal, - padded(s.mytaglist, 8, 4), - s.mypromptbox, - { title, left = 18, widget = wibox.container.margin }, - }, - nil, -- empty center - padded(right, 4, 12), - } -end) --- }}} - --- {{{ Helper: launcher (prefer rofi, fall back to built-in menubar) -local function launcher() - awful.spawn.easy_async_with_shell("command -v rofi", function(out) - if out and out:match("%S") then - awful.spawn("rofi -show drun") - else - menubar.show() - end - end) -end --- }}} - --- {{{ Global keys -globalkeys = gears.table.join( - awful.key({ modkey }, "s", hotkeys_popup.show_help, {description = "show help", group = "awesome"}), - - -- Directional focus (vim keys) - awful.key({ modkey }, "h", function () awful.client.focus.bydirection("left") end, {description = "focus left", group = "client"}), - awful.key({ modkey }, "j", function () awful.client.focus.bydirection("down") end, {description = "focus down", group = "client"}), - awful.key({ modkey }, "k", function () awful.client.focus.bydirection("up") end, {description = "focus up", group = "client"}), - awful.key({ modkey }, "l", function () awful.client.focus.bydirection("right") end, {description = "focus right", group = "client"}), - - -- Directional move (swap clients in the tiling layout) - awful.key({ modkey, "Shift" }, "h", function () awful.client.swap.bydirection("left") end, {description = "move left", group = "client"}), - awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.bydirection("down") end, {description = "move down", group = "client"}), - awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.bydirection("up") end, {description = "move up", group = "client"}), - awful.key({ modkey, "Shift" }, "l", function () awful.client.swap.bydirection("right") end, {description = "move right", group = "client"}), - - -- Resize the master/other split - awful.key({ modkey, "Control" }, "h", function () awful.tag.incmwfact(-0.05) end, {description = "shrink master", group = "layout"}), - awful.key({ modkey, "Control" }, "l", function () awful.tag.incmwfact( 0.05) end, {description = "grow master", group = "layout"}), - - -- Launching / layout - awful.key({ modkey }, "Return", function () awful.spawn(terminal) end, {description = "open a terminal", group = "launcher"}), - awful.key({ modkey }, "space", launcher, {description = "application launcher", group = "launcher"}), - awful.key({ modkey }, "e", function () awful.spawn("thunar") end, {description = "Filemanager", group = "system"}), - awful.key({ modkey }, "b", function () awful.spawn("chromium") end, {description = "Browswer", group = "internet"}), - awful.key({ modkey }, "t", function () awful.layout.inc(1) end, {description = "next layout", group = "layout"}), - awful.key({ modkey }, "p", function () awful.spawn("xfce4-screenshooter") end, {description = "screenshot", group = "system"}), - - -- Alt tab only in max mode - awful.key({ "Mod1" }, "Tab", function () awful.client.focus.byidx(1) end), - - -- Media keys: volume up/down/mute (works even without a hardware key - -- if you bind these in your compositor/DE too) - awful.key({ }, "XF86AudioRaiseVolume", function () awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" +2%']]) end, {description = "volume up", group = "media"}), - awful.key({ }, "XF86AudioLowerVolume", function () awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" -2%']]) end, {description = "volume down", group = "media"}), - awful.key({ }, "XF86AudioMute", function () awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-mute "$(pactl get-default-sink)" toggle']]) end, {description = "toggle mute", group = "media"}), - - -- rofi menus - awful.key({ modkey }, "a", function () awful.spawn("/home/jason/.local/bin/audioswitch") end, {description = "audio output", group = "system"}), - awful.key({ modkey, "Shift" }, "p", function () awful.spawn("/home/jason/.local/bin/powermenu") end, {description = "power menu", group = "system"}), - - -- Awesome control - awful.key({ modkey, "Shift" }, "r", awesome.restart, {description = "reload awesome", group = "awesome"}) -) - --- Workspace keys 1..5: Alt+N view, Alt+Shift+N move client to tag -for i = 1, 5 do - globalkeys = gears.table.join(globalkeys, - awful.key({ modkey }, "#" .. i + 9, function () - local screen = awful.screen.focused() - local tag = screen.tags[i] - if tag then tag:view_only() end - end, - {description = "view tag #" .. i, group = "tag"}), - awful.key({ modkey, "Shift" }, "#" .. i + 9, function () - if client.focus then - local tag = client.focus.screen.tags[i] - if tag then client.focus:move_to_tag(tag) end - end - end, - {description = "move focused client to tag #" .. i, group = "tag"}) - ) -end --- }}} - --- {{{ Per-client keys -clientkeys = gears.table.join( - awful.key({ modkey }, "q", function (c) c:kill() end, {description = "kill window", group = "client"}), - awful.key({ modkey }, "f", function (c) c.fullscreen = not c.fullscreen c:raise() end, {description = "toggle fullscreen", group = "client"}), - awful.key({ modkey }, "m", function (c) c:swap(awful.client.getmaster()) end, {description = "make master", group = "client"}), - awful.key({ modkey, "Shift" }, "space", awful.client.floating.toggle, {description = "toggle floating", group = "client"}) -) - -clientbuttons = gears.table.join( - awful.button({ }, 1, function (c) c:emit_signal("request::activate", "mouse_click", {raise = true}) end), - awful.button({ modkey }, 1, function (c) c:emit_signal("request::activate", "mouse_click", {raise = true}) awful.mouse.client.move(c) end), - awful.button({ modkey }, 3, function (c) c:emit_signal("request::activate", "mouse_click", {raise = true}) awful.mouse.client.resize(c) end) -) - -root.keys(globalkeys) --- }}} - --- {{{ Rules -awful.rules.rules = { - { rule = { }, - properties = { - border_width = beautiful.border_width, - border_color = beautiful.border_normal, - focus = awful.client.focus.filter, - raise = true, - keys = clientkeys, - buttons = clientbuttons, - screen = awful.screen.preferred, - placement = awful.placement.no_overlap + awful.placement.no_offscreen, - } - }, - - { rule_any = { - instance = { "pinentry" }, - class = { "Arandr", "Blueman-manager", "Gpick", "Pavucontrol" }, - name = { "Event Tester" }, - role = { "AlarmWindow", "pop-up" }, - }, properties = { floating = true }}, - -} --- }}} - --- {{{ Signals -client.connect_signal("manage", function (c) - if awesome.startup - and not c.size_hints.user_position - and not c.size_hints.program_position then - awful.placement.no_offscreen(c) - end - - -- New windows open into the stack (to the right); first window becomes master. - if not awesome.startup then - awful.client.setslave(c) - end - - c.shape = function(cr, width, height) - -- 8 = corner radius in px - gears.shape.rounded_rect(cr, width, height, 13) - end +-- Kill xfce4-notifyd on startup (with a short delay + retry, in case it +-- hasn't started yet at this point in the session) +awful.spawn.easy_async_with_shell("pkill xfce4-notifyd", function() end) +gears.timer.start_new(3, function() + awful.spawn.easy_async_with_shell("pkill xfce4-notifyd", function() end) + return false -- don't repeat end) -client.connect_signal("property::floating", function(c) - if c.floating and c.type ~= "notification" then - awful.placement.centered(c, { honor_workarea = true }) - end -end) +-- Error handling +if awesome.startup_errors then + naughty.notify({ preset = naughty.config.presets.critical, title = "Error during startup", text = awesome.startup_errors }) +end +do + local in_error = false + awesome.connect_signal("debug::error", function(err) + if in_error then return end + in_error = true + naughty.notify({ preset = naughty.config.presets.critical, title = "An error happened", text = tostring(err) }) + in_error = false + end) +end -client.connect_signal("manage", function(c) - if c.floating and c.type ~= "notification" then - awful.placement.centered(c, { honor_workarea = true }) - end -end) - --- Focus follows mouse (i3-like). Comment out for click-to-focus only. -client.connect_signal("mouse::enter", function(c) - c:emit_signal("request::activate", "mouse_enter", {raise = false}) -end) - -client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end) -client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end) --- }}} +-- Modules (order matters: theme before bar, keys before rules) +require("config.theme") +local keys = require("config.keys") +require("config.bar").setup() +root.keys(keys.globalkeys) +awful.rules.rules = require("config.rules") +require("config.signals") -- Wallpaper bling.module.wallpaper.setup { - wallpaper = {"/home/jason/Pictures/Wallpapers/farewell.jpg"}, - position = "fit", - background = "#181818" + wallpaper = { "/home/jason/Pictures/Wallpapers/farewell.jpg" }, + position = "fit", + background = "#181818", } diff --git a/config/fish/config.fish b/config/fish/config.fish index 44cd278..9521cd4 100644 --- a/config/fish/config.fish +++ b/config/fish/config.fish @@ -92,7 +92,7 @@ alias fetch='pfetch' # Custom shortcuts alias reload='source ~/.config/fish/config.fish' -alias dotf='cd ~/.dotfiles' +alias dots='cd ~/.dotfiles && nvim' alias doti='bash ~/.dotfiles/install.sh -i' alias dotl='bash ~/.dotfiles/install.sh -l' alias myip='curl ipinfo.io/ip; echo ""' diff --git a/config/rofi/config.rasi b/config/rofi/config.rasi index 1b84f28..1343508 100644 --- a/config/rofi/config.rasi +++ b/config/rofi/config.rasi @@ -21,7 +21,7 @@ window { /* Anchor top-center, right below the wibar. */ location: north; anchor: north; - y-offset: 38px; + y-offset: 48px; width: 32em; height: 26em; /* fixed — box size no longer changes with result count */