Basic xdg_shell_v6 handling
This commit is contained in:
parent
cea9ecfc61
commit
1fc2bdc8a8
9 changed files with 262 additions and 75 deletions
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Box<keyboard::Handler>> {
|
||||
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<Box<pointer::Handler>> {
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
41
src/main.rs
41
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<keyboard::Handle>,
|
||||
xcursor_manager: xcursor::Manager,
|
||||
cursor_handle: cursor::Handle,
|
||||
layout_handle: layout::Handle,
|
||||
keyboards: Vec<keyboard::Handle>,
|
||||
shells: Vec<xdg_shell_v6::Handle>,
|
||||
seat_handle: Option<seat::Handle>,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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<output::BuilderResult<'output>> {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
mod manager;
|
||||
mod output;
|
||||
|
||||
pub use self::manager::*;
|
||||
|
||||
use self::output::*;
|
||||
|
|
62
src/output/output.rs
Normal file
62
src/output/output.rs
Normal file
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
1
src/shells/mod.rs
Normal file
1
src/shells/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod xdg_v6;
|
62
src/shells/xdg_v6.rs
Normal file
62
src/shells/xdg_v6.rs
Normal file
|
@ -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<Box<xdg_shell_v6::Handler>>,
|
||||
Option<Box<surface::Handler>>,
|
||||
) {
|
||||
{
|
||||
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)))
|
||||
}
|
Loading…
Reference in a new issue