anvil: draw custom cursors and dnd icons
This commit is contained in:
parent
280decf863
commit
d1d608ab2b
|
@ -20,9 +20,14 @@ use smithay::{
|
|||
},
|
||||
wayland::{
|
||||
compositor::{roles::Role, SubsurfaceRole, TraversalAction},
|
||||
data_device::DnDIconRole,
|
||||
seat::CursorImageRole,
|
||||
shm::with_buffer_contents as shm_buffer_contents,
|
||||
},
|
||||
wayland_server::{protocol::wl_buffer, Resource},
|
||||
wayland_server::{
|
||||
protocol::{wl_buffer, wl_surface},
|
||||
Resource,
|
||||
},
|
||||
};
|
||||
|
||||
use shaders;
|
||||
|
@ -284,20 +289,16 @@ pub struct TextureMetadata {
|
|||
}
|
||||
|
||||
impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||
pub fn draw_windows(&self, window_map: &MyWindowMap, compositor_token: MyCompositorToken, log: &Logger) {
|
||||
let mut frame = self.draw();
|
||||
frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None);
|
||||
// redraw the frame, in a simple but inneficient way
|
||||
{
|
||||
let screen_dimensions = self.borrow().get_framebuffer_dimensions();
|
||||
window_map.with_windows_from_bottom_to_top(|toplevel_surface, initial_place| {
|
||||
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
||||
// this surface is a root of a subsurface tree that needs to be drawn
|
||||
fn draw_surface_tree(
|
||||
&self,
|
||||
frame: &mut Frame,
|
||||
root: &Resource<wl_surface::WlSurface>,
|
||||
location: (i32, i32),
|
||||
compositor_token: MyCompositorToken,
|
||||
screen_dimensions: (u32, u32),
|
||||
) {
|
||||
compositor_token
|
||||
.with_surface_tree_upward(
|
||||
wl_surface,
|
||||
initial_place,
|
||||
|_surface, attributes, role, &(mut x, mut y)| {
|
||||
.with_surface_tree_upward(root, location, |_surface, attributes, role, &(mut x, mut y)| {
|
||||
// there is actually something to draw !
|
||||
if attributes.user_data.texture.is_none() {
|
||||
if let Some(buffer) = attributes.user_data.buffer.take() {
|
||||
|
@ -315,7 +316,7 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
|||
y += subdata.location.1;
|
||||
}
|
||||
self.render_texture(
|
||||
&mut frame,
|
||||
frame,
|
||||
&metadata.texture,
|
||||
metadata.fragment,
|
||||
metadata.y_inverted,
|
||||
|
@ -325,13 +326,11 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
|||
::glium::Blend {
|
||||
color: ::glium::BlendingFunction::Addition {
|
||||
source: ::glium::LinearBlendingFactor::One,
|
||||
destination:
|
||||
::glium::LinearBlendingFactor::OneMinusSourceAlpha,
|
||||
destination: ::glium::LinearBlendingFactor::OneMinusSourceAlpha,
|
||||
},
|
||||
alpha: ::glium::BlendingFunction::Addition {
|
||||
source: ::glium::LinearBlendingFactor::One,
|
||||
destination:
|
||||
::glium::LinearBlendingFactor::OneMinusSourceAlpha,
|
||||
destination: ::glium::LinearBlendingFactor::OneMinusSourceAlpha,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -341,14 +340,69 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
|||
// we are not display, so our children are neither
|
||||
TraversalAction::SkipChildren
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn draw_windows(
|
||||
&self,
|
||||
frame: &mut Frame,
|
||||
window_map: &MyWindowMap,
|
||||
compositor_token: MyCompositorToken,
|
||||
) {
|
||||
// redraw the frame, in a simple but inneficient way
|
||||
{
|
||||
let screen_dimensions = self.borrow().get_framebuffer_dimensions();
|
||||
window_map.with_windows_from_bottom_to_top(|toplevel_surface, initial_place| {
|
||||
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
||||
// this surface is a root of a subsurface tree that needs to be drawn
|
||||
self.draw_surface_tree(
|
||||
frame,
|
||||
&wl_surface,
|
||||
initial_place,
|
||||
compositor_token,
|
||||
screen_dimensions,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
if let Err(err) = frame.finish() {
|
||||
error!(log, "Error during rendering: {:?}", err);
|
||||
}
|
||||
|
||||
pub fn draw_cursor(
|
||||
&self,
|
||||
frame: &mut Frame,
|
||||
surface: &Resource<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,
|
||||
surface: &Resource<wl_surface::WlSurface>,
|
||||
(x, y): (i32, i32),
|
||||
token: MyCompositorToken,
|
||||
) {
|
||||
if !token.has_role::<DnDIconRole>(surface) {
|
||||
warn!(
|
||||
self.log,
|
||||
"Trying to display as a dnd icon a surface that does not have the DndIcon role."
|
||||
);
|
||||
}
|
||||
let screen_dimensions = self.borrow().get_framebuffer_dimensions();
|
||||
self.draw_surface_tree(frame, surface, (x, y), token, screen_dimensions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
rc::Rc,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
Arc, Mutex,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -43,9 +43,9 @@ use smithay::{
|
|||
input::Libinput,
|
||||
wayland::{
|
||||
compositor::CompositorToken,
|
||||
data_device::{default_action_chooser, init_data_device, set_data_device_focus},
|
||||
data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent},
|
||||
output::{Mode, Output, PhysicalProperties},
|
||||
seat::{Seat, XkbConfig},
|
||||
seat::{CursorImageStatus, Seat, XkbConfig},
|
||||
shm::init_shm_global,
|
||||
},
|
||||
wayland_server::{
|
||||
|
@ -53,8 +53,8 @@ use smithay::{
|
|||
generic::{EventedFd, Generic},
|
||||
EventLoop, LoopHandle, Source,
|
||||
},
|
||||
protocol::wl_output,
|
||||
Display,
|
||||
protocol::{wl_output, wl_surface},
|
||||
Display, Resource,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -101,6 +101,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
|
|||
let running = Arc::new(AtomicBool::new(true));
|
||||
|
||||
let pointer_location = Rc::new(RefCell::new((0.0, 0.0)));
|
||||
let cursor_status = Arc::new(Mutex::new(CursorImageStatus::Default));
|
||||
let dnd_icon = Arc::new(Mutex::new(None));
|
||||
|
||||
/*
|
||||
* Initialize the udev backend
|
||||
|
@ -124,6 +126,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
|
|||
window_map: window_map.clone(),
|
||||
pointer_location: pointer_location.clone(),
|
||||
pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(),
|
||||
cursor_status: cursor_status.clone(),
|
||||
dnd_icon: dnd_icon.clone(),
|
||||
loop_handle: event_loop.handle(),
|
||||
notifier: udev_notifier,
|
||||
logger: log.clone(),
|
||||
|
@ -136,9 +140,18 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
|
|||
/*
|
||||
* Initialize wayland clipboard
|
||||
*/
|
||||
|
||||
init_data_device(
|
||||
&mut display.borrow_mut(),
|
||||
|_| {},
|
||||
move |event| match event {
|
||||
DataDeviceEvent::DnDStarted { icon, .. } => {
|
||||
*dnd_icon.lock().unwrap() = icon;
|
||||
}
|
||||
DataDeviceEvent::DnDDropped => {
|
||||
*dnd_icon.lock().unwrap() = None;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
default_action_chooser,
|
||||
compositor_token.clone(),
|
||||
log.clone(),
|
||||
|
@ -154,7 +167,9 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
|
|||
log.clone(),
|
||||
);
|
||||
|
||||
let pointer = w_seat.add_pointer(compositor_token.clone(), |_| {});
|
||||
let pointer = w_seat.add_pointer(compositor_token.clone(), move |new_status| {
|
||||
*cursor_status.lock().unwrap() = new_status;
|
||||
});
|
||||
let keyboard = w_seat
|
||||
.add_keyboard(XkbConfig::default(), 1000, 500, |seat, focus| {
|
||||
set_data_device_focus(seat, focus.and_then(|s| s.client()))
|
||||
|
@ -271,6 +286,8 @@ struct UdevHandlerImpl<S: SessionNotifier, Data: 'static> {
|
|||
window_map: Rc<RefCell<MyWindowMap>>,
|
||||
pointer_location: Rc<RefCell<(f64, f64)>>,
|
||||
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
|
||||
cursor_status: Arc<Mutex<CursorImageStatus>>,
|
||||
dnd_icon: Arc<Mutex<Option<Resource<wl_surface::WlSurface>>>>,
|
||||
loop_handle: LoopHandle<Data>,
|
||||
notifier: S,
|
||||
logger: ::slog::Logger,
|
||||
|
@ -410,6 +427,8 @@ impl<S: SessionNotifier, Data: 'static> UdevHandler for UdevHandlerImpl<S, Data>
|
|||
backends: backends.clone(),
|
||||
window_map: self.window_map.clone(),
|
||||
pointer_location: self.pointer_location.clone(),
|
||||
cursor_status: self.cursor_status.clone(),
|
||||
dnd_icon: self.dnd_icon.clone(),
|
||||
logger: self.logger.clone(),
|
||||
});
|
||||
|
||||
|
@ -504,6 +523,8 @@ pub struct DrmHandlerImpl {
|
|||
backends: Rc<RefCell<HashMap<crtc::Handle, GliumDrawer<RenderSurface>>>>,
|
||||
window_map: Rc<RefCell<MyWindowMap>>,
|
||||
pointer_location: Rc<RefCell<(f64, f64)>>,
|
||||
cursor_status: Arc<Mutex<CursorImageStatus>>,
|
||||
dnd_icon: Arc<Mutex<Option<Resource<wl_surface::WlSurface>>>>,
|
||||
logger: ::slog::Logger,
|
||||
}
|
||||
|
||||
|
@ -520,7 +541,44 @@ impl DeviceHandler for DrmHandlerImpl {
|
|||
}
|
||||
|
||||
// and draw in sync with our monitor
|
||||
drawer.draw_windows(&*self.window_map.borrow(), self.compositor_token, &self.logger);
|
||||
let mut frame = drawer.draw();
|
||||
frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None);
|
||||
// draw the surfaces
|
||||
drawer.draw_windows(&mut frame, &*self.window_map.borrow(), self.compositor_token);
|
||||
let (x, y) = *self.pointer_location.borrow();
|
||||
// draw the dnd icon if applicable
|
||||
{
|
||||
let guard = self.dnd_icon.lock().unwrap();
|
||||
if let Some(ref surface) = *guard {
|
||||
if surface.is_alive() {
|
||||
drawer.draw_dnd_icon(
|
||||
&mut frame,
|
||||
surface,
|
||||
(x as i32, y as i32),
|
||||
self.compositor_token,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw the cursor as relevant
|
||||
{
|
||||
let mut guard = self.cursor_status.lock().unwrap();
|
||||
// reset the cursor if the surface is no longer alive
|
||||
let mut reset = false;
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
reset = !surface.is_alive();
|
||||
}
|
||||
if reset {
|
||||
*guard = CursorImageStatus::Default;
|
||||
}
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
drawer.draw_cursor(&mut frame, surface, (x as i32, y as i32), self.compositor_token);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(err) = frame.finish() {
|
||||
error!(self.logger, "Error during rendering: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
sync::{atomic::AtomicBool, Arc, Mutex},
|
||||
};
|
||||
|
||||
use smithay::{
|
||||
backend::{egl::EGLGraphicsBackend, graphics::gl::GLGraphicsBackend, input::InputBackend, winit},
|
||||
wayland::{
|
||||
data_device::{default_action_chooser, init_data_device, set_data_device_focus},
|
||||
data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent},
|
||||
output::{Mode, Output, PhysicalProperties},
|
||||
seat::{Seat, XkbConfig},
|
||||
seat::{CursorImageStatus, Seat, XkbConfig},
|
||||
shm::init_shm_global,
|
||||
},
|
||||
wayland_server::{calloop::EventLoop, protocol::wl_output, Display},
|
||||
|
@ -50,9 +50,20 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
|
|||
|
||||
let (compositor_token, _, _, window_map) = init_shell(display, log.clone());
|
||||
|
||||
let dnd_icon = Arc::new(Mutex::new(None));
|
||||
|
||||
let dnd_icon2 = dnd_icon.clone();
|
||||
init_data_device(
|
||||
display,
|
||||
|_| {},
|
||||
move |event| match event {
|
||||
DataDeviceEvent::DnDStarted { icon, .. } => {
|
||||
*dnd_icon2.lock().unwrap() = icon;
|
||||
}
|
||||
DataDeviceEvent::DnDDropped => {
|
||||
*dnd_icon2.lock().unwrap() = None;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
default_action_chooser,
|
||||
compositor_token.clone(),
|
||||
log.clone(),
|
||||
|
@ -60,7 +71,13 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
|
|||
|
||||
let (mut seat, _) = Seat::new(display, "winit".into(), compositor_token.clone(), log.clone());
|
||||
|
||||
let pointer = seat.add_pointer(compositor_token.clone(), |_| {});
|
||||
let cursor_status = Arc::new(Mutex::new(CursorImageStatus::Default));
|
||||
|
||||
let cursor_status2 = cursor_status.clone();
|
||||
let pointer = seat.add_pointer(compositor_token.clone(), move |new_status| {
|
||||
// TODO: hide winit system cursor when relevant
|
||||
*cursor_status2.lock().unwrap() = new_status
|
||||
});
|
||||
|
||||
let keyboard = seat
|
||||
.add_keyboard(XkbConfig::default(), 1000, 500, |seat, focus| {
|
||||
|
@ -96,6 +113,8 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
|
|||
refresh: 60_000,
|
||||
});
|
||||
|
||||
let pointer_location = Rc::new(RefCell::new((0.0, 0.0)));
|
||||
|
||||
input.set_handler(AnvilInputHandler::new(
|
||||
log.clone(),
|
||||
pointer,
|
||||
|
@ -103,7 +122,7 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
|
|||
window_map.clone(),
|
||||
(0, 0),
|
||||
running.clone(),
|
||||
Rc::new(RefCell::new((0.0, 0.0))),
|
||||
pointer_location.clone(),
|
||||
));
|
||||
|
||||
info!(log, "Initialization completed, starting the main loop.");
|
||||
|
@ -111,7 +130,46 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
|
|||
loop {
|
||||
input.dispatch_new_events().unwrap();
|
||||
|
||||
drawer.draw_windows(&*window_map.borrow(), compositor_token, &log);
|
||||
// drawing logic
|
||||
{
|
||||
use glium::Surface;
|
||||
let mut frame = drawer.draw();
|
||||
frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None);
|
||||
|
||||
// draw the windows
|
||||
drawer.draw_windows(&mut frame, &*window_map.borrow(), compositor_token);
|
||||
|
||||
let (x, y) = *pointer_location.borrow();
|
||||
// draw the dnd icon if any
|
||||
{
|
||||
let guard = dnd_icon.lock().unwrap();
|
||||
if let Some(ref surface) = *guard {
|
||||
if surface.is_alive() {
|
||||
drawer.draw_dnd_icon(&mut frame, surface, (x as i32, y as i32), compositor_token);
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw the cursor as relevant
|
||||
{
|
||||
let mut guard = cursor_status.lock().unwrap();
|
||||
// reset the cursor if the surface is no longer alive
|
||||
let mut reset = false;
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
reset = !surface.is_alive();
|
||||
}
|
||||
if reset {
|
||||
*guard = CursorImageStatus::Default;
|
||||
}
|
||||
// draw as relevant
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
drawer.draw_cursor(&mut frame, surface, (x as i32, y as i32), compositor_token);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(err) = frame.finish() {
|
||||
error!(log, "Error during rendering: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
event_loop
|
||||
.dispatch(Some(::std::time::Duration::from_millis(16)), &mut ())
|
||||
|
|
|
@ -17,7 +17,7 @@ pub struct CursorImageRole {
|
|||
}
|
||||
|
||||
/// Possible status of a cursor as requested by clients
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum CursorImageStatus {
|
||||
/// The cursor should be hidden
|
||||
Hidden,
|
||||
|
|
Loading…
Reference in New Issue