1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

upgrade to latest smithay client toolkit

This version greatly improves the client side decoration handling
under Wayland and allows rendering the window title in the titlebar
(shocker!).
This commit is contained in:
Wez Furlong 2020-05-02 15:53:32 -07:00
parent fa32457656
commit d3cb27129c
10 changed files with 433 additions and 332 deletions

180
Cargo.lock generated
View File

@ -15,6 +15,12 @@ dependencies = [
"const-random",
]
[[package]]
name = "ahash"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35b909d1c126f78ace756fc337133356c499eebeefcce930fa5fb018823f2b2d"
[[package]]
name = "aho-corasick"
version = "0.7.10"
@ -317,6 +323,16 @@ version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1"
[[package]]
name = "calloop"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e9e85e9184ff1f5129d751a87500ac57069e28086da57da858b78f0f1530973"
dependencies = [
"log",
"nix",
]
[[package]]
name = "cassowary"
version = "0.3.0"
@ -726,6 +742,15 @@ dependencies = [
"libloading",
]
[[package]]
name = "dlv-list"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b391911b9a786312a10cb9d2b3d0735adfd5a8113eb3648de26a75e91b0826c"
dependencies = [
"rand 0.7.3",
]
[[package]]
name = "downcast-rs"
version = "1.1.1"
@ -1126,10 +1151,20 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead"
dependencies = [
"ahash",
"ahash 0.2.18",
"autocfg 0.1.7",
]
[[package]]
name = "hashbrown"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf"
dependencies = [
"ahash 0.3.3",
"autocfg 1.0.0",
]
[[package]]
name = "hdrhistogram"
version = "6.3.4"
@ -1688,9 +1723,9 @@ dependencies = [
[[package]]
name = "nix"
version = "0.14.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
dependencies = [
"bitflags 1.2.1",
"cc",
@ -1705,6 +1740,12 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nom"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
[[package]]
name = "nom"
version = "4.2.3"
@ -1957,6 +1998,16 @@ dependencies = [
"num-traits 0.2.11",
]
[[package]]
name = "ordered-multimap"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88f947c6799d5eff50e6cf8a2365c17ac4aa8f8f43aceeedc29b616d872a358"
dependencies = [
"dlv-list",
"hashbrown 0.7.2",
]
[[package]]
name = "output_vt100"
version = "0.1.2"
@ -2508,6 +2559,16 @@ dependencies = [
"crossbeam-utils 0.7.2",
]
[[package]]
name = "rust-ini"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c609fa8151080b18c38d39e09d1e55d6301d5610428ff804d0d59c4bac15cf7"
dependencies = [
"cfg-if",
"ordered-multimap",
]
[[package]]
name = "rustc-demangle"
version = "0.1.16"
@ -2558,6 +2619,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
@ -2743,17 +2810,20 @@ checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
[[package]]
name = "smithay-client-toolkit"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "421c8dc7acf5cb205b88160f8b4cc2c5cfabe210e43b2f80f009f4c1ef910f1d"
version = "0.9.1"
source = "git+https://github.com/wez/client-toolkit.git?branch=title_tunc#a178efdd19113228d02ce711602bb9ab78f66084"
dependencies = [
"andrew",
"bitflags 1.2.1",
"byteorder",
"calloop",
"dlib",
"lazy_static",
"log",
"memmap",
"nix",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
]
@ -3374,14 +3444,15 @@ checksum = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad"
[[package]]
name = "wayland-client"
version = "0.23.6"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda"
checksum = "b1d7a5dfc26df8b651cebffeda272b0e444a7485cc83009be2aaffee249d9ea6"
dependencies = [
"bitflags 1.2.1",
"downcast-rs",
"libc",
"nix",
"scoped-tls",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
@ -3389,19 +3460,43 @@ dependencies = [
[[package]]
name = "wayland-commons"
version = "0.23.6"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb"
checksum = "3b0ad6f753185c9ad9c7d6daa588b5c42b2531c58a4ba2f2268f81f1aafb0580"
dependencies = [
"nix",
"once_cell",
"smallvec 1.4.0",
"wayland-sys",
]
[[package]]
name = "wayland-cursor"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b823dded13083b2874710af9a7d258a90d44d8501e2c34bb43568b4cc427f47b"
dependencies = [
"nix",
"wayland-client",
"xcur",
"xcursor",
]
[[package]]
name = "wayland-egl"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73ba50703dbdb6d4b5524b593519547b45b69bf1bb3692c191647325faa50371"
dependencies = [
"wayland-client",
"wayland-sys",
]
[[package]]
name = "wayland-protocols"
version = "0.23.6"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
checksum = "d3458a4a34c37220130cce717aa4e4766a6ee8c19a8db1a565e19dc54d666c68"
dependencies = [
"bitflags 1.2.1",
"wayland-client",
@ -3411,20 +3506,20 @@ dependencies = [
[[package]]
name = "wayland-scanner"
version = "0.23.6"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d"
checksum = "e794b09da468acaeee5f21feb6148ff61a79a6614f6540fe513b060bbb03f1e3"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"proc-macro2 1.0.12",
"quote 1.0.4",
"xml-rs 0.8.3",
]
[[package]]
name = "wayland-sys"
version = "0.23.6"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4"
checksum = "26d91fd1620a38a2815091741e6e75e104d7c135f2239d464d319d63f872d906"
dependencies = [
"dlib",
]
@ -3594,10 +3689,11 @@ dependencies = [
"smithay-client-toolkit",
"thiserror",
"wayland-client",
"wayland-egl",
"winapi 0.3.8",
"winreg",
"x11",
"xcb",
"xcb 0.9.0",
"xcb-util",
"xkbcommon",
]
@ -3659,7 +3755,7 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89bd49c06c9eb5d98e6ba6536cf64ac9f7ee3a009b2f53996d405b3944f6bcea"
dependencies = [
"xcb",
"xcb 0.8.2",
]
[[package]]
@ -3673,13 +3769,41 @@ dependencies = [
]
[[package]]
name = "xcb-util"
version = "0.2.1"
name = "xcb"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d35fc0bbe4349a46322f30a670f61f4da2c2896f64cef53fe54e6c5ec48d8ab"
checksum = "62056f63138b39116f82a540c983cc11f1c90cd70b3d492a70c25eaa50bd22a6"
dependencies = [
"libc",
"xcb",
"log",
]
[[package]]
name = "xcb-util"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43893e47f27bf7d81d489feef3a0e34a457e90bc314b7e74ad9bb3980e4c1c48"
dependencies = [
"libc",
"xcb 0.9.0",
]
[[package]]
name = "xcur"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1879006e82c8f58cf3d1a260434a39c210964e9665fa2f826dc53619201e8b"
dependencies = [
"nom 1.2.4",
]
[[package]]
name = "xcursor"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad3ff3b2f6870f8bf3472cdb4aac8063d8bc2c2ef4d71746e307f5cca592d8a1"
dependencies = [
"rust-ini",
]
[[package]]
@ -3696,12 +3820,12 @@ checksum = "7395cdb9d0a6219fa0ea77d08c946adf9c1984c72fcd443ace30365f3daadef7"
[[package]]
name = "xkbcommon"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce"
version = "0.5.0"
source = "git+https://github.com/wez/xkbcommon-rs.git?rev=01a0a0cd5663405e6e4abb1ad3add9add1496f58#01a0a0cd5663405e6e4abb1ad3add9add1496f58"
dependencies = [
"libc",
"xcb",
"memmap",
"xcb 0.9.0",
]
[[package]]

View File

@ -33,7 +33,7 @@ glium = { version = "0.26.0-alpha3", optional=true, default-features = false}
[features]
async_await = []
opengl = ["cgl", "glium", "gl_generator", "libloading"]
wayland = ["smithay-client-toolkit", "memmap", "wayland-client"]
wayland = ["smithay-client-toolkit", "memmap", "wayland-client", "wayland-egl"]
[target."cfg(windows)".dependencies]
lazy_static = "1.4"
@ -52,16 +52,16 @@ clipboard-win = "2.2"
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
filedescriptor = { version="0.7", path = "../filedescriptor" }
x11 = {version ="2.18", features = ["xlib_xcb"]}
xcb = "0.8"
# See: https://github.com/meh/rust-xcb-util/issues/12
xcb-util = { features = [ "icccm", "ewmh", "keysyms", "shm"], version = "=0.2.1" }
xkbcommon = { version = "0.4", features = ["x11"] }
xcb = {version="0.9", features=["shm", "xkb"]}
xcb-util = { features = [ "icccm", "ewmh", "keysyms", "shm"], version = "0.3" }
xkbcommon = { version = "0.5", features = ["x11", "wayland"], git="https://github.com/wez/xkbcommon-rs.git", rev="01a0a0cd5663405e6e4abb1ad3add9add1496f58"}
mio = "0.6"
mio-extras = "2.0"
libc = "0.2"
smithay-client-toolkit = {version = "0.6", optional = true}
smithay-client-toolkit = {version = "0.9", optional = true, features=["calloop"], git="https://github.com/wez/client-toolkit.git", branch="title_tunc"}
memmap = {version="0.7", optional=true}
wayland-client = {version="0.23", optional=true, features=["egl"]}
wayland-client = {version="0.26", optional=true}
wayland-egl = {version="0.26", optional=true}
[target.'cfg(target_os="macos")'.dependencies]
cocoa = "0.20"

View File

@ -238,7 +238,7 @@ impl GlState {
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
pub fn create_wayland(
display: Option<ffi::EGLNativeDisplayType>,
wegl_surface: &wayland_client::egl::WlEglSurface,
wegl_surface: &wayland_egl::WlEglSurface,
) -> anyhow::Result<Self> {
Self::with_egl_lib(move |egl| {
let egl_display = egl.get_display(display)?;

View File

@ -6,18 +6,19 @@ use crate::connection::ConnectionOps;
use crate::spawn::*;
use crate::timerlist::{TimerEntry, TimerList};
use crate::Connection;
use anyhow::{bail, Context};
use mio::unix::EventedFd;
use mio::{Evented, Events, Poll, PollOpt, Ready, Token};
use anyhow::{anyhow, bail, Context};
use smithay_client_toolkit as toolkit;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize;
use std::time::{Duration, Instant};
use toolkit::reexports::client::protocol::wl_seat::{Event as SeatEvent, WlSeat};
use toolkit::reexports::client::{Display, EventQueue};
use toolkit::Environment;
use toolkit::environment::Environment;
use toolkit::reexports::calloop::{EventLoop, EventSource, Interest, Mode, Poll, Readiness, Token};
use toolkit::reexports::client::Display;
use toolkit::WaylandSource;
toolkit::default_environment!(MyEnvironment, desktop);
pub struct WaylandConnection {
should_terminate: RefCell<bool>,
@ -34,77 +35,55 @@ pub struct WaylandConnection {
// bottom of this list.
pub(crate) pointer: PointerDispatcher,
pub(crate) keyboard: KeyboardDispatcher,
pub(crate) seat: WlSeat,
pub(crate) environment: RefCell<Environment>,
event_q: RefCell<EventQueue>,
pub(crate) environment: RefCell<Environment<MyEnvironment>>,
event_q: RefCell<EventLoop<()>>,
pub(crate) display: RefCell<Display>,
}
impl Evented for WaylandConnection {
fn register(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> std::io::Result<()> {
EventedFd(&self.event_q.borrow().get_connection_fd()).register(poll, token, interest, opts)
}
fn reregister(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> std::io::Result<()> {
EventedFd(&self.event_q.borrow().get_connection_fd())
.reregister(poll, token, interest, opts)
}
fn deregister(&self, poll: &Poll) -> std::io::Result<()> {
EventedFd(&self.event_q.borrow().get_connection_fd()).deregister(poll)
}
}
impl WaylandConnection {
pub fn create_new() -> anyhow::Result<Self> {
let (display, mut event_q) = Display::connect_to_env()?;
let environment = Environment::from_display(&*display, &mut event_q)?;
let (environment, display, event_q) =
toolkit::init_default_environment!(MyEnvironment, desktop)?;
let event_loop = toolkit::reexports::calloop::EventLoop::<()>::new()?;
let seat = environment
.manager
.instantiate_range(1, 6, move |seat| {
seat.implement_closure(
move |event, _seat| {
if let SeatEvent::Name { name } = event {
log::info!("seat name is {}", name);
}
},
(),
let keyboard = KeyboardDispatcher::new();
let mut pointer = None;
for seat in environment.get_all_seats() {
if let Some((has_kbd, has_ptr)) = toolkit::seat::with_seat_data(&seat, |seat_data| {
(
seat_data.has_keyboard && !seat_data.defunct,
seat_data.has_pointer && !seat_data.defunct,
)
})
.context("Failed to create seat")?;
let keyboard = KeyboardDispatcher::register(&seat)?;
}) {
if has_kbd {
keyboard.register(event_loop.handle(), &seat)?;
}
if has_ptr {
pointer.replace(PointerDispatcher::register(
&seat,
environment.require_global(),
environment.require_global(),
environment.require_global(),
)?);
}
}
}
let pointer = PointerDispatcher::register(
&seat,
environment.compositor.clone(),
&environment.shm,
&environment.data_device_manager,
)?;
WaylandSource::new(event_q)
.quick_insert(event_loop.handle())
.map_err(|e| anyhow!("failed to setup WaylandSource: {:?}", e))?;
Ok(Self {
display: RefCell::new(display),
event_q: RefCell::new(event_q),
event_q: RefCell::new(event_loop),
environment: RefCell::new(environment),
should_terminate: RefCell::new(false),
timers: RefCell::new(TimerList::new()),
next_window_id: AtomicUsize::new(1),
windows: RefCell::new(HashMap::new()),
seat,
keyboard,
pointer,
pointer: pointer.unwrap(),
})
}
@ -124,22 +103,6 @@ impl WaylandConnection {
fn do_paint(&self) {}
fn process_queued_events(&self) -> anyhow::Result<()> {
{
let mut event_q = self.event_q.borrow_mut();
if let Some(guard) = event_q.prepare_read() {
if let Err(e) = guard.read_events() {
if e.kind() != ::std::io::ErrorKind::WouldBlock {
bail!("Error while reading events: {}", e);
}
}
}
event_q.dispatch_pending()?;
}
self.flush()?;
Ok(())
}
pub(crate) fn window_by_id(&self, window_id: usize) -> Option<Rc<RefCell<WaylandWindowInner>>> {
self.windows.borrow().get(&window_id).map(Rc::clone)
}
@ -168,6 +131,38 @@ impl WaylandConnection {
}
}
struct SpawnQueueSource {}
impl EventSource for SpawnQueueSource {
type Event = ();
type Metadata = ();
type Ret = ();
fn process_events<F>(
&mut self,
_readiness: Readiness,
_token: Token,
mut callback: F,
) -> std::io::Result<()>
where
F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
{
callback((), &mut ());
Ok(())
}
fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.register(SPAWN_QUEUE.raw_fd(), Interest::Readable, Mode::Level, token)
}
fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.register(SPAWN_QUEUE.raw_fd(), Interest::Readable, Mode::Level, token)
}
fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {
poll.unregister(SPAWN_QUEUE.raw_fd())
}
}
impl ConnectionOps for WaylandConnection {
fn terminate_message_loop(&self) {
*self.should_terminate.borrow_mut() = true;
@ -176,20 +171,16 @@ impl ConnectionOps for WaylandConnection {
fn run_message_loop(&self) -> anyhow::Result<()> {
self.flush()?;
const TOK_WAYLAND: usize = 0xffff_fffc;
const TOK_SPAWN: usize = 0xffff_fffd;
let tok_wayland = Token(TOK_WAYLAND);
let tok_spawn = Token(TOK_SPAWN);
let poll = Poll::new()?;
let mut events = Events::with_capacity(8);
poll.register(self, tok_wayland, Ready::readable(), PollOpt::level())?;
poll.register(
&*SPAWN_QUEUE,
tok_spawn,
Ready::readable(),
PollOpt::level(),
)?;
self.event_q
.borrow_mut()
.handle()
.insert_source(SpawnQueueSource {}, move |_, _, _| {
// In theory, we'd SPAWN_QUEUE.run() here but we
// prefer to defer that to the loop below where we
// can have better control over the event_q borrow,
// and so that we can inspect its return code.
})
.map_err(|e| anyhow!("failed to insert SpawnQueueSource: {:?}", e))?;
let paint_interval = Duration::from_millis(25);
let mut last_interval = Instant::now();
@ -207,13 +198,6 @@ impl ConnectionOps for WaylandConnection {
paint_interval - diff
};
// Process any events that might have accumulated in the local
// buffer (eg: due to a flush) before we potentially go to sleep.
// The locally queued events won't mark the fd as ready, so we
// could potentially sleep when there is work to be done if we
// relied solely on that.
self.process_queued_events()?;
// 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
@ -230,15 +214,16 @@ impl ConnectionOps for WaylandConnection {
.unwrap_or(period)
};
match poll.poll(&mut events, Some(period)) {
Ok(_) => {
// We process both event sources unconditionally
// in the loop above anyway; we're just using
// this to get woken up.
}
self.flush()?;
Err(err) => {
bail!("polling for events: {:?}", err);
{
let mut event_q = self.event_q.borrow_mut();
if let Err(err) = event_q.dispatch(Some(period), &mut ()) {
if err.kind() != std::io::ErrorKind::WouldBlock
&& err.kind() != std::io::ErrorKind::Interrupted
{
return Err(err).context("error during event_q.dispatch");
}
}
}
}

View File

@ -5,6 +5,7 @@ use std::os::unix::io::AsRawFd;
use std::sync::{Arc, Mutex};
use toolkit::reexports::client::protocol::wl_data_offer::{Event as DataOfferEvent, WlDataOffer};
use toolkit::reexports::client::protocol::wl_data_source::WlDataSource;
use wayland_client::Attached;
#[derive(Default)]
pub struct CopyAndPaste {
@ -69,7 +70,7 @@ impl CopyAndPaste {
self.data_offer.replace(offer);
}
pub fn set_selection(&mut self, source: WlDataSource) {
pub fn set_selection(&mut self, source: &Attached<WlDataSource>) {
use crate::connection::ConnectionOps;
crate::Connection::get()
.unwrap()

View File

@ -4,12 +4,13 @@ use anyhow::anyhow;
use smithay_client_toolkit as toolkit;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use toolkit::keyboard::{
map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind, KeyState,
ModifiersState,
use toolkit::reexports::calloop::LoopHandle;
use toolkit::seat::keyboard::{
map_keyboard_repeat, Event as KbEvent, KeyState, ModifiersState, RepeatKind,
};
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::protocol::wl_surface::WlSurface;
use wayland_client::Attached;
#[derive(Default)]
struct Inner {
@ -37,16 +38,6 @@ impl Inner {
}
}
fn handle_repeat(&mut self, rawkey: u32, keysym: u32, utf8: Option<String>) {
self.dispatch_to_window(KeyboardEvent::Key {
serial: 0,
rawkey,
keysym,
is_down: true,
utf8,
});
}
fn dispatch_to_window(&mut self, evt: KeyboardEvent) {
if let Some(window_id) = self.surface_to_window_id.get(&self.active_surface_id) {
let mut evt = Some(evt);
@ -64,31 +55,29 @@ pub struct KeyboardDispatcher {
}
impl KeyboardDispatcher {
pub fn register(seat: &WlSeat) -> anyhow::Result<Self> {
pub fn new() -> Self {
let inner = Arc::new(Mutex::new(Inner::default()));
Self { inner }
}
map_keyboard_auto_with_repeat(
pub fn register(
&self,
loop_handle: LoopHandle<()>,
seat: &Attached<WlSeat>,
) -> anyhow::Result<()> {
let inner = Arc::clone(&self.inner);
let (_kbd, _source) = map_keyboard_repeat(
loop_handle,
&seat,
KeyRepeatKind::System,
{
let inner = Arc::clone(&inner);
move |evt: KbEvent, _| {
inner.lock().unwrap().handle_event(evt);
}
},
{
let inner = Arc::clone(&inner);
move |evt: KeyRepeatEvent, _| {
inner
.lock()
.unwrap()
.handle_repeat(evt.rawkey, evt.keysym, evt.utf8);
}
None,
RepeatKind::System,
move |evt: KbEvent, _, _| {
inner.lock().unwrap().handle_event(evt);
},
)
.map_err(|e| anyhow!("Failed to configure keyboard callback: {:?}", e))?;
Ok(Self { inner })
Ok(())
}
pub fn add_window(&self, window_id: usize, surface: &WlSurface) {
@ -138,10 +127,21 @@ impl KeyboardEvent {
serial,
utf8,
},
KbEvent::Repeat {
rawkey,
keysym,
utf8,
..
} => KeyboardEvent::Key {
rawkey,
keysym,
is_down: true,
serial: 0,
utf8,
},
KbEvent::Modifiers { modifiers } => KeyboardEvent::Modifiers {
modifiers: modifier_keys(modifiers),
},
_ => return None,
})
}
}

View File

@ -1,11 +1,9 @@
use super::copy_and_paste::*;
use crate::input::*;
use crate::os::wayland::connection::WaylandConnection;
use anyhow::anyhow;
use smithay_client_toolkit as toolkit;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use toolkit::pointer::{AutoPointer, AutoThemer};
use toolkit::reexports::client::protocol::wl_data_device::{
Event as DataDeviceEvent, WlDataDevice,
};
@ -14,10 +12,12 @@ use toolkit::reexports::client::protocol::wl_pointer::{
self, Axis, AxisSource, Event as PointerEvent,
};
use toolkit::reexports::client::protocol::wl_surface::WlSurface;
use toolkit::seat::pointer::{ThemeManager, ThemeSpec, ThemedPointer};
use wayland_client::protocol::wl_compositor::WlCompositor;
use wayland_client::protocol::wl_data_device_manager::WlDataDeviceManager;
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::protocol::wl_shm::WlShm;
use wayland_client::{Attached, Main};
#[derive(Default)]
struct Inner {
@ -66,16 +66,13 @@ impl Inner {
fn handle_data_event(&mut self, event: DataDeviceEvent, inner: &Arc<Mutex<Self>>) {
match event {
DataDeviceEvent::DataOffer { id } => {
id.implement_closure(
{
let inner = Arc::clone(inner);
move |event, offer| {
let mut inner = inner.lock().unwrap();
inner.route_data_offer(event, offer);
}
},
(),
);
id.quick_assign({
let inner = Arc::clone(inner);
move |offer, event, _dispatch_data| {
let mut inner = inner.lock().unwrap();
inner.route_data_offer(event, offer.detach());
}
});
}
DataDeviceEvent::Enter { .. }
| DataDeviceEvent::Leave { .. }
@ -96,10 +93,10 @@ impl Inner {
pub struct PointerDispatcher {
inner: Arc<Mutex<Inner>>,
pub(crate) data_device: WlDataDevice,
auto_pointer: AutoPointer,
pub(crate) data_device: Main<WlDataDevice>,
auto_pointer: ThemedPointer,
#[allow(dead_code)]
themer: AutoThemer,
themer: ThemeManager,
}
#[derive(Clone, Debug)]
@ -214,47 +211,29 @@ impl PendingMouse {
impl PointerDispatcher {
pub fn register(
seat: &WlSeat,
compositor: WlCompositor,
shm: &WlShm,
dev_mgr: &WlDataDeviceManager,
compositor: Attached<WlCompositor>,
shm: Attached<WlShm>,
dev_mgr: Attached<WlDataDeviceManager>,
) -> anyhow::Result<Self> {
let inner = Arc::new(Mutex::new(Inner::default()));
let pointer = seat
.get_pointer({
let inner = Arc::clone(&inner);
move |ptr| {
ptr.implement_closure(
{
let inner = Arc::clone(&inner);
move |evt, _| {
inner.lock().unwrap().handle_event(evt);
}
},
(),
)
}
})
.map_err(|()| anyhow!("Failed to configure pointer callback"))?;
let pointer = seat.get_pointer();
pointer.quick_assign({
let inner = Arc::clone(&inner);
move |_, evt, _| {
inner.lock().unwrap().handle_event(evt);
}
});
let themer = AutoThemer::init(None, compositor, shm);
let auto_pointer = themer.theme_pointer(pointer);
let themer = ThemeManager::init(ThemeSpec::System, compositor, shm);
let auto_pointer = themer.theme_pointer(pointer.detach());
let data_device = dev_mgr
.get_data_device(seat, {
let inner = Arc::clone(&inner);
move |device| {
device.implement_closure(
{
let inner = Arc::clone(&inner);
move |event, _device| {
inner.lock().unwrap().handle_data_event(event, &inner);
}
},
(),
)
}
})
.map_err(|()| anyhow!("Failed to configure data_device"))?;
let data_device = dev_mgr.get_data_device(seat);
data_device.quick_assign({
let inner = Arc::clone(&inner);
move |_device, event, _| {
inner.lock().unwrap().handle_data_event(event, &inner);
}
});
Ok(Self {
inner,

View File

@ -22,61 +22,62 @@ use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use toolkit::get_surface_scale_factor;
use toolkit::reexports::client::protocol::wl_data_source::Event as DataSourceEvent;
use toolkit::reexports::client::protocol::wl_surface::WlSurface;
use toolkit::utils::MemPool;
use toolkit::window::Event;
use toolkit::shm::MemPool;
use toolkit::window::{ButtonColorSpec, ColorSpec, ConceptConfig, ConceptFrame, Event};
use wayland_client::protocol::wl_data_device_manager::WlDataDeviceManager;
#[cfg(feature = "opengl")]
use wayland_client::egl::{is_available as egl_is_available, WlEglSurface};
struct MyTheme;
use toolkit::window::ButtonState;
use wayland_egl::{is_available as egl_is_available, WlEglSurface};
const DARK_GRAY: [u8; 4] = [0xff, 0x35, 0x35, 0x35];
const DARK_PURPLE: [u8; 4] = [0xff, 0x2b, 0x20, 0x42];
const PURPLE: [u8; 4] = [0xff, 0x3b, 0x30, 0x52];
const WHITE: [u8; 4] = [0xff, 0xff, 0xff, 0xff];
const GRAY: [u8; 4] = [0x80, 0x80, 0x80, 0x80];
const SILVER: [u8; 4] = [0xcc, 0xcc, 0xcc, 0xcc];
impl toolkit::window::Theme for MyTheme {
fn get_primary_color(&self, active: bool) -> [u8; 4] {
if active {
DARK_PURPLE
} else {
DARK_GRAY
}
}
fn frame_config() -> ConceptConfig {
let icon = ButtonColorSpec {
hovered: ColorSpec::identical(WHITE.into()),
idle: ColorSpec {
active: PURPLE.into(),
inactive: SILVER.into(),
},
disabled: ColorSpec::invisible(),
};
fn get_secondary_color(&self, active: bool) -> [u8; 4] {
self.get_primary_color(active)
}
let close = Some((
icon,
ButtonColorSpec {
hovered: ColorSpec::identical(PURPLE.into()),
idle: ColorSpec {
active: DARK_PURPLE.into(),
inactive: DARK_GRAY.into(),
},
disabled: ColorSpec::invisible(),
},
));
fn get_close_button_color(&self, status: ButtonState) -> [u8; 4] {
match status {
ButtonState::Hovered => PURPLE,
ButtonState::Idle => DARK_PURPLE,
ButtonState::Disabled => DARK_GRAY,
}
}
fn get_maximize_button_color(&self, status: ButtonState) -> [u8; 4] {
self.get_close_button_color(status)
}
fn get_minimize_button_color(&self, status: ButtonState) -> [u8; 4] {
self.get_close_button_color(status)
}
ConceptConfig {
primary_color: ColorSpec {
active: DARK_PURPLE.into(),
inactive: DARK_GRAY.into(),
},
fn get_close_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
match status {
ButtonState::Hovered => WHITE,
ButtonState::Idle => GRAY,
ButtonState::Disabled => DARK_GRAY,
}
}
fn get_maximize_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
self.get_close_button_icon_color(status)
}
fn get_minimize_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
self.get_close_button_icon_color(status)
secondary_color: ColorSpec {
active: DARK_PURPLE.into(),
inactive: DARK_GRAY.into(),
},
close_button: close,
maximize_button: close,
minimize_button: close,
title_font: Some(("sans".into(), 17.0)),
title_color: ColorSpec {
active: WHITE.into(),
inactive: SILVER.into(),
},
}
}
@ -85,7 +86,7 @@ pub struct WaylandWindowInner {
callbacks: Box<dyn WindowCallbacks>,
surface: WlSurface,
copy_and_paste: Arc<Mutex<CopyAndPaste>>,
window: Option<toolkit::window::Window<toolkit::window::ConceptFrame>>,
window: Option<toolkit::window::Window<ConceptFrame>>,
pool: MemPool,
dimensions: Dimensions,
need_paint: bool,
@ -167,21 +168,24 @@ impl WaylandWindow {
let window_id = conn.next_window_id();
let pending_event = Arc::new(Mutex::new(PendingEvent::default()));
let surface = conn.environment.borrow_mut().create_surface({
let pending_event = Arc::clone(&pending_event);
move |dpi, surface| {
pending_event.lock().unwrap().dpi.replace(dpi);
log::debug!(
"surface id={} dpi scale changed to {}",
surface.as_ref().id(),
dpi
);
WaylandConnection::with_window_inner(window_id, move |inner| {
inner.dispatch_pending_event();
Ok(())
});
}
});
let surface = conn
.environment
.borrow_mut()
.create_surface_with_scale_callback({
let pending_event = Arc::clone(&pending_event);
move |dpi, surface, _dispatch_data| {
pending_event.lock().unwrap().dpi.replace(dpi);
log::debug!(
"surface id={} dpi scale changed to {}",
surface.as_ref().id(),
dpi
);
WaylandConnection::with_window_inner(window_id, move |inner| {
inner.dispatch_pending_event();
Ok(())
});
}
});
let dimensions = Dimensions {
pixel_width: width,
@ -189,36 +193,37 @@ impl WaylandWindow {
dpi: 96,
};
let mut window = toolkit::window::Window::<toolkit::window::ConceptFrame>::init_from_env(
&*conn.environment.borrow(),
surface.clone(),
(
dimensions.pixel_width as u32,
dimensions.pixel_height as u32,
),
{
let pending_event = Arc::clone(&pending_event);
move |evt| {
if pending_event.lock().unwrap().queue(evt) {
WaylandConnection::with_window_inner(window_id, move |inner| {
inner.dispatch_pending_event();
Ok(())
});
let mut window = conn
.environment
.borrow()
.create_window::<ConceptFrame, _>(
surface.clone(),
(
dimensions.pixel_width as u32,
dimensions.pixel_height as u32,
),
{
let pending_event = Arc::clone(&pending_event);
move |evt, mut _dispatch_data| {
if pending_event.lock().unwrap().queue(evt) {
WaylandConnection::with_window_inner(window_id, move |inner| {
inner.dispatch_pending_event();
Ok(())
});
}
}
}
},
)
.context("Failed to create window")?;
},
)
.context("Failed to create window")?;
window.set_app_id(class_name.to_string());
window.set_decorate(true);
window.set_resizable(true);
window.set_title(name.to_string());
window.set_theme(MyTheme {});
window.set_frame_config(frame_config());
let pool = MemPool::new(&conn.environment.borrow().shm, || {})?;
let pool = MemPool::new(conn.environment.borrow().require_global(), |_| {})?;
window.new_seat(&conn.seat);
// window.new_seat(&conn.seat);
conn.keyboard.add_window(window_id, &surface);
let copy_and_paste = CopyAndPaste::create();
@ -437,7 +442,7 @@ impl WaylandWindowInner {
if let Some((w, h)) = pending.configure.take() {
if self.window.is_some() {
let factor = toolkit::surface::get_dpi_factor(&self.surface);
let factor = get_surface_scale_factor(&self.surface);
let pixel_width = self.surface_to_pixels(w.try_into().unwrap());
let pixel_height = self.surface_to_pixels(h.try_into().unwrap());
@ -472,6 +477,7 @@ impl WaylandWindowInner {
}
self.refresh_frame();
self.need_paint = true;
self.do_paint().unwrap();
}
}
@ -483,6 +489,7 @@ impl WaylandWindowInner {
fn refresh_frame(&mut self) {
if let Some(window) = self.window.as_mut() {
window.refresh();
self.surface.commit();
}
}
@ -502,7 +509,6 @@ impl WaylandWindowInner {
frame.finish()?;
// self.damage();
self.refresh_frame();
self.surface.commit();
self.need_paint = false;
return Ok(());
}
@ -783,26 +789,22 @@ impl WindowOps for WaylandWindow {
WaylandConnection::with_window_inner(self.0, move |inner| {
let text = text.clone();
let conn = Connection::get().unwrap().wayland();
let source = conn
.environment
.borrow()
.data_device_manager
.create_data_source(move |source| {
source.implement_closure(
move |event, _source| {
if let DataSourceEvent::Send { fd, .. } = event {
let fd = unsafe { FileDescriptor::from_raw_fd(fd) };
if let Err(e) = write_pipe_with_timeout(fd, text.as_bytes()) {
log::error!("while sending paste to pipe: {}", e);
}
}
},
(),
)
})
.map_err(|()| anyhow!("failed to create data source"))?;
.require_global::<WlDataDeviceManager>()
.create_data_source();
source.quick_assign(move |_source, event, _dispatch_data| {
if let DataSourceEvent::Send { fd, .. } = event {
let fd = unsafe { FileDescriptor::from_raw_fd(fd) };
if let Err(e) = write_pipe_with_timeout(fd, text.as_bytes()) {
log::error!("while sending paste to pipe: {}", e);
}
}
});
source.offer(TEXT_MIME_TYPE.to_string());
inner.copy_and_paste.lock().unwrap().set_selection(source);
inner.copy_and_paste.lock().unwrap().set_selection(&source);
Ok(())
})
@ -887,7 +889,13 @@ impl WindowOpsMut for WaylandWindowInner {
}
let conn = Connection::get().unwrap().wayland();
if !conn.environment.borrow().shell.needs_configure() {
if !conn
.environment
.borrow()
.get_shell()
.unwrap()
.needs_configure()
{
self.do_paint().unwrap();
} else {
self.refresh_frame();

View File

@ -51,7 +51,7 @@ impl Keyboard {
device_id,
xkb::KEYMAP_COMPILE_NO_FLAGS,
);
let state = xkb::x11::state_new_from_device(&keymap, &connection, device_id);
let state = xkb::x11::state_new_from_device(&keymap, connection, device_id);
let locale = query_lc_ctype()?;
@ -225,7 +225,7 @@ impl Keyboard {
"problem with new keymap"
);
let new_state = xkb::x11::state_new_from_device(&new_keymap, &connection, self.device_id);
let new_state = xkb::x11::state_new_from_device(&new_keymap, connection, self.device_id);
ensure!(!new_state.get_raw_ptr().is_null(), "problem with new state");
self.state.replace(new_state);

View File

@ -169,6 +169,10 @@ impl SpawnQueue {
self.has_any_queued()
}
pub(crate) fn raw_fd(&self) -> std::os::unix::io::RawFd {
self.read.lock().unwrap().as_raw_fd()
}
}
#[cfg(all(unix, not(target_os = "macos")))]
@ -180,7 +184,7 @@ impl Evented for SpawnQueue {
interest: Ready,
opts: PollOpt,
) -> std::io::Result<()> {
EventedFd(&self.read.lock().unwrap().as_raw_fd()).register(poll, token, interest, opts)
EventedFd(&self.raw_fd()).register(poll, token, interest, opts)
}
fn reregister(
@ -190,11 +194,11 @@ impl Evented for SpawnQueue {
interest: Ready,
opts: PollOpt,
) -> std::io::Result<()> {
EventedFd(&self.read.lock().unwrap().as_raw_fd()).reregister(poll, token, interest, opts)
EventedFd(&self.raw_fd()).reregister(poll, token, interest, opts)
}
fn deregister(&self, poll: &Poll) -> std::io::Result<()> {
EventedFd(&self.read.lock().unwrap().as_raw_fd()).deregister(poll)
EventedFd(&self.raw_fd()).deregister(poll)
}
}