This commit is contained in:
2026-07-30 15:24:55 +09:00
parent c566f426ec
commit 8dc9452d95
14 changed files with 218 additions and 102 deletions
+18 -17
View File
@@ -28,7 +28,7 @@ makes any statement here stale, update `AGENTS.md` in the same change.
Use **unit** as the generic internal term for a Registry-managed component and
**profile** for a unit that composes multiple units. Do not introduce a
`features/` layer. Window managers and desktop environments such as niri and
GNOME belong in `modules/applications/`; do not create a separate `desktop/`
labwc belong in `modules/applications/`; do not create a separate `desktop/`
module category.
Before adding configuration, decide whether it is owned by an application,
@@ -46,9 +46,9 @@ Prefer the following placements:
| Finder-specific preferences | `modules/applications/finder/darwin.nix` |
| Ghostty-specific configuration | `modules/applications/ghostty/` |
| niri-specific configuration | `modules/applications/niri/` |
| Desktop applications shared by GNOME and niri | `modules/profiles/interface/linux-desktop/meta.nix` |
| Desktop applications shared by labwc and niri | `modules/profiles/interface/linux-desktop/meta.nix` |
| Applications and services specific to niri | `modules/profiles/interface/niri/meta.nix` |
| GNOME itself | `modules/applications/gnome/` |
| labwc and its session configuration | `modules/applications/labwc/` |
| A Linux package plus its macOS Homebrew cask | `modules/applications/<name>/home.nix` and `darwin.nix` |
| Docker daemon and Docker group membership | `modules/services/docker/nixos.nix` |
| The laptop unit composition | `modules/profiles/platform/laptop/meta.nix` |
@@ -138,7 +138,7 @@ modules/applications/ghostty/
└── settings.nix
# NixOS only
modules/applications/gnome/
modules/services/docker/
└── nixos.nix
# nix-darwin only
@@ -316,10 +316,11 @@ the application to work. A profile owns the user's choice to adopt several
otherwise independent applications together. For example, the niri application
includes the Wayland foundation as a technical dependency. The
`profiles.interface.linux-desktop` profile selects Ghostty and Nautilus because
both GNOME and niri use them, while the cross-platform `profiles.interface.gui`
profile selects Vicinae for graphical hosts. `profiles.interface.niri` selects
only the niri-specific shell and services. Ghostty and Vicinae must not depend
on niri, and niri-specific keybindings remain owned by the niri unit.
both labwc and niri use them, while the cross-platform `profiles.interface.gui`
profile selects Vicinae for graphical hosts. The labwc and niri profiles select
their compositor, Noctalia, and the session services they require. Ghostty and
Vicinae must not depend on either compositor, and compositor-specific
keybindings remain owned by the corresponding application unit.
## Profiles
@@ -336,7 +337,7 @@ modules/profiles/
│ ├── gui/
│ ├── macos/
│ ├── linux-desktop/
│ ├── gnome/
│ ├── labwc/
│ └── niri/
├── networking/
│ ├── tailscale-client/
@@ -375,8 +376,8 @@ The profile layers have these responsibilities:
graphical interface applications such as Vicinae. `interface.macos` owns the
macOS Finder, Dock, trackpad, and shared default preferences and includes
`interface.gui`.
`interface.linux-desktop` owns the common GNOME/niri desktop selection,
including Ghostty and Nautilus, and also includes `interface.gui`. GNOME and
`interface.linux-desktop` owns the common labwc/niri desktop selection,
including Ghostty and Nautilus, and also includes `interface.gui`. Labwc and
niri remain independently selectable and do not imply CLI or personal
workloads.
- `platform` describes NixOS foundations and physical or virtual form factors.
@@ -552,7 +553,7 @@ A host registry may use a specification like this:
profiles = [
"base"
"interface.cli"
"interface.gnome"
"interface.labwc"
"interface.niri"
"platform.thinkpad-x1"
"security.fingerprint"
@@ -569,7 +570,7 @@ A host registry may use a specification like this:
profiles = [
"base"
"interface.cli"
"interface.gnome"
"interface.labwc"
"interface.niri"
"networking.tailscale-client"
"platform.thinkpad-x1"
@@ -604,7 +605,7 @@ The current role assignment is intentional: nix-example is the development VM;
ops is the remote-access VM with host-specific static networking;
internal-app-01 is the container server VM; and installer builds the minimal
installation ISO without Home Manager. x1g9 is a full NixOS desktop with niri,
GNOME, ly, the shared Linux desktop applications, and the personal workload.
labwc, ly, the shared Linux desktop applications, and the personal workload.
x1g13 is the secure NixOS development and personal ThinkPad, with the same
desktop sessions plus Tailscale client, SOPS, Secure Boot, and TPM-backed disk
unlock. m2 is the daily-use macOS development and personal machine with the
@@ -709,8 +710,8 @@ When implementing or modifying modules:
- Keep cross-platform profile names semantic. Put Linux package installation in
an application's `home.nix` and the corresponding macOS Homebrew cask in its
`darwin.nix`; do not create a thin `*-linux` profile for that difference.
- Keep shared GNOME/niri selections in `profiles.interface.linux-desktop` and
session-specific applications or services in the respective GNOME or niri
- Keep shared labwc/niri selections in `profiles.interface.linux-desktop` and
session-specific applications or services in the respective labwc or niri
profile.
- Keep `modules/profiles/README.md`, the profile directories, and host profile
selections synchronized whenever any of them changes.
@@ -767,7 +768,7 @@ For profile changes, additionally:
- Preserve the intended host roles: nix-example remains the development VM;
ops remains the statically networked remote-access VM; internal-app-01 remains
the container server VM; installer remains the Home Manager-free installation
ISO; x1g9 provides niri, GNOME, ly, and the personal application set; x1g13
ISO; x1g9 provides niri, labwc, ly, and the personal application set; x1g13
additionally provides the development, Tailscale client, secrets, Secure Boot,
and TPM storage roles; m2 remains the daily-use development and personal
machine.
+2 -2
View File
@@ -61,7 +61,7 @@
profiles = [
"base"
"interface.cli"
"interface.gnome"
"interface.labwc"
"interface.niri"
"platform.thinkpad-x1"
"security.fingerprint"
@@ -79,7 +79,7 @@
profiles = [
"base"
"interface.cli"
"interface.gnome"
"interface.labwc"
"interface.niri"
"networking.tailscale-client"
"platform.thinkpad-x1"
-56
View File
@@ -1,56 +0,0 @@
{ pkgs, lib, ... }:
lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
dconf.settings = {
"org/gnome/desktop/sound" = {
event-sounds = false;
input-feedback-sounds = false;
};
"org/gnome/desktop/wm/keybindings" = {
close = [ "<Super>q" ];
show-desktop = [ ];
};
"org/gnome/settings-daemon/plugins/media-keys" = {
home = [ ];
screensaver = [ "<Super>l" ];
custom-keybindings = [
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom2/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom3/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom4/"
];
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0" = {
name = "Open Terminal";
command = "ghostty";
binding = "<Super>t";
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1" = {
name = "Run Application";
command = "vicinae toggle";
binding = "<Super>d";
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom2" = {
name = "Open File Manager";
command = "nautilus --new-window";
binding = "<Super>e";
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom3" = {
name = "Clipboard History";
command = "vicinae vicinae://extensions/vicinae/clipboard/history";
binding = "<Super>v";
};
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom4" = {
name = "Log Out";
command = "gnome-session-quit --logout --no-prompt";
binding = "<Super><Shift>e";
};
"org/gnome/shell".favorite-apps = [
"google-chrome.desktop"
"code.desktop"
"com.mitchellh.ghostty.desktop"
"slack.desktop"
"vesktop.desktop"
];
};
}
-10
View File
@@ -1,10 +0,0 @@
{ pkgs, lib, ... }:
{
services.desktopManager.gnome.enable = true;
services.displayManager.gdm.enable = lib.mkForce false;
environment.systemPackages = [
pkgs.gnome-tweaks
pkgs.gnome-extension-manager
];
}
+20
View File
@@ -0,0 +1,20 @@
{ lib, pkgs, ... }:
{
xdg.configFile = {
"labwc/rc.xml".source = ./rc.xml;
"labwc/environment".text = ''
XKB_DEFAULT_LAYOUT=jp
XKB_DEFAULT_OPTIONS=ctrl:nocaps
'';
"labwc/autostart".text = ''
# Pull in graphical-session.target so Home Manager services such as
# portals, Vicinae, and the idle manager follow the labwc session.
${lib.getExe' pkgs.systemd "systemctl"} --user --no-block start labwc-session.target
noctalia >/dev/null 2>&1 &
${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1 >/dev/null 2>&1 &
'';
};
}
+5
View File
@@ -0,0 +1,5 @@
{
description = "labwc Wayland stacking compositor";
includes = [ "systems.wayland" ];
}
+20
View File
@@ -0,0 +1,20 @@
{ inputs, pkgs, ... }:
let
unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.stdenv.hostPlatform.system};
in
{
programs.labwc = {
enable = true;
package = unstable.labwc;
};
xdg.portal.config.labwc.default = [
"wlr"
"gtk"
];
environment.systemPackages = [
pkgs.wdisplays
pkgs.wlr-randr
];
}
+125
View File
@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<labwc_config>
<core>
<decoration>server</decoration>
<gap>10</gap>
<autoEnableOutputs>yes</autoEnableOutputs>
<reuseOutputMode>yes</reuseOutputMode>
</core>
<theme>
<name>Dracula</name>
<cornerRadius>8</cornerRadius>
<dropShadows>yes</dropShadows>
<dropShadowsOnTiled>yes</dropShadowsOnTiled>
</theme>
<windowSwitcher preview="no" outlines="yes">
<osd style="thumbnail" />
</windowSwitcher>
<focus>
<followMouse>yes</followMouse>
<followMouseRequiresMovement>yes</followMouseRequiresMovement>
<raiseOnFocus>no</raiseOnFocus>
</focus>
<desktops number="9" popupTime="500" prefix="Workspace" />
<keyboard>
<default />
<keybind key="W-q">
<action name="Close" />
</keybind>
<keybind key="W-t">
<action name="Execute" command="ghostty" />
</keybind>
<keybind key="W-d">
<action name="Execute" command="vicinae toggle" />
</keybind>
<keybind key="W-e">
<action name="Execute" command="nautilus --new-window" />
</keybind>
<keybind key="W-l">
<action name="Execute" command="loginctl lock-session" />
</keybind>
<keybind key="W-v">
<action name="Execute" command="vicinae vicinae://launch/clipboard/history?toggle=true" />
</keybind>
<keybind key="W-space">
<action name="Execute" command="ghostty +toggle-quick-terminal" />
</keybind>
<keybind key="W-p">
<action name="Execute" command="wdisplays" />
</keybind>
<keybind key="W-s">
<action name="Execute" command="noctalia msg panel-toggle control-center" />
</keybind>
<keybind key="W-comma">
<action name="Execute" command="noctalia msg settings-toggle" />
</keybind>
<keybind key="W-S-e">
<action name="Exit" />
</keybind>
<keybind key="W-1"><action name="GoToDesktop" to="1" /></keybind>
<keybind key="W-2"><action name="GoToDesktop" to="2" /></keybind>
<keybind key="W-3"><action name="GoToDesktop" to="3" /></keybind>
<keybind key="W-4"><action name="GoToDesktop" to="4" /></keybind>
<keybind key="W-5"><action name="GoToDesktop" to="5" /></keybind>
<keybind key="W-6"><action name="GoToDesktop" to="6" /></keybind>
<keybind key="W-7"><action name="GoToDesktop" to="7" /></keybind>
<keybind key="W-8"><action name="GoToDesktop" to="8" /></keybind>
<keybind key="W-9"><action name="GoToDesktop" to="9" /></keybind>
<keybind key="W-C-1"><action name="SendToDesktop" to="1" /></keybind>
<keybind key="W-C-2"><action name="SendToDesktop" to="2" /></keybind>
<keybind key="W-C-3"><action name="SendToDesktop" to="3" /></keybind>
<keybind key="W-C-4"><action name="SendToDesktop" to="4" /></keybind>
<keybind key="W-C-5"><action name="SendToDesktop" to="5" /></keybind>
<keybind key="W-C-6"><action name="SendToDesktop" to="6" /></keybind>
<keybind key="W-C-7"><action name="SendToDesktop" to="7" /></keybind>
<keybind key="W-C-8"><action name="SendToDesktop" to="8" /></keybind>
<keybind key="W-C-9"><action name="SendToDesktop" to="9" /></keybind>
<keybind key="XF86AudioRaiseVolume">
<action name="Execute" command="noctalia msg volume-up" />
</keybind>
<keybind key="XF86AudioLowerVolume">
<action name="Execute" command="noctalia msg volume-down" />
</keybind>
<keybind key="XF86AudioMute">
<action name="Execute" command="noctalia msg volume-mute" />
</keybind>
<keybind key="XF86AudioMicMute">
<action name="Execute" command="noctalia msg mic-mute" />
</keybind>
<keybind key="XF86MonBrightnessUp">
<action name="Execute" command="noctalia msg brightness-up" />
</keybind>
<keybind key="XF86MonBrightnessDown">
<action name="Execute" command="noctalia msg brightness-down" />
</keybind>
</keyboard>
<mouse>
<default />
</mouse>
<libinput>
<device category="touchpad">
<naturalScroll>yes</naturalScroll>
<tap>yes</tap>
<tapAndDrag>yes</tapAndDrag>
<dragLock>yes</dragLock>
<clickMethod>clickfinger</clickMethod>
<scrollMethod>twoFinger</scrollMethod>
<scrollFactor>4.0</scrollFactor>
</device>
<device category="non-touch">
<pointerSpeed>-0.1</pointerSpeed>
<accelProfile>flat</accelProfile>
</device>
</libinput>
</labwc_config>
+4 -4
View File
@@ -27,7 +27,7 @@ when removing it from any supported host would make that host invalid.
| `interface.gui` | NixOS, macOS with Home Manager |
| `interface.macos` | macOS |
| `interface.linux-desktop` | NixOS with Home Manager |
| `interface.gnome` | NixOS with Home Manager |
| `interface.labwc` | NixOS with Home Manager |
| `interface.niri` | NixOS with Home Manager |
| `platform.nixos` | NixOS |
| `platform.desktop` | Physical NixOS desktop |
@@ -47,9 +47,9 @@ when removing it from any supported host would make that host invalid.
| `security.tpm-storage` | NixOS with a host-defined LUKS device |
Select independent concerns independently in `hosts/default.nix`. For example,
a NixOS desktop can combine `interface.gnome` and `interface.niri` to provide
both sessions while sharing `interface.linux-desktop` and `interface.gui`; niri
supplies ly. A
a NixOS desktop can combine `interface.labwc` and `interface.niri` to provide
both sessions while sharing `interface.linux-desktop` and `interface.gui`; both
session profiles select ly. A
daily-use macOS development machine can combine `interface.macos`,
`workload.development`, and `workload.personal`. Hardware support does not
implicitly select an interface or workload.
@@ -1,8 +0,0 @@
{
description = "GNOME desktop session for NixOS";
includes = [
"profiles.interface.linux-desktop"
"applications.gnome"
];
}
+12
View File
@@ -0,0 +1,12 @@
{
description = "labwc desktop session for NixOS";
includes = [
"profiles.interface.linux-desktop"
"applications.labwc"
"applications.noctalia"
"services.ly"
"services.swayidle"
"services.swaylock"
];
}
@@ -0,0 +1,9 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
alacritty
grim
slurp
wf-recorder
];
}
+2 -2
View File
@@ -1,9 +1,9 @@
{ lib, pkgs, ... }:
let
brightnessctl = lib.getExe pkgs.brightnessctl;
niri = lib.getExe pkgs.niri;
rm = "${pkgs.coreutils}/bin/rm";
systemctl = lib.getExe' pkgs.systemd "systemctl";
wlopm = lib.getExe pkgs.wlopm;
brightnessState = "$XDG_RUNTIME_DIR/swayidle-brightness";
skipIfOnAC = ''
@@ -37,7 +37,7 @@ let
'';
afterResume = pkgs.writeShellScript "swayidle-after-resume" ''
${niri} msg action power-on-monitors
${wlopm} --on '*'
${restoreBrightness}
'';
in
+1 -3
View File
@@ -1,5 +1,3 @@
{
description = "swayidle idle management for Niri";
includes = [ "applications.niri" ];
description = "swayidle idle management for Wayland sessions";
}