Merge pull request #571 from vberger/master

Add decorations to wayland windows
This commit is contained in:
tomaka 2015-08-16 16:58:18 +02:00
commit 6ba15de7db
3 changed files with 176 additions and 32 deletions

View file

@ -75,24 +75,28 @@ dwmapi-sys = "0.1"
[target.i686-unknown-linux-gnu.dependencies] [target.i686-unknown-linux-gnu.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.0"
[target.x86_64-unknown-linux-gnu.dependencies] [target.x86_64-unknown-linux-gnu.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.0"
[target.arm-unknown-linux-gnueabihf.dependencies] [target.arm-unknown-linux-gnueabihf.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.0"
[target.aarch64-unknown-linux-gnu.dependencies] [target.aarch64-unknown-linux-gnu.dependencies]
osmesa-sys = "0.0.5" osmesa-sys = "0.0.5"
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] } wayland-client = { version = "0.2.1", features = ["egl", "dlopen"] }
wayland-kbd = "0.2.0" wayland-kbd = "0.2.0"
wayland-window = "0.1.0"
x11-dl = "~2.0" x11-dl = "~2.0"

View file

@ -25,7 +25,7 @@ pub struct WaylandContext {
pub compositor: Compositor, pub compositor: Compositor,
pub shell: Shell, pub shell: Shell,
pub seat: Seat, pub seat: Seat,
pub pointer: Option<Pointer<WSurface>>, pointer: Option<Mutex<Pointer<WSurface>>>,
keyboard: Option<AnyKeyboard>, keyboard: Option<AnyKeyboard>,
windows_event_queues: Arc<Mutex<HashMap<SurfaceId, Arc<Mutex<VecDeque<Event>>>>>>, windows_event_queues: Arc<Mutex<HashMap<SurfaceId, Arc<Mutex<VecDeque<Event>>>>>>,
current_pointer_surface: Arc<Mutex<Option<SurfaceId>>>, current_pointer_surface: Arc<Mutex<Option<SurfaceId>>>,
@ -196,7 +196,7 @@ impl WaylandContext {
compositor: compositor, compositor: compositor,
shell: shell, shell: shell,
seat: seat, seat: seat,
pointer: pointer, pointer: pointer.map(|p| Mutex::new(p)),
keyboard: keyboard, keyboard: keyboard,
windows_event_queues: windows_event_queues, windows_event_queues: windows_event_queues,
current_pointer_surface: current_pointer_surface, current_pointer_surface: current_pointer_surface,
@ -207,9 +207,15 @@ impl WaylandContext {
pub fn register_surface(&self, sid: SurfaceId, queue: Arc<Mutex<VecDeque<Event>>>) { pub fn register_surface(&self, sid: SurfaceId, queue: Arc<Mutex<VecDeque<Event>>>) {
self.windows_event_queues.lock().unwrap().insert(sid, queue); self.windows_event_queues.lock().unwrap().insert(sid, queue);
if let Some(ref p) = self.pointer {
p.lock().unwrap().add_handled_surface(sid);
}
} }
pub fn deregister_surface(&self, sid: SurfaceId) { pub fn deregister_surface(&self, sid: SurfaceId) {
self.windows_event_queues.lock().unwrap().remove(&sid); self.windows_event_queues.lock().unwrap().remove(&sid);
if let Some(ref p) = self.pointer {
p.lock().unwrap().remove_handled_surface(sid);
}
} }
} }

View file

@ -6,6 +6,8 @@ use self::wayland::core::Surface;
use self::wayland::core::output::Output; use self::wayland::core::output::Output;
use self::wayland::core::shell::{ShellSurface, ShellFullscreenMethod}; use self::wayland::core::shell::{ShellSurface, ShellFullscreenMethod};
use self::wayland_window::{DecoratedSurface, SurfaceGuard, substract_borders};
use libc; use libc;
use api::dlopen; use api::dlopen;
use api::egl; use api::egl;
@ -21,6 +23,7 @@ use MouseCursor;
use GlContext; use GlContext;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::ffi::CString; use std::ffi::CString;
@ -30,6 +33,7 @@ use self::context::WaylandContext;
extern crate wayland_client as wayland; extern crate wayland_client as wayland;
extern crate wayland_kbd; extern crate wayland_kbd;
extern crate wayland_window;
mod context; mod context;
mod keyboard; mod keyboard;
@ -44,12 +48,97 @@ pub fn is_available() -> bool {
WAYLAND_CONTEXT.is_some() WAYLAND_CONTEXT.is_some()
} }
enum ShellWindow {
Plain(ShellSurface<EGLSurface>),
Decorated(DecoratedSurface<EGLSurface>)
}
impl ShellWindow {
fn get_shell(&mut self) -> ShellGuard {
match self {
&mut ShellWindow::Plain(ref mut s) => {
ShellGuard::Plain(s)
},
&mut ShellWindow::Decorated(ref mut s) => {
ShellGuard::Decorated(s.get_shell())
}
}
}
fn resize(&mut self, w: i32, h: i32, x: i32, y: i32) {
match self {
&mut ShellWindow::Plain(ref s) => s.resize(w, h, x, y),
&mut ShellWindow::Decorated(ref mut s) => {
s.resize(w, h);
s.get_shell().resize(w, h, x, y);
}
}
}
fn set_cfg_callback(&mut self, arc: Arc<Mutex<(i32, i32, bool)>>) {
match self {
&mut ShellWindow::Decorated(ref mut s) => {
s.get_shell().set_configure_callback(move |_, w, h| {
let (w, h) = substract_borders(w, h);
let mut guard = arc.lock().unwrap();
*guard = (w, h, true);
})
}
_ => {}
}
}
}
enum ShellGuard<'a> {
Plain(&'a mut ShellSurface<EGLSurface>),
Decorated(SurfaceGuard<'a, EGLSurface>)
}
impl<'a> Deref for ShellGuard<'a> {
type Target = ShellSurface<EGLSurface>;
fn deref(&self) -> &ShellSurface<EGLSurface> {
match self {
&ShellGuard::Plain(ref s) => s,
&ShellGuard::Decorated(ref s) => s.deref()
}
}
}
impl<'a> DerefMut for ShellGuard<'a> {
fn deref_mut(&mut self) -> &mut ShellSurface<EGLSurface> {
match self {
&mut ShellGuard::Plain(ref mut s) => s,
&mut ShellGuard::Decorated(ref mut s) => s.deref_mut()
}
}
}
pub struct Window { pub struct Window {
shell_surface: ShellSurface<EGLSurface>, shell_window: Mutex<ShellWindow>,
pending_events: Arc<Mutex<VecDeque<Event>>>, pending_events: Arc<Mutex<VecDeque<Event>>>,
need_resize: Arc<Mutex<(i32, i32, bool)>>,
resize_callback: Option<fn(u32, u32)>,
pub context: EglContext, pub context: EglContext,
} }
// private methods of wayalnd windows
impl Window {
fn resize_if_needed(&self) -> bool {
let mut guard = self.need_resize.lock().unwrap();
let (w, h, b) = *guard;
*guard = (0, 0, false);
if b {
let mut guard = self.shell_window.lock().unwrap();
guard.resize(w, h, 0, 0);
if let Some(f) = self.resize_callback {
f(w as u32, h as u32);
}
}
b
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct WindowProxy; pub struct WindowProxy;
@ -113,8 +202,12 @@ impl<'a> Iterator for PollEventsIterator<'a> {
if let Some(ref ctxt) = *WAYLAND_CONTEXT { if let Some(ref ctxt) = *WAYLAND_CONTEXT {
ctxt.display.dispatch_pending(); ctxt.display.dispatch_pending();
} }
if self.window.resize_if_needed() {
Some(Event::Refresh)
} else {
self.window.pending_events.lock().unwrap().pop_front() self.window.pending_events.lock().unwrap().pop_front()
} }
}
} }
pub struct WaitEventsIterator<'a> { pub struct WaitEventsIterator<'a> {
@ -125,10 +218,18 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
type Item = Event; type Item = Event;
fn next(&mut self) -> Option<Event> { fn next(&mut self) -> Option<Event> {
let mut evt = None;
while evt.is_none() {
if let Some(ref ctxt) = *WAYLAND_CONTEXT { if let Some(ref ctxt) = *WAYLAND_CONTEXT {
ctxt.display.dispatch(); ctxt.display.dispatch();
} }
evt = if self.window.resize_if_needed() {
Some(Event::Refresh)
} else {
self.window.pending_events.lock().unwrap().pop_front() self.window.pending_events.lock().unwrap().pop_front()
};
}
evt
} }
} }
@ -151,12 +252,26 @@ impl Window {
h as i32 h as i32
); );
let mut shell_window = if let Some(PlatformMonitorID::Wayland(ref monitor)) = builder.monitor {
let shell_surface = wayland_context.shell.get_shell_surface(surface); let shell_surface = wayland_context.shell.get_shell_surface(surface);
if let Some(PlatformMonitorID::Wayland(ref monitor)) = builder.monitor {
shell_surface.set_fullscreen(ShellFullscreenMethod::Default, Some(&monitor.output)); shell_surface.set_fullscreen(ShellFullscreenMethod::Default, Some(&monitor.output));
ShellWindow::Plain(shell_surface)
} else { } else {
shell_surface.set_toplevel(); if builder.decorations {
ShellWindow::Decorated(match DecoratedSurface::new(
surface,
w as i32,
h as i32,
&wayland_context.registry,
Some(&wayland_context.seat)
) {
Ok(s) => s,
Err(_) => return Err(CreationError::NotSupported)
})
} else {
ShellWindow::Plain(wayland_context.shell.get_shell_surface(surface))
} }
};
let context = { let context = {
let libegl = unsafe { dlopen::dlopen(b"libEGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW) }; let libegl = unsafe { dlopen::dlopen(b"libEGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW) };
@ -171,26 +286,43 @@ impl Window {
egl, egl,
&builder, &builder,
egl::NativeDisplay::Wayland(Some(wayland_context.display.ptr() as *const _))) egl::NativeDisplay::Wayland(Some(wayland_context.display.ptr() as *const _)))
.and_then(|p| p.finish((*shell_surface).ptr() as *const _)) .and_then(|p| p.finish((**shell_window.get_shell()).ptr() as *const _))
) )
}; };
let events = Arc::new(Mutex::new(VecDeque::new())); // create a queue already containing a refresh event to trigger first draw
// it's harmless and a removes the need to do a first swap_buffers() before
// starting the event loop
let events = Arc::new(Mutex::new({
let mut v = VecDeque::new();
v.push_back(Event::Refresh);
v
}));
wayland_context.register_surface(shell_surface.get_wsurface().get_id(), events.clone()); wayland_context.register_surface(shell_window.get_shell().get_wsurface().get_id(),
events.clone());
let need_resize = Arc::new(Mutex::new((0, 0, false)));
shell_window.set_cfg_callback(need_resize.clone());
wayland_context.display.flush().unwrap(); wayland_context.display.flush().unwrap();
Ok(Window { Ok(Window {
shell_surface: shell_surface, shell_window: Mutex::new(shell_window),
pending_events: events, pending_events: events,
need_resize: need_resize,
resize_callback: None,
context: context context: context
}) })
} }
pub fn set_title(&self, title: &str) { pub fn set_title(&self, title: &str) {
let ctitle = CString::new(title).unwrap(); let ctitle = CString::new(title).unwrap();
self.shell_surface.set_title(&ctitle); // intermediate variable is forced,
// see https://github.com/rust-lang/rust/issues/22921
let mut guard = self.shell_window.lock().unwrap();
guard.get_shell().set_title(&ctitle);
} }
pub fn show(&self) { pub fn show(&self) {
@ -211,7 +343,11 @@ impl Window {
} }
pub fn get_inner_size(&self) -> Option<(u32, u32)> { pub fn get_inner_size(&self) -> Option<(u32, u32)> {
let (w, h) = self.shell_surface.get_attached_size(); // intermediate variables are forced,
// see https://github.com/rust-lang/rust/issues/22921
let mut guard = self.shell_window.lock().unwrap();
let shell = guard.get_shell();
let (w, h) = shell.get_attached_size();
Some((w as u32, h as u32)) Some((w as u32, h as u32))
} }
@ -222,7 +358,7 @@ impl Window {
} }
pub fn set_inner_size(&self, x: u32, y: u32) { pub fn set_inner_size(&self, x: u32, y: u32) {
self.shell_surface.resize(x as i32, y as i32, 0, 0) self.shell_window.lock().unwrap().resize(x as i32, y as i32, 0, 0)
} }
pub fn create_window_proxy(&self) -> WindowProxy { pub fn create_window_proxy(&self) -> WindowProxy {
@ -242,15 +378,7 @@ impl Window {
} }
pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) { pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
if let Some(callback) = callback { self.resize_callback = callback;
self.shell_surface.set_configure_callback(
move |_,w,h| { callback(w as u32, h as u32) }
);
} else {
self.shell_surface.set_configure_callback(
move |_,_,_| {}
);
}
} }
pub fn set_cursor(&self, cursor: MouseCursor) { pub fn set_cursor(&self, cursor: MouseCursor) {
@ -309,7 +437,13 @@ impl GlContext for Window {
impl Drop for Window { impl Drop for Window {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(ref ctxt) = *WAYLAND_CONTEXT { if let Some(ref ctxt) = *WAYLAND_CONTEXT {
ctxt.deregister_surface(self.shell_surface.get_wsurface().get_id()) // intermediate variable is forced,
// see https://github.com/rust-lang/rust/issues/22921
let mut guard = self.shell_window.lock().unwrap();
let shell = guard.get_shell();
ctxt.deregister_surface(
shell.get_wsurface().get_id()
)
} }
} }
} }