Winit pointer drawing, start on udev backend

This commit is contained in:
Seaotatop 2023-06-07 12:12:54 -05:00
parent e3b65456d6
commit 8f5c55d3a0
7 changed files with 229 additions and 52 deletions

View file

@ -9,3 +9,6 @@ edition = "2021"
tracing = "0.1.37" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
smithay = { git = "https://github.com/Smithay/smithay" } smithay = { git = "https://github.com/Smithay/smithay" }
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", optional = true }
thiserror = "1.0.40"
xcursor = { version = "0.3.4", optional = true }

View file

@ -1,5 +1,6 @@
use smithay::{output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface}; use smithay::{output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface};
pub mod udev;
pub mod winit; pub mod winit;
/// A trait defining common methods for each available backend: winit and tty-udev /// A trait defining common methods for each available backend: winit and tty-udev

View file

@ -1,4 +1,9 @@
use std::{error::Error, os::fd::AsRawFd, sync::Arc, time::Duration}; use std::{
error::Error,
os::fd::AsRawFd,
sync::{Arc, Mutex},
time::Duration,
};
use smithay::{ use smithay::{
backend::{ backend::{
@ -6,8 +11,11 @@ use smithay::{
egl::EGLDevice, egl::EGLDevice,
renderer::{ renderer::{
damage::{self, OutputDamageTracker}, damage::{self, OutputDamageTracker},
element::default_primary_scanout_output_compare, element::{
gles::GlesRenderer, default_primary_scanout_output_compare, surface::WaylandSurfaceRenderElement,
AsRenderElements,
},
gles::{GlesRenderer, GlesTexture},
ImportDma, ImportMemWl, ImportDma, ImportMemWl,
}, },
winit::{WinitError, WinitEvent, WinitGraphicsBackend}, winit::{WinitError, WinitEvent, WinitGraphicsBackend},
@ -16,9 +24,12 @@ use smithay::{
desktop::{ desktop::{
space, space,
utils::{surface_primary_scanout_output, update_surface_primary_scanout_output}, utils::{surface_primary_scanout_output, update_surface_primary_scanout_output},
Space, Window, PopupManager, Space, Window,
},
input::{
pointer::{CursorImageAttributes, CursorImageStatus},
SeatState,
}, },
input::{pointer::CursorImageStatus, SeatState},
output::{Output, Subpixel}, output::{Output, Subpixel},
reexports::{ reexports::{
calloop::{ calloop::{
@ -28,9 +39,9 @@ use smithay::{
}, },
wayland_server::{protocol::wl_surface::WlSurface, Display}, wayland_server::{protocol::wl_surface::WlSurface, Display},
}, },
utils::{Clock, Monotonic, Physical, Point, Scale, Transform}, utils::{Clock, IsAlive, Monotonic, Physical, Point, Scale, Transform},
wayland::{ wayland::{
compositor::CompositorState, compositor::{self, CompositorState},
data_device::DataDeviceState, data_device::DataDeviceState,
dmabuf::{ dmabuf::{
DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState, DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState,
@ -45,7 +56,11 @@ use smithay::{
}, },
}; };
use crate::state::{CalloopData, ClientState, State}; use crate::{
layout::{Direction, Layout},
render::{pointer::PointerElement, CustomRenderElements, OutputRenderElements},
state::{CalloopData, ClientState, State},
};
use super::Backend; use super::Backend;
@ -214,10 +229,10 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
compositor_state: CompositorState::new::<State<WinitData>>(&display_handle), compositor_state: CompositorState::new::<State<WinitData>>(&display_handle),
data_device_state: DataDeviceState::new::<State<WinitData>>(&display_handle), data_device_state: DataDeviceState::new::<State<WinitData>>(&display_handle),
seat_state, seat_state,
shm_state: ShmState::new::<State<WinitData>>(&display_handle, Vec::new()), pointer_location: (0.0, 0.0).into(),
shm_state: ShmState::new::<State<WinitData>>(&display_handle, vec![]),
space: Space::<Window>::default(), space: Space::<Window>::default(),
cursor_status: CursorImageStatus::Default, cursor_status: CursorImageStatus::Default,
pointer_location: (0.0, 0.0).into(),
output_manager_state: OutputManagerState::new_with_xdg_output::<State<WinitData>>( output_manager_state: OutputManagerState::new_with_xdg_output::<State<WinitData>>(
&display_handle, &display_handle,
), ),
@ -229,6 +244,8 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
move_mode: false, move_mode: false,
socket_name: socket_name.clone(), socket_name: socket_name.clone(),
popup_manager: PopupManager::default(),
}; };
state state
@ -239,6 +256,8 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
std::env::set_var("WAYLAND_DISPLAY", socket_name); std::env::set_var("WAYLAND_DISPLAY", socket_name);
let mut pointer_element = PointerElement::<GlesTexture>::new();
// TODO: pointer // TODO: pointer
evt_loop_handle.insert_source(Timer::immediate(), move |_instant, _metadata, data| { evt_loop_handle.insert_source(Timer::immediate(), move |_instant, _metadata, data| {
let display = &mut data.display; let display = &mut data.display;
@ -258,6 +277,11 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
None, None,
None, None,
); );
Layout::master_stack(
state,
state.space.elements().cloned().collect(),
Direction::Left,
);
} }
WinitEvent::Focus(_) => {} WinitEvent::Focus(_) => {}
WinitEvent::Input(input_evt) => { WinitEvent::Input(input_evt) => {
@ -273,9 +297,50 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
} }
}; };
if let CursorImageStatus::Surface(ref surface) = state.cursor_status {
if !surface.alive() {
state.cursor_status = CursorImageStatus::Default;
}
}
let cursor_visible = !matches!(state.cursor_status, CursorImageStatus::Surface(_));
pointer_element.set_status(state.cursor_status.clone());
let full_redraw = &mut state.backend_data.full_redraw; let full_redraw = &mut state.backend_data.full_redraw;
*full_redraw = full_redraw.saturating_sub(1); *full_redraw = full_redraw.saturating_sub(1);
let scale = Scale::from(output.current_scale().fractional_scale());
let cursor_hotspot = if let CursorImageStatus::Surface(ref surface) = state.cursor_status {
compositor::with_states(surface, |states| {
states
.data_map
.get::<Mutex<CursorImageAttributes>>()
.unwrap()
.lock()
.unwrap()
.hotspot
})
} else {
(0, 0).into()
};
let cursor_pos = state.pointer_location - cursor_hotspot.to_f64();
let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round::<i32>();
let mut custom_render_elements = Vec::<CustomRenderElements<GlesRenderer>>::new();
custom_render_elements.extend(pointer_element.render_elements(
state.backend_data.backend.renderer(),
cursor_pos_scaled,
scale,
1.0,
));
tracing::info!(
"custom_render_elements len = {}",
custom_render_elements.len()
);
let render_res = state.backend_data.backend.bind().and_then(|_| { let render_res = state.backend_data.backend.bind().and_then(|_| {
let age = if *full_redraw > 0 { let age = if *full_redraw > 0 {
0 0
@ -286,9 +351,24 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
let renderer = state.backend_data.backend.renderer(); let renderer = state.backend_data.backend.renderer();
// render_output() // render_output()
let output_render_elements = let space_render_elements =
space::space_render_elements(renderer, [&state.space], &output, 1.0).unwrap(); space::space_render_elements(renderer, [&state.space], &output, 1.0).unwrap();
let mut output_render_elements = Vec::<
OutputRenderElements<GlesRenderer, WaylandSurfaceRenderElement<GlesRenderer>>,
>::new();
output_render_elements.extend(
custom_render_elements
.into_iter()
.map(OutputRenderElements::from),
);
output_render_elements.extend(
space_render_elements
.into_iter()
.map(OutputRenderElements::from),
);
state state
.backend_data .backend_data
.damage_tracker .damage_tracker
@ -307,6 +387,13 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
tracing::warn!("{}", err); tracing::warn!("{}", err);
} }
} }
state
.backend_data
.backend
.window()
.set_cursor_visible(cursor_visible);
let throttle = Some(Duration::from_secs(1)); let throttle = Some(Duration::from_secs(1));
state.space.elements().for_each(|window| { state.space.elements().for_each(|window| {
@ -347,13 +434,11 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
} }
} }
let scale = Scale::from(output.current_scale().fractional_scale());
let cursor_pos = state.pointer_location;
let _cursor_pos_scaled: Point<i32, Physical> = cursor_pos.to_physical(scale).to_i32_round();
state.space.refresh(); state.space.refresh();
state.popup_manager.cleanup();
display.flush_clients().unwrap(); display
.flush_clients()
.expect("failed to flush client buffers");
TimeoutAction::ToDuration(Duration::from_millis(6)) TimeoutAction::ToDuration(Duration::from_millis(6))
})?; })?;

View file

@ -2,8 +2,14 @@ use smithay::{
backend::renderer::utils, backend::renderer::utils,
delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_output, delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_output,
delegate_seat, delegate_shm, delegate_viewporter, delegate_xdg_shell, delegate_seat, delegate_shm, delegate_viewporter, delegate_xdg_shell,
desktop::Window, desktop::{
input::{pointer::CursorImageStatus, Seat, SeatHandler, SeatState}, find_popup_root_surface, PopupKeyboardGrab, PopupKind, PopupManager, PopupPointerGrab,
PopupUngrabStrategy, Space, Window,
},
input::{
pointer::{CursorImageStatus, Focus},
Seat, SeatHandler, SeatState,
},
reexports::{ reexports::{
calloop::Interest, calloop::Interest,
wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge, wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
@ -25,8 +31,8 @@ use smithay::{
dmabuf, dmabuf,
fractional_scale::{self, FractionalScaleHandler}, fractional_scale::{self, FractionalScaleHandler},
shell::xdg::{ shell::xdg::{
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData,
XdgShellState, XdgToplevelSurfaceData, XdgShellHandler, XdgShellState, XdgToplevelSurfaceData,
}, },
shm::{ShmHandler, ShmState}, shm::{ShmHandler, ShmState},
}, },
@ -93,27 +99,9 @@ impl<B: Backend> CompositorHandler for State<B> {
} }
}; };
if let Some(window) = self.window_for_surface(surface) { self.popup_manager.commit(surface);
let initial_configure_sent = compositor::with_states(surface, |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap()
.initial_configure_sent
});
// println!("initial_configure_sent is {}", initial_configure_sent);
if !initial_configure_sent { ensure_initial_configure(surface, self);
println!("initial configure");
window.toplevel().send_configure();
// println!(
// "ensured_configured: {}",
// window.toplevel().ensure_configured()
// );
}
}
crate::grab::resize_grab::handle_commit(self, surface); crate::grab::resize_grab::handle_commit(self, surface);
} }
@ -123,6 +111,44 @@ impl<B: Backend> CompositorHandler for State<B> {
} }
} }
delegate_compositor!(@<B: Backend> State<B>); delegate_compositor!(@<B: Backend> State<B>);
fn ensure_initial_configure<B: Backend>(surface: &WlSurface, state: &mut State<B>) {
if let Some(window) = state.window_for_surface(surface) {
let initial_configure_sent = compositor::with_states(surface, |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap()
.initial_configure_sent
});
// println!("initial_configure_sent is {}", initial_configure_sent);
if !initial_configure_sent {
window.toplevel().send_configure();
}
return;
}
if let Some(popup) = state.popup_manager.find_popup(surface) {
let PopupKind::Xdg(ref popup) = popup;
let initial_configure_sent = compositor::with_states(surface, |states| {
states
.data_map
.get::<XdgPopupSurfaceData>()
.unwrap()
.lock()
.unwrap()
.initial_configure_sent
});
if !initial_configure_sent {
popup
.send_configure()
.expect("popup initial configure failed");
}
}
// TODO: layer map thingys
}
impl<B: Backend> ClientDndGrabHandler for State<B> {} impl<B: Backend> ClientDndGrabHandler for State<B> {}
impl<B: Backend> ServerDndGrabHandler for State<B> {} impl<B: Backend> ServerDndGrabHandler for State<B> {}
@ -136,7 +162,7 @@ impl<B: Backend> DataDeviceHandler for State<B> {
} }
delegate_data_device!(@<B: Backend> State<B>); delegate_data_device!(@<B: Backend> State<B>);
impl<B: Backend + 'static> SeatHandler for State<B> { impl<B: Backend> SeatHandler for State<B> {
type KeyboardFocus = WlSurface; type KeyboardFocus = WlSurface;
type PointerFocus = WlSurface; type PointerFocus = WlSurface;
@ -145,6 +171,7 @@ impl<B: Backend + 'static> SeatHandler for State<B> {
} }
fn cursor_image(&mut self, _seat: &Seat<Self>, image: CursorImageStatus) { fn cursor_image(&mut self, _seat: &Seat<Self>, image: CursorImageStatus) {
tracing::info!("new cursor image: {:?}", image);
self.cursor_status = image; self.cursor_status = image;
} }
@ -177,7 +204,11 @@ impl<B: Backend> XdgShellHandler for State<B> {
Layout::master_stack(self, windows, crate::layout::Direction::Left); Layout::master_stack(self, windows, crate::layout::Direction::Left);
} }
fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) {} fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) {
if let Err(err) = self.popup_manager.track_popup(PopupKind::from(surface)) {
tracing::warn!("failed to track popup: {}", err);
}
}
fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) { fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) {
crate::xdg::request::move_request( crate::xdg::request::move_request(
@ -206,7 +237,58 @@ impl<B: Backend> XdgShellHandler for State<B> {
); );
} }
fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) {} fn reposition_request(
&mut self,
surface: PopupSurface,
positioner: PositionerState,
token: u32,
) {
surface.with_pending_state(|state| {
state.geometry = positioner.get_geometry();
state.positioner = positioner;
});
surface.send_repositioned(token);
}
fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) {
let seat: Seat<State<B>> = Seat::from_resource(&seat).unwrap();
let popup_kind = PopupKind::Xdg(surface);
if let Some(root) = find_popup_root_surface(&popup_kind)
.ok()
.and_then(|root| self.window_for_surface(&root))
{
if let Ok(mut grab) = self.popup_manager.grab_popup(
root.toplevel().wl_surface().clone(),
popup_kind,
&seat,
serial,
) {
if let Some(keyboard) = seat.get_keyboard() {
if keyboard.is_grabbed()
&& !(keyboard.has_grab(serial)
|| keyboard.has_grab(grab.previous_serial().unwrap_or(serial)))
{
grab.ungrab(PopupUngrabStrategy::All);
return;
}
keyboard.set_focus(self, grab.current_grab(), serial);
keyboard.set_grab(PopupKeyboardGrab::new(&grab), serial);
}
if let Some(pointer) = seat.get_pointer() {
if pointer.is_grabbed()
&& !(pointer.has_grab(serial)
|| pointer
.has_grab(grab.previous_serial().unwrap_or_else(|| grab.serial())))
{
grab.ungrab(PopupUngrabStrategy::All);
return;
}
pointer.set_grab(self, PopupPointerGrab::new(&grab), serial, Focus::Keep);
}
}
}
}
fn ack_configure(&mut self, surface: WlSurface, configure: Configure) { fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
// println!("surface ack_configure: {:?}", configure); // println!("surface ack_configure: {:?}", configure);

View file

@ -86,6 +86,8 @@ impl State<WinitData> {
let serial = SERIAL_COUNTER.next_serial(); let serial = SERIAL_COUNTER.next_serial();
let pointer = seat.get_pointer().unwrap(); let pointer = seat.get_pointer().unwrap();
self.pointer_location = pointer_loc;
let surface_under_pointer = let surface_under_pointer =
self.space self.space
.element_under(pointer_loc) .element_under(pointer_loc)
@ -268,7 +270,6 @@ impl State<WinitData> {
frame = frame.stop(Axis::Vertical); frame = frame.stop(Axis::Vertical);
} }
println!("axisframe: {:?}", frame);
pointer.axis(self, frame); pointer.axis(self, frame);
} }

View file

@ -4,7 +4,7 @@ mod handlers;
mod input; mod input;
mod layout; mod layout;
mod pointer; mod pointer;
mod shell; mod render;
mod state; mod state;
mod tag; mod tag;
mod window; mod window;

View file

@ -1,7 +1,7 @@
use std::ffi::OsString; use std::ffi::OsString;
use smithay::{ use smithay::{
desktop::{Space, Window}, desktop::{PopupManager, Space, Window},
input::{pointer::CursorImageStatus, SeatState}, input::{pointer::CursorImageStatus, SeatState},
reexports::{ reexports::{
calloop::{LoopHandle, LoopSignal}, calloop::{LoopHandle, LoopSignal},
@ -28,23 +28,28 @@ use crate::backend::{winit::WinitData, Backend};
pub struct State<B: Backend> { pub struct State<B: Backend> {
pub backend_data: B, pub backend_data: B,
pub loop_signal: LoopSignal, pub loop_signal: LoopSignal,
pub loop_handle: LoopHandle<'static, CalloopData>, pub loop_handle: LoopHandle<'static, CalloopData>,
pub clock: Clock<Monotonic>, pub clock: Clock<Monotonic>,
pub space: Space<Window>,
pub move_mode: bool,
pub socket_name: OsString,
pub compositor_state: CompositorState, pub compositor_state: CompositorState,
pub data_device_state: DataDeviceState, pub data_device_state: DataDeviceState,
pub seat_state: SeatState<Self>, pub seat_state: SeatState<Self>,
pub shm_state: ShmState, pub shm_state: ShmState,
pub space: Space<Window>,
pub cursor_status: CursorImageStatus,
pub pointer_location: Point<f64, Logical>,
pub output_manager_state: OutputManagerState, pub output_manager_state: OutputManagerState,
pub xdg_shell_state: XdgShellState, pub xdg_shell_state: XdgShellState,
pub viewporter_state: ViewporterState, pub viewporter_state: ViewporterState,
pub fractional_scale_manager_state: FractionalScaleManagerState, pub fractional_scale_manager_state: FractionalScaleManagerState,
pub move_mode: bool, pub popup_manager: PopupManager,
pub socket_name: OsString,
pub cursor_status: CursorImageStatus,
pub pointer_location: Point<f64, Logical>,
} }
impl<B: Backend> State<B> { impl<B: Backend> State<B> {