mirror of
https://github.com/wez/wezterm.git
synced 2024-08-17 10:10:23 +03:00
Nuke Wayland
This commit is contained in:
parent
9df250f1d2
commit
3eaba4e3d6
104
Cargo.lock
generated
104
Cargo.lock
generated
@ -3520,18 +3520,6 @@ dependencies = [
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.25.1"
|
||||
@ -5039,20 +5027,23 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
version = "0.16.1"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9"
|
||||
checksum = "e1476c3d89bb67079264b88aaf4f14358353318397e083b7c4e8c14517f55de7"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memmap2 0.5.10",
|
||||
"nix 0.24.3",
|
||||
"pkg-config",
|
||||
"nix 0.26.4",
|
||||
"thiserror",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
"wayland-protocols-wlr",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6092,84 +6083,97 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.29.5"
|
||||
name = "wayland-backend"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715"
|
||||
checksum = "41b48e27457e8da3b2260ac60d0a94512f5cba36448679f3747c0865b7893ed8"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cc",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix 0.24.3",
|
||||
"io-lifetimes",
|
||||
"nix 0.26.4",
|
||||
"scoped-tls",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-commons"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
|
||||
dependencies = [
|
||||
"nix 0.24.3",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.29.5"
|
||||
name = "wayland-client"
|
||||
version = "0.30.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
|
||||
checksum = "489c9654770f674fc7e266b3c579f4053d7551df0ceb392f153adb1f9ed06ac8"
|
||||
dependencies = [
|
||||
"nix 0.24.3",
|
||||
"bitflags 1.3.2",
|
||||
"nix 0.26.4",
|
||||
"wayland-backend",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d0c3a0d5b4b688b07b0442362d3ed6bf04724fcc16cd69ab6285b90dbc487aa"
|
||||
dependencies = [
|
||||
"nix 0.26.4",
|
||||
"wayland-client",
|
||||
"xcursor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-egl"
|
||||
version = "0.29.5"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "402de949f81a012926d821a2d659f930694257e76dd92b6e0042ceb27be4107d"
|
||||
checksum = "1187695fe81c3153c3163f9d2953149f638c5d7dbc6fe988914ca3f4961e28ed"
|
||||
dependencies = [
|
||||
"wayland-client",
|
||||
"wayland-backend",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.29.5"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
|
||||
checksum = "3b28101e5ca94f70461a6c2d610f76d85ad223d042dd76585ab23d3422dd9b4d"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols-wlr"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fce991093320e4a6a525876e6b629ab24da25f9baef0c2e0080ad173ec89588a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-protocols",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.29.5"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
|
||||
checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quick-xml 0.28.2",
|
||||
"quote",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.29.5"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4"
|
||||
checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"log",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
|
@ -70,20 +70,22 @@ winreg = "0.10"
|
||||
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
|
||||
dirs-next = "2.0"
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
futures-util = "0.3"
|
||||
futures-lite = "1.12"
|
||||
x11 = {version ="2.21", features = ["xlib_xcb", "xlib"]}
|
||||
xcb = {version="1.3", features=["render", "randr", "dri2", "xkb", "xlib_xcb", "present", "as-raw-xcb-connection"]}
|
||||
xkbcommon = { version = "0.7.0", features = ["x11", "wayland"] }
|
||||
mio = {version="0.8", features=["os-ext"]}
|
||||
libc = "0.2"
|
||||
smithay-client-toolkit = {version = "0.16.1", default-features=false, optional=true}
|
||||
wayland-protocols = {version="0.29", optional=true}
|
||||
wayland-client = {version="0.29", optional=true}
|
||||
wayland-egl = {version="0.29", optional=true}
|
||||
xcb-imdkit = { version="0.3", git="https://github.com/wez/xcb-imdkit-rs.git", rev="215ce4b08ac9c4822e541efd4f4ffb1062806051"}
|
||||
zbus = "3.14"
|
||||
zvariant = "3.15"
|
||||
futures-util = "0.3"
|
||||
futures-lite = "1.12"
|
||||
|
||||
smithay-client-toolkit = {version = "0.17.0", default-features=false, optional=true}
|
||||
wayland-protocols = {version="0.30", optional=true}
|
||||
wayland-client = {version="0.30", optional=true}
|
||||
wayland-egl = {version="0.30", optional=true}
|
||||
xcb-imdkit = { version="0.2", git="https://github.com/wez/xcb-imdkit-rs.git", branch="hangfix"}
|
||||
|
||||
[target.'cfg(target_os="macos")'.dependencies]
|
||||
cocoa = "0.25"
|
||||
|
@ -1,552 +1 @@
|
||||
#![allow(dead_code)]
|
||||
use super::pointer::*;
|
||||
use super::window::*;
|
||||
use crate::connection::ConnectionOps;
|
||||
use crate::os::wayland::inputhandler::InputHandler;
|
||||
use crate::os::wayland::output::OutputHandler;
|
||||
use crate::os::x11::keyboard::KeyboardWithFallback;
|
||||
use crate::screen::{ScreenInfo, Screens};
|
||||
use crate::spawn::*;
|
||||
use crate::{Appearance, Connection, ScreenRect, WindowEvent};
|
||||
use anyhow::{bail, Context};
|
||||
use mio::unix::SourceFd;
|
||||
use mio::{Events, Interest, Poll, Token};
|
||||
use smithay_client_toolkit as toolkit;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Read;
|
||||
use std::os::unix::fs::FileExt;
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use toolkit::environment::Environment;
|
||||
use toolkit::reexports::client::Display;
|
||||
use toolkit::seat::SeatListener;
|
||||
use toolkit::shm::AutoMemPool;
|
||||
use wayland_client::protocol::wl_keyboard::{Event as WlKeyboardEvent, KeymapFormat, WlKeyboard};
|
||||
use wayland_client::{EventQueue, Main};
|
||||
|
||||
toolkit::default_environment!(MyEnvironment, desktop,
|
||||
fields=[
|
||||
output_handler: OutputHandler,
|
||||
input_handler: InputHandler,
|
||||
],
|
||||
singles=[
|
||||
wayland_protocols::wlr::unstable::output_management::v1::client::zwlr_output_manager_v1::ZwlrOutputManagerV1 => output_handler,
|
||||
wayland_protocols::unstable::text_input::v3::client::zwp_text_input_manager_v3::ZwpTextInputManagerV3 => input_handler,
|
||||
]);
|
||||
|
||||
impl MyEnvironment {
|
||||
pub fn input_handler(&mut self) -> &mut InputHandler {
|
||||
&mut self.input_handler
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WaylandConnection {
|
||||
should_terminate: RefCell<bool>,
|
||||
pub(crate) next_window_id: AtomicUsize,
|
||||
pub(crate) windows: RefCell<HashMap<usize, Rc<RefCell<WaylandWindowInner>>>>,
|
||||
|
||||
// Take care with the destruction order: the underlying wayland
|
||||
// libraries are not safe and require destruction in reverse
|
||||
// creation order. This list of fields must reflect that otherwise
|
||||
// we'll segfault on shutdown.
|
||||
// Rust guarantees that struct fields are dropped in the order
|
||||
// they appear in the struct, so the Display must be at the
|
||||
// bottom of this list, and opengl, which depends on everything
|
||||
// must be ahead of the rest.
|
||||
pub(crate) gl_connection: RefCell<Option<Rc<crate::egl::GlConnection>>>,
|
||||
pub(crate) pointer: RefCell<PointerDispatcher>,
|
||||
pub(crate) keyboard_mapper: RefCell<Option<KeyboardWithFallback>>,
|
||||
pub(crate) keyboard_window_id: RefCell<Option<usize>>,
|
||||
pub(crate) surface_to_window_id: RefCell<HashMap<u32, usize>>,
|
||||
pub(crate) active_surface_id: RefCell<u32>,
|
||||
|
||||
/// Repeats per second
|
||||
pub(crate) key_repeat_rate: RefCell<i32>,
|
||||
|
||||
pub(crate) mem_pool: RefCell<AutoMemPool>,
|
||||
|
||||
/// Delay before repeating, in milliseconds
|
||||
pub(crate) key_repeat_delay: RefCell<i32>,
|
||||
pub(crate) last_serial: RefCell<u32>,
|
||||
seat_listener: SeatListener,
|
||||
pub(crate) environment: Environment<MyEnvironment>,
|
||||
event_q: RefCell<EventQueue>,
|
||||
pub(crate) display: RefCell<Display>,
|
||||
}
|
||||
|
||||
impl Drop for WaylandConnection {
|
||||
fn drop(&mut self) {
|
||||
self.environment
|
||||
.with_inner(|env| env.input_handler.shutdown());
|
||||
}
|
||||
}
|
||||
|
||||
impl WaylandConnection {
|
||||
pub fn create_new() -> anyhow::Result<Self> {
|
||||
let (environment, display, event_q) = toolkit::new_default_environment!(
|
||||
MyEnvironment,
|
||||
desktop,
|
||||
fields = [
|
||||
output_handler: OutputHandler::new(),
|
||||
input_handler: InputHandler::new(),
|
||||
]
|
||||
)?;
|
||||
|
||||
let mut pointer = None;
|
||||
let mut seat_keyboards = HashMap::new();
|
||||
|
||||
for seat in environment.get_all_seats() {
|
||||
if let Some((has_kbd, has_ptr, name)) =
|
||||
toolkit::seat::with_seat_data(&seat, |seat_data| {
|
||||
(
|
||||
seat_data.has_keyboard && !seat_data.defunct,
|
||||
seat_data.has_pointer && !seat_data.defunct,
|
||||
seat_data.name.clone(),
|
||||
)
|
||||
})
|
||||
{
|
||||
if has_kbd {
|
||||
let keyboard = seat.get_keyboard();
|
||||
keyboard.quick_assign(|keyboard, event, _| {
|
||||
let conn = Connection::get().unwrap().wayland();
|
||||
if let Err(err) = conn.keyboard_event(keyboard, event) {
|
||||
log::error!("keyboard_event: {:#}", err);
|
||||
}
|
||||
});
|
||||
environment.with_inner(|env| env.input_handler.advise_seat(&seat, &keyboard));
|
||||
seat_keyboards.insert(name, keyboard);
|
||||
}
|
||||
if has_ptr {
|
||||
pointer.replace(PointerDispatcher::register(
|
||||
&seat,
|
||||
environment.require_global(),
|
||||
environment.require_global(),
|
||||
environment.require_global(),
|
||||
environment.get_primary_selection_manager(),
|
||||
)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
let pointer =
|
||||
pointer.ok_or_else(|| anyhow::anyhow!("no seats have an available pointer"))?;
|
||||
|
||||
let seat_listener;
|
||||
{
|
||||
let env = environment.clone();
|
||||
seat_listener = environment.listen_for_seats(move |seat, seat_data, _| {
|
||||
if seat_data.has_keyboard {
|
||||
if !seat_data.defunct {
|
||||
// We only want to assign a new keyboard object if we don't already have
|
||||
// one for this seat. When a seat is being created or updated, the listener
|
||||
// can receive the same seat multiple times: for example, when switching
|
||||
// back from another virtual console, the same seat is usually seen four
|
||||
// times with different data flags:
|
||||
//
|
||||
// has_pointer: true; has_keyboard: false
|
||||
// has_pointer: false; has_keyboard: false
|
||||
// has_pointer: false; has_keyboard: true
|
||||
// has_pointer: true; has_keyboard: true
|
||||
//
|
||||
// This is essentially telling the client to re-assign its keyboard and
|
||||
// pointer, but that means that this listener will fire twice with
|
||||
// has_keyboard set to true. If we assign a handler both times, then we end
|
||||
// up handling key events twice.
|
||||
if !seat_keyboards.contains_key(&seat_data.name) {
|
||||
let keyboard = seat.get_keyboard();
|
||||
|
||||
keyboard.quick_assign(|keyboard, event, _| {
|
||||
let conn = Connection::get().unwrap().wayland();
|
||||
if let Err(err) = conn.keyboard_event(keyboard, event) {
|
||||
log::error!("keyboard_event: {:#}", err);
|
||||
}
|
||||
});
|
||||
env.with_inner(|env| env.input_handler.advise_seat(&seat, &keyboard));
|
||||
seat_keyboards.insert(seat_data.name.clone(), keyboard);
|
||||
}
|
||||
} else {
|
||||
env.with_inner(|env| env.input_handler.seat_defunct(&seat));
|
||||
}
|
||||
} else {
|
||||
// If we previously had a keyboard object on this seat, it's no longer valid if
|
||||
// has_keyboard is false, so we remove the keyboard object we knew about and
|
||||
// thereby ensure that we assign a new keyboard object next time the listener
|
||||
// fires for this seat with has_keyboard = true.
|
||||
seat_keyboards.remove(&seat_data.name);
|
||||
}
|
||||
if seat_data.has_pointer && !seat_data.defunct {
|
||||
let conn = Connection::get().unwrap().wayland();
|
||||
conn.pointer.borrow_mut().seat_changed(&seat);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let mem_pool = environment.create_auto_pool()?;
|
||||
|
||||
Ok(Self {
|
||||
display: RefCell::new(display),
|
||||
environment,
|
||||
should_terminate: RefCell::new(false),
|
||||
next_window_id: AtomicUsize::new(1),
|
||||
windows: RefCell::new(HashMap::new()),
|
||||
event_q: RefCell::new(event_q),
|
||||
pointer: RefCell::new(pointer),
|
||||
seat_listener,
|
||||
mem_pool: RefCell::new(mem_pool),
|
||||
gl_connection: RefCell::new(None),
|
||||
keyboard_mapper: RefCell::new(None),
|
||||
key_repeat_rate: RefCell::new(25),
|
||||
key_repeat_delay: RefCell::new(400),
|
||||
keyboard_window_id: RefCell::new(None),
|
||||
last_serial: RefCell::new(0),
|
||||
surface_to_window_id: RefCell::new(HashMap::new()),
|
||||
active_surface_id: RefCell::new(0),
|
||||
})
|
||||
}
|
||||
|
||||
fn keyboard_event(
|
||||
&self,
|
||||
keyboard: Main<WlKeyboard>,
|
||||
event: WlKeyboardEvent,
|
||||
) -> anyhow::Result<()> {
|
||||
match &event {
|
||||
WlKeyboardEvent::Enter {
|
||||
serial, surface, ..
|
||||
} => {
|
||||
// update global active surface id
|
||||
*self.active_surface_id.borrow_mut() = surface.as_ref().id();
|
||||
|
||||
*self.last_serial.borrow_mut() = *serial;
|
||||
if let Some(&window_id) = self
|
||||
.surface_to_window_id
|
||||
.borrow()
|
||||
.get(&surface.as_ref().id())
|
||||
{
|
||||
self.keyboard_window_id.borrow_mut().replace(window_id);
|
||||
self.environment.with_inner(|env| {
|
||||
if let Some(input) =
|
||||
env.input_handler.get_text_input_for_keyboard(&keyboard)
|
||||
{
|
||||
input.enable();
|
||||
input.commit();
|
||||
}
|
||||
env.input_handler.advise_surface(&surface, &keyboard);
|
||||
});
|
||||
} else {
|
||||
log::warn!("{:?}, no known surface", event);
|
||||
}
|
||||
}
|
||||
WlKeyboardEvent::Leave { serial, .. } => {
|
||||
if let Some(input) = self
|
||||
.environment
|
||||
.with_inner(|env| env.input_handler.get_text_input_for_keyboard(&keyboard))
|
||||
{
|
||||
input.disable();
|
||||
input.commit();
|
||||
}
|
||||
*self.last_serial.borrow_mut() = *serial;
|
||||
}
|
||||
WlKeyboardEvent::Key { serial, .. } | WlKeyboardEvent::Modifiers { serial, .. } => {
|
||||
*self.last_serial.borrow_mut() = *serial;
|
||||
}
|
||||
WlKeyboardEvent::RepeatInfo { rate, delay } => {
|
||||
*self.key_repeat_rate.borrow_mut() = *rate;
|
||||
*self.key_repeat_delay.borrow_mut() = *delay;
|
||||
}
|
||||
WlKeyboardEvent::Keymap { format, fd, size } => {
|
||||
let mut file = unsafe { std::fs::File::from_raw_fd(*fd) };
|
||||
match format {
|
||||
KeymapFormat::XkbV1 => {
|
||||
let mut data = vec![0u8; *size as usize];
|
||||
// If we weren't passed a pipe, be sure to explicitly
|
||||
// read from the start of the file
|
||||
match file.read_exact_at(&mut data, 0) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
// ideally: we check for:
|
||||
// err.kind() == std::io::ErrorKind::NotSeekable
|
||||
// but that is not yet in stable rust
|
||||
if err.raw_os_error() == Some(libc::ESPIPE) {
|
||||
// It's a pipe, which cannot be seeked, so we
|
||||
// just try reading from the current pipe position
|
||||
file.read(&mut data).context("read from Keymap fd/pipe")?;
|
||||
} else {
|
||||
return Err(err).context("read_exact_at from Keymap fd");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Dance around CString panicing on the NUL terminator
|
||||
// in the xkbcommon crate
|
||||
while let Some(0) = data.last() {
|
||||
data.pop();
|
||||
}
|
||||
let s = String::from_utf8(data)?;
|
||||
match KeyboardWithFallback::new_from_string(s) {
|
||||
Ok(k) => {
|
||||
self.keyboard_mapper.replace(Some(k));
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Error processing keymap change: {:#}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(&window_id) = self.keyboard_window_id.borrow().as_ref() {
|
||||
if let Some(win) = self.window_by_id(window_id) {
|
||||
let mut inner = win.borrow_mut();
|
||||
inner.keyboard_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_to_focused_window(&self, event: WindowEvent) {
|
||||
if let Some(&window_id) = self.keyboard_window_id.borrow().as_ref() {
|
||||
if let Some(win) = self.window_by_id(window_id) {
|
||||
let mut inner = win.borrow_mut();
|
||||
inner.events.dispatch(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn next_window_id(&self) -> usize {
|
||||
self.next_window_id
|
||||
.fetch_add(1, ::std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn flush(&self) -> anyhow::Result<()> {
|
||||
if let Err(e) = self.display.borrow_mut().flush() {
|
||||
if e.kind() != ::std::io::ErrorKind::WouldBlock {
|
||||
bail!("Error while flushing display: {}", e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn window_by_id(&self, window_id: usize) -> Option<Rc<RefCell<WaylandWindowInner>>> {
|
||||
self.windows.borrow().get(&window_id).map(Rc::clone)
|
||||
}
|
||||
|
||||
pub(crate) fn with_window_inner<
|
||||
R,
|
||||
F: FnOnce(&mut WaylandWindowInner) -> anyhow::Result<R> + Send + 'static,
|
||||
>(
|
||||
window: usize,
|
||||
f: F,
|
||||
) -> promise::Future<R>
|
||||
where
|
||||
R: Send + 'static,
|
||||
{
|
||||
let mut prom = promise::Promise::new();
|
||||
let future = prom.get_future().unwrap();
|
||||
|
||||
promise::spawn::spawn_into_main_thread(async move {
|
||||
if let Some(handle) = Connection::get().unwrap().wayland().window_by_id(window) {
|
||||
let mut inner = handle.borrow_mut();
|
||||
prom.result(f(&mut inner));
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
future
|
||||
}
|
||||
|
||||
fn run_message_loop_impl(&self) -> anyhow::Result<()> {
|
||||
const TOK_WL: usize = 0xffff_fffc;
|
||||
const TOK_SPAWN: usize = 0xffff_fffd;
|
||||
let tok_wl = Token(TOK_WL);
|
||||
let tok_spawn = Token(TOK_SPAWN);
|
||||
|
||||
let mut poll = Poll::new()?;
|
||||
let mut events = Events::with_capacity(8);
|
||||
poll.registry().register(
|
||||
&mut SourceFd(&self.display.borrow().get_connection_fd()),
|
||||
tok_wl,
|
||||
Interest::READABLE,
|
||||
)?;
|
||||
poll.registry().register(
|
||||
&mut SourceFd(&SPAWN_QUEUE.raw_fd()),
|
||||
tok_spawn,
|
||||
Interest::READABLE,
|
||||
)?;
|
||||
|
||||
while !*self.should_terminate.borrow() {
|
||||
// Check the spawn queue before we try to sleep; there may
|
||||
// be work pending and we don't guarantee that there is a
|
||||
// 1:1 wakeup to queued function, so we need to be assertive
|
||||
// in order to avoid missing wakeups
|
||||
let timeout = if SPAWN_QUEUE.run() {
|
||||
// if we processed one, we don't want to sleep because
|
||||
// there may be others to deal with
|
||||
Some(std::time::Duration::from_secs(0))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
{
|
||||
let mut event_q = self.event_q.borrow_mut();
|
||||
if let Err(err) = event_q.dispatch_pending(&mut (), |_, _, _| {}) {
|
||||
return Err(err).with_context(|| {
|
||||
format!(
|
||||
"error during event_q.dispatch protocol_error={:?}",
|
||||
self.display.borrow().protocol_error()
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.flush()?;
|
||||
if let Err(err) = poll.poll(&mut events, timeout) {
|
||||
if err.kind() == std::io::ErrorKind::Interrupted {
|
||||
continue;
|
||||
}
|
||||
bail!("polling for events: {:?}", err);
|
||||
}
|
||||
|
||||
for event in &events {
|
||||
if event.token() == tok_wl {
|
||||
let event_q = self.event_q.borrow();
|
||||
if let Some(guard) = event_q.prepare_read() {
|
||||
if let Err(err) = guard.read_events() {
|
||||
if err.kind() != std::io::ErrorKind::WouldBlock
|
||||
&& err.kind() != std::io::ErrorKind::Interrupted
|
||||
{
|
||||
return Err(err).with_context(|| {
|
||||
format!(
|
||||
"error during event_q.read_events protocol_error={:?}",
|
||||
self.display.borrow().protocol_error()
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn advise_of_appearance_change(&self, appearance: crate::Appearance) {
|
||||
for win in self.windows.borrow().values() {
|
||||
win.borrow_mut().appearance_changed(appearance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectionOps for WaylandConnection {
|
||||
fn name(&self) -> String {
|
||||
"Wayland".to_string()
|
||||
}
|
||||
|
||||
fn terminate_message_loop(&self) {
|
||||
*self.should_terminate.borrow_mut() = true;
|
||||
}
|
||||
|
||||
fn get_appearance(&self) -> Appearance {
|
||||
match promise::spawn::block_on(crate::os::xdg_desktop_portal::get_appearance()) {
|
||||
Ok(Some(appearance)) => return appearance,
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
log::debug!("Unable to resolve appearance using xdg-desktop-portal: {err:#}");
|
||||
}
|
||||
}
|
||||
// fallback
|
||||
Appearance::Light
|
||||
}
|
||||
|
||||
fn run_message_loop(&self) -> anyhow::Result<()> {
|
||||
let res = self.run_message_loop_impl();
|
||||
// Ensure that we drop these eagerly, to avoid
|
||||
// noisy errors wrt. global destructors unwinding
|
||||
// in unexpected places
|
||||
self.windows.borrow_mut().clear();
|
||||
res
|
||||
}
|
||||
|
||||
fn screens(&self) -> anyhow::Result<Screens> {
|
||||
if let Some(screens) = self
|
||||
.environment
|
||||
.with_inner(|env| env.output_handler.screens())
|
||||
{
|
||||
return Ok(screens);
|
||||
}
|
||||
|
||||
let mut by_name = HashMap::new();
|
||||
let mut virtual_rect: ScreenRect = euclid::rect(0, 0, 0, 0);
|
||||
let config = config::configuration();
|
||||
for output in self.environment.get_all_outputs() {
|
||||
toolkit::output::with_output_info(&output, |info| {
|
||||
let name = if info.name.is_empty() {
|
||||
format!("{} {}", info.model, info.make)
|
||||
} else {
|
||||
info.name.clone()
|
||||
};
|
||||
|
||||
let (width, height) = info
|
||||
.modes
|
||||
.iter()
|
||||
.find(|mode| mode.is_current)
|
||||
.map(|mode| mode.dimensions)
|
||||
.unwrap_or((info.physical_size.0, info.physical_size.1));
|
||||
|
||||
let rect = euclid::rect(
|
||||
info.location.0 as isize,
|
||||
info.location.1 as isize,
|
||||
width as isize,
|
||||
height as isize,
|
||||
);
|
||||
|
||||
let scale = info.scale_factor as f64;
|
||||
|
||||
// FIXME: teach this how to resolve dpi_by_screen once
|
||||
// dispatch_pending_event knows how to do the same
|
||||
let effective_dpi = Some(config.dpi.unwrap_or(scale * crate::DEFAULT_DPI));
|
||||
|
||||
virtual_rect = virtual_rect.union(&rect);
|
||||
by_name.insert(
|
||||
name.clone(),
|
||||
ScreenInfo {
|
||||
name,
|
||||
rect,
|
||||
scale,
|
||||
max_fps: None,
|
||||
effective_dpi,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// The main screen is the one either at the origin of
|
||||
// the virtual area, or if that doesn't exist for some weird
|
||||
// reason, the screen closest to the origin.
|
||||
let main = by_name
|
||||
.values()
|
||||
.min_by_key(|screen| {
|
||||
screen
|
||||
.rect
|
||||
.origin
|
||||
.to_f32()
|
||||
.distance_to(euclid::Point2D::origin())
|
||||
.abs() as isize
|
||||
})
|
||||
.ok_or_else(|| anyhow::anyhow!("no screens were found"))?
|
||||
.clone();
|
||||
|
||||
// We don't yet know how to determine the active screen,
|
||||
// so assume the main screen.
|
||||
let active = main.clone();
|
||||
|
||||
Ok(Screens {
|
||||
main,
|
||||
active,
|
||||
by_name,
|
||||
virtual_rect,
|
||||
})
|
||||
}
|
||||
}
|
||||
pub struct WaylandConnection {}
|
||||
|
@ -1,26 +1,27 @@
|
||||
#![cfg(all(unix, not(target_os = "macos")))]
|
||||
|
||||
pub mod connection;
|
||||
pub mod inputhandler;
|
||||
pub mod output;
|
||||
pub mod window;
|
||||
pub use self::window::*;
|
||||
// pub mod inputhandler;
|
||||
// pub mod output;
|
||||
// pub mod window;
|
||||
// pub use self::window::*;
|
||||
pub use connection::*;
|
||||
pub use output::*;
|
||||
mod copy_and_paste;
|
||||
mod drag_and_drop;
|
||||
mod frame;
|
||||
mod pointer;
|
||||
// pub use output::*;
|
||||
// mod copy_and_paste;
|
||||
// mod drag_and_drop;
|
||||
// mod frame;
|
||||
// mod pointer;
|
||||
|
||||
/// Returns the id of a wayland proxy object, suitable for using
|
||||
/// a key into hash maps
|
||||
pub fn wl_id<I, T>(obj: T) -> u32
|
||||
where
|
||||
I: wayland_client::Interface,
|
||||
T: AsRef<wayland_client::Proxy<I>>,
|
||||
I: AsRef<wayland_client::Proxy<I>>,
|
||||
I: From<wayland_client::Proxy<I>>,
|
||||
{
|
||||
let proxy: &wayland_client::Proxy<I> = obj.as_ref();
|
||||
proxy.id()
|
||||
}
|
||||
pub fn todo() {}
|
||||
// pub fn wl_id<I, T>(obj: T) -> u32
|
||||
// where
|
||||
// I: wayland_client::Interface,
|
||||
// T: AsRef<wayland_client::Proxy<I>>,
|
||||
// I: AsRef<wayland_client::Proxy<I>>,
|
||||
// I: From<wayland_client::Proxy<I>>,
|
||||
// {
|
||||
// let proxy: &wayland_client::Proxy<I> = obj.as_ref();
|
||||
// proxy.id()
|
||||
// }
|
||||
|
Loading…
Reference in New Issue
Block a user