anvil: GliumDrawer handle hardware cursors and track state

This commit is contained in:
Victor Brekenfeld 2020-06-27 23:59:10 +02:00
parent a1f14cb571
commit 3fd336aba5
3 changed files with 93 additions and 50 deletions

View File

@ -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<F: GLGraphicsBackend + 'static> {
index_buffer: glium::IndexBuffer<u16>,
programs: [glium::Program; shaders::FRAGMENT_COUNT],
buffer_loader: BufferUtils,
pub hardware_cursor: AtomicBool,
log: Logger,
}
@ -110,11 +112,90 @@ impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer
index_buffer,
programs,
buffer_loader,
hardware_cursor: AtomicBool::new(false),
log,
}
}
}
impl<F: GLGraphicsBackend + CursorBackend + 'static> GliumDrawer<F> {
pub fn draw_hardware_cursor(
&self,
cursor: &<F as CursorBackend>::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::<CursorImageRole, _, _>(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<F: GLGraphicsBackend + !CursorBackend + 'static> GliumDrawer<F> {
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::<CursorImageRole, _, _>(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<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
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<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
}
}
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::<CursorImageRole, _, _>(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,

View File

@ -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<Data: 'static> UdevHandlerImpl<Data> {
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<Rgba<u8>, Vec<u8>>,
cursor_status: Arc<Mutex<CursorImageStatus>>,
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
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() {

View File

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