diff --git a/Cargo.toml b/Cargo.toml index d74816cf..d9f9ffec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,5 @@ dwmapi-sys = "0.1" wayland-client = { version = "0.12.0", features = ["dlopen"] } wayland-protocols = { version = "0.12.0", features = ["unstable_protocols"] } wayland-kbd = "0.13.0" -wayland-window = "0.12.0" -tempfile = "2.1" +wayland-window = "0.13.0" x11-dl = "2.8" diff --git a/examples/cursor.rs b/examples/cursor.rs index 2062d8a7..bc7deea6 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -11,12 +11,6 @@ fn main() { let cursors = [MouseCursor::Default, MouseCursor::Crosshair, MouseCursor::Hand, MouseCursor::Arrow, MouseCursor::Move, MouseCursor::Text, MouseCursor::Wait, MouseCursor::Help, MouseCursor::Progress, MouseCursor::NotAllowed, MouseCursor::ContextMenu, MouseCursor::NoneCursor, MouseCursor::Cell, MouseCursor::VerticalText, MouseCursor::Alias, MouseCursor::Copy, MouseCursor::NoDrop, MouseCursor::Grab, MouseCursor::Grabbing, MouseCursor::AllScroll, MouseCursor::ZoomIn, MouseCursor::ZoomOut, MouseCursor::EResize, MouseCursor::NResize, MouseCursor::NeResize, MouseCursor::NwResize, MouseCursor::SResize, MouseCursor::SeResize, MouseCursor::SwResize, MouseCursor::WResize, MouseCursor::EwResize, MouseCursor::NsResize, MouseCursor::NeswResize, MouseCursor::NwseResize, MouseCursor::ColResize, MouseCursor::RowResize]; let mut cursor_idx = 0; - if cfg!(target_os = "linux") { - println!("Running this example under wayland may not display a window at all.\n\ - This is normal and because this example does not actually draw anything in the window,\ - thus the compositor does not display it."); - } - events_loop.run_forever(|event| { match event { Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => { diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index bbabe34b..933eceba 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -31,12 +31,6 @@ fn main() { .build(&events_loop) .unwrap(); - if cfg!(target_os = "linux") { - println!("Running this example under wayland may not display a window at all.\n\ - This is normal and because this example does not actually draw anything in the window,\ - thus the compositor does not display it."); - } - events_loop.run_forever(|event| { println!("{:?}", event); diff --git a/examples/grabbing.rs b/examples/grabbing.rs index 68ef7701..f7e7c9b3 100644 --- a/examples/grabbing.rs +++ b/examples/grabbing.rs @@ -10,12 +10,6 @@ fn main() { let mut grabbed = false; - if cfg!(target_os = "linux") { - println!("Running this example under wayland may not display a window at all.\n\ - This is normal and because this example does not actually draw anything in the window,\ - thus the compositor does not display it."); - } - events_loop.run_forever(|event| { println!("{:?}", event); diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index b5020e73..7500e893 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -9,12 +9,6 @@ fn main() { .build(&events_loop) .unwrap(); - if cfg!(target_os = "linux") { - println!("Running this example under wayland may not display a window at all.\n\ - This is normal and because this example does not actually draw anything in the window,\ - thus the compositor does not display it."); - } - events_loop.run_forever(|event| { println!("{:?}", event); diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index c020f69d..9c5b93b8 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -9,12 +9,6 @@ fn main() { let mut num_windows = 3; - if cfg!(target_os = "linux") { - println!("Running this example under wayland may not display a window at all.\n\ - This is normal and because this example does not actually draw anything in the window,\ - thus the compositor does not display it."); - } - events_loop.run_forever(|event| { match event { winit::Event::WindowEvent { event: winit::WindowEvent::Closed, window_id } => { diff --git a/examples/proxy.rs b/examples/proxy.rs index fa9ca014..338c4675 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -10,12 +10,6 @@ fn main() { let proxy = events_loop.create_proxy(); - if cfg!(target_os = "linux") { - println!("Running this example under wayland may not display a window at all.\n\ - This is normal and because this example does not actually draw anything in the window,\ - thus the compositor does not display it."); - } - std::thread::spawn(move || { // Wake up the `events_loop` once every second. loop { diff --git a/examples/transparent.rs b/examples/transparent.rs index 29dd9415..de633175 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -9,12 +9,6 @@ fn main() { window.set_title("A fantastic window!"); - if cfg!(target_os = "linux") { - println!("Running this example under wayland may not display a window at all.\n\ - This is normal and because this example does not actually draw anything in the window,\ - thus the compositor does not display it."); - } - events_loop.run_forever(|event| { println!("{:?}", event); diff --git a/examples/window.rs b/examples/window.rs index 6dc909a8..65f0ade2 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -8,12 +8,6 @@ fn main() { .build(&events_loop) .unwrap(); - if cfg!(target_os = "linux") { - println!("Running this example under wayland may not display a window at all.\n\ - This is normal and because this example does not actually draw anything in the window,\ - thus the compositor does not display it."); - } - events_loop.run_forever(|event| { println!("{:?}", event); diff --git a/src/os/unix.rs b/src/os/unix.rs index e6d43628..eb0cb8b0 100644 --- a/src/os/unix.rs +++ b/src/os/unix.rs @@ -121,13 +121,11 @@ pub trait WindowExt { /// Check if the window is ready for drawing /// - /// On wayland, drawing on a surface before the server has configured - /// it using a special event is illegal. As a result, you should wait - /// until this method returns `true`. + /// It is a remnant of a previous implementation detail for the + /// wayland backend, and is no longer relevant. /// - /// Once it starts returning `true`, it can never return `false` again. - /// - /// If the window is X11-based, this will just always return `true`. + /// Always return true. + #[deprecated] fn is_ready(&self) -> bool; } @@ -195,10 +193,7 @@ impl WindowExt for Window { #[inline] fn is_ready(&self) -> bool { - match self.window { - LinuxWindow::Wayland(ref w) => w.is_ready(), - LinuxWindow::X(_) => true - } + true } } diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index a5bfc75d..4da5c64a 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -1,8 +1,5 @@ use std::cell::RefCell; use std::collections::VecDeque; -use std::fs::File; -use std::io::Write; -use std::os::unix::io::AsRawFd; use std::sync::{Arc, Mutex, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -14,14 +11,12 @@ use super::keyboard::init_keyboard; use wayland_client::{EnvHandler, EnvNotify, default_connect, EventQueue, EventQueueHandle, Proxy, StateToken}; use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor, - wl_display, wl_registry, wl_output, wl_surface, wl_buffer, + wl_display, wl_registry, wl_output, wl_surface, wl_pointer, wl_keyboard}; -use super::wayland_window::{DecoratedSurface, Shell, init_decorated_surface, DecoratedSurfaceImplementation}; +use super::wayland_window::{Frame, Shell, create_frame, FrameImplementation}; use super::wayland_protocols::unstable::xdg_shell::v6::client::zxdg_shell_v6; -use super::tempfile; - pub struct EventsLoopSink { buffer: VecDeque<::Event> } @@ -345,10 +340,15 @@ impl EventsLoop { } // process pending resize/refresh evq.state().get_mut(&self.store).for_each( - |newsize, refresh, closed, wid, decorated| { - if let (Some((w, h)), Some(decorated)) = (newsize, decorated) { - decorated.resize(w as i32, h as i32); - sink.send_event(::WindowEvent::Resized(w as u32, h as u32), wid); + |newsize, refresh, frame_refresh, closed, wid, frame| { + if let Some(frame) = frame { + if let Some((w, h)) = newsize { + frame.resize(w as i32, h as i32); + frame.refresh(); + sink.send_event(::WindowEvent::Resized(w as u32, h as u32), wid); + } else if frame_refresh { + frame.refresh(); + } } if refresh { sink.send_event(::WindowEvent::Refresh, wid); @@ -360,50 +360,24 @@ impl EventsLoop { ) } - /// Creates a buffer of given size and assign it to the surface - /// - /// This buffer only contains white pixels, and is needed when using wl_shell - /// to make sure the window actually exists and can receive events before the - /// use starts its event loop - fn blank_surface(&self, surface: &wl_surface::WlSurface, width: i32, height: i32) { - 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 mut evq = self.evq.borrow_mut(); - let pool = evq.state() - .get(&self.env_token) - .shm - .create_pool(tmp.as_raw_fd(), width*height*4); - let buffer = pool.create_buffer(0, width, height, width, wl_shm::Format::Argb8888) - .expect("Pool cannot be already dead"); - surface.attach(Some(&buffer), 0, 0); - surface.commit(); - // the buffer will keep the contents alive as needed - pool.destroy(); - // register the buffer for freeing - evq.register(&buffer, free_buffer(), Some(tmp)); - } - /// Create a new window with given dimensions /// /// Grabs a lock on the event queue in the process - pub fn create_window(&self, width: u32, height: u32, decorated: bool, implem: DecoratedSurfaceImplementation, idata: F) - -> (wl_surface::WlSurface, DecoratedSurface, bool) + pub fn create_window(&self, width: u32, height: u32, implem: FrameImplementation, idata: F) + -> (wl_surface::WlSurface, Frame) where F: FnOnce(&wl_surface::WlSurface) -> ID { - let (surface, decorated, xdg) = { + let (surface, frame) = { let mut guard = self.evq.borrow_mut(); let env = guard.state().get(&self.env_token).clone_inner().unwrap(); - let (shell, xdg) = match guard.state().get(&self.ctxt_token).shell { - Some(Shell::Wl(ref wl_shell)) => (Shell::Wl(wl_shell.clone().unwrap()), false), - Some(Shell::Xdg(ref xdg_shell)) => (Shell::Xdg(xdg_shell.clone().unwrap()), true), + let shell = match guard.state().get(&self.ctxt_token).shell { + Some(Shell::Wl(ref wl_shell)) => Shell::Wl(wl_shell.clone().unwrap()), + Some(Shell::Xdg(ref xdg_shell)) => Shell::Xdg(xdg_shell.clone().unwrap()), None => unreachable!() }; let seat = guard.state().get(&self.ctxt_token).seat.as_ref().and_then(|s| s.clone()); let surface = env.compositor.create_surface(); - let decorated = init_decorated_surface( + let frame = create_frame( &mut guard, implem, idata(&surface), @@ -412,21 +386,12 @@ impl EventsLoop { &env.subcompositor, &env.shm, &shell, - seat, - decorated + seat ).expect("Failed to create a tmpfile buffer."); - (surface, decorated, xdg) + (surface, frame) }; - if !xdg { - // if using wl_shell, we need to draw something in order to kickstart - // the event loop - // if using xdg_shell, it is an error to do it now, and the events loop will not - // be stuck. We cannot draw anything before having received an appropriate event - // from the compositor - self.blank_surface(&surface, width as i32, height as i32); - } - (surface, decorated, xdg) + (surface, frame) } } @@ -470,15 +435,6 @@ fn xdg_ping_implementation() -> zxdg_shell_v6::Implementation<()> { } } -fn free_buffer() -> wl_buffer::Implementation> { - wl_buffer::Implementation { - release: |_, data, buffer| { - buffer.destroy(); - *data = None; - } - } -} - struct SeatIData { sink: Arc>, pointer: Option, diff --git a/src/platform/linux/wayland/mod.rs b/src/platform/linux/wayland/mod.rs index 1cf6964d..732bfc3e 100644 --- a/src/platform/linux/wayland/mod.rs +++ b/src/platform/linux/wayland/mod.rs @@ -6,7 +6,6 @@ pub use self::event_loop::{EventsLoop, EventsLoopProxy, EventsLoopSink, MonitorI extern crate wayland_kbd; extern crate wayland_window; extern crate wayland_protocols; -extern crate tempfile; use wayland_client::protocol::wl_surface; use wayland_client::Proxy; diff --git a/src/platform/linux/wayland/window.rs b/src/platform/linux/wayland/window.rs index eb48819b..a5c2057a 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -8,14 +8,13 @@ use platform::MonitorId as PlatformMonitorId; use window::MonitorId as RootMonitorId; use super::{EventsLoop, WindowId, make_wid, MonitorId}; -use super::wayland_window::{DecoratedSurface, DecoratedSurfaceImplementation}; +use super::wayland_window::{Frame, FrameImplementation, State as FrameState}; use super::event_loop::StateContext; pub struct Window { surface: wl_surface::WlSurface, - decorated: Arc>, + frame: Arc>, monitors: Arc>, - ready: Arc>, size: Arc>, kill_switch: (Arc>, Arc>), display: Arc, @@ -27,24 +26,30 @@ impl Window { let (width, height) = attributes.dimensions.unwrap_or((800,600)); // Create the decorated surface - let ready = Arc::new(Mutex::new(false)); let size = Arc::new(Mutex::new((width, height))); let store_token = evlp.store.clone(); - let (surface, mut decorated, xdg) = evlp.create_window( - width, height, attributes.decorations, decorated_impl(), - |surface| DecoratedIData { - ready: ready.clone(), + let (surface, mut frame) = evlp.create_window( + width, height, decorated_impl(), + |surface| FrameIData { surface: surface.clone().unwrap(), store_token: store_token.clone() } ); - // If we are using xdg, we are not ready yet - { *ready.lock().unwrap() = !xdg; } // Check for fullscreen requirements if let Some(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = attributes.fullscreen { let info = monitor_id.info.lock().unwrap(); - decorated.set_fullscreen(Some(&info.output)); + frame.set_state(FrameState::Fullscreen(Some(&info.output))); + } else if attributes.maximized { + frame.set_state(FrameState::Maximized); } + + // set decorations + frame.set_decorate(attributes.decorations); + + // min-max dimensions + frame.set_min_size(attributes.min_dimensions.map(|(w, h)| (w as i32, h as i32))); + frame.set_max_size(attributes.max_dimensions.map(|(w, h)| (w as i32, h as i32))); + // setup the monitor tracking let monitor_list = Arc::new(Mutex::new(MonitorList::default())); { @@ -52,12 +57,9 @@ impl Window { let idata = (evlp.ctxt_token.clone(), monitor_list.clone()); evq.register(&surface, surface_impl(), idata); } - // a surface commit with no buffer so that the compositor don't - // forget to configure us - surface.commit(); let kill_switch = Arc::new(Mutex::new(false)); - let decorated = Arc::new(Mutex::new(decorated)); + let frame = Arc::new(Mutex::new(frame)); { let mut evq = evlp.evq.borrow_mut(); @@ -65,9 +67,10 @@ impl Window { closed: false, newsize: None, need_refresh: false, + need_frame_refresh: true, surface: surface.clone().unwrap(), kill_switch: kill_switch.clone(), - decorated: Arc::downgrade(&decorated) + frame: Arc::downgrade(&frame) }); evq.sync_roundtrip().unwrap(); } @@ -75,9 +78,8 @@ impl Window { Ok(Window { display: evlp.display.clone(), surface: surface, - decorated: decorated, + frame: frame, monitors: monitor_list, - ready: ready, size: size, kill_switch: (kill_switch, evlp.cleanup_needed.clone()) }) @@ -89,7 +91,7 @@ impl Window { } pub fn set_title(&self, title: &str) { - self.decorated.lock().unwrap().set_title(title.into()); + self.frame.lock().unwrap().set_title(title.into()); } #[inline] @@ -127,7 +129,7 @@ impl Window { #[inline] // NOTE: This will only resize the borders, the contents must be updated by the user pub fn set_inner_size(&self, x: u32, y: u32) { - self.decorated.lock().unwrap().resize(x as i32, y as i32); + self.frame.lock().unwrap().resize(x as i32, y as i32); *(self.size.lock().unwrap()) = (x, y); } @@ -178,10 +180,6 @@ impl Window { let guard = self.monitors.lock().unwrap(); guard.monitors.last().unwrap().clone() } - - pub fn is_ready(&self) -> bool { - *self.ready.lock().unwrap() - } } impl Drop for Window { @@ -199,9 +197,10 @@ struct InternalWindow { surface: wl_surface::WlSurface, newsize: Option<(i32, i32)>, need_refresh: bool, + need_frame_refresh: bool, closed: bool, kill_switch: Arc>, - decorated: Weak> + frame: Weak> } pub struct WindowStore { @@ -235,14 +234,15 @@ impl WindowStore { } pub fn for_each(&mut self, mut f: F) - where F: FnMut(Option<(i32, i32)>, bool, bool, WindowId, Option<&mut DecoratedSurface>) + where F: FnMut(Option<(i32, i32)>, bool, bool, bool, WindowId, Option<&mut Frame>) { for window in &mut self.windows { - let opt_arc = window.decorated.upgrade(); + let opt_arc = window.frame.upgrade(); let mut opt_mutex_lock = opt_arc.as_ref().map(|m| m.lock().unwrap()); f( window.newsize.take(), window.need_refresh, + window.need_frame_refresh, window.closed, make_wid(&window.surface), opt_mutex_lock.as_mut().map(|m| &mut **m) @@ -258,21 +258,20 @@ impl WindowStore { * Protocol implementation */ -struct DecoratedIData { - ready: Arc>, +struct FrameIData { store_token: StateToken, surface: wl_surface::WlSurface } -fn decorated_impl() -> DecoratedSurfaceImplementation { - DecoratedSurfaceImplementation { +fn decorated_impl() -> FrameImplementation { + FrameImplementation { configure: |evqh, idata, _, newsize| { - *idata.ready.lock().unwrap() = true; let store = evqh.state().get_mut(&idata.store_token); for window in &mut store.windows { if window.surface.equals(&idata.surface) { window.newsize = newsize; window.need_refresh = true; + window.need_frame_refresh = true; return; } } @@ -285,6 +284,15 @@ fn decorated_impl() -> DecoratedSurfaceImplementation { return; } } + }, + refresh: |evqh, idata| { + let store = evqh.state().get_mut(&idata.store_token); + for window in &mut store.windows { + if window.surface.equals(&idata.surface) { + window.need_frame_refresh = true; + return; + } + } } } }