Skip to content

Commit

Permalink
feat: xwayland rootful and rootless (both broken)
Browse files Browse the repository at this point in the history
  • Loading branch information
technobaboo committed Nov 20, 2023
1 parent fe84611 commit 8396228
Show file tree
Hide file tree
Showing 10 changed files with 737 additions and 107 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ path = "src/main.rs"
[features]
default = ["wayland"]
wayland = ["dep:smithay", "dep:xkbcommon"]
xwayland = ["smithay/xwayland"]
xwayland_rootful = []
xwayland_rootless = ["smithay/xwayland"]
profile_tokio = ["dep:console-subscriber", "tokio/tracing"]
profile_app = ["dep:tracing-tracy"]

Expand Down Expand Up @@ -63,6 +64,9 @@ ctrlc = "3.4.1"
libc = "0.2.148"
input-event-codes = "5.16.8"
nix = "0.27.1"
wayland-scanner = "0.31.0"
wayland-backend = "0.3.2"
cluFlock = "1.2.7"

[dependencies.smithay]
# git = "https://github.com/technobaboo/smithay.git" # Until we get stereokit to understand OES samplers and external textures
Expand Down
7 changes: 5 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::objects::input::mouse_pointer::MousePointer;
use crate::objects::input::sk_controller::SkController;
use crate::objects::input::sk_hand::SkHand;
use crate::objects::play_space::PlaySpace;
use crate::wayland::X_DISPLAY;

use self::core::eventloop::EventLoop;
use clap::Parser;
Expand Down Expand Up @@ -235,8 +236,10 @@ fn main() {
if let Some(wayland_socket) = wayland.socket_name.as_ref() {
startup_command.env("WAYLAND_DISPLAY", &wayland_socket);
}
#[cfg(feature = "xwayland")]
startup_command.env("DISPLAY", format!(":{}", wayland.xwayland_state.display));
startup_command.env(
"DISPLAY",
format!(":{}", X_DISPLAY.get().cloned().unwrap_or_default()),
);
startup_command.env("GDK_BACKEND", "wayland");
startup_command.env("QT_QPA_PLATFORM", "wayland");
startup_command.env("MOZ_ENABLE_WAYLAND", "1");
Expand Down
8 changes: 7 additions & 1 deletion src/nodes/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use crate::core::client::Client;
use crate::core::client_state::{ClientState, ClientStateInternal};
use crate::core::registry::Registry;
use crate::core::scenegraph::MethodResponseSender;
#[cfg(feature = "wayland")]
use crate::wayland::WAYLAND_DISPLAY;
#[cfg(feature = "xwayland")]
use crate::wayland::X_DISPLAY;
use crate::STARDUST_INSTANCE;
use color_eyre::eyre::Result;
use glam::Mat4;
Expand Down Expand Up @@ -125,7 +128,10 @@ pub fn get_connection_environment_flex(
{
var_env_insert!(env, WAYLAND_DISPLAY);
#[cfg(feature = "xwayland")]
var_env_insert!(env, DISPLAY);
env.insert(
"DISPLAY".to_string(),
format!(":{}", X_DISPLAY.get().unwrap()),
);
env.insert("GDK_BACKEND".to_string(), "wayland".to_string());
env.insert("QT_QPA_PLATFORM".to_string(), "wayland".to_string());
env.insert("MOZ_ENABLE_WAYLAND".to_string(), "1".to_string());
Expand Down
139 changes: 139 additions & 0 deletions src/wayland/drm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-3.0-only

// Re-export only the actual code, and then only use this re-export
// The `generated` module below is just some boilerplate to properly isolate stuff
// and avoid exposing internal details.
//
// You can use all the types from my_protocol as if they went from `wayland_client::protocol`.
pub use generated::wl_drm;

#[allow(non_upper_case_globals, non_camel_case_types)]
mod generated {
use smithay::reexports::wayland_server::{self, protocol::*};

pub mod __interfaces {
use smithay::reexports::wayland_server::protocol::__interfaces::*;
wayland_scanner::generate_interfaces!("src/wayland/wayland-drm.xml");
}
use self::__interfaces::*;

wayland_scanner::generate_server_code!("src/wayland/wayland-drm.xml");
}

use super::state::WaylandState;
use smithay::{
backend::allocator::{
dmabuf::{Dmabuf, DmabufFlags},
Fourcc, Modifier,
},
reexports::wayland_server::{
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
},
};
use std::convert::TryFrom;

impl GlobalDispatch<wl_drm::WlDrm, (), WaylandState> for WaylandState {
fn bind(
state: &mut WaylandState,
_dh: &DisplayHandle,
_client: &Client,
resource: New<wl_drm::WlDrm>,
_global_data: &(),
data_init: &mut DataInit<'_, WaylandState>,
) {
let drm_instance = data_init.init(resource, ());

drm_instance.device("/dev/dri/renderD128".to_string());
if drm_instance.version() >= 2 {
drm_instance.capabilities(wl_drm::Capability::Prime as u32);
}
for format in state.drm_formats.iter() {
if let Ok(converted) = wl_drm::Format::try_from(*format as u32) {
drm_instance.format(converted as u32);
}
}
}

fn can_view(_client: Client, _global_dataa: &()) -> bool {
true
}
}

impl Dispatch<wl_drm::WlDrm, (), WaylandState> for WaylandState {
fn request(
state: &mut WaylandState,
_client: &Client,
drm: &wl_drm::WlDrm,
request: wl_drm::Request,
_data: &(),
_dh: &DisplayHandle,
data_init: &mut DataInit<'_, WaylandState>,
) {
match request {
wl_drm::Request::Authenticate { .. } => drm.authenticated(),
wl_drm::Request::CreateBuffer { .. } => drm.post_error(
wl_drm::Error::InvalidName,
String::from("Flink handles are unsupported, use PRIME"),
),
wl_drm::Request::CreatePlanarBuffer { .. } => drm.post_error(
wl_drm::Error::InvalidName,
String::from("Flink handles are unsupported, use PRIME"),
),
wl_drm::Request::CreatePrimeBuffer {
id,
name,
width,
height,
format,
offset0,
stride0,
..
} => {
let format = match Fourcc::try_from(format) {
Ok(format) => {
if !state.drm_formats.contains(&format) {
drm.post_error(
wl_drm::Error::InvalidFormat,
String::from("Format not advertised by wl_drm"),
);
return;
}
format
}
Err(_) => {
drm.post_error(
wl_drm::Error::InvalidFormat,
String::from("Format unknown / not advertised by wl_drm"),
);
return;
}
};

if width < 1 || height < 1 {
drm.post_error(
wl_drm::Error::InvalidFormat,
String::from("width or height not positive"),
);
return;
}

let mut dma = Dmabuf::builder((width, height), format, DmabufFlags::empty());
dma.add_plane(name, 0, offset0 as u32, stride0 as u32, Modifier::Invalid);
match dma.build() {
Some(dmabuf) => {
state.dmabuf_tx.send((dmabuf.clone(), None)).unwrap();
data_init.init(id, dmabuf);
}
None => {
// Buffer import failed. The protocol documentation heavily implies killing the
// client is the right thing to do here.
drm.post_error(
wl_drm::Error::InvalidName,
"dmabuf global was destroyed on server",
);
}
}
}
}
}
}
37 changes: 28 additions & 9 deletions src/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@ mod seat;
mod state;
mod surface;
// mod xdg_activation;
mod drm;
mod xdg_shell;
#[cfg(feature = "xwayland")]
pub mod xwayland;
#[cfg(feature = "xwayland_rootful")]
pub mod xwayland_rootful;
#[cfg(feature = "xwayland_rootful")]
use self::xwayland_rootful::X11Lock;
#[cfg(feature = "xwayland_rootful")]
use crate::wayland::xwayland_rootful::start_xwayland;
#[cfg(feature = "xwayland_rootless")]
pub mod xwayland_rootless;
#[cfg(feature = "xwayland_rootless")]
use self::xwayland_rootless::XWaylandState;

use self::{state::WaylandState, surface::CORE_SURFACES};
use crate::wayland::seat::SeatData;
Expand Down Expand Up @@ -40,6 +49,7 @@ use tokio::{
};
use tracing::{debug_span, info, instrument};

pub static X_DISPLAY: OnceCell<u32> = OnceCell::new();
pub static WAYLAND_DISPLAY: OnceCell<String> = OnceCell::new();
pub static SERIAL_COUNTER: CounterU32 = CounterU32::new(0);

Expand Down Expand Up @@ -87,10 +97,12 @@ pub struct Wayland {
pub socket_name: Option<String>,
join_handle: JoinHandle<Result<()>>,
renderer: GlesRenderer,
dmabuf_rx: UnboundedReceiver<(Dmabuf, dmabuf::ImportNotifier)>,
dmabuf_rx: UnboundedReceiver<(Dmabuf, Option<dmabuf::ImportNotifier>)>,
wayland_state: Arc<Mutex<WaylandState>>,
#[cfg(feature = "xwayland")]
pub xwayland_state: xwayland::XWaylandState,
#[cfg(feature = "xwayland_rootful")]
pub x_lock: X11Lock,
#[cfg(feature = "xwayland_rootless")]
pub xwayland_state: XWaylandState,
}
impl Wayland {
pub fn new() -> Result<Self> {
Expand All @@ -108,8 +120,9 @@ impl Wayland {

let (dmabuf_tx, dmabuf_rx) = mpsc::unbounded_channel();
let display = Arc::new(DisplayWrapper(Mutex::new(display), display_handle.clone()));
#[cfg(feature = "xwayland")]
let xwayland_state = xwayland::XWaylandState::create(&display_handle)?;

#[cfg(feature = "xwayland_rootless")]
let xwayland_state = XWaylandState::create(&display_handle)?;
let wayland_state = WaylandState::new(display_handle, &renderer, dmabuf_tx);

let socket = ListeningSocket::bind_auto("wayland", 0..33)?;
Expand All @@ -120,6 +133,8 @@ impl Wayland {
if let Some(socket_name) = &socket_name {
let _ = WAYLAND_DISPLAY.set(socket_name.clone());
}
#[cfg(feature = "xwayland_rootful")]
let x_display = start_xwayland(socket.as_raw_fd())?;
info!(socket_name, "Wayland active");

let join_handle = Wayland::start_loop(display.clone(), socket, wayland_state.clone())?;
Expand All @@ -131,7 +146,9 @@ impl Wayland {
renderer,
dmabuf_rx,
wayland_state,
#[cfg(feature = "xwayland")]
#[cfg(feature = "xwayland_rootful")]
x_lock: x_display,
#[cfg(feature = "xwayland_rootless")]
xwayland_state,
})
}
Expand Down Expand Up @@ -183,7 +200,9 @@ impl Wayland {
pub fn update(&mut self, sk: &impl StereoKitDraw) {
while let Ok((dmabuf, notifier)) = self.dmabuf_rx.try_recv() {
if self.renderer.import_dmabuf(&dmabuf, None).is_err() {
notifier.failed();
if let Some(notifier) = notifier {
notifier.failed();
}
}
}
for core_surface in CORE_SURFACES.get_valid_contents() {
Expand Down
23 changes: 15 additions & 8 deletions src/wayland/state.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use crate::wayland::seat::SeatData;
use super::DisplayWrapper;
use crate::wayland::{drm::wl_drm::WlDrm, seat::SeatData};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use smithay::{
backend::{allocator::dmabuf::Dmabuf, egl::EGLDevice, renderer::gles::GlesRenderer},
backend::{
allocator::{dmabuf::Dmabuf, Fourcc},
egl::EGLDevice,
renderer::gles::GlesRenderer,
},
delegate_dmabuf, delegate_output, delegate_shm,
output::{Mode, Output, Scale, Subpixel},
reexports::{
Expand Down Expand Up @@ -32,8 +37,6 @@ use std::sync::{Arc, Weak};
use tokio::sync::mpsc::UnboundedSender;
use tracing::{info, warn};

use super::DisplayWrapper;

pub struct ClientState {
pub id: OnceCell<ClientId>,
pub compositor_state: CompositorClientState,
Expand Down Expand Up @@ -71,15 +74,16 @@ pub struct WaylandState {
pub kde_decoration_state: KdeDecorationState,
pub shm_state: ShmState,
dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
dmabuf_tx: UnboundedSender<(Dmabuf, dmabuf::ImportNotifier)>,
pub drm_formats: Vec<Fourcc>,
pub dmabuf_tx: UnboundedSender<(Dmabuf, Option<dmabuf::ImportNotifier>)>,
pub output: Output,
}

impl WaylandState {
pub fn new(
display_handle: DisplayHandle,
renderer: &GlesRenderer,
dmabuf_tx: UnboundedSender<(Dmabuf, dmabuf::ImportNotifier)>,
dmabuf_tx: UnboundedSender<(Dmabuf, Option<dmabuf::ImportNotifier>)>,
) -> Arc<Mutex<Self>> {
let compositor_state = CompositorState::new::<Self>(&display_handle);
// let xdg_activation_state = XdgActivationState::new::<Self, _>(&display_handle);
Expand All @@ -88,13 +92,14 @@ impl WaylandState {
let shm_state = ShmState::new::<Self>(&display_handle, vec![]);
let render_node = EGLDevice::device_for_display(renderer.egl_context().display())
.and_then(|device| device.try_get_render_node());

let dmabuf_formats = renderer
.egl_context()
.dmabuf_render_formats()
.iter()
.cloned()
.collect::<Vec<_>>();
let drm_formats = dmabuf_formats.iter().map(|f| f.code).collect();

let dmabuf_default_feedback = match render_node {
Ok(Some(node)) => DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats.clone())
.build()
Expand Down Expand Up @@ -148,6 +153,7 @@ impl WaylandState {
display_handle.create_global::<Self, WlDataDeviceManager, _>(3, ());
display_handle.create_global::<Self, XdgWmBase, _>(5, ());
display_handle.create_global::<Self, ZxdgDecorationManagerV1, _>(1, ());
display_handle.create_global::<Self, WlDrm, _>(2, ());

info!("Init Wayland compositor");

Expand All @@ -160,6 +166,7 @@ impl WaylandState {
// xdg_activation_state,
kde_decoration_state,
shm_state,
drm_formats,
dmabuf_state,
dmabuf_tx,
output,
Expand Down Expand Up @@ -191,7 +198,7 @@ impl DmabufHandler for WaylandState {
dmabuf: Dmabuf,
notifier: dmabuf::ImportNotifier,
) {
self.dmabuf_tx.send((dmabuf, notifier)).unwrap();
self.dmabuf_tx.send((dmabuf, Some(notifier))).unwrap();
}
}
delegate_dmabuf!(WaylandState);
Expand Down
Loading

0 comments on commit 8396228

Please sign in to comment.