Fix pointer clamping regression and also update Smithay

This commit is contained in:
Ottatop 2024-04-27 21:26:54 -05:00
parent 058350db43
commit 4b3839e380
8 changed files with 124 additions and 117 deletions

24
Cargo.lock generated
View file

@ -737,9 +737,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "drm"
version = "0.11.1"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde"
checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1"
dependencies = [
"bitflags 2.5.0",
"bytemuck",
@ -750,9 +750,9 @@ dependencies = [
[[package]]
name = "drm-ffi"
version = "0.7.1"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6"
checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53"
dependencies = [
"drm-sys",
"rustix",
@ -766,9 +766,9 @@ checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
[[package]]
name = "drm-sys"
version = "0.6.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176"
checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986"
dependencies = [
"libc",
"linux-raw-sys 0.6.4",
@ -974,11 +974,11 @@ dependencies = [
[[package]]
name = "gbm"
version = "0.14.2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "313702b30cdeb83ddc72bc14dcee67803cd0ae2d12282ea06e368c25a900c844"
checksum = "45bf55ba6dd53ad0ac115046ff999c5324c283444ee6e0be82454c4e8eb2f36a"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.5.0",
"drm",
"drm-fourcc",
"gbm-sys",
@ -1370,7 +1370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if",
"windows-targets 0.52.4",
"windows-targets 0.48.5",
]
[[package]]
@ -2300,7 +2300,7 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]]
name = "smithay"
version = "0.3.0"
source = "git+https://github.com/Smithay/smithay?rev=c293ec7#c293ec730fa66b53b8e16cffac94e9d0c8870a2c"
source = "git+https://github.com/Smithay/smithay?rev=f3e442c#f3e442c28830ad752a5ca197ec1fb885af09f3ab"
dependencies = [
"appendlist",
"ash",
@ -2375,7 +2375,7 @@ dependencies = [
[[package]]
name = "smithay-drm-extras"
version = "0.1.0"
source = "git+https://github.com/Smithay/smithay?rev=c293ec7#c293ec730fa66b53b8e16cffac94e9d0c8870a2c"
source = "git+https://github.com/Smithay/smithay?rev=f3e442c#f3e442c28830ad752a5ca197ec1fb885af09f3ab"
dependencies = [
"drm",
"edid-rs",

View file

@ -49,7 +49,7 @@ keywords = ["wayland", "compositor", "smithay", "lua"]
[dependencies]
# Smithay
smithay = { workspace = true }
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "c293ec7" }
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "f3e442c" }
# Tracing
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
@ -89,7 +89,7 @@ gag = "1.0.0"
[workspace.dependencies.smithay]
git = "https://github.com/Smithay/smithay"
rev = "c293ec7"
rev = "f3e442c"
default-features = false
features = [
"desktop",

View file

@ -5,7 +5,6 @@ use smithay::backend::renderer::test::DummyRenderer;
use smithay::backend::renderer::ImportMemWl;
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
use smithay::utils::{Physical, Size};
use std::ffi::OsString;
use std::path::PathBuf;
use smithay::{
@ -119,13 +118,7 @@ pub fn setup_dummy(
state.pinnacle.space.map_output(&output, (0, 0));
if let Err(err) = state.pinnacle.xwayland.start(
state.pinnacle.loop_handle.clone(),
None,
std::iter::empty::<(OsString, OsString)>(),
true,
|_| {},
) {
if let Err(err) = state.pinnacle.start_xwayland() {
tracing::error!("Failed to start XWayland: {err}");
}

View file

@ -5,7 +5,6 @@ mod gamma;
use std::{
collections::{HashMap, HashSet},
ffi::OsString,
path::{Path, PathBuf},
time::Duration,
};
@ -684,13 +683,7 @@ pub fn setup_udev(
});
});
if let Err(err) = state.pinnacle.xwayland.start(
state.pinnacle.loop_handle.clone(),
None,
std::iter::empty::<(OsString, OsString)>(),
true,
|_| {},
) {
if let Err(err) = state.pinnacle.start_xwayland() {
error!("Failed to start XWayland: {err}");
}

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
use std::{ffi::OsString, path::PathBuf, time::Duration};
use std::{path::PathBuf, time::Duration};
use anyhow::{anyhow, ensure};
use smithay::{
@ -201,13 +201,7 @@ pub fn setup_winit(
state.pinnacle.space.map_output(&output, (0, 0));
if let Err(err) = state.pinnacle.xwayland.start(
state.pinnacle.loop_handle.clone(),
None,
std::iter::empty::<(OsString, OsString)>(),
true,
|_| {},
) {
if let Err(err) = state.pinnacle.start_xwayland() {
error!("Failed to start XWayland: {err}");
}

View file

@ -1,8 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-or-later
use std::{process::Stdio, time::Duration};
use anyhow::anyhow;
use smithay::{
desktop::Window,
utils::{Logical, Point, Rectangle, SERIAL_COUNTER},
utils::{Logical, Point, Rectangle, Size, SERIAL_COUNTER},
wayland::{
seat::WaylandFocus,
selection::{
@ -19,12 +22,13 @@ use smithay::{
},
xwayland::{
xwm::{Reorder, WmWindowType, XwmId},
X11Surface, X11Wm, XwmHandler,
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
},
};
use tracing::{debug, error, trace, warn};
use crate::{
cursor::Cursor,
focus::keyboard::KeyboardFocusTarget,
state::{Pinnacle, State, WithState},
window::{window_state::FloatingOrTiled, WindowElement},
@ -585,3 +589,66 @@ fn should_float(surface: &X11Surface) -> bool {
});
surface.is_popup() || is_popup_by_type || is_popup_by_size
}
impl Pinnacle {
pub fn start_xwayland(&mut self) -> anyhow::Result<()> {
// TODO: xwayland keybaord grab state
let (xwayland, client) = XWayland::spawn(
&self.display_handle,
None,
std::iter::empty::<(String, String)>(),
true,
Stdio::null(),
Stdio::null(),
|_| (),
)?;
let display_handle = self.display_handle.clone();
self.loop_handle
.insert_source(xwayland, move |event, _, state| match event {
XWaylandEvent::Ready {
x11_socket,
display_number,
} => {
let mut wm = X11Wm::start_wm(
state.pinnacle.loop_handle.clone(),
display_handle.clone(),
x11_socket,
client.clone(),
)
.expect("failed to attach x11wm");
let cursor = Cursor::load();
let image = cursor.get_image(1, Duration::ZERO);
wm.set_cursor(
&image.pixels_rgba,
Size::from((image.width as u16, image.height as u16)),
Point::from((image.xhot as u16, image.yhot as u16)),
)
.expect("failed to set xwayland default cursor");
tracing::debug!("setting xwm and xdisplay");
state.pinnacle.xwm = Some(wm);
state.pinnacle.xdisplay = Some(display_number);
std::env::set_var("DISPLAY", format!(":{display_number}"));
if let Err(err) = state.pinnacle.start_config(Some(
state.pinnacle.config.dir(&state.pinnacle.xdg_base_dirs),
)) {
panic!("failed to start config: {err}");
}
}
XWaylandEvent::Error => {
warn!("XWayland crashed on startup");
}
})
.map(|_| ())
.map_err(|err| {
anyhow!("Failed to insert the XWaylandSource into the event loop: {err}")
})
}
}

View file

@ -644,7 +644,7 @@ impl State {
return;
};
let mut pointer_loc = pointer.current_location();
let pointer_loc = pointer.current_location();
let mut pointer_confined_to: Option<(
WlSurface,
@ -712,18 +712,14 @@ impl State {
}
}
pointer_loc += event.delta();
let mut new_pointer_loc = pointer_loc + event.delta();
// clamp to screen limits
// this event is never generated by winit
let output_locs = self
.pinnacle
.space
.outputs()
.flat_map(|op| self.pinnacle.space.output_geometry(op));
pointer_loc = clamp_coords_inside_rects(pointer_loc, output_locs);
let surface_under = self.pinnacle.pointer_focus_target_under(pointer_loc);
new_pointer_loc = constrain_point_inside_rects(new_pointer_loc, output_locs);
if let Some((surf, surf_loc, region)) = pointer_confined_to {
let region = region.or_else(|| {
@ -755,27 +751,30 @@ impl State {
}
}
pointer_loc = clamp_coords_inside_rects(pointer_loc, region_rects);
new_pointer_loc = constrain_point_inside_rects(new_pointer_loc, region_rects);
}
}
self.pinnacle.maybe_activate_pointer_constraint(pointer_loc);
self.pinnacle
.maybe_activate_pointer_constraint(new_pointer_loc);
if let Some(output) = self
.pinnacle
.space
.output_under(pointer_loc)
.output_under(new_pointer_loc)
.next()
.cloned()
{
self.pinnacle.output_focus_stack.set_focus(output);
}
let surface_under = self.pinnacle.pointer_focus_target_under(new_pointer_loc);
pointer.motion(
self,
surface_under.clone(),
&MotionEvent {
location: pointer_loc,
location: new_pointer_loc,
serial: SERIAL_COUNTER.next_serial(),
time: event.time_msec(),
},
@ -802,26 +801,42 @@ impl State {
/// Clamp the given point within the given rects.
///
/// This returns the nearest point inside the rects.
fn clamp_coords_inside_rects(
fn constrain_point_inside_rects(
pos: Point<f64, Logical>,
rects: impl IntoIterator<Item = Rectangle<i32, Logical>>,
) -> Point<f64, Logical> {
let (pos_x, pos_y) = pos.into();
let nearest_points = rects.into_iter().map(|rect| {
let loc = rect.loc;
let size = rect.size;
let pos_x = pos_x.clamp(loc.x as f64, (loc.x + size.w - 1) as f64);
let pos_y = pos_y.clamp(loc.y as f64, (loc.y + size.h - 1) as f64);
(pos_x, pos_y)
// TODO: replace with constrain once fix is merged
// let pos = pos.constrain(rect.to_f64());
// (rect, pos.x, pos.y)
let pos_x = pos_x.clamp(rect.loc.x as f64, (rect.loc.x + rect.size.w) as f64);
let pos_y = pos_y.clamp(rect.loc.y as f64, (rect.loc.y + rect.size.h) as f64);
(rect, pos_x, pos_y)
});
let nearest_point = nearest_points.min_by(|(x1, y1), (x2, y2)| {
let nearest_point = nearest_points.min_by(|(_, x1, y1), (_, x2, y2)| {
f64::total_cmp(
&((pos_x - x1).powi(2) + (pos_y - y1).powi(2)).sqrt(),
&((pos_x - x2).powi(2) + (pos_y - y2).powi(2)).sqrt(),
)
});
nearest_point.map(|point| point.into()).unwrap_or(pos)
nearest_point
.map(|(rect, mut x, mut y)| {
let rect = rect.to_f64();
// If the passed in point is to the right/bottom, nudge the nearest point by 1
// in the other direction to make it actually inside the rect and not touching
// its edge.
if pos_x >= rect.loc.x + rect.size.w {
x -= 1.0;
}
if pos_y >= rect.loc.y + rect.size.h {
y -= 1.0;
}
(x, y).into()
})
.unwrap_or(pos)
}

View file

@ -4,7 +4,6 @@ use crate::{
api::signal::SignalState,
backend::Backend,
config::Config,
cursor::Cursor,
focus::OutputFocusStack,
grab::resize_grab::ResizeSurfaceState,
layout::LayoutState,
@ -24,7 +23,7 @@ use smithay::{
Display, DisplayHandle,
},
},
utils::{Clock, Monotonic, Point, Size},
utils::{Clock, Monotonic},
wayland::{
compositor::{self, CompositorClientState, CompositorState},
dmabuf::DmabufFeedback,
@ -41,9 +40,9 @@ use smithay::{
socket::ListeningSocketSource,
viewporter::ViewporterState,
},
xwayland::{X11Wm, XWayland, XWaylandEvent},
xwayland::X11Wm,
};
use std::{cell::RefCell, path::PathBuf, sync::Arc, time::Duration};
use std::{cell::RefCell, path::PathBuf, sync::Arc};
use sysinfo::{ProcessRefreshKind, RefreshKind};
use tracing::{error, info, warn};
use xdg::BaseDirectories;
@ -103,7 +102,6 @@ pub struct Pinnacle {
pub config: Config,
// xwayland stuff
pub xwayland: XWayland,
pub xwm: Option<X11Wm>,
pub xdisplay: Option<u32>,
@ -186,58 +184,6 @@ impl State {
seat.add_keyboard(XkbConfig::default(), 500, 25)?;
let xwayland = {
let (xwayland, channel) = XWayland::new(&display_handle);
let dh_clone = display_handle.clone();
let res = loop_handle.insert_source(channel, move |event, _, state| match event {
XWaylandEvent::Ready {
connection,
client,
client_fd: _,
display,
} => {
let mut wm = X11Wm::start_wm(
state.pinnacle.loop_handle.clone(),
dh_clone.clone(),
connection,
client,
)
.expect("failed to attach x11wm");
let cursor = Cursor::load();
let image = cursor.get_image(1, Duration::ZERO);
wm.set_cursor(
&image.pixels_rgba,
Size::from((image.width as u16, image.height as u16)),
Point::from((image.xhot as u16, image.yhot as u16)),
)
.expect("failed to set xwayland default cursor");
tracing::debug!("setting xwm and xdisplay");
state.pinnacle.xwm = Some(wm);
state.pinnacle.xdisplay = Some(display);
std::env::set_var("DISPLAY", format!(":{display}"));
if let Err(err) = state.pinnacle.start_config(Some(
state.pinnacle.config.dir(&state.pinnacle.xdg_base_dirs),
)) {
panic!("failed to start config: {err}");
}
}
XWaylandEvent::Exited => {
state.pinnacle.xwm.take();
}
});
if let Err(err) = res {
error!("Failed to insert XWayland source into loop: {err}");
}
xwayland
};
tracing::debug!("xwayland set up");
let primary_selection_state = PrimarySelectionState::new::<Self>(&display_handle);
let data_control_state = DataControlState::new::<Self, _>(
@ -300,7 +246,6 @@ impl State {
windows: Vec::new(),
new_windows: Vec::new(),
xwayland,
xwm: None,
xdisplay: None,