feat: space switches region mode to window mode

This commit is contained in:
elwrcl committed 2026-10-02 16:20:11 +03:00
1 parent 5034cdc54f
commit d362ee060c
4 files changed
+49 -10

No files matched your search

+8 -1
View File
@@ -172,10 +172,17 @@ fn capture(mode: Mode, common: Common) -> Result<()> {
} }
Mode::Region => { Mode::Region => {
let frames = wl.capture(&outputs, cursor)?; let frames = wl.capture(&outputs, cursor)?;
let (i, r) = region::select(&mut wl, &outputs, &frames)?; match region::select(&mut wl, &outputs, &frames)? {
region::Choice::Region(i, r) => {
let source = frames[i].output.name.clone(); let source = frames[i].output.name.clone();
(vec![(frames[i].to_rgba(r), None)], 0, source) (vec![(frames[i].to_rgba(r), None)], 0, source)
} }
region::Choice::Window => {
drop(frames);
window_shot(&outputs, cursor)?
}
}
}
Mode::Window => window_shot(&outputs, cursor)?, Mode::Window => window_shot(&outputs, cursor)?,
}; };
drop(wl); drop(wl);
+19 -5
View File
@@ -30,8 +30,14 @@ use crate::wayland::{Output, State, Wayland};
pub const NAMESPACE: &str = "valw-overlay"; pub const NAMESPACE: &str = "valw-overlay";
/// What the user picked: an output index and a rectangle in its frame. /// What the user chose in the overlay.
pub type Picked = (usize, PixelRect); #[derive(Debug, PartialEq)]
pub enum Choice {
/// A rectangle in the frame of output `.0`.
Region(usize, PixelRect),
/// Space before dragging: capture a window instead.
Window,
}
/// One full-screen layer surface per output, showing the frozen frame. /// One full-screen layer surface per output, showing the frozen frame.
pub struct Overlay { pub struct Overlay {
@@ -39,7 +45,7 @@ pub struct Overlay {
selection: Selection, selection: Selection,
/// Output where the current drag started; the capture is clipped to it. /// Output where the current drag started; the capture is clipped to it.
anchor: Option<usize>, anchor: Option<usize>,
outcome: Option<Option<Picked>>, outcome: Option<Option<Choice>>,
} }
struct Surface { struct Surface {
@@ -59,7 +65,8 @@ struct Surface {
/// Shows the overlay on every output and waits for a selection. /// Shows the overlay on every output and waits for a selection.
/// Returns `Cancelled` if the user presses Esc or right-clicks. /// Returns `Cancelled` if the user presses Esc or right-clicks.
pub fn select(wl: &mut Wayland, outputs: &[Output], frames: &[Frame]) -> Result<Picked> { /// Space before dragging returns `Choice::Window`.
pub fn select(wl: &mut Wayland, outputs: &[Output], frames: &[Frame]) -> Result<Choice> {
let qh = wl.queue.handle(); let qh = wl.queue.handle();
let s = &wl.state; let s = &wl.state;
let layer_shell = s let layer_shell = s
@@ -162,6 +169,13 @@ impl Overlay {
self.outcome.get_or_insert(None); self.outcome.get_or_insert(None);
} }
pub fn switch_to_window(&mut self) {
if self.selection.allows_window_switch() {
tracing::info!("switching to window mode");
self.outcome.get_or_insert(Some(Choice::Window));
}
}
fn index_of(&self, surface: &WlSurface) -> Option<usize> { fn index_of(&self, surface: &WlSurface) -> Option<usize> {
self.surfaces self.surfaces
.iter() .iter()
@@ -266,7 +280,7 @@ impl Overlay {
"selected {rect:?} on {} (logical {start:?} to {end:?})", "selected {rect:?} on {} (logical {start:?} to {end:?})",
s.geom.name s.geom.name
); );
self.outcome = Some(Some((a, rect))); self.outcome = Some(Some(Choice::Region(a, rect)));
} }
// A click, not a drag: clear it and keep waiting. // A click, not a drag: clear it and keep waiting.
None => self.redraw(a, qh), None => self.redraw(a, qh),
+15
View File
@@ -38,6 +38,11 @@ impl Selection {
Selection::Idle => None, Selection::Idle => None,
} }
} }
/// Space switches to window mode only before a drag starts.
pub fn allows_window_switch(&self) -> bool {
*self == Selection::Idle
}
} }
/// The part of the drag from `a` to `b` that falls on `out`, in the physical /// The part of the drag from `a` to `b` that falls on `out`, in the physical
@@ -77,6 +82,16 @@ pub fn resolve(
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn window_switch_only_before_a_drag() {
let mut s = Selection::default();
assert!(s.allows_window_switch());
s.press(Point { x: 1.0, y: 1.0 });
assert!(!s.allows_window_switch(), "Space during a drag is reserved");
s.release(Point { x: 5.0, y: 5.0 });
assert!(s.allows_window_switch());
}
fn out(name: &str, x: i32, y: i32, width: i32, height: i32) -> OutputGeom { fn out(name: &str, x: i32, y: i32, width: i32, height: i32) -> OutputGeom {
OutputGeom { OutputGeom {
name: name.into(), name: name.into(),
+7 -4
View File
@@ -449,10 +449,13 @@ impl KeyboardHandler for State {
_: u32, _: u32,
event: KeyEvent, event: KeyEvent,
) { ) {
if event.keysym == Keysym::Escape let Some(overlay) = &mut self.overlay else {
&& let Some(overlay) = &mut self.overlay return;
{ };
overlay.cancel(); match event.keysym {
Keysym::Escape => overlay.cancel(),
Keysym::space => overlay.switch_to_window(),
_ => {}
} }
} }