Basic xdg_shell_v6 handling

This commit is contained in:
buffet 2019-01-31 16:37:27 +01:00
parent cea9ecfc61
commit 1fc2bdc8a8
9 changed files with 262 additions and 75 deletions

View file

@ -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();
}
_ => {}
}
@ -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,
);
}
}

View file

@ -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");
with_handles!([(compositor: {compositor_handle})] => {
let compositor_state: &mut CompositorState = compositor.data.downcast_mut().unwrap();
compositor_state.keyboards.push(keyboard_handle);
})
.unwrap();
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);
}
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");
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();
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());
}
Some(Box::new(Pointer))
}

View file

@ -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();
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();
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
}

View file

@ -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
}

View file

@ -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})
] => {
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);
}).unwrap();
}
Some(result)
})
.unwrap()
}

View file

@ -1,3 +1,6 @@
mod manager;
mod output;
pub use self::manager::*;
use self::output::*;

62
src/output/output.rs Normal file
View 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
View file

@ -0,0 +1 @@
pub mod xdg_v6;

62
src/shells/xdg_v6.rs Normal file
View 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)))
}