mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 21:31:29 +11:00
wayland: window creation & resizing
This commit is contained in:
parent
a505eddf29
commit
34c00aa153
|
@ -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.7.1", features = ["dlopen"] }
|
wayland-client = { version = "0.7.3", features = ["dlopen"] }
|
||||||
wayland-kbd = "0.6"
|
wayland-kbd = "0.6"
|
||||||
wayland-window = "0.4"
|
wayland-window = "0.4.2"
|
||||||
x11-dl = "2.8"
|
x11-dl = "2.8"
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
use Event;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use wayland_client::{EnvHandler, default_connect, EventQueue, EventQueueHandle, Init, Proxy};
|
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::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor,
|
||||||
wl_display, wl_registry, wl_output};
|
wl_display, wl_registry, wl_output, wl_surface};
|
||||||
|
|
||||||
|
use super::wayland_window;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Registry and globals handling
|
* Registry and globals handling
|
||||||
|
@ -21,7 +25,8 @@ struct WaylandEnv {
|
||||||
registry: wl_registry::WlRegistry,
|
registry: wl_registry::WlRegistry,
|
||||||
inner: EnvHandler<InnerEnv>,
|
inner: EnvHandler<InnerEnv>,
|
||||||
monitors: Vec<OutputInfo>,
|
monitors: Vec<OutputInfo>,
|
||||||
my_id: usize
|
my_id: usize,
|
||||||
|
windows: Vec<(Arc<wl_surface::WlSurface>,Arc<Mutex<VecDeque<Event>>>)>
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OutputInfo {
|
struct OutputInfo {
|
||||||
|
@ -50,9 +55,21 @@ impl WaylandEnv {
|
||||||
registry: registry,
|
registry: registry,
|
||||||
inner: EnvHandler::new(),
|
inner: EnvHandler::new(),
|
||||||
monitors: Vec::new(),
|
monitors: Vec::new(),
|
||||||
my_id: 0
|
my_id: 0,
|
||||||
|
windows: Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl Init for WaylandEnv {
|
||||||
|
@ -156,9 +173,11 @@ impl WaylandContext {
|
||||||
Err(e) => return None
|
Err(e) => return None
|
||||||
};
|
};
|
||||||
|
|
||||||
// this expect cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69)
|
// this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69)
|
||||||
let registry = display.get_registry().expect("Display cannot be already destroyed.");
|
let registry = display.get_registry().expect("Display cannot be already destroyed.");
|
||||||
let env_id = event_queue.add_handler_with_init(WaylandEnv::new(registry));
|
let env_id = event_queue.add_handler_with_init(WaylandEnv::new(registry));
|
||||||
|
// two syncs fully initialize
|
||||||
|
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
|
||||||
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
|
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
|
||||||
|
|
||||||
Some(WaylandContext {
|
Some(WaylandContext {
|
||||||
|
@ -167,6 +186,59 @@ impl WaylandContext {
|
||||||
env_id: env_id
|
env_id: env_id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dispatch_pending(&self) {
|
||||||
|
let mut guard = self.evq.lock().unwrap();
|
||||||
|
guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dispatch(&self) {
|
||||||
|
let mut guard = self.evq.lock().unwrap();
|
||||||
|
guard.dispatch().expect("Wayland connection unexpectedly lost");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush(&self) {
|
||||||
|
self.display.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_output<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 create_window<H: wayland_window::Handler>(&self)
|
||||||
|
-> (Arc<wl_surface::WlSurface>, Arc<Mutex<VecDeque<Event>>>, wayland_window::DecoratedSurface<H>)
|
||||||
|
{
|
||||||
|
let mut guard = self.evq.lock().unwrap();
|
||||||
|
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 prune_dead_windows(&self) {
|
||||||
|
let mut guard = self.evq.lock().unwrap();
|
||||||
|
let mut state = guard.state();
|
||||||
|
let env = state.get_mut_handler::<WaylandEnv>(self.env_id);
|
||||||
|
env.windows.retain(|w| w.0.is_alive());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_primary_monitor(ctxt: &Arc<WaylandContext>) -> MonitorId {
|
pub fn get_primary_monitor(ctxt: &Arc<WaylandContext>) -> MonitorId {
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
use std::sync::Arc;
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use wayland_client::protocol::{wl_display,wl_surface};
|
use wayland_client::{EventQueue, EventQueueHandle, Init};
|
||||||
|
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};
|
||||||
|
|
||||||
use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
|
use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
|
||||||
|
use platform::MonitorId as PlatformMonitorId;
|
||||||
|
|
||||||
use super::WaylandContext;
|
use super::WaylandContext;
|
||||||
|
use super::wayland_window;
|
||||||
|
use super::wayland_window::DecoratedSurface;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WindowProxy;
|
pub struct WindowProxy;
|
||||||
|
@ -17,7 +22,13 @@ impl WindowProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
resize_callback: Option<fn(u32,u32)>
|
ctxt: Arc<WaylandContext>,
|
||||||
|
evq: Mutex<EventQueue>,
|
||||||
|
eviter: Arc<Mutex<VecDeque<Event>>>,
|
||||||
|
surface: Arc<wl_surface::WlSurface>,
|
||||||
|
size: Mutex<(u32, u32)>,
|
||||||
|
handler_id: usize,
|
||||||
|
decorated_id: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PollEventsIterator<'a> {
|
pub struct PollEventsIterator<'a> {
|
||||||
|
@ -28,7 +39,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> {
|
||||||
unimplemented!()
|
self.window.next_event(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,14 +51,112 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
|
||||||
type Item = Event;
|
type Item = Event;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Event> {
|
fn next(&mut self) -> Option<Event> {
|
||||||
unimplemented!()
|
self.window.next_event(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes) -> Result<Window, CreationError>
|
pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes) -> Result<Window, CreationError>
|
||||||
{
|
{
|
||||||
unimplemented!()
|
let (width, height) = attributes.dimensions.unwrap_or((800,600));
|
||||||
|
|
||||||
|
let mut evq = ctxt.display.create_event_queue();
|
||||||
|
|
||||||
|
let (surface, eviter, decorated) = ctxt.create_window::<DecoratedHandler>();
|
||||||
|
|
||||||
|
// init DecoratedSurface
|
||||||
|
let decorated_id = evq.add_handler_with_init(decorated);
|
||||||
|
{
|
||||||
|
let mut state = evq.state();
|
||||||
|
let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
|
||||||
|
*(decorated.handler()) = Some(DecoratedHandler::new());
|
||||||
|
|
||||||
|
if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor {
|
||||||
|
ctxt.with_output(monitor_id.clone(), |output| {
|
||||||
|
decorated.set_fullscreen(
|
||||||
|
wl_shell_surface::FullscreenMethod::Default,
|
||||||
|
0,
|
||||||
|
Some(output)
|
||||||
|
)
|
||||||
|
});
|
||||||
|
} else if attributes.decorations {
|
||||||
|
decorated.set_decorate(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// init general handler
|
||||||
|
let handler = WindowHandler::new();
|
||||||
|
let handler_id = evq.add_handler_with_init(handler);
|
||||||
|
|
||||||
|
Ok(Window {
|
||||||
|
ctxt: ctxt,
|
||||||
|
evq: Mutex::new(evq),
|
||||||
|
eviter: eviter,
|
||||||
|
surface: surface,
|
||||||
|
size: Mutex::new((width, height)),
|
||||||
|
handler_id: handler_id,
|
||||||
|
decorated_id: decorated_id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_resize(&self) {
|
||||||
|
use std::cmp::max;
|
||||||
|
let mut evq_guard = self.evq.lock().unwrap();
|
||||||
|
let mut state = evq_guard.state();
|
||||||
|
let newsize = {
|
||||||
|
let decorated = state.get_mut_handler::<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 }
|
||||||
|
|
||||||
|
// try a pending dispatch
|
||||||
|
// TODO: insert a non-blocking read from socket, overwise no new events will ever come
|
||||||
|
{
|
||||||
|
self.ctxt.dispatch_pending();
|
||||||
|
let mut guard = self.evq.lock().unwrap().dispatch_pending();
|
||||||
|
// some events were dispatched, need to process a potential resising
|
||||||
|
self.process_resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut evt = {
|
||||||
|
let mut guard = self.eviter.lock().unwrap();
|
||||||
|
guard.pop_front()
|
||||||
|
};
|
||||||
|
|
||||||
|
while block && evt.is_none() {
|
||||||
|
// no event waiting, need to repopulate!
|
||||||
|
{
|
||||||
|
self.ctxt.flush();
|
||||||
|
self.ctxt.dispatch();
|
||||||
|
let mut guard = self.evq.lock().unwrap().dispatch();
|
||||||
|
// some events were dispatched, need to process a potential resising
|
||||||
|
self.process_resize();
|
||||||
|
}
|
||||||
|
// try again
|
||||||
|
let mut guard = self.eviter.lock().unwrap();
|
||||||
|
evt = guard.pop_front()
|
||||||
|
}
|
||||||
|
evt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_title(&self, title: &str) {
|
pub fn set_title(&self, title: &str) {
|
||||||
|
@ -112,7 +221,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]
|
||||||
|
@ -144,16 +256,59 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_display(&self) -> &wl_display::WlDisplay {
|
pub fn get_display(&self) -> &wl_display::WlDisplay {
|
||||||
unimplemented!()
|
&self.ctxt.display
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_surface(&self) -> &wl_surface::WlSurface {
|
pub fn get_surface(&self) -> &wl_surface::WlSurface {
|
||||||
unimplemented!()
|
&self.surface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Window {
|
impl Drop for Window {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// TODO
|
self.surface.destroy();
|
||||||
|
self.ctxt.prune_dead_windows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DecoratedHandler {
|
||||||
|
newsize: Option<(u32, u32)>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DecoratedHandler {
|
||||||
|
fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }}
|
||||||
|
fn take_newsize(&mut self) -> Option<(u32, u32)> {
|
||||||
|
self.newsize.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl wayland_window::Handler for DecoratedHandler {
|
||||||
|
fn configure(&mut self,
|
||||||
|
_: &mut EventQueueHandle,
|
||||||
|
_: wl_shell_surface::Resize,
|
||||||
|
width: i32, height: i32)
|
||||||
|
{
|
||||||
|
use std::cmp::max;
|
||||||
|
self.newsize = Some((max(width,1) as u32, max(height,1) as u32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WindowHandler {
|
||||||
|
my_id: usize,
|
||||||
|
resize_callback: Option<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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue