aboutsummaryrefslogtreecommitdiff
path: root/src/input.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-08-13 12:46:53 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-08-13 12:46:53 +0400
commit95c810c855a27a28f4dfa7dc6b949fef0901c7b2 (patch)
treec240dd8d8c6eac7cd18c507fbe35724ca7de8aeb /src/input.rs
parente02e35f9c61e103a01640d3dc95a894e8855e1c9 (diff)
downloadniri-95c810c855a27a28f4dfa7dc6b949fef0901c7b2.tar.gz
niri-95c810c855a27a28f4dfa7dc6b949fef0901c7b2.tar.bz2
niri-95c810c855a27a28f4dfa7dc6b949fef0901c7b2.zip
Refactor everything, add initial tiling code
Diffstat (limited to 'src/input.rs')
-rw-r--r--src/input.rs278
1 files changed, 201 insertions, 77 deletions
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_location.x = pointer_location.x.clamp(0., output_geo.size.w as f64);
- pointer_location.y = pointer_location.y.clamp(0., output_geo.size.h as f64);
+ let under = self.surface_under_and_global_space(pos);
- let under = self.surface_under(pointer_location);
pointer.motion(
self,
under.clone(),
&MotionEvent {
- location: pointer_location,
+ location: pos,
serial,
time: event.time_msec(),
},
@@ -179,12 +312,14 @@ impl Niri {
);
// Redraw to update the cursor position.
- self.queue_redraw();
+ // FIXME: redraw only outputs overlapping the cursor.
+ self.queue_redraw_all();
}
InputEvent::PointerMotionAbsolute { event, .. } => {
- let output = self.space.outputs().next().unwrap();
+ // FIXME: allow mapping tablet to different outputs.
+ let output = self.global_space.outputs().next().unwrap();
- let output_geo = self.space.output_geometry(output).unwrap();
+ let output_geo = self.global_space.output_geometry(output).unwrap();
let pos = event.position_transformed(output_geo.size) + output_geo.loc.to_f64();
@@ -192,7 +327,7 @@ impl Niri {
let pointer = self.seat.get_pointer().unwrap();
- let under = self.surface_under(pos);
+ let under = self.surface_under_and_global_space(pos);
pointer.motion(
self,
@@ -205,11 +340,11 @@ impl Niri {
);
// Redraw to update the cursor position.
- self.queue_redraw();
+ // FIXME: redraw only outputs overlapping the cursor.
+ self.queue_redraw_all();
}
InputEvent::PointerButton { event, .. } => {
let pointer = self.seat.get_pointer().unwrap();
- let keyboard = self.seat.get_keyboard().unwrap();
let serial = SERIAL_COUNTER.next_serial();
@@ -218,27 +353,16 @@ impl Niri {
let button_state = event.state();
if ButtonState::Pressed == button_state && !pointer.is_grabbed() {
- if let Some((window, _loc)) = self
- .space
- .element_under(pointer.current_location())
- .map(|(w, l)| (w.clone(), l))
+ if let Some((_space, window, _loc)) =
+ self.window_under(pointer.current_location())
{
- self.space.raise_element(&window, true);
- keyboard.set_focus(
- self,
- Some(window.toplevel().wl_surface().clone()),
- serial,
- );
- self.space.elements().for_each(|window| {
- window.toplevel().send_pending_configure();
- });
+ self.monitor_set.activate_window(&window);
} else {
- self.space.elements().for_each(|window| {
- window.set_activated(false);
- window.toplevel().send_pending_configure();
- });
- keyboard.set_focus(self, Option::<WlSurface>::None, serial);
+ let output = self.output_under_cursor().unwrap();
+ self.monitor_set.activate_output(&output);
}
+
+ self.update_focus();
};
pointer.button(