diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/handlers/xdg_shell.rs | 39 | ||||
| -rw-r--r-- | src/input.rs | 47 | ||||
| -rw-r--r-- | src/window/mapped.rs | 14 |
3 files changed, 84 insertions, 16 deletions
diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index afd0bab9..4be323af 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -7,7 +7,7 @@ use smithay::input::pointer::Focus; use smithay::output::Output; use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_positioner::ConstraintAdjustment; -use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge}; +use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::{self}; use smithay::reexports::wayland_server::protocol::wl_output; use smithay::reexports::wayland_server::protocol::wl_seat::WlSeat; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; @@ -30,9 +30,11 @@ use smithay::{ delegate_kde_decoration, delegate_xdg_decoration, delegate_xdg_foreign, delegate_xdg_shell, }; +use crate::input::DOUBLE_CLICK_TIME; use crate::layout::workspace::ColumnWidth; use crate::niri::{PopupGrabState, State}; use crate::resize_grab::ResizeGrab; +use crate::utils::{get_monotonic_time, ResizeEdge}; use crate::window::{InitialConfigureState, ResolvedWindowRules, Unmapped, WindowRef}; impl XdgShellHandler for State { @@ -65,7 +67,7 @@ impl XdgShellHandler for State { surface: ToplevelSurface, _seat: WlSeat, serial: Serial, - edges: ResizeEdge, + edges: xdg_toplevel::ResizeEdge, ) { let pointer = self.niri.seat.get_pointer().unwrap(); if !pointer.has_grab(serial) { @@ -89,16 +91,37 @@ impl XdgShellHandler for State { return; }; + let edges = ResizeEdge::from(edges); let window = mapped.window.clone(); - if !self - .niri - .layout - .interactive_resize_begin(window.clone(), edges.into()) - { + + // See if we got a double resize-click gesture. + let time = get_monotonic_time(); + let last_cell = mapped.last_interactive_resize_start(); + let last = last_cell.get(); + last_cell.set(Some((time, edges))); + if let Some((last_time, last_edges)) = last { + if time.saturating_sub(last_time) <= DOUBLE_CLICK_TIME { + let intersection = edges.intersection(last_edges); + if intersection.intersects(ResizeEdge::LEFT_RIGHT) { + // FIXME: don't activate once we can pass specific windows to actions. + self.niri.layout.activate_window(&window); + self.niri.layout.toggle_full_width(); + } + if intersection.intersects(ResizeEdge::TOP_BOTTOM) { + // FIXME: don't activate once we can pass specific windows to actions. + self.niri.layout.activate_window(&window); + self.niri.layout.reset_window_height(); + } + return; + } + } + + let grab = ResizeGrab::new(start_data, window.clone()); + + if !self.niri.layout.interactive_resize_begin(window, edges) { return; } - let grab = ResizeGrab::new(start_data, window); pointer.set_grab(self, grab, serial, Focus::Clear); self.niri.interactive_resize_ongoing = true; } diff --git a/src/input.rs b/src/input.rs index 208d48f0..cacbaaca 100644 --- a/src/input.rs +++ b/src/input.rs @@ -31,7 +31,9 @@ use crate::niri::State; use crate::resize_grab::ResizeGrab; use crate::ui::screenshot_ui::ScreenshotUi; use crate::utils::spawning::spawn; -use crate::utils::{center, get_monotonic_time}; +use crate::utils::{center, get_monotonic_time, ResizeEdge}; + +pub const DOUBLE_CLICK_TIME: Duration = Duration::from_millis(400); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CompositorMod { @@ -1076,7 +1078,6 @@ impl State { if ButtonState::Pressed == button_state { if let Some(mapped) = self.niri.window_under_cursor() { let window = mapped.window.clone(); - self.niri.layout.activate_window(&window); // Check if we need to start an interactive resize. if event.button() == Some(MouseButton::Right) && !pointer.is_grabbed() { @@ -1093,23 +1094,55 @@ impl State { .layout .resize_edges_under(output, pos_within_output) .unwrap(); - if self - .niri - .layout - .interactive_resize_begin(window.clone(), edges) + + // See if we got a double resize-click gesture. + // FIXME: deduplicate with resize_request in xdg-shell somehow. + let time = get_monotonic_time(); + let last_cell = mapped.last_interactive_resize_start(); + let last = last_cell.get(); + last_cell.set(Some((time, edges))); + let mut did_gesture = false; + if let Some((last_time, last_edges)) = last { + if time.saturating_sub(last_time) <= DOUBLE_CLICK_TIME { + let intersection = edges.intersection(last_edges); + if intersection.intersects(ResizeEdge::LEFT_RIGHT) { + // FIXME: don't activate once we can pass specific windows to + // actions. + self.niri.layout.activate_window(&window); + self.niri.layout.toggle_full_width(); + } + if intersection.intersects(ResizeEdge::TOP_BOTTOM) { + // FIXME: don't activate once we can pass specific windows to + // actions. + self.niri.layout.activate_window(&window); + self.niri.layout.reset_window_height(); + } + did_gesture = true; + } + } + + self.niri.layout.activate_window(&window); + + if !did_gesture + && self + .niri + .layout + .interactive_resize_begin(window.clone(), edges) { let start_data = PointerGrabStartData { focus: None, button: event.button_code(), location, }; - let grab = ResizeGrab::new(start_data, window); + let grab = ResizeGrab::new(start_data, window.clone()); pointer.set_grab(self, grab, serial, Focus::Clear); self.niri.interactive_resize_ongoing = true; } } } + self.niri.layout.activate_window(&window); + // FIXME: granular. self.niri.queue_redraw_all(); } else if let Some(output) = self.niri.output_under_cursor() { diff --git a/src/window/mapped.rs b/src/window/mapped.rs index 952a2bf3..4b31da22 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -1,5 +1,6 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::cmp::{max, min}; +use std::time::Duration; use niri_config::WindowRule; use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; @@ -27,6 +28,7 @@ use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::snapshot::RenderSnapshot; use crate::render_helpers::surface::render_snapshot_from_surface_tree; use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements}; +use crate::utils::ResizeEdge; #[derive(Debug)] pub struct Mapped { @@ -61,6 +63,11 @@ pub struct Mapped { /// State of an ongoing interactive resize. interactive_resize: Option<InteractiveResize>, + + /// Last time interactive resize was started. + /// + /// Used for double-resize-click tracking. + last_interactive_resize_start: Cell<Option<(Duration, ResizeEdge)>>, } /// Interactive resize state. @@ -100,6 +107,7 @@ impl Mapped { animate_serials: Vec::new(), animation_snapshot: None, interactive_resize: None, + last_interactive_resize_start: Cell::new(None), } } @@ -199,6 +207,10 @@ impl Mapped { pub fn store_animation_snapshot(&mut self, renderer: &mut GlesRenderer) { self.animation_snapshot = Some(self.render_snapshot(renderer)); } + + pub fn last_interactive_resize_start(&self) -> &Cell<Option<(Duration, ResizeEdge)>> { + &self.last_interactive_resize_start + } } impl Drop for Mapped { |
