anvil: GliumDrawer handle hardware cursors and track state
This commit is contained in:
parent
a1f14cb571
commit
3fd336aba5
|
@ -1,7 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell},
|
cell::{Ref, RefCell},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
sync::atomic::{AtomicUsize, AtomicBool, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
use glium::{
|
use glium::{
|
||||||
|
@ -14,6 +14,7 @@ use slog::Logger;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::graphics::{
|
backend::graphics::{
|
||||||
|
CursorBackend,
|
||||||
gl::GLGraphicsBackend,
|
gl::GLGraphicsBackend,
|
||||||
glium::{Frame, GliumGraphicsBackend},
|
glium::{Frame, GliumGraphicsBackend},
|
||||||
SwapBuffersError,
|
SwapBuffersError,
|
||||||
|
@ -56,6 +57,7 @@ pub struct GliumDrawer<F: GLGraphicsBackend + 'static> {
|
||||||
index_buffer: glium::IndexBuffer<u16>,
|
index_buffer: glium::IndexBuffer<u16>,
|
||||||
programs: [glium::Program; shaders::FRAGMENT_COUNT],
|
programs: [glium::Program; shaders::FRAGMENT_COUNT],
|
||||||
buffer_loader: BufferUtils,
|
buffer_loader: BufferUtils,
|
||||||
|
pub hardware_cursor: AtomicBool,
|
||||||
log: Logger,
|
log: Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,11 +112,90 @@ impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer
|
||||||
index_buffer,
|
index_buffer,
|
||||||
programs,
|
programs,
|
||||||
buffer_loader,
|
buffer_loader,
|
||||||
|
hardware_cursor: AtomicBool::new(false),
|
||||||
log,
|
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> {
|
impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||||
pub fn render_texture(&self, target: &mut Frame, spec: RenderTextureSpec<'_>) {
|
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);
|
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(
|
pub fn draw_dnd_icon(
|
||||||
&self,
|
&self,
|
||||||
frame: &mut Frame,
|
frame: &mut Frame,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
os::unix::io::{AsRawFd, RawFd},
|
os::unix::io::{AsRawFd, RawFd},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{atomic::{Ordering, AtomicBool}, Arc, Mutex},
|
sync::{atomic::Ordering, Arc, Mutex},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ use smithay::{
|
||||||
encoder::Info as EncoderInfo,
|
encoder::Info as EncoderInfo,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
image::{ImageBuffer, Rgba, Pixel},
|
image::{ImageBuffer, Rgba},
|
||||||
input::Libinput,
|
input::Libinput,
|
||||||
nix::{fcntl::OFlag, sys::stat::dev_t},
|
nix::{fcntl::OFlag, sys::stat::dev_t},
|
||||||
wayland_server::{
|
wayland_server::{
|
||||||
|
@ -435,7 +435,6 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||||
pointer_image: self.pointer_image.clone(),
|
pointer_image: self.pointer_image.clone(),
|
||||||
cursor_status: self.cursor_status.clone(),
|
cursor_status: self.cursor_status.clone(),
|
||||||
dnd_icon: self.dnd_icon.clone(),
|
dnd_icon: self.dnd_icon.clone(),
|
||||||
hardware_cursor: AtomicBool::new(false),
|
|
||||||
logger: self.logger.clone(),
|
logger: self.logger.clone(),
|
||||||
});
|
});
|
||||||
let mut listener = DrmRendererSessionListener {
|
let mut listener = DrmRendererSessionListener {
|
||||||
|
@ -566,7 +565,6 @@ pub struct DrmRenderer {
|
||||||
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
|
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
|
||||||
cursor_status: Arc<Mutex<CursorImageStatus>>,
|
cursor_status: Arc<Mutex<CursorImageStatus>>,
|
||||||
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
|
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
|
||||||
hardware_cursor: AtomicBool,
|
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,15 +613,11 @@ impl DrmRenderer {
|
||||||
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
|
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
|
||||||
|
|
||||||
// set cursor
|
// set cursor
|
||||||
// TODO hack, should be possible to clear the cursor
|
if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
|
||||||
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 {
|
|
||||||
let _ = drawer
|
let _ = drawer
|
||||||
.borrow()
|
.borrow()
|
||||||
.set_cursor_position(ptr_x as u32, ptr_y as u32);
|
.set_cursor_position(ptr_x as u32, ptr_y as u32);
|
||||||
|
|
||||||
let mut needs_software_cursor = false;
|
|
||||||
|
|
||||||
// draw the dnd icon if applicable
|
// draw the dnd icon if applicable
|
||||||
{
|
{
|
||||||
let guard = self.dnd_icon.lock().unwrap();
|
let guard = self.dnd_icon.lock().unwrap();
|
||||||
|
@ -635,7 +629,6 @@ impl DrmRenderer {
|
||||||
(ptr_x, ptr_y),
|
(ptr_x, ptr_y),
|
||||||
self.compositor_token,
|
self.compositor_token,
|
||||||
);
|
);
|
||||||
//needs_software_cursor = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -651,26 +644,13 @@ impl DrmRenderer {
|
||||||
*guard = CursorImageStatus::Default;
|
*guard = CursorImageStatus::Default;
|
||||||
}
|
}
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
drawer.draw_cursor(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token);
|
drawer.draw_software_cursor(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token);
|
||||||
needs_software_cursor = true;
|
} else {
|
||||||
}
|
drawer.draw_hardware_cursor(&self.pointer_image, (2, 2), (ptr_x, ptr_y));
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.hardware_cursor.swap(false, Ordering::AcqRel) {
|
drawer.clear_cursor();
|
||||||
if let Err(err) = drawer.borrow().set_cursor_representation(&empty, (0, 0)) {
|
|
||||||
error!(self.logger, "Error setting cursor: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = frame.finish() {
|
if let Err(err) = frame.finish() {
|
||||||
|
|
|
@ -5,6 +5,7 @@ use smithay::{
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::EventLoop,
|
calloop::EventLoop,
|
||||||
wayland_server::{protocol::wl_output, Display},
|
wayland_server::{protocol::wl_output, Display},
|
||||||
|
winit::window::CursorIcon,
|
||||||
},
|
},
|
||||||
wayland::{
|
wayland::{
|
||||||
output::{Mode, Output, PhysicalProperties},
|
output::{Mode, Output, PhysicalProperties},
|
||||||
|
@ -128,7 +129,9 @@ pub fn run_winit(
|
||||||
}
|
}
|
||||||
// draw as relevant
|
// draw as relevant
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
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