mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
Rewrite of wayland backend to new wayland-client API (#325)
* wayland: clean state for rewrite to new wayland-client API * wayland: context init * wayland: Monitors logic * wayland: Basic event loop logic * wayland: Keyboard handling * wayland: pointer handling * wayland: refactor to remove WaylandContext * wayland: window logic * wayland: event dispatching logic * wayland: update changelog
This commit is contained in:
parent
4e4db1749d
commit
d10312c6b1
|
@ -7,6 +7,8 @@
|
||||||
- **Breaking:** `EventsLoop` is `!Send` and `!Sync` because of platform-dependant constraints,
|
- **Breaking:** `EventsLoop` is `!Send` and `!Sync` because of platform-dependant constraints,
|
||||||
but `Window`, `WindowId`, `DeviceId` and `MonitorId` guaranteed to be `Send`.
|
but `Window`, `WindowId`, `DeviceId` and `MonitorId` guaranteed to be `Send`.
|
||||||
- `MonitorId::get_position` now returns `(i32, i32)` instead of `(u32, u32)`.
|
- `MonitorId::get_position` now returns `(i32, i32)` instead of `(u32, u32)`.
|
||||||
|
- Rewrite of the wayland backend to use wayland-client-0.11
|
||||||
|
- Support for dead keys on wayland for keyboard utf8 input
|
||||||
|
|
||||||
# Version 0.8.3 (2017-10-11)
|
# Version 0.8.3 (2017-10-11)
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,9 @@ 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.9.9", features = ["dlopen"] }
|
wayland-client = { version = "0.11.2", features = ["dlopen"] }
|
||||||
wayland-protocols = { version = "0.9.9", features = ["unstable_protocols"] }
|
wayland-protocols = { version = "0.11.2", features = ["unstable_protocols"] }
|
||||||
wayland-kbd = "0.9.1"
|
wayland-kbd = "0.12.0"
|
||||||
wayland-window = "0.8.0"
|
wayland-window = "0.11.0"
|
||||||
tempfile = "2.1"
|
tempfile = "2.1"
|
||||||
x11-dl = "2.8"
|
x11-dl = "2.8"
|
||||||
|
|
|
@ -332,8 +332,8 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_wayland() -> Result<EventsLoop, ()> {
|
pub fn new_wayland() -> Result<EventsLoop, ()> {
|
||||||
wayland::WaylandContext::init()
|
wayland::EventsLoop::new()
|
||||||
.map(|ctx| EventsLoop::Wayland(wayland::EventsLoop::new(ctx)))
|
.map(EventsLoop::Wayland)
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ impl EventsLoop {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
||||||
match *self {
|
match *self {
|
||||||
EventsLoop::Wayland(ref evlp) => wayland::get_available_monitors(evlp.context())
|
EventsLoop::Wayland(ref evlp) => evlp.get_available_monitors()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(MonitorId::Wayland)
|
.map(MonitorId::Wayland)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -361,7 +361,7 @@ impl EventsLoop {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_primary_monitor(&self) -> MonitorId {
|
pub fn get_primary_monitor(&self) -> MonitorId {
|
||||||
match *self {
|
match *self {
|
||||||
EventsLoop::Wayland(ref evlp) => MonitorId::Wayland(wayland::get_primary_monitor(evlp.context())),
|
EventsLoop::Wayland(ref evlp) => MonitorId::Wayland(evlp.get_primary_monitor()),
|
||||||
EventsLoop::X(ref evlp) => MonitorId::X(x11::get_primary_monitor(evlp.x_connection())),
|
EventsLoop::X(ref evlp) => MonitorId::X(x11::get_primary_monitor(evlp.x_connection())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,431 +0,0 @@
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
use wayland_client::{EnvHandler, default_connect, EventQueue, EventQueueHandle, Init, Proxy};
|
|
||||||
use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor,
|
|
||||||
wl_display, wl_registry, wl_output, wl_surface, wl_buffer};
|
|
||||||
|
|
||||||
use super::wayland_protocols::unstable::xdg_shell::client::zxdg_shell_v6;
|
|
||||||
|
|
||||||
use super::{wayland_window, tempfile};
|
|
||||||
|
|
||||||
use super::wayland_window::Shell;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Registry and globals handling
|
|
||||||
*/
|
|
||||||
|
|
||||||
wayland_env!(InnerEnv,
|
|
||||||
compositor: wl_compositor::WlCompositor,
|
|
||||||
shm: wl_shm::WlShm,
|
|
||||||
subcompositor: wl_subcompositor::WlSubcompositor
|
|
||||||
);
|
|
||||||
|
|
||||||
struct WaylandEnv {
|
|
||||||
registry: wl_registry::WlRegistry,
|
|
||||||
inner: EnvHandler<InnerEnv>,
|
|
||||||
shell: Option<wayland_window::Shell>,
|
|
||||||
monitors: Vec<OutputInfo>,
|
|
||||||
my_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OutputInfo {
|
|
||||||
output: wl_output::WlOutput,
|
|
||||||
id: u32,
|
|
||||||
scale: f32,
|
|
||||||
pix_size: (u32, u32),
|
|
||||||
pix_pos: (i32, i32),
|
|
||||||
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),
|
|
||||||
pix_pos: (0, 0),
|
|
||||||
name: "".into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WaylandEnv {
|
|
||||||
fn new(registry: wl_registry::WlRegistry) -> WaylandEnv {
|
|
||||||
WaylandEnv {
|
|
||||||
registry: registry,
|
|
||||||
inner: EnvHandler::new(),
|
|
||||||
shell: None,
|
|
||||||
monitors: Vec::new(),
|
|
||||||
my_id: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_seat(&self) -> Option<wl_seat::WlSeat> {
|
|
||||||
for &(name, ref interface, version) in self.inner.globals() {
|
|
||||||
if interface == "wl_seat" {
|
|
||||||
if version < 5 {
|
|
||||||
panic!("Winit requires at least version 5 of the wl_seat global.");
|
|
||||||
}
|
|
||||||
let seat = self.registry.bind::<wl_seat::WlSeat>(5, name);
|
|
||||||
return Some(seat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_shell(&mut self) -> bool {
|
|
||||||
if self.shell.is_some() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// xdg_shell is not available, so initialize wl_shell
|
|
||||||
for &(name, ref interface, _) in self.inner.globals() {
|
|
||||||
if interface == "wl_shell" {
|
|
||||||
self.shell = Some(Shell::Wl(self.registry.bind::<wl_shell::WlShell>(1, name)));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_shell(&self) -> &Shell {
|
|
||||||
self.shell.as_ref().expect("Shell was not properly initialized")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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::WlOutput::interface_name() {
|
|
||||||
// intercept outputs
|
|
||||||
let output = self.registry.bind::<wl_output::WlOutput>(1, name);
|
|
||||||
evqh.register::<_, WaylandEnv>(&output, self.my_id);
|
|
||||||
self.monitors.push(OutputInfo::new(output, name));
|
|
||||||
} else if interface == zxdg_shell_v6::ZxdgShellV6::interface_name() {
|
|
||||||
let xdg_shell = self.registry.bind::<zxdg_shell_v6::ZxdgShellV6>(1, name);
|
|
||||||
let xdg_ping_hid = evqh.add_handler(XdgShellPingHandler);
|
|
||||||
evqh.register::<_, XdgShellPingHandler>(&xdg_shell, xdg_ping_hid);
|
|
||||||
self.shell = Some(Shell::Xdg(xdg_shell));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct XdgShellPingHandler;
|
|
||||||
|
|
||||||
impl zxdg_shell_v6::Handler for XdgShellPingHandler {
|
|
||||||
fn ping(&mut self, _: &mut EventQueueHandle, proxy: &zxdg_shell_v6::ZxdgShellV6, serial: u32) {
|
|
||||||
proxy.pong(serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_handler!(XdgShellPingHandler, zxdg_shell_v6::Handler, zxdg_shell_v6::ZxdgShellV6);
|
|
||||||
|
|
||||||
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);
|
|
||||||
m.pix_pos = (x, y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn mode(&mut self,
|
|
||||||
_: &mut EventQueueHandle,
|
|
||||||
proxy: &wl_output::WlOutput,
|
|
||||||
flags: wl_output::Mode,
|
|
||||||
width: i32, height: i32,
|
|
||||||
_refresh: i32)
|
|
||||||
{
|
|
||||||
if flags.contains(wl_output::Current) {
|
|
||||||
for m in self.monitors.iter_mut().filter(|m| m.output.equals(proxy)) {
|
|
||||||
m.pix_size = (width as u32, height as u32);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn scale(&mut self,
|
|
||||||
_: &mut EventQueueHandle,
|
|
||||||
proxy: &wl_output::WlOutput,
|
|
||||||
factor: i32)
|
|
||||||
{
|
|
||||||
for m in self.monitors.iter_mut().filter(|m| m.output.equals(proxy)) {
|
|
||||||
m.scale = factor as f32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_handler!(WaylandEnv, wl_output::Handler, wl_output::WlOutput);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Main context struct
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub struct WaylandContext {
|
|
||||||
pub display: wl_display::WlDisplay,
|
|
||||||
pub evq: Mutex<EventQueue>,
|
|
||||||
env_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WaylandContext {
|
|
||||||
pub fn init() -> Option<WaylandContext> {
|
|
||||||
// attempt to connect to the wayland server
|
|
||||||
// this handles both "no libwayland" and "no compositor" cases
|
|
||||||
let (display, mut event_queue) = match default_connect() {
|
|
||||||
Ok(ret) => ret,
|
|
||||||
Err(_) => return None
|
|
||||||
};
|
|
||||||
|
|
||||||
// this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69)
|
|
||||||
let registry = display.get_registry();
|
|
||||||
let env_id = event_queue.add_handler_with_init(WaylandEnv::new(registry));
|
|
||||||
// two round trips to fully initialize
|
|
||||||
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
|
|
||||||
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut state = event_queue.state();
|
|
||||||
let mut env = state.get_mut_handler::<WaylandEnv>(env_id);
|
|
||||||
if !env.ensure_shell() {
|
|
||||||
// This is a compositor bug, it _must_ at least support xl_shell
|
|
||||||
panic!("Compositor didi not advertize xdg_shell not wl_shell.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(WaylandContext {
|
|
||||||
evq: Mutex::new(event_queue),
|
|
||||||
display: display,
|
|
||||||
env_id: env_id
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_events(&self) {
|
|
||||||
let evq_guard = self.evq.lock().unwrap();
|
|
||||||
// read some events from the socket if some are waiting & queue is empty
|
|
||||||
if let Some(guard) = evq_guard.prepare_read() {
|
|
||||||
guard.read_events().expect("Wayland connection unexpectedly lost");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dispatch_pending(&self) {
|
|
||||||
let mut guard = self.evq.lock().unwrap();
|
|
||||||
guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dispatch(&self) {
|
|
||||||
let mut guard = self.evq.lock().unwrap();
|
|
||||||
guard.dispatch().expect("Wayland connection unexpectedly lost");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flush(&self) {
|
|
||||||
let _ = self.display.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_seat(&self) -> Option<wl_seat::WlSeat> {
|
|
||||||
let mut guard = self.evq.lock().unwrap();
|
|
||||||
let state = guard.state();
|
|
||||||
state.get_handler::<WaylandEnv>(self.env_id).get_seat()
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn blank_surface(&self, surface: &wl_surface::WlSurface, evq: &mut EventQueue, width: i32, height: i32) {
|
|
||||||
let mut tmp = tempfile::tempfile().expect("Failed to create a tmpfile buffer.");
|
|
||||||
for _ in 0..(width*height) {
|
|
||||||
tmp.write_all(&[0xff,0xff,0xff,0xff]).unwrap();
|
|
||||||
}
|
|
||||||
tmp.flush().unwrap();
|
|
||||||
let pool = {
|
|
||||||
let mut state = evq.state();
|
|
||||||
let env = state.get_mut_handler::<WaylandEnv>(self.env_id);
|
|
||||||
env.inner.shm.create_pool(tmp.as_raw_fd(), width*height*4)
|
|
||||||
};
|
|
||||||
let buffer = pool.create_buffer(0, width, height, width, wl_shm::Format::Argb8888).expect("Pool cannot be already dead");
|
|
||||||
surface.attach(Some(&buffer), 0, 0);
|
|
||||||
surface.commit();
|
|
||||||
// the buffer will keep the contents alive as needed
|
|
||||||
pool.destroy();
|
|
||||||
|
|
||||||
// create a handler to clean up initial buffer
|
|
||||||
let init_buffer_handler = InitialBufferHandler {
|
|
||||||
initial_buffer: Some((buffer.clone().unwrap(), tmp))
|
|
||||||
};
|
|
||||||
let initial_buffer_handler_id = evq.add_handler(init_buffer_handler);
|
|
||||||
// register the buffer to it
|
|
||||||
evq.register::<_, InitialBufferHandler>(&buffer, initial_buffer_handler_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_window<H: wayland_window::Handler>(&self, width: u32, height: u32, decorated: bool)
|
|
||||||
-> (Arc<wl_surface::WlSurface>, wayland_window::DecoratedSurface<H>, bool)
|
|
||||||
{
|
|
||||||
let mut guard = self.evq.lock().unwrap();
|
|
||||||
let (surface, decorated, xdg) = {
|
|
||||||
let mut state = guard.state();
|
|
||||||
let env = state.get_mut_handler::<WaylandEnv>(self.env_id);
|
|
||||||
let surface = Arc::new(env.inner.compositor.create_surface());
|
|
||||||
let decorated = wayland_window::DecoratedSurface::new(
|
|
||||||
&*surface, 800, 600,
|
|
||||||
&env.inner.compositor,
|
|
||||||
&env.inner.subcompositor,
|
|
||||||
&env.inner.shm,
|
|
||||||
env.get_shell(),
|
|
||||||
env.get_seat(),
|
|
||||||
decorated
|
|
||||||
).expect("Failed to create a tmpfile buffer.");
|
|
||||||
let xdg = match env.get_shell() {
|
|
||||||
&Shell::Xdg(_) => true,
|
|
||||||
&Shell::Wl(_) => false
|
|
||||||
};
|
|
||||||
(surface, decorated, xdg)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !xdg {
|
|
||||||
// if using wl_shell, we need to draw something in order to kickstart
|
|
||||||
// the event loop
|
|
||||||
// if using xdg_shell, it is an error to do it now, and the events loop will not
|
|
||||||
// be stuck. We cannot draw anything before having received an appropriate event
|
|
||||||
// from the compositor
|
|
||||||
self.blank_surface(&surface, &mut *guard, width as i32, height as i32);
|
|
||||||
}
|
|
||||||
(surface, decorated, xdg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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) -> u32 {
|
|
||||||
self.id
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_position(&self) -> (i32, i32) {
|
|
||||||
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_pos
|
|
||||||
}
|
|
||||||
// if we reach here, this monitor does not exist any more
|
|
||||||
(0,0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_hidpi_factor(&self) -> f32 {
|
|
||||||
1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// a handler to release the ressources acquired to draw the initial white screen as soon as
|
|
||||||
// the compositor does not use them any more
|
|
||||||
pub struct InitialBufferHandler {
|
|
||||||
initial_buffer: Option<(wl_buffer::WlBuffer, File)>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl wl_buffer::Handler for InitialBufferHandler {
|
|
||||||
fn release(&mut self, _: &mut EventQueueHandle, buffer: &wl_buffer::WlBuffer) {
|
|
||||||
// release the ressources we've acquired for initial white window
|
|
||||||
buffer.destroy();
|
|
||||||
self.initial_buffer = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_handler!(InitialBufferHandler, wl_buffer::Handler, wl_buffer::WlBuffer);
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,71 +1,131 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use {VirtualKeyCode, ElementState, WindowEvent as Event, KeyboardInput};
|
use {VirtualKeyCode, ElementState, WindowEvent as Event, KeyboardInput, ModifiersState};
|
||||||
|
|
||||||
use events::ModifiersState;
|
use super::{EventsLoopSink, WindowId, make_wid, DeviceId};
|
||||||
|
use super::wayland_kbd::{MappedKeyboardImplementation, register_kbd};
|
||||||
use super::{wayland_kbd, EventsLoopSink, WindowId, DeviceId};
|
|
||||||
use wayland_client::EventQueueHandle;
|
|
||||||
use wayland_client::protocol::wl_keyboard;
|
use wayland_client::protocol::wl_keyboard;
|
||||||
|
use wayland_client::EventQueueHandle;
|
||||||
|
|
||||||
pub struct KbdHandler {
|
pub fn init_keyboard(evq: &mut EventQueueHandle, keyboard: &wl_keyboard::WlKeyboard, sink: &Arc<Mutex<EventsLoopSink>>) {
|
||||||
sink: Arc<Mutex<EventsLoopSink>>,
|
let idata = KeyboardIData {
|
||||||
pub target: Option<WindowId>
|
sink: sink.clone(),
|
||||||
}
|
target: None
|
||||||
|
};
|
||||||
|
|
||||||
impl KbdHandler {
|
if register_kbd(evq, keyboard, mapped_keyboard_impl(), idata).is_err() {
|
||||||
pub fn new(sink: Arc<Mutex<EventsLoopSink>>) -> KbdHandler {
|
// initializing libxkbcommon failed :(
|
||||||
KbdHandler { sink: sink, target: None }
|
// fallback implementation
|
||||||
|
let idata = KeyboardIData {
|
||||||
|
sink: sink.clone(),
|
||||||
|
target: None
|
||||||
|
};
|
||||||
|
evq.register(keyboard, raw_keyboard_impl(), idata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wayland_kbd::Handler for KbdHandler {
|
struct KeyboardIData {
|
||||||
fn key(&mut self,
|
sink: Arc<Mutex<EventsLoopSink>>,
|
||||||
_evqh: &mut EventQueueHandle,
|
target: Option<WindowId>
|
||||||
_proxy: &wl_keyboard::WlKeyboard,
|
}
|
||||||
_serial: u32,
|
|
||||||
_time: u32,
|
fn mapped_keyboard_impl() -> MappedKeyboardImplementation<KeyboardIData> {
|
||||||
mods: &wayland_kbd::ModifiersState,
|
MappedKeyboardImplementation {
|
||||||
rawkey: u32,
|
enter: |_, idata, _, _, surface, _, _, _| {
|
||||||
keysym: u32,
|
let wid = make_wid(surface);
|
||||||
state: wl_keyboard::KeyState,
|
idata.sink.lock().unwrap().send_event(Event::Focused(true), wid);
|
||||||
utf8: Option<String>)
|
idata.target = Some(wid);
|
||||||
{
|
},
|
||||||
if let Some(wid) = self.target {
|
leave: |_, idata, _, _, surface| {
|
||||||
let state = match state {
|
let wid = make_wid(surface);
|
||||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
idata.sink.lock().unwrap().send_event(Event::Focused(false), wid);
|
||||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
idata.target = None;
|
||||||
};
|
},
|
||||||
let vkcode = key_to_vkey(rawkey, keysym);
|
key: |_, idata, _, _, _, mods, rawkey, keysym, state, utf8| {
|
||||||
let mut guard = self.sink.lock().unwrap();
|
if let Some(wid) = idata.target {
|
||||||
guard.send_event(
|
let state = match state {
|
||||||
Event::KeyboardInput {
|
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||||
input: KeyboardInput {
|
};
|
||||||
state: state,
|
let vkcode = key_to_vkey(rawkey, keysym);
|
||||||
scancode: rawkey,
|
let mut guard = idata.sink.lock().unwrap();
|
||||||
virtual_keycode: vkcode,
|
guard.send_event(
|
||||||
modifiers: ModifiersState {
|
Event::KeyboardInput {
|
||||||
shift: mods.shift,
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
ctrl: mods.ctrl,
|
input: KeyboardInput {
|
||||||
alt: mods.alt,
|
state: state,
|
||||||
logo: mods.logo
|
scancode: rawkey,
|
||||||
|
virtual_keycode: vkcode,
|
||||||
|
modifiers: ModifiersState {
|
||||||
|
shift: mods.shift,
|
||||||
|
ctrl: mods.ctrl,
|
||||||
|
alt: mods.alt,
|
||||||
|
logo: mods.logo
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
wid
|
||||||
wid
|
);
|
||||||
);
|
// send char event only on key press, not release
|
||||||
// send char event only on key press, not release
|
if let ElementState::Released = state { return }
|
||||||
if let ElementState::Released = state { return }
|
if let Some(txt) = utf8 {
|
||||||
if let Some(txt) = utf8 {
|
for chr in txt.chars() {
|
||||||
for chr in txt.chars() {
|
guard.send_event(Event::ReceivedCharacter(chr), wid);
|
||||||
guard.send_event(Event::ReceivedCharacter(chr), wid);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
repeat_info: |_, _idata, _, _rate, _delay| {
|
||||||
|
// TODO: handle repeat info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This is fallback impl if libxkbcommon was not available
|
||||||
|
// This case should probably never happen, as most wayland
|
||||||
|
// compositors _need_ libxkbcommon anyway...
|
||||||
|
//
|
||||||
|
// In this case, we don't have the keymap information (it is
|
||||||
|
// supposed to be serialized by the compositor using libxkbcommon)
|
||||||
|
fn raw_keyboard_impl() -> wl_keyboard::Implementation<KeyboardIData> {
|
||||||
|
wl_keyboard::Implementation {
|
||||||
|
enter: |_, idata, _, _, surface, _| {
|
||||||
|
let wid = make_wid(surface);
|
||||||
|
idata.sink.lock().unwrap().send_event(Event::Focused(true), wid);
|
||||||
|
idata.target = Some(wid);
|
||||||
|
},
|
||||||
|
leave: |_, idata, _, _, surface| {
|
||||||
|
let wid = make_wid(surface);
|
||||||
|
idata.sink.lock().unwrap().send_event(Event::Focused(false), wid);
|
||||||
|
idata.target = None;
|
||||||
|
},
|
||||||
|
key: |_, idata, _, _, _, key, state| {
|
||||||
|
if let Some(wid) = idata.target {
|
||||||
|
let state = match state {
|
||||||
|
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||||
|
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||||
|
};
|
||||||
|
idata.sink.lock().unwrap().send_event(
|
||||||
|
Event::KeyboardInput {
|
||||||
|
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||||
|
input: KeyboardInput {
|
||||||
|
state: state,
|
||||||
|
scancode: key,
|
||||||
|
virtual_keycode: None,
|
||||||
|
modifiers: ModifiersState::default(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
repeat_info: |_, _idata, _, _rate, _delay| {},
|
||||||
|
keymap: |_, _, _, _, _, _| {},
|
||||||
|
modifiers: |_, _, _, _, _, _, _, _| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn key_to_vkey(rawkey: u32, keysym: u32) -> Option<VirtualKeyCode> {
|
fn key_to_vkey(rawkey: u32, keysym: u32) -> Option<VirtualKeyCode> {
|
||||||
match rawkey {
|
match rawkey {
|
||||||
1 => Some(VirtualKeyCode::Escape),
|
1 => Some(VirtualKeyCode::Escape),
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
#![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::window::{Window, WindowId};
|
pub use self::window::Window;
|
||||||
pub use self::event_loop::{EventsLoop, EventsLoopProxy};
|
pub use self::event_loop::{EventsLoop, EventsLoopProxy, EventsLoopSink, MonitorId};
|
||||||
pub use self::context::{WaylandContext, MonitorId, get_available_monitors,
|
|
||||||
get_primary_monitor};
|
|
||||||
|
|
||||||
use self::window::{make_wid, DecoratedHandler};
|
|
||||||
use self::event_loop::EventsLoopSink;
|
|
||||||
|
|
||||||
extern crate wayland_kbd;
|
extern crate wayland_kbd;
|
||||||
extern crate wayland_window;
|
extern crate wayland_window;
|
||||||
extern crate wayland_protocols;
|
extern crate wayland_protocols;
|
||||||
extern crate tempfile;
|
extern crate tempfile;
|
||||||
|
|
||||||
mod context;
|
use wayland_client::protocol::wl_surface;
|
||||||
|
use wayland_client::Proxy;
|
||||||
|
|
||||||
mod event_loop;
|
mod event_loop;
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct DeviceId;
|
pub struct DeviceId;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct WindowId(usize);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn make_wid(s: &wl_surface::WlSurface) -> WindowId {
|
||||||
|
WindowId(s.ptr() as usize)
|
||||||
|
}
|
|
@ -1,97 +1,86 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
use std::sync::atomic::{Ordering, AtomicBool};
|
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
use wayland_client::{EventQueueHandle, Proxy};
|
|
||||||
use wayland_client::protocol::{wl_display,wl_surface};
|
use wayland_client::protocol::{wl_display,wl_surface};
|
||||||
|
use wayland_client::{Proxy, StateToken};
|
||||||
|
|
||||||
use {CreationError, MouseCursor, CursorState, WindowAttributes};
|
use {CreationError, MouseCursor, CursorState, WindowAttributes};
|
||||||
use platform::MonitorId as PlatformMonitorId;
|
use platform::MonitorId as PlatformMonitorId;
|
||||||
use window::MonitorId as RootMonitorId;
|
use window::MonitorId as RootMonitorId;
|
||||||
use platform::wayland::MonitorId as WaylandMonitorId;
|
|
||||||
use platform::wayland::context::get_available_monitors;
|
|
||||||
|
|
||||||
use super::{WaylandContext, EventsLoop};
|
use super::{EventsLoop, WindowId, make_wid, MonitorId};
|
||||||
use super::wayland_window;
|
use super::wayland_window::{DecoratedSurface, DecoratedSurfaceImplementation};
|
||||||
use super::wayland_window::DecoratedSurface;
|
use super::event_loop::StateContext;
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
// the global wayland context
|
display: Arc<wl_display::WlDisplay>,
|
||||||
ctxt: Arc<WaylandContext>,
|
surface: wl_surface::WlSurface,
|
||||||
// signal to advertize the EventsLoop when we are destroyed
|
decorated: Arc<Mutex<DecoratedSurface>>,
|
||||||
cleanup_signal: Arc<AtomicBool>,
|
monitors: Arc<Mutex<MonitorList>>,
|
||||||
// our wayland surface
|
ready: Arc<Mutex<bool>>,
|
||||||
surface: Arc<wl_surface::WlSurface>,
|
size: Arc<Mutex<(u32, u32)>>,
|
||||||
// our current inner dimensions
|
kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>),
|
||||||
size: Mutex<(u32, u32)>,
|
|
||||||
// the id of our DecoratedHandler in the EventQueue
|
|
||||||
decorated_id: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub struct WindowId(usize);
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn make_wid(s: &wl_surface::WlSurface) -> WindowId {
|
|
||||||
WindowId(s.ptr() as usize)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(evlp: &EventsLoop, attributes: &WindowAttributes) -> Result<Window, CreationError>
|
pub fn new(evlp: &EventsLoop, attributes: &WindowAttributes) -> Result<Window, CreationError>
|
||||||
{
|
{
|
||||||
let ctxt = evlp.context().clone();
|
|
||||||
let (width, height) = attributes.dimensions.unwrap_or((800,600));
|
let (width, height) = attributes.dimensions.unwrap_or((800,600));
|
||||||
|
|
||||||
let (surface, decorated, xdg) = ctxt.create_window::<DecoratedHandler>(width, height, attributes.decorations);
|
// Create the decorated surface
|
||||||
|
let ready = Arc::new(Mutex::new(false));
|
||||||
// init DecoratedSurface
|
let size = Arc::new(Mutex::new((width, height)));
|
||||||
let cleanup_signal = evlp.get_window_init();
|
let store_token = evlp.store.clone();
|
||||||
|
let (surface, mut decorated, xdg) = evlp.create_window(
|
||||||
let mut fullscreen_monitor = None;
|
width, height, attributes.decorations, decorated_impl(),
|
||||||
|
|surface| DecoratedIData {
|
||||||
|
ready: ready.clone(),
|
||||||
|
surface: surface.clone().unwrap(),
|
||||||
|
store_token: store_token.clone()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// If we are using xdg, we are not ready yet
|
||||||
|
{ *ready.lock().unwrap() = !xdg; }
|
||||||
|
// Check for fullscreen requirements
|
||||||
if let Some(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = attributes.fullscreen {
|
if let Some(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = attributes.fullscreen {
|
||||||
ctxt.with_output(monitor_id.clone(), |output| {
|
let info = monitor_id.info.lock().unwrap();
|
||||||
fullscreen_monitor = output.clone();
|
decorated.set_fullscreen(Some(&info.output));
|
||||||
|
}
|
||||||
|
// setup the monitor tracking
|
||||||
|
let monitor_list = Arc::new(Mutex::new(MonitorList::default()));
|
||||||
|
{
|
||||||
|
let mut evq = evlp.evq.borrow_mut();
|
||||||
|
let idata = (evlp.ctxt_token.clone(), monitor_list.clone());
|
||||||
|
evq.register(&surface, surface_impl(), idata);
|
||||||
|
}
|
||||||
|
// a surface commit with no buffer so that the compositor don't
|
||||||
|
// forget to configure us
|
||||||
|
surface.commit();
|
||||||
|
|
||||||
|
let kill_switch = Arc::new(Mutex::new(false));
|
||||||
|
let decorated = Arc::new(Mutex::new(decorated));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut evq = evlp.evq.borrow_mut();
|
||||||
|
evq.state().get_mut(&store_token).windows.push(InternalWindow {
|
||||||
|
closed: false,
|
||||||
|
newsize: None,
|
||||||
|
need_refresh: false,
|
||||||
|
surface: surface.clone().unwrap(),
|
||||||
|
kill_switch: kill_switch.clone(),
|
||||||
|
decorated: Arc::downgrade(&decorated)
|
||||||
});
|
});
|
||||||
|
evq.sync_roundtrip().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let decorated_id = {
|
Ok(Window {
|
||||||
let mut evq_guard = ctxt.evq.lock().unwrap();
|
display: evlp.display.clone(),
|
||||||
// store the DecoratedSurface handler
|
|
||||||
let decorated_id = evq_guard.add_handler_with_init(decorated);
|
|
||||||
{
|
|
||||||
let mut state = evq_guard.state();
|
|
||||||
// initialize the DecoratedHandler
|
|
||||||
let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
|
|
||||||
*(decorated.handler()) = Some(DecoratedHandler::new(!xdg));
|
|
||||||
|
|
||||||
// set fullscreen if necessary
|
|
||||||
if let Some(output) = fullscreen_monitor {
|
|
||||||
decorated.set_fullscreen(Some(&output));
|
|
||||||
}
|
|
||||||
// Finally, set the decorations size
|
|
||||||
decorated.resize(width as i32, height as i32);
|
|
||||||
}
|
|
||||||
|
|
||||||
evq_guard.sync_roundtrip().unwrap();
|
|
||||||
|
|
||||||
decorated_id
|
|
||||||
};
|
|
||||||
// send our configuration to the compositor
|
|
||||||
// if we're in xdg mode, no buffer is attached yet, so this
|
|
||||||
// is fine (and more or less required actually)
|
|
||||||
surface.commit();
|
|
||||||
let me = Window {
|
|
||||||
ctxt: ctxt,
|
|
||||||
cleanup_signal: cleanup_signal,
|
|
||||||
surface: surface,
|
surface: surface,
|
||||||
size: Mutex::new((width, height)),
|
decorated: decorated,
|
||||||
decorated_id: decorated_id
|
monitors: monitor_list,
|
||||||
};
|
ready: ready,
|
||||||
|
size: size,
|
||||||
// register ourselves to the EventsLoop
|
kill_switch: (kill_switch, evlp.cleanup_needed.clone())
|
||||||
evlp.register_window(me.decorated_id, me.surface.clone());
|
})
|
||||||
|
|
||||||
Ok(me)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -100,10 +89,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_title(&self, title: &str) {
|
pub fn set_title(&self, title: &str) {
|
||||||
let mut guard = self.ctxt.evq.lock().unwrap();
|
self.decorated.lock().unwrap().set_title(title.into());
|
||||||
let mut state = guard.state();
|
|
||||||
let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
|
|
||||||
decorated.set_title(title.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -141,10 +127,7 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
// NOTE: This will only resize the borders, the contents must be updated by the user
|
// 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.ctxt.evq.lock().unwrap();
|
self.decorated.lock().unwrap().resize(x as i32, y as i32);
|
||||||
let mut state = guard.state();
|
|
||||||
let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
|
|
||||||
decorated.resize(x as i32, y as i32);
|
|
||||||
*(self.size.lock().unwrap()) = (x, y);
|
*(self.size.lock().unwrap()) = (x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,8 +149,13 @@ impl Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn hidpi_factor(&self) -> f32 {
|
pub fn hidpi_factor(&self) -> f32 {
|
||||||
// TODO
|
let mut factor = 1.0;
|
||||||
1.0
|
let guard = self.monitors.lock().unwrap();
|
||||||
|
for monitor_id in &guard.monitors {
|
||||||
|
let info = monitor_id.info.lock().unwrap();
|
||||||
|
if info.scale > factor { factor = info.scale; }
|
||||||
|
}
|
||||||
|
factor
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -177,109 +165,148 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_display(&self) -> &wl_display::WlDisplay {
|
pub fn get_display(&self) -> &wl_display::WlDisplay {
|
||||||
&self.ctxt.display
|
&*self.display
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_surface(&self) -> &wl_surface::WlSurface {
|
pub fn get_surface(&self) -> &wl_surface::WlSurface {
|
||||||
&self.surface
|
&self.surface
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_monitor(&self) -> WaylandMonitorId {
|
pub fn get_current_monitor(&self) -> MonitorId {
|
||||||
let monitors = get_available_monitors(&self.ctxt);
|
// we don't know how much each monitor sees us so...
|
||||||
let default = monitors[0].clone();
|
// just return the most recent one ?
|
||||||
|
let guard = self.monitors.lock().unwrap();
|
||||||
let (wx,wy) = match self.get_position() {
|
guard.monitors.last().unwrap().clone()
|
||||||
Some(val) => (cmp::max(0,val.0) as u32, cmp::max(0,val.1) as u32),
|
|
||||||
None=> return default,
|
|
||||||
};
|
|
||||||
let (ww,wh) = match self.get_outer_size() {
|
|
||||||
Some(val) => val,
|
|
||||||
None=> return default,
|
|
||||||
};
|
|
||||||
// Opposite corner coordinates
|
|
||||||
let (wxo, wyo) = (wx+ww-1, wy+wh-1);
|
|
||||||
|
|
||||||
// Find the monitor with the biggest overlap with the window
|
|
||||||
let mut overlap = 0;
|
|
||||||
let mut find = default;
|
|
||||||
for monitor in monitors {
|
|
||||||
let (mx, my) = monitor.get_position();
|
|
||||||
let mx = mx as u32;
|
|
||||||
let my = my as u32;
|
|
||||||
let (mw, mh) = monitor.get_dimensions();
|
|
||||||
let (mxo, myo) = (mx+mw-1, my+mh-1);
|
|
||||||
let (ox, oy) = (cmp::max(wx, mx), cmp::max(wy, my));
|
|
||||||
let (oxo, oyo) = (cmp::min(wxo, mxo), cmp::min(wyo, myo));
|
|
||||||
let osize = if ox <= oxo || oy <= oyo { 0 } else { (oxo-ox)*(oyo-oy) };
|
|
||||||
|
|
||||||
if osize > overlap {
|
|
||||||
overlap = osize;
|
|
||||||
find = monitor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
find
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ready(&self) -> bool {
|
pub fn is_ready(&self) -> bool {
|
||||||
let mut guard = self.ctxt.evq.lock().unwrap();
|
*self.ready.lock().unwrap()
|
||||||
let mut state = guard.state();
|
|
||||||
let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
|
|
||||||
decorated.handler().as_ref().unwrap().configured
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Window {
|
impl Drop for Window {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.surface.destroy();
|
*(self.kill_switch.0.lock().unwrap()) = true;
|
||||||
self.cleanup_signal.store(true, Ordering::Relaxed);
|
*(self.kill_switch.1.lock().unwrap()) = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DecoratedHandler {
|
/*
|
||||||
newsize: Option<(u32, u32)>,
|
* Internal store for windows
|
||||||
refresh: bool,
|
*/
|
||||||
|
|
||||||
|
struct InternalWindow {
|
||||||
|
surface: wl_surface::WlSurface,
|
||||||
|
newsize: Option<(i32, i32)>,
|
||||||
|
need_refresh: bool,
|
||||||
closed: bool,
|
closed: bool,
|
||||||
configured: bool
|
kill_switch: Arc<Mutex<bool>>,
|
||||||
|
decorated: Weak<Mutex<DecoratedSurface>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DecoratedHandler {
|
pub struct WindowStore {
|
||||||
fn new(configured: bool) -> DecoratedHandler {
|
windows: Vec<InternalWindow>
|
||||||
DecoratedHandler {
|
}
|
||||||
newsize: None,
|
|
||||||
refresh: false,
|
impl WindowStore {
|
||||||
closed: false,
|
pub fn new() -> WindowStore {
|
||||||
configured: configured
|
WindowStore { windows: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_wid(&self, surface: &wl_surface::WlSurface) -> Option<WindowId> {
|
||||||
|
for window in &self.windows {
|
||||||
|
if surface.equals(&window.surface) {
|
||||||
|
return Some(make_wid(surface));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup(&mut self) {
|
||||||
|
self.windows.retain(|w| {
|
||||||
|
if *w.kill_switch.lock().unwrap() {
|
||||||
|
// window is dead, cleanup
|
||||||
|
w.surface.destroy();
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn for_each<F>(&mut self, mut f: F)
|
||||||
|
where F: FnMut(Option<(i32, i32)>, bool, bool, WindowId, Option<&mut DecoratedSurface>)
|
||||||
|
{
|
||||||
|
for window in &mut self.windows {
|
||||||
|
let opt_arc = window.decorated.upgrade();
|
||||||
|
let mut opt_mutex_lock = opt_arc.as_ref().map(|m| m.lock().unwrap());
|
||||||
|
f(
|
||||||
|
window.newsize.take(),
|
||||||
|
window.need_refresh,
|
||||||
|
window.closed,
|
||||||
|
make_wid(&window.surface),
|
||||||
|
opt_mutex_lock.as_mut().map(|m| &mut **m)
|
||||||
|
);
|
||||||
|
window.need_refresh = false;
|
||||||
|
// avoid re-spamming the event
|
||||||
|
window.closed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_newsize(&mut self) -> Option<(u32, u32)> {
|
|
||||||
self.newsize.take()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take_refresh(&mut self) -> bool {
|
|
||||||
let refresh = self.refresh;
|
|
||||||
self.refresh = false;
|
|
||||||
refresh
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_closed(&self) -> bool { self.closed }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wayland_window::Handler for DecoratedHandler {
|
/*
|
||||||
fn configure(&mut self,
|
* Protocol implementation
|
||||||
_: &mut EventQueueHandle,
|
*/
|
||||||
_cfg: wayland_window::Configure,
|
|
||||||
newsize: Option<(i32, i32)>)
|
|
||||||
{
|
|
||||||
self.newsize = newsize.map(|(w, h)| (w as u32, h as u32));
|
|
||||||
self.refresh = true;
|
|
||||||
self.configured = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn close(&mut self, _: &mut EventQueueHandle) {
|
struct DecoratedIData {
|
||||||
self.closed = true;
|
ready: Arc<Mutex<bool>>,
|
||||||
|
store_token: StateToken<WindowStore>,
|
||||||
|
surface: wl_surface::WlSurface
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decorated_impl() -> DecoratedSurfaceImplementation<DecoratedIData> {
|
||||||
|
DecoratedSurfaceImplementation {
|
||||||
|
configure: |evqh, idata, _, newsize| {
|
||||||
|
*idata.ready.lock().unwrap() = true;
|
||||||
|
let store = evqh.state().get_mut(&idata.store_token);
|
||||||
|
for window in &mut store.windows {
|
||||||
|
if window.surface.equals(&idata.surface) {
|
||||||
|
window.newsize = newsize;
|
||||||
|
window.need_refresh = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close: |evqh, idata| {
|
||||||
|
let store = evqh.state().get_mut(&idata.store_token);
|
||||||
|
for window in &mut store.windows {
|
||||||
|
if window.surface.equals(&idata.surface) {
|
||||||
|
window.closed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct MonitorList {
|
||||||
|
monitors: Vec<MonitorId>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn surface_impl() -> wl_surface::Implementation<(StateToken<StateContext>, Arc<Mutex<MonitorList>>)> {
|
||||||
|
wl_surface::Implementation {
|
||||||
|
enter: |evqh, &mut (ref token, ref list), _, output| {
|
||||||
|
let mut guard = list.lock().unwrap();
|
||||||
|
let ctxt = evqh.state().get(token);
|
||||||
|
let monitor = ctxt.monitor_id_for(output);
|
||||||
|
guard.monitors.push(monitor);
|
||||||
|
},
|
||||||
|
leave: |evqh, &mut (ref token, ref list), _, output| {
|
||||||
|
let mut guard = list.lock().unwrap();
|
||||||
|
let ctxt = evqh.state().get(token);
|
||||||
|
let monitor = ctxt.monitor_id_for(output);
|
||||||
|
guard.monitors.retain(|m| !Arc::ptr_eq(&m.info, &monitor.info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue