diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2023-08-13 12:46:53 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-08-13 12:46:53 +0400 |
| commit | 95c810c855a27a28f4dfa7dc6b949fef0901c7b2 (patch) | |
| tree | c240dd8d8c6eac7cd18c507fbe35724ca7de8aeb /src | |
| parent | e02e35f9c61e103a01640d3dc95a894e8855e1c9 (diff) | |
| download | niri-95c810c855a27a28f4dfa7dc6b949fef0901c7b2.tar.gz niri-95c810c855a27a28f4dfa7dc6b949fef0901c7b2.tar.bz2 niri-95c810c855a27a28f4dfa7dc6b949fef0901c7b2.zip | |
Refactor everything, add initial tiling code
Diffstat (limited to 'src')
| -rw-r--r-- | src/backend.rs | 2 | ||||
| -rw-r--r-- | src/grabs/move_grab.rs | 12 | ||||
| -rw-r--r-- | src/grabs/resize_grab.rs | 82 | ||||
| -rw-r--r-- | src/handlers/compositor.rs | 103 | ||||
| -rw-r--r-- | src/handlers/xdg_shell.rs | 187 | ||||
| -rw-r--r-- | src/input.rs | 278 | ||||
| -rw-r--r-- | src/layout.rs | 1099 | ||||
| -rw-r--r-- | src/main.rs | 3 | ||||
| -rw-r--r-- | src/niri.rs | 247 | ||||
| -rw-r--r-- | src/tty.rs | 313 | ||||
| -rw-r--r-- | src/winit.rs | 19 |
11 files changed, 1911 insertions, 434 deletions
diff --git a/src/backend.rs b/src/backend.rs index 7dcc0121..55ddfaff 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -1,5 +1,6 @@ use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; use smithay::backend::renderer::gles::GlesRenderer; +use smithay::output::Output; use crate::niri::OutputRenderElements; use crate::Niri; @@ -10,6 +11,7 @@ pub trait Backend { fn render( &mut self, niri: &mut Niri, + output: &Output, elements: &[OutputRenderElements< GlesRenderer, WaylandSurfaceRenderElement<GlesRenderer>, diff --git a/src/grabs/move_grab.rs b/src/grabs/move_grab.rs index 699921d1..67a1f285 100644 --- a/src/grabs/move_grab.rs +++ b/src/grabs/move_grab.rs @@ -5,6 +5,7 @@ use smithay::input::pointer::{ }; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::utils::{Logical, Point}; +use smithay::wayland::seat::WaylandFocus; use crate::Niri; @@ -25,10 +26,13 @@ impl PointerGrab<Niri> for MoveSurfaceGrab { // While the grab is active, no client has pointer focus handle.motion(data, None, event); - let delta = event.location - self.start_data.location; - let new_location = self.initial_window_location.to_f64() + delta; - data.space - .map_element(self.window.clone(), new_location.to_i32_round(), true); + // let delta = event.location - self.start_data.location; + // let new_location = self.initial_window_location.to_f64() + delta; + // let (window, space) = data + // .monitor_set + // .find_window_and_space(self.window.wl_surface().as_ref().unwrap()) + // .unwrap(); + // space.map_element(window.clone(), new_location.to_i32_round(), true); } fn relative_motion( diff --git a/src/grabs/resize_grab.rs b/src/grabs/resize_grab.rs index 2bc2f194..819e0b6a 100644 --- a/src/grabs/resize_grab.rs +++ b/src/grabs/resize_grab.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; -use smithay::desktop::{Space, Window}; +use smithay::desktop::Window; use smithay::input::pointer::{ AxisFrame, ButtonEvent, GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent, @@ -241,48 +241,48 @@ impl ResizeSurfaceState { } } -/// Should be called on `WlSurface::commit` -pub fn handle_commit(space: &mut Space<Window>, surface: &WlSurface) -> Option<()> { - let window = space - .elements() - .find(|w| w.toplevel().wl_surface() == surface) - .cloned()?; - - let mut window_loc = space.element_location(&window)?; - let geometry = window.geometry(); - - let new_loc: Point<Option<i32>, Logical> = ResizeSurfaceState::with(surface, |state| { - state - .commit() - .and_then(|(edges, initial_rect)| { - // If the window is being resized by top or left, its location must be adjusted - // accordingly. - edges.intersects(ResizeEdge::TOP_LEFT).then(|| { - let new_x = edges - .intersects(ResizeEdge::LEFT) - .then_some(initial_rect.loc.x + (initial_rect.size.w - geometry.size.w)); - - let new_y = edges - .intersects(ResizeEdge::TOP) - .then_some(initial_rect.loc.y + (initial_rect.size.h - geometry.size.h)); - - (new_x, new_y).into() - }) - }) - .unwrap_or_default() +pub fn handle_commit(window: &Window) -> Option<()> { + // FIXME + let surface = window.toplevel().wl_surface(); + ResizeSurfaceState::with(surface, |state| { + state.commit(); }); - if let Some(new_x) = new_loc.x { - window_loc.x = new_x; - } - if let Some(new_y) = new_loc.y { - window_loc.y = new_y; - } - - if new_loc.x.is_some() || new_loc.y.is_some() { - // If TOP or LEFT side of the window got resized, we have to move it - space.map_element(window, window_loc, false); - } + // let mut window_loc = space.element_location(&window)?; + // let geometry = window.geometry(); + + // let new_loc: Point<Option<i32>, Logical> = ResizeSurfaceState::with(surface, |state| { + // state + // .commit() + // .and_then(|(edges, initial_rect)| { + // // If the window is being resized by top or left, its location must be adjusted + // // accordingly. + // edges.intersects(ResizeEdge::TOP_LEFT).then(|| { + // let new_x = edges + // .intersects(ResizeEdge::LEFT) + // .then_some(initial_rect.loc.x + (initial_rect.size.w - geometry.size.w)); + + // let new_y = edges + // .intersects(ResizeEdge::TOP) + // .then_some(initial_rect.loc.y + (initial_rect.size.h - geometry.size.h)); + + // (new_x, new_y).into() + // }) + // }) + // .unwrap_or_default() + // }); + + // if let Some(new_x) = new_loc.x { + // window_loc.x = new_x; + // } + // if let Some(new_y) = new_loc.y { + // window_loc.y = new_y; + // } + + // if new_loc.x.is_some() || new_loc.y.is_some() { + // // If TOP or LEFT side of the window got resized, we have to move it + // space.map_element(window, window_loc, false); + // } Some(()) } diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs index f5a955e1..d9e25b8f 100644 --- a/src/handlers/compositor.rs +++ b/src/handlers/compositor.rs @@ -1,4 +1,7 @@ -use smithay::backend::renderer::utils::on_commit_buffer_handler; +use std::collections::hash_map::Entry; + +use smithay::backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state}; +use smithay::desktop::find_popup_root_surface; use smithay::reexports::wayland_server::protocol::wl_buffer; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::reexports::wayland_server::Client; @@ -9,6 +12,7 @@ use smithay::wayland::compositor::{ use smithay::wayland::shm::{ShmHandler, ShmState}; use smithay::{delegate_compositor, delegate_shm}; +use super::xdg_shell; use crate::grabs::resize_grab; use crate::niri::ClientState; use crate::Niri; @@ -28,24 +32,95 @@ impl CompositorHandler for Niri { .message("client commit", 0); on_commit_buffer_handler::<Self>(surface); - if !is_sync_subsurface(surface) { - let mut root = surface.clone(); - while let Some(parent) = get_parent(&root) { - root = parent; + + if is_sync_subsurface(surface) { + return; + } + + let mut root_surface = surface.clone(); + while let Some(parent) = get_parent(&root_surface) { + root_surface = parent; + } + + if surface == &root_surface { + // This is a root surface commit. It might have mapped a previously-unmapped toplevel. + if let Entry::Occupied(entry) = self.unmapped_windows.entry(surface.clone()) { + let is_mapped = + with_renderer_surface_state(surface, |state| state.buffer().is_some()); + + if is_mapped { + // The toplevel got mapped. + let window = entry.remove(); + window.on_commit(); + + let output = self.monitor_set.active_output().unwrap().clone(); + self.monitor_set.add_window_to_output(&output, window, true); + self.update_focus(); + + self.queue_redraw(output); + return; + } + + // The toplevel remains unmapped. + let window = entry.get(); + xdg_shell::send_initial_configure_if_needed(window); + return; } - if let Some(window) = self - .space - .elements() - .find(|w| w.toplevel().wl_surface() == &root) - { + + // This is a commit of a previously-mapped root or a non-toplevel root. + if let Some((window, space)) = self.monitor_set.find_window_and_space(surface) { + // This is a commit of a previously-mapped toplevel. + let output = space.outputs().next().unwrap().clone(); + window.on_commit(); + + // This is a commit of a previously-mapped toplevel. + let is_mapped = + with_renderer_surface_state(surface, |state| state.buffer().is_some()); + + if !is_mapped { + // The toplevel got unmapped. + let window = window.clone(); + self.monitor_set.remove_window(&window); + self.unmapped_windows.insert(surface.clone(), window); + self.update_focus(); + + self.queue_redraw(output); + return; + } + + // The toplevel remains mapped. + resize_grab::handle_commit(&window); + self.monitor_set.update_window(&window); + + self.queue_redraw(output); + return; } - }; - self.xdg_handle_commit(surface); - resize_grab::handle_commit(&mut self.space, surface); + // This is a commit of a non-toplevel root. + } - self.queue_redraw(); + // This is a commit of a non-root or a non-toplevel root. + let root_window_space = self.monitor_set.find_window_and_space(&root_surface); + if let Some((window, space)) = root_window_space { + let output = space.outputs().next().unwrap().clone(); + window.on_commit(); + self.monitor_set.update_window(&window); + self.queue_redraw(output); + return; + } + + // This might be a popup. + self.popups_handle_commit(surface); + if let Some(popup) = self.popups.find_popup(surface) { + if let Ok(root) = find_popup_root_surface(&popup) { + let root_window_space = self.monitor_set.find_window_and_space(&root); + if let Some((_window, space)) = root_window_space { + let output = space.outputs().next().unwrap().clone(); + self.queue_redraw(output); + } + } + } } } diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 0e1ad760..c7df18c7 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -2,20 +2,19 @@ use smithay::delegate_xdg_shell; use smithay::desktop::{PopupKind, Window}; use smithay::input::pointer::{Focus, GrabStartData as PointerGrabStartData}; use smithay::input::Seat; -use smithay::output::Output; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::reexports::wayland_server::protocol::{wl_output, wl_seat}; use smithay::reexports::wayland_server::Resource; use smithay::utils::{Rectangle, Serial}; use smithay::wayland::compositor::with_states; -use smithay::wayland::seat::WaylandFocus; use smithay::wayland::shell::xdg::{ PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData, XdgShellHandler, XdgShellState, XdgToplevelSurfaceData, }; use crate::grabs::{MoveSurfaceGrab, ResizeSurfaceGrab}; +use crate::layout::MonitorSet; use crate::Niri; impl XdgShellHandler for Niri { @@ -24,8 +23,16 @@ impl XdgShellHandler for Niri { } fn new_toplevel(&mut self, surface: ToplevelSurface) { + let wl_surface = surface.wl_surface().clone(); let window = Window::new(surface); - self.space.map_element(window, (0, 0), false); + + // Tell the surface the preferred size and bounds for its likely output. + let output = self.monitor_set.active_output().unwrap(); + MonitorSet::configure_new_window(output, &window); + + // At the moment of creation, xdg toplevels must have no buffer. + let existing = self.unmapped_windows.insert(wl_surface, window); + assert!(existing.is_none()); } fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) { @@ -49,17 +56,12 @@ impl XdgShellHandler for Niri { if let Some(start_data) = check_grab(&seat, wl_surface, serial) { let pointer = seat.get_pointer().unwrap(); - let window = self - .space - .elements() - .find(|w| w.toplevel().wl_surface() == wl_surface) - .unwrap() - .clone(); - let initial_window_location = self.space.element_location(&window).unwrap(); + let (window, space) = self.monitor_set.find_window_and_space(wl_surface).unwrap(); + let initial_window_location = space.element_location(&window).unwrap(); let grab = MoveSurfaceGrab { start_data, - window, + window: window.clone(), initial_window_location, }; @@ -81,13 +83,8 @@ impl XdgShellHandler for Niri { if let Some(start_data) = check_grab(&seat, wl_surface, serial) { let pointer = seat.get_pointer().unwrap(); - let window = self - .space - .elements() - .find(|w| w.toplevel().wl_surface() == wl_surface) - .unwrap() - .clone(); - let initial_window_location = self.space.element_location(&window).unwrap(); + let (window, space) = self.monitor_set.find_window_and_space(wl_surface).unwrap(); + let initial_window_location = space.element_location(&window).unwrap(); let initial_window_size = window.geometry().size; surface.with_pending_state(|state| { @@ -98,7 +95,7 @@ impl XdgShellHandler for Niri { let grab = ResizeSurfaceGrab::start( start_data, - window, + window.clone(), edges.into(), Rectangle::from_loc_and_size(initial_window_location, initial_window_size), ); @@ -126,7 +123,7 @@ impl XdgShellHandler for Niri { } fn grab(&mut self, _surface: PopupSurface, _seat: wl_seat::WlSeat, _serial: Serial) { - // TODO popup grabs + // FIXME popup grabs } fn maximize_request(&mut self, surface: ToplevelSurface) { @@ -135,23 +132,17 @@ impl XdgShellHandler for Niri { .capabilities .contains(xdg_toplevel::WmCapabilities::Maximize) { - let wl_surface = surface.wl_surface(); - let window = self - .space - .elements() - .find(|w| w.toplevel().wl_surface() == wl_surface) - .unwrap() - .clone(); - let geometry = self - .space - .output_geometry(self.output.as_ref().unwrap()) - .unwrap(); - - surface.with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Maximized); - state.size = Some(geometry.size); - }); - self.space.map_element(window, geometry.loc, true); + // let wl_surface = surface.wl_surface(); + // let (window, space) = self.monitor_set.find_window_and_space(wl_surface).unwrap(); + // let geometry = space + // .output_geometry(space.outputs().next().unwrap()) + // .unwrap(); + + // surface.with_pending_state(|state| { + // state.states.set(xdg_toplevel::State::Maximized); + // state.size = Some(geometry.size); + // }); + // space.map_element(window.clone(), geometry.loc, true); } // The protocol demands us to always reply with a configure, @@ -185,44 +176,32 @@ impl XdgShellHandler for Niri { .capabilities .contains(xdg_toplevel::WmCapabilities::Fullscreen) { - // NOTE: This is only one part of the solution. We can set the - // location and configure size here, but the surface should be rendered fullscreen - // independently from its buffer size - let wl_surface = surface.wl_surface(); - - let output = wl_output - .as_ref() - .and_then(Output::from_resource) - .or_else(|| { - let w = self - .space - .elements() - .find(|window| { - window - .wl_surface() - .map(|s| s == *wl_surface) - .unwrap_or(false) - }) - .cloned(); - w.and_then(|w| self.space.outputs_for_element(&w).get(0).cloned()) - }); - - if let Some(output) = output { - let geometry = self.space.output_geometry(&output).unwrap(); - - surface.with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Fullscreen); - state.size = Some(geometry.size); - }); - - let window = self - .space - .elements() - .find(|w| w.toplevel().wl_surface() == wl_surface) - .unwrap() - .clone(); - self.space.map_element(window, geometry.loc, true); - } + // // NOTE: This is only one part of the solution. We can set the + // // location and configure size here, but the surface should be rendered fullscreen + // // independently from its buffer size + // let wl_surface = surface.wl_surface(); + + // let output = wl_output + // .as_ref() + // .and_then(Output::from_resource) + // .or_else(|| { + // self.monitor_set + // .find_window_and_space(wl_surface) + // .and_then(|(_window, space)| space.outputs().next().cloned()) + // }); + + // if let Some(output) = output { + // let (window, space) = + // self.monitor_set.find_window_and_space(wl_surface).unwrap(); + // let geometry = space.output_geometry(&output).unwrap(); + + // surface.with_pending_state(|state| { + // state.states.set(xdg_toplevel::State::Fullscreen); + // state.size = Some(geometry.size); + // }); + + // space.map_element(window.clone(), geometry.loc, true); + // } } // The protocol demands us to always reply with a configure, @@ -247,12 +226,25 @@ impl XdgShellHandler for Niri { surface.send_pending_configure(); } - fn toplevel_destroyed(&mut self, _surface: ToplevelSurface) { - self.queue_redraw(); + fn toplevel_destroyed(&mut self, surface: ToplevelSurface) { + if self.unmapped_windows.remove(surface.wl_surface()).is_some() { + // An unmapped toplevel got destroyed. + return; + } + + let (window, space) = self + .monitor_set + .find_window_and_space(surface.wl_surface()) + .unwrap(); + let output = space.outputs().next().unwrap().clone(); + self.monitor_set.remove_window(&window); + self.update_focus(); + self.queue_redraw(output); } fn popup_destroyed(&mut self, _surface: PopupSurface) { - self.queue_redraw(); + // FIXME granular + self.queue_redraw_all(); } } @@ -282,32 +274,27 @@ fn check_grab( Some(start_data) } +pub fn send_initial_configure_if_needed(window: &Window) { + let initial_configure_sent = with_states(window.toplevel().wl_surface(), |states| { + states + .data_map + .get::<XdgToplevelSurfaceData>() + .unwrap() + .lock() + .unwrap() + .initial_configure_sent + }); + + if !initial_configure_sent { + window.toplevel().send_configure(); + } +} + impl Niri { /// Should be called on `WlSurface::commit` - pub fn xdg_handle_commit(&mut self, surface: &WlSurface) { + pub fn popups_handle_commit(&mut self, surface: &WlSurface) { self.popups.commit(surface); - if let Some(window) = self - .space - .elements() - .find(|w| w.toplevel().wl_surface() == surface) - .cloned() - { - let initial_configure_sent = with_states(surface, |states| { - states - .data_map - .get::<XdgToplevelSurfaceData>() - .unwrap() - .lock() - .unwrap() - .initial_configure_sent - }); - - if !initial_configure_sent { - window.toplevel().send_configure(); - } - } - if let Some(popup) = self.popups.find_popup(surface) { let PopupKind::Xdg(ref popup) = popup; let initial_configure_sent = with_states(surface, |states| { diff --git a/src/input.rs b/src/input.rs index 1b7c65ee..0c7c3e62 100644 --- a/src/input.rs +++ b/src/input.rs @@ -5,21 +5,35 @@ use smithay::backend::input::{ AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent, }; -use smithay::input::keyboard::{keysyms, FilterResult}; +use smithay::input::keyboard::{keysyms, FilterResult, KeysymHandle, ModifiersState}; use smithay::input::pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent}; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; -use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::utils::SERIAL_COUNTER; use smithay::wayland::shell::xdg::XdgShellHandler; use crate::niri::Niri; -enum InputAction { +enum Action { + None, Quit, ChangeVt(i32), SpawnTerminal, CloseWindow, ToggleFullscreen, + FocusLeft, + FocusRight, + FocusDown, + FocusUp, + MoveLeft, + MoveRight, + MoveDown, + MoveUp, + ConsumeIntoColumn, + ExpelFromColumn, + SwitchWorkspaceDown, + SwitchWorkspaceUp, + MoveToWorkspaceDown, + MoveToWorkspaceUp, } pub enum CompositorMod { @@ -27,11 +41,64 @@ pub enum CompositorMod { Alt, } +impl From<Action> for FilterResult<Action> { + fn from(value: Action) -> Self { + match value { + Action::None => FilterResult::Forward, + action => FilterResult::Intercept(action), + } + } +} + +fn action(comp_mod: CompositorMod, keysym: KeysymHandle, mods: ModifiersState) -> Action { + use keysyms::*; + + let modified = keysym.modified_sym(); + if matches!(modified, KEY_XF86Switch_VT_1..=KEY_XF86Switch_VT_12) { + let vt = (modified - KEY_XF86Switch_VT_1 + 1) as i32; + return Action::ChangeVt(vt); + } + + let mod_down = match comp_mod { + CompositorMod::Super => mods.logo, + CompositorMod::Alt => mods.alt, + }; + + if !mod_down { + return Action::None; + } + + // FIXME: these don't work in the Russian layout. I guess I'll need to + // find a US keymap, then map keys somehow. + #[allow(non_upper_case_globals)] // wat + match modified { + KEY_E => Action::Quit, + KEY_t => Action::SpawnTerminal, + KEY_q => Action::CloseWindow, + KEY_f => Action::ToggleFullscreen, + KEY_h | KEY_Left if mods.ctrl => Action::MoveLeft, + KEY_l | KEY_Right if mods.ctrl => Action::MoveRight, + KEY_j | KEY_Down if mods.ctrl => Action::MoveDown, + KEY_k | KEY_Up if mods.ctrl => Action::MoveUp, + KEY_h | KEY_Left => Action::FocusLeft, + KEY_l | KEY_Right => Action::FocusRight, + KEY_j | KEY_Down => Action::FocusDown, + KEY_k | KEY_Up => Action::FocusUp, + KEY_u if mods.ctrl => Action::MoveToWorkspaceDown, + KEY_i if mods.ctrl => Action::MoveToWorkspaceUp, + KEY_u => Action::SwitchWorkspaceDown, + KEY_i => Action::SwitchWorkspaceUp, + KEY_comma => Action::ConsumeIntoColumn, + KEY_period => Action::ExpelFromColumn, + _ => Action::None, + } +} + impl Niri { pub fn process_input_event<I: InputBackend>( &mut self, change_vt: &mut dyn FnMut(i32), - compositor_mod: CompositorMod, + comp_mod: CompositorMod, event: InputEvent<I>, ) { let _span = tracy_client::span!("process_input_event"); @@ -50,33 +117,7 @@ impl Niri { time, |_, mods, keysym| { if event.state() == KeyState::Pressed { - let mod_down = match compositor_mod { - CompositorMod::Super => mods.logo, - CompositorMod::Alt => mods.alt, - }; - - // FIXME: these don't work in the Russian layout. I guess I'll need to - // find a US keymap, then map keys somehow. - match keysym.modified_sym() { - keysyms::KEY_E if mod_down => { - FilterResult::Intercept(InputAction::Quit) - } - keysym @ keysyms::KEY_XF86Switch_VT_1 - ..=keysyms::KEY_XF86Switch_VT_12 => { - let vt = (keysym - keysyms::KEY_XF86Switch_VT_1 + 1) as i32; - FilterResult::Intercept(InputAction::ChangeVt(vt)) - } - keysyms::KEY_t if mod_down => { - FilterResult::Intercept(InputAction::SpawnTerminal) - } - keysyms::KEY_q if mod_down => { - FilterResult::Intercept(InputAction::CloseWindow) - } - keysyms::KEY_f if mod_down => { - FilterResult::Intercept(InputAction::ToggleFullscreen) - } - _ => FilterResult::Forward, - } + action(comp_mod, keysym, *mods).into() } else { FilterResult::Forward } @@ -85,22 +126,27 @@ impl Niri { if let Some(action) = action { match action { - InputAction::Quit => { + Action::None => unreachable!(), + Action::Quit => { info!("quitting because quit bind was pressed"); self.stop_signal.stop() } - InputAction::ChangeVt(vt) => { + Action::ChangeVt(vt) => { (*change_vt)(vt); } - InputAction::SpawnTerminal => { + Action::SpawnTerminal => { if let Err(err) = Command::new("alacritty").spawn() { warn!("error spawning alacritty: {err}"); } } - InputAction::CloseWindow => { + Action::CloseWindow => { if let Some(focus) = self.seat.get_keyboard().unwrap().current_focus() { // FIXME: is there a better way of doing this? - for window in self.space.elements() { + for window in self + .monitor_set + .workspaces() + .flat_map(|workspace| workspace.space.elements()) + { let found = Cell::new(false); window.with_surfaces(|surface, _| { if surface == &focus { @@ -114,18 +160,22 @@ impl Niri { } } } - InputAction::ToggleFullscreen => { + Action::ToggleFullscreen => { if let Some(focus) = self.seat.get_keyboard().unwrap().current_focus() { // FIXME: is there a better way of doing this? - let window = self.space.elements().find(|window| { - let found = Cell::new(false); - window.with_surfaces(|surface, _| { - if surface == &focus { - found.set(true); - } + let window = self + .monitor_set + .workspaces() + .flat_map(|workspace| workspace.space.elements()) + .find(|window| { + let found = Cell::new(false); + window.with_surfaces(|surface, _| { + if surface == &focus { + found.set(true); + } + }); + found.get() }); - found.get() - }); if let Some(window) = window { let toplevel = window.toplevel().clone(); if toplevel @@ -140,6 +190,78 @@ impl Niri { } } } + Action::MoveLeft => { + self.monitor_set.move_left(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::MoveRight => { + self.monitor_set.move_right(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::MoveDown => { + self.monitor_set.move_down(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::MoveUp => { + self.monitor_set.move_up(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::FocusLeft => { + self.monitor_set.focus_left(); + self.update_focus(); + } + Action::FocusRight => { + self.monitor_set.focus_right(); + self.update_focus(); + } + Action::FocusDown => { + self.monitor_set.focus_down(); + self.update_focus(); + } + Action::FocusUp => { + self.monitor_set.focus_up(); + self.update_focus(); + } + Action::MoveToWorkspaceDown => { + self.monitor_set.move_to_workspace_down(); + self.update_focus(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::MoveToWorkspaceUp => { + self.monitor_set.move_to_workspace_up(); + self.update_focus(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::SwitchWorkspaceDown => { + self.monitor_set.switch_workspace_down(); + self.update_focus(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::SwitchWorkspaceUp => { + self.monitor_set.switch_workspace_up(); + self.update_focus(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::ConsumeIntoColumn => { + self.monitor_set.consume_into_column(); + self.update_focus(); + // FIXME: granular + self.queue_redraw_all(); + } + Action::ExpelFromColumn => { + self.monitor_set.expel_from_column(); + self.update_focus(); + // FIXME: granular + self.queue_redraw_all(); + } } } } @@ -147,22 +269,33 @@ impl Niri { let serial = SERIAL_COUNTER.next_serial(); |
