From a224f774eecae2f84e01c406366f46a86966637e Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Mon, 3 Feb 2020 08:42:12 +0300 Subject: [PATCH] anvil: store buffer dimensions separately Before this change, the texture size was used for the dimensions. However, the texture is not created until the next rendered frame, which means that frequently size was returned as zero, resulting in pointer focus artifacts. With this change, the dimensions are retrieved immediately on surface commit. --- anvil/src/shell.rs | 28 +++++++++++++++++++--------- anvil/src/udev.rs | 9 ++++++++- anvil/src/winit.rs | 10 ++++++++-- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index 21ddb8e..5c40a62 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -28,7 +28,10 @@ use smithay::{ }, }; -use crate::window_map::{Kind as SurfaceKind, WindowMap}; +use crate::{ + buffer_utils::BufferUtils, + window_map::{Kind as SurfaceKind, WindowMap}, +}; define_roles!(Roles => [ XdgSurface, XdgSurfaceRole ] @@ -47,6 +50,7 @@ pub type MyCompositorToken = CompositorToken; pub fn init_shell( display: &mut Display, + buffer_utils: BufferUtils, log: ::slog::Logger, ) -> ( CompositorToken, @@ -58,7 +62,7 @@ pub fn init_shell( let (compositor_token, _, _) = compositor_init( display, move |request, surface, ctoken| match request { - SurfaceEvent::Commit => surface_commit(&surface, ctoken), + SurfaceEvent::Commit => surface_commit(&surface, ctoken, &buffer_utils), SurfaceEvent::Frame { callback } => callback .implement_closure(|_, _| unreachable!(), None::, ()) .done(0), @@ -138,10 +142,15 @@ pub fn init_shell( pub struct SurfaceData { pub buffer: Option, pub texture: Option, + pub dimensions: Option<(i32, i32)>, pub input_region: Option, } -fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken) { +fn surface_commit( + surface: &wl_surface::WlSurface, + token: CompositorToken, + buffer_utils: &BufferUtils, +) { token.with_surface_data(surface, |attributes| { attributes.user_data.insert_if_missing(SurfaceData::default); let data = attributes.user_data.get_mut::().unwrap(); @@ -157,6 +166,8 @@ fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken old_buffer.release(); } data.texture = None; + // If this fails, the buffer will be discarded later by the drawing code. + data.dimensions = buffer_utils.dimensions(data.buffer.as_ref().unwrap()); } Some(None) => { // erase the contents @@ -164,6 +175,7 @@ fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken old_buffer.release(); } data.texture = None; + data.dimensions = None; } None => {} } @@ -171,12 +183,10 @@ fn surface_commit(surface: &wl_surface::WlSurface, token: CompositorToken } fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> { - attrs.user_data.get::().and_then(|data| { - data.texture - .as_ref() - .map(|ref meta| meta.dimensions) - .map(|(x, y)| (x as i32, y as i32)) - }) + attrs + .user_data + .get::() + .and_then(|data| data.dimensions) } fn contains_point(attrs: &SurfaceAttributes, point: (f64, f64)) -> bool { diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 24ddb21..c3b3710 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -61,6 +61,7 @@ use smithay::{ }, }; +use crate::buffer_utils::BufferUtils; use crate::glium_drawer::GliumDrawer; use crate::input_handler::AnvilInputHandler; use crate::shell::{init_shell, MyWindowMap, Roles}; @@ -85,6 +86,11 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger #[cfg(feature = "egl")] let active_egl_context = Rc::new(RefCell::new(None)); + #[cfg(feature = "egl")] + let buffer_utils = BufferUtils::new(active_egl_context.clone(), log.clone()); + #[cfg(not(feature = "egl"))] + let buffer_utils = BufferUtils::new(log.clone()); + let display = Rc::new(RefCell::new(display)); /* @@ -92,7 +98,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger */ init_shm_global(&mut display.borrow_mut(), vec![], log.clone()); - let (compositor_token, _, _, window_map) = init_shell(&mut display.borrow_mut(), log.clone()); + let (compositor_token, _, _, window_map) = + init_shell(&mut display.borrow_mut(), buffer_utils, log.clone()); /* * Initialize session diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 48ceb7e..841936d 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -23,6 +23,7 @@ use smithay::{ use slog::Logger; +use crate::buffer_utils::BufferUtils; use crate::glium_drawer::GliumDrawer; use crate::input_handler::AnvilInputHandler; use crate::shell::init_shell; @@ -42,10 +43,15 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log let (w, h) = renderer.get_framebuffer_dimensions(); #[cfg(feature = "egl")] - let drawer = GliumDrawer::init(renderer, egl_display, log.clone()); + let drawer = GliumDrawer::init(renderer, egl_display.clone(), log.clone()); #[cfg(not(feature = "egl"))] let drawer = GliumDrawer::init(renderer, log.clone()); + #[cfg(feature = "egl")] + let buffer_utils = BufferUtils::new(egl_display, log.clone()); + #[cfg(not(feature = "egl"))] + let buffer_utils = BufferUtils::new(log.clone()); + let name = display.add_socket_auto().unwrap().into_string().unwrap(); info!(log, "Listening on wayland socket"; "name" => name.clone()); ::std::env::set_var("WAYLAND_DISPLAY", name); @@ -58,7 +64,7 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log init_shm_global(display, vec![], log.clone()); - let (compositor_token, _, _, window_map) = init_shell(display, log.clone()); + let (compositor_token, _, _, window_map) = init_shell(display, buffer_utils, log.clone()); let dnd_icon = Arc::new(Mutex::new(None));