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-subscriber = { version = "0.3.17", features = ["env-filter"] }
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};
pub mod udev;
pub mod winit;
/// 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::{
backend::{
@ -6,8 +11,11 @@ use smithay::{
egl::EGLDevice,
renderer::{
damage::{self, OutputDamageTracker},
element::default_primary_scanout_output_compare,
gles::GlesRenderer,
element::{
default_primary_scanout_output_compare, surface::WaylandSurfaceRenderElement,
AsRenderElements,
},
gles::{GlesRenderer, GlesTexture},
ImportDma, ImportMemWl,
},
winit::{WinitError, WinitEvent, WinitGraphicsBackend},
@ -16,9 +24,12 @@ use smithay::{
desktop::{
space,
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},
reexports::{
calloop::{
@ -28,9 +39,9 @@ use smithay::{
},
wayland_server::{protocol::wl_surface::WlSurface, Display},
},
utils::{Clock, Monotonic, Physical, Point, Scale, Transform},
utils::{Clock, IsAlive, Monotonic, Physical, Point, Scale, Transform},
wayland::{
compositor::CompositorState,
compositor::{self, CompositorState},
data_device::DataDeviceState,
dmabuf::{
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;
@ -214,10 +229,10 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
compositor_state: CompositorState::new::<State<WinitData>>(&display_handle),
data_device_state: DataDeviceState::new::<State<WinitData>>(&display_handle),
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(),
cursor_status: CursorImageStatus::Default,
pointer_location: (0.0, 0.0).into(),
output_manager_state: OutputManagerState::new_with_xdg_output::<State<WinitData>>(
&display_handle,
),
@ -229,6 +244,8 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
move_mode: false,
socket_name: socket_name.clone(),
popup_manager: PopupManager::default(),
};
state
@ -239,6 +256,8 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
std::env::set_var("WAYLAND_DISPLAY", socket_name);
let mut pointer_element = PointerElement::<GlesTexture>::new();
// TODO: pointer
evt_loop_handle.insert_source(Timer::immediate(), move |_instant, _metadata, data| {
let display = &mut data.display;
@ -258,6 +277,11 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
None,
None,
);
Layout::master_stack(
state,
state.space.elements().cloned().collect(),
Direction::Left,
);
}
WinitEvent::Focus(_) => {}
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;
*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 age = if *full_redraw > 0 {
0
@ -286,9 +351,24 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
let renderer = state.backend_data.backend.renderer();
// render_output()
let output_render_elements =
let space_render_elements =
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
.backend_data
.damage_tracker
@ -307,6 +387,13 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
tracing::warn!("{}", err);
}
}
state
.backend_data
.backend
.window()
.set_cursor_visible(cursor_visible);
let throttle = Some(Duration::from_secs(1));
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();
display.flush_clients().unwrap();
state.popup_manager.cleanup();
display
.flush_clients()
.expect("failed to flush client buffers");
TimeoutAction::ToDuration(Duration::from_millis(6))
})?;

View file

@ -2,8 +2,14 @@ use smithay::{
backend::renderer::utils,
delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_output,
delegate_seat, delegate_shm, delegate_viewporter, delegate_xdg_shell,
desktop::Window,
input::{pointer::CursorImageStatus, Seat, SeatHandler, SeatState},
desktop::{
find_popup_root_surface, PopupKeyboardGrab, PopupKind, PopupManager, PopupPointerGrab,
PopupUngrabStrategy, Space, Window,
},
input::{
pointer::{CursorImageStatus, Focus},
Seat, SeatHandler, SeatState,
},
reexports::{
calloop::Interest,
wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
@ -25,8 +31,8 @@ use smithay::{
dmabuf,
fractional_scale::{self, FractionalScaleHandler},
shell::xdg::{
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler,
XdgShellState, XdgToplevelSurfaceData,
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData,
XdgShellHandler, XdgShellState, XdgToplevelSurfaceData,
},
shm::{ShmHandler, ShmState},
},
@ -93,7 +99,20 @@ impl<B: Backend> CompositorHandler for State<B> {
}
};
if let Some(window) = self.window_for_surface(surface) {
self.popup_manager.commit(surface);
ensure_initial_configure(surface, self);
crate::grab::resize_grab::handle_commit(self, surface);
}
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
&client.get_data::<ClientState>().unwrap().compositor_state
}
}
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
@ -106,23 +125,30 @@ impl<B: Backend> CompositorHandler for State<B> {
// println!("initial_configure_sent is {}", initial_configure_sent);
if !initial_configure_sent {
println!("initial configure");
window.toplevel().send_configure();
// println!(
// "ensured_configured: {}",
// window.toplevel().ensure_configured()
// );
}
return;
}
crate::grab::resize_grab::handle_commit(self, surface);
}
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
&client.get_data::<ClientState>().unwrap().compositor_state
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");
}
}
delegate_compositor!(@<B: Backend> State<B>);
// TODO: layer map thingys
}
impl<B: Backend> ClientDndGrabHandler 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>);
impl<B: Backend + 'static> SeatHandler for State<B> {
impl<B: Backend> SeatHandler for State<B> {
type KeyboardFocus = 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) {
tracing::info!("new cursor image: {:?}", 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);
}
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) {
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) {
// println!("surface ack_configure: {:?}", configure);

View file

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

View file

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

View file

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