feat(noctalia): add modular Hyprland profiles
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# Hyprland desktop status bar. Ashell reloads this file when it changes.
|
||||
# Keep this intentionally lean while replacing the existing Waybar profile.
|
||||
|
||||
position = "Bottom"
|
||||
layer = "Top"
|
||||
|
||||
[modules]
|
||||
left = ["Workspaces", "KeyboardLayout"]
|
||||
center = ["WindowTitle"]
|
||||
right = ["SystemInfo", "MediaPlayer", ["Tray", "Tempo", "Settings"]]
|
||||
|
||||
[workspaces]
|
||||
visibility_mode = "MonitorSpecific"
|
||||
disable_special_workspaces = true
|
||||
@@ -0,0 +1,135 @@
|
||||
-- Shared Hyprland profile. yadm deploys machine.lua for the active class.
|
||||
--
|
||||
-- Scope: preserve launch, media, directional focus/move, workspace, scratchpad,
|
||||
-- floating, fullscreen, and window-placement muscle memory. i3's split-tree,
|
||||
-- stacking/tabbed, and resize-mode behavior is intentionally deferred.
|
||||
local machine = dofile(os.getenv("HOME") .. "/.config/hypr/machine.lua")
|
||||
|
||||
for _, monitor in ipairs(machine.monitors or {}) do
|
||||
hl.monitor(monitor)
|
||||
end
|
||||
|
||||
local main_mod = "SUPER"
|
||||
local terminal = "alacritty"
|
||||
|
||||
hl.config({
|
||||
input = {
|
||||
kb_layout = "us",
|
||||
kb_variant = "intl",
|
||||
numlock_by_default = true,
|
||||
},
|
||||
general = {
|
||||
gaps_in = 8,
|
||||
-- Keep a thin black perimeter so the bottom border remains on-screen.
|
||||
gaps_out = 2,
|
||||
border_size = 2,
|
||||
col = {
|
||||
-- Muted Ember tones: visible focus without a high-brightness OLED edge.
|
||||
active_border = "rgba(c9782ed9)",
|
||||
inactive_border = "rgba(2a190fa6)",
|
||||
},
|
||||
},
|
||||
decoration = {
|
||||
rounding = 0,
|
||||
},
|
||||
animations = {
|
||||
enabled = false,
|
||||
},
|
||||
})
|
||||
|
||||
-- Application and session bindings.
|
||||
local noctalia_ipc = "noctalia msg "
|
||||
-- Tap and release Super on its own to open Noctalia's control-center home.
|
||||
hl.bind(main_mod .. " + SUPER_L", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle control-center"), { release = true })
|
||||
hl.bind(main_mod .. " + RETURN", hl.dsp.exec_cmd(terminal))
|
||||
hl.bind(main_mod .. " + CTRL + RETURN", hl.dsp.exec_cmd(terminal .. " -e zellij"))
|
||||
hl.bind(main_mod .. " + SHIFT + RETURN", hl.dsp.exec_cmd("rofi -show combi"))
|
||||
hl.bind(main_mod .. " + SPACE", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle launcher"))
|
||||
hl.bind(main_mod .. " + S", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle control-center"))
|
||||
hl.bind(main_mod .. " + SHIFT + F", hl.dsp.exec_cmd(noctalia_ipc .. "bar-toggle main"))
|
||||
hl.bind(main_mod .. " + SHIFT + R", hl.dsp.exec_cmd("hyprctl reload"))
|
||||
hl.bind(main_mod .. " + CTRL + L", hl.dsp.exec_cmd("command -v hyprlock >/dev/null && hyprlock || loginctl lock-session"))
|
||||
hl.bind(main_mod .. " + CTRL + SHIFT + ALT + S", hl.dsp.exec_cmd("systemctl suspend"))
|
||||
hl.bind(main_mod .. " + CTRL + SHIFT + ALT + H", hl.dsp.exec_cmd("systemctl hibernate"))
|
||||
hl.bind(main_mod .. " + SHIFT + C", hl.dsp.window.close())
|
||||
hl.bind(main_mod .. " + CTRL + SHIFT + F", hl.dsp.exec_cmd("env LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 flameshot gui"))
|
||||
|
||||
-- Audio, media, brightness, and calculator keys.
|
||||
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { locked = true })
|
||||
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"), { locked = true })
|
||||
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), { locked = true })
|
||||
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
|
||||
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
||||
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86AudioRaiseVolume", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86AudioLowerVolume", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
||||
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd('light -A 5 && notify-send "Brightness set to $(light)"'), { locked = true })
|
||||
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd('light -U 5 && notify-send "Brightness set to $(light)"'), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86MonBrightnessDown", hl.dsp.exec_cmd('light -S 0.2 && notify-send "Brightness set to min"'), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86MonBrightnessUp", hl.dsp.exec_cmd('light -S 100 && notify-send "Brightness set to max"'), { locked = true })
|
||||
hl.bind("XF86Calculator", hl.dsp.exec_cmd("qalculate-qt"), { locked = true })
|
||||
|
||||
-- Retain i3's hjkl and arrow-key directional workflow.
|
||||
for _, direction in ipairs({ "left", "down", "up", "right" }) do
|
||||
local key = ({ left = "H", down = "J", up = "K", right = "L" })[direction]
|
||||
hl.bind(main_mod .. " + " .. key, hl.dsp.focus({ direction = direction }))
|
||||
hl.bind(main_mod .. " + " .. direction, hl.dsp.focus({ direction = direction }))
|
||||
end
|
||||
|
||||
for key, direction in pairs({ H = "l", J = "d", K = "u", L = "r", LEFT = "l", DOWN = "d", UP = "u", RIGHT = "r" }) do
|
||||
hl.bind(main_mod .. " + SHIFT + " .. key, hl.dsp.window.move({ direction = direction }))
|
||||
end
|
||||
|
||||
-- Numbered workspaces match the i3 profile. Shift moves; Ctrl moves and follows.
|
||||
for workspace = 1, 9 do
|
||||
local key = tostring(workspace)
|
||||
hl.bind(main_mod .. " + " .. key, hl.dsp.focus({ workspace = workspace }))
|
||||
hl.bind(main_mod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = workspace }))
|
||||
hl.bind(main_mod .. " + CTRL + " .. key, hl.dsp.window.move({ workspace = workspace, follow = true }))
|
||||
end
|
||||
-- Hyprland has no direct i3-style back_and_forth dispatcher; use numbered workspaces.
|
||||
hl.bind(main_mod .. " + CTRL + RIGHT", hl.dsp.focus({ workspace = "+1" }))
|
||||
hl.bind(main_mod .. " + CTRL + LEFT", hl.dsp.focus({ workspace = "-1" }))
|
||||
|
||||
-- Hyprland special workspaces are the Wayland analogue of the i3 scratchpad.
|
||||
hl.bind(main_mod .. " + MINUS", hl.dsp.workspace.toggle_special("scratchpad"))
|
||||
hl.bind(main_mod .. " + SHIFT + MINUS", hl.dsp.window.move({ workspace = "special:scratchpad" }))
|
||||
|
||||
-- Keep the i3 floating and fullscreen shortcuts. Layout-specific binds are deferred.
|
||||
hl.bind(main_mod .. " + F", hl.dsp.window.fullscreen({ action = "toggle" }))
|
||||
hl.bind(main_mod .. " + SHIFT + SPACE", hl.dsp.window.float({ action = "toggle" }))
|
||||
hl.bind(main_mod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
||||
hl.bind(main_mod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
|
||||
|
||||
-- i3 for_window/assign translations. Verify Wayland class/title values with `hyprctl clients`.
|
||||
local function float_rule(name, match, border_size)
|
||||
hl.window_rule({
|
||||
name = name,
|
||||
match = match,
|
||||
float = true,
|
||||
border_size = border_size,
|
||||
})
|
||||
end
|
||||
|
||||
hl.window_rule({ name = "thunderbird-workspace", match = { class = "^Thunderbird$" }, workspace = "9" })
|
||||
float_rule("alsamixer", { title = "^alsamixer$" }, 1)
|
||||
float_rule("qalculate", { title = "^Qalculate!$" })
|
||||
float_rule("psensor", { class = "^Psensor$" })
|
||||
float_rule("lxrandr", { title = "^lxrandr$" })
|
||||
float_rule("blueman", { class = "^Blueman-manager$" })
|
||||
float_rule("gparted", { class = "^GParted$" })
|
||||
float_rule("pavucontrol", { class = "^pavucontrol$" })
|
||||
float_rule("volume-control", { title = "^Volume Control$" })
|
||||
float_rule("virtualbox", { class = ".*VirtualBox.*" })
|
||||
hl.window_rule({ name = "virtualbox-manager-tiles", match = { class = ".*VirtualBox Manager.*" }, tile = true })
|
||||
hl.window_rule({ name = "virtualbox-machine-tiles", match = { class = ".*VirtualBox Machine.*" }, tile = true })
|
||||
-- Send music clients to the existing scratchpad without stealing startup focus.
|
||||
hl.window_rule({ name = "spotify-music", match = { class = "^Spotify$" }, workspace = "special:scratchpad silent", no_initial_focus = true })
|
||||
hl.window_rule({ name = "deezer-music", match = { class = "^Deezer$" }, workspace = "special:scratchpad silent", no_initial_focus = true })
|
||||
|
||||
hl.on("hyprland.start", function()
|
||||
for _, command in ipairs(machine.startup or {}) do
|
||||
hl.exec_cmd(command)
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Desktop-only display and startup profile.
|
||||
return {
|
||||
monitors = {
|
||||
{
|
||||
output = "HDMI-A-1",
|
||||
mode = "3840x2160@120",
|
||||
position = "0x0",
|
||||
scale = 1,
|
||||
},
|
||||
},
|
||||
startup = {
|
||||
"noctalia",
|
||||
-- Electron's tray icon registers only when the SNI watcher already exists.
|
||||
"sh -c 'sleep 2; exec mullvad-vpn'",
|
||||
"thunderbird",
|
||||
"nextcloud",
|
||||
"spotify",
|
||||
"brave",
|
||||
"alacritty -e tmux",
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
-- Laptop profile: leave monitor selection to Hyprland's hotplug support.
|
||||
-- Noctalia replaces the i3-era Redshift, Polybar, Blueman Applet, and Picom stack.
|
||||
return {
|
||||
monitors = {},
|
||||
startup = {
|
||||
"noctalia",
|
||||
-- Start after Noctalia has claimed the StatusNotifier watcher.
|
||||
"sh -c 'sleep 2; exec mullvad-vpn'",
|
||||
"nextcloud",
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# Shared Noctalia defaults. Keep GUI experiments in state; promote durable choices here.
|
||||
[shell]
|
||||
setup_wizard_enabled = false
|
||||
offline_mode = true
|
||||
external_ip_enabled = false
|
||||
telemetry_enabled = false
|
||||
|
||||
[theme]
|
||||
mode = "dark"
|
||||
source = "custom"
|
||||
custom_palette = "Ember OLED"
|
||||
pure_black_dark = true
|
||||
@@ -0,0 +1,110 @@
|
||||
# Desktop-specific shell layout and hardware telemetry.
|
||||
[bar.main]
|
||||
position = "bottom"
|
||||
layer = "overlay"
|
||||
capsule_radius = 5
|
||||
center = ["group:g3", "notifications"]
|
||||
end = ["bluetooth", "volume", "control-center", "group:g1", "session"]
|
||||
font_weight = 400
|
||||
margin_ends = 0
|
||||
padding = 0
|
||||
panel_overlap = 3
|
||||
radius = 0
|
||||
shadow = false
|
||||
smart_auto_hide = true
|
||||
# The bar may overlay the thin perimeter while visible; hidden bars release the space.
|
||||
reserve_space = false
|
||||
start = ["tray", "group:g4", "group:g2", "privacy"]
|
||||
thickness = 39
|
||||
widget_spacing = 10
|
||||
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g1"
|
||||
members = ["caffeine", "date", "clock"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g2"
|
||||
members = ["network_rx", "network_tx", "network"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g3"
|
||||
members = ["launcher", "media", "control-center", "clipboard"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
radius = 5.0
|
||||
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g4"
|
||||
members = ["cpu", "temp", "ram", "gpu", "gpu_temp", "disk", "battery"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
[widget.cpu]
|
||||
type = "alex/system-status:cpu"
|
||||
|
||||
[widget.ram]
|
||||
type = "alex/system-status:memory"
|
||||
|
||||
[widget.temp]
|
||||
type = "sysmon"
|
||||
stat = "cpu_temp"
|
||||
display = "text"
|
||||
|
||||
[widget.gpu]
|
||||
type = "sysmon"
|
||||
stat = "gpu_usage"
|
||||
display = "graph"
|
||||
|
||||
[widget.gpu_temp]
|
||||
type = "sysmon"
|
||||
stat = "gpu_temp"
|
||||
display = "text"
|
||||
|
||||
[widget.disk]
|
||||
type = "sysmon"
|
||||
stat = "disk_pct"
|
||||
display = "text"
|
||||
path = "/"
|
||||
|
||||
[battery.device."/org/freedesktop/UPower/devices/battery_hidpp_battery_0"]
|
||||
warning_threshold = 20
|
||||
|
||||
[control_center]
|
||||
sidebar = "full"
|
||||
sidebar_section = "full"
|
||||
width = 880
|
||||
|
||||
[desktop_widgets]
|
||||
enabled = false
|
||||
|
||||
[wallpaper]
|
||||
enabled = true
|
||||
fill_color = "#000000"
|
||||
|
||||
[wallpaper.default]
|
||||
path = "color:#000000"
|
||||
|
||||
[system.monitor]
|
||||
# GPU polling is disabled by Noctalia by default; enable it for the RTX 3090 widgets.
|
||||
gpu_poll_seconds = 2.0
|
||||
|
||||
[plugins]
|
||||
enabled = ["alex/system-status"]
|
||||
|
||||
[nightlight]
|
||||
enabled = true
|
||||
force = false
|
||||
temperature_day = 6500
|
||||
temperature_night = 2500
|
||||
@@ -0,0 +1,93 @@
|
||||
# Laptop-specific Noctalia layout. Shared privacy/theme defaults live in 10-base.toml.
|
||||
[bar.main]
|
||||
position = "top"
|
||||
layer = "overlay"
|
||||
capsule_radius = 5
|
||||
center = ["group:g3", "notifications"]
|
||||
end = ["bluetooth", "volume", "control-center", "group:g1", "session"]
|
||||
font_weight = 400
|
||||
margin_ends = 0
|
||||
padding = 0
|
||||
panel_overlap = 3
|
||||
radius = 0
|
||||
shadow = false
|
||||
auto_hide = false
|
||||
smart_auto_hide = false
|
||||
reserve_space = true
|
||||
start = ["tray", "group:g4", "group:g2", "privacy"]
|
||||
thickness = 39
|
||||
widget_spacing = 10
|
||||
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g1"
|
||||
members = ["caffeine", "date", "clock"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g2"
|
||||
members = ["network_rx", "network_tx", "network"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g3"
|
||||
members = ["launcher", "media", "control-center", "clipboard"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
radius = 5.0
|
||||
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g4"
|
||||
members = ["cpu", "temp", "ram", "disk", "battery"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
[widget.cpu]
|
||||
type = "alex/system-status:cpu"
|
||||
|
||||
[widget.ram]
|
||||
type = "alex/system-status:memory"
|
||||
|
||||
[widget.temp]
|
||||
type = "sysmon"
|
||||
stat = "cpu_temp"
|
||||
display = "text"
|
||||
|
||||
[widget.disk]
|
||||
type = "sysmon"
|
||||
stat = "disk_pct"
|
||||
display = "text"
|
||||
path = "/"
|
||||
|
||||
[control_center]
|
||||
sidebar = "full"
|
||||
sidebar_section = "full"
|
||||
width = 720
|
||||
|
||||
[desktop_widgets]
|
||||
enabled = false
|
||||
|
||||
[wallpaper]
|
||||
enabled = true
|
||||
fill_color = "#000000"
|
||||
|
||||
[wallpaper.default]
|
||||
path = "color:#000000"
|
||||
|
||||
[plugins]
|
||||
enabled = ["alex/system-status"]
|
||||
|
||||
[nightlight]
|
||||
enabled = true
|
||||
force = false
|
||||
temperature_day = 6500
|
||||
temperature_night = 2500
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"dark": {
|
||||
"mPrimary": "#ff8800",
|
||||
"mOnPrimary": "#1a0d00",
|
||||
"mSecondary": "#ffb05c",
|
||||
"mOnSecondary": "#2b1600",
|
||||
"mTertiary": "#ffcc99",
|
||||
"mOnTertiary": "#2b1600",
|
||||
"mError": "#ff6b4a",
|
||||
"mOnError": "#2b0700",
|
||||
"mSurface": "#050403",
|
||||
"mOnSurface": "#fff1e6",
|
||||
"mSurfaceVariant": "#1a110c",
|
||||
"mOnSurfaceVariant": "#f4c7a1",
|
||||
"mOutline": "#6e4a31",
|
||||
"mShadow": "#000000",
|
||||
"mHover": "#2a190f",
|
||||
"mOnHover": "#fff1e6",
|
||||
"terminal": {
|
||||
"background": "#050403",
|
||||
"foreground": "#fff1e6",
|
||||
"cursor": "#fff1e6",
|
||||
"cursorText": "#050403",
|
||||
"selectionBg": "#3b220f",
|
||||
"selectionFg": "#fff1e6",
|
||||
"normal": {
|
||||
"black": "#050403",
|
||||
"red": "#ff6b4a",
|
||||
"green": "#c98a45",
|
||||
"yellow": "#ffb05c",
|
||||
"blue": "#c97c45",
|
||||
"magenta": "#d98a5c",
|
||||
"cyan": "#e8a76a",
|
||||
"white": "#fff1e6"
|
||||
},
|
||||
"bright": {
|
||||
"black": "#6e4a31",
|
||||
"red": "#ff8f72",
|
||||
"green": "#e8ad68",
|
||||
"yellow": "#ffca80",
|
||||
"blue": "#e8a06a",
|
||||
"magenta": "#f0ad82",
|
||||
"cyan": "#ffd0a0",
|
||||
"white": "#ffffff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
-- Sum each logical CPU's interval utilization. Unlike the built-in average,
|
||||
-- this follows Unix tools by allowing the value to exceed 100%.
|
||||
local command = [[awk '
|
||||
/^cpu[0-9]+ / {
|
||||
total = 0
|
||||
for (i = 2; i <= NF; i++) total += $i
|
||||
idle = $5 + $6
|
||||
printf "%s %.0f %.0f\n", $1, total, idle
|
||||
}' /proc/stat]]
|
||||
|
||||
local previous = {}
|
||||
local request_in_flight = false
|
||||
|
||||
function update()
|
||||
noctalia.setUpdateInterval(2000)
|
||||
|
||||
if request_in_flight then
|
||||
return
|
||||
end
|
||||
|
||||
request_in_flight = true
|
||||
noctalia.runAsync(command, function(result)
|
||||
request_in_flight = false
|
||||
|
||||
if result.exitCode ~= 0 then
|
||||
barWidget.setText("CPU —")
|
||||
return
|
||||
end
|
||||
|
||||
local utilization = 0
|
||||
local sampled = 0
|
||||
for line in string.gmatch(result.stdout, "[^\r\n]+") do
|
||||
local name, total, idle = string.match(line, "^(cpu%d+) (%d+) (%d+)$")
|
||||
total = tonumber(total)
|
||||
idle = tonumber(idle)
|
||||
local prior = previous[name]
|
||||
|
||||
if prior ~= nil then
|
||||
local total_delta = total - prior.total
|
||||
local idle_delta = idle - prior.idle
|
||||
if total_delta > 0 then
|
||||
utilization = utilization + (100 * (total_delta - idle_delta) / total_delta)
|
||||
sampled = sampled + 1
|
||||
end
|
||||
end
|
||||
|
||||
previous[name] = { total = total, idle = idle }
|
||||
end
|
||||
|
||||
barWidget.setGlyph("cpu")
|
||||
if sampled > 0 then
|
||||
barWidget.setText(string.format("%.0f%%", utilization))
|
||||
barWidget.setTooltip("Aggregate CPU utilization (100% per logical CPU)")
|
||||
else
|
||||
barWidget.setText("—")
|
||||
barWidget.setTooltip("Sampling CPU utilization…")
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
-- Read the tiny kernel meminfo pseudo-file every five seconds. This avoids a
|
||||
-- resident helper process and reuses Noctalia's lightweight widget lifecycle.
|
||||
local command = [[awk '
|
||||
$1 == "MemTotal:" { total = $2 }
|
||||
$1 == "MemAvailable:" { available = $2 }
|
||||
$1 == "SwapTotal:" { swap_total = $2 }
|
||||
$1 == "SwapFree:" { swap_free = $2 }
|
||||
END {
|
||||
if (!total || !available) exit 1
|
||||
used = total - available
|
||||
if (swap_total > 0) {
|
||||
swap_used = (swap_total - swap_free) * 100 / swap_total
|
||||
printf "RAM %.1f/%.1f GiB S %.0f%%\n", used / 1048576, total / 1048576, swap_used
|
||||
} else {
|
||||
printf "RAM %.1f/%.1f GiB S —\n", used / 1048576, total / 1048576
|
||||
}
|
||||
}' /proc/meminfo]]
|
||||
|
||||
local request_in_flight = false
|
||||
|
||||
function update()
|
||||
noctalia.setUpdateInterval(5000)
|
||||
|
||||
if request_in_flight then
|
||||
return
|
||||
end
|
||||
|
||||
request_in_flight = true
|
||||
noctalia.runAsync(command, function(result)
|
||||
request_in_flight = false
|
||||
|
||||
if result.exitCode ~= 0 then
|
||||
barWidget.setText("RAM —")
|
||||
barWidget.setTooltip("Unable to read /proc/meminfo")
|
||||
return
|
||||
end
|
||||
|
||||
local text = string.gsub(result.stdout, "%s+$", "")
|
||||
barWidget.setGlyph("memory")
|
||||
barWidget.setText(text)
|
||||
barWidget.setTooltip("RAM used / total · S = swap used")
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
id = "alex/system-status"
|
||||
name = "System Status"
|
||||
version = "1.0.0"
|
||||
plugin_api = 3
|
||||
author = "alex"
|
||||
description = "Low-overhead memory and swap indicator for the bar."
|
||||
|
||||
[[widget]]
|
||||
id = "cpu"
|
||||
entry = "cpu.luau"
|
||||
|
||||
[[widget]]
|
||||
id = "memory"
|
||||
entry = "memory.luau"
|
||||
Reference in New Issue
Block a user