From 72e76dec61df020876104a7f6955f3f9d851f789 Mon Sep 17 00:00:00 2001 From: Seaotatop Date: Fri, 2 Jun 2023 12:26:33 -0500 Subject: [PATCH] Extracted input processing into new file --- src/backend.rs | 1 + src/backend/winit.rs | 298 +++---------------------------------------- src/input.rs | 285 +++++++++++++++++++++++++++++++++++++++++ src/main.rs | 35 +---- src/window.rs | 1 + 5 files changed, 312 insertions(+), 308 deletions(-) create mode 100644 src/input.rs diff --git a/src/backend.rs b/src/backend.rs index fa9ca26..1467f10 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -2,6 +2,7 @@ use smithay::{output::Output, reexports::wayland_server::protocol::wl_surface::W pub mod winit; +/// A trait defining common methods for each available backend: winit and tty-udev pub trait Backend: 'static { fn seat_name(&self) -> String; fn reset_buffers(&mut self, output: &Output); diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 7b2a7e0..088884d 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -241,286 +241,26 @@ pub fn run_winit() -> Result<(), Box> { let display = &mut data.display; let state = &mut data.state; - let result = winit_evt_loop.dispatch_new_events(|event| { - match event { - WinitEvent::Resized { - size, - scale_factor: _, - } => { - output.change_current_state( - Some(smithay::output::Mode { - size, - refresh: 144_000, - }), - None, - None, - None, - ); - } - WinitEvent::Focus(_) => {} - WinitEvent::Input(input_evt) => match input_evt { - // TODO: extract input events - // | into separate function - - // InputEvent::DeviceAdded { device } => todo!(), - // InputEvent::DeviceRemoved { device } => todo!(), - InputEvent::Keyboard { event } => { - let serial = SERIAL_COUNTER.next_serial(); - let time = event.time_msec(); - let press_state = event.state(); - let mut move_mode = false; - let action = seat.get_keyboard().unwrap().input( - state, - event.key_code(), - press_state, - serial, - time, - |_state, _modifiers, keysym| { - if press_state == KeyState::Pressed { - match keysym.modified_sym() { - keysyms::KEY_L => return FilterResult::Intercept(1), - keysyms::KEY_K => return FilterResult::Intercept(2), - keysyms::KEY_J => return FilterResult::Intercept(3), - keysyms::KEY_H => return FilterResult::Intercept(4), - _ => {} - } - } - - if keysym.modified_sym() == keysyms::KEY_Control_L { - match press_state { - KeyState::Pressed => { - move_mode = true; - } - KeyState::Released => { - move_mode = false; - } - } - FilterResult::Forward - } else { - FilterResult::Forward - } - }, - ); - - state.move_mode = move_mode; - - match action { - Some(1) => { - std::process::Command::new("alacritty").spawn().unwrap(); - } - Some(2) => { - std::process::Command::new("nautilus").spawn().unwrap(); - } - Some(3) => { - std::process::Command::new("kitty").spawn().unwrap(); - } - Some(4) => { - std::process::Command::new("foot").spawn().unwrap(); - } - Some(_) => {} - None => {} - } - } - InputEvent::PointerMotion { event } => {} - InputEvent::PointerMotionAbsolute { event } => { - let output = state.space.outputs().next().unwrap(); - let output_geo = state.space.output_geometry(output).unwrap(); - let pointer_loc = - event.position_transformed(output_geo.size) + output_geo.loc.to_f64(); - let serial = SERIAL_COUNTER.next_serial(); - let pointer = seat.get_pointer().unwrap(); - - let surface_under_pointer = state - .space - .element_under(pointer_loc) - .and_then(|(window, location)| { - window - .surface_under( - pointer_loc - location.to_f64(), - WindowSurfaceType::ALL, - ) - .map(|(s, p)| (s, p + location)) - }); - - pointer.motion( - state, - surface_under_pointer, - &MotionEvent { - location: pointer_loc, - serial, - time: event.time_msec(), - }, - ); - } - InputEvent::PointerButton { event } => { - let pointer = seat.get_pointer().unwrap(); - let keyboard = seat.get_keyboard().unwrap(); - - // A serial is a number sent with a event that is sent back to the - // server by the clients in further requests. This allows the server to - // keep track of which event caused which requests. It is an AtomicU32 - // that increments when next_serial is called. - let serial = SERIAL_COUNTER.next_serial(); - - // Returns which button on the pointer was used. - let button = event.button_code(); - - // The state, either released or pressed. - let button_state = event.state(); - - let pointer_loc = pointer.current_location(); - - // If the button was clicked, focus on the window below if exists, else - // unfocus on windows. - if ButtonState::Pressed == button_state { - if let Some((window, window_loc)) = state - .space - .element_under(pointer_loc) - .map(|(w, l)| (w.clone(), l)) - { - const BUTTON_LEFT: u32 = 0x110; - const BUTTON_RIGHT: u32 = 0x111; - if state.move_mode { - if event.button_code() == BUTTON_LEFT { - crate::xdg::request::move_request_force( - state, - window.toplevel(), - &seat, - serial, - ); - return; // TODO: kinda ugly return here - } else if event.button_code() == BUTTON_RIGHT { - let window_geometry = window.geometry(); - let window_x = window_loc.x as f64; - let window_y = window_loc.y as f64; - let window_width = window_geometry.size.w as f64; - let window_height = window_geometry.size.h as f64; - let half_width = window_x + window_width / 2.0; - let half_height = window_y + window_height / 2.0; - let full_width = window_x + window_width; - let full_height = window_y + window_height; - - println!( - "window loc: {}, {} | window size: {}, {}", - window_x, window_y, window_width, window_height - ); - - let edges = match pointer_loc { - Point { x, y, .. } - if (window_x..=half_width).contains(&x) - && (window_y..=half_height).contains(&y) => - { - ResizeEdge::TopLeft - } - Point { x, y, .. } - if (half_width..=full_width).contains(&x) - && (window_y..=half_height).contains(&y) => - { - ResizeEdge::TopRight - } - Point { x, y, .. } - if (window_x..=half_width).contains(&x) - && (half_height..=full_height).contains(&y) => - { - ResizeEdge::BottomLeft - } - Point { x, y, .. } - if (half_width..=full_width).contains(&x) - && (half_height..=full_height).contains(&y) => - { - ResizeEdge::BottomRight - } - _ => ResizeEdge::None, - }; - - crate::xdg::request::resize_request_force( - state, - window.toplevel(), - &seat, - serial, - edges, - BUTTON_RIGHT, - ); - } - } else { - // Move window to top of stack. - state.space.raise_element(&window, true); - - // Focus on window. - keyboard.set_focus( - state, - Some(window.toplevel().wl_surface().clone()), - serial, - ); - state.space.elements().for_each(|window| { - window.toplevel().send_configure(); - }); - } - } else { - state.space.elements().for_each(|window| { - window.set_activated(false); - window.toplevel().send_configure(); - }); - keyboard.set_focus(state, None, serial); - } - }; - - // Send the button event to the client. - pointer.button( - state, - &ButtonEvent { - button, - state: button_state, - serial, - time: event.time_msec(), - }, - ); - } - InputEvent::PointerAxis { event } => { - let pointer = seat.get_pointer().unwrap(); - - let source = event.source(); - - let horizontal_amount = - event.amount(Axis::Horizontal).unwrap_or_else(|| { - event.amount_discrete(Axis::Horizontal).unwrap() * 3.0 - }); - - let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| { - event.amount_discrete(Axis::Vertical).unwrap() * 3.0 - }); - - let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal); - let vertical_amount_discrete = event.amount_discrete(Axis::Vertical); - - let mut frame = AxisFrame::new(event.time_msec()).source(source); - - if horizontal_amount != 0.0 { - frame = frame.value(Axis::Horizontal, horizontal_amount); - if let Some(discrete) = horizontal_amount_discrete { - frame = frame.discrete(Axis::Horizontal, discrete as i32); - } - } else if source == AxisSource::Finger { - frame = frame.stop(Axis::Horizontal); - } - - if vertical_amount != 0.0 { - frame = frame.value(Axis::Vertical, vertical_amount); - if let Some(discrete) = vertical_amount_discrete { - frame = frame.discrete(Axis::Vertical, discrete as i32); - } - } else if source == AxisSource::Finger { - frame = frame.stop(Axis::Vertical); - } - - println!("axisframe: {:?}", frame); - pointer.axis(state, frame); - } - // TODO: rest of the InputEvents - _ => (), - }, - WinitEvent::Refresh => {} + let result = winit_evt_loop.dispatch_new_events(|event| match event { + WinitEvent::Resized { + size, + scale_factor: _, + } => { + output.change_current_state( + Some(smithay::output::Mode { + size, + refresh: 144_000, + }), + None, + None, + None, + ); } + WinitEvent::Focus(_) => {} + WinitEvent::Input(input_evt) => { + state.process_input_event(&seat, input_evt); + } // TODO: + WinitEvent::Refresh => {} }); match result { diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..a7a450a --- /dev/null +++ b/src/input.rs @@ -0,0 +1,285 @@ +use smithay::{ + backend::input::{ + AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent, + KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, + }, + desktop::WindowSurfaceType, + input::{ + keyboard::{keysyms, FilterResult}, + pointer::{AxisFrame, ButtonEvent, MotionEvent}, + Seat, + }, + reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge, + utils::{Point, SERIAL_COUNTER}, +}; + +use crate::{backend::winit::WinitData, State}; + +impl State { + pub fn process_input_event( + &mut self, + seat: &Seat>, + event: InputEvent, + ) { + match event { + // TODO: extract input events + // | into separate function + + // InputEvent::DeviceAdded { device } => todo!(), + // InputEvent::DeviceRemoved { device } => todo!(), + InputEvent::Keyboard { event } => { + let serial = SERIAL_COUNTER.next_serial(); + let time = event.time_msec(); + let press_state = event.state(); + let mut move_mode = false; + let action = seat.get_keyboard().unwrap().input( + self, + event.key_code(), + press_state, + serial, + time, + |_state, _modifiers, keysym| { + if press_state == KeyState::Pressed { + match keysym.modified_sym() { + keysyms::KEY_L => return FilterResult::Intercept(1), + keysyms::KEY_K => return FilterResult::Intercept(2), + keysyms::KEY_J => return FilterResult::Intercept(3), + keysyms::KEY_H => return FilterResult::Intercept(4), + _ => {} + } + } + + if keysym.modified_sym() == keysyms::KEY_Control_L { + match press_state { + KeyState::Pressed => { + move_mode = true; + } + KeyState::Released => { + move_mode = false; + } + } + FilterResult::Forward + } else { + FilterResult::Forward + } + }, + ); + + self.move_mode = move_mode; + + match action { + Some(1) => { + std::process::Command::new("alacritty").spawn().unwrap(); + } + Some(2) => { + std::process::Command::new("nautilus").spawn().unwrap(); + } + Some(3) => { + std::process::Command::new("kitty").spawn().unwrap(); + } + Some(4) => { + std::process::Command::new("foot").spawn().unwrap(); + } + Some(_) => {} + None => {} + } + } + InputEvent::PointerMotion { event } => {} + InputEvent::PointerMotionAbsolute { event } => { + let output = self.space.outputs().next().unwrap(); + let output_geo = self.space.output_geometry(output).unwrap(); + let pointer_loc = + event.position_transformed(output_geo.size) + output_geo.loc.to_f64(); + let serial = SERIAL_COUNTER.next_serial(); + let pointer = seat.get_pointer().unwrap(); + + let surface_under_pointer = + self.space + .element_under(pointer_loc) + .and_then(|(window, location)| { + window + .surface_under( + pointer_loc - location.to_f64(), + WindowSurfaceType::ALL, + ) + .map(|(s, p)| (s, p + location)) + }); + + pointer.motion( + self, + surface_under_pointer, + &MotionEvent { + location: pointer_loc, + serial, + time: event.time_msec(), + }, + ); + } + InputEvent::PointerButton { event } => { + let pointer = seat.get_pointer().unwrap(); + let keyboard = seat.get_keyboard().unwrap(); + + // A serial is a number sent with a event that is sent back to the + // server by the clients in further requests. This allows the server to + // keep track of which event caused which requests. It is an AtomicU32 + // that increments when next_serial is called. + let serial = SERIAL_COUNTER.next_serial(); + + // Returns which button on the pointer was used. + let button = event.button_code(); + + // The state, either released or pressed. + let button_state = event.state(); + + let pointer_loc = pointer.current_location(); + + // If the button was clicked, focus on the window below if exists, else + // unfocus on windows. + if ButtonState::Pressed == button_state { + if let Some((window, window_loc)) = self + .space + .element_under(pointer_loc) + .map(|(w, l)| (w.clone(), l)) + { + const BUTTON_LEFT: u32 = 0x110; + const BUTTON_RIGHT: u32 = 0x111; + if self.move_mode { + if event.button_code() == BUTTON_LEFT { + crate::xdg::request::move_request_force( + self, + window.toplevel(), + seat, + serial, + ); + return; // TODO: kinda ugly return here + } else if event.button_code() == BUTTON_RIGHT { + let window_geometry = window.geometry(); + let window_x = window_loc.x as f64; + let window_y = window_loc.y as f64; + let window_width = window_geometry.size.w as f64; + let window_height = window_geometry.size.h as f64; + let half_width = window_x + window_width / 2.0; + let half_height = window_y + window_height / 2.0; + let full_width = window_x + window_width; + let full_height = window_y + window_height; + + println!( + "window loc: {}, {} | window size: {}, {}", + window_x, window_y, window_width, window_height + ); + + let edges = match pointer_loc { + Point { x, y, .. } + if (window_x..=half_width).contains(&x) + && (window_y..=half_height).contains(&y) => + { + ResizeEdge::TopLeft + } + Point { x, y, .. } + if (half_width..=full_width).contains(&x) + && (window_y..=half_height).contains(&y) => + { + ResizeEdge::TopRight + } + Point { x, y, .. } + if (window_x..=half_width).contains(&x) + && (half_height..=full_height).contains(&y) => + { + ResizeEdge::BottomLeft + } + Point { x, y, .. } + if (half_width..=full_width).contains(&x) + && (half_height..=full_height).contains(&y) => + { + ResizeEdge::BottomRight + } + _ => ResizeEdge::None, + }; + + crate::xdg::request::resize_request_force( + self, + window.toplevel(), + seat, + serial, + edges, + BUTTON_RIGHT, + ); + } + } else { + // Move window to top of stack. + self.space.raise_element(&window, true); + + // Focus on window. + keyboard.set_focus( + self, + Some(window.toplevel().wl_surface().clone()), + serial, + ); + self.space.elements().for_each(|window| { + window.toplevel().send_configure(); + }); + } + } else { + self.space.elements().for_each(|window| { + window.set_activated(false); + window.toplevel().send_configure(); + }); + keyboard.set_focus(self, None, serial); + } + }; + + // Send the button event to the client. + pointer.button( + self, + &ButtonEvent { + button, + state: button_state, + serial, + time: event.time_msec(), + }, + ); + } + InputEvent::PointerAxis { event } => { + let pointer = seat.get_pointer().unwrap(); + + let source = event.source(); + + let horizontal_amount = event + .amount(Axis::Horizontal) + .unwrap_or_else(|| event.amount_discrete(Axis::Horizontal).unwrap() * 3.0); + + let vertical_amount = event + .amount(Axis::Vertical) + .unwrap_or_else(|| event.amount_discrete(Axis::Vertical).unwrap() * 3.0); + + let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal); + let vertical_amount_discrete = event.amount_discrete(Axis::Vertical); + + let mut frame = AxisFrame::new(event.time_msec()).source(source); + + if horizontal_amount != 0.0 { + frame = frame.value(Axis::Horizontal, horizontal_amount); + if let Some(discrete) = horizontal_amount_discrete { + frame = frame.discrete(Axis::Horizontal, discrete as i32); + } + } else if source == AxisSource::Finger { + frame = frame.stop(Axis::Horizontal); + } + + if vertical_amount != 0.0 { + frame = frame.value(Axis::Vertical, vertical_amount); + if let Some(discrete) = vertical_amount_discrete { + frame = frame.discrete(Axis::Vertical, discrete as i32); + } + } else if source == AxisSource::Finger { + frame = frame.stop(Axis::Vertical); + } + + println!("axisframe: {:?}", frame); + pointer.axis(self, frame); + } + + _ => (), + } + } +} diff --git a/src/main.rs b/src/main.rs index 9abea96..55c9425 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,56 +1,33 @@ mod backend; mod grab; mod handlers; +mod input; mod layout; mod pointer; mod tag; mod window; mod xdg; -use std::{error::Error, os::fd::AsRawFd, sync::Arc, time::Duration}; +use std::error::Error; use backend::{winit::WinitData, Backend}; use smithay::{ - backend::{ - egl::EGLDevice, - input::{ - AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputEvent, KeyState, - KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, - }, - renderer::{ - damage::OutputDamageTracker, element::surface::WaylandSurfaceRenderElement, - gles::GlesRenderer, ImportDma, - }, - winit::{WinitError, WinitEvent}, - }, - desktop::{space, Space, Window, WindowSurfaceType}, - input::{ - keyboard::{keysyms, FilterResult}, - pointer::{AxisFrame, ButtonEvent, CursorImageStatus, MotionEvent}, - SeatState, - }, - output::{Output, Subpixel}, + desktop::{Space, Window}, + input::{pointer::CursorImageStatus, SeatState}, reexports::{ - calloop::{ - generic::Generic, - timer::{TimeoutAction, Timer}, - EventLoop, Interest, LoopHandle, LoopSignal, Mode, PostAction, - }, - wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge, + calloop::{LoopHandle, LoopSignal}, wayland_server::{ backend::{ClientData, ClientId, DisconnectReason}, Display, }, }, - utils::{Clock, Logical, Monotonic, Physical, Point, Scale, Transform, SERIAL_COUNTER}, + utils::{Clock, Logical, Monotonic, Point}, wayland::{ compositor::{CompositorClientState, CompositorState}, data_device::DataDeviceState, - dmabuf::{DmabufFeedbackBuilder, DmabufState}, output::OutputManagerState, shell::xdg::XdgShellState, shm::ShmState, - socket::ListeningSocketSource, }, }; diff --git a/src/window.rs b/src/window.rs index c3b9a24..5f74494 100644 --- a/src/window.rs +++ b/src/window.rs @@ -9,6 +9,7 @@ use self::window_state::{Float, WindowState}; pub mod window_state; pub trait SurfaceState: Default + 'static { + /// Access the [SurfaceState] associated with a [WlSurface] fn with_state(wl_surface: &WlSurface, function: F) -> T where F: FnOnce(&mut Self) -> T,