aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend.rs2
-rw-r--r--src/grabs/move_grab.rs12
-rw-r--r--src/grabs/resize_grab.rs82
-rw-r--r--src/handlers/compositor.rs103
-rw-r--r--src/handlers/xdg_shell.rs187
-rw-r--r--src/input.rs278
-rw-r--r--src/layout.rs1099
-rw-r--r--src/main.rs3
-rw-r--r--src/niri.rs247
-rw-r--r--src/tty.rs313
-rw-r--r--src/winit.rs19
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();
let pointer = self.seat.get_pointer().unwrap();
- let mut pointer_location = pointer.current_location();
+ let mut pos = pointer.current_location();
+
+ pos += event.delta();
- pointer_location += event.delta();
+ let mut min_x = i32::MAX;
+ let mut min_y = i32::MAX;
+ let mut max_x = 0;
+ let mut max_y = 0;
+ for output in self.global_space.outputs() {
+ // FIXME: smarter clamping.
+ let geom = self.global_space.output_geometry(output).unwrap();
+ min_x = min_x.min(geom.loc.x);
+ min_y = min_y.min(geom.loc.y);
+ max_x = max_x.max(geom.loc.x + geom.size.w);
+ max_y = max_y.max(geom.loc.y + geom.size.h);
+ }
- let output = self.space.outputs().next().unwrap();
- let output_geo = self.space.output_geometry(output).unwrap();
+ pos.x = pos.x.clamp(min_x as f64, max_x as f64);
+ pos.y = pos.y.clamp(min_y as f64, max_y as f64);
- pointer_l