wayland server fixes

This commit is contained in:
galister
2026-01-10 16:21:43 +09:00
parent ef6da380c4
commit 782bd0dc47
2 changed files with 141 additions and 27 deletions

View File

@@ -3,33 +3,43 @@ use smithay::backend::allocator::dmabuf::Dmabuf;
use smithay::backend::renderer::{BufferType, buffer_type};
use smithay::desktop::{PopupKind, PopupManager};
use smithay::input::{Seat, SeatHandler, SeatState};
use smithay::reexports::rustix::fs::{OFlags, fcntl_setfl};
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel;
use smithay::reexports::wayland_server;
use smithay::reexports::wayland_server::Resource;
use smithay::reexports::wayland_server::protocol::{wl_buffer, wl_output, wl_seat};
use smithay::reexports::wayland_server::{self, DisplayHandle};
use smithay::wayland::buffer::BufferHandler;
use smithay::wayland::dmabuf::{
DmabufFeedback, DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier, get_dmabuf,
};
use smithay::wayland::fractional_scale::with_fractional_scale;
use smithay::wayland::output::OutputHandler;
use smithay::wayland::selection::{
ext_data_control as selection_ext,
primary_selection::{PrimarySelectionHandler, PrimarySelectionState, set_primary_focus},
wlr_data_control as selection_wlr,
};
use smithay::wayland::shm::{ShmHandler, ShmState, with_buffer_contents};
use smithay::wayland::single_pixel_buffer::get_single_pixel_buffer;
use smithay::{
delegate_compositor, delegate_data_device, delegate_dmabuf, delegate_output, delegate_seat,
delegate_shm, delegate_xdg_shell,
delegate_compositor, delegate_data_control, delegate_data_device, delegate_dmabuf,
delegate_ext_data_control, delegate_output, delegate_primary_selection, delegate_seat,
delegate_shm, delegate_single_pixel_buffer, delegate_xdg_shell,
};
use std::collections::HashSet;
use std::fs::File;
use std::io::Write;
use std::os::fd::OwnedFd;
use std::sync::{Arc, Mutex};
use smithay::utils::Serial;
use smithay::wayland::compositor::{self, BufferAssignment, SurfaceAttributes, send_surface_state};
use smithay::wayland::selection::SelectionHandler;
use smithay::wayland::selection::data_device::{
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
set_data_device_focus,
};
use smithay::wayland::selection::{self, SelectionHandler};
use smithay::wayland::shell::xdg::{
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
};
@@ -51,9 +61,13 @@ pub struct Application {
pub seat_state: SeatState<Application>,
pub shm: ShmState,
pub data_device: DataDeviceState,
pub primary_selection_state: PrimarySelectionState,
pub ext_data_control_state: selection_ext::DataControlState,
pub wlr_data_control_state: selection_wlr::DataControlState,
pub wayvr_tasks: SyncEventQueue<WayVRTask>,
pub redraw_requests: HashSet<wayland_server::backend::ObjectId>,
pub popup_manager: PopupManager,
pub display_handle: DisplayHandle,
}
impl Application {
@@ -205,7 +219,13 @@ impl SeatHandler for Application {
&mut self.seat_state
}
fn focus_changed(&mut self, _seat: &Seat<Self>, _focused: Option<&WlSurface>) {}
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) {
let dh = &self.display_handle;
let client = focused.and_then(|s| dh.get_client(s.id()).ok());
set_data_device_focus(dh, seat, client.clone());
set_primary_focus(dh, seat, client);
}
fn cursor_image(
&mut self,
_seat: &Seat<Self>,
@@ -231,7 +251,35 @@ impl DataDeviceHandler for Application {
}
impl SelectionHandler for Application {
type SelectionUserData = ();
type SelectionUserData = Arc<[u8]>;
fn send_selection(
&mut self,
_ty: selection::SelectionTarget,
_mime_type: String,
fd: OwnedFd,
_seat: Seat<Self>,
user_data: &Self::SelectionUserData,
) {
let buf = user_data.clone();
std::thread::spawn(move || {
// Clear O_NONBLOCK, otherwise File::write_all() will stop halfway.
if let Err(err) = fcntl_setfl(&fd, OFlags::empty()) {
log::warn!("error clearing flags on selection target fd: {err:?}");
}
if let Err(err) = File::from(fd).write_all(&buf) {
log::warn!("error writing selection: {err:?}");
}
});
}
fn new_selection(
&mut self,
_ty: selection::SelectionTarget,
_source: Option<selection::SelectionSource>,
_seat: Seat<Self>,
) {
}
}
#[derive(Default)]
@@ -371,6 +419,24 @@ impl DmabufHandler for Application {
}
}
impl PrimarySelectionHandler for Application {
fn primary_selection_state(&self) -> &PrimarySelectionState {
&self.primary_selection_state
}
}
impl selection_wlr::DataControlHandler for Application {
fn data_control_state(&self) -> &selection_wlr::DataControlState {
&self.wlr_data_control_state
}
}
impl selection_ext::DataControlHandler for Application {
fn data_control_state(&self) -> &selection_ext::DataControlState {
&self.ext_data_control_state
}
}
delegate_dmabuf!(Application);
delegate_xdg_shell!(Application);
delegate_compositor!(Application);
@@ -378,6 +444,10 @@ delegate_shm!(Application);
delegate_seat!(Application);
delegate_data_device!(Application);
delegate_output!(Application);
delegate_primary_selection!(Application);
delegate_data_control!(Application);
delegate_ext_data_control!(Application);
delegate_single_pixel_buffer!(Application);
const fn wl_transform_to_frame_transform(
transform: wl_output::Transform,

View File

@@ -15,11 +15,15 @@ use smithay::{
input::{SeatState, keyboard::XkbConfig},
output::{Mode, Output},
reexports::wayland_server::{self, backend::ClientId},
utils::{Logical, Size},
wayland::{
compositor::{self, SurfaceData, with_states},
dmabuf::{DmabufFeedbackBuilder, DmabufState},
selection::data_device::DataDeviceState,
shell::xdg::{ToplevelSurface, XdgShellState, XdgToplevelSurfaceData},
selection::{
data_device::DataDeviceState, ext_data_control as selection_ext,
primary_selection::PrimarySelectionState, wlr_data_control as selection_wlr,
},
shell::xdg::{SurfaceCachedState, ToplevelSurface, XdgShellState, XdgToplevelSurfaceData},
shm::ShmState,
},
};
@@ -148,8 +152,23 @@ impl WvrServerState {
let mut seat_state = SeatState::new();
let shm = ShmState::new::<Application>(&dh, Vec::new());
let data_device = DataDeviceState::new::<Application>(&dh);
let primary_selection_state = PrimarySelectionState::new::<Application>(&dh);
let mut seat = seat_state.new_wl_seat(&dh, "wayvr");
fn filter_allow_any(_: &wayland_server::Client) -> bool {
true
}
let ext_data_control_state = selection_ext::DataControlState::new::<Application, _>(
&dh,
Some(&primary_selection_state),
filter_allow_any,
);
let wlr_data_control_state = selection_wlr::DataControlState::new::<Application, _>(
&dh,
Some(&primary_selection_state),
filter_allow_any,
);
let dummy_milli_hz = 60000; /* refresh rate in millihertz */
let output = Output::new(
@@ -214,11 +233,15 @@ impl WvrServerState {
let state = Application {
image_importer: dma_importer,
display_handle: dh,
compositor,
xdg_shell,
seat_state,
shm,
data_device,
primary_selection_state,
wlr_data_control_state,
ext_data_control_state,
wayvr_tasks: tasks.clone(),
redraw_requests: HashSet::new(),
dmabuf_state,
@@ -300,29 +323,50 @@ impl WvrServerState {
continue;
};
// Size, icon & fallback title comes from process
let ([size_x, size_y], pos, fallback_title, icon, is_cage) =
match wvr_server.processes.get(&process_handle) {
Some(Process::Managed(p)) => (
p.resolution,
p.pos_mode,
Some(p.app_name.clone()),
p.icon.as_ref().cloned(),
p.exec_path.ends_with("cage"),
),
_ => ([1920, 1080], PositionMode::Float, None, None, false),
};
let (min_size, max_size) = with_states(toplevel.wl_surface(), |state| {
let mut guard = state.cached_state.get::<SurfaceCachedState>();
let mut min_size = guard.current().min_size;
let mut max_size = guard.current().max_size;
let window_handle = wvr_server.wm.create_window(
toplevel.clone(),
process_handle,
size_x,
size_y,
);
if min_size.is_empty() {
min_size = Size::new(1, 1);
}
if max_size.is_empty() {
max_size = Size::new(4096, 4096);
}
(min_size, max_size)
});
// Size, icon & fallback title comes from process
let (size, pos, fallback_title, icon, is_cage) =
match wvr_server.processes.get(&process_handle) {
Some(Process::Managed(p)) => {
let size: Size<i32, Logical> =
Size::new(p.resolution[0] as _, p.resolution[1] as _);
(
size.clamp(min_size, max_size),
p.pos_mode,
Some(p.app_name.clone()),
p.icon.as_ref().cloned(),
p.exec_path.ends_with("cage"),
)
}
_ => (min_size, PositionMode::Float, None, None, false),
};
let mut title: Arc<str> = fallback_title
.unwrap_or_else(|| format!("P{}", client.pid))
.into();
let window_handle = wvr_server.wm.create_window(
toplevel.clone(),
process_handle,
size.w as _,
size.h as _,
);
let mut icon = icon;
// Try to get title from xdg_toplevel, unless it's running in cage
@@ -374,7 +418,7 @@ impl WvrServerState {
app,
window_handle,
icon,
[size_x, size_y],
[size.w as _, size.h as _],
pos,
)
.context("Could not create WvrWindow overlay")