From c991172a28755e43981b9cea65f873d5cdd8dd87 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 7 Oct 2016 19:52:19 +0200 Subject: [PATCH 01/12] wayland: remove old code for new backend --- Cargo.toml | 6 +- src/api/wayland/context.rs | 231 +++++------------------------ src/api/wayland/events.rs | 112 -------------- src/api/wayland/keyboard.rs | 229 ---------------------------- src/api/wayland/mod.rs | 10 +- src/api/wayland/monitor.rs | 75 ---------- src/api/wayland/window.rs | 208 +++----------------------- src/os/unix.rs | 23 ++- src/platform/linux/api_dispatch.rs | 23 ++- 9 files changed, 83 insertions(+), 834 deletions(-) delete mode 100644 src/api/wayland/events.rs delete mode 100644 src/api/wayland/keyboard.rs delete mode 100644 src/api/wayland/monitor.rs diff --git a/Cargo.toml b/Cargo.toml index b2af1c94..da966210 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ kernel32-sys = "0.2" dwmapi-sys = "0.1" [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies] -wayland-client = { version = "0.5.4", features = ["dlopen"] } -wayland-kbd = "0.3.3" -wayland-window = "0.2.2" +wayland-client = { version = "0.7.1", features = ["dlopen"] } +wayland-kbd = "0.6" +wayland-window = "0.4" x11-dl = "2.8" diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index 58789202..dc03e964 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -1,211 +1,46 @@ -use Event as GlutinEvent; +use std::collections::VecDeque; -use std::collections::{HashMap, VecDeque, HashSet}; -use std::sync::{Arc, Mutex}; - -use libc::c_void; - -use wayland_client::{EventIterator, Proxy, ProxyId}; -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, WlShellSurface}; -use wayland_client::wayland::shm::WlShm; -use wayland_client::wayland::subcompositor::WlSubcompositor; - -use super::wayland_kbd::MappedKeyboard; -use super::wayland_window::DecoratedSurface; - -lazy_static! { - pub static ref WAYLAND_CONTEXT: Option = { - WaylandContext::init() - }; -} +use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor}; wayland_env!(InnerEnv, - compositor: WlCompositor, - seat: WlSeat, - shell: WlShell, - shm: WlShm, - subcompositor: WlSubcompositor + compositor: wl_compositor::WlCompositor, + seat: wl_seat::WlSeat, + shell: wl_shell::WlShell, + shm: wl_shm::WlShm, + subcompositor: wl_subcompositor::WlSubcompositor ); -pub struct WaylandFocuses { - pub pointer: Option, - pub pointer_on: Option, - pub pointer_at: Option<(f64, f64)>, - pub keyboard: Option, - pub keyboard_on: Option -} - pub struct WaylandContext { - inner: InnerEnv, - iterator: Mutex, - monitors: Vec<(WlOutput, u32, u32, String)>, - queues: Mutex>>>>, - known_surfaces: Mutex>, - focuses: Mutex } impl WaylandContext { - fn init() -> Option { - let display = match get_display() { - Some(display) => display, - None => return None - }; - - let (mut inner_env, iterator) = InnerEnv::init(display); - - let outputs_events = EventIterator::new(); - - let mut monitors = inner_env.globals.iter() - .flat_map(|&(id, _, _)| inner_env.rebind_id::(id)) - .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), - monitors: monitors, - queues: Mutex::new(HashMap::new()), - known_surfaces: Mutex::new(HashSet::new()), - focuses: Mutex::new(WaylandFocuses { - pointer: None, - pointer_on: None, - pointer_at: None, - keyboard: None, - keyboard_on: None - }) - }) - } - - pub fn new_surface(&self) -> Option<(WlSurface, Arc>>)> { - self.inner.compositor.as_ref().map(|c| { - let s = c.0.create_surface(); - let id = s.id(); - let queue = { - let mut q = VecDeque::new(); - q.push_back(GlutinEvent::Refresh); - Arc::new(Mutex::new(q)) - }; - self.queues.lock().unwrap().insert(id, queue.clone()); - self.known_surfaces.lock().unwrap().insert(id); - (s, queue) - }) - } - - pub fn dropped_surface(&self, id: ProxyId) { - self.queues.lock().unwrap().remove(&id); - self.known_surfaces.lock().unwrap().remove(&id); - } - - pub fn decorated_from(&self, surface: &WlSurface, width: i32, height: i32) -> Option { - let inner = &self.inner; - match (&inner.compositor, &inner.subcompositor, &inner.shm, &inner.shell) { - (&Some(ref compositor), &Some(ref subcompositor), &Some(ref shm), &Some(ref shell)) => { - DecoratedSurface::new( - surface, width, height, - &compositor.0, &subcompositor.0, &shm.0, &shell.0, - self.inner.rebind::().map(|(seat, _)| seat) - ).ok() - } - _ => None - } - } - - 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 _ - } - - pub fn dispatch_events(&self) { - self.inner.display.dispatch_pending().unwrap(); - let mut iterator = self.iterator.lock().unwrap(); - let mut focuses = self.focuses.lock().unwrap(); - let known_surfaces = self.known_surfaces.lock().unwrap(); - let queues = self.queues.lock().unwrap(); - // first, keyboard events - let kdb_evts = super::keyboard::translate_kbd_events(&mut *focuses, &known_surfaces); - for (evt, id) in kdb_evts { - if let Some(q) = queues.get(&id) { - q.lock().unwrap().push_back(evt); - } - } - // then, the rest - for evt in &mut *iterator { - if let Some((evt, id)) = super::events::translate_event( - evt, &mut *focuses, &known_surfaces, - self.inner.seat.as_ref().map(|s| &s.0)) - { - if let Some(q) = queues.get(&id) { - q.lock().unwrap().push_back(evt); - } - } - } - } - - pub fn flush_events(&self) -> ::std::io::Result { - self.inner.display.flush() - } - - pub fn read_events(&self) -> ::std::io::Result> { - let guard = match self.inner.display.prepare_read() { - Some(g) => g, - None => return Ok(None) - }; - 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()) - } - } + pub fn init() -> Option { 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 + + pub fn get_primary_monitor(&self) -> MonitorId { + unimplemented!() + } + + pub fn get_available_monitors(&self) -> VecDeque { + unimplemented!() + } +} + +#[derive(Clone)] +pub struct MonitorId; + +impl MonitorId { + pub fn get_name(&self) -> Option { + unimplemented!() + } + + #[inline] + pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId { + ::native_monitor::NativeMonitorId::Unavailable + } + + pub fn get_dimensions(&self) -> (u32, u32) { + unimplemented!() } } diff --git a/src/api/wayland/events.rs b/src/api/wayland/events.rs deleted file mode 100644 index 92a0b95f..00000000 --- a/src/api/wayland/events.rs +++ /dev/null @@ -1,112 +0,0 @@ -use std::collections::HashSet; - -use TouchPhase; -use Event as GlutinEvent; -use ElementState; -use MouseButton; -use MouseScrollDelta; - -use wayland_client::Event as WaylandEvent; -use wayland_client::ProxyId; -use wayland_client::wayland::WaylandProtocolEvent as WPE; -use wayland_client::wayland::seat::{WlSeat, WlSeatEvent, WlPointerEvent, - WlPointerButtonState, - WlPointerAxis, WlSeatCapability}; - -use super::wayland_kbd::MappedKeyboard; - -use super::context::WaylandFocuses; - -pub fn translate_event( - evt: WaylandEvent, - focuses: &mut WaylandFocuses, - known_surfaces: &HashSet, - seat: Option<&WlSeat>, - ) -> Option<(GlutinEvent, ProxyId)> -{ - let WaylandEvent::Wayland(wayland_evt) = evt; - match wayland_evt { - WPE::WlSeat(_, seat_evt) => match seat_evt { - WlSeatEvent::Capabilities(cap) => { - if cap.contains(WlSeatCapability::Pointer) && focuses.pointer.is_none() { - if let Some(seat) = seat { - focuses.pointer = Some(seat.get_pointer()); - } - } - if cap.contains(WlSeatCapability::Keyboard) && focuses.keyboard.is_none() { - if let Some(seat) = seat { - match MappedKeyboard::new(seat) { - Ok(mk) => { - focuses.keyboard = Some(mk) - }, - Err(_) => {} - } - } - } - None - }, - _ => None - }, - WPE::WlPointer(_, pointer_evt) => match pointer_evt { - WlPointerEvent::Enter(_, surface, x, y) => { - if known_surfaces.contains(&surface) { - focuses.pointer_on = Some(surface); - focuses.pointer_at = Some((x, y)); - Some((GlutinEvent::MouseMoved(x as i32, y as i32), surface)) - } else { - None - } - } - WlPointerEvent::Leave(_, _) => { - focuses.pointer_on = None; - focuses.pointer_at = None; - None - } - WlPointerEvent::Motion(_, x, y) => { - if let Some(surface) = focuses.pointer_on { - focuses.pointer_at = Some((x, y)); - Some((GlutinEvent::MouseMoved(x as i32, y as i32), surface)) - } else { - None - } - } - WlPointerEvent::Button(_, _, button, state) => { - if let Some(surface) = focuses.pointer_on { - Some((GlutinEvent::MouseInput( - match state { - WlPointerButtonState::Pressed => ElementState::Pressed, - WlPointerButtonState::Released => ElementState::Released - }, - match button { - 0x110 => MouseButton::Left, - 0x111 => MouseButton::Right, - 0x112 => MouseButton::Middle, - // TODO figure out the translation ? - _ => return None - } - ), surface)) - } else { - None - } - } - WlPointerEvent::Axis(_, axis, amplitude) => { - if let Some(surface) = focuses.pointer_on { - Some((GlutinEvent::MouseWheel( - match axis { - WlPointerAxis::VerticalScroll => { - MouseScrollDelta::PixelDelta(amplitude as f32, 0.0) - } - WlPointerAxis::HorizontalScroll => { - MouseScrollDelta::PixelDelta(0.0, amplitude as f32) - } - }, - TouchPhase::Moved - ), surface)) - } else { - None - } - } - }, - _ => None - } -} diff --git a/src/api/wayland/keyboard.rs b/src/api/wayland/keyboard.rs deleted file mode 100644 index 3190b870..00000000 --- a/src/api/wayland/keyboard.rs +++ /dev/null @@ -1,229 +0,0 @@ -use std::collections::HashSet; - -use Event as GlutinEvent; -use ElementState; -use VirtualKeyCode; - -use wayland_client::ProxyId; -use wayland_client::wayland::seat::{WlKeyboardEvent,WlKeyboardKeyState}; - -use super::wayland_kbd::MappedKeyboardEvent; - -use super::context::WaylandFocuses; - -pub fn translate_kbd_events( - focuses: &mut WaylandFocuses, - known_surfaces: &HashSet, -) -> Vec<(GlutinEvent, ProxyId)> { - let mut out = Vec::new(); - if let Some(mkbd) = focuses.keyboard.as_mut() { - for evt in mkbd { - match evt { - MappedKeyboardEvent::KeyEvent(kevt) => { - if let Some(surface) = focuses.keyboard_on { - let vkcode = match kevt.keycode { - 1 => Some(VirtualKeyCode::Escape), - 2 => Some(VirtualKeyCode::Key1), - 3 => Some(VirtualKeyCode::Key2), - 4 => Some(VirtualKeyCode::Key3), - 5 => Some(VirtualKeyCode::Key4), - 6 => Some(VirtualKeyCode::Key5), - 7 => Some(VirtualKeyCode::Key6), - 8 => Some(VirtualKeyCode::Key7), - 9 => Some(VirtualKeyCode::Key8), - 10 => Some(VirtualKeyCode::Key9), - 11 => Some(VirtualKeyCode::Key0), - _ => kevt.as_symbol().and_then(keysym_to_vkey) - }; - let text = kevt.as_utf8(); - out.push(( - GlutinEvent::KeyboardInput( - match kevt.keystate { - WlKeyboardKeyState::Pressed => ElementState::Pressed, - WlKeyboardKeyState::Released =>ElementState::Released - }, - (kevt.keycode & 0xff) as u8, - vkcode - ), - surface - )); - if let Some(c) = text.and_then(|s| s.chars().next()) { - out.push(( - GlutinEvent::ReceivedCharacter(c), - surface - )); - } - } - - } - MappedKeyboardEvent::Other(oevt) => match oevt { - WlKeyboardEvent::Enter(_, surface, _) => { - if known_surfaces.contains(&surface) { - focuses.keyboard_on = Some(surface); - out.push((GlutinEvent::Focused(true), surface)); - } - }, - WlKeyboardEvent::Leave(_, surface) => { - if known_surfaces.contains(&surface) { - focuses.keyboard_on = None; - out.push((GlutinEvent::Focused(false), surface)); - } - } - _ => {} - } - } - } - } - out -} - -pub fn keysym_to_vkey(keysym: u32) -> Option { - use super::wayland_kbd::keysyms; - match keysym { - // letters - keysyms::XKB_KEY_A | keysyms::XKB_KEY_a => Some(VirtualKeyCode::A), - keysyms::XKB_KEY_B | keysyms::XKB_KEY_b => Some(VirtualKeyCode::B), - keysyms::XKB_KEY_C | keysyms::XKB_KEY_c => Some(VirtualKeyCode::C), - keysyms::XKB_KEY_D | keysyms::XKB_KEY_d => Some(VirtualKeyCode::D), - keysyms::XKB_KEY_E | keysyms::XKB_KEY_e => Some(VirtualKeyCode::E), - keysyms::XKB_KEY_F | keysyms::XKB_KEY_f => Some(VirtualKeyCode::F), - keysyms::XKB_KEY_G | keysyms::XKB_KEY_g => Some(VirtualKeyCode::G), - keysyms::XKB_KEY_H | keysyms::XKB_KEY_h => Some(VirtualKeyCode::H), - keysyms::XKB_KEY_I | keysyms::XKB_KEY_i => Some(VirtualKeyCode::I), - keysyms::XKB_KEY_J | keysyms::XKB_KEY_j => Some(VirtualKeyCode::J), - keysyms::XKB_KEY_K | keysyms::XKB_KEY_k => Some(VirtualKeyCode::K), - keysyms::XKB_KEY_L | keysyms::XKB_KEY_l => Some(VirtualKeyCode::L), - keysyms::XKB_KEY_M | keysyms::XKB_KEY_m => Some(VirtualKeyCode::M), - keysyms::XKB_KEY_N | keysyms::XKB_KEY_n => Some(VirtualKeyCode::N), - keysyms::XKB_KEY_O | keysyms::XKB_KEY_o => Some(VirtualKeyCode::O), - keysyms::XKB_KEY_P | keysyms::XKB_KEY_p => Some(VirtualKeyCode::P), - keysyms::XKB_KEY_Q | keysyms::XKB_KEY_q => Some(VirtualKeyCode::Q), - keysyms::XKB_KEY_R | keysyms::XKB_KEY_r => Some(VirtualKeyCode::R), - keysyms::XKB_KEY_S | keysyms::XKB_KEY_s => Some(VirtualKeyCode::S), - keysyms::XKB_KEY_T | keysyms::XKB_KEY_t => Some(VirtualKeyCode::T), - keysyms::XKB_KEY_U | keysyms::XKB_KEY_u => Some(VirtualKeyCode::U), - keysyms::XKB_KEY_V | keysyms::XKB_KEY_v => Some(VirtualKeyCode::V), - keysyms::XKB_KEY_W | keysyms::XKB_KEY_w => Some(VirtualKeyCode::W), - keysyms::XKB_KEY_X | keysyms::XKB_KEY_x => Some(VirtualKeyCode::X), - keysyms::XKB_KEY_Y | keysyms::XKB_KEY_y => Some(VirtualKeyCode::Y), - keysyms::XKB_KEY_Z | keysyms::XKB_KEY_z => Some(VirtualKeyCode::Z), - // F-- - keysyms::XKB_KEY_F1 => Some(VirtualKeyCode::F1), - keysyms::XKB_KEY_F2 => Some(VirtualKeyCode::F2), - keysyms::XKB_KEY_F3 => Some(VirtualKeyCode::F3), - keysyms::XKB_KEY_F4 => Some(VirtualKeyCode::F4), - keysyms::XKB_KEY_F5 => Some(VirtualKeyCode::F5), - keysyms::XKB_KEY_F6 => Some(VirtualKeyCode::F6), - keysyms::XKB_KEY_F7 => Some(VirtualKeyCode::F7), - keysyms::XKB_KEY_F8 => Some(VirtualKeyCode::F8), - keysyms::XKB_KEY_F9 => Some(VirtualKeyCode::F9), - keysyms::XKB_KEY_F10 => Some(VirtualKeyCode::F10), - keysyms::XKB_KEY_F11 => Some(VirtualKeyCode::F11), - keysyms::XKB_KEY_F12 => Some(VirtualKeyCode::F12), - keysyms::XKB_KEY_F13 => Some(VirtualKeyCode::F13), - keysyms::XKB_KEY_F14 => Some(VirtualKeyCode::F14), - keysyms::XKB_KEY_F15 => Some(VirtualKeyCode::F15), - // flow control - keysyms::XKB_KEY_Print => Some(VirtualKeyCode::Snapshot), - keysyms::XKB_KEY_Scroll_Lock => Some(VirtualKeyCode::Scroll), - keysyms::XKB_KEY_Pause => Some(VirtualKeyCode::Pause), - keysyms::XKB_KEY_Insert => Some(VirtualKeyCode::Insert), - keysyms::XKB_KEY_Home => Some(VirtualKeyCode::Home), - keysyms::XKB_KEY_Delete => Some(VirtualKeyCode::Delete), - keysyms::XKB_KEY_End => Some(VirtualKeyCode::End), - keysyms::XKB_KEY_Page_Down => Some(VirtualKeyCode::PageDown), - keysyms::XKB_KEY_Page_Up => Some(VirtualKeyCode::PageUp), - // arrows - keysyms::XKB_KEY_Left => Some(VirtualKeyCode::Left), - keysyms::XKB_KEY_Up => Some(VirtualKeyCode::Up), - keysyms::XKB_KEY_Right => Some(VirtualKeyCode::Right), - keysyms::XKB_KEY_Down => Some(VirtualKeyCode::Down), - // - keysyms::XKB_KEY_BackSpace => Some(VirtualKeyCode::Back), - keysyms::XKB_KEY_Return => Some(VirtualKeyCode::Return), - keysyms::XKB_KEY_space => Some(VirtualKeyCode::Space), - // keypad - keysyms::XKB_KEY_Num_Lock => Some(VirtualKeyCode::Numlock), - keysyms::XKB_KEY_KP_0 => Some(VirtualKeyCode::Numpad0), - keysyms::XKB_KEY_KP_1 => Some(VirtualKeyCode::Numpad1), - keysyms::XKB_KEY_KP_2 => Some(VirtualKeyCode::Numpad2), - keysyms::XKB_KEY_KP_3 => Some(VirtualKeyCode::Numpad3), - keysyms::XKB_KEY_KP_4 => Some(VirtualKeyCode::Numpad4), - keysyms::XKB_KEY_KP_5 => Some(VirtualKeyCode::Numpad5), - keysyms::XKB_KEY_KP_6 => Some(VirtualKeyCode::Numpad6), - keysyms::XKB_KEY_KP_7 => Some(VirtualKeyCode::Numpad7), - keysyms::XKB_KEY_KP_8 => Some(VirtualKeyCode::Numpad8), - keysyms::XKB_KEY_KP_9 => Some(VirtualKeyCode::Numpad9), - // misc - // => Some(VirtualKeyCode::AbntC1), - // => Some(VirtualKeyCode::AbntC2), - keysyms::XKB_KEY_plus => Some(VirtualKeyCode::Add), - keysyms::XKB_KEY_apostrophe => Some(VirtualKeyCode::Apostrophe), - // => Some(VirtualKeyCode::Apps), - // => Some(VirtualKeyCode::At), - // => Some(VirtualKeyCode::Ax), - keysyms::XKB_KEY_backslash => Some(VirtualKeyCode::Backslash), - // => Some(VirtualKeyCode::Calculator), - // => Some(VirtualKeyCode::Capital), - keysyms::XKB_KEY_colon => Some(VirtualKeyCode::Colon), - keysyms::XKB_KEY_comma => Some(VirtualKeyCode::Comma), - // => Some(VirtualKeyCode::Convert), - // => Some(VirtualKeyCode::Decimal), - // => Some(VirtualKeyCode::Divide), - keysyms::XKB_KEY_equal => Some(VirtualKeyCode::Equals), - // => Some(VirtualKeyCode::Grave), - // => Some(VirtualKeyCode::Kana), - // => Some(VirtualKeyCode::Kanji), - keysyms::XKB_KEY_Alt_L => Some(VirtualKeyCode::LAlt), - // => Some(VirtualKeyCode::LBracket), - keysyms::XKB_KEY_Control_L => Some(VirtualKeyCode::LControl), - // => Some(VirtualKeyCode::LMenu), - keysyms::XKB_KEY_Shift_L => Some(VirtualKeyCode::LShift), - // => Some(VirtualKeyCode::LWin), - // => Some(VirtualKeyCode::Mail), - // => Some(VirtualKeyCode::MediaSelect), - // => Some(VirtualKeyCode::MediaStop), - keysyms::XKB_KEY_minus => Some(VirtualKeyCode::Minus), - keysyms::XKB_KEY_asterisk => Some(VirtualKeyCode::Multiply), - // => Some(VirtualKeyCode::Mute), - // => Some(VirtualKeyCode::MyComputer), - // => Some(VirtualKeyCode::NextTrack), - // => Some(VirtualKeyCode::NoConvert), - keysyms::XKB_KEY_KP_Separator => Some(VirtualKeyCode::NumpadComma), - keysyms::XKB_KEY_KP_Enter => Some(VirtualKeyCode::NumpadEnter), - keysyms::XKB_KEY_KP_Equal => Some(VirtualKeyCode::NumpadEquals), - // => Some(VirtualKeyCode::OEM102), - // => Some(VirtualKeyCode::Period), - // => Some(VirtualKeyCode::Playpause), - // => Some(VirtualKeyCode::Power), - // => Some(VirtualKeyCode::Prevtrack), - keysyms::XKB_KEY_Alt_R => Some(VirtualKeyCode::RAlt), - // => Some(VirtualKeyCode::RBracket), - keysyms::XKB_KEY_Control_R => Some(VirtualKeyCode::RControl), - // => Some(VirtualKeyCode::RMenu), - keysyms::XKB_KEY_Shift_R => Some(VirtualKeyCode::RShift), - // => Some(VirtualKeyCode::RWin), - keysyms::XKB_KEY_semicolon => Some(VirtualKeyCode::Semicolon), - keysyms::XKB_KEY_slash => Some(VirtualKeyCode::Slash), - // => Some(VirtualKeyCode::Sleep), - // => Some(VirtualKeyCode::Stop), - // => Some(VirtualKeyCode::Subtract), - // => Some(VirtualKeyCode::Sysrq), - keysyms::XKB_KEY_Tab => Some(VirtualKeyCode::Tab), - // => Some(VirtualKeyCode::Underline), - // => Some(VirtualKeyCode::Unlabeled), - keysyms::XKB_KEY_XF86AudioLowerVolume => Some(VirtualKeyCode::VolumeDown), - keysyms::XKB_KEY_XF86AudioRaiseVolume => Some(VirtualKeyCode::VolumeUp), - // => Some(VirtualKeyCode::Wake), - // => Some(VirtualKeyCode::Webback), - // => Some(VirtualKeyCode::WebFavorites), - // => Some(VirtualKeyCode::WebForward), - // => Some(VirtualKeyCode::WebHome), - // => Some(VirtualKeyCode::WebRefresh), - // => Some(VirtualKeyCode::WebSearch), - // => Some(VirtualKeyCode::WebStop), - // => Some(VirtualKeyCode::Yen), - // fallback - _ => None - } -} \ No newline at end of file diff --git a/src/api/wayland/mod.rs b/src/api/wayland/mod.rs index 77f018e5..11ab4842 100644 --- a/src/api/wayland/mod.rs +++ b/src/api/wayland/mod.rs @@ -1,18 +1,10 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] -pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor}; pub use self::window::{PollEventsIterator, WaitEventsIterator, Window, WindowProxy}; +pub use self::context::{WaylandContext,MonitorId}; extern crate wayland_kbd; extern crate wayland_window; mod context; -mod events; -mod keyboard; -mod monitor; mod window; - -#[inline] -pub fn is_available() -> bool { - context::WAYLAND_CONTEXT.is_some() -} diff --git a/src/api/wayland/monitor.rs b/src/api/wayland/monitor.rs deleted file mode 100644 index d87d4b67..00000000 --- a/src/api/wayland/monitor.rs +++ /dev/null @@ -1,75 +0,0 @@ -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(ProxyId); - -#[inline] -pub fn get_available_monitors() -> VecDeque { - 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 { - 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 { - WAYLAND_CONTEXT.as_ref().and_then(|ctxt| ctxt.monitor_name(self.0)) - } - - #[inline] - pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId { - ::native_monitor::NativeMonitorId::Unavailable - } - - pub fn get_dimensions(&self) -> (u32, u32) { - 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 38f89bfe..99b7e694 100644 --- a/src/api/wayland/window.rs +++ b/src/api/wayland/window.rs @@ -1,16 +1,10 @@ -use std::collections::VecDeque; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; -use libc; +use wayland_client::protocol::{wl_display,wl_surface}; -use {CreationError, CursorState, Event, MouseCursor, WindowAttributes}; -use platform::MonitorId as PlatformMonitorId; +use {CreationError, MouseCursor, CursorState, Event, WindowAttributes}; -use wayland_client::EventIterator; -use wayland_client::wayland::compositor::WlSurface; -use wayland_client::wayland::shell::WlShellSurface; -use super::wayland_window::{DecoratedSurface, add_borders, substract_borders}; -use super::context::{WaylandContext, WAYLAND_CONTEXT}; +use super::WaylandContext; #[derive(Clone)] pub struct WindowProxy; @@ -23,61 +17,7 @@ impl WindowProxy { } pub struct Window { - wayland_context: &'static WaylandContext, - surface: WlSurface, - shell_window: Mutex, - evt_queue: Arc>>, - inner_size: Mutex<(i32, i32)>, - resize_callback: Option, -} - -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; - 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); - if let ShellWindow::Decorated(ref mut deco) = *shell_window_guard { - deco.resize(w, h); - } - if let Some(f) = self.resize_callback { - f(w as u32, h as u32); - } - Some(Event::Resized(w as u32, h as u32)) - } else { - evt_queue_guard.pop_front() - } - } + resize_callback: Option } pub struct PollEventsIterator<'a> { @@ -88,13 +28,7 @@ impl<'a> Iterator for PollEventsIterator<'a> { type Item = Event; fn next(&mut self) -> Option { - match self.window.next_event() { - Some(evt) => return Some(evt), - None => {} - } - // the queue was empty, try a dispatch and see the result - self.window.wayland_context.dispatch_events(); - return self.window.next_event(); + unimplemented!() } } @@ -106,91 +40,18 @@ impl<'a> Iterator for WaitEventsIterator<'a> { type Item = Event; fn next(&mut self) -> Option { - loop { - match self.window.next_event() { - Some(evt) => return Some(evt), - None => {} - } - // the queue was empty, try a dispatch & read and see the result - self.window.wayland_context.flush_events().expect("Connexion with the wayland compositor lost."); - match self.window.wayland_context.read_events() { - Ok(_) => { - // events were read or dispatch is needed, in both cases, we dispatch - self.window.wayland_context.dispatch_events() - } - Err(_) => panic!("Connexion with the wayland compositor lost.") - } - } + unimplemented!() } } -enum ShellWindow { - Plain(WlShellSurface, EventIterator), - Decorated(DecoratedSurface) -} - impl Window { - pub fn new(window: &WindowAttributes) -> Result + pub fn new(ctxt: Arc, attributes: &WindowAttributes) -> Result { - use wayland_client::Proxy; - // not implemented - assert!(window.min_dimensions.is_none()); - assert!(window.max_dimensions.is_none()); - - let wayland_context = match *WAYLAND_CONTEXT { - Some(ref c) => c, - None => return Err(CreationError::NotSupported), - }; - - let (w, h) = window.dimensions.unwrap_or((800, 600)); - - let (surface, evt_queue) = match wayland_context.new_surface() { - Some(t) => t, - 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(&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(&surface, w as i32, h as i32) { - Some(s) => ShellWindow::Decorated(s), - None => return Err(CreationError::NotSupported) - } - } else { - match wayland_context.plain_from(&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, - surface: surface, - shell_window: Mutex::new(shell_window), - evt_queue: evt_queue, - inner_size: Mutex::new((w as i32, h as i32)), - resize_callback: None, - }) + unimplemented!() } pub fn set_title(&self, title: &str) { - 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()); } - } + // TODO } #[inline] @@ -215,24 +76,19 @@ impl Window { } pub fn get_inner_size(&self) -> Option<(u32, u32)> { - let (w, h) = *self.inner_size.lock().unwrap(); - Some((w as u32, h as u32)) + // TODO + None } #[inline] pub fn get_outer_size(&self) -> Option<(u32, u32)> { - let (w, h) = *self.inner_size.lock().unwrap(); - let (w, h) = add_borders(w, h); - Some((w as u32, h as u32)) + // TODO + None } #[inline] pub fn set_inner_size(&self, x: u32, y: u32) { - let mut guard = self.shell_window.lock().unwrap(); - match *guard { - ShellWindow::Decorated(ref mut deco) => { deco.resize(x as i32, y as i32); }, - _ => {} - } + // TODO } #[inline] @@ -277,6 +133,7 @@ impl Window { #[inline] pub fn hidpi_factor(&self) -> f32 { + // TODO 1.0 } @@ -285,35 +142,18 @@ impl Window { // TODO: not yet possible on wayland Err(()) } - - #[inline] - pub fn get_wayland_display(&self) -> *mut libc::c_void { - WAYLAND_CONTEXT.as_ref().unwrap() // context exists if window was created - .display_ptr() as *mut libc::c_void + + pub fn get_display(&self) -> &wl_display::WlDisplay { + unimplemented!() } - - #[inline] - pub fn get_wayland_surface(&self) -> *mut libc::c_void { - use wayland_client::Proxy; - self.surface.ptr() as *mut libc::c_void - } - - #[inline] - pub fn platform_display(&self) -> *mut libc::c_void { - WAYLAND_CONTEXT.as_ref().unwrap() // context exists if window was created - .display_ptr() as *mut libc::c_void - } - - #[inline] - pub fn platform_window(&self) -> *mut libc::c_void { - use wayland_client::Proxy; - self.surface.ptr() as *mut libc::c_void + + pub fn get_surface(&self) -> &wl_surface::WlSurface { + unimplemented!() } } impl Drop for Window { fn drop(&mut self) { - use wayland_client::Proxy; - self.wayland_context.dropped_surface(self.surface.id()); + // TODO } -} \ No newline at end of file +} diff --git a/src/os/unix.rs b/src/os/unix.rs index c4dfac90..ae5928cd 100644 --- a/src/os/unix.rs +++ b/src/os/unix.rs @@ -5,6 +5,9 @@ use Window; use platform::Window as LinuxWindow; use WindowBuilder; +use wayland_client::protocol::wl_display::WlDisplay; +use wayland_client::protocol::wl_surface::WlSurface; + /// Additional methods on `Window` that are specific to Unix. pub trait WindowExt { /// Returns a pointer to the `Window` object of xlib that is used by this window. @@ -29,19 +32,15 @@ pub trait WindowExt { /// The pointer will become invalid when the glutin `Window` is destroyed. fn get_xcb_connection(&self) -> Option<*mut libc::c_void>; - /// Returns a pointer to the `wl_surface` object of wayland that is used by this window. + /// Returns a reference to the `WlSurface` object of wayland that is used by this window. /// /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). - /// - /// The pointer will become invalid when the glutin `Window` is destroyed. - fn get_wayland_surface(&self) -> Option<*mut libc::c_void>; + fn get_wayland_surface(&self) -> Option<&WlSurface>; - /// Returns a pointer to the `wl_display` object of wayland that is used by this window. + /// Returns a pointer to the `WlDisplay` object of wayland that is used by this window. /// /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). - /// - /// The pointer will become invalid when the glutin `Window` is destroyed. - fn get_wayland_display(&self) -> Option<*mut libc::c_void>; + fn get_wayland_display(&self) -> Option<&WlDisplay>; } impl WindowExt for Window { @@ -69,17 +68,17 @@ impl WindowExt for Window { } #[inline] - fn get_wayland_surface(&self) -> Option<*mut libc::c_void> { + fn get_wayland_surface(&self) -> Option<&WlSurface> { match self.window { - LinuxWindow::Wayland(ref w) => Some(w.get_wayland_surface()), + LinuxWindow::Wayland(ref w) => Some(w.get_surface()), _ => None } } #[inline] - fn get_wayland_display(&self) -> Option<*mut libc::c_void> { + fn get_wayland_display(&self) -> Option<&WlDisplay> { match self.window { - LinuxWindow::Wayland(ref w) => Some(w.get_wayland_display()), + LinuxWindow::Wayland(ref w) => Some(w.get_display()), _ => None } } diff --git a/src/platform/linux/api_dispatch.rs b/src/platform/linux/api_dispatch.rs index 975cadaf..6b542c81 100644 --- a/src/platform/linux/api_dispatch.rs +++ b/src/platform/linux/api_dispatch.rs @@ -1,6 +1,3 @@ -/*pub use api::x11::{Window, WindowProxy, MonitorId, get_available_monitors, get_primary_monitor}; -pub use api::x11::{WaitEventsIterator, PollEventsIterator};*/ - use std::collections::VecDeque; use std::sync::Arc; @@ -22,15 +19,15 @@ pub struct PlatformSpecificWindowBuilderAttributes; enum Backend { X(Arc), - Wayland, + Wayland(Arc), Error(XNotSupported), } lazy_static!( static ref BACKEND: Backend = { // Wayland backend is not production-ready yet so we disable it - if wayland::is_available() { - Backend::Wayland + if let Some(ctxt) = wayland::WaylandContext::init() { + Backend::Wayland(Arc::new(ctxt)) } else { match XConnection::new(Some(x_error_callback)) { Ok(x) => Backend::X(Arc::new(x)), @@ -78,7 +75,7 @@ pub enum MonitorId { #[inline] pub fn get_available_monitors() -> VecDeque { match *BACKEND { - Backend::Wayland => wayland::get_available_monitors() + Backend::Wayland(ref ctxt) => ctxt.get_available_monitors() .into_iter() .map(MonitorId::Wayland) .collect(), @@ -93,7 +90,7 @@ pub fn get_available_monitors() -> VecDeque { #[inline] pub fn get_primary_monitor() -> MonitorId { match *BACKEND { - Backend::Wayland => MonitorId::Wayland(wayland::get_primary_monitor()), + Backend::Wayland(ref ctxt) => MonitorId::Wayland(ctxt.get_primary_monitor()), Backend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)), Backend::Error(_) => MonitorId::None, } @@ -173,8 +170,8 @@ impl Window { -> Result { match *BACKEND { - Backend::Wayland => { - wayland::Window::new(window).map(Window::Wayland) + Backend::Wayland(ref ctxt) => { + wayland::Window::new(ctxt.clone(), window).map(Window::Wayland) }, Backend::X(ref connec) => { @@ -318,17 +315,19 @@ impl Window { #[inline] pub fn platform_display(&self) -> *mut libc::c_void { + use wayland_client::Proxy; match self { &Window::X(ref w) => w.platform_display(), - &Window::Wayland(ref w) => w.platform_display() + &Window::Wayland(ref w) => w.get_display().ptr() as *mut _ } } #[inline] pub fn platform_window(&self) -> *mut libc::c_void { + use wayland_client::Proxy; match self { &Window::X(ref w) => w.platform_window(), - &Window::Wayland(ref w) => w.platform_window() + &Window::Wayland(ref w) => w.get_surface().ptr() as *mut _ } } } From a505eddf29b1d96130e11a20633e0c458f2c6007 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 7 Oct 2016 21:10:21 +0200 Subject: [PATCH 02/12] wayland: bases of backend and output handling --- src/api/wayland/context.rs | 208 +++++++++++++++++++++++++++-- src/api/wayland/mod.rs | 3 +- src/lib.rs | 2 +- src/platform/linux/api_dispatch.rs | 4 +- 4 files changed, 200 insertions(+), 17 deletions(-) diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index dc03e964..28c4f204 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -1,6 +1,13 @@ use std::collections::VecDeque; +use std::sync::{Arc, Mutex}; -use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor}; +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}; + +/* + * Registry and globals handling + */ wayland_env!(InnerEnv, compositor: wl_compositor::WlCompositor, @@ -10,29 +17,197 @@ wayland_env!(InnerEnv, subcompositor: wl_subcompositor::WlSubcompositor ); +struct WaylandEnv { + registry: wl_registry::WlRegistry, + inner: EnvHandler, + monitors: Vec, + my_id: usize +} + +struct OutputInfo { + output: wl_output::WlOutput, + id: u32, + scale: f32, + pix_size: (u32, u32), + name: String +} + +impl OutputInfo { + fn new(output: wl_output::WlOutput, id: u32) -> OutputInfo { + OutputInfo { + output: output, + id: id, + scale: 1.0, + pix_size: (0, 0), + name: "".into() + } + } +} + +impl WaylandEnv { + fn new(registry: wl_registry::WlRegistry) -> WaylandEnv { + WaylandEnv { + registry: registry, + inner: EnvHandler::new(), + monitors: Vec::new(), + my_id: 0 + } + } +} + +impl Init for WaylandEnv { + fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) { + evqh.register::<_, WaylandEnv>(&self.registry, index); + self.my_id = index + } +} + +impl wl_registry::Handler for WaylandEnv { + fn global(&mut self, + evqh: &mut EventQueueHandle, + registry: &wl_registry::WlRegistry, + name: u32, + interface: String, + version: u32) + { + if interface == "wl_output" { + // intercept outputs + // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) + let output = self.registry.bind::(1, name) + .expect("Registry cannot be dead"); + evqh.register::<_, WaylandEnv>(&output, self.my_id); + self.monitors.push(OutputInfo::new(output, name)); + } + self.inner.global(evqh, registry, name, interface, version); + } + + fn global_remove(&mut self, + evqh: &mut EventQueueHandle, + registry: &wl_registry::WlRegistry, + name: u32) + { + // prune old monitors + self.monitors.retain(|m| m.id != name); + self.inner.global_remove(evqh, registry, name); + } +} + +declare_handler!(WaylandEnv, wl_registry::Handler, wl_registry::WlRegistry); + +impl wl_output::Handler for WaylandEnv { + fn geometry(&mut self, + _: &mut EventQueueHandle, + proxy: &wl_output::WlOutput, + _x: i32, _y: i32, + _physical_width: i32, _physical_height: i32, + _subpixel: wl_output::Subpixel, + make: String, model: String, + _transform: wl_output::Transform) + { + for m in self.monitors.iter_mut().filter(|m| m.output.equals(proxy)) { + m.name = format!("{} ({})", model, make); + break; + } + } + fn mode(&mut self, + _: &mut EventQueueHandle, + proxy: &wl_output::WlOutput, + flags: wl_output::Mode, + width: i32, height: i32, + _refresh: i32) + { + if flags.contains(wl_output::Current) { + for m in self.monitors.iter_mut().filter(|m| m.output.equals(proxy)) { + m.pix_size = (width as u32, height as u32); + break; + } + } + } + fn scale(&mut self, + _: &mut EventQueueHandle, + proxy: &wl_output::WlOutput, + factor: i32) + { + for m in self.monitors.iter_mut().filter(|m| m.output.equals(proxy)) { + m.scale = factor as f32; + break; + } + } +} + +declare_handler!(WaylandEnv, wl_output::Handler, wl_output::WlOutput); + +/* + * Main context struct + */ + pub struct WaylandContext { + pub display: wl_display::WlDisplay, + evq: Mutex, + env_id: usize, } impl WaylandContext { pub fn init() -> Option { - None - } - - pub fn get_primary_monitor(&self) -> MonitorId { - unimplemented!() - } - - pub fn get_available_monitors(&self) -> VecDeque { - unimplemented!() + // attempt to connect to the wayland server + // this handles both "no libwayland" and "no compositor" cases + let (display, mut event_queue) = match default_connect() { + Ok(ret) => ret, + Err(e) => return None + }; + + // this expect cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) + let registry = display.get_registry().expect("Display cannot be already destroyed."); + let env_id = event_queue.add_handler_with_init(WaylandEnv::new(registry)); + event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost"); + + Some(WaylandContext { + evq: Mutex::new(event_queue), + display: display, + env_id: env_id + }) } } +pub fn get_primary_monitor(ctxt: &Arc) -> MonitorId { + let mut guard = ctxt.evq.lock().unwrap(); + let state = guard.state(); + let env = state.get_handler::(ctxt.env_id); + if let Some(ref monitor) = env.monitors.iter().next() { + MonitorId { + id: monitor.id, + ctxt: ctxt.clone() + } + } else { + panic!("No monitor is available.") + } +} + +pub fn get_available_monitors(ctxt: &Arc) -> VecDeque { + let mut guard = ctxt.evq.lock().unwrap(); + let state = guard.state(); + let env = state.get_handler::(ctxt.env_id); + env.monitors.iter() + .map(|m| MonitorId { id: m.id, ctxt: ctxt.clone() }) + .collect() +} + #[derive(Clone)] -pub struct MonitorId; +pub struct MonitorId { + id: u32, + ctxt: Arc +} impl MonitorId { pub fn get_name(&self) -> Option { - unimplemented!() + let mut guard = self.ctxt.evq.lock().unwrap(); + let state = guard.state(); + let env = state.get_handler::(self.ctxt.env_id); + for m in env.monitors.iter().filter(|m| m.id == self.id) { + return Some(m.name.clone()) + } + // if we reach here, this monitor does not exist any more + None } #[inline] @@ -41,6 +216,13 @@ impl MonitorId { } pub fn get_dimensions(&self) -> (u32, u32) { - unimplemented!() + let mut guard = self.ctxt.evq.lock().unwrap(); + let state = guard.state(); + let env = state.get_handler::(self.ctxt.env_id); + for m in env.monitors.iter().filter(|m| m.id == self.id) { + return m.pix_size + } + // if we reach here, this monitor does not exist any more + (0,0) } } diff --git a/src/api/wayland/mod.rs b/src/api/wayland/mod.rs index 11ab4842..bf6ba775 100644 --- a/src/api/wayland/mod.rs +++ b/src/api/wayland/mod.rs @@ -1,7 +1,8 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] pub use self::window::{PollEventsIterator, WaitEventsIterator, Window, WindowProxy}; -pub use self::context::{WaylandContext,MonitorId}; +pub use self::context::{WaylandContext, MonitorId, get_available_monitors, + get_primary_monitor}; extern crate wayland_kbd; extern crate wayland_window; diff --git a/src/lib.rs b/src/lib.rs index e37b9bf4..1f1c626b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,7 @@ extern crate core_graphics; #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] extern crate x11_dl; #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] -#[macro_use(wayland_env)] +#[macro_use(wayland_env,declare_handler)] extern crate wayland_client; pub use events::*; diff --git a/src/platform/linux/api_dispatch.rs b/src/platform/linux/api_dispatch.rs index 6b542c81..1609a1aa 100644 --- a/src/platform/linux/api_dispatch.rs +++ b/src/platform/linux/api_dispatch.rs @@ -75,7 +75,7 @@ pub enum MonitorId { #[inline] pub fn get_available_monitors() -> VecDeque { match *BACKEND { - Backend::Wayland(ref ctxt) => ctxt.get_available_monitors() + Backend::Wayland(ref ctxt) => wayland::get_available_monitors(ctxt) .into_iter() .map(MonitorId::Wayland) .collect(), @@ -90,7 +90,7 @@ pub fn get_available_monitors() -> VecDeque { #[inline] pub fn get_primary_monitor() -> MonitorId { match *BACKEND { - Backend::Wayland(ref ctxt) => MonitorId::Wayland(ctxt.get_primary_monitor()), + Backend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)), Backend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)), Backend::Error(_) => MonitorId::None, } From 34c00aa153f28f3bce8884f25879f9d809cdaaae Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sat, 8 Oct 2016 14:51:29 +0200 Subject: [PATCH 03/12] wayland: window creation & resizing --- Cargo.toml | 4 +- src/api/wayland/context.rs | 80 ++++++++++++++++- src/api/wayland/window.rs | 175 ++++++++++++++++++++++++++++++++++--- 3 files changed, 243 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index da966210..7d6c68ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ kernel32-sys = "0.2" dwmapi-sys = "0.1" [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies] -wayland-client = { version = "0.7.1", features = ["dlopen"] } +wayland-client = { version = "0.7.3", features = ["dlopen"] } wayland-kbd = "0.6" -wayland-window = "0.4" +wayland-window = "0.4.2" x11-dl = "2.8" diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index 28c4f204..73e4ac44 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -1,9 +1,13 @@ +use Event; + use std::collections::VecDeque; 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_display, wl_registry, wl_output, wl_surface}; + +use super::wayland_window; /* * Registry and globals handling @@ -21,7 +25,8 @@ struct WaylandEnv { registry: wl_registry::WlRegistry, inner: EnvHandler, monitors: Vec, - my_id: usize + my_id: usize, + windows: Vec<(Arc,Arc>>)> } struct OutputInfo { @@ -50,9 +55,21 @@ impl WaylandEnv { registry: registry, inner: EnvHandler::new(), monitors: Vec::new(), - my_id: 0 + my_id: 0, + windows: Vec::new() } } + + fn get_seat(&self) -> Option { + for &(name, ref interface, version) in self.inner.globals() { + if interface == "wl_seat" { + // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) + let seat = self.registry.bind::(5, name).expect("Seat cannot be destroyed"); + return Some(seat) + } + } + None + } } impl Init for WaylandEnv { @@ -156,9 +173,11 @@ impl WaylandContext { Err(e) => return None }; - // this expect cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) + // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) let registry = display.get_registry().expect("Display cannot be already destroyed."); let env_id = event_queue.add_handler_with_init(WaylandEnv::new(registry)); + // two syncs fully initialize + event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost"); event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost"); Some(WaylandContext { @@ -167,6 +186,59 @@ impl WaylandContext { env_id: env_id }) } + + pub fn dispatch_pending(&self) { + let mut guard = self.evq.lock().unwrap(); + guard.dispatch_pending().expect("Wayland connection unexpectedly lost"); + } + + pub fn dispatch(&self) { + let mut guard = self.evq.lock().unwrap(); + guard.dispatch().expect("Wayland connection unexpectedly lost"); + } + + pub fn flush(&self) { + self.display.flush(); + } + + pub fn with_output(&self, id: MonitorId, f: F) where F: FnOnce(&wl_output::WlOutput) { + let mut guard = self.evq.lock().unwrap(); + let state = guard.state(); + let env = state.get_handler::(self.env_id); + for m in env.monitors.iter().filter(|m| m.id == id.id) { + f(&m.output); + break + } + } + + pub fn create_window(&self) + -> (Arc, Arc>>, wayland_window::DecoratedSurface) + { + 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().expect("Compositor cannot be dead")); + let eventiter = Arc::new(Mutex::new(VecDeque::new())); + env.windows.push((surface.clone(), eventiter.clone())); + let decorated = wayland_window::DecoratedSurface::new( + &*surface, 800, 600, + &env.inner.compositor, + &env.inner.subcompositor, + &env.inner.shm, + &env.inner.shell, + env.get_seat(), + false + ).expect("Failed to create a tmpfile buffer."); + (surface, eventiter, decorated) + } + + pub fn prune_dead_windows(&self) { + let mut guard = self.evq.lock().unwrap(); + let mut state = guard.state(); + let env = state.get_mut_handler::(self.env_id); + env.windows.retain(|w| w.0.is_alive()); + } } pub fn get_primary_monitor(ctxt: &Arc) -> MonitorId { diff --git a/src/api/wayland/window.rs b/src/api/wayland/window.rs index 99b7e694..bdb063c9 100644 --- a/src/api/wayland/window.rs +++ b/src/api/wayland/window.rs @@ -1,10 +1,15 @@ -use std::sync::Arc; +use std::collections::VecDeque; +use std::sync::{Arc, Mutex}; -use wayland_client::protocol::{wl_display,wl_surface}; +use wayland_client::{EventQueue, EventQueueHandle, Init}; +use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface}; use {CreationError, MouseCursor, CursorState, Event, WindowAttributes}; +use platform::MonitorId as PlatformMonitorId; use super::WaylandContext; +use super::wayland_window; +use super::wayland_window::DecoratedSurface; #[derive(Clone)] pub struct WindowProxy; @@ -17,7 +22,13 @@ impl WindowProxy { } pub struct Window { - resize_callback: Option + ctxt: Arc, + evq: Mutex, + eviter: Arc>>, + surface: Arc, + size: Mutex<(u32, u32)>, + handler_id: usize, + decorated_id: usize } pub struct PollEventsIterator<'a> { @@ -28,7 +39,7 @@ impl<'a> Iterator for PollEventsIterator<'a> { type Item = Event; fn next(&mut self) -> Option { - unimplemented!() + self.window.next_event(false) } } @@ -40,14 +51,112 @@ impl<'a> Iterator for WaitEventsIterator<'a> { type Item = Event; fn next(&mut self) -> Option { - unimplemented!() + self.window.next_event(true) } } impl Window { pub fn new(ctxt: Arc, attributes: &WindowAttributes) -> Result { - unimplemented!() + let (width, height) = attributes.dimensions.unwrap_or((800,600)); + + let mut evq = ctxt.display.create_event_queue(); + + let (surface, eviter, decorated) = ctxt.create_window::(); + + // init DecoratedSurface + let decorated_id = evq.add_handler_with_init(decorated); + { + let mut state = evq.state(); + let decorated = state.get_mut_handler::>(decorated_id); + *(decorated.handler()) = Some(DecoratedHandler::new()); + + if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor { + ctxt.with_output(monitor_id.clone(), |output| { + decorated.set_fullscreen( + wl_shell_surface::FullscreenMethod::Default, + 0, + Some(output) + ) + }); + } else if attributes.decorations { + decorated.set_decorate(true); + } + } + + // init general handler + let handler = WindowHandler::new(); + let handler_id = evq.add_handler_with_init(handler); + + Ok(Window { + ctxt: ctxt, + evq: Mutex::new(evq), + eviter: eviter, + surface: surface, + size: Mutex::new((width, height)), + handler_id: handler_id, + decorated_id: decorated_id + }) + } + + fn process_resize(&self) { + use std::cmp::max; + let mut evq_guard = self.evq.lock().unwrap(); + let mut state = evq_guard.state(); + let newsize = { + let decorated = state.get_mut_handler::>(self.decorated_id); + let newsize = decorated.handler().as_mut().and_then(|h| h.take_newsize()); + if let Some((w, h)) = newsize { + decorated.resize(w as i32, h as i32); + *self.size.lock().unwrap() = (w, h); + } + newsize + }; + // callback_resize if any + if let Some((w, h)) = newsize { + let mut handler = state.get_mut_handler::(self.handler_id); + if let Some(ref callback) = handler.resize_callback { + callback(w, h); + } + self.eviter.lock().unwrap().push_back(Event::Resized(w,h)); + } + } + + fn next_event(&self, block: bool) -> Option { + let mut evt = { + let mut guard = self.eviter.lock().unwrap(); + guard.pop_front() + }; + if evt.is_some() { return evt } + + // try a pending dispatch + // TODO: insert a non-blocking read from socket, overwise no new events will ever come + { + self.ctxt.dispatch_pending(); + let mut guard = self.evq.lock().unwrap().dispatch_pending(); + // some events were dispatched, need to process a potential resising + self.process_resize(); + } + + let mut evt = { + let mut guard = self.eviter.lock().unwrap(); + guard.pop_front() + }; + + while block && evt.is_none() { + // no event waiting, need to repopulate! + { + self.ctxt.flush(); + self.ctxt.dispatch(); + let mut guard = self.evq.lock().unwrap().dispatch(); + // some events were dispatched, need to process a potential resising + self.process_resize(); + } + // try again + let mut guard = self.eviter.lock().unwrap(); + evt = guard.pop_front() + } + evt } pub fn set_title(&self, title: &str) { @@ -112,7 +221,10 @@ impl Window { #[inline] pub fn set_window_resize_callback(&mut self, callback: Option) { - self.resize_callback = callback; + let mut guard = self.evq.lock().unwrap(); + let mut state = guard.state(); + let mut handler = state.get_mut_handler::(self.handler_id); + handler.resize_callback = callback; } #[inline] @@ -144,16 +256,59 @@ impl Window { } pub fn get_display(&self) -> &wl_display::WlDisplay { - unimplemented!() + &self.ctxt.display } pub fn get_surface(&self) -> &wl_surface::WlSurface { - unimplemented!() + &self.surface } } impl Drop for Window { fn drop(&mut self) { - // TODO + self.surface.destroy(); + self.ctxt.prune_dead_windows(); + } +} + +struct DecoratedHandler { + newsize: Option<(u32, u32)> +} + +impl DecoratedHandler { + fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }} + fn take_newsize(&mut self) -> Option<(u32, u32)> { + self.newsize.take() + } +} + +impl wayland_window::Handler for DecoratedHandler { + fn configure(&mut self, + _: &mut EventQueueHandle, + _: wl_shell_surface::Resize, + width: i32, height: i32) + { + use std::cmp::max; + self.newsize = Some((max(width,1) as u32, max(height,1) as u32)); + } +} + +struct WindowHandler { + my_id: usize, + resize_callback: Option, +} + +impl WindowHandler { + fn new() -> WindowHandler { + WindowHandler { + my_id: 0, + resize_callback: None + } + } +} + +impl Init for WindowHandler { + fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) { + self.my_id = index; } } From a5ba9983c934b5469e4d95a825912a6c5e98ee7e Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 9 Oct 2016 16:03:00 +0200 Subject: [PATCH 04/12] wayland: basic mouse & keyboard support --- Cargo.toml | 2 +- src/api/wayland/context.rs | 272 +++++++++++++++++++++++++++++++++++- src/api/wayland/keyboard.rs | 216 ++++++++++++++++++++++++++++ src/api/wayland/mod.rs | 1 + 4 files changed, 485 insertions(+), 6 deletions(-) create mode 100644 src/api/wayland/keyboard.rs diff --git a/Cargo.toml b/Cargo.toml index 7d6c68ac..40fae0fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,6 @@ dwmapi-sys = "0.1" [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies] wayland-client = { version = "0.7.3", features = ["dlopen"] } -wayland-kbd = "0.6" +wayland-kbd = "0.6.2" wayland-window = "0.4.2" x11-dl = "2.8" diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index 73e4ac44..45a13529 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -1,13 +1,16 @@ -use Event; +use {Event, ElementState, MouseButton}; use std::collections::VecDeque; 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_pointer, + wl_keyboard}; use super::wayland_window; +use super::wayland_kbd::MappedKeyboard; +use super::keyboard::KbdHandler; /* * Registry and globals handling @@ -15,7 +18,6 @@ use super::wayland_window; wayland_env!(InnerEnv, compositor: wl_compositor::WlCompositor, - seat: wl_seat::WlSeat, shell: wl_shell::WlShell, shm: wl_shm::WlShm, subcompositor: wl_subcompositor::WlSubcompositor @@ -26,7 +28,13 @@ struct WaylandEnv { inner: EnvHandler, monitors: Vec, my_id: usize, - windows: Vec<(Arc,Arc>>)> + windows: Vec<(Arc,Arc>>)>, + seat: Option, + mouse: Option, + mouse_focus: Option>>>, + mouse_location: (i32, i32), + kbd: Option, + kbd_handler: MappedKeyboard } struct OutputInfo { @@ -56,7 +64,13 @@ impl WaylandEnv { inner: EnvHandler::new(), monitors: Vec::new(), my_id: 0, - windows: Vec::new() + windows: Vec::new(), + seat: None, + mouse: None, + mouse_focus: None, + mouse_location: (0,0), + kbd: None, + kbd_handler: MappedKeyboard::new(KbdHandler::new()).ok().expect("Missing libxkbcommon!") // TODO } } @@ -94,6 +108,14 @@ impl wl_registry::Handler for WaylandEnv { .expect("Registry cannot be dead"); evqh.register::<_, WaylandEnv>(&output, self.my_id); self.monitors.push(OutputInfo::new(output, name)); + } else if interface == "wl_seat" && self.seat.is_none() { + // Only grab the first seat + // TODO: Handle multi-seat-setup? + assert!(version >= 5, "Version 5 of seat interface is needed by glutin."); + let seat = self.registry.bind::(5, name) + .expect("Registry cannot be dead"); + evqh.register::<_, WaylandEnv>(&seat, self.my_id); + self.seat = Some(seat); } self.inner.global(evqh, registry, name, interface, version); } @@ -241,6 +263,10 @@ impl WaylandContext { } } +/* + * Monitors API + */ + pub fn get_primary_monitor(ctxt: &Arc) -> MonitorId { let mut guard = ctxt.evq.lock().unwrap(); let state = guard.state(); @@ -298,3 +324,239 @@ impl MonitorId { (0,0) } } + +/* + * Input Handling + */ + +impl wl_seat::Handler for WaylandEnv { + fn capabilities(&mut self, + evqh: &mut EventQueueHandle, + seat: &wl_seat::WlSeat, + capabilities: wl_seat::Capability) + { + // create pointer if applicable + if capabilities.contains(wl_seat::Pointer) && self.mouse.is_none() { + let pointer = seat.get_pointer().expect("Seat is not dead"); + evqh.register::<_, WaylandEnv>(&pointer, self.my_id); + self.mouse = Some(pointer); + } + // destroy pointer if applicable + if !capabilities.contains(wl_seat::Pointer) { + if let Some(pointer) = self.mouse.take() { + pointer.release(); + } + } + // create keyboard if applicable + if capabilities.contains(wl_seat::Keyboard) && self.kbd.is_none() { + let kbd = seat.get_keyboard().expect("Seat is not dead"); + evqh.register::<_, WaylandEnv>(&kbd, self.my_id); + self.kbd = Some(kbd); + } + // destroy keyboard if applicable + if !capabilities.contains(wl_seat::Keyboard) { + if let Some(kbd) = self.kbd.take() { + kbd.release(); + } + } + } +} + +declare_handler!(WaylandEnv, wl_seat::Handler, wl_seat::WlSeat); + +/* + * Pointer Handling + */ + +impl wl_pointer::Handler for WaylandEnv { + fn enter(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _serial: u32, + surface: &wl_surface::WlSurface, + surface_x: f64, + surface_y: f64) + { + self.mouse_location = (surface_x as i32, surface_y as i32); + for &(ref window, ref eviter) in &self.windows { + if window.equals(surface) { + self.mouse_focus = Some(eviter.clone()); + let (w, h) = self.mouse_location; + eviter.lock().unwrap().push_back( + Event::MouseMoved(w, h) + ); + break; + } + } + } + + fn leave(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _serial: u32, + _surface: &wl_surface::WlSurface) + { + self.mouse_focus = None + } + + fn motion(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _time: u32, + surface_x: f64, + surface_y: f64) + { + self.mouse_location = (surface_x as i32, surface_y as i32); + if let Some(ref eviter) = self.mouse_focus { + let (w,h) = self.mouse_location; + eviter.lock().unwrap().push_back( + Event::MouseMoved(w, h) + ); + } + } + + fn button(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _serial: u32, + _time: u32, + button: u32, + state: wl_pointer::ButtonState) + { + if let Some(ref eviter) = self.mouse_focus { + let state = match state { + wl_pointer::ButtonState::Pressed => ElementState::Pressed, + wl_pointer::ButtonState::Released => ElementState::Released + }; + let button = match button { + 0x110 => MouseButton::Left, + 0x111 => MouseButton::Right, + 0x112 => MouseButton::Middle, + // TODO figure out the translation ? + _ => return + }; + eviter.lock().unwrap().push_back( + Event::MouseInput(state, button) + ); + } + } + + // TODO: proper scroll handling + + fn axis(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _time: u32, + axis: wl_pointer::Axis, + value: f64) + { + } + + fn frame(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer) + { + } + + fn axis_source(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + axis_source: wl_pointer::AxisSource) + { + } + + fn axis_stop(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _time: u32, + axis: wl_pointer::Axis) + { + } + + fn axis_discrete(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + axis: wl_pointer::Axis, + discrete: i32) + { + } +} + +declare_handler!(WaylandEnv, wl_pointer::Handler, wl_pointer::WlPointer); + +/* + * Keyboard Handling + */ + +impl wl_keyboard::Handler for WaylandEnv { + // mostly pass-through + fn keymap(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + format: wl_keyboard::KeymapFormat, + fd: ::std::os::unix::io::RawFd, + size: u32) + { + self.kbd_handler.keymap(evqh, proxy, format, fd, size) + } + + fn enter(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + serial: u32, + surface: &wl_surface::WlSurface, + keys: Vec) + { + for &(ref window, ref eviter) in &self.windows { + if window.equals(surface) { + self.kbd_handler.handler().target = Some(eviter.clone()); + break + } + } + self.kbd_handler.enter(evqh, proxy, serial, surface, keys) + } + + fn leave(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + serial: u32, + surface: &wl_surface::WlSurface) + { + self.kbd_handler.handler().target = None; + self.kbd_handler.leave(evqh, proxy, serial, surface) + } + + fn key(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + serial: u32, + time: u32, + key: u32, + state: wl_keyboard::KeyState) + { + self.kbd_handler.key(evqh, proxy, serial, time, key, state) + } + + fn modifiers(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + serial: u32, + mods_depressed: u32, + mods_latched: u32, + mods_locked: u32, + group: u32) + { + self.kbd_handler.modifiers(evqh, proxy, serial, mods_depressed, mods_latched, mods_locked, group) + } + + fn repeat_info(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + rate: i32, + delay: i32) + { + self.kbd_handler.repeat_info(evqh, proxy, rate, delay) + } +} + +declare_handler!(WaylandEnv, wl_keyboard::Handler, wl_keyboard::WlKeyboard); diff --git a/src/api/wayland/keyboard.rs b/src/api/wayland/keyboard.rs new file mode 100644 index 00000000..abc3069c --- /dev/null +++ b/src/api/wayland/keyboard.rs @@ -0,0 +1,216 @@ +use std::collections::VecDeque; +use std::sync::{Arc, Mutex}; + +use {VirtualKeyCode, ElementState, Event}; + +use super::wayland_kbd; +use wayland_client::EventQueueHandle; +use wayland_client::protocol::wl_keyboard; + +pub struct KbdHandler { + pub target: Option>>> +} + +impl KbdHandler { + pub fn new() -> KbdHandler { + KbdHandler { target: None } + } +} + +impl wayland_kbd::Handler for KbdHandler { + fn key(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_keyboard::WlKeyboard, + _serial: u32, + _time: u32, + rawkey: u32, + keysym: u32, + state: wl_keyboard::KeyState, + utf8: Option) + { + if let Some(ref eviter) = self.target { + let state = match state { + wl_keyboard::KeyState::Pressed => ElementState::Pressed, + wl_keyboard::KeyState::Released => ElementState::Released, + }; + let vkcode = key_to_vkey(rawkey, keysym); + let mut guard = eviter.lock().unwrap(); + guard.push_back(Event::KeyboardInput(state, rawkey as u8, vkcode)); + // send char event only on key press, not release + if let ElementState::Released = state { return } + if let Some(txt) = utf8 { + for chr in txt.chars() { + guard.push_back(Event::ReceivedCharacter(chr)); + } + } + } + } +} + +fn key_to_vkey(rawkey: u32, keysym: u32) -> Option { + match rawkey { + 1 => Some(VirtualKeyCode::Escape), + 2 => Some(VirtualKeyCode::Key1), + 3 => Some(VirtualKeyCode::Key2), + 4 => Some(VirtualKeyCode::Key3), + 5 => Some(VirtualKeyCode::Key4), + 6 => Some(VirtualKeyCode::Key5), + 7 => Some(VirtualKeyCode::Key6), + 8 => Some(VirtualKeyCode::Key7), + 9 => Some(VirtualKeyCode::Key8), + 10 => Some(VirtualKeyCode::Key9), + 11 => Some(VirtualKeyCode::Key0), + _ => keysym_to_vkey(keysym) + } +} + +fn keysym_to_vkey(keysym: u32) -> Option { + use super::wayland_kbd::keysyms; + match keysym { + // letters + keysyms::XKB_KEY_A | keysyms::XKB_KEY_a => Some(VirtualKeyCode::A), + keysyms::XKB_KEY_B | keysyms::XKB_KEY_b => Some(VirtualKeyCode::B), + keysyms::XKB_KEY_C | keysyms::XKB_KEY_c => Some(VirtualKeyCode::C), + keysyms::XKB_KEY_D | keysyms::XKB_KEY_d => Some(VirtualKeyCode::D), + keysyms::XKB_KEY_E | keysyms::XKB_KEY_e => Some(VirtualKeyCode::E), + keysyms::XKB_KEY_F | keysyms::XKB_KEY_f => Some(VirtualKeyCode::F), + keysyms::XKB_KEY_G | keysyms::XKB_KEY_g => Some(VirtualKeyCode::G), + keysyms::XKB_KEY_H | keysyms::XKB_KEY_h => Some(VirtualKeyCode::H), + keysyms::XKB_KEY_I | keysyms::XKB_KEY_i => Some(VirtualKeyCode::I), + keysyms::XKB_KEY_J | keysyms::XKB_KEY_j => Some(VirtualKeyCode::J), + keysyms::XKB_KEY_K | keysyms::XKB_KEY_k => Some(VirtualKeyCode::K), + keysyms::XKB_KEY_L | keysyms::XKB_KEY_l => Some(VirtualKeyCode::L), + keysyms::XKB_KEY_M | keysyms::XKB_KEY_m => Some(VirtualKeyCode::M), + keysyms::XKB_KEY_N | keysyms::XKB_KEY_n => Some(VirtualKeyCode::N), + keysyms::XKB_KEY_O | keysyms::XKB_KEY_o => Some(VirtualKeyCode::O), + keysyms::XKB_KEY_P | keysyms::XKB_KEY_p => Some(VirtualKeyCode::P), + keysyms::XKB_KEY_Q | keysyms::XKB_KEY_q => Some(VirtualKeyCode::Q), + keysyms::XKB_KEY_R | keysyms::XKB_KEY_r => Some(VirtualKeyCode::R), + keysyms::XKB_KEY_S | keysyms::XKB_KEY_s => Some(VirtualKeyCode::S), + keysyms::XKB_KEY_T | keysyms::XKB_KEY_t => Some(VirtualKeyCode::T), + keysyms::XKB_KEY_U | keysyms::XKB_KEY_u => Some(VirtualKeyCode::U), + keysyms::XKB_KEY_V | keysyms::XKB_KEY_v => Some(VirtualKeyCode::V), + keysyms::XKB_KEY_W | keysyms::XKB_KEY_w => Some(VirtualKeyCode::W), + keysyms::XKB_KEY_X | keysyms::XKB_KEY_x => Some(VirtualKeyCode::X), + keysyms::XKB_KEY_Y | keysyms::XKB_KEY_y => Some(VirtualKeyCode::Y), + keysyms::XKB_KEY_Z | keysyms::XKB_KEY_z => Some(VirtualKeyCode::Z), + // F-- + keysyms::XKB_KEY_F1 => Some(VirtualKeyCode::F1), + keysyms::XKB_KEY_F2 => Some(VirtualKeyCode::F2), + keysyms::XKB_KEY_F3 => Some(VirtualKeyCode::F3), + keysyms::XKB_KEY_F4 => Some(VirtualKeyCode::F4), + keysyms::XKB_KEY_F5 => Some(VirtualKeyCode::F5), + keysyms::XKB_KEY_F6 => Some(VirtualKeyCode::F6), + keysyms::XKB_KEY_F7 => Some(VirtualKeyCode::F7), + keysyms::XKB_KEY_F8 => Some(VirtualKeyCode::F8), + keysyms::XKB_KEY_F9 => Some(VirtualKeyCode::F9), + keysyms::XKB_KEY_F10 => Some(VirtualKeyCode::F10), + keysyms::XKB_KEY_F11 => Some(VirtualKeyCode::F11), + keysyms::XKB_KEY_F12 => Some(VirtualKeyCode::F12), + keysyms::XKB_KEY_F13 => Some(VirtualKeyCode::F13), + keysyms::XKB_KEY_F14 => Some(VirtualKeyCode::F14), + keysyms::XKB_KEY_F15 => Some(VirtualKeyCode::F15), + // flow control + keysyms::XKB_KEY_Print => Some(VirtualKeyCode::Snapshot), + keysyms::XKB_KEY_Scroll_Lock => Some(VirtualKeyCode::Scroll), + keysyms::XKB_KEY_Pause => Some(VirtualKeyCode::Pause), + keysyms::XKB_KEY_Insert => Some(VirtualKeyCode::Insert), + keysyms::XKB_KEY_Home => Some(VirtualKeyCode::Home), + keysyms::XKB_KEY_Delete => Some(VirtualKeyCode::Delete), + keysyms::XKB_KEY_End => Some(VirtualKeyCode::End), + keysyms::XKB_KEY_Page_Down => Some(VirtualKeyCode::PageDown), + keysyms::XKB_KEY_Page_Up => Some(VirtualKeyCode::PageUp), + // arrows + keysyms::XKB_KEY_Left => Some(VirtualKeyCode::Left), + keysyms::XKB_KEY_Up => Some(VirtualKeyCode::Up), + keysyms::XKB_KEY_Right => Some(VirtualKeyCode::Right), + keysyms::XKB_KEY_Down => Some(VirtualKeyCode::Down), + // + keysyms::XKB_KEY_BackSpace => Some(VirtualKeyCode::Back), + keysyms::XKB_KEY_Return => Some(VirtualKeyCode::Return), + keysyms::XKB_KEY_space => Some(VirtualKeyCode::Space), + // keypad + keysyms::XKB_KEY_Num_Lock => Some(VirtualKeyCode::Numlock), + keysyms::XKB_KEY_KP_0 => Some(VirtualKeyCode::Numpad0), + keysyms::XKB_KEY_KP_1 => Some(VirtualKeyCode::Numpad1), + keysyms::XKB_KEY_KP_2 => Some(VirtualKeyCode::Numpad2), + keysyms::XKB_KEY_KP_3 => Some(VirtualKeyCode::Numpad3), + keysyms::XKB_KEY_KP_4 => Some(VirtualKeyCode::Numpad4), + keysyms::XKB_KEY_KP_5 => Some(VirtualKeyCode::Numpad5), + keysyms::XKB_KEY_KP_6 => Some(VirtualKeyCode::Numpad6), + keysyms::XKB_KEY_KP_7 => Some(VirtualKeyCode::Numpad7), + keysyms::XKB_KEY_KP_8 => Some(VirtualKeyCode::Numpad8), + keysyms::XKB_KEY_KP_9 => Some(VirtualKeyCode::Numpad9), + // misc + // => Some(VirtualKeyCode::AbntC1), + // => Some(VirtualKeyCode::AbntC2), + keysyms::XKB_KEY_plus => Some(VirtualKeyCode::Add), + keysyms::XKB_KEY_apostrophe => Some(VirtualKeyCode::Apostrophe), + // => Some(VirtualKeyCode::Apps), + // => Some(VirtualKeyCode::At), + // => Some(VirtualKeyCode::Ax), + keysyms::XKB_KEY_backslash => Some(VirtualKeyCode::Backslash), + // => Some(VirtualKeyCode::Calculator), + // => Some(VirtualKeyCode::Capital), + keysyms::XKB_KEY_colon => Some(VirtualKeyCode::Colon), + keysyms::XKB_KEY_comma => Some(VirtualKeyCode::Comma), + // => Some(VirtualKeyCode::Convert), + // => Some(VirtualKeyCode::Decimal), + // => Some(VirtualKeyCode::Divide), + keysyms::XKB_KEY_equal => Some(VirtualKeyCode::Equals), + // => Some(VirtualKeyCode::Grave), + // => Some(VirtualKeyCode::Kana), + // => Some(VirtualKeyCode::Kanji), + keysyms::XKB_KEY_Alt_L => Some(VirtualKeyCode::LAlt), + // => Some(VirtualKeyCode::LBracket), + keysyms::XKB_KEY_Control_L => Some(VirtualKeyCode::LControl), + // => Some(VirtualKeyCode::LMenu), + keysyms::XKB_KEY_Shift_L => Some(VirtualKeyCode::LShift), + // => Some(VirtualKeyCode::LWin), + // => Some(VirtualKeyCode::Mail), + // => Some(VirtualKeyCode::MediaSelect), + // => Some(VirtualKeyCode::MediaStop), + keysyms::XKB_KEY_minus => Some(VirtualKeyCode::Minus), + keysyms::XKB_KEY_asterisk => Some(VirtualKeyCode::Multiply), + // => Some(VirtualKeyCode::Mute), + // => Some(VirtualKeyCode::MyComputer), + // => Some(VirtualKeyCode::NextTrack), + // => Some(VirtualKeyCode::NoConvert), + keysyms::XKB_KEY_KP_Separator => Some(VirtualKeyCode::NumpadComma), + keysyms::XKB_KEY_KP_Enter => Some(VirtualKeyCode::NumpadEnter), + keysyms::XKB_KEY_KP_Equal => Some(VirtualKeyCode::NumpadEquals), + // => Some(VirtualKeyCode::OEM102), + // => Some(VirtualKeyCode::Period), + // => Some(VirtualKeyCode::Playpause), + // => Some(VirtualKeyCode::Power), + // => Some(VirtualKeyCode::Prevtrack), + keysyms::XKB_KEY_Alt_R => Some(VirtualKeyCode::RAlt), + // => Some(VirtualKeyCode::RBracket), + keysyms::XKB_KEY_Control_R => Some(VirtualKeyCode::RControl), + // => Some(VirtualKeyCode::RMenu), + keysyms::XKB_KEY_Shift_R => Some(VirtualKeyCode::RShift), + // => Some(VirtualKeyCode::RWin), + keysyms::XKB_KEY_semicolon => Some(VirtualKeyCode::Semicolon), + keysyms::XKB_KEY_slash => Some(VirtualKeyCode::Slash), + // => Some(VirtualKeyCode::Sleep), + // => Some(VirtualKeyCode::Stop), + // => Some(VirtualKeyCode::Subtract), + // => Some(VirtualKeyCode::Sysrq), + keysyms::XKB_KEY_Tab => Some(VirtualKeyCode::Tab), + // => Some(VirtualKeyCode::Underline), + // => Some(VirtualKeyCode::Unlabeled), + keysyms::XKB_KEY_XF86AudioLowerVolume => Some(VirtualKeyCode::VolumeDown), + keysyms::XKB_KEY_XF86AudioRaiseVolume => Some(VirtualKeyCode::VolumeUp), + // => Some(VirtualKeyCode::Wake), + // => Some(VirtualKeyCode::Webback), + // => Some(VirtualKeyCode::WebFavorites), + // => Some(VirtualKeyCode::WebForward), + // => Some(VirtualKeyCode::WebHome), + // => Some(VirtualKeyCode::WebRefresh), + // => Some(VirtualKeyCode::WebSearch), + // => Some(VirtualKeyCode::WebStop), + // => Some(VirtualKeyCode::Yen), + // fallback + _ => None + } +} diff --git a/src/api/wayland/mod.rs b/src/api/wayland/mod.rs index bf6ba775..cb0c5b5b 100644 --- a/src/api/wayland/mod.rs +++ b/src/api/wayland/mod.rs @@ -8,4 +8,5 @@ extern crate wayland_kbd; extern crate wayland_window; mod context; +mod keyboard; mod window; From 6483e7f4082f268b0e665f6e6cf58e06ffe385b2 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 9 Oct 2016 16:19:06 +0200 Subject: [PATCH 05/12] wayland: Some Window methods --- src/api/wayland/window.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/api/wayland/window.rs b/src/api/wayland/window.rs index bdb063c9..70b0d566 100644 --- a/src/api/wayland/window.rs +++ b/src/api/wayland/window.rs @@ -160,7 +160,10 @@ impl Window { } pub fn set_title(&self, title: &str) { - // TODO + let mut guard = self.evq.lock().unwrap(); + let mut state = guard.state(); + let mut decorated = state.get_mut_handler::>(self.decorated_id); + decorated.set_title(title.into()) } #[inline] @@ -185,19 +188,23 @@ impl Window { } pub fn get_inner_size(&self) -> Option<(u32, u32)> { - // TODO - None + Some(self.size.lock().unwrap().clone()) } #[inline] pub fn get_outer_size(&self) -> Option<(u32, u32)> { - // TODO - None + let (w, h) = self.size.lock().unwrap().clone(); + let (w, h) = super::wayland_window::add_borders(w as i32, h as i32); + Some((w as u32, h as u32)) } #[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) { - // TODO + let mut guard = self.evq.lock().unwrap(); + let mut state = guard.state(); + let mut decorated = state.get_mut_handler::>(self.decorated_id); + decorated.resize(x as i32, y as i32); } #[inline] From c6f8ed2f8137fc3394ceae727a935883cc2f6013 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 9 Oct 2016 16:33:29 +0200 Subject: [PATCH 06/12] wayland: handle `Focused` event --- src/api/wayland/context.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index 45a13529..615df82c 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -510,6 +510,8 @@ impl wl_keyboard::Handler for WaylandEnv { for &(ref window, ref eviter) in &self.windows { if window.equals(surface) { self.kbd_handler.handler().target = Some(eviter.clone()); + let mut guard = eviter.lock().unwrap(); + guard.push_back(Event::Focused(true)); break } } @@ -522,7 +524,10 @@ impl wl_keyboard::Handler for WaylandEnv { serial: u32, surface: &wl_surface::WlSurface) { - self.kbd_handler.handler().target = None; + if let Some(eviter) = self.kbd_handler.handler().target.take() { + let mut guard = eviter.lock().unwrap(); + guard.push_back(Event::Focused(false)); + } self.kbd_handler.leave(evqh, proxy, serial, surface) } From 2d025a4a357bfed36a6be84c8b4478c264aa4564 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 9 Oct 2016 18:26:24 +0200 Subject: [PATCH 07/12] wayland: gracefully handle missing libxkbcommon --- src/api/wayland/context.rs | 77 +++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index 615df82c..70cf6991 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -23,6 +23,11 @@ wayland_env!(InnerEnv, subcompositor: wl_subcompositor::WlSubcompositor ); +enum KbdType { + Mapped(MappedKeyboard), + Plain(Option>>>) +} + struct WaylandEnv { registry: wl_registry::WlRegistry, inner: EnvHandler, @@ -34,7 +39,7 @@ struct WaylandEnv { mouse_focus: Option>>>, mouse_location: (i32, i32), kbd: Option, - kbd_handler: MappedKeyboard + kbd_handler: KbdType } struct OutputInfo { @@ -59,6 +64,10 @@ impl OutputInfo { impl WaylandEnv { fn new(registry: wl_registry::WlRegistry) -> WaylandEnv { + let kbd_handler = match MappedKeyboard::new(KbdHandler::new()) { + Ok(h) => KbdType::Mapped(h), + Err(_) => KbdType::Plain(None) + }; WaylandEnv { registry: registry, inner: EnvHandler::new(), @@ -70,7 +79,7 @@ impl WaylandEnv { mouse_focus: None, mouse_location: (0,0), kbd: None, - kbd_handler: MappedKeyboard::new(KbdHandler::new()).ok().expect("Missing libxkbcommon!") // TODO + kbd_handler: kbd_handler } } @@ -497,7 +506,10 @@ impl wl_keyboard::Handler for WaylandEnv { fd: ::std::os::unix::io::RawFd, size: u32) { - self.kbd_handler.keymap(evqh, proxy, format, fd, size) + match self.kbd_handler { + KbdType::Mapped(ref mut h) => h.keymap(evqh, proxy, format, fd, size), + _ => () + } } fn enter(&mut self, @@ -507,15 +519,25 @@ impl wl_keyboard::Handler for WaylandEnv { surface: &wl_surface::WlSurface, keys: Vec) { + let mut opt_eviter = None; for &(ref window, ref eviter) in &self.windows { if window.equals(surface) { - self.kbd_handler.handler().target = Some(eviter.clone()); - let mut guard = eviter.lock().unwrap(); - guard.push_back(Event::Focused(true)); - break + opt_eviter = Some(eviter.clone()); + break; } } - self.kbd_handler.enter(evqh, proxy, serial, surface, keys) + if let Some(ref eviter) = opt_eviter { + // send focused event + let mut guard = eviter.lock().unwrap(); + guard.push_back(Event::Focused(true)); + } + match self.kbd_handler { + KbdType::Mapped(ref mut h) => { + h.handler().target = opt_eviter; + h.enter(evqh, proxy, serial, surface, keys); + }, + KbdType::Plain(ref mut opt) => { *opt = opt_eviter; } + } } fn leave(&mut self, @@ -524,11 +546,18 @@ impl wl_keyboard::Handler for WaylandEnv { serial: u32, surface: &wl_surface::WlSurface) { - if let Some(eviter) = self.kbd_handler.handler().target.take() { + let opt_eviter = match self.kbd_handler { + KbdType::Mapped(ref mut h) => { + let eviter = h.handler().target.take(); + h.leave(evqh, proxy, serial, surface); + eviter + }, + KbdType::Plain(ref mut opt) => opt.take() + }; + if let Some(eviter) = opt_eviter { let mut guard = eviter.lock().unwrap(); guard.push_back(Event::Focused(false)); } - self.kbd_handler.leave(evqh, proxy, serial, surface) } fn key(&mut self, @@ -539,7 +568,22 @@ impl wl_keyboard::Handler for WaylandEnv { key: u32, state: wl_keyboard::KeyState) { - self.kbd_handler.key(evqh, proxy, serial, time, key, state) + match self.kbd_handler { + KbdType::Mapped(ref mut h) => h.key(evqh, proxy, serial, time, key, state), + KbdType::Plain(Some(ref eviter)) => { + let state = match state { + wl_keyboard::KeyState::Pressed => ElementState::Pressed, + wl_keyboard::KeyState::Released => ElementState::Released, + }; + let mut guard = eviter.lock().unwrap(); + guard.push_back(Event::KeyboardInput( + state, + key as u8, + None + )); + }, + KbdType::Plain(None) => () + } } fn modifiers(&mut self, @@ -551,7 +595,11 @@ impl wl_keyboard::Handler for WaylandEnv { mods_locked: u32, group: u32) { - self.kbd_handler.modifiers(evqh, proxy, serial, mods_depressed, mods_latched, mods_locked, group) + match self.kbd_handler { + KbdType::Mapped(ref mut h) => h.modifiers(evqh, proxy, serial, mods_depressed, + mods_latched, mods_locked, group), + _ => () + } } fn repeat_info(&mut self, @@ -560,7 +608,10 @@ impl wl_keyboard::Handler for WaylandEnv { rate: i32, delay: i32) { - self.kbd_handler.repeat_info(evqh, proxy, rate, delay) + match self.kbd_handler { + KbdType::Mapped(ref mut h) => h.repeat_info(evqh, proxy, rate, delay), + _ => () + } } } From 42d73a14885539cac707ac840cdbdb131cf30cfe Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 9 Oct 2016 18:26:46 +0200 Subject: [PATCH 08/12] wayland: fix event dispatch, avoid double wait --- src/api/wayland/window.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/wayland/window.rs b/src/api/wayland/window.rs index 70b0d566..b286b404 100644 --- a/src/api/wayland/window.rs +++ b/src/api/wayland/window.rs @@ -148,13 +148,13 @@ impl Window { { self.ctxt.flush(); self.ctxt.dispatch(); - let mut guard = self.evq.lock().unwrap().dispatch(); + let mut guard = self.evq.lock().unwrap().dispatch_pending(); // some events were dispatched, need to process a potential resising self.process_resize(); } // try again let mut guard = self.eviter.lock().unwrap(); - evt = guard.pop_front() + evt = guard.pop_front(); } evt } From 44996acf9458a0a4a03283e29b5d4cd82d494787 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Mon, 10 Oct 2016 08:01:58 +0200 Subject: [PATCH 09/12] wayland: expose internals as side unsable methods --- src/os/unix.rs | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/os/unix.rs b/src/os/unix.rs index ae5928cd..e6229714 100644 --- a/src/os/unix.rs +++ b/src/os/unix.rs @@ -32,15 +32,37 @@ pub trait WindowExt { /// The pointer will become invalid when the glutin `Window` is destroyed. fn get_xcb_connection(&self) -> Option<*mut libc::c_void>; - /// Returns a reference to the `WlSurface` object of wayland that is used by this window. + /// Returns a pointer to the `wl_surface` object of wayland that is used by this window. /// /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). - fn get_wayland_surface(&self) -> Option<&WlSurface>; + /// + /// The pointer will become invalid when the glutin `Window` is destroyed. + fn get_wayland_surface(&self) -> Option<*mut libc::c_void>; + + /// Returns a pointer to the `wl_display` object of wayland that is used by this window. + /// + /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). + /// + /// The pointer will become invalid when the glutin `Window` is destroyed. + fn get_wayland_display(&self) -> Option<*mut libc::c_void>; + + /// Returns a reference to the `WlSurface` object of wayland that is used by this window. + /// + /// For use with the `wayland-client` crate. + /// + /// **This function is not part of winit's public API.** + /// + /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). + fn get_wayland_client_surface(&self) -> Option<&WlSurface>; /// Returns a pointer to the `WlDisplay` object of wayland that is used by this window. /// + /// For use with the `wayland-client` crate. + /// + /// **This function is not part of winit's public API.** + /// /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). - fn get_wayland_display(&self) -> Option<&WlDisplay>; + fn get_wayland_client_display(&self) -> Option<&WlDisplay>; } impl WindowExt for Window { @@ -68,7 +90,20 @@ impl WindowExt for Window { } #[inline] - fn get_wayland_surface(&self) -> Option<&WlSurface> { + fn get_wayland_surface(&self) -> Option<*mut libc::c_void> { + use wayland_client::Proxy; + self.get_wayland_client_surface().map(|p| p.ptr() as *mut _) + } + + + #[inline] + fn get_wayland_display(&self) -> Option<*mut libc::c_void> { + use wayland_client::Proxy; + self.get_wayland_client_display().map(|p| p.ptr() as *mut _) + } + + #[inline] + fn get_wayland_client_surface(&self) -> Option<&WlSurface> { match self.window { LinuxWindow::Wayland(ref w) => Some(w.get_surface()), _ => None @@ -76,7 +111,7 @@ impl WindowExt for Window { } #[inline] - fn get_wayland_display(&self) -> Option<&WlDisplay> { + fn get_wayland_client_display(&self) -> Option<&WlDisplay> { match self.window { LinuxWindow::Wayland(ref w) => Some(w.get_display()), _ => None From db6b4606a11ef365d550b7296babd69bfe76c55e Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 16 Oct 2016 22:33:39 +0200 Subject: [PATCH 10/12] wayland: Support for wheel scrolling --- src/api/wayland/context.rs | 50 +++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index 70cf6991..f98b1e88 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -1,4 +1,4 @@ -use {Event, ElementState, MouseButton}; +use {Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase}; use std::collections::VecDeque; use std::sync::{Arc, Mutex}; @@ -38,6 +38,9 @@ struct WaylandEnv { mouse: Option, mouse_focus: Option>>>, mouse_location: (i32, i32), + axis_buffer: Option<(f32, f32)>, + axis_discrete_buffer: Option<(i32, i32)>, + axis_state: TouchPhase, kbd: Option, kbd_handler: KbdType } @@ -78,6 +81,9 @@ impl WaylandEnv { mouse: None, mouse_focus: None, mouse_location: (0,0), + axis_buffer: None, + axis_discrete_buffer: None, + axis_state: TouchPhase::Started, kbd: None, kbd_handler: kbd_handler } @@ -450,8 +456,6 @@ impl wl_pointer::Handler for WaylandEnv { } } - // TODO: proper scroll handling - fn axis(&mut self, _evqh: &mut EventQueueHandle, _proxy: &wl_pointer::WlPointer, @@ -459,12 +463,41 @@ impl wl_pointer::Handler for WaylandEnv { axis: wl_pointer::Axis, value: f64) { + let (mut x, mut y) = self.axis_buffer.unwrap_or((0.0, 0.0)); + match axis { + wl_pointer::Axis::VerticalScroll => y += value as f32, + wl_pointer::Axis::HorizontalScroll => x += value as f32 + } + self.axis_buffer = Some((x,y)); + self.axis_state = match self.axis_state { + TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, + _ => TouchPhase::Started + } } fn frame(&mut self, _evqh: &mut EventQueueHandle, _proxy: &wl_pointer::WlPointer) { + let axis_buffer = self.axis_buffer.take(); + let axis_discrete_buffer = self.axis_discrete_buffer.take(); + if let Some(ref eviter) = self.mouse_focus { + if let Some((x, y)) = axis_discrete_buffer { + eviter.lock().unwrap().push_back( + Event::MouseWheel( + MouseScrollDelta::LineDelta(x as f32, y as f32), + self.axis_state + ) + ); + } else if let Some((x, y)) = axis_buffer { + eviter.lock().unwrap().push_back( + Event::MouseWheel( + MouseScrollDelta::PixelDelta(x as f32, y as f32), + self.axis_state + ) + ); + } + } } fn axis_source(&mut self, @@ -480,6 +513,7 @@ impl wl_pointer::Handler for WaylandEnv { _time: u32, axis: wl_pointer::Axis) { + self.axis_state = TouchPhase::Ended; } fn axis_discrete(&mut self, @@ -488,6 +522,16 @@ impl wl_pointer::Handler for WaylandEnv { axis: wl_pointer::Axis, discrete: i32) { + let (mut x, mut y) = self.axis_discrete_buffer.unwrap_or((0,0)); + match axis { + wl_pointer::Axis::VerticalScroll => y += discrete, + wl_pointer::Axis::HorizontalScroll => x += discrete + } + self.axis_discrete_buffer = Some((x,y)); + self.axis_state = match self.axis_state { + TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, + _ => TouchPhase::Started + } } } From 0663269482968624829ea58d4833a31a670728ee Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 16 Oct 2016 22:53:53 +0200 Subject: [PATCH 11/12] wayland: Implement wakeup_event_loop() --- src/api/wayland/window.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/api/wayland/window.rs b/src/api/wayland/window.rs index b286b404..aa71bc3b 100644 --- a/src/api/wayland/window.rs +++ b/src/api/wayland/window.rs @@ -12,12 +12,17 @@ use super::wayland_window; use super::wayland_window::DecoratedSurface; #[derive(Clone)] -pub struct WindowProxy; +pub struct WindowProxy { + ctxt: Arc, + eviter: Arc>>, +} impl WindowProxy { #[inline] pub fn wakeup_event_loop(&self) { - unimplemented!() + // Send a sync event, so that any waiting "dispatch" will return + self.ctxt.display.sync(); + self.eviter.lock().unwrap().push_back(Event::Awakened); } } @@ -209,7 +214,10 @@ impl Window { #[inline] pub fn create_window_proxy(&self) -> WindowProxy { - WindowProxy + WindowProxy { + ctxt: self.ctxt.clone(), + eviter: self.eviter.clone() + } } #[inline] From 76f56134961cafe0e015890b37dba79efd162b61 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 16 Oct 2016 23:29:29 +0200 Subject: [PATCH 12/12] wayland: properly fetch new events with Window::poll_events() --- Cargo.toml | 2 +- src/api/wayland/window.rs | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 40fae0fb..4252a1b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ kernel32-sys = "0.2" dwmapi-sys = "0.1" [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies] -wayland-client = { version = "0.7.3", features = ["dlopen"] } +wayland-client = { version = "0.7.4", features = ["dlopen"] } wayland-kbd = "0.6.2" wayland-window = "0.4.2" x11-dl = "2.8" diff --git a/src/api/wayland/window.rs b/src/api/wayland/window.rs index aa71bc3b..f08e17cd 100644 --- a/src/api/wayland/window.rs +++ b/src/api/wayland/window.rs @@ -134,11 +134,20 @@ impl Window { }; if evt.is_some() { return evt } + // There is no event in the queue, we need to fetch more + + // flush the display + self.ctxt.flush(); + + // read some events if some are waiting & queue is empty + if let Some(guard) = self.evq.lock().unwrap().prepare_read() { + guard.read_events(); + } + // try a pending dispatch - // TODO: insert a non-blocking read from socket, overwise no new events will ever come { self.ctxt.dispatch_pending(); - let mut guard = self.evq.lock().unwrap().dispatch_pending(); + self.evq.lock().unwrap().dispatch_pending(); // some events were dispatched, need to process a potential resising self.process_resize(); } @@ -153,7 +162,7 @@ impl Window { { self.ctxt.flush(); self.ctxt.dispatch(); - let mut guard = self.evq.lock().unwrap().dispatch_pending(); + self.evq.lock().unwrap().dispatch_pending(); // some events were dispatched, need to process a potential resising self.process_resize(); }