mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-25 06:41:31 +11:00
commit
1f170264ed
|
@ -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"
|
||||||
|
|
|
@ -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(
|
|
||||||
surface, width, height,
|
|
||||||
&compositor.0, &subcompositor.0, &shm.0, &shell.0,
|
|
||||||
self.inner.rebind::<WlSeat>().map(|(seat, _)| seat)
|
|
||||||
).ok()
|
|
||||||
}
|
}
|
||||||
_ => None
|
|
||||||
|
pub fn with_output<F>(&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::<WaylandEnv>(self.env_id);
|
||||||
|
for m in env.monitors.iter().filter(|m| m.id == id.id) {
|
||||||
|
f(&m.output);
|
||||||
|
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;
|
|
||||||
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) {
|
let mut guard = self.evq.lock().unwrap();
|
||||||
q.lock().unwrap().push_back(evt);
|
let mut state = guard.state();
|
||||||
}
|
let env = state.get_mut_handler::<WaylandEnv>(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 flush_events(&self) -> ::std::io::Result<i32> {
|
pub fn prune_dead_windows(&self) {
|
||||||
self.inner.display.flush()
|
let mut guard = self.evq.lock().unwrap();
|
||||||
}
|
let mut state = guard.state();
|
||||||
|
let env = state.get_mut_handler::<WaylandEnv>(self.env_id);
|
||||||
pub fn read_events(&self) -> ::std::io::Result<Option<i32>> {
|
env.windows.retain(|w| w.0.is_alive());
|
||||||
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);
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,54 @@
|
||||||
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 {
|
{
|
||||||
|
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<VirtualKeyCode> {
|
||||||
|
match rawkey {
|
||||||
1 => Some(VirtualKeyCode::Escape),
|
1 => Some(VirtualKeyCode::Escape),
|
||||||
2 => Some(VirtualKeyCode::Key1),
|
2 => Some(VirtualKeyCode::Key1),
|
||||||
3 => Some(VirtualKeyCode::Key2),
|
3 => Some(VirtualKeyCode::Key2),
|
||||||
|
@ -33,51 +60,11 @@ pub fn translate_kbd_events(
|
||||||
9 => Some(VirtualKeyCode::Key8),
|
9 => Some(VirtualKeyCode::Key8),
|
||||||
10 => Some(VirtualKeyCode::Key9),
|
10 => Some(VirtualKeyCode::Key9),
|
||||||
11 => Some(VirtualKeyCode::Key0),
|
11 => Some(VirtualKeyCode::Key0),
|
||||||
_ => kevt.as_symbol().and_then(keysym_to_vkey)
|
_ => keysym_to_vkey(keysym)
|
||||||
};
|
|
||||||
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 keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> {
|
||||||
use super::wayland_kbd::keysyms;
|
use super::wayland_kbd::keysyms;
|
||||||
match keysym {
|
match keysym {
|
||||||
// letters
|
// letters
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,91 +56,128 @@ 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),
|
|
||||||
None => return Err(CreationError::NotSupported)
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
match wayland_context.plain_from(&surface, None) {
|
// init general handler
|
||||||
Some(mut s) => {
|
let handler = WindowHandler::new();
|
||||||
let iter = EventIterator::new();
|
let handler_id = evq.add_handler_with_init(handler);
|
||||||
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]
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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::*;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue