diff --git a/anvil/src/glium_drawer.rs b/anvil/src/glium_drawer.rs index b3d99a6..d2bc935 100644 --- a/anvil/src/glium_drawer.rs +++ b/anvil/src/glium_drawer.rs @@ -1,7 +1,7 @@ use std::{ cell::{Ref, RefCell}, rc::Rc, - sync::atomic::{AtomicUsize, Ordering}, + sync::atomic::{AtomicUsize, AtomicBool, Ordering}, }; use glium::{ @@ -14,6 +14,7 @@ use slog::Logger; use smithay::{ backend::graphics::{ + CursorBackend, gl::GLGraphicsBackend, glium::{Frame, GliumGraphicsBackend}, SwapBuffersError, @@ -56,6 +57,7 @@ pub struct GliumDrawer { index_buffer: glium::IndexBuffer, programs: [glium::Program; shaders::FRAGMENT_COUNT], buffer_loader: BufferUtils, + pub hardware_cursor: AtomicBool, log: Logger, } @@ -110,11 +112,90 @@ impl> + GLGraphicsBackend + 'static> GliumDrawer index_buffer, programs, buffer_loader, + hardware_cursor: AtomicBool::new(false), log, } } } +impl GliumDrawer { + pub fn draw_hardware_cursor( + &self, + cursor: &::CursorFormat, + hotspot: (u32, u32), + position: (i32, i32), + ) { + let (x, y) = position; + let _ = self.display.borrow().set_cursor_position(x as u32, y as u32); + if !self.hardware_cursor.swap(true, Ordering::SeqCst) { + if let Err(_) = self.display.borrow().set_cursor_representation(cursor, hotspot) { + warn!( + self.log, + "Failed to upload hardware cursor", + ); + } + } + } + + pub fn draw_software_cursor( + &self, + frame: &mut Frame, + surface: &wl_surface::WlSurface, + (x, y): (i32, i32), + token: MyCompositorToken, + ) { + let (dx, dy) = match token.with_role_data::(surface, |data| data.hotspot) { + Ok(h) => h, + Err(_) => { + warn!( + self.log, + "Trying to display as a cursor a surface that does not have the CursorImage role." + ); + (0, 0) + } + }; + let screen_dimensions = self.borrow().get_framebuffer_dimensions(); + self.draw_surface_tree(frame, surface, (x - dx, y - dy), token, screen_dimensions); + self.clear_cursor() + } + + pub fn clear_cursor(&self) { + if self.hardware_cursor.swap(false, Ordering::SeqCst) { + if let Err(_) = self.display.borrow().clear_cursor_representation() { + warn!(self.log, "Failed to clear cursor"); + } + } + } +} + +// I would love to do this, but this is essentially specialization... +// And since this is just an example compositor, it seems we require now, +// that for the use of software cursors we need the hardware cursor trait (to do automatic cleanup..) +/* +impl GliumDrawer { + pub fn draw_software_cursor( + &self, + frame: &mut Frame, + surface: &wl_surface::WlSurface, + (x, y): (i32, i32), + token: MyCompositorToken, + ) { + let (dx, dy) = match token.with_role_data::(surface, |data| data.hotspot) { + Ok(h) => h, + Err(_) => { + warn!( + self.log, + "Trying to display as a cursor a surface that does not have the CursorImage role." + ); + (0, 0) + } + }; + let screen_dimensions = self.borrow().get_framebuffer_dimensions(); + self.draw_surface_tree(frame, surface, (x - dx, y - dy), token, screen_dimensions); + } +} +*/ + impl GliumDrawer { pub fn render_texture(&self, target: &mut Frame, spec: RenderTextureSpec<'_>) { let xscale = 2.0 * (spec.surface_dimensions.0 as f32) / (spec.screen_size.0 as f32); @@ -288,27 +369,6 @@ impl GliumDrawer { } } - pub fn draw_cursor( - &self, - frame: &mut Frame, - surface: &wl_surface::WlSurface, - (x, y): (i32, i32), - token: MyCompositorToken, - ) { - let (dx, dy) = match token.with_role_data::(surface, |data| data.hotspot) { - Ok(h) => h, - Err(_) => { - warn!( - self.log, - "Trying to display as a cursor a surface that does not have the CursorImage role." - ); - (0, 0) - } - }; - let screen_dimensions = self.borrow().get_framebuffer_dimensions(); - self.draw_surface_tree(frame, surface, (x - dx, y - dy), token, screen_dimensions); - } - pub fn draw_dnd_icon( &self, frame: &mut Frame, diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 15ae828..f2fd041 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -5,7 +5,7 @@ use std::{ os::unix::io::{AsRawFd, RawFd}, path::PathBuf, rc::Rc, - sync::{atomic::{Ordering, AtomicBool}, Arc, Mutex}, + sync::{atomic::Ordering, Arc, Mutex}, time::Duration, }; @@ -45,7 +45,7 @@ use smithay::{ encoder::Info as EncoderInfo, }, }, - image::{ImageBuffer, Rgba, Pixel}, + image::{ImageBuffer, Rgba}, input::Libinput, nix::{fcntl::OFlag, sys::stat::dev_t}, wayland_server::{ @@ -435,7 +435,6 @@ impl UdevHandlerImpl { pointer_image: self.pointer_image.clone(), cursor_status: self.cursor_status.clone(), dnd_icon: self.dnd_icon.clone(), - hardware_cursor: AtomicBool::new(false), logger: self.logger.clone(), }); let mut listener = DrmRendererSessionListener { @@ -566,7 +565,6 @@ pub struct DrmRenderer { pointer_image: ImageBuffer, Vec>, cursor_status: Arc>, dnd_icon: Arc>>, - hardware_cursor: AtomicBool, logger: ::slog::Logger, } @@ -615,15 +613,11 @@ impl DrmRenderer { let ptr_y = ptr_y.trunc().abs() as i32 - y as i32; // set cursor - // TODO hack, should be possible to clear the cursor - let empty = ImageBuffer::from_fn(self.pointer_image.width(), self.pointer_image.height(), |_, _| Rgba::from_channels(0, 0, 0, 0)); - if ptr_x > 0 && ptr_x < width as i32 && ptr_y > 0 && ptr_y < height as i32 { + if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 { let _ = drawer .borrow() .set_cursor_position(ptr_x as u32, ptr_y as u32); - let mut needs_software_cursor = false; - // draw the dnd icon if applicable { let guard = self.dnd_icon.lock().unwrap(); @@ -635,7 +629,6 @@ impl DrmRenderer { (ptr_x, ptr_y), self.compositor_token, ); - //needs_software_cursor = true; } } } @@ -651,26 +644,13 @@ impl DrmRenderer { *guard = CursorImageStatus::Default; } if let CursorImageStatus::Image(ref surface) = *guard { - drawer.draw_cursor(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token); - needs_software_cursor = true; - } - } - - if needs_software_cursor && self.hardware_cursor.swap(false, Ordering::AcqRel) { - if let Err(err) = drawer.borrow().set_cursor_representation(&empty, (0, 0)) { - error!(self.logger, "Error setting cursor: {}", err); - } - } else if !needs_software_cursor && !self.hardware_cursor.swap(true, Ordering::AcqRel) { - if let Err(err) = drawer.borrow().set_cursor_representation(&self.pointer_image, (2, 2)) { - error!(self.logger, "Error setting cursor: {}", err); + drawer.draw_software_cursor(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token); + } else { + drawer.draw_hardware_cursor(&self.pointer_image, (2, 2), (ptr_x, ptr_y)); } } } else { - if self.hardware_cursor.swap(false, Ordering::AcqRel) { - if let Err(err) = drawer.borrow().set_cursor_representation(&empty, (0, 0)) { - error!(self.logger, "Error setting cursor: {}", err); - } - } + drawer.clear_cursor(); } if let Err(err) = frame.finish() { diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 9432d59..104286d 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -5,6 +5,7 @@ use smithay::{ reexports::{ calloop::EventLoop, wayland_server::{protocol::wl_output, Display}, + winit::window::CursorIcon, }, wayland::{ output::{Mode, Output, PhysicalProperties}, @@ -128,7 +129,9 @@ pub fn run_winit( } // draw as relevant if let CursorImageStatus::Image(ref surface) = *guard { - drawer.draw_cursor(&mut frame, surface, (x as i32, y as i32), state.ctoken); + drawer.draw_software_cursor(&mut frame, surface, (x as i32, y as i32), state.ctoken); + } else { + drawer.draw_hardware_cursor(&CursorIcon::Default, (0, 0), (x as i32, y as i32)); } }