From 3f268fb2564919d30926d132211c8bdc30417be2 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Thu, 23 Jan 2025 11:50:43 +0300 Subject: [PATCH 1/2] Add find_root_shell_surface() that goes through popups --- src/handlers/mod.rs | 13 ++++++------- src/niri.rs | 20 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 9ffe5babc..8c1374d3e 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -343,13 +343,12 @@ impl ClientDndGrabHandler for State { // example. On successful drop, additionally activate the target window. let mut activate_output = true; if let Some(target) = validated.then_some(target).flatten() { - if let Some(root) = self.niri.root_surface.get(&target) { - if let Some((mapped, _)) = self.niri.layout.find_window_and_output(root) { - let window = mapped.window.clone(); - self.niri.layout.activate_window(&window); - self.niri.layer_shell_on_demand_focus = None; - activate_output = false; - } + let root = self.niri.find_root_shell_surface(&target); + if let Some((mapped, _)) = self.niri.layout.find_window_and_output(&root) { + let window = mapped.window.clone(); + self.niri.layout.activate_window(&window); + self.niri.layer_shell_on_demand_focus = None; + activate_output = false; } } diff --git a/src/niri.rs b/src/niri.rs index 687f85393..dbbc9ff26 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -41,8 +41,8 @@ use smithay::desktop::utils::{ under_from_surface_tree, update_surface_primary_scanout_output, OutputPresentationFeedback, }; use smithay::desktop::{ - layer_map_for_output, LayerMap, LayerSurface, PopupGrab, PopupManager, PopupUngrabStrategy, - Space, Window, WindowSurfaceType, + find_popup_root_surface, layer_map_for_output, LayerMap, LayerSurface, PopupGrab, PopupManager, + PopupUngrabStrategy, Space, Window, WindowSurfaceType, }; use smithay::input::keyboard::Layout as KeyboardLayout; use smithay::input::pointer::{CursorIcon, CursorImageAttributes, CursorImageStatus, MotionEvent}; @@ -4907,6 +4907,22 @@ impl Niri { } } + /// Tries to find and return the root shell surface for a given surface. + /// + /// I.e. for popups, this function will try to find the parent toplevel or layer surface. For + /// regular subsurfaces, it will find the root surface. + pub fn find_root_shell_surface(&self, surface: &WlSurface) -> WlSurface { + let Some(root) = self.root_surface.get(surface) else { + return surface.clone(); + }; + + if let Some(popup) = self.popups.find_popup(root) { + return find_popup_root_surface(&popup).unwrap_or_else(|_| root.clone()); + } + + root.clone() + } + #[cfg(feature = "dbus")] pub fn on_ipc_outputs_changed(&self) { let _span = tracy_client::span!("Niri::on_ipc_outputs_changed"); From 4e398dd772f8f6d189866e7a8658f7f3b2cefef9 Mon Sep 17 00:00:00 2001 From: bbb651 Date: Mon, 20 Jan 2025 22:52:43 +0200 Subject: [PATCH 2/2] Add `scroll-factor` window rule --- niri-config/src/lib.rs | 2 ++ src/input/mod.rs | 15 +++++++++++---- src/window/mod.rs | 7 +++++++ wiki/Configuration:-Window-Rules.md | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 2fd3d45c0..11da976ed 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -1079,6 +1079,8 @@ pub struct WindowRule { pub variable_refresh_rate: Option, #[knuffel(child)] pub default_floating_position: Option, + #[knuffel(child, unwrap(argument))] + pub scroll_factor: Option>, } #[derive(knuffel::Decode, Debug, Default, Clone, PartialEq)] diff --git a/src/input/mod.rs b/src/input/mod.rs index c9ab0b307..12746376b 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -2086,6 +2086,8 @@ impl State { } fn on_pointer_axis(&mut self, event: I::PointerAxisEvent) { + let pointer = &self.niri.seat.get_pointer().unwrap(); + let source = event.source(); // We received an event for the regular pointer, so show it now. This is also needed for @@ -2232,12 +2234,20 @@ impl State { } } + self.update_pointer_contents(); + let scroll_factor = match source { AxisSource::Wheel => self.niri.config.borrow().input.mouse.scroll_factor, AxisSource::Finger => self.niri.config.borrow().input.touchpad.scroll_factor, _ => None, }; - let scroll_factor = scroll_factor.map(|x| x.0).unwrap_or(1.); + let window_scroll_factor = pointer + .current_focus() + .map(|focused| self.niri.find_root_shell_surface(&focused)) + .and_then(|root| self.niri.layout.find_window_and_output(&root).unzip().0) + .and_then(|window| window.rules().scroll_factor); + let scroll_factor = + scroll_factor.map(|x| x.0).unwrap_or(1.) * window_scroll_factor.unwrap_or(1.); let horizontal_amount = horizontal_amount.unwrap_or_else(|| { // Winit backend, discrete scrolling. @@ -2278,9 +2288,6 @@ impl State { } } - self.update_pointer_contents(); - - let pointer = &self.niri.seat.get_pointer().unwrap(); pointer.axis(self, frame); pointer.frame(self); } diff --git a/src/window/mod.rs b/src/window/mod.rs index 189049b34..84c33d5ea 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -100,6 +100,9 @@ pub struct ResolvedWindowRules { /// Whether to enable VRR on this window's primary output if it is on-demand. pub variable_refresh_rate: Option, + + /// Multiplier for all scroll events sent to this window. + pub scroll_factor: Option, } impl<'a> WindowRef<'a> { @@ -190,6 +193,7 @@ impl ResolvedWindowRules { clip_to_geometry: None, block_out_from: None, variable_refresh_rate: None, + scroll_factor: None, } } @@ -301,6 +305,9 @@ impl ResolvedWindowRules { if let Some(x) = rule.variable_refresh_rate { resolved.variable_refresh_rate = Some(x); } + if let Some(x) = rule.scroll_factor { + resolved.scroll_factor = Some(x.0); + } } resolved.open_on_output = open_on_output.map(|x| x.to_owned()); diff --git a/wiki/Configuration:-Window-Rules.md b/wiki/Configuration:-Window-Rules.md index cd0a65b22..5fa44021f 100644 --- a/wiki/Configuration:-Window-Rules.md +++ b/wiki/Configuration:-Window-Rules.md @@ -53,6 +53,7 @@ window-rule { // block-out-from "screen-capture" variable-refresh-rate true default-floating-position x=100 y=200 relative-to="bottom-left" + scroll-factor 0.75 focus-ring { // off @@ -557,6 +558,23 @@ window-rule { } ``` +#### `scroll-factor` + +Since: next release + +Set a scroll factor for all scroll events sent to a window. + +This will be multiplied with the scroll factor set for your input device in the [input](/wiki/Configuration:-Input.md) section. + +```kdl +// Make scrolling in Firefox a bit slower. +window-rule { + match app-id="firefox$" + + scroll-factor 0.75 +} +``` + #### `draw-border-with-background` Override whether the border and the focus ring draw with a background.