diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index 285f50c5..f303b54a 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -10,7 +10,7 @@ use wayland_client::wayland::get_display; use wayland_client::wayland::compositor::{WlCompositor, WlSurface}; use wayland_client::wayland::output::WlOutput; use wayland_client::wayland::seat::{WlSeat, WlPointer}; -use wayland_client::wayland::shell::WlShell; +use wayland_client::wayland::shell::{WlShell, WlShellSurface}; use wayland_client::wayland::shm::WlShm; use wayland_client::wayland::subcompositor::WlSubcompositor; @@ -42,7 +42,7 @@ pub struct WaylandFocuses { pub struct WaylandContext { inner: InnerEnv, iterator: Mutex, - monitors: Vec, + monitors: Vec<(WlOutput, u32, u32, String)>, queues: Mutex>>>>, known_surfaces: Mutex>, focuses: Mutex @@ -57,13 +57,19 @@ impl WaylandContext { let (mut inner_env, iterator) = InnerEnv::init(display); - let monitors = inner_env.globals.iter() + let mut outputs_events = EventIterator::new(); + + let mut monitors = inner_env.globals.iter() .flat_map(|&(id, _, _)| inner_env.rebind_id::(id)) - .map(|(monitor, _)| monitor) - .collect(); + .map(|(mut monitor, _)| { + monitor.set_evt_iterator(&outputs_events); + (monitor, 0, 0, String::new()) + }).collect(); inner_env.display.sync_roundtrip().unwrap(); + super::monitor::init_monitors(&mut monitors, outputs_events); + Some(WaylandContext { inner: inner_env, iterator: Mutex::new(iterator), @@ -114,6 +120,31 @@ impl WaylandContext { } } + pub fn plain_from(&self, surface: &WlSurface, fullscreen: Option) -> Option { + use wayland_client::wayland::shell::WlShellSurfaceFullscreenMethod; + + let inner = &self.inner; + if let Some((ref shell, _)) = inner.shell { + let shell_surface = shell.get_shell_surface(surface); + if let Some(monitor_id) = fullscreen { + for m in &self.monitors { + if m.0.id() == monitor_id { + shell_surface.set_fullscreen( + WlShellSurfaceFullscreenMethod::Default, + 0, + Some(&m.0) + ); + return Some(shell_surface) + } + } + } + shell_surface.set_toplevel(); + Some(shell_surface) + } else { + None + } + } + pub fn display_ptr(&self) -> *const c_void { self.inner.display.ptr() as *const _ } @@ -155,4 +186,26 @@ impl WaylandContext { }; return guard.read_events().map(|i| Some(i)); } + + pub fn monitor_ids(&self) -> Vec { + self.monitors.iter().map(|o| o.0.id()).collect() + } + + pub fn monitor_name(&self, pid: ProxyId) -> Option { + for o in &self.monitors { + if o.0.id() == pid { + return Some(o.3.clone()) + } + } + None + } + + pub fn monitor_dimensions(&self, pid: ProxyId) -> Option<(u32, u32)> { + for o in &self.monitors { + if o.0.id() == pid { + return Some((o.1, o.2)) + } + } + None + } } diff --git a/src/api/wayland/monitor.rs b/src/api/wayland/monitor.rs index 3a42f1f7..d87d4b67 100644 --- a/src/api/wayland/monitor.rs +++ b/src/api/wayland/monitor.rs @@ -1,28 +1,75 @@ use std::collections::VecDeque; +use wayland_client::{ProxyId, EventIterator}; +use wayland_client::wayland::output::WlOutput; + +use super::context::WAYLAND_CONTEXT; + #[derive(Clone)] -pub struct MonitorId; +pub struct MonitorId(ProxyId); #[inline] pub fn get_available_monitors() -> VecDeque { - unimplemented!() + WAYLAND_CONTEXT.as_ref().map(|ctxt| + ctxt.monitor_ids().into_iter().map(MonitorId).collect() + ).unwrap_or(VecDeque::new()) } #[inline] pub fn get_primary_monitor() -> MonitorId { - unimplemented!() + WAYLAND_CONTEXT.as_ref().and_then(|ctxt| + ctxt.monitor_ids().into_iter().next().map(MonitorId) + ).expect("wayland: No monitor available.") } impl MonitorId { pub fn get_name(&self) -> Option { - unimplemented!() + WAYLAND_CONTEXT.as_ref().and_then(|ctxt| ctxt.monitor_name(self.0)) } #[inline] pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId { - unimplemented!() + ::native_monitor::NativeMonitorId::Unavailable } pub fn get_dimensions(&self) -> (u32, u32) { - unimplemented!() + WAYLAND_CONTEXT.as_ref().and_then(|ctxt| ctxt.monitor_dimensions(self.0)).unwrap() + } +} + +pub fn proxid_from_monitorid(x: &MonitorId) -> ProxyId { + x.0 +} + +pub fn init_monitors(outputs: &mut Vec<(WlOutput, u32, u32, String)>, evts: EventIterator) { + use wayland_client::{Event, Proxy}; + use wayland_client::wayland::WaylandProtocolEvent; + use wayland_client::wayland::output::{WlOutputEvent, WlOutputMode}; + + for evt in evts { + match evt { + Event::Wayland(WaylandProtocolEvent::WlOutput(pid, oevt)) => match oevt { + WlOutputEvent::Geometry(_, _, _, _, _, maker, model, _) => { + for o in outputs.iter_mut() { + if o.0.id() == pid { + o.3 = format!("{} - {}", maker, model); + break + } + } + }, + WlOutputEvent::Mode(flags, width, height, _) => { + if flags.contains(WlOutputMode::Current) { + for o in outputs.iter_mut() { + if o.0.id() == pid { + o.1 = width as u32; + o.2 = height as u32; + break + } + } + } + }, + _ => {} + }, + _ => {} + } } } \ No newline at end of file diff --git a/src/api/wayland/window.rs b/src/api/wayland/window.rs index faf772e0..a9285fa0 100644 --- a/src/api/wayland/window.rs +++ b/src/api/wayland/window.rs @@ -9,8 +9,11 @@ use {ContextError, CreationError, CursorState, Event, GlAttributes, GlContext, use api::dlopen; use api::egl; use api::egl::Context as EglContext; +use platform::MonitorId as PlatformMonitorId; +use wayland_client::EventIterator; use wayland_client::egl as wegl; +use wayland_client::wayland::shell::WlShellSurface; use super::wayland_window::{DecoratedSurface, add_borders, substract_borders}; use super::context::{WaylandContext, WAYLAND_CONTEXT}; @@ -27,7 +30,7 @@ impl WindowProxy { pub struct Window { wayland_context: &'static WaylandContext, egl_surface: wegl::WlEglSurface, - decorated_surface: Mutex, + shell_window: Mutex, evt_queue: Arc>>, inner_size: Mutex<(i32, i32)>, resize_callback: Option, @@ -36,21 +39,50 @@ pub struct Window { impl Window { fn next_event(&self) -> Option { + use wayland_client::Event as WEvent; + use wayland_client::wayland::WaylandProtocolEvent; + use wayland_client::wayland::shell::WlShellSurfaceEvent; + let mut newsize = None; - for (_, w, h) in &mut *self.decorated_surface.lock().unwrap() { - newsize = Some((w, h)); + let mut evt_queue_guard = self.evt_queue.lock().unwrap(); + + let mut shell_window_guard = self.shell_window.lock().unwrap(); + match *shell_window_guard { + ShellWindow::Decorated(ref mut deco) => { + for (_, w, h) in deco { + newsize = Some((w, h)); + } + }, + ShellWindow::Plain(ref plain, ref mut evtiter) => { + for evt in evtiter { + if let WEvent::Wayland(WaylandProtocolEvent::WlShellSurface(_, ssevt)) = evt { + match ssevt { + WlShellSurfaceEvent::Ping(u) => { + plain.pong(u); + }, + WlShellSurfaceEvent::Configure(_, w, h) => { + newsize = Some((w, h)); + }, + _ => {} + } + } + } + } } + if let Some((w, h)) = newsize { let (w, h) = substract_borders(w, h); *self.inner_size.lock().unwrap() = (w, h); - self.decorated_surface.lock().unwrap().resize(w, h); + if let ShellWindow::Decorated(ref mut deco) = *shell_window_guard { + deco.resize(w, h); + } self.egl_surface.resize(w, h, 0, 0); if let Some(f) = self.resize_callback { f(w as u32, h as u32); } Some(Event::Resized(w as u32, h as u32)) } else { - self.evt_queue.lock().unwrap().pop_front() + evt_queue_guard.pop_front() } } } @@ -99,10 +131,16 @@ impl<'a> Iterator for WaitEventsIterator<'a> { } } +enum ShellWindow { + Plain(WlShellSurface, EventIterator), + Decorated(DecoratedSurface) +} + impl Window { pub fn new(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements, opengl: &GlAttributes<&Window>) -> Result { + use wayland_client::Proxy; // not implemented assert!(window.min_dimensions.is_none()); assert!(window.max_dimensions.is_none()); @@ -142,15 +180,36 @@ impl Window { ) }; - let decorated_surface = match wayland_context.decorated_from(&egl_surface, w as i32, h as i32) { - Some(s) => s, - None => return Err(CreationError::NotSupported) + let shell_window = if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = window.monitor { + let pid = super::monitor::proxid_from_monitorid(monitor_id); + match wayland_context.plain_from(&egl_surface, Some(pid)) { + Some(mut s) => { + let iter = EventIterator::new(); + s.set_evt_iterator(&iter); + ShellWindow::Plain(s, iter) + }, + None => return Err(CreationError::NotSupported) + } + } else if window.decorations { + match wayland_context.decorated_from(&egl_surface, w as i32, h as i32) { + Some(s) => ShellWindow::Decorated(s), + None => return Err(CreationError::NotSupported) + } + } else { + match wayland_context.plain_from(&egl_surface, None) { + Some(mut s) => { + let iter = EventIterator::new(); + s.set_evt_iterator(&iter); + ShellWindow::Plain(s, iter) + }, + None => return Err(CreationError::NotSupported) + } }; Ok(Window { wayland_context: wayland_context, egl_surface: egl_surface, - decorated_surface: Mutex::new(decorated_surface), + shell_window: Mutex::new(shell_window), evt_queue: evt_queue, inner_size: Mutex::new((w as i32, h as i32)), resize_callback: None, @@ -159,7 +218,11 @@ impl Window { } pub fn set_title(&self, title: &str) { - self.decorated_surface.lock().unwrap().set_title(title.into()) + let guard = self.shell_window.lock().unwrap(); + match *guard { + ShellWindow::Plain(ref plain, _) => { plain.set_title(title.into()); }, + ShellWindow::Decorated(ref deco) => { deco.set_title(title.into()); } + } } #[inline] @@ -197,7 +260,12 @@ impl Window { #[inline] pub fn set_inner_size(&self, x: u32, y: u32) { - self.decorated_surface.lock().unwrap().resize(x as i32, y as i32) + let mut guard = self.shell_window.lock().unwrap(); + match *guard { + ShellWindow::Decorated(ref mut deco) => { deco.resize(x as i32, y as i32); }, + _ => {} + } + self.egl_surface.resize(x as i32, y as i32, 0, 0) } #[inline]