From 42cceac491f460b8e664ac043b57801f869a5d3d Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 7 Apr 2019 20:17:47 +0200 Subject: [PATCH] wayland: use an invisible surface as shell surface This decorelates the window management from the actual user content, meaning: - the created window no longer needs the user to draw something to start existing - it reduces our need to do roundtrips during initialization to avoid protocol errors --- CHANGELOG.md | 1 + Cargo.toml | 2 +- src/platform_impl/linux/wayland/window.rs | 60 +++++++++++++++++------ 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14acb6cfb5..be8835df57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ - Remove `WindowBuilder::multitouch` field, since it was only implemented on a few platforms. Multitouch is always enabled now. - **Breaking:** On macOS, change `ns` identifiers to use snake_case for consistency with iOS's `ui` identifiers. - Add `MonitorHandle::video_modes` method for retrieving supported video modes for the given monitor. +- On Wayland, the window now exists even if nothing has been drawn. # Version 0.19.1 (2019-04-08) diff --git a/Cargo.toml b/Cargo.toml index ea087739d6..e66d23f600 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,7 @@ features = [ [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies] wayland-client = { version = "0.23.0", features = [ "dlopen", "egl", "cursor", "eventloop"] } calloop = "0.4.2" -smithay-client-toolkit = "0.6" +smithay-client-toolkit = "0.6.1" x11-dl = "2.18.3" percent-encoding = "1.0" diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index 976caf7593..c670ec93e8 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -1,4 +1,5 @@ use std::collections::VecDeque; +use std::io::{Seek, SeekFrom, Write}; use std::sync::{Arc, Mutex, Weak}; use dpi::{LogicalPosition, LogicalSize}; @@ -9,15 +10,17 @@ use window::{WindowAttributes, CursorIcon}; use sctk::surface::{get_dpi_factor, get_outputs}; use sctk::window::{ConceptFrame, Event as WEvent, State as WState, Window as SWindow, Theme}; -use sctk::reexports::client::Display; -use sctk::reexports::client::protocol::{wl_seat, wl_surface}; +use sctk::reexports::client::{Display, NewProxy}; +use sctk::reexports::client::protocol::{wl_seat, wl_surface, wl_subsurface, wl_shm}; use sctk::output::OutputMgr; use super::{make_wid, EventLoopWindowTarget, MonitorHandle, WindowId}; use platform_impl::platform::wayland::event_loop::{available_monitors, primary_monitor}; pub struct Window { - surface: wl_surface::WlSurface, + _bg_surface: wl_surface::WlSurface, + user_surface: wl_surface::WlSurface, + _user_subsurface: wl_subsurface::WlSubsurface, frame: Arc>>, outputs: OutputMgr, // Access to info for all monitors size: Arc>, @@ -36,16 +39,37 @@ impl Window { let fullscreen = Arc::new(Mutex::new(false)); let window_store = evlp.store.clone(); - let surface = evlp.env.create_surface(move |dpi, surface| { + let bg_surface = evlp + .env + .compositor + .create_surface(NewProxy::implement_dummy) + .unwrap(); + let user_surface = evlp.env.create_surface(move |dpi, surface| { window_store.lock().unwrap().dpi_change(&surface, dpi); surface.set_buffer_scale(dpi); }); + let user_subsurface = evlp + .env + .subcompositor + .get_subsurface(&user_surface, &bg_surface, NewProxy::implement_dummy) + .unwrap(); + user_subsurface.set_desync(); let window_store = evlp.store.clone(); - let my_surface = surface.clone(); + let my_surface = user_surface.clone(); + let my_bg_surface = bg_surface.clone(); + + // prepare a 1px buffer to display on the root window + let mut pool = sctk::utils::MemPool::new(&evlp.env.shm, || {}).unwrap(); + pool.resize(4).unwrap(); + pool.seek(SeekFrom::Start(0)).unwrap(); + pool.write(&[0, 0, 0, 0]).unwrap(); + pool.flush().unwrap(); + let buffer = pool.buffer(0, 1, 1, 4, wl_shm::Format::Argb8888); + let mut frame = SWindow::::init_from_env( &evlp.env, - surface.clone(), + bg_surface.clone(), (width, height), move |event| match event { WEvent::Configure { new_size, states } => { @@ -58,6 +82,12 @@ impl Window { *(window.need_refresh.lock().unwrap()) = true; *(window.fullscreen.lock().unwrap()) = is_fullscreen; *(window.need_frame_refresh.lock().unwrap()) = true; + if !window.configured { + // this is our first configure event, display ourselves ! + window.configured = true; + my_bg_surface.attach(Some(&buffer), 0, 0); + my_bg_surface.commit(); + } return; } } @@ -125,17 +155,19 @@ impl Window { need_refresh: need_refresh.clone(), fullscreen: fullscreen.clone(), need_frame_refresh: need_frame_refresh.clone(), - surface: surface.clone(), + surface: user_surface.clone(), kill_switch: kill_switch.clone(), frame: Arc::downgrade(&frame), current_dpi: 1, new_dpi: None, + configured: false, }); - evlp.evq.borrow_mut().sync_roundtrip().unwrap(); Ok(Window { display: evlp.display.clone(), - surface: surface, + _bg_surface: bg_surface, + user_surface: user_surface, + _user_subsurface: user_subsurface, frame: frame, outputs: evlp.env.outputs.clone(), size: size, @@ -148,7 +180,7 @@ impl Window { #[inline] pub fn id(&self) -> WindowId { - make_wid(&self.surface) + make_wid(&self.user_surface) } pub fn set_title(&self, title: &str) { @@ -214,7 +246,7 @@ impl Window { #[inline] pub fn hidpi_factor(&self) -> i32 { - get_dpi_factor(&self.surface) + get_dpi_factor(&self.user_surface) } pub fn set_decorations(&self, decorate: bool) { @@ -252,7 +284,6 @@ impl Window { } } - pub fn set_theme(&self, theme: T) { self.frame.lock().unwrap().set_theme(theme) } @@ -282,11 +313,11 @@ impl Window { } pub fn surface(&self) -> &wl_surface::WlSurface { - &self.surface + &self.user_surface } pub fn current_monitor(&self) -> MonitorHandle { - let output = get_outputs(&self.surface).last().unwrap().clone(); + let output = get_outputs(&self.user_surface).last().unwrap().clone(); MonitorHandle { proxy: output, mgr: self.outputs.clone(), @@ -325,6 +356,7 @@ struct InternalWindow { frame: Weak>>, current_dpi: i32, new_dpi: Option, + configured: bool, } pub struct WindowStore {