Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions config/noctalia/ac-idle-inhibit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# Inhibit idle when on AC power so noctalia's idle timeouts only fire on battery.
# Polls every 2s so AC state changes take effect well within the 5-min idle window.
set -euo pipefail

AC=/sys/class/power_supply/ACAD/online

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded ACAD path diverges from the repo's portable pattern.

This repo already has two AC-aware scripts that don't hardcode the adapter name:

  • home-manager/modules/local-scripts/decafinate.sh:42-46 and :174-178 iterate for ac_path in /sys/class/power_supply/AC*/online; do ....
  • scripts/wallpaper-power-check.sh takes the path as @ac_supply_path@ via pkgs.replaceVars.

With the hardcoded path here, cat "$AC" 2>/dev/null returns empty when the file is missing, the test fails, and the script silently behaves as if on battery — with no warning. It works today only because config/noctalia/ is loaded under isDesktop = true, which only named-hosts/matic enables. If noctalia is ever turned on for another desktop host with a different adapter name (e.g. AC0, ADP1), this script will silently do nothing and the failure will be invisible.

Consider switching to the AC*/online glob to match the existing pattern.


while true; do
if [ "$(cat "$AC" 2>/dev/null)" = "1" ]; then
systemd-inhibit --what=idle --why="On AC power" --mode=block sleep 2
else
sleep 2
fi
done
Comment on lines +6 to +14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The script hardcodes the AC adapter path to /sys/class/power_supply/ACAD/online, which is hardware-dependent and may not exist on all systems (e.g., some use AC or ADP1). Using a glob with grep is more robust and avoids potential failures if the specific path is missing. Additionally, since set -e is used, the script would terminate if the hardcoded path was missing and accessed via a subshell in a different context.

Suggested change
AC=/sys/class/power_supply/ACAD/online
while true; do
if [ "$(cat "$AC" 2>/dev/null)" = "1" ]; then
systemd-inhibit --what=idle --why="On AC power" --mode=block sleep 20
else
sleep 20
fi
done
while true;
do
if grep -q 1 /sys/class/power_supply/*/online 2>/dev/null; then
systemd-inhibit --what=idle --why="On AC power" --mode=block sleep 20
else
sleep 20
fi
done

41 changes: 36 additions & 5 deletions config/noctalia/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@
force = true;
};

# Inhibit idle when plugged into AC; noctalia's idle timeouts apply on battery only.
systemd.user.services.ac-idle-inhibit = {
Unit = {
Description = "Inhibit idle when on AC power";
After = [ "graphical-session.target" ];
PartOf = [ "graphical-session.target" ];
};
Service = {
Type = "simple";
ExecStart = "${pkgs.bash}/bin/bash ${./ac-idle-inhibit.sh}";
Restart = "on-failure";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add RestartSec to avoid a tight restart loop on transient failures.

The script runs under set -euo pipefail, so any non-zero exit from systemd-inhibit (e.g., logind not yet reachable early in the graphical session, polkit denial, missing binary on PATH) aborts the loop. With Restart = "on-failure" and no RestartSec, systemd will respawn at the default ~100 ms until the default start-limit trips and the unit is marked failed silently.

Other similar units in this repo set this:

  • home-manager/services/keyd-application-mapper/default.nix:40RestartSec = 3;
  • named-hosts/matic/default.nix:462 (wallpaper-power-monitor) — RestartSec = 5;

Suggested:

      Restart = "on-failure";
      RestartSec = 5;

};
Comment on lines +19 to +23

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The systemd service relies on systemd-inhibit, grep, and sleep being in the PATH. In a systemd user service, the environment might be restricted. It is safer to explicitly provide the required packages in the service's path attribute to ensure reliability across different environments.

    path = [ pkgs.systemd pkgs.coreutils pkgs.gnugrep ];
    Service = {
      Type = "simple";
      ExecStart = "${pkgs.bash}/bin/bash ${./ac-idle-inhibit.sh}";
      Restart = "on-failure";
    };

Install.WantedBy = [ "graphical-session.target" ];
};

programs.noctalia-shell = {
enable = true;
package = inputs.noctalia-shell.packages.${pkgs.system}.default;
Expand All @@ -20,6 +35,7 @@
capsuleOpacity = 0;
widgets.left = [
{ id = "Launcher"; }
{ id = "Workspaces"; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid widget id — Workspaces (plural) is not registered in noctalia.

noctalia-shell @ 9f8dd48 only registers the singular Workspace in Services/UI/BarWidgetRegistry.qml, and BarWidgetLoader.qml loads widgets via _barWidgetsDir + widgetId + ".qml" against Modules/Bar/Widgets/Workspace.qml. With Workspaces (plural), BarWidgetRegistry.hasWidget() returns false, the loader logs "Widget not found in registry", and the slot renders nothing — so the workspaces indicator never appears between Launcher and Clock.

Fix: use the singular id.

Suggested change
{ id = "Workspaces"; }
{ id = "Workspace"; }

{
id = "Clock";
formatHorizontal = "yyyy/MM/dd HH:mm:ss";
Expand All @@ -44,12 +60,11 @@
{ id = "PowerProfile"; }
{ id = "Volume"; }
{ id = "Brightness"; }
{ id = "Settings"; }
{ id = "ControlCenter"; }
];
};
ui = {
fontDefault = "JetBrainsMono Nerd Font";
fontDefault = "Noto Sans";
fontFixed = "JetBrainsMono Nerd Font";
};
notifications = {
Expand All @@ -69,20 +84,36 @@
compactLockScreen = true;
autoStartAuth = true;
allowPasswordWithFprintd = true;
lockOnSuspend = true;
};
colorSchemes.predefinedScheme = "Dracula-Custom";
hooks = {
enabled = true;
darkModeChange = ''if [ "$1" = "true" ]; then dconf write /org/gnome/desktop/interface/color-scheme "'prefer-dark'" && dconf write /org/gnome/desktop/interface/gtk-theme "'Adwaita-dark'"; else dconf write /org/gnome/desktop/interface/color-scheme "'prefer-light'" && dconf write /org/gnome/desktop/interface/gtk-theme "'Adwaita'"; fi'';
darkModeChange = ''
if [ "$1" = "true" ]; then
dconf write /org/gnome/desktop/interface/color-scheme "'prefer-dark'"
dconf write /org/gnome/desktop/interface/gtk-theme "'Adwaita-dark'"
dconf write /org/gnome/desktop/interface/icon-theme "'Adwaita'"
else
dconf write /org/gnome/desktop/interface/color-scheme "'prefer-light'"
dconf write /org/gnome/desktop/interface/gtk-theme "'Adwaita'"
dconf write /org/gnome/desktop/interface/icon-theme "'Adwaita'"
fi
'';
Comment on lines +92 to +102

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The icon-theme is set to the same value ('Adwaita') in both branches of the if statement. Moving it outside the conditional block improves maintainability. Additionally, using the absolute path to the dconf binary from pkgs makes the hook more robust against environment variations, adhering to the repository's pattern for Nix-extracted scripts.

        darkModeChange = ''
          ${pkgs.dconf}/bin/dconf write /org/gnome/desktop/interface/icon-theme "'Adwaita'"
          if [ "$1" = "true" ]; then
            ${pkgs.dconf}/bin/dconf write /org/gnome/desktop/interface/color-scheme "'prefer-dark'"
            ${pkgs.dconf}/bin/dconf write /org/gnome/desktop/interface/gtk-theme "'Adwaita-dark'"
          else
            ${pkgs.dconf}/bin/dconf write /org/gnome/desktop/interface/color-scheme "'prefer-light'"
            ${pkgs.dconf}/bin/dconf write /org/gnome/desktop/interface/gtk-theme "'Adwaita'"
          fi
        '';
References
  1. Maintain consistency with established patterns for writing scripts that are extracted from Nix expressions.

};
dock = {
colorizeIcons = true;
showLauncherIcon = true;
showDockIndicator = true;
showDockIndicator = false;
};
desktopWidgets.enabled = true;
wallpaper.enabled = false;
idle.enabled = true;
idle = {
enabled = true;
screenOffTimeout = 300; # 5 min on battery
lockTimeout = 300;
suspendTimeout = 600; # 10 min on battery
};
systemMonitor.enableDgpuMonitoring = true;
colorSchemes.schedulingMode = "location";
location.autoLocate = true;
Expand Down
1 change: 1 addition & 0 deletions spec/coverage_spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ config/git-ai/activate.sh
config/hyprland/scripts/record-screen.sh
config/hyprland/scripts/toggle-terminal.sh
config/k3s/activate.sh
config/noctalia/ac-idle-inhibit.sh

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This new shell script is added to the coverage list without a corresponding spec-file check, so the coverage guard no longer verifies test-file presence for it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At spec/coverage_spec.sh, line 363:

<comment>This new shell script is added to the coverage list without a corresponding spec-file check, so the coverage guard no longer verifies test-file presence for it.</comment>

<file context>
@@ -360,6 +360,7 @@ config/git-ai/activate.sh
 config/hyprland/scripts/record-screen.sh
 config/hyprland/scripts/toggle-terminal.sh
 config/k3s/activate.sh
+config/noctalia/ac-idle-inhibit.sh
 config/obsidian/activate.sh
 config/omp/activate.sh
</file context>

config/obsidian/activate.sh
config/omp/activate.sh
config/openclaw/hydrate.sh
Expand Down
Loading