diff --git a/src/input/keyboard.rs b/src/input/keyboard.rs index ea435d9..c5bd6cd 100644 --- a/src/input/keyboard.rs +++ b/src/input/keyboard.rs @@ -1,35 +1,45 @@ +use crate::CompositorState; + use log::debug; use wlroots::{ compositor, input::{self, keyboard}, + wlroots_dehandle, xkbcommon::xkb::{keysym_get_name, keysyms}, WLR_KEY_PRESSED, }; +use std::{process::Command, thread}; + pub struct Keyboard; impl input::keyboard::Handler for Keyboard { + #[wlroots_dehandle(compositor, seat)] fn on_key( &mut self, compositor_handle: compositor::Handle, _keyboard_handle: keyboard::Handle, key_event: &keyboard::event::Key, ) { + use compositor_handle as compositor; + if key_event.key_state() == WLR_KEY_PRESSED { for key in key_event.pressed_keys() { debug!("Key down: {}", keysym_get_name(key)); + match key { keysyms::KEY_Escape => compositor::terminate(), + keysyms::KEY_F1 => { + thread::spawn(move || { + Command::new("weston-terminal").output().unwrap(); + }); + } keysyms::KEY_XF86Switch_VT_1..=keysyms::KEY_XF86Switch_VT_12 => { - compositor_handle - .run(|compositor| { - let backend = compositor.backend_mut(); - if let Some(mut session) = backend.get_session() { - session.change_vt(key - keysyms::KEY_XF86Switch_VT_1 + 1); - } - }) - .unwrap(); + let backend = compositor.backend_mut(); + if let Some(mut session) = backend.get_session() { + session.change_vt(key - keysyms::KEY_XF86Switch_VT_1 + 1); + } } _ => {} } @@ -39,5 +49,14 @@ impl input::keyboard::Handler for Keyboard { debug!("Key up: {}", keysym_get_name(key)); } } + + let state: &mut CompositorState = compositor.downcast(); + let seat_handle = state.seat_handle.clone().unwrap(); + use seat_handle as seat; + seat.keyboard_notify_key( + key_event.time_msec(), + key_event.keycode(), + key_event.key_state() as u32, + ); } } diff --git a/src/input/manager.rs b/src/input/manager.rs index 998bc74..fe397cc 100644 --- a/src/input/manager.rs +++ b/src/input/manager.rs @@ -8,7 +8,7 @@ use log::debug; use wlroots::{ compositor, input::{self, keyboard, pointer}, - with_handles, + wlroots_dehandle, }; pub fn build() -> input::manager::Builder { @@ -17,32 +17,46 @@ pub fn build() -> input::manager::Builder { .pointer_added(pointer_added) } +#[wlroots_dehandle(compositor, keyboard, seat)] fn keyboard_added( compositor_handle: compositor::Handle, keyboard_handle: keyboard::Handle, ) -> Option> { - debug!("Keyboard added"); + { + debug!("Keyboard added"); + + use compositor_handle as compositor; + let state: &mut CompositorState = compositor.data.downcast_mut().unwrap(); + + { + let seat_handle = state.seat_handle.as_ref().unwrap(); + use keyboard_handle as keyboard; + use seat_handle as seat; + seat.set_keyboard(keyboard.input_device()); + } + + state.keyboards.push(keyboard_handle); + } - with_handles!([(compositor: {compositor_handle})] => { - let compositor_state: &mut CompositorState = compositor.data.downcast_mut().unwrap(); - compositor_state.keyboards.push(keyboard_handle); - }) - .unwrap(); Some(Box::new(Keyboard)) } +#[wlroots_dehandle(compositor, pointer, cursor)] fn pointer_added( compositor_handle: compositor::Handle, pointer_handle: pointer::Handle, ) -> Option> { - debug!("Pointer added"); + { + debug!("Pointer added"); + + use compositor_handle as compositor; + let state: &mut CompositorState = compositor.downcast(); + + let cursor_handle = &state.cursor_handle; + use cursor_handle as cursor; + use pointer_handle as pointer; + cursor.attach_input_device(pointer.input_device()); + } - with_handles!([(compositor: {compositor_handle}), (pointer: {pointer_handle})] => { - let compositor_state: &mut CompositorState = compositor.downcast(); - compositor_state.cursor_handle - .run(|cursor| cursor.attach_input_device(pointer.input_device())) - .unwrap(); - }) - .unwrap(); Some(Box::new(Pointer)) } diff --git a/src/input/pointer.rs b/src/input/pointer.rs index 2ef0347..4a34bc0 100644 --- a/src/input/pointer.rs +++ b/src/input/pointer.rs @@ -1,41 +1,41 @@ use crate::CompositorState; -use wlroots::{compositor, input::pointer, with_handles}; +use wlroots::{compositor, input::pointer, wlroots_dehandle}; pub struct Pointer; impl pointer::Handler for Pointer { + #[wlroots_dehandle(compositor, cursor)] fn on_motion_absolute( &mut self, compositor_handle: compositor::Handle, _pointer_handle: pointer::Handle, absolute_motion_event: &pointer::event::AbsoluteMotion, ) { - with_handles!([(compositor: {compositor_handle})] => { - let compositor_state: &mut CompositorState = compositor.downcast(); - let (x, y) = absolute_motion_event.pos(); + use compositor_handle as compositor; + let state: &mut CompositorState = compositor.downcast(); + let (x, y) = absolute_motion_event.pos(); - compositor_state.cursor_handle - .run(|cursor| cursor.warp_absolute(absolute_motion_event.device(), x, y)) - .unwrap(); - }) - .unwrap(); + let cursor_handle = &state.cursor_handle; + use cursor_handle as cursor; + cursor.warp_absolute(absolute_motion_event.device(), x, y); } + #[wlroots_dehandle(compositor, cursor)] fn on_motion( &mut self, compositor_handle: compositor::Handle, _pointer_handle: pointer::Handle, motion_event: &pointer::event::Motion, ) { - with_handles!([(compositor: {compositor_handle})] => { - let compositor_state: &mut CompositorState = compositor.downcast(); - let (dx, dy) = motion_event.delta(); + use compositor_handle as compositor; + let state: &mut CompositorState = compositor.downcast(); + let (dx, dy) = motion_event.delta(); - compositor_state.cursor_handle - .run(|cursor| cursor.move_to(None, dx, dy)) - .unwrap(); - }) - .unwrap(); + let cursor_handle = &state.cursor_handle; + use cursor_handle as cursor; + cursor.move_to(None, dx, dy); } + + // TODO: implement on_button } diff --git a/src/main.rs b/src/main.rs index 9b61c4c..daa2c00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod input; mod output; +mod shells; use log::{info, warn, LevelFilter}; @@ -8,6 +9,8 @@ use wlroots::{ cursor::{self, xcursor, Cursor}, input::keyboard, output::layout, + seat::{self, Seat}, + shell::xdg_shell_v6, utils::log::Logger, }; @@ -18,10 +21,12 @@ struct ExOutputLayout; impl layout::Handler for ExOutputLayout {} struct CompositorState { - pub xcursor_manager: xcursor::Manager, - pub cursor_handle: cursor::Handle, - pub layout_handle: layout::Handle, - pub keyboards: Vec, + xcursor_manager: xcursor::Manager, + cursor_handle: cursor::Handle, + layout_handle: layout::Handle, + keyboards: Vec, + shells: Vec, + seat_handle: Option, } impl CompositorState { @@ -44,7 +49,9 @@ impl CompositorState { xcursor_manager: xcursor_manager, cursor_handle: cursor_handle, layout_handle: layout_handle, - keyboards: Vec::new(), + keyboards: vec![], + shells: vec![], + seat_handle: None, } } } @@ -56,11 +63,31 @@ fn main() { build_compositor().run(); } +struct SeatHandler; +impl seat::Handler for SeatHandler {} + fn build_compositor() -> compositor::Compositor { - compositor::Builder::new() + let mut compositor = compositor::Builder::new() .gles2(true) + .wl_shm(true) .data_device(true) .input_manager(input::build()) .output_manager(output::build()) - .build_auto(CompositorState::new()) + .xdg_shell_v6_manager(shells::xdg_v6::build()) + .build_auto(CompositorState::new()); + + let seat_handle = Seat::create( + &mut compositor, + String::from("seat0"), + Box::new(SeatHandler), + ); + + seat_handle + .run(|seat| seat.set_capabilities(seat::Capability::all())) + .unwrap(); + + let state: &mut CompositorState = compositor.downcast(); + state.seat_handle = Some(seat_handle); + + compositor } diff --git a/src/output/manager.rs b/src/output/manager.rs index b6aecc6..2770771 100644 --- a/src/output/manager.rs +++ b/src/output/manager.rs @@ -1,42 +1,41 @@ -use crate::CompositorState; +use crate::{output::Output, CompositorState}; use log::debug; -use wlroots::{compositor, output, with_handles}; +use wlroots::{compositor, output, wlroots_dehandle}; pub fn build() -> output::manager::Builder { output::manager::Builder::default().output_added(output_added) } -struct Output; - -impl output::Handler for Output {} - +#[wlroots_dehandle(compositor, layout, cursor, output)] fn output_added<'output>( compositor_handle: compositor::Handle, output_builder: output::Builder<'output>, ) -> Option> { debug!("Output added"); - let mut result = output_builder.build_best_mode(Output); - with_handles!([(compositor: {compositor_handle})] => { - let compositor_state: &mut CompositorState = compositor.data.downcast_mut().unwrap(); - let layout_handle = &mut compositor_state.layout_handle; - let cursor_handle = &mut compositor_state.cursor_handle; - let xcursor_manager = &mut compositor_state.xcursor_manager; - // TODO use output config if present instead of auto - with_handles!([ - (layout: {layout_handle}), - (cursor: {cursor_handle}), - (output: {&mut result.output}) - ] => { - layout.add_auto(output); - cursor.attach_output_layout(layout); - xcursor_manager.load(output.scale()); - xcursor_manager.set_cursor_image("left_ptr".to_string(), cursor); - let (x, y) = cursor.coords(); - cursor.warp(None, x, y); - }).unwrap(); - Some(result) - }) - .unwrap() + let result = output_builder.build_best_mode(Output); + + { + use compositor_handle as compositor; + let state: &mut CompositorState = compositor.data.downcast_mut().unwrap(); + + let xcursor_manager = &mut state.xcursor_manager; + let layout_handle = &state.layout_handle; + let cursor_handle = &state.cursor_handle; + let output_handle = &result.output; + + use cursor_handle as cursor; + use layout_handle as layout; + use output_handle as output; + + layout.add_auto(output); + cursor.attach_output_layout(layout); + xcursor_manager.load(output.scale()); + xcursor_manager.set_cursor_image("left_ptr".to_string(), cursor); + let (x, y) = cursor.coords(); + cursor.warp(None, x, y); + } + + Some(result) } diff --git a/src/output/mod.rs b/src/output/mod.rs index c9d7a66..5cb79fa 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -1,3 +1,6 @@ mod manager; +mod output; pub use self::manager::*; + +use self::output::*; diff --git a/src/output/output.rs b/src/output/output.rs new file mode 100644 index 0000000..18a5474 --- /dev/null +++ b/src/output/output.rs @@ -0,0 +1,62 @@ +use crate::CompositorState; + +use wlroots::{ + area::{Area, Origin, Size}, + compositor, output, + render::{matrix, Renderer}, + utils::current_time, + wlroots_dehandle, +}; + +pub struct Output; + +impl output::Handler for Output { + #[wlroots_dehandle(compositor, output)] + fn on_frame(&mut self, compositor_handle: compositor::Handle, output_handle: output::Handle) { + use compositor_handle as compositor; + use output_handle as output; + let state: &mut CompositorState = compositor.data.downcast_mut().unwrap(); + let renderer = compositor + .renderer + .as_mut() + .expect("Compositor was not loaded with a renderer"); + let mut render_context = renderer.render(output, None); + render_context.clear([0.45, 0.25, 0.25, 1.0]); + render_shells(state, &mut render_context) + } +} + +#[wlroots_dehandle(shell, surface, layout)] +fn render_shells(state: &mut CompositorState, renderer: &mut Renderer) { + let shells = state.shells.clone(); + let layout_handle = &state.layout_handle; + for shell_handle in shells { + use shell_handle as shell; + let surface_handle = shell.surface(); + use layout_handle as layout; + use surface_handle as surface; + let (width, height) = surface.current_state().size(); + let (render_width, render_height) = ( + width * renderer.output.scale() as i32, + height * renderer.output.scale() as i32, + ); + let (lx, ly) = (0.0, 0.0); + let render_box = Area::new( + Origin::new(lx as i32, ly as i32), + Size::new(render_width, render_height), + ); + if layout.intersects(renderer.output, render_box) { + let transform = renderer.output.get_transform().invert(); + let matrix = matrix::project_box( + render_box, + transform, + 0.0, + renderer.output.transform_matrix(), + ); + if let Some(texture) = surface.texture().as_ref() { + renderer.render_texture_with_matrix(texture, matrix); + } + surface.send_frame_done(current_time()); + } + } +} diff --git a/src/shells/mod.rs b/src/shells/mod.rs new file mode 100644 index 0000000..2f49118 --- /dev/null +++ b/src/shells/mod.rs @@ -0,0 +1 @@ +pub mod xdg_v6; diff --git a/src/shells/xdg_v6.rs b/src/shells/xdg_v6.rs new file mode 100644 index 0000000..b147878 --- /dev/null +++ b/src/shells/xdg_v6.rs @@ -0,0 +1,62 @@ +use crate::CompositorState; + +use log::debug; + +use wlroots::{compositor, shell::xdg_shell_v6, surface, utils::Handleable, wlroots_dehandle}; + +pub fn build() -> xdg_shell_v6::manager::Builder { + xdg_shell_v6::manager::Builder::default().surface_added(surface_added) +} + +struct XdgShellV6Handler; + +impl xdg_shell_v6::Handler for XdgShellV6Handler { + #[wlroots_dehandle(compositor)] + fn destroyed( + &mut self, + compositor_handle: compositor::Handle, + shell_handle: xdg_shell_v6::Handle, + ) { + use compositor_handle as compositor; + let state: &mut CompositorState = compositor.downcast(); + let weak = shell_handle; + + if let Some(index) = state.shells.iter().position(|s| *s == weak) { + state.shells.remove(index); + } + } +} + +struct Surface; + +impl surface::Handler for Surface { + fn on_commit(&mut self, _: compositor::Handle, surface_handle: surface::Handle) { + debug!("Commiting for surface {:?}", surface_handle); + } +} + +#[wlroots_dehandle(compositor, shell, layout, output)] +fn surface_added( + compositor_handle: compositor::Handle, + shell_handle: xdg_shell_v6::Handle, +) -> ( + Option>, + Option>, +) { + { + use compositor_handle as compositor; + use shell_handle as shell; + shell.ping(); + let state: &mut CompositorState = compositor.downcast(); + state.shells.push(shell.weak_reference()); + log::warn!("shells.len(): {}", state.shells.len()); + let layout_handle = &state.layout_handle; + use layout_handle as layout; + for (output_handle, _) in layout.outputs() { + use output_handle as output; + output.schedule_frame() + } + } + + (Some(Box::new(XdgShellV6Handler)), Some(Box::new(Surface))) +}