Implement stub mutter-x11-interop

Allows xdp-gnome dialogs to work with X11 clients.

Fixes https://github.com/YaLTeR/niri/issues/594
This commit is contained in:
Ivan Molodetskikh 2024-08-13 09:15:57 +03:00
parent 9063a5dbdc
commit 883763c172
8 changed files with 154 additions and 2 deletions

2
Cargo.lock generated
View File

@ -2260,6 +2260,8 @@ dependencies = [
"tracing-subscriber",
"tracy-client",
"url",
"wayland-backend",
"wayland-scanner",
"xcursor",
"xshell",
"zbus",

View File

@ -78,6 +78,8 @@ tracing-subscriber.workspace = true
tracing.workspace = true
tracy-client.workspace = true
url = { version = "2.5.2", optional = true }
wayland-backend = "0.3.6"
wayland-scanner = "0.31.4"
xcursor = "0.3.6"
zbus = { version = "~3.15.2", optional = true }

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="mutter_x11_interop">
<description summary="X11 interoperability helper">
This protocol is intended to be used by the portal backend to map Wayland
dialogs as modal dialogs on top of X11 windows.
</description>
<interface name="mutter_x11_interop" version="1">
<description summary="X11 interoperability helper"/>
<request name="destroy" type="destructor"/>
<request name="set_x11_parent">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="xwindow" type="uint"/>
</request>
</interface>
</protocol>

View File

@ -69,12 +69,13 @@ use crate::protocols::foreign_toplevel::{
self, ForeignToplevelHandler, ForeignToplevelManagerState,
};
use crate::protocols::gamma_control::{GammaControlHandler, GammaControlManagerState};
use crate::protocols::mutter_x11_interop::MutterX11InteropHandler;
use crate::protocols::output_management::{OutputManagementHandler, OutputManagementManagerState};
use crate::protocols::screencopy::{Screencopy, ScreencopyHandler, ScreencopyManagerState};
use crate::utils::{output_size, send_scale_transform};
use crate::{
delegate_foreign_toplevel, delegate_gamma_control, delegate_output_management,
delegate_screencopy,
delegate_foreign_toplevel, delegate_gamma_control, delegate_mutter_x11_interop,
delegate_output_management, delegate_screencopy,
};
impl SeatHandler for State {
@ -580,3 +581,6 @@ impl OutputManagementHandler for State {
}
}
delegate_output_management!(State);
impl MutterX11InteropHandler for State {}
delegate_mutter_x11_interop!(State);

View File

@ -118,6 +118,7 @@ use crate::ipc::server::IpcServer;
use crate::layout::{Layout, LayoutElement as _, MonitorRenderElement};
use crate::protocols::foreign_toplevel::{self, ForeignToplevelManagerState};
use crate::protocols::gamma_control::GammaControlManagerState;
use crate::protocols::mutter_x11_interop::MutterX11InteropManagerState;
use crate::protocols::output_management::OutputManagementManagerState;
use crate::protocols::screencopy::{Screencopy, ScreencopyBuffer, ScreencopyManagerState};
use crate::pw_utils::{Cast, PipeWire};
@ -233,6 +234,7 @@ pub struct Niri {
pub security_context_state: SecurityContextState,
pub gamma_control_manager_state: GammaControlManagerState,
pub activation_state: XdgActivationState,
pub mutter_x11_interop_state: MutterX11InteropManagerState,
pub seat: Seat<State>,
/// Scancodes of the keys to suppress.
@ -1602,6 +1604,8 @@ impl Niri {
is_tty && !client.get_data::<ClientState>().unwrap().restricted
});
let activation_state = XdgActivationState::new::<State>(&display_handle);
let mutter_x11_interop_state =
MutterX11InteropManagerState::new::<State, _>(&display_handle, move |_| true);
let mut seat: Seat<State> = seat_state.new_wl_seat(&display_handle, backend.seat_name());
seat.add_keyboard(
@ -1764,6 +1768,7 @@ impl Niri {
security_context_state,
gamma_control_manager_state,
activation_state,
mutter_x11_interop_state,
seat,
keyboard_focus: KeyboardFocus::Layout { surface: None },

View File

@ -1,4 +1,7 @@
pub mod foreign_toplevel;
pub mod gamma_control;
pub mod mutter_x11_interop;
pub mod output_management;
pub mod screencopy;
pub mod raw;

View File

@ -0,0 +1,93 @@
use mutter_x11_interop::MutterX11Interop;
use smithay::reexports::wayland_server::{
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
};
use super::raw::mutter_x11_interop::v1::server::mutter_x11_interop;
const VERSION: u32 = 1;
pub struct MutterX11InteropManagerState {}
pub struct MutterX11InteropManagerGlobalData {
filter: Box<dyn for<'c> Fn(&'c Client) -> bool + Send + Sync>,
}
pub trait MutterX11InteropHandler {}
impl MutterX11InteropManagerState {
pub fn new<D, F>(display: &DisplayHandle, filter: F) -> Self
where
D: GlobalDispatch<MutterX11Interop, MutterX11InteropManagerGlobalData>,
D: Dispatch<MutterX11Interop, ()>,
D: MutterX11InteropHandler,
D: 'static,
F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static,
{
let global_data = MutterX11InteropManagerGlobalData {
filter: Box::new(filter),
};
display.create_global::<D, MutterX11Interop, _>(VERSION, global_data);
Self {}
}
}
impl<D> GlobalDispatch<MutterX11Interop, MutterX11InteropManagerGlobalData, D>
for MutterX11InteropManagerState
where
D: GlobalDispatch<MutterX11Interop, MutterX11InteropManagerGlobalData>,
D: Dispatch<MutterX11Interop, ()>,
D: MutterX11InteropHandler,
D: 'static,
{
fn bind(
_state: &mut D,
_handle: &DisplayHandle,
_client: &Client,
manager: New<MutterX11Interop>,
_manager_state: &MutterX11InteropManagerGlobalData,
data_init: &mut DataInit<'_, D>,
) {
data_init.init(manager, ());
}
fn can_view(client: Client, global_data: &MutterX11InteropManagerGlobalData) -> bool {
(global_data.filter)(&client)
}
}
impl<D> Dispatch<MutterX11Interop, (), D> for MutterX11InteropManagerState
where
D: Dispatch<MutterX11Interop, ()>,
D: MutterX11InteropHandler,
D: 'static,
{
fn request(
_state: &mut D,
_client: &Client,
_resource: &MutterX11Interop,
request: <MutterX11Interop as Resource>::Request,
_data: &(),
_dhandle: &DisplayHandle,
_data_init: &mut DataInit<'_, D>,
) {
match request {
mutter_x11_interop::Request::Destroy => (),
mutter_x11_interop::Request::SetX11Parent { .. } => (),
}
}
}
#[macro_export]
macro_rules! delegate_mutter_x11_interop {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::protocols::raw::mutter_x11_interop::v1::server::mutter_x11_interop::MutterX11Interop: $crate::protocols::mutter_x11_interop::MutterX11InteropManagerGlobalData
] => $crate::protocols::mutter_x11_interop::MutterX11InteropManagerState);
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::protocols::raw::mutter_x11_interop::v1::server::mutter_x11_interop::MutterX11Interop: ()
] => $crate::protocols::mutter_x11_interop::MutterX11InteropManagerState);
};
}

25
src/protocols/raw.rs Normal file
View File

@ -0,0 +1,25 @@
pub mod mutter_x11_interop {
pub mod v1 {
pub use self::generated::server;
mod generated {
pub mod server {
#![allow(dead_code, non_camel_case_types, unused_unsafe, unused_variables)]
#![allow(non_upper_case_globals, non_snake_case, unused_imports)]
#![allow(missing_docs, clippy::all)]
use smithay::reexports::wayland_server;
use wayland_server::protocol::*;
pub mod __interfaces {
use smithay::reexports::wayland_server;
use wayland_server::protocol::__interfaces::*;
wayland_scanner::generate_interfaces!("resources/mutter-x11-interop.xml");
}
use self::__interfaces::*;
wayland_scanner::generate_server_code!("resources/mutter-x11-interop.xml");
}
}
}
}