1
1
mirror of https://github.com/wez/wezterm.git synced 2024-08-17 02:00:25 +03:00

Revert SCTK changes

panics on startup under weston with no obvious fix.

This reverts commit 3938d1a7db.
This reverts commit aab3835f1a.
This reverts commit 0c97ace3cb.

refs: https://github.com/wez/wezterm/pull/5044
This commit is contained in:
Wez Furlong 2024-03-25 09:34:48 -07:00
parent 3938d1a7db
commit e5ac32f297
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
11 changed files with 468 additions and 442 deletions

98
Cargo.lock generated
View File

@ -1274,12 +1274,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "cursor-icon"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
[[package]]
name = "d3d12"
version = "0.7.0"
@ -3224,18 +3218,18 @@ dependencies = [
[[package]]
name = "memmap2"
version = "0.8.0"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
dependencies = [
"libc",
]
[[package]]
name = "memmap2"
version = "0.9.4"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
dependencies = [
"libc",
]
@ -4300,6 +4294,15 @@ dependencies = [
"bytemuck",
]
[[package]]
name = "quick-xml"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1"
dependencies = [
"memchr",
]
[[package]]
name = "quick-xml"
version = "0.30.0"
@ -5052,25 +5055,23 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]]
name = "smithay-client-toolkit"
version = "0.18.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a"
checksum = "e1476c3d89bb67079264b88aaf4f14358353318397e083b7c4e8c14517f55de7"
dependencies = [
"bitflags 2.4.2",
"cursor-icon",
"libc",
"bitflags 1.3.2",
"dlib",
"lazy_static",
"log",
"memmap2 0.9.4",
"rustix 0.38.31",
"memmap2 0.5.10",
"nix 0.26.4",
"thiserror",
"wayland-backend",
"wayland-client",
"wayland-csd-frame",
"wayland-cursor",
"wayland-protocols",
"wayland-protocols-wlr",
"wayland-scanner",
"xkeysym",
]
[[package]]
@ -6124,13 +6125,14 @@ checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
[[package]]
name = "wayland-backend"
version = "0.3.3"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40"
checksum = "41b48e27457e8da3b2260ac60d0a94512f5cba36448679f3747c0865b7893ed8"
dependencies = [
"cc",
"downcast-rs",
"rustix 0.38.31",
"io-lifetimes",
"nix 0.26.4",
"scoped-tls",
"smallvec",
"wayland-sys",
@ -6138,43 +6140,32 @@ dependencies = [
[[package]]
name = "wayland-client"
version = "0.31.2"
version = "0.30.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f"
checksum = "489c9654770f674fc7e266b3c579f4053d7551df0ceb392f153adb1f9ed06ac8"
dependencies = [
"bitflags 2.4.2",
"rustix 0.38.31",
"bitflags 1.3.2",
"nix 0.26.4",
"wayland-backend",
"wayland-scanner",
]
[[package]]
name = "wayland-csd-frame"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
dependencies = [
"bitflags 2.4.2",
"cursor-icon",
"wayland-backend",
]
[[package]]
name = "wayland-cursor"
version = "0.31.1"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba"
checksum = "2d0c3a0d5b4b688b07b0442362d3ed6bf04724fcc16cd69ab6285b90dbc487aa"
dependencies = [
"rustix 0.38.31",
"nix 0.26.4",
"wayland-client",
"xcursor",
]
[[package]]
name = "wayland-egl"
version = "0.32.0"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "355f652e5a24ae02d2ad536c8fc2d3dcc6c2bd635027cd6103a193e7d75eeda2"
checksum = "1187695fe81c3153c3163f9d2953149f638c5d7dbc6fe988914ca3f4961e28ed"
dependencies = [
"wayland-backend",
"wayland-sys",
@ -6182,11 +6173,11 @@ dependencies = [
[[package]]
name = "wayland-protocols"
version = "0.31.2"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
checksum = "3b28101e5ca94f70461a6c2d610f76d85ad223d042dd76585ab23d3422dd9b4d"
dependencies = [
"bitflags 2.4.2",
"bitflags 1.3.2",
"wayland-backend",
"wayland-client",
"wayland-scanner",
@ -6194,11 +6185,11 @@ dependencies = [
[[package]]
name = "wayland-protocols-wlr"
version = "0.2.0"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6"
checksum = "fce991093320e4a6a525876e6b629ab24da25f9baef0c2e0080ad173ec89588a"
dependencies = [
"bitflags 2.4.2",
"bitflags 1.3.2",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@ -6207,20 +6198,20 @@ dependencies = [
[[package]]
name = "wayland-scanner"
version = "0.31.1"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283"
checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e"
dependencies = [
"proc-macro2",
"quick-xml 0.31.0",
"quick-xml 0.28.2",
"quote",
]
[[package]]
name = "wayland-sys"
version = "0.31.1"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af"
checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06"
dependencies = [
"dlib",
"log",
@ -6890,7 +6881,6 @@ dependencies = [
"tiny-skia",
"url",
"wayland-client",
"wayland-csd-frame",
"wayland-egl",
"wayland-protocols",
"wezterm-bidi",

View File

@ -15,7 +15,7 @@ k9 = "0.11.0"
gl_generator = "0.14"
[features]
wayland = ["wayland-client", "smithay-client-toolkit", "wayland-egl", "wayland-protocols", "wayland-csd-frame"]
wayland = ["wayland-client", "smithay-client-toolkit", "wayland-egl", "wayland-protocols"]
[dependencies]
async-channel = "1.6"
@ -81,11 +81,10 @@ xcb-imdkit = { version="0.3", git="https://github.com/wez/xcb-imdkit-rs.git", re
zbus = "3.14"
zvariant = "3.15"
smithay-client-toolkit = {version = "0.18.1", default-features=false, optional=true}
wayland-protocols = {version="0.31", optional=true}
wayland-client = {version="0.31", optional=true}
wayland-egl = {version="0.32", optional=true}
wayland-csd-frame = { version = "0.3.0", optional = true}
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}
[target.'cfg(target_os="macos")'.dependencies]
cocoa = "0.25"

View File

@ -58,11 +58,7 @@ impl WaylandConnection {
let mut events = Events::with_capacity(8);
let wl_fd = {
let read_guard = self
.event_queue
.borrow()
.prepare_read()
.ok_or_else(|| anyhow::anyhow!("Failed to preapre event queue"))?;
let read_guard = self.event_queue.borrow().prepare_read()?;
read_guard.connection_fd().as_raw_fd()
};
@ -104,7 +100,7 @@ impl WaylandConnection {
continue;
}
if let Some(guard) = event_q.prepare_read() {
if let Ok(guard) = event_q.prepare_read() {
if let Err(err) = guard.read() {
log::trace!("Event Q error: {:?}", err);
if let WaylandError::Protocol(perr) = err {

View File

@ -1,15 +1,17 @@
use anyhow::{anyhow, bail};
use anyhow::{anyhow, Error, bail};
use filedescriptor::{FileDescriptor, Pipe};
use smithay_client_toolkit as toolkit;
use toolkit::globals::GlobalData;
use wayland_client::{Dispatch, event_created_child};
use wayland_client::globals::{GlobalList, BindError};
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1;
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_v1::{ZwpPrimarySelectionDeviceV1, self, Event as PrimarySelectionDeviceEvent};
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_offer_v1::{ZwpPrimarySelectionOfferV1, Event as PrimarySelectionOfferEvent};
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_source_v1::{ZwpPrimarySelectionSourceV1, Event as PrimarySelectionSourceEvent};
use std::io::Write;
use std::os::fd::AsRawFd;
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
use std::sync::{Arc, Mutex};
use toolkit::data_device_manager::data_offer::SelectionOffer;
use toolkit::data_device_manager::{ReadPipe, WritePipe};
use toolkit::primary_selection::device::PrimarySelectionDeviceHandler;
use toolkit::primary_selection::selection::PrimarySelectionSourceHandler;
use wayland_client::{Connection as WConnection, QueueHandle};
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1;
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1;
use toolkit::reexports::client::protocol::wl_data_offer::WlDataOffer;
use crate::{Clipboard, ConnectionOps};
@ -18,7 +20,7 @@ use super::state::WaylandState;
#[derive(Default)]
pub struct CopyAndPaste {
data_offer: Option<SelectionOffer>,
data_offer: Option<WlDataOffer>,
}
impl std::fmt::Debug for CopyAndPaste {
@ -34,31 +36,37 @@ impl CopyAndPaste {
Arc::new(Mutex::new(Default::default()))
}
pub(super) fn get_clipboard_data(&mut self, clipboard: Clipboard) -> anyhow::Result<ReadPipe> {
pub(super) fn get_clipboard_data(
&mut self,
clipboard: Clipboard,
) -> anyhow::Result<FileDescriptor> {
let conn = crate::Connection::get().unwrap().wayland();
let wayland_state = conn.wayland_state.borrow();
let primary_selection = if let Clipboard::PrimarySelection = clipboard {
wayland_state.primary_selection_device.as_ref()
wayland_state.primary_selection_manager.as_ref()
} else {
None
};
match primary_selection {
Some(primary_selection) => {
let offer = primary_selection
.data()
.selection_offer()
let inner = primary_selection.inner.lock().unwrap();
let offer = inner
.offer
.as_ref()
.ok_or_else(|| anyhow!("no primary selection offer"))?;
let pipe = offer.receive(TEXT_MIME_TYPE.to_string())?;
Ok(pipe)
let pipe = Pipe::new().map_err(Error::msg)?;
offer.receive(TEXT_MIME_TYPE.to_string(), pipe.write.as_raw_fd());
Ok(pipe.read)
}
None => {
let offer = self
.data_offer
.as_ref()
.ok_or_else(|| anyhow!("no data offer"))?;
let pipe = offer.receive(TEXT_MIME_TYPE.to_string())?;
Ok(pipe)
let pipe = Pipe::new().map_err(Error::msg)?;
offer.receive(TEXT_MIME_TYPE.to_string(), pipe.write.as_raw_fd());
Ok(pipe.read)
}
}
}
@ -70,16 +78,18 @@ impl CopyAndPaste {
let last_serial = *wayland_state.last_serial.borrow();
let primary_selection = if let Clipboard::PrimarySelection = clipboard {
wayland_state.primary_selection_device.as_ref()
wayland_state.primary_selection_manager.as_ref()
} else {
None
};
match primary_selection {
Some(selection_device) => {
let manager = wayland_state.primary_selection_manager.as_ref().unwrap();
let source = manager.create_selection_source(&qh, [TEXT_MIME_TYPE]);
source.set_selection(&selection_device, last_serial);
Some(primary_selection) => {
let manager = &primary_selection.manager;
let selection_device = wayland_state.primary_select_device.as_ref().unwrap();
let source = manager.create_source(&qh, PrimarySelectionManagerData::default());
source.offer(TEXT_MIME_TYPE.to_string());
selection_device.set_selection(Some(&source), last_serial);
wayland_state
.primary_selection_source
.replace((source, data));
@ -95,7 +105,7 @@ impl CopyAndPaste {
}
}
pub(super) fn confirm_selection(&mut self, offer: SelectionOffer) {
pub(super) fn confirm_selection(&mut self, offer: WlDataOffer) {
self.data_offer.replace(offer);
}
}
@ -112,17 +122,14 @@ impl WaylandState {
}
}
pub(super) fn write_selection_to_pipe(pipe: WritePipe, text: &str) {
if let Err(e) = write_pipe_with_timeout(pipe, text.as_bytes()) {
pub(super) fn write_selection_to_pipe(fd: FileDescriptor, text: &str) {
if let Err(e) = write_pipe_with_timeout(fd, text.as_bytes()) {
log::error!("while sending primary selection to pipe: {}", e);
}
}
fn write_pipe_with_timeout(mut file: WritePipe, data: &[u8]) -> anyhow::Result<()> {
// Set the file as non-blocking
unsafe {
libc::fcntl(file.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
}
fn write_pipe_with_timeout(mut file: FileDescriptor, data: &[u8]) -> anyhow::Result<()> {
file.set_non_blocking(true)?;
let mut pfd = libc::pollfd {
fd: file.as_raw_fd(),
events: libc::POLLOUT,
@ -150,43 +157,150 @@ fn write_pipe_with_timeout(mut file: WritePipe, data: &[u8]) -> anyhow::Result<(
Ok(())
}
impl PrimarySelectionSourceHandler for WaylandState {
fn send_request(
&mut self,
_conn: &WConnection,
_qh: &QueueHandle<WaylandState>,
source: &ZwpPrimarySelectionSourceV1,
mime_type: String,
write_pipe: WritePipe,
// Smithay has their own primary selection handler in 0.18
// Some code borrowed from https://github.com/Smithay/client-toolkit/commit/4a5c4f59f640bc588a55277261bbed1bd2abea98
pub(super) struct PrimarySelectionManagerState {
pub(super) manager: ZwpPrimarySelectionDeviceManagerV1,
inner: Mutex<PrimaryInner>,
}
#[derive(Default, Debug)]
struct PrimaryInner {
pending_offer: Option<ZwpPrimarySelectionOfferV1>,
offer: Option<ZwpPrimarySelectionOfferV1>,
valid_mime: bool,
}
#[derive(Default)]
pub(super) struct PrimarySelectionManagerData {}
impl PrimarySelectionManagerState {
pub(super) fn bind(
globals: &GlobalList,
queue_handle: &wayland_client::QueueHandle<WaylandState>,
) -> Result<Self, BindError> {
let manager = globals.bind(queue_handle, 1..=1, GlobalData)?;
Ok(Self {
manager,
inner: Mutex::new(PrimaryInner::default()),
})
}
}
impl Dispatch<ZwpPrimarySelectionDeviceManagerV1, GlobalData, WaylandState>
for PrimarySelectionManagerState
{
fn event(
_state: &mut WaylandState,
_proxy: &ZwpPrimarySelectionDeviceManagerV1,
_event: <ZwpPrimarySelectionDeviceManagerV1 as wayland_client::Proxy>::Event,
_data: &GlobalData,
_conn: &wayland_client::Connection,
_qhandle: &wayland_client::QueueHandle<WaylandState>,
) {
if mime_type != TEXT_MIME_TYPE {
return;
}
if let Some((ps_source, data)) = &self.primary_selection_source {
if ps_source.inner() != source {
return;
unreachable!("primary selection manager has no events");
}
}
impl Dispatch<ZwpPrimarySelectionSourceV1, PrimarySelectionManagerData, WaylandState>
for PrimarySelectionManagerState
{
fn event(
state: &mut WaylandState,
source: &ZwpPrimarySelectionSourceV1,
event: <ZwpPrimarySelectionSourceV1 as wayland_client::Proxy>::Event,
_data: &PrimarySelectionManagerData,
_conn: &wayland_client::Connection,
_qhandle: &wayland_client::QueueHandle<WaylandState>,
) {
match event {
PrimarySelectionSourceEvent::Send { mime_type, fd } => {
if mime_type != TEXT_MIME_TYPE {
return;
};
if let Some((ps_source, data)) = &state.primary_selection_source {
if ps_source != source {
return;
}
let fd = unsafe { FileDescriptor::from_raw_fd(fd.into_raw_fd()) };
write_selection_to_pipe(fd, data);
}
}
write_selection_to_pipe(write_pipe, data);
PrimarySelectionSourceEvent::Cancelled => {
state.primary_selection_source.take();
source.destroy();
}
_ => unreachable!(),
}
}
}
fn cancelled(
&mut self,
_conn: &WConnection,
_qh: &QueueHandle<WaylandState>,
source: &ZwpPrimarySelectionSourceV1,
impl Dispatch<ZwpPrimarySelectionOfferV1, PrimarySelectionManagerData, WaylandState>
for PrimarySelectionManagerState
{
fn event(
state: &mut WaylandState,
_proxy: &ZwpPrimarySelectionOfferV1,
event: <ZwpPrimarySelectionOfferV1 as wayland_client::Proxy>::Event,
_data: &PrimarySelectionManagerData,
_conn: &wayland_client::Connection,
_qhandle: &wayland_client::QueueHandle<WaylandState>,
) {
self.primary_selection_source.take();
source.destroy();
match event {
PrimarySelectionOfferEvent::Offer { mime_type } => {
if mime_type == TEXT_MIME_TYPE {
let mgr = state.primary_selection_manager.as_ref().unwrap();
let mut inner = mgr.inner.lock().unwrap();
inner.valid_mime = true;
}
}
_ => unreachable!(),
}
}
}
impl PrimarySelectionDeviceHandler for WaylandState {
fn selection(
&mut self,
_conn: &WConnection,
_qh: &QueueHandle<Self>,
impl Dispatch<ZwpPrimarySelectionDeviceV1, PrimarySelectionManagerData, WaylandState>
for PrimarySelectionManagerState
{
event_created_child!(WaylandState, ZwpPrimarySelectionDeviceV1, [
zwp_primary_selection_device_v1::EVT_DATA_OFFER_OPCODE => (ZwpPrimarySelectionOfferV1, PrimarySelectionManagerData::default())
]);
fn event(
state: &mut WaylandState,
_primary_selection_device: &ZwpPrimarySelectionDeviceV1,
event: <ZwpPrimarySelectionDeviceV1 as wayland_client::Proxy>::Event,
_data: &PrimarySelectionManagerData,
_conn: &wayland_client::Connection,
_qhandle: &wayland_client::QueueHandle<WaylandState>,
) {
let psm = state.primary_selection_manager.as_ref().unwrap();
let mut inner = psm.inner.lock().unwrap();
match event {
PrimarySelectionDeviceEvent::DataOffer { offer } => {
inner.pending_offer = Some(offer);
}
PrimarySelectionDeviceEvent::Selection { id } => {
if !inner.valid_mime {
return;
}
if let Some(offer) = inner.offer.take() {
offer.destroy();
}
if id == inner.pending_offer {
inner.offer = inner.pending_offer.take();
} else {
// Remove the pending offer, assign the new delivered one.
if let Some(offer) = inner.pending_offer.take() {
offer.destroy()
}
inner.offer = id;
}
}
_ => unreachable!(),
}
}
}

View File

@ -1,8 +1,12 @@
use smithay_client_toolkit::data_device_manager::data_device::DataDeviceHandler;
use std::os::fd::{FromRawFd, IntoRawFd};
use filedescriptor::FileDescriptor;
use smithay_client_toolkit::data_device_manager::data_device::{
DataDevice, DataDeviceDataExt, DataDeviceHandler,
};
use smithay_client_toolkit::data_device_manager::data_offer::DataOfferHandler;
use smithay_client_toolkit::data_device_manager::data_source::DataSourceHandler;
use smithay_client_toolkit::data_device_manager::WritePipe;
use wayland_client::protocol::wl_data_device::WlDataDevice;
use wayland_client::protocol::wl_data_device_manager::DndAction;
use wayland_client::Proxy;
@ -22,25 +26,19 @@ impl DataDeviceHandler for WaylandState {
&mut self,
_conn: &wayland_client::Connection,
_qh: &wayland_client::QueueHandle<Self>,
data_device: &WlDataDevice,
data_device: DataDevice,
) {
let data = match self.data_device {
Some(ref dv) if dv.inner() == data_device => dv.data(),
_ => {
log::warn!("No existing device manager for {:?}", data_device);
return;
}
};
let drag_offer = data.drag_offer().unwrap();
let mut drag_offer = data_device.drag_offer().unwrap();
log::trace!(
"Data offer entered: {:?}, mime_types: {:?}",
drag_offer,
drag_offer.with_mime_types(|m| m.iter().cloned().collect::<Vec<_>>())
data_device.drag_mime_types()
);
if let Some(m) =
drag_offer.with_mime_types(|m| m.iter().find(|s| *s == URI_MIME_TYPE).cloned())
if let Some(m) = data_device
.drag_mime_types()
.iter()
.find(|s| *s == URI_MIME_TYPE)
{
drag_offer.accept_mime_type(*self.last_serial.borrow(), Some(m.clone()));
}
@ -56,8 +54,8 @@ impl DataDeviceHandler for WaylandState {
.lock()
.unwrap();
let offer = drag_offer;
let window_id = SurfaceUserData::from_wl(&offer.surface).window_id;
let offer = drag_offer.inner().clone();
let window_id = SurfaceUserData::from_wl(&drag_offer.surface).window_id;
pstate.drag_and_drop.offer = Some(SurfaceAndOffer { window_id, offer });
}
@ -66,7 +64,7 @@ impl DataDeviceHandler for WaylandState {
&mut self,
_conn: &wayland_client::Connection,
_qh: &wayland_client::QueueHandle<Self>,
_data_device: &WlDataDevice,
_data_device: DataDevice,
) {
let pointer = self.pointer.as_mut().unwrap();
let mut pstate = pointer
@ -85,7 +83,7 @@ impl DataDeviceHandler for WaylandState {
&mut self,
_conn: &wayland_client::Connection,
_qh: &wayland_client::QueueHandle<Self>,
_data_device: &WlDataDevice,
_data_device: DataDevice,
) {
}
@ -93,21 +91,19 @@ impl DataDeviceHandler for WaylandState {
&mut self,
_conn: &wayland_client::Connection,
_qh: &wayland_client::QueueHandle<Self>,
data_device: &WlDataDevice,
data_device: DataDevice,
) {
let selection = match self.data_device {
Some(ref dv) if dv.inner() == data_device => dv.data().selection_offer(),
_ => {
return;
}
};
let mime_types = data_device.selection_mime_types();
if !mime_types.iter().any(|s| s == TEXT_MIME_TYPE) {
return;
}
if let Some(offer) = selection {
if !offer.with_mime_types(|m| m.iter().any(|s| *s == TEXT_MIME_TYPE)) {
return;
}
if let Some(offer) = data_device.selection_offer() {
if let Some(copy_and_paste) = self.resolve_copy_and_paste() {
copy_and_paste.lock().unwrap().confirm_selection(offer);
copy_and_paste
.lock()
.unwrap()
.confirm_selection(offer.inner().clone());
}
}
}
@ -116,7 +112,7 @@ impl DataDeviceHandler for WaylandState {
&mut self,
_conn: &wayland_client::Connection,
_qh: &wayland_client::QueueHandle<Self>,
_data_device: &WlDataDevice,
_data_device: DataDevice,
) {
let pointer = self.pointer.as_mut().unwrap();
let mut pstate = pointer
@ -139,6 +135,22 @@ impl DataDeviceHandler for WaylandState {
}
impl DataOfferHandler for WaylandState {
fn offer(
&mut self,
_conn: &wayland_client::Connection,
_qh: &wayland_client::QueueHandle<Self>,
offer: &mut smithay_client_toolkit::data_device_manager::data_offer::DataDeviceOffer,
mime_type: String,
) {
log::trace!("Received offer with mime type: {mime_type}");
if mime_type == TEXT_MIME_TYPE {
offer.accept_mime_type(*self.last_serial.borrow(), Some(mime_type));
} else {
// Refuse other mime types
offer.accept_mime_type(*self.last_serial.borrow(), None);
}
}
// Ignore drag and drop events
fn source_actions(
&mut self,
@ -186,6 +198,7 @@ impl DataSourceHandler for WaylandState {
if cp_source.inner() != source {
return;
}
let fd = unsafe { FileDescriptor::from_raw_fd(fd.into_raw_fd()) };
write_selection_to_pipe(fd, data);
}
}

View File

@ -1,9 +1,10 @@
use crate::wayland::read_pipe_with_timeout;
use crate::ConnectionOps;
use filedescriptor::{FileDescriptor, Pipe};
use smithay_client_toolkit as toolkit;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use toolkit::data_device_manager::data_offer::DragOffer;
use toolkit::data_device_manager::ReadPipe;
use toolkit::reexports::client::protocol::wl_data_offer::WlDataOffer;
use url::Url;
use super::data_device::URI_MIME_TYPE;
@ -16,12 +17,12 @@ pub struct DragAndDrop {
pub(super) struct SurfaceAndOffer {
pub(super) window_id: usize,
pub(super) offer: DragOffer,
pub(super) offer: WlDataOffer,
}
pub(super) struct SurfaceAndPipe {
pub(super) window_id: usize,
pub(super) read: ReadPipe,
pub(super) read: FileDescriptor,
}
impl DragAndDrop {
@ -29,15 +30,16 @@ impl DragAndDrop {
/// returning that surface and pipe descriptor.
pub(super) fn create_pipe_for_drop(&mut self) -> Option<SurfaceAndPipe> {
let SurfaceAndOffer { window_id, offer } = self.offer.take()?;
let read = offer
.receive(URI_MIME_TYPE.to_string())
.map_err(|err| log::error!("Unable to receive data: {:#}", err))
let pipe = Pipe::new()
.map_err(|err| log::error!("Unable to create pipe: {:#}", err))
.ok()?;
offer.receive(URI_MIME_TYPE.to_string(), pipe.write.as_raw_fd());
let read = pipe.read;
offer.finish();
Some(SurfaceAndPipe { window_id, read })
}
pub(super) fn read_paths_from_pipe(read: ReadPipe) -> Option<Vec<PathBuf>> {
pub(super) fn read_paths_from_pipe(read: FileDescriptor) -> Option<Vec<PathBuf>> {
read_pipe_with_timeout(read)
.map_err(|err| {
log::error!("Error while reading pipe from drop result: {:#}", err);

View File

@ -2,8 +2,6 @@
//! in smithay_client_toolkit 0.11 which is Copyright (c) 2018 Victor Berger
//! and provided under the terms of the MIT license.
// TODO: update this for SCTK 0.18 and use this instead of the FallbackFrame
use crate::os::wayland::pointer::make_theme_manager;
use config::{ConfigHandle, RgbaColor, WindowFrameConfig};
use smithay_client_toolkit::output::{add_output_listener, with_output_info, OutputListener};

View File

@ -1,16 +1,15 @@
use std::cell::RefCell;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use smithay_client_toolkit::compositor::SurfaceData;
use smithay_client_toolkit::seat::pointer::{
PointerData, PointerDataExt, PointerEvent, PointerEventKind, PointerHandler,
};
use smithay_client_toolkit::shell::xdg::frame::{DecorationsFrame, FrameClick};
use wayland_client::backend::ObjectId;
use wayland_client::protocol::wl_pointer::{ButtonState, WlPointer};
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::{Connection, Proxy, QueueHandle};
use wayland_csd_frame::{DecorationsFrame, FrameClick};
use wezterm_input_types::MousePress;
use crate::wayland::SurfaceUserData;
@ -219,52 +218,33 @@ impl WaylandState {
let wid = SurfaceUserData::from_wl(parent_surface).window_id;
let mut inner = windows.get(&wid).unwrap().borrow_mut();
if let Some(frame) = inner.decorations.as_mut() {
match evt.kind {
PointerEventKind::Enter { .. } => {
frame.click_point_moved(Duration::ZERO, &evt.surface.id(), x, y);
}
PointerEventKind::Leave { .. } => {
frame.click_point_left();
}
PointerEventKind::Motion { time, .. } => {
frame.click_point_moved(
Duration::from_millis(time as u64),
&evt.surface.id(),
x,
y,
);
}
PointerEventKind::Press {
button,
serial,
time,
..
}
| PointerEventKind::Release {
button,
serial,
time,
..
} => {
let pressed = if matches!(evt.kind, PointerEventKind::Press { .. }) {
true
} else {
false
};
let click = match button {
0x110 => FrameClick::Normal,
0x111 => FrameClick::Alternate,
_ => continue,
};
if let Some(action) =
frame.on_click(Duration::from_millis(time as u64), click, pressed)
{
inner.frame_action(pointer, serial, action);
}
}
_ => {}
match evt.kind {
PointerEventKind::Enter { .. } => {
inner.window_frame.click_point_moved(&evt.surface, x, y);
}
PointerEventKind::Leave { .. } => {
inner.window_frame.click_point_left();
}
PointerEventKind::Motion { .. } => {
inner.window_frame.click_point_moved(&evt.surface, x, y);
}
PointerEventKind::Press { button, serial, .. }
| PointerEventKind::Release { button, serial, .. } => {
let pressed = if matches!(evt.kind, PointerEventKind::Press { .. }) {
true
} else {
false
};
let click = match button {
0x110 => FrameClick::Normal,
0x111 => FrameClick::Alternate,
_ => continue,
};
if let Some(action) = inner.window_frame.on_click(click, pressed) {
inner.frame_action(pointer, serial, action);
}
}
_ => {}
}
}
}

View File

@ -1,9 +1,9 @@
use smithay_client_toolkit::compositor::SurfaceData;
use smithay_client_toolkit::seat::pointer::ThemeSpec;
use smithay_client_toolkit::seat::{Capability, SeatHandler, SeatState};
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::{Connection, QueueHandle};
use crate::wayland::copy_and_paste::PrimarySelectionManagerData;
use crate::wayland::keyboard::KeyboardData;
use crate::wayland::pointer::PointerUserData;
@ -14,7 +14,9 @@ impl SeatHandler for WaylandState {
&mut self.seat
}
fn new_seat(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _seat: WlSeat) {}
fn new_seat(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _seat: WlSeat) {
todo!()
}
fn new_capability(
&mut self,
@ -24,10 +26,7 @@ impl SeatHandler for WaylandState {
capability: smithay_client_toolkit::seat::Capability,
) {
if capability == Capability::Keyboard && self.keyboard.is_none() {
log::trace!(
"Setting keyboard
capability"
);
log::trace!("Setting keyboard capability");
let keyboard = seat.get_keyboard(qh, KeyboardData {});
self.keyboard = Some(keyboard.clone());
@ -37,18 +36,12 @@ impl SeatHandler for WaylandState {
}
if capability == Capability::Pointer && self.pointer.is_none() {
log::trace!(
"Setting
pointer capability"
);
let surface = self.compositor.create_surface(qh);
log::trace!("Setting pointer capability");
let pointer = self
.seat
.get_pointer_with_theme_and_data::<WaylandState, SurfaceData, PointerUserData>(
.get_pointer_with_theme_and_data(
qh,
&seat,
self.shm.wl_shm(),
surface,
ThemeSpec::System,
PointerUserData::new(seat.clone()),
)
@ -59,11 +52,11 @@ impl SeatHandler for WaylandState {
let data_device = data_device_manager.get_data_device(qh, &seat);
self.data_device.replace(data_device);
let primary_select_device = self
.primary_selection_manager
.as_ref()
.map(|m| m.get_selection_device(qh, &seat));
self.primary_selection_device = primary_select_device;
let primary_select_device = self.primary_selection_manager.as_ref().map(|m| {
m.manager
.get_device(&seat, qh, PrimarySelectionManagerData::default())
});
self.primary_select_device = primary_select_device;
}
}
@ -74,9 +67,10 @@ impl SeatHandler for WaylandState {
_seat: WlSeat,
_capability: smithay_client_toolkit::seat::Capability,
) {
// we need to clean up the keyboard and pointer resources we created earlier
todo!()
}
fn remove_seat(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _seat: WlSeat) {}
fn remove_seat(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _seat: WlSeat) {
todo!()
}
}

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use smithay_client_toolkit::compositor::{CompositorState, SurfaceData};
use smithay_client_toolkit::compositor::CompositorState;
use smithay_client_toolkit::data_device_manager::data_device::DataDevice;
use smithay_client_toolkit::data_device_manager::data_source::CopyPasteSource;
use smithay_client_toolkit::data_device_manager::DataDeviceManagerState;
@ -13,9 +13,6 @@ use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::cli
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_manager_v1::ZwlrOutputManagerV1;
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_mode_v1::ZwlrOutputModeV1;
use smithay_client_toolkit::registry::{ProvidesRegistryState, RegistryState};
use smithay_client_toolkit::primary_selection::PrimarySelectionManagerState;
use smithay_client_toolkit::primary_selection::selection::PrimarySelectionSource;
use smithay_client_toolkit::primary_selection::device::PrimarySelectionDevice;
use smithay_client_toolkit::seat::pointer::ThemedPointer;
use smithay_client_toolkit::seat::SeatState;
use smithay_client_toolkit::shell::xdg::XdgShell;
@ -23,18 +20,25 @@ use smithay_client_toolkit::shm::slot::SlotPool;
use smithay_client_toolkit::shm::{Shm, ShmHandler};
use smithay_client_toolkit::subcompositor::SubcompositorState;
use smithay_client_toolkit::{
delegate_compositor, delegate_pointer, delegate_data_device, delegate_primary_selection, delegate_output, delegate_registry, delegate_seat, delegate_shm, delegate_subcompositor, delegate_xdg_shell, delegate_xdg_window, registry_handlers
delegate_compositor, delegate_data_device, delegate_data_device_manager, delegate_data_offer, delegate_data_source, delegate_output, delegate_registry, delegate_seat, delegate_shm, delegate_subcompositor, delegate_xdg_shell, delegate_xdg_window, registry_handlers
};
use wayland_client::backend::ObjectId;
use wayland_client::globals::GlobalList;
use wayland_client::protocol::wl_keyboard::WlKeyboard;
use wayland_client::protocol::wl_output::WlOutput;
use wayland_client::protocol::wl_pointer::WlPointer;
use wayland_client::protocol::wl_surface::WlSurface;
use wayland_client::{delegate_dispatch, Connection, QueueHandle};
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1;
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1;
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1;
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1;
use wayland_protocols::wp::text_input::zv3::client::zwp_text_input_manager_v3::ZwpTextInputManagerV3;
use wayland_protocols::wp::text_input::zv3::client::zwp_text_input_v3::ZwpTextInputV3;
use crate::x11::KeyboardWithFallback;
use super::copy_and_paste::{PrimarySelectionManagerData, PrimarySelectionManagerState};
use super::inputhandler::{TextInputData, TextInputState};
use super::pointer::{PendingMouse, PointerUserData};
use super::{OutputManagerData, OutputManagerState, SurfaceUserData, WaylandWindowInner};
@ -67,8 +71,8 @@ pub(super) struct WaylandState {
pub(super) data_device: Option<DataDevice>,
pub(super) copy_paste_source: Option<(CopyPasteSource, String)>,
pub(super) primary_selection_manager: Option<PrimarySelectionManagerState>,
pub(super) primary_selection_source: Option<(PrimarySelectionSource, String)>,
pub(super) primary_selection_device: Option<PrimarySelectionDevice>,
pub(super) primary_select_device: Option<ZwpPrimarySelectionDeviceV1>,
pub(super) primary_selection_source: Option<(ZwpPrimarySelectionSourceV1, String)>,
pub(super) shm: Shm,
pub(super) mem_pool: RefCell<SlotPool>,
}
@ -109,8 +113,8 @@ impl WaylandState {
data_device: None,
copy_paste_source: None,
primary_selection_manager: PrimarySelectionManagerState::bind(globals, qh).ok(),
primary_select_device: None,
primary_selection_source: None,
primary_selection_device: None,
shm,
mem_pool: RefCell::new(mem_pool),
};
@ -149,20 +153,28 @@ impl OutputHandler for WaylandState {
log::trace!("output destroyed: OutputHandler");
}
}
// Undocumented in sctk 0.17: This is required to use have user data with a surface
// Will be just delegate_compositor!(WaylandState, surface: [SurfaceData, SurfaceUserData]) in 0.18
delegate_dispatch!(WaylandState: [ WlSurface: SurfaceUserData] => CompositorState);
delegate_registry!(WaylandState);
delegate_shm!(WaylandState);
delegate_output!(WaylandState);
delegate_compositor!(WaylandState, surface: [SurfaceData, SurfaceUserData]);
delegate_compositor!(WaylandState);
delegate_subcompositor!(WaylandState);
delegate_seat!(WaylandState);
delegate_data_device_manager!(WaylandState);
delegate_data_device!(WaylandState);
delegate_primary_selection!(WaylandState);
delegate_pointer!(WaylandState, pointer: [PointerUserData]);
delegate_data_source!(WaylandState);
delegate_data_offer!(WaylandState);
// Updating to 0.18 should have this be able to work
// delegate_pointer!(WaylandState, pointer: [PointerUserData]);
delegate_dispatch!(WaylandState: [WlPointer: PointerUserData] => SeatState);
delegate_xdg_shell!(WaylandState);
delegate_xdg_window!(WaylandState);
@ -173,3 +185,8 @@ delegate_dispatch!(WaylandState: [ZwpTextInputV3: TextInputData] => TextInputSta
delegate_dispatch!(WaylandState: [ZwlrOutputManagerV1: GlobalData] => OutputManagerState);
delegate_dispatch!(WaylandState: [ZwlrOutputHeadV1: OutputManagerData] => OutputManagerState);
delegate_dispatch!(WaylandState: [ZwlrOutputModeV1: OutputManagerData] => OutputManagerState);
delegate_dispatch!(WaylandState: [ZwpPrimarySelectionDeviceManagerV1: GlobalData] => PrimarySelectionManagerState);
delegate_dispatch!(WaylandState: [ZwpPrimarySelectionDeviceV1: PrimarySelectionManagerData] => PrimarySelectionManagerState);
delegate_dispatch!(WaylandState: [ZwpPrimarySelectionSourceV1: PrimarySelectionManagerData] => PrimarySelectionManagerState);
delegate_dispatch!(WaylandState: [ZwpPrimarySelectionOfferV1: PrimarySelectionManagerData] => PrimarySelectionManagerState);

View File

@ -1,5 +1,5 @@
use std::any::Any;
use std::cell::RefCell;
use std::cell::{RefCell, RefMut};
use std::cmp::max;
use std::convert::TryInto;
use std::io::Read;
@ -14,18 +14,18 @@ use anyhow::{anyhow, bail};
use async_io::Timer;
use async_trait::async_trait;
use config::ConfigHandle;
use filedescriptor::FileDescriptor;
use promise::{Future, Promise};
use raw_window_handle::{
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
WaylandDisplayHandle, WaylandWindowHandle,
};
use smithay_client_toolkit::compositor::{CompositorHandler, SurfaceData, SurfaceDataExt};
use smithay_client_toolkit::data_device_manager::ReadPipe;
use smithay_client_toolkit::seat::pointer::CursorIcon;
use smithay_client_toolkit::shell::xdg::fallback_frame::FallbackFrame;
use smithay_client_toolkit::shell::xdg::frame::fallback_frame::FallbackFrame;
use smithay_client_toolkit::shell::xdg::frame::{DecorationsFrame, FrameAction};
use smithay_client_toolkit::shell::xdg::window::{
DecorationMode, Window as XdgWindow, WindowConfigure, WindowDecorations as Decorations,
WindowHandler,
WindowHandler, WindowState as SCTKWindowState,
};
use smithay_client_toolkit::shell::xdg::XdgSurface;
use smithay_client_toolkit::shell::WaylandSurface;
@ -34,9 +34,7 @@ use wayland_client::protocol::wl_keyboard::{Event as WlKeyboardEvent, KeyState};
use wayland_client::protocol::wl_pointer::{ButtonState, WlPointer};
use wayland_client::protocol::wl_surface::WlSurface;
use wayland_client::{Connection as WConnection, Proxy};
use wayland_csd_frame::{DecorationsFrame, FrameAction, WindowState as CsdWindowState};
use wayland_egl::{is_available as egl_is_available, WlEglSurface};
use wayland_protocols::xdg::shell::client::xdg_toplevel;
use wezterm_font::FontConfiguration;
use wezterm_input_types::{
KeyboardLedStatus, Modifiers, MouseButtons, MouseEvent, MouseEventKind, MousePress,
@ -195,6 +193,11 @@ impl WaylandWindow {
compositor.create_surface_with_data(&qh, surface_data)
};
let pointer_surface = {
let compositor = &conn.wayland_state.borrow().compositor;
compositor.create_surface(&qh)
};
let ResolvedGeometry {
x: _,
y: _,
@ -208,33 +211,54 @@ impl WaylandWindow {
dpi: config.dpi.unwrap_or(crate::DEFAULT_DPI) as usize,
};
let decorations = config.window_decorations;
let decorations_mode = if decorations == WindowDecorations::NONE {
Decorations::None
} else if decorations == WindowDecorations::default() {
Decorations::ServerDefault
} else {
// SCTK/Wayland don't allow more nuance than "decorations are hidden",
// so if we have a mixture of things, then we need to force our
// client side decoration rendering.
Decorations::RequestClient
};
let window = {
let xdg_shell = &conn.wayland_state.borrow().xdg;
xdg_shell.create_window(surface.clone(), decorations_mode, &qh)
xdg_shell.create_window(surface.clone(), Decorations::RequestServer, &qh)
};
window.set_app_id(class_name.to_string());
window.set_title(name.to_string());
let decorations = config.window_decorations;
let decor_mode = if decorations == WindowDecorations::NONE {
None
} else if decorations == WindowDecorations::default() {
Some(DecorationMode::Server)
} else {
Some(DecorationMode::Client)
};
window.request_decoration_mode(decor_mode);
let mut window_frame = {
let wayland_state = &conn.wayland_state.borrow();
let shm = &wayland_state.shm;
let subcompositor = wayland_state.subcompositor.clone();
FallbackFrame::new(&window, shm, subcompositor, qh.clone())
.expect("failed to create csd frame")
};
let hidden = match decor_mode {
Some(DecorationMode::Client) => false,
_ => true,
};
window_frame.set_hidden(hidden);
if !hidden {
window_frame.resize(
NonZeroU32::new(dimensions.pixel_width as u32)
.ok_or_else(|| anyhow!("dimensions {dimensions:?} are invalid"))?,
NonZeroU32::new(dimensions.pixel_height as u32)
.ok_or_else(|| anyhow!("dimensions {dimensions:?} are invalid"))?,
);
}
window.set_min_size(Some((32, 32)));
window.set_window_geometry(
0,
0,
let (w, h) = window_frame.add_borders(
dimensions.pixel_width as u32,
dimensions.pixel_height as u32,
);
let (x, y) = window_frame.location();
window
.xdg_surface()
.set_window_geometry(x, y, w as i32, h as i32);
window.commit();
let copy_and_paste = CopyAndPaste::create();
@ -251,7 +275,7 @@ impl WaylandWindow {
copy_and_paste,
invalidated: false,
window: Some(window),
decorations: None,
window_frame,
dimensions,
resize_increments: None,
window_state: WindowState::default(),
@ -266,6 +290,7 @@ impl WaylandWindow {
key_repeat: None,
pending_event,
pending_mouse,
pointer_surface,
pending_first_configure: Some(pending_first_configure),
frame_callback: None,
@ -431,6 +456,7 @@ impl WindowOps for WaylandWindow {
pub(crate) struct PendingEvent {
pub(crate) close: bool,
pub(crate) had_configure_event: bool,
refresh_decorations: bool,
// XXX: configure and window_configure could probably be combined, but right now configure only
// queues a new size, so it can be out of sync. Example would be maximizing and minimizing winodw
pub(crate) configure: Option<(u32, u32)>,
@ -439,10 +465,10 @@ pub(crate) struct PendingEvent {
pub(crate) window_state: Option<WindowState>,
}
pub(crate) fn read_pipe_with_timeout(mut file: ReadPipe) -> anyhow::Result<String> {
pub(crate) fn read_pipe_with_timeout(mut file: FileDescriptor) -> anyhow::Result<String> {
let mut result = Vec::new();
unsafe { libc::fcntl(file.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK) };
file.set_non_blocking(true)?;
let mut pfd = libc::pollfd {
fd: file.as_raw_fd(),
events: libc::POLLIN,
@ -475,10 +501,11 @@ pub struct WaylandWindowInner {
surface_factor: f64,
copy_and_paste: Arc<Mutex<CopyAndPaste>>,
window: Option<XdgWindow>,
pub(super) decorations: Option<FallbackFrame<WaylandState>>,
pub(super) window_frame: FallbackFrame<WaylandState>,
dimensions: Dimensions,
resize_increments: Option<ResizeIncrement>,
window_state: WindowState,
pointer_surface: WlSurface,
last_mouse_coords: Point,
mouse_buttons: MouseButtons,
hscroll_remainder: f64,
@ -509,7 +536,6 @@ impl WaylandWindowInner {
fn close(&mut self) {
self.events.dispatch(WindowEvent::Destroyed);
self.window.take();
self.decorations.take();
}
fn show(&mut self) {
@ -522,10 +548,11 @@ impl WaylandWindowInner {
}
fn refresh_frame(&mut self) {
if let Some(frame) = self.decorations.as_mut() {
if frame.is_dirty() && !frame.is_hidden() {
frame.draw();
if let Some(window) = self.window.as_mut() {
if self.window_frame.is_dirty() && !self.window_frame.is_hidden() {
self.window_frame.draw();
}
window.wl_surface().commit();
}
}
@ -708,7 +735,7 @@ impl WaylandWindowInner {
}
}
fn dispatch_pending_event(&mut self) {
pub(crate) fn dispatch_pending_event(&mut self) {
let mut pending;
{
let mut pending_events = self.pending_event.lock().unwrap();
@ -740,49 +767,11 @@ impl WaylandWindowInner {
}
}
let conn = Connection::get().unwrap().wayland();
if let Some(window_config) = pending.window_configure {
if self.window.is_some()
&& window_config.decoration_mode == DecorationMode::Client
&& self.config.window_decorations != WindowDecorations::NONE
{
log::trace!("Client side decoration");
// the server requested client side decoration
// create a frame, if we don't have one already
let title = self.title.as_ref();
let window = self.window.as_ref();
let decorations = self.decorations.get_or_insert_with(|| {
let state = conn.wayland_state.borrow();
let qh = WaylandConnection::get()
.unwrap()
.wayland()
.event_queue
.borrow()
.handle()
.clone();
let mut frame = FallbackFrame::new(
window.unwrap(),
&state.shm,
state.subcompositor.clone(),
qh,
)
.expect("failed to create csd frame.");
if let Some(title) = title {
frame.set_title(title.clone());
}
frame.into()
});
decorations.set_hidden(false);
decorations.update_state(window_config.state);
decorations.update_wm_capabilities(window_config.capabilities);
} else {
if let Some(frame) = self.decorations.as_mut() {
// If we have a frame already, hide it.
frame.set_hidden(true);
}
}
};
if let Some(ref window_config) = pending.window_configure {
self.window_frame.update_state(window_config.state);
self.window_frame
.update_wm_capabilities(window_config.capabilities);
}
if let Some((mut w, mut h)) = pending.configure.take() {
log::trace!("Pending configure: w:{w}, h{h} -- {:?}", self.window);
@ -797,29 +786,11 @@ impl WaylandWindowInner {
// Do this early because this affects surface_to_pixels/pixels_to_surface
self.dimensions.dpi = dpi;
// we need to subtract the decorations before trying to resize
const MIN_PIXELS: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(1) };
if let Some(ref dec) = self.decorations {
if !dec.is_hidden() {
let inner_size = dec.subtract_borders(
NonZeroU32::new(w).unwrap(),
NonZeroU32::new(h).unwrap(),
);
// Clamp the size to at least one pixel.
let inner_width = inner_size.0.unwrap_or(MIN_PIXELS);
let inner_height = inner_size.1.unwrap_or(MIN_PIXELS);
w = inner_width.get();
h = inner_height.get();
}
}
let mut pixel_width = self.surface_to_pixels(w.try_into().unwrap());
let mut pixel_height = self.surface_to_pixels(h.try_into().unwrap());
if self.window_state.can_resize() {
if let Some(ref mut dec) = self.decorations {
dec.set_resizable(true);
}
self.window_frame.set_resizable(true);
if let Some(incr) = self.resize_increments {
let min_width = incr.base_width + incr.x;
let min_height = incr.base_height + incr.y;
@ -830,33 +801,29 @@ impl WaylandWindowInner {
max(pixel_height - extra_height, min_height as i32);
w = self.pixels_to_surface(desired_pixel_width) as u32;
h = self.pixels_to_surface(desired_pixel_height) as u32;
pixel_width = self.surface_to_pixels(w.try_into().unwrap());
pixel_height = self.surface_to_pixels(h.try_into().unwrap());
}
}
let window = self.window.as_ref().unwrap();
match self.decorations.as_mut() {
Some(frame) if !frame.is_hidden() => {
log::trace!("Resizing frame");
frame.resize(w.try_into().unwrap(), h.try_into().unwrap());
let outer_size = frame.add_borders(w, h);
let (x, y) = frame.location();
window.set_window_geometry(
x.try_into().unwrap(),
y.try_into().unwrap(),
outer_size.0,
outer_size.1,
);
}
_ => {
window.set_window_geometry(0, 0, w, h);
}
log::trace!("Resizing frame");
let (width, height) = self.window_frame.subtract_borders(
NonZeroU32::new(pixel_width as u32).unwrap(),
NonZeroU32::new(pixel_height as u32).unwrap(),
);
// Clamp the size to at least one pixel.
let width = width.unwrap_or(NonZeroU32::new(1).unwrap());
let height = height.unwrap_or(NonZeroU32::new(1).unwrap());
if !self.window_frame.is_hidden() {
self.window_frame.resize(width, height);
}
// recompute the pixel dimensions because they may have changed
// due to resizing or decorations
pixel_width = self.surface_to_pixels(w.try_into().unwrap());
pixel_height = self.surface_to_pixels(h.try_into().unwrap());
let (x, y) = self.window_frame.location();
let outer_size = self.window_frame.add_borders(width.get(), height.get());
self.window
.as_mut()
.unwrap()
.xdg_surface()
.set_window_geometry(x, y, outer_size.0 as i32, outer_size.1 as i32);
// Compute the new pixel dimensions
let new_dimensions = Dimensions {
pixel_width: pixel_width.try_into().unwrap(),
@ -892,7 +859,8 @@ impl WaylandWindowInner {
wegl_surface.resize(pixel_width, pixel_height, 0, 0);
}
if self.surface_factor != factor {
let wayland_state = conn.wayland_state.borrow();
let wayland_conn = Connection::get().unwrap().wayland();
let wayland_state = wayland_conn.wayland_state.borrow();
let mut pool = wayland_state.mem_pool.borrow_mut();
// Make a "fake" buffer with the right dimensions, as
@ -914,6 +882,9 @@ impl WaylandWindowInner {
self.do_paint().unwrap();
}
}
if pending.refresh_decorations && self.window.is_some() {
self.refresh_frame();
}
if pending.had_configure_event && self.window.is_some() {
log::debug!("Had configured an event");
if let Some(notify) = self.pending_first_configure.take() {
@ -924,20 +895,27 @@ impl WaylandWindowInner {
}
fn set_cursor(&mut self, cursor: Option<MouseCursor>) {
let icon = cursor.map_or(CursorIcon::Default, |cursor| match cursor {
MouseCursor::Arrow => CursorIcon::Default,
MouseCursor::Hand => CursorIcon::Pointer,
MouseCursor::SizeUpDown => CursorIcon::NsResize,
MouseCursor::SizeLeftRight => CursorIcon::EwResize,
MouseCursor::Text => CursorIcon::Text,
let name = cursor.map_or("none", |cursor| match cursor {
MouseCursor::Arrow => "arrow",
MouseCursor::Hand => "hand",
MouseCursor::SizeUpDown => "ns-resize",
MouseCursor::SizeLeftRight => "ew-resize",
MouseCursor::Text => "xterm",
});
let conn = Connection::get().unwrap().wayland();
let mut state = conn.wayland_state.borrow_mut();
let pointer = state.pointer.as_mut().unwrap();
let state = conn.wayland_state.borrow_mut();
let (shm, pointer) =
RefMut::map_split(state, |s| (&mut s.shm, s.pointer.as_mut().unwrap()));
// Much different API in 0.18
if let Err(err) = pointer.set_cursor(&conn.connection, icon) {
log::error!("set_cursor: (icon={}) {}", icon, err);
if let Err(err) = pointer.set_cursor(
&conn.connection,
name,
shm.wl_shm(),
&self.pointer_surface,
1,
) {
log::error!("set_cursor: {}", err);
}
}
@ -989,9 +967,6 @@ impl WaylandWindowInner {
if let Some(window) = self.window.as_ref() {
window.set_title(title.clone());
}
if let Some(frame) = self.decorations.as_mut() {
frame.set_title(title.clone());
}
self.refresh_frame();
self.title = Some(title);
}
@ -1171,14 +1146,8 @@ impl WaylandWindowInner {
.unwrap()
.show_window_menu(seat, serial, (x, y))
}
FrameAction::Resize(edge) => {
self.window
.as_ref()
.unwrap()
.resize(seat, serial, frame_edge_to_window_edge(edge))
}
FrameAction::Resize(edge) => self.window.as_ref().unwrap().resize(seat, serial, edge),
FrameAction::Move => self.window.as_ref().unwrap().move_(seat, serial),
_ => {} // just ignore unrecognized frame actions
}
}
}
@ -1188,7 +1157,7 @@ impl WaylandState {
self.windows.borrow().get(&window_id).map(Rc::clone)
}
fn handle_window_event(&mut self, window: &XdgWindow, event: WaylandWindowEvent) {
fn handle_window_event(&self, window: &XdgWindow, event: WaylandWindowEvent) {
let surface_data = SurfaceUserData::from_wl(window.wl_surface());
let window_id = surface_data.window_id;
@ -1211,12 +1180,12 @@ impl WaylandState {
}
}
WaylandWindowEvent::Request(configure) => {
pending_event.window_configure.replace(configure.clone());
// TODO: This should the new queue function
// p.queue_configure(&configure)
//
let mut changed;
pending_event.had_configure_event = true;
if let (Some(w), Some(h)) = configure.new_size {
changed = pending_event.configure.is_none();
pending_event.configure.replace((w.get(), h.get()));
@ -1225,14 +1194,14 @@ impl WaylandState {
}
let mut state = WindowState::default();
if configure.state.contains(CsdWindowState::FULLSCREEN) {
if configure.state.contains(SCTKWindowState::FULLSCREEN) {
state |= WindowState::FULL_SCREEN;
}
let fs_bits = CsdWindowState::MAXIMIZED
| CsdWindowState::TILED_LEFT
| CsdWindowState::TILED_RIGHT
| CsdWindowState::TILED_TOP
| CsdWindowState::TILED_BOTTOM;
let fs_bits = SCTKWindowState::MAXIMIZED
| SCTKWindowState::TILED_LEFT
| SCTKWindowState::TILED_RIGHT
| SCTKWindowState::TILED_TOP
| SCTKWindowState::TILED_BOTTOM;
if !((configure.state & fs_bits).is_empty()) {
state |= WindowState::MAXIMIZED;
}
@ -1247,12 +1216,8 @@ impl WaylandState {
if pending_event.window_state.is_none() && state != WindowState::default() {
changed = true;
}
if pending_event.window_configure.is_none() {
changed = true;
}
pending_event.window_state.replace(state);
pending_event.window_configure.replace(configure);
changed
}
};
@ -1267,30 +1232,13 @@ impl WaylandState {
impl CompositorHandler for WaylandState {
fn scale_factor_changed(
&mut self,
_conn: &WConnection,
_qh: &wayland_client::QueueHandle<Self>,
surface: &wayland_client::protocol::wl_surface::WlSurface,
new_factor: i32,
) {
let window_id = SurfaceUserData::from_wl(surface).window_id;
WaylandConnection::with_window_inner(window_id, move |inner| {
if let Some(frame) = inner.decorations.as_mut() {
frame.set_scaling_factor(new_factor as f64);
}
Ok(())
});
// We do nothing, we get the scale_factor from surface_data
}
fn transform_changed(
&mut self,
_conn: &WConnection,
_qh: &wayland_client::QueueHandle<Self>,
_surface: &wayland_client::protocol::wl_surface::WlSurface,
_new_transform: wayland_client::protocol::wl_output::Transform,
_new_factor: i32,
) {
// Nothing to do here
// We do nothing, we get the scale_factor from surface_data
}
fn frame(
@ -1358,7 +1306,7 @@ unsafe impl HasRawWindowHandle for WaylandWindowInner {
fn raw_window_handle(&self) -> RawWindowHandle {
let mut handle = WaylandWindowHandle::empty();
let surface = self.surface();
handle.surface = surface.id().interface().c_ptr.unwrap() as *const _ as *mut _;
handle.surface = surface.id().as_ptr() as *mut _;
RawWindowHandle::Wayland(handle)
}
}
@ -1367,13 +1315,7 @@ unsafe impl HasRawDisplayHandle for WaylandWindow {
fn raw_display_handle(&self) -> RawDisplayHandle {
let mut handle = WaylandDisplayHandle::empty();
let conn = WaylandConnection::get().unwrap().wayland();
handle.display = conn
.connection
.backend()
.display_id()
.interface()
.c_ptr
.unwrap() as *const _ as *mut _;
handle.display = conn.connection.backend().display_ptr() as *mut _;
RawDisplayHandle::Wayland(handle)
}
}
@ -1390,22 +1332,3 @@ unsafe impl HasRawWindowHandle for WaylandWindow {
inner.raw_window_handle()
}
}
fn frame_edge_to_window_edge(
frame_edge: wayland_csd_frame::ResizeEdge,
) -> xdg_toplevel::ResizeEdge {
use wayland_csd_frame::ResizeEdge;
use xdg_toplevel::ResizeEdge as XdgResizeEdge;
match frame_edge {
ResizeEdge::None => XdgResizeEdge::None,
ResizeEdge::Top => XdgResizeEdge::Top,
ResizeEdge::Bottom => XdgResizeEdge::Bottom,
ResizeEdge::Left => XdgResizeEdge::Left,
ResizeEdge::TopLeft => XdgResizeEdge::TopLeft,
ResizeEdge::BottomLeft => XdgResizeEdge::BottomLeft,
ResizeEdge::Right => XdgResizeEdge::Right,
ResizeEdge::TopRight => XdgResizeEdge::TopRight,
ResizeEdge::BottomRight => XdgResizeEdge::BottomRight,
_ => XdgResizeEdge::None,
}
}