Merge pull request #21 from vberger/master

Wayland backend rewrite
This commit is contained in:
tomaka 2016-10-17 12:40:00 +02:00 committed by GitHub
commit 1f170264ed
10 changed files with 933 additions and 636 deletions

View file

@ -39,7 +39,7 @@ kernel32-sys = "0.2"
dwmapi-sys = "0.1" dwmapi-sys = "0.1"
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies] [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-client = { version = "0.7.4", features = ["dlopen"] }
wayland-kbd = "0.3.3" wayland-kbd = "0.6.2"
wayland-window = "0.2.2" wayland-window = "0.4.2"
x11-dl = "2.8" x11-dl = "2.8"

View file

@ -1,211 +1,662 @@
use Event as GlutinEvent; use {Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase};
use std::collections::{HashMap, VecDeque, HashSet}; use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use libc::c_void; use wayland_client::{EnvHandler, default_connect, EventQueue, EventQueueHandle, Init, Proxy};
use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor,
use wayland_client::{EventIterator, Proxy, ProxyId}; wl_display, wl_registry, wl_output, wl_surface, wl_pointer,
use wayland_client::wayland::get_display; wl_keyboard};
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_window;
use super::wayland_kbd::MappedKeyboard; use super::wayland_kbd::MappedKeyboard;
use super::wayland_window::DecoratedSurface; use super::keyboard::KbdHandler;
lazy_static! { /*
pub static ref WAYLAND_CONTEXT: Option<WaylandContext> = { * Registry and globals handling
WaylandContext::init() */
};
}
wayland_env!(InnerEnv, wayland_env!(InnerEnv,
compositor: WlCompositor, compositor: wl_compositor::WlCompositor,
seat: WlSeat, shell: wl_shell::WlShell,
shell: WlShell, shm: wl_shm::WlShm,
shm: WlShm, subcompositor: wl_subcompositor::WlSubcompositor
subcompositor: WlSubcompositor
); );
pub struct WaylandFocuses { enum KbdType {
pub pointer: Option<WlPointer>, Mapped(MappedKeyboard<KbdHandler>),
pub pointer_on: Option<ProxyId>, Plain(Option<Arc<Mutex<VecDeque<Event>>>>)
pub pointer_at: Option<(f64, f64)>,
pub keyboard: Option<MappedKeyboard>,
pub keyboard_on: Option<ProxyId>
} }
struct WaylandEnv {
registry: wl_registry::WlRegistry,
inner: EnvHandler<InnerEnv>,
monitors: Vec<OutputInfo>,
my_id: usize,
windows: Vec<(Arc<wl_surface::WlSurface>,Arc<Mutex<VecDeque<Event>>>)>,
seat: Option<wl_seat::WlSeat>,
mouse: Option<wl_pointer::WlPointer>,
mouse_focus: Option<Arc<Mutex<VecDeque<Event>>>>,
mouse_location: (i32, i32),
axis_buffer: Option<(f32, f32)>,
axis_discrete_buffer: Option<(i32, i32)>,
axis_state: TouchPhase,
kbd: Option<wl_keyboard::WlKeyboard>,
kbd_handler: KbdType
}
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 {
let kbd_handler = match MappedKeyboard::new(KbdHandler::new()) {
Ok(h) => KbdType::Mapped(h),
Err(_) => KbdType::Plain(None)
};
WaylandEnv {
registry: registry,
inner: EnvHandler::new(),
monitors: Vec::new(),
my_id: 0,
windows: Vec::new(),
seat: None,
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
}
}
fn get_seat(&self) -> Option<wl_seat::WlSeat> {
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::<wl_seat::WlSeat>(5, name).expect("Seat cannot be destroyed");
return Some(seat)
}
}
None
}
}
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::<wl_output::WlOutput>(1, name)
.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::<wl_seat::WlSeat>(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);
}
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 struct WaylandContext {
inner: InnerEnv, pub display: wl_display::WlDisplay,
iterator: Mutex<EventIterator>, evq: Mutex<EventQueue>,
monitors: Vec<(WlOutput, u32, u32, String)>, env_id: usize,
queues: Mutex<HashMap<ProxyId, Arc<Mutex<VecDeque<GlutinEvent>>>>>,
known_surfaces: Mutex<HashSet<ProxyId>>,
focuses: Mutex<WaylandFocuses>
} }
impl WaylandContext { impl WaylandContext {
fn init() -> Option<WaylandContext> { pub fn init() -> Option<WaylandContext> {
let display = match get_display() { // attempt to connect to the wayland server
Some(display) => display, // this handles both "no libwayland" and "no compositor" cases
None => return None let (display, mut event_queue) = match default_connect() {
Ok(ret) => ret,
Err(e) => return None
}; };
let (mut inner_env, iterator) = InnerEnv::init(display); // 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 outputs_events = EventIterator::new(); let env_id = event_queue.add_handler_with_init(WaylandEnv::new(registry));
// two syncs fully initialize
let mut monitors = inner_env.globals.iter() event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
.flat_map(|&(id, _, _)| inner_env.rebind_id::<WlOutput>(id)) event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
.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 { Some(WaylandContext {
inner: inner_env, evq: Mutex::new(event_queue),
iterator: Mutex::new(iterator), display: display,
monitors: monitors, env_id: env_id
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<Mutex<VecDeque<GlutinEvent>>>)> { pub fn dispatch_pending(&self) {
self.inner.compositor.as_ref().map(|c| { let mut guard = self.evq.lock().unwrap();
let s = c.0.create_surface(); guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
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) { pub fn dispatch(&self) {
self.queues.lock().unwrap().remove(&id); let mut guard = self.evq.lock().unwrap();
self.known_surfaces.lock().unwrap().remove(&id); guard.dispatch().expect("Wayland connection unexpectedly lost");
} }
pub fn decorated_from(&self, surface: &WlSurface, width: i32, height: i32) -> Option<DecoratedSurface> { pub fn flush(&self) {
let inner = &self.inner; self.display.flush();
match (&inner.compositor, &inner.subcompositor, &inner.shm, &inner.shell) { }
(&Some(ref compositor), &Some(ref subcompositor), &Some(ref shm), &Some(ref shell)) => {
DecoratedSurface::new( pub fn with_output<F>(&self, id: MonitorId, f: F) where F: FnOnce(&wl_output::WlOutput) {
surface, width, height, let mut guard = self.evq.lock().unwrap();
&compositor.0, &subcompositor.0, &shm.0, &shell.0, let state = guard.state();
self.inner.rebind::<WlSeat>().map(|(seat, _)| seat) let env = state.get_handler::<WaylandEnv>(self.env_id);
).ok() for m in env.monitors.iter().filter(|m| m.id == id.id) {
} f(&m.output);
_ => None break
} }
} }
pub fn plain_from(&self, surface: &WlSurface, fullscreen: Option<ProxyId>) -> Option<WlShellSurface> { pub fn create_window<H: wayland_window::Handler>(&self)
use wayland_client::wayland::shell::WlShellSurfaceFullscreenMethod; -> (Arc<wl_surface::WlSurface>, Arc<Mutex<VecDeque<Event>>>, wayland_window::DecoratedSurface<H>)
{
let inner = &self.inner; let mut guard = self.evq.lock().unwrap();
if let Some((ref shell, _)) = inner.shell { let mut state = guard.state();
let shell_surface = shell.get_shell_surface(surface); let env = state.get_mut_handler::<WaylandEnv>(self.env_id);
if let Some(monitor_id) = fullscreen { // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69)
for m in &self.monitors { let surface = Arc::new(env.inner.compositor.create_surface().expect("Compositor cannot be dead"));
if m.0.id() == monitor_id { let eventiter = Arc::new(Mutex::new(VecDeque::new()));
shell_surface.set_fullscreen( env.windows.push((surface.clone(), eventiter.clone()));
WlShellSurfaceFullscreenMethod::Default, let decorated = wayland_window::DecoratedSurface::new(
0, &*surface, 800, 600,
Some(&m.0) &env.inner.compositor,
); &env.inner.subcompositor,
return Some(shell_surface) &env.inner.shm,
} &env.inner.shell,
} env.get_seat(),
} false
shell_surface.set_toplevel(); ).expect("Failed to create a tmpfile buffer.");
Some(shell_surface) (surface, eventiter, decorated)
} else {
None
}
} }
pub fn display_ptr(&self) -> *const c_void { pub fn prune_dead_windows(&self) {
self.inner.display.ptr() as *const _ let mut guard = self.evq.lock().unwrap();
} let mut state = guard.state();
let env = state.get_mut_handler::<WaylandEnv>(self.env_id);
pub fn dispatch_events(&self) { env.windows.retain(|w| w.0.is_alive());
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<i32> {
self.inner.display.flush()
}
pub fn read_events(&self) -> ::std::io::Result<Option<i32>> {
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<ProxyId> {
self.monitors.iter().map(|o| o.0.id()).collect()
}
pub fn monitor_name(&self, pid: ProxyId) -> Option<String> {
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
} }
} }
/*
* Monitors API
*/
pub fn get_primary_monitor(ctxt: &Arc<WaylandContext>) -> MonitorId {
let mut guard = ctxt.evq.lock().unwrap();
let state = guard.state();
let env = state.get_handler::<WaylandEnv>(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<WaylandContext>) -> VecDeque<MonitorId> {
let mut guard = ctxt.evq.lock().unwrap();
let state = guard.state();
let env = state.get_handler::<WaylandEnv>(ctxt.env_id);
env.monitors.iter()
.map(|m| MonitorId { id: m.id, ctxt: ctxt.clone() })
.collect()
}
#[derive(Clone)]
pub struct MonitorId {
id: u32,
ctxt: Arc<WaylandContext>
}
impl MonitorId {
pub fn get_name(&self) -> Option<String> {
let mut guard = self.ctxt.evq.lock().unwrap();
let state = guard.state();
let env = state.get_handler::<WaylandEnv>(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]
pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
::native_monitor::NativeMonitorId::Unavailable
}
pub fn get_dimensions(&self) -> (u32, u32) {
let mut guard = self.ctxt.evq.lock().unwrap();
let state = guard.state();
let env = state.get_handler::<WaylandEnv>(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)
}
}
/*
* 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)
);
}
}
fn axis(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
_time: u32,
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,
_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)
{
self.axis_state = TouchPhase::Ended;
}
fn axis_discrete(&mut self,
_evqh: &mut EventQueueHandle,
_proxy: &wl_pointer::WlPointer,
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
}
}
}
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)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.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<u8>)
{
let mut opt_eviter = None;
for &(ref window, ref eviter) in &self.windows {
if window.equals(surface) {
opt_eviter = Some(eviter.clone());
break;
}
}
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,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
surface: &wl_surface::WlSurface)
{
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));
}
}
fn key(&mut self,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
time: u32,
key: u32,
state: wl_keyboard::KeyState)
{
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,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
serial: u32,
mods_depressed: u32,
mods_latched: u32,
mods_locked: u32,
group: u32)
{
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,
evqh: &mut EventQueueHandle,
proxy: &wl_keyboard::WlKeyboard,
rate: i32,
delay: i32)
{
match self.kbd_handler {
KbdType::Mapped(ref mut h) => h.repeat_info(evqh, proxy, rate, delay),
_ => ()
}
}
}
declare_handler!(WaylandEnv, wl_keyboard::Handler, wl_keyboard::WlKeyboard);

View file

@ -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<ProxyId>,
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
}
}

View file

@ -1,83 +1,70 @@
use std::collections::HashSet; use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use Event as GlutinEvent; use {VirtualKeyCode, ElementState, Event};
use ElementState;
use VirtualKeyCode;
use wayland_client::ProxyId; use super::wayland_kbd;
use wayland_client::wayland::seat::{WlKeyboardEvent,WlKeyboardKeyState}; use wayland_client::EventQueueHandle;
use wayland_client::protocol::wl_keyboard;
use super::wayland_kbd::MappedKeyboardEvent; pub struct KbdHandler {
pub target: Option<Arc<Mutex<VecDeque<Event>>>>
}
use super::context::WaylandFocuses; impl KbdHandler {
pub fn new() -> KbdHandler {
KbdHandler { target: None }
}
}
pub fn translate_kbd_events( impl wayland_kbd::Handler for KbdHandler {
focuses: &mut WaylandFocuses, fn key(&mut self,
known_surfaces: &HashSet<ProxyId>, _evqh: &mut EventQueueHandle,
) -> Vec<(GlutinEvent, ProxyId)> { _proxy: &wl_keyboard::WlKeyboard,
let mut out = Vec::new(); _serial: u32,
if let Some(mkbd) = focuses.keyboard.as_mut() { _time: u32,
for evt in mkbd { rawkey: u32,
match evt { keysym: u32,
MappedKeyboardEvent::KeyEvent(kevt) => { state: wl_keyboard::KeyState,
if let Some(surface) = focuses.keyboard_on { utf8: Option<String>)
let vkcode = match kevt.keycode { {
1 => Some(VirtualKeyCode::Escape), if let Some(ref eviter) = self.target {
2 => Some(VirtualKeyCode::Key1), let state = match state {
3 => Some(VirtualKeyCode::Key2), wl_keyboard::KeyState::Pressed => ElementState::Pressed,
4 => Some(VirtualKeyCode::Key3), wl_keyboard::KeyState::Released => ElementState::Released,
5 => Some(VirtualKeyCode::Key4), };
6 => Some(VirtualKeyCode::Key5), let vkcode = key_to_vkey(rawkey, keysym);
7 => Some(VirtualKeyCode::Key6), let mut guard = eviter.lock().unwrap();
8 => Some(VirtualKeyCode::Key7), guard.push_back(Event::KeyboardInput(state, rawkey as u8, vkcode));
9 => Some(VirtualKeyCode::Key8), // send char event only on key press, not release
10 => Some(VirtualKeyCode::Key9), if let ElementState::Released = state { return }
11 => Some(VirtualKeyCode::Key0), if let Some(txt) = utf8 {
_ => kevt.as_symbol().and_then(keysym_to_vkey) for chr in txt.chars() {
}; guard.push_back(Event::ReceivedCharacter(chr));
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<VirtualKeyCode> { fn key_to_vkey(rawkey: u32, keysym: u32) -> Option<VirtualKeyCode> {
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<VirtualKeyCode> {
use super::wayland_kbd::keysyms; use super::wayland_kbd::keysyms;
match keysym { match keysym {
// letters // letters

View file

@ -1,18 +1,12 @@
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] #![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::window::{PollEventsIterator, WaitEventsIterator, Window, WindowProxy};
pub use self::context::{WaylandContext, MonitorId, get_available_monitors,
get_primary_monitor};
extern crate wayland_kbd; extern crate wayland_kbd;
extern crate wayland_window; extern crate wayland_window;
mod context; mod context;
mod events;
mod keyboard; mod keyboard;
mod monitor;
mod window; mod window;
#[inline]
pub fn is_available() -> bool {
context::WAYLAND_CONTEXT.is_some()
}

View file

@ -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<MonitorId> {
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<String> {
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
}
}
}
},
_ => {}
},
_ => {}
}
}
}

View file

@ -1,83 +1,39 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use libc; use wayland_client::{EventQueue, EventQueueHandle, Init};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};
use {CreationError, CursorState, Event, MouseCursor, WindowAttributes}; use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
use platform::MonitorId as PlatformMonitorId; use platform::MonitorId as PlatformMonitorId;
use wayland_client::EventIterator; use super::WaylandContext;
use wayland_client::wayland::compositor::WlSurface; use super::wayland_window;
use wayland_client::wayland::shell::WlShellSurface; use super::wayland_window::DecoratedSurface;
use super::wayland_window::{DecoratedSurface, add_borders, substract_borders};
use super::context::{WaylandContext, WAYLAND_CONTEXT};
#[derive(Clone)] #[derive(Clone)]
pub struct WindowProxy; pub struct WindowProxy {
ctxt: Arc<WaylandContext>,
eviter: Arc<Mutex<VecDeque<Event>>>,
}
impl WindowProxy { impl WindowProxy {
#[inline] #[inline]
pub fn wakeup_event_loop(&self) { 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);
} }
} }
pub struct Window { pub struct Window {
wayland_context: &'static WaylandContext, ctxt: Arc<WaylandContext>,
surface: WlSurface, evq: Mutex<EventQueue>,
shell_window: Mutex<ShellWindow>, eviter: Arc<Mutex<VecDeque<Event>>>,
evt_queue: Arc<Mutex<VecDeque<Event>>>, surface: Arc<wl_surface::WlSurface>,
inner_size: Mutex<(i32, i32)>, size: Mutex<(u32, u32)>,
resize_callback: Option<fn(u32, u32)>, handler_id: usize,
} decorated_id: usize
impl Window {
fn next_event(&self) -> Option<Event> {
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()
}
}
} }
pub struct PollEventsIterator<'a> { pub struct PollEventsIterator<'a> {
@ -88,13 +44,7 @@ impl<'a> Iterator for PollEventsIterator<'a> {
type Item = Event; type Item = Event;
fn next(&mut self) -> Option<Event> { fn next(&mut self) -> Option<Event> {
match self.window.next_event() { self.window.next_event(false)
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();
} }
} }
@ -106,93 +56,130 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
type Item = Event; type Item = Event;
fn next(&mut self) -> Option<Event> { fn next(&mut self) -> Option<Event> {
loop { self.window.next_event(true)
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.")
}
}
} }
} }
enum ShellWindow {
Plain(WlShellSurface, EventIterator),
Decorated(DecoratedSurface)
}
impl Window { impl Window {
pub fn new(window: &WindowAttributes) -> Result<Window, CreationError> pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes) -> Result<Window, CreationError>
{ {
use wayland_client::Proxy; let (width, height) = attributes.dimensions.unwrap_or((800,600));
// not implemented
assert!(window.min_dimensions.is_none());
assert!(window.max_dimensions.is_none());
let wayland_context = match *WAYLAND_CONTEXT { let mut evq = ctxt.display.create_event_queue();
Some(ref c) => c,
None => return Err(CreationError::NotSupported),
};
let (w, h) = window.dimensions.unwrap_or((800, 600)); let (surface, eviter, decorated) = ctxt.create_window::<DecoratedHandler>();
let (surface, evt_queue) = match wayland_context.new_surface() { // init DecoratedSurface
Some(t) => t, let decorated_id = evq.add_handler_with_init(decorated);
None => return Err(CreationError::NotSupported) {
}; let mut state = evq.state();
let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
*(decorated.handler()) = Some(DecoratedHandler::new());
let shell_window = if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = window.monitor { if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor {
let pid = super::monitor::proxid_from_monitorid(monitor_id); ctxt.with_output(monitor_id.clone(), |output| {
match wayland_context.plain_from(&surface, Some(pid)) { decorated.set_fullscreen(
Some(mut s) => { wl_shell_surface::FullscreenMethod::Default,
let iter = EventIterator::new(); 0,
s.set_evt_iterator(&iter); Some(output)
ShellWindow::Plain(s, iter) )
}, });
None => return Err(CreationError::NotSupported) } else if attributes.decorations {
decorated.set_decorate(true);
} }
} else if window.decorations { }
match wayland_context.decorated_from(&surface, w as i32, h as i32) {
Some(s) => ShellWindow::Decorated(s), // init general handler
None => return Err(CreationError::NotSupported) let handler = WindowHandler::new();
} let handler_id = evq.add_handler_with_init(handler);
} 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 { Ok(Window {
wayland_context: wayland_context, ctxt: ctxt,
evq: Mutex::new(evq),
eviter: eviter,
surface: surface, surface: surface,
shell_window: Mutex::new(shell_window), size: Mutex::new((width, height)),
evt_queue: evt_queue, handler_id: handler_id,
inner_size: Mutex::new((w as i32, h as i32)), decorated_id: decorated_id
resize_callback: None,
}) })
} }
pub fn set_title(&self, title: &str) { fn process_resize(&self) {
let guard = self.shell_window.lock().unwrap(); use std::cmp::max;
match *guard { let mut evq_guard = self.evq.lock().unwrap();
ShellWindow::Plain(ref plain, _) => { plain.set_title(title.into()); }, let mut state = evq_guard.state();
ShellWindow::Decorated(ref deco) => { deco.set_title(title.into()); } let newsize = {
let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(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::<WindowHandler>(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<Event> {
let mut evt = {
let mut guard = self.eviter.lock().unwrap();
guard.pop_front()
};
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
{
self.ctxt.dispatch_pending();
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();
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
}
pub fn set_title(&self, title: &str) {
let mut guard = self.evq.lock().unwrap();
let mut state = guard.state();
let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
decorated.set_title(title.into())
}
#[inline] #[inline]
pub fn show(&self) { pub fn show(&self) {
// TODO // TODO
@ -215,29 +202,31 @@ impl Window {
} }
pub fn get_inner_size(&self) -> Option<(u32, u32)> { pub fn get_inner_size(&self) -> Option<(u32, u32)> {
let (w, h) = *self.inner_size.lock().unwrap(); Some(self.size.lock().unwrap().clone())
Some((w as u32, h as u32))
} }
#[inline] #[inline]
pub fn get_outer_size(&self) -> Option<(u32, u32)> { pub fn get_outer_size(&self) -> Option<(u32, u32)> {
let (w, h) = *self.inner_size.lock().unwrap(); let (w, h) = self.size.lock().unwrap().clone();
let (w, h) = add_borders(w, h); let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
Some((w as u32, h as u32)) Some((w as u32, h as u32))
} }
#[inline] #[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) { pub fn set_inner_size(&self, x: u32, y: u32) {
let mut guard = self.shell_window.lock().unwrap(); let mut guard = self.evq.lock().unwrap();
match *guard { let mut state = guard.state();
ShellWindow::Decorated(ref mut deco) => { deco.resize(x as i32, y as i32); }, let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
_ => {} decorated.resize(x as i32, y as i32);
}
} }
#[inline] #[inline]
pub fn create_window_proxy(&self) -> WindowProxy { pub fn create_window_proxy(&self) -> WindowProxy {
WindowProxy WindowProxy {
ctxt: self.ctxt.clone(),
eviter: self.eviter.clone()
}
} }
#[inline] #[inline]
@ -256,7 +245,10 @@ impl Window {
#[inline] #[inline]
pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) { pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
self.resize_callback = callback; let mut guard = self.evq.lock().unwrap();
let mut state = guard.state();
let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
handler.resize_callback = callback;
} }
#[inline] #[inline]
@ -277,6 +269,7 @@ impl Window {
#[inline] #[inline]
pub fn hidpi_factor(&self) -> f32 { pub fn hidpi_factor(&self) -> f32 {
// TODO
1.0 1.0
} }
@ -286,34 +279,60 @@ impl Window {
Err(()) Err(())
} }
#[inline] pub fn get_display(&self) -> &wl_display::WlDisplay {
pub fn get_wayland_display(&self) -> *mut libc::c_void { &self.ctxt.display
WAYLAND_CONTEXT.as_ref().unwrap() // context exists if window was created
.display_ptr() as *mut libc::c_void
} }
#[inline] pub fn get_surface(&self) -> &wl_surface::WlSurface {
pub fn get_wayland_surface(&self) -> *mut libc::c_void { &self.surface
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
} }
} }
impl Drop for Window { impl Drop for Window {
fn drop(&mut self) { fn drop(&mut self) {
use wayland_client::Proxy; self.surface.destroy();
self.wayland_context.dropped_surface(self.surface.id()); 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<fn(u32,u32)>,
}
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;
} }
} }

View file

@ -57,7 +57,7 @@ extern crate core_graphics;
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
extern crate x11_dl; extern crate x11_dl;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] #[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; extern crate wayland_client;
pub use events::*; pub use events::*;

View file

@ -5,6 +5,9 @@ use Window;
use platform::Window as LinuxWindow; use platform::Window as LinuxWindow;
use WindowBuilder; 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. /// Additional methods on `Window` that are specific to Unix.
pub trait WindowExt { pub trait WindowExt {
/// Returns a pointer to the `Window` object of xlib that is used by this window. /// Returns a pointer to the `Window` object of xlib that is used by this window.
@ -42,6 +45,24 @@ pub trait WindowExt {
/// ///
/// The pointer will become invalid when the glutin `Window` is destroyed. /// 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<*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_client_display(&self) -> Option<&WlDisplay>;
} }
impl WindowExt for Window { impl WindowExt for Window {
@ -70,16 +91,29 @@ impl WindowExt for Window {
#[inline] #[inline]
fn get_wayland_surface(&self) -> Option<*mut libc::c_void> { 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 { match self.window {
LinuxWindow::Wayland(ref w) => Some(w.get_wayland_surface()), LinuxWindow::Wayland(ref w) => Some(w.get_surface()),
_ => None _ => None
} }
} }
#[inline] #[inline]
fn get_wayland_display(&self) -> Option<*mut libc::c_void> { fn get_wayland_client_display(&self) -> Option<&WlDisplay> {
match self.window { match self.window {
LinuxWindow::Wayland(ref w) => Some(w.get_wayland_display()), LinuxWindow::Wayland(ref w) => Some(w.get_display()),
_ => None _ => None
} }
} }

View file

@ -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::collections::VecDeque;
use std::sync::Arc; use std::sync::Arc;
@ -22,15 +19,15 @@ pub struct PlatformSpecificWindowBuilderAttributes;
enum Backend { enum Backend {
X(Arc<XConnection>), X(Arc<XConnection>),
Wayland, Wayland(Arc<wayland::WaylandContext>),
Error(XNotSupported), Error(XNotSupported),
} }
lazy_static!( lazy_static!(
static ref BACKEND: Backend = { static ref BACKEND: Backend = {
// Wayland backend is not production-ready yet so we disable it // Wayland backend is not production-ready yet so we disable it
if wayland::is_available() { if let Some(ctxt) = wayland::WaylandContext::init() {
Backend::Wayland Backend::Wayland(Arc::new(ctxt))
} else { } else {
match XConnection::new(Some(x_error_callback)) { match XConnection::new(Some(x_error_callback)) {
Ok(x) => Backend::X(Arc::new(x)), Ok(x) => Backend::X(Arc::new(x)),
@ -78,7 +75,7 @@ pub enum MonitorId {
#[inline] #[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> { pub fn get_available_monitors() -> VecDeque<MonitorId> {
match *BACKEND { match *BACKEND {
Backend::Wayland => wayland::get_available_monitors() Backend::Wayland(ref ctxt) => wayland::get_available_monitors(ctxt)
.into_iter() .into_iter()
.map(MonitorId::Wayland) .map(MonitorId::Wayland)
.collect(), .collect(),
@ -93,7 +90,7 @@ pub fn get_available_monitors() -> VecDeque<MonitorId> {
#[inline] #[inline]
pub fn get_primary_monitor() -> MonitorId { pub fn get_primary_monitor() -> MonitorId {
match *BACKEND { match *BACKEND {
Backend::Wayland => MonitorId::Wayland(wayland::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::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
Backend::Error(_) => MonitorId::None, Backend::Error(_) => MonitorId::None,
} }
@ -173,8 +170,8 @@ impl Window {
-> Result<Window, CreationError> -> Result<Window, CreationError>
{ {
match *BACKEND { match *BACKEND {
Backend::Wayland => { Backend::Wayland(ref ctxt) => {
wayland::Window::new(window).map(Window::Wayland) wayland::Window::new(ctxt.clone(), window).map(Window::Wayland)
}, },
Backend::X(ref connec) => { Backend::X(ref connec) => {
@ -318,17 +315,19 @@ impl Window {
#[inline] #[inline]
pub fn platform_display(&self) -> *mut libc::c_void { pub fn platform_display(&self) -> *mut libc::c_void {
use wayland_client::Proxy;
match self { match self {
&Window::X(ref w) => w.platform_display(), &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] #[inline]
pub fn platform_window(&self) -> *mut libc::c_void { pub fn platform_window(&self) -> *mut libc::c_void {
use wayland_client::Proxy;
match self { match self {
&Window::X(ref w) => w.platform_window(), &Window::X(ref w) => w.platform_window(),
&Window::Wayland(ref w) => w.platform_window() &Window::Wayland(ref w) => w.get_surface().ptr() as *mut _
} }
} }
} }