diff --git a/Cargo.toml b/Cargo.toml index 23adc010..164f9562 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,4 +40,5 @@ dwmapi-sys = "0.1" wayland-client = { version = "0.8.6", features = ["dlopen"] } wayland-kbd = "0.8.0" wayland-window = "0.5.0" +tempfile = "2.1" x11-dl = "2.8" diff --git a/src/platform/linux/wayland/context.rs b/src/platform/linux/wayland/context.rs index 35092475..54e18c67 100644 --- a/src/platform/linux/wayland/context.rs +++ b/src/platform/linux/wayland/context.rs @@ -1,11 +1,14 @@ use std::collections::VecDeque; +use std::fs::File; +use std::io::Write; +use std::os::unix::io::AsRawFd; use std::sync::{Arc, Mutex}; use wayland_client::{EnvHandler, default_connect, EventQueue, EventQueueHandle, Init, Proxy}; use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor, - wl_display, wl_registry, wl_output, wl_surface}; + wl_display, wl_registry, wl_output, wl_surface, wl_buffer}; -use super::wayland_window; +use super::{wayland_window, tempfile}; /* * Registry and globals handling @@ -213,13 +216,12 @@ impl WaylandContext { } } - pub fn create_window(&self) - -> (Arc, wayland_window::DecoratedSurface) + pub fn create_window(&self, width: u32, height: u32) + -> (Arc, wayland_window::DecoratedSurface, wl_buffer::WlBuffer, File) { let mut guard = self.evq.lock().unwrap(); let mut state = guard.state(); let env = state.get_mut_handler::(self.env_id); - // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) let surface = Arc::new(env.inner.compositor.create_surface()); let decorated = wayland_window::DecoratedSurface::new( &*surface, 800, 600, @@ -230,7 +232,19 @@ impl WaylandContext { env.get_seat(), false ).expect("Failed to create a tmpfile buffer."); - (surface, decorated) + // prepare a white content for the window, so that it exists + let mut tmp = tempfile::tempfile().expect("Failed to create a tmpfile buffer."); + for _ in 0..(width*height) { + tmp.write_all(&[0xff,0xff,0xff,0xff]).unwrap(); + } + tmp.flush().unwrap(); + let pool = env.inner.shm.create_pool(tmp.as_raw_fd(), (width*height*4) as i32); + let buffer = pool.create_buffer(0, width as i32, height as i32, width as i32, wl_shm::Format::Argb8888).expect("Pool cannot be already dead"); + surface.attach(Some(&buffer), 0, 0); + surface.commit(); + // the buffer wiil keep the contents alive as needed + pool.destroy(); + (surface, decorated, buffer, tmp) } } diff --git a/src/platform/linux/wayland/mod.rs b/src/platform/linux/wayland/mod.rs index 9567d57e..f267669b 100644 --- a/src/platform/linux/wayland/mod.rs +++ b/src/platform/linux/wayland/mod.rs @@ -10,6 +10,7 @@ use self::event_loop::EventsLoopSink; extern crate wayland_kbd; extern crate wayland_window; +extern crate tempfile; mod context; mod event_loop; diff --git a/src/platform/linux/wayland/window.rs b/src/platform/linux/wayland/window.rs index 6486c710..10e9124a 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -1,8 +1,9 @@ +use std::fs::File; use std::sync::{Arc, Mutex}; use std::sync::atomic::AtomicBool; use wayland_client::{EventQueue, EventQueueHandle, Proxy}; -use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface}; +use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface,wl_buffer}; use {CreationError, MouseCursor, CursorState, WindowAttributes}; use platform::MonitorId as PlatformMonitorId; @@ -39,16 +40,27 @@ impl Window { { let (width, height) = attributes.dimensions.unwrap_or((800,600)); - let (surface, decorated) = ctxt.create_window::(); + let (surface, decorated, buffer, tmpfile) = ctxt.create_window::(width, height); // init DecoratedSurface let (evq, cleanup_signal) = evlp.get_window_init(); let decorated_id = { let mut evq_guard = evq.lock().unwrap(); + // create a handler to clean up initial buffer + let initial_buffer_handler_id = evq_guard.add_handler(InitialBufferHandler::new()); + // register the buffer to it + evq_guard.register::<_, InitialBufferHandler>(&buffer, initial_buffer_handler_id); + // store the DecoratedSurface handler let decorated_id = evq_guard.add_handler_with_init(decorated); { - // initialize the DecoratedHandler let mut state = evq_guard.state(); + { + // store the buffer and tempfile in the handler, to be cleanded up at the right + // time + let initial_buffer_h = state.get_mut_handler::(initial_buffer_handler_id); + initial_buffer_h.initial_buffer = Some((buffer, tmpfile)); + } + // initialize the DecoratedHandler let decorated = state.get_mut_handler::>(decorated_id); *(decorated.handler()) = Some(DecoratedHandler::new()); @@ -203,3 +215,29 @@ impl wayland_window::Handler for DecoratedHandler { self.newsize = Some((max(width,1) as u32, max(height,1) as u32)); } } + +// a handler to release the ressources acquired to draw the initial white screen as soon as +// the compositor does not use them any more + +pub struct InitialBufferHandler { + initial_buffer: Option<(wl_buffer::WlBuffer, File)> +} + +impl InitialBufferHandler { + fn new() -> InitialBufferHandler { + InitialBufferHandler { + initial_buffer: None, + } + } +} + + +impl wl_buffer::Handler for InitialBufferHandler { + fn release(&mut self, _: &mut EventQueueHandle, buffer: &wl_buffer::WlBuffer) { + // release the ressources we've acquired for initial white window + buffer.destroy(); + self.initial_buffer = None; + } +} + +declare_handler!(InitialBufferHandler, wl_buffer::Handler, wl_buffer::WlBuffer);