anvil: GliumDrawer handle hardware cursors and track state
This commit is contained in:
parent
a1f14cb571
commit
3fd336aba5
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue