sway: add bindswitches option (#7095)

Adds the bindswitches option to the sway module.

Bindswitches allows you to run a sway command when a state changes (when a certain event occurs).
See https://github.com/swaywm/sway/wiki#clamshell-mode and sway(5) for more information

It was already possible to configure this through sway.extraConfig but I find this approach dirty as described by the Nix RFC 42, and there is currently no settings as it describes.
This commit is contained in:
Eldolfin
2025-05-26 04:46:49 +02:00
committed by GitHub
parent a45222c731
commit d23d20f55d
4 changed files with 230 additions and 2 deletions

View File

@@ -162,6 +162,36 @@ let
'';
};
bindswitches = mkOption {
type = types.attrsOf bindswitchOption;
default = { };
defaultText = "No bindswitches by default";
description = ''
Binds <switch> to execute the sway command command on state changes. Supported switches are lid (laptop
lid) and tablet (tablet mode) switches. Valid values for state are on, off and toggle. These switches are
on when the device lid is shut and when tablet mode is active respectively. toggle is also supported to run
a command both when the switch is toggled on or off.
See sway(5).
'';
example = lib.literalExpression ''
let
laptop = "eDP-1";
in
{
"lid:on" = {
reload = true;
locked = true;
action = "output ''${laptop} disable";
};
"lid:off" = {
reload = true;
locked = true;
action = "output ''${laptop} enable";
};
}
'';
};
bindkeysToCode = mkOption {
type = types.bool;
default = false;
@@ -267,6 +297,42 @@ let
};
};
bindswitchOption = types.submodule {
options = {
action = mkOption {
type = types.str;
description = "The sway command to execute on state changes";
};
locked = mkOption {
type = types.bool;
default = false;
description = ''
Unless the flag --locked is set, the command
will not be run when a screen locking program
is active. If there is a matching binding with
and without --locked, the one with will be preferred
when locked and the one without will be
preferred when unlocked.
'';
};
reload = mkOption {
type = types.bool;
default = false;
description = ''
If the --reload flag is given, the binding will
also be executed when the config is reloaded.
toggle bindings will not be executed on reload.
The --locked flag will operate as normal so if
the config is reloaded while locked and
--locked is not given, the binding will not be
executed.
'';
};
};
};
commonFunctions = import ./lib/functions.nix {
inherit config cfg lib;
moduleName = "sway";
@@ -290,11 +356,32 @@ let
;
startupEntryStr =
{ command, always, ... }:
{
command,
always,
...
}:
''
${if always then "exec_always" else "exec"} ${command}
'';
bindswitchesStr =
bindswitches:
concatStringsSep "\n" (
mapAttrsToList (
event:
{
locked,
reload,
action,
}:
let
args = (lib.optionalString locked "--locked ") + (lib.optionalString reload "--reload ");
in
"bindswitch ${args} ${event} ${action}"
) bindswitches
);
moduleStr = moduleType: name: attrs: ''
${moduleType} "${name}" {
${concatStringsSep "\n" (lib.mapAttrsToList (name: value: " ${name} ${value}") attrs)}
@@ -358,6 +445,7 @@ let
})
(keycodebindingsStr keycodebindings)
]
++ optional (builtins.attrNames bindswitches != [ ]) (bindswitchesStr bindswitches)
++ mapAttrsToList inputStr input
++ mapAttrsToList outputStr output # outputs
++ mapAttrsToList seatStr seat # seats
@@ -378,7 +466,6 @@ let
++ [ cfg.extraConfig ]
);
};
in
{
meta.maintainers = with lib.maintainers; [

View File

@@ -1,6 +1,7 @@
{
sway-bar-focused-colors = ./sway-bar-focused-colors.nix;
sway-bindkeys-to-code-and-extra-config = ./sway-bindkeys-to-code-and-extra-config.nix;
sway-bindswitches = ./sway-bindswitches.nix;
sway-default = ./sway-default.nix;
sway-followmouse = ./sway-followmouse.nix;
sway-followmouse-legacy = ./sway-followmouse-legacy.nix;

View File

@@ -0,0 +1,110 @@
font pango:monospace 8.000000
floating_modifier Mod1
default_border pixel 2
default_floating_border pixel 2
hide_edge_borders none
focus_wrapping no
focus_follows_mouse yes
focus_on_window_activation smart
mouse_warping output
workspace_layout default
workspace_auto_back_and_forth no
client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577
client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a
client.unfocused #333333 #222222 #888888 #292d2e #222222
client.urgent #2f343a #900000 #ffffff #900000 #900000
client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c
client.background #ffffff
bindsym Mod1+0 workspace number 10
bindsym Mod1+1 workspace number 1
bindsym Mod1+2 workspace number 2
bindsym Mod1+3 workspace number 3
bindsym Mod1+4 workspace number 4
bindsym Mod1+5 workspace number 5
bindsym Mod1+6 workspace number 6
bindsym Mod1+7 workspace number 7
bindsym Mod1+8 workspace number 8
bindsym Mod1+9 workspace number 9
bindsym Mod1+Down focus down
bindsym Mod1+Left focus left
bindsym Mod1+Return exec @foot@/bin/foot
bindsym Mod1+Right focus right
bindsym Mod1+Shift+0 move container to workspace number 10
bindsym Mod1+Shift+1 move container to workspace number 1
bindsym Mod1+Shift+2 move container to workspace number 2
bindsym Mod1+Shift+3 move container to workspace number 3
bindsym Mod1+Shift+4 move container to workspace number 4
bindsym Mod1+Shift+5 move container to workspace number 5
bindsym Mod1+Shift+6 move container to workspace number 6
bindsym Mod1+Shift+7 move container to workspace number 7
bindsym Mod1+Shift+8 move container to workspace number 8
bindsym Mod1+Shift+9 move container to workspace number 9
bindsym Mod1+Shift+Down move down
bindsym Mod1+Shift+Left move left
bindsym Mod1+Shift+Right move right
bindsym Mod1+Shift+Up move up
bindsym Mod1+Shift+c reload
bindsym Mod1+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
bindsym Mod1+Shift+h move left
bindsym Mod1+Shift+j move down
bindsym Mod1+Shift+k move up
bindsym Mod1+Shift+l move right
bindsym Mod1+Shift+minus move scratchpad
bindsym Mod1+Shift+q kill
bindsym Mod1+Shift+space floating toggle
bindsym Mod1+Up focus up
bindsym Mod1+a focus parent
bindsym Mod1+b splith
bindsym Mod1+d exec @dmenu@/bin/dmenu_run
bindsym Mod1+e layout toggle split
bindsym Mod1+f fullscreen toggle
bindsym Mod1+h focus left
bindsym Mod1+j focus down
bindsym Mod1+k focus up
bindsym Mod1+l focus right
bindsym Mod1+minus scratchpad show
bindsym Mod1+r mode resize
bindsym Mod1+s layout stacking
bindsym Mod1+space focus mode_toggle
bindsym Mod1+v splitv
bindsym Mod1+w layout tabbed
bindswitch lid:on exec echo "Lid moved"
bindswitch --locked --reload tablet:on exec echo "Lid moved"
mode "resize" {
bindsym Down resize grow height 10 px
bindsym Escape mode default
bindsym Left resize shrink width 10 px
bindsym Return mode default
bindsym Right resize grow width 10 px
bindsym Up resize shrink height 10 px
bindsym h resize shrink width 10 px
bindsym j resize grow height 10 px
bindsym k resize shrink height 10 px
bindsym l resize grow width 10 px
}
bar {
font pango:monospace 8.000000
mode dock
hidden_state hide
position bottom
status_command @i3status@/bin/i3status
swaybar_command @sway@/bin/swaybar
workspace_buttons yes
strip_workspace_numbers no
tray_output *
colors {
background #000000
statusline #ffffff
separator #666666
focused_workspace #4c7899 #285577 #ffffff
active_workspace #333333 #5f676a #ffffff
inactive_workspace #333333 #222222 #888888
urgent_workspace #2f343a #900000 #ffffff
binding_mode #2f343a #900000 #ffffff
}
}
exec "@dbus@/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_TYPE NIXOS_OZONE_WL XCURSOR_THEME XCURSOR_SIZE; systemctl --user reset-failed && systemctl --user start sway-session.target && swaymsg -mt subscribe '[]' || true && systemctl --user stop sway-session.target"

View File

@@ -0,0 +1,30 @@
{ config, pkgs, ... }:
{
home.enableNixpkgsReleaseCheck = false;
wayland.windowManager.sway = {
enable = true;
package = config.lib.test.mkStubPackage { outPath = "@sway@"; };
checkConfig = false;
# overriding findutils causes issues
config.menu = "${pkgs.dmenu}/bin/dmenu_run";
config = {
bindswitches = {
"lid:on" = {
action = ''exec echo "Lid moved"'';
};
"tablet:on" = {
action = ''exec echo "Lid moved"'';
reload = true;
locked = true;
};
};
};
};
nmt.script = ''
assertFileExists home-files/.config/sway/config
assertFileContent home-files/.config/sway/config \
${./sway-bindswitches.conf}
'';
}