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 */