diff --git a/modules/applications/niri/home.nix b/modules/applications/niri/home.nix index 96f5e7f..d595206 100644 --- a/modules/applications/niri/home.nix +++ b/modules/applications/niri/home.nix @@ -185,9 +185,38 @@ in default-window-height.fixed = 920; } { - # Keep Zoom Workplace and meeting windows tiled, but let meeting - # controls, screen-share toolbars, and other auxiliary Zoom windows be - # positioned freely. + # Zoom presents these two fixed-size primary windows. Explicitly keep + # them tiled, overriding Niri's automatic fixed-size-window floating. + matches = [ + { + app-id = "^(?i:zoom)$"; + title = "^(?i:zoom workplace)$"; + } + { + app-id = "^(?i:zoom)$"; + title = "^ミーティング$"; + } + ]; + open-floating = false; + } + { + # Zoom's screen-share controls are a toolbar, so open them where the + # client expects them rather than in the middle of the workspace. + matches = [ + { + app-id = "^(?i:zoom)$"; + title = "^as_toolbar$"; + } + ]; + open-floating = true; + default-floating-position = { + x = 0; + y = 8; + relative-to = "top"; + }; + } + { + # Keep all other Zoom auxiliary windows freely positionable. matches = [ { app-id = "^(?i:zoom)$"; } ]; excludes = [ { title = "^(?i:zoom workplace)$"; } diff --git a/modules/applications/niri/nixos.nix b/modules/applications/niri/nixos.nix index d0c854c..0be33a4 100644 --- a/modules/applications/niri/nixos.nix +++ b/modules/applications/niri/nixos.nix @@ -1,4 +1,9 @@ { config, pkgs, ... }: +let + wdisplays = pkgs.wdisplays.overrideAttrs (oldAttrs: { + patches = (oldAttrs.patches or [ ]) ++ [ ./wdisplays-canonical-scale.patch ]; + }); +in { programs.niri.enable = true; @@ -6,8 +11,10 @@ # user units with NixOS. Without this, Ly cannot start niri-session. systemd.packages = [ config.programs.niri.package ]; - environment.systemPackages = with pkgs; [ - wdisplays # Wayland display configuration GUI - wlr-randr # Wayland output management CLI + environment.systemPackages = [ + # Keep the transient Wayland-native GUI, with fractional scales rounded to + # the same wl_fixed_t value that niri receives on the first Apply. + wdisplays + pkgs.wlr-randr # Wayland output management CLI ]; } diff --git a/modules/applications/niri/wdisplays-canonical-scale.patch b/modules/applications/niri/wdisplays-canonical-scale.patch new file mode 100644 index 0000000..3a99d3b --- /dev/null +++ b/modules/applications/niri/wdisplays-canonical-scale.patch @@ -0,0 +1,22 @@ +diff --git a/src/headform.c b/src/headform.c +--- a/src/headform.c ++++ b/src/headform.c +@@ -39,1 +39,8 @@ ++/* The output-management protocol transmits scale as a Wayland 24.8 fixed ++ * point value. Use that same value for preview geometry so a fractional scale ++ * cannot change underneath positions during the first apply. */ ++static double canonicalize_scale(double scale) { ++ return wl_fixed_to_double(wl_fixed_from_double(scale)); ++} ++ + static void head_form_update_sensitivity(WdHeadForm *form) { +@@ -359,2 +366,3 @@ void wd_head_form_fill_config(WdHeadForm *form, struct wd_head_config *output) { +- output->scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->scale)); ++ output->scale = canonicalize_scale( ++ gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->scale))); + output->x = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->pos_x)); +@@ -385,2 +393,3 @@ void wd_head_form_get_dimensions(WdHeadForm *form, WdHeadDimensions *dimensions) +- dimensions->scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->scale)); ++ dimensions->scale = canonicalize_scale( ++ gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->scale))); + dimensions->rotation_id = g_variant_get_int32(g_action_get_state(priv->rotate_action)) / 90;