wayland server fixes
This commit is contained in:
@@ -3,33 +3,43 @@ use smithay::backend::allocator::dmabuf::Dmabuf;
|
|||||||
use smithay::backend::renderer::{BufferType, buffer_type};
|
use smithay::backend::renderer::{BufferType, buffer_type};
|
||||||
use smithay::desktop::{PopupKind, PopupManager};
|
use smithay::desktop::{PopupKind, PopupManager};
|
||||||
use smithay::input::{Seat, SeatHandler, SeatState};
|
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_protocols::xdg::shell::server::xdg_toplevel;
|
||||||
use smithay::reexports::wayland_server;
|
|
||||||
use smithay::reexports::wayland_server::Resource;
|
use smithay::reexports::wayland_server::Resource;
|
||||||
use smithay::reexports::wayland_server::protocol::{wl_buffer, wl_output, wl_seat};
|
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::buffer::BufferHandler;
|
||||||
use smithay::wayland::dmabuf::{
|
use smithay::wayland::dmabuf::{
|
||||||
DmabufFeedback, DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier, get_dmabuf,
|
DmabufFeedback, DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier, get_dmabuf,
|
||||||
};
|
};
|
||||||
use smithay::wayland::fractional_scale::with_fractional_scale;
|
use smithay::wayland::fractional_scale::with_fractional_scale;
|
||||||
use smithay::wayland::output::OutputHandler;
|
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::shm::{ShmHandler, ShmState, with_buffer_contents};
|
||||||
use smithay::wayland::single_pixel_buffer::get_single_pixel_buffer;
|
use smithay::wayland::single_pixel_buffer::get_single_pixel_buffer;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
delegate_compositor, delegate_data_device, delegate_dmabuf, delegate_output, delegate_seat,
|
delegate_compositor, delegate_data_control, delegate_data_device, delegate_dmabuf,
|
||||||
delegate_shm, delegate_xdg_shell,
|
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::collections::HashSet;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
use std::os::fd::OwnedFd;
|
use std::os::fd::OwnedFd;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use smithay::utils::Serial;
|
use smithay::utils::Serial;
|
||||||
use smithay::wayland::compositor::{self, BufferAssignment, SurfaceAttributes, send_surface_state};
|
use smithay::wayland::compositor::{self, BufferAssignment, SurfaceAttributes, send_surface_state};
|
||||||
|
|
||||||
use smithay::wayland::selection::SelectionHandler;
|
|
||||||
use smithay::wayland::selection::data_device::{
|
use smithay::wayland::selection::data_device::{
|
||||||
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
|
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
|
||||||
|
set_data_device_focus,
|
||||||
};
|
};
|
||||||
|
use smithay::wayland::selection::{self, SelectionHandler};
|
||||||
use smithay::wayland::shell::xdg::{
|
use smithay::wayland::shell::xdg::{
|
||||||
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
|
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
|
||||||
};
|
};
|
||||||
@@ -51,9 +61,13 @@ pub struct Application {
|
|||||||
pub seat_state: SeatState<Application>,
|
pub seat_state: SeatState<Application>,
|
||||||
pub shm: ShmState,
|
pub shm: ShmState,
|
||||||
pub data_device: DataDeviceState,
|
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 wayvr_tasks: SyncEventQueue<WayVRTask>,
|
||||||
pub redraw_requests: HashSet<wayland_server::backend::ObjectId>,
|
pub redraw_requests: HashSet<wayland_server::backend::ObjectId>,
|
||||||
pub popup_manager: PopupManager,
|
pub popup_manager: PopupManager,
|
||||||
|
pub display_handle: DisplayHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application {
|
impl Application {
|
||||||
@@ -205,7 +219,13 @@ impl SeatHandler for Application {
|
|||||||
&mut self.seat_state
|
&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(
|
fn cursor_image(
|
||||||
&mut self,
|
&mut self,
|
||||||
_seat: &Seat<Self>,
|
_seat: &Seat<Self>,
|
||||||
@@ -231,7 +251,35 @@ impl DataDeviceHandler for Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SelectionHandler 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)]
|
#[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_dmabuf!(Application);
|
||||||
delegate_xdg_shell!(Application);
|
delegate_xdg_shell!(Application);
|
||||||
delegate_compositor!(Application);
|
delegate_compositor!(Application);
|
||||||
@@ -378,6 +444,10 @@ delegate_shm!(Application);
|
|||||||
delegate_seat!(Application);
|
delegate_seat!(Application);
|
||||||
delegate_data_device!(Application);
|
delegate_data_device!(Application);
|
||||||
delegate_output!(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(
|
const fn wl_transform_to_frame_transform(
|
||||||
transform: wl_output::Transform,
|
transform: wl_output::Transform,
|
||||||
|
|||||||
@@ -15,11 +15,15 @@ use smithay::{
|
|||||||
input::{SeatState, keyboard::XkbConfig},
|
input::{SeatState, keyboard::XkbConfig},
|
||||||
output::{Mode, Output},
|
output::{Mode, Output},
|
||||||
reexports::wayland_server::{self, backend::ClientId},
|
reexports::wayland_server::{self, backend::ClientId},
|
||||||
|
utils::{Logical, Size},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{self, SurfaceData, with_states},
|
compositor::{self, SurfaceData, with_states},
|
||||||
dmabuf::{DmabufFeedbackBuilder, DmabufState},
|
dmabuf::{DmabufFeedbackBuilder, DmabufState},
|
||||||
selection::data_device::DataDeviceState,
|
selection::{
|
||||||
shell::xdg::{ToplevelSurface, XdgShellState, XdgToplevelSurfaceData},
|
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,
|
shm::ShmState,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -148,8 +152,23 @@ impl WvrServerState {
|
|||||||
let mut seat_state = SeatState::new();
|
let mut seat_state = SeatState::new();
|
||||||
let shm = ShmState::new::<Application>(&dh, Vec::new());
|
let shm = ShmState::new::<Application>(&dh, Vec::new());
|
||||||
let data_device = DataDeviceState::new::<Application>(&dh);
|
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");
|
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 dummy_milli_hz = 60000; /* refresh rate in millihertz */
|
||||||
|
|
||||||
let output = Output::new(
|
let output = Output::new(
|
||||||
@@ -214,11 +233,15 @@ impl WvrServerState {
|
|||||||
|
|
||||||
let state = Application {
|
let state = Application {
|
||||||
image_importer: dma_importer,
|
image_importer: dma_importer,
|
||||||
|
display_handle: dh,
|
||||||
compositor,
|
compositor,
|
||||||
xdg_shell,
|
xdg_shell,
|
||||||
seat_state,
|
seat_state,
|
||||||
shm,
|
shm,
|
||||||
data_device,
|
data_device,
|
||||||
|
primary_selection_state,
|
||||||
|
wlr_data_control_state,
|
||||||
|
ext_data_control_state,
|
||||||
wayvr_tasks: tasks.clone(),
|
wayvr_tasks: tasks.clone(),
|
||||||
redraw_requests: HashSet::new(),
|
redraw_requests: HashSet::new(),
|
||||||
dmabuf_state,
|
dmabuf_state,
|
||||||
@@ -300,29 +323,50 @@ impl WvrServerState {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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
|
// Size, icon & fallback title comes from process
|
||||||
let ([size_x, size_y], pos, fallback_title, icon, is_cage) =
|
let (size, pos, fallback_title, icon, is_cage) =
|
||||||
match wvr_server.processes.get(&process_handle) {
|
match wvr_server.processes.get(&process_handle) {
|
||||||
Some(Process::Managed(p)) => (
|
Some(Process::Managed(p)) => {
|
||||||
p.resolution,
|
let size: Size<i32, Logical> =
|
||||||
|
Size::new(p.resolution[0] as _, p.resolution[1] as _);
|
||||||
|
(
|
||||||
|
size.clamp(min_size, max_size),
|
||||||
p.pos_mode,
|
p.pos_mode,
|
||||||
Some(p.app_name.clone()),
|
Some(p.app_name.clone()),
|
||||||
p.icon.as_ref().cloned(),
|
p.icon.as_ref().cloned(),
|
||||||
p.exec_path.ends_with("cage"),
|
p.exec_path.ends_with("cage"),
|
||||||
),
|
)
|
||||||
_ => ([1920, 1080], PositionMode::Float, None, None, false),
|
}
|
||||||
|
_ => (min_size, PositionMode::Float, None, None, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let window_handle = wvr_server.wm.create_window(
|
|
||||||
toplevel.clone(),
|
|
||||||
process_handle,
|
|
||||||
size_x,
|
|
||||||
size_y,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut title: Arc<str> = fallback_title
|
let mut title: Arc<str> = fallback_title
|
||||||
.unwrap_or_else(|| format!("P{}", client.pid))
|
.unwrap_or_else(|| format!("P{}", client.pid))
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
let window_handle = wvr_server.wm.create_window(
|
||||||
|
toplevel.clone(),
|
||||||
|
process_handle,
|
||||||
|
size.w as _,
|
||||||
|
size.h as _,
|
||||||
|
);
|
||||||
|
|
||||||
let mut icon = icon;
|
let mut icon = icon;
|
||||||
|
|
||||||
// Try to get title from xdg_toplevel, unless it's running in cage
|
// Try to get title from xdg_toplevel, unless it's running in cage
|
||||||
@@ -374,7 +418,7 @@ impl WvrServerState {
|
|||||||
app,
|
app,
|
||||||
window_handle,
|
window_handle,
|
||||||
icon,
|
icon,
|
||||||
[size_x, size_y],
|
[size.w as _, size.h as _],
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
.context("Could not create WvrWindow overlay")
|
.context("Could not create WvrWindow overlay")
|
||||||
|
|||||||
Reference in New Issue
Block a user