1
0
Fork 0
forked from wry/wry

wayland: implement wp_cursor_shap_manager_v1

This commit is contained in:
Julian Orth 2024-02-08 14:13:18 +01:00
parent af3b7b0868
commit 3acf0558a3
12 changed files with 452 additions and 60 deletions

View file

@ -61,29 +61,77 @@ pub trait Cursor {
pub struct ServerCursors {
pub default: ServerCursorTemplate,
pub context_menu: ServerCursorTemplate,
pub help: ServerCursorTemplate,
pub pointer: ServerCursorTemplate,
pub resize_right: ServerCursorTemplate,
pub resize_left: ServerCursorTemplate,
pub resize_top: ServerCursorTemplate,
pub resize_bottom: ServerCursorTemplate,
pub resize_top_bottom: ServerCursorTemplate,
pub resize_left_right: ServerCursorTemplate,
pub resize_top_left: ServerCursorTemplate,
pub resize_top_right: ServerCursorTemplate,
pub resize_bottom_left: ServerCursorTemplate,
pub resize_bottom_right: ServerCursorTemplate,
pub progress: ServerCursorTemplate,
pub wait: ServerCursorTemplate,
pub cell: ServerCursorTemplate,
pub crosshair: ServerCursorTemplate,
pub text: ServerCursorTemplate,
pub vertical_text: ServerCursorTemplate,
pub alias: ServerCursorTemplate,
pub copy: ServerCursorTemplate,
pub r#move: ServerCursorTemplate,
pub no_drop: ServerCursorTemplate,
pub not_allowed: ServerCursorTemplate,
pub grab: ServerCursorTemplate,
pub grabbing: ServerCursorTemplate,
pub e_resize: ServerCursorTemplate,
pub n_resize: ServerCursorTemplate,
pub ne_resize: ServerCursorTemplate,
pub nw_resize: ServerCursorTemplate,
pub s_resize: ServerCursorTemplate,
pub se_resize: ServerCursorTemplate,
pub sw_resize: ServerCursorTemplate,
pub w_resize: ServerCursorTemplate,
pub ew_resize: ServerCursorTemplate,
pub ns_resize: ServerCursorTemplate,
pub nesw_resize: ServerCursorTemplate,
pub nwse_resize: ServerCursorTemplate,
pub col_resize: ServerCursorTemplate,
pub row_resize: ServerCursorTemplate,
pub all_scroll: ServerCursorTemplate,
pub zoom_in: ServerCursorTemplate,
pub zoom_out: ServerCursorTemplate,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive)]
pub enum KnownCursor {
Default,
ContextMenu,
Help,
Pointer,
ResizeLeftRight,
ResizeTopBottom,
ResizeTopLeft,
ResizeTopRight,
ResizeBottomLeft,
ResizeBottomRight,
Progress,
Wait,
Cell,
Crosshair,
Text,
VerticalText,
Alias,
Copy,
Move,
NoDrop,
NotAllowed,
Grab,
Grabbing,
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
AllScroll,
ZoomIn,
ZoomOut,
}
impl ServerCursors {
@ -99,21 +147,42 @@ impl ServerCursors {
let theme = xcursor_theme.as_ref().map(|theme| BStr::new(theme.bytes()));
let load =
|name: &str| ServerCursorTemplate::load(name, theme, &scales, &sizes, &paths, ctx);
|names: &[&str]| ServerCursorTemplate::load(names, theme, &scales, &sizes, &paths, ctx);
Ok(Some(Self {
default: load("left_ptr")?,
pointer: load("hand2")?,
// default: load("left_ptr_watch")?,
resize_right: load("right_side")?,
resize_left: load("left_side")?,
resize_top: load("top_side")?,
resize_bottom: load("bottom_side")?,
resize_top_bottom: load("v_double_arrow")?,
resize_left_right: load("h_double_arrow")?,
resize_top_left: load("top_left_corner")?,
resize_top_right: load("top_right_corner")?,
resize_bottom_left: load("bottom_left_corner")?,
resize_bottom_right: load("bottom_right_corner")?,
default: load(&["default", "left_ptr"])?,
context_menu: load(&["context-menu"])?,
help: load(&["help"])?,
pointer: load(&["pointer", "hand2", "hand1"])?,
progress: load(&["progress"])?,
wait: load(&["wait", "watch"])?,
cell: load(&["cell"])?,
crosshair: load(&["crosshair"])?,
text: load(&["text", "xterm"])?,
vertical_text: load(&["vertical-text"])?,
alias: load(&["alias"])?,
copy: load(&["copy"])?,
r#move: load(&["move"])?,
no_drop: load(&["no-drop"])?,
not_allowed: load(&["not-allowed"])?,
grab: load(&["grab"])?,
grabbing: load(&["grabbing"])?,
e_resize: load(&["e-resize", "right_side"])?,
w_resize: load(&["w-resize", "left_side"])?,
n_resize: load(&["n-resize", "top_side"])?,
s_resize: load(&["s-resize", "bottom_side"])?,
ns_resize: load(&["ns-resize", "v_double_arrow"])?,
ew_resize: load(&["ew-resize", "h_double_arrow"])?,
nw_resize: load(&["nw-resize", "top_left_corner"])?,
ne_resize: load(&["ne-resize", "top_right_corner"])?,
sw_resize: load(&["sw-resize", "bottom_left_corner"])?,
se_resize: load(&["se-resize", "bottom_right_corner"])?,
nesw_resize: load(&["nesw-resize"])?,
nwse_resize: load(&["nwse-resize"])?,
col_resize: load(&["col-resize"])?,
row_resize: load(&["row-resize"])?,
all_scroll: load(&["all-scroll", "grabbing"])?,
zoom_in: load(&["zoom-in"])?,
zoom_out: load(&["zoom-out"])?,
}))
}
}
@ -130,14 +199,14 @@ enum ServerCursorTemplateVariant {
impl ServerCursorTemplate {
fn load(
name: &str,
names: &[&str],
theme: Option<&BStr>,
scales: &[Scale],
sizes: &[u32],
paths: &[BString],
ctx: &Rc<dyn GfxContext>,
) -> Result<Self, CursorError> {
match open_cursor(name, theme, scales, sizes, paths) {
match open_cursor(names, theme, scales, sizes, paths) {
Ok(cs) => {
if cs.images.len() == 1 {
let mut sizes = SmallMapMut::new();
@ -178,7 +247,7 @@ impl ServerCursorTemplate {
}
}
Err(e) => {
log::warn!("Could not load cursor {}: {}", name, ErrorFmt(e));
log::warn!("Could not load cursor {:?}: {}", names, ErrorFmt(e));
let empty: [Cell<u8>; 4] = unsafe { MaybeUninit::zeroed().assume_init() };
let mut img_sizes = SmallMapMut::new();
for scale in scales {
@ -399,20 +468,31 @@ struct OpenCursorResult {
}
fn open_cursor(
name: &str,
names: &[&str],
theme: Option<&BStr>,
scales: &[Scale],
sizes: &[u32],
paths: &[BString],
) -> Result<OpenCursorResult, CursorError> {
let name = name.as_bytes().as_bstr();
let mut file = None;
let mut themes_tested = AHashSet::new();
let mut pairs_tested = AHashSet::new();
if let Some(theme) = theme {
file = open_cursor_file(&mut themes_tested, paths, theme, name);
for name in names {
let name = name.as_bytes().as_bstr();
file = open_cursor_file(&mut pairs_tested, paths, theme, name);
if file.is_some() {
break;
}
}
}
if file.is_none() {
file = open_cursor_file(&mut themes_tested, paths, b"default".as_bstr(), name);
for name in names {
let name = name.as_bytes().as_bstr();
file = open_cursor_file(&mut pairs_tested, paths, b"default".as_bstr(), name);
if file.is_some() {
break;
}
}
}
let file = match file {
Some(f) => f,
@ -422,13 +502,13 @@ fn open_cursor(
parser_cursor_file(&mut file, scales, sizes)
}
fn open_cursor_file(
themes_tested: &mut AHashSet<BString>,
fn open_cursor_file<'a>(
pairs_tested: &mut AHashSet<(BString, &'a BStr)>,
paths: &[BString],
theme: &BStr,
name: &BStr,
name: &'a BStr,
) -> Option<File> {
if !themes_tested.insert(theme.to_owned()) {
if !pairs_tested.insert((theme.to_owned(), name)) {
return None;
}
if paths.is_empty() {
@ -453,7 +533,7 @@ fn open_cursor_file(
}
if let Some(parents) = parents {
for parent in parents {
if let Some(file) = open_cursor_file(themes_tested, paths, parent.as_bstr(), name) {
if let Some(file) = open_cursor_file(pairs_tested, paths, parent.as_bstr(), name) {
return Some(file);
}
}

View file

@ -20,6 +20,7 @@ use {
wl_shm::WlShmGlobal,
wl_subcompositor::WlSubcompositorGlobal,
wl_surface::xwayland_shell_v1::XwaylandShellV1Global,
wp_cursor_shape_manager_v1::WpCursorShapeManagerV1Global,
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
wp_presentation::WpPresentationGlobal,
wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1Global,
@ -158,6 +159,7 @@ impl Globals {
add_singleton!(XwaylandShellV1Global);
add_singleton!(WpTearingControlManagerV1Global);
add_singleton!(WpSinglePixelBufferManagerV1Global);
add_singleton!(WpCursorShapeManagerV1Global);
}
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {

View file

@ -27,6 +27,8 @@ pub mod wl_shm;
pub mod wl_shm_pool;
pub mod wl_subcompositor;
pub mod wl_surface;
pub mod wp_cursor_shape_device_v1;
pub mod wp_cursor_shape_manager_v1;
pub mod wp_fractional_scale_manager_v1;
pub mod wp_presentation;
pub mod wp_presentation_feedback;

View file

@ -784,13 +784,39 @@ impl WlSeatGlobal {
};
let tpl = match cursor {
KnownCursor::Default => &cursors.default,
KnownCursor::ContextMenu => &cursors.context_menu,
KnownCursor::Help => &cursors.help,
KnownCursor::Pointer => &cursors.pointer,
KnownCursor::ResizeLeftRight => &cursors.resize_left_right,
KnownCursor::ResizeTopBottom => &cursors.resize_top_bottom,
KnownCursor::ResizeTopLeft => &cursors.resize_top_left,
KnownCursor::ResizeTopRight => &cursors.resize_top_right,
KnownCursor::ResizeBottomLeft => &cursors.resize_bottom_left,
KnownCursor::ResizeBottomRight => &cursors.resize_bottom_right,
KnownCursor::Progress => &cursors.progress,
KnownCursor::Wait => &cursors.wait,
KnownCursor::Cell => &cursors.cell,
KnownCursor::Crosshair => &cursors.crosshair,
KnownCursor::Text => &cursors.text,
KnownCursor::VerticalText => &cursors.vertical_text,
KnownCursor::Alias => &cursors.alias,
KnownCursor::Copy => &cursors.copy,
KnownCursor::Move => &cursors.r#move,
KnownCursor::NoDrop => &cursors.no_drop,
KnownCursor::NotAllowed => &cursors.not_allowed,
KnownCursor::Grab => &cursors.grab,
KnownCursor::Grabbing => &cursors.grabbing,
KnownCursor::EResize => &cursors.e_resize,
KnownCursor::NResize => &cursors.n_resize,
KnownCursor::NeResize => &cursors.ne_resize,
KnownCursor::NwResize => &cursors.nw_resize,
KnownCursor::SResize => &cursors.s_resize,
KnownCursor::SeResize => &cursors.se_resize,
KnownCursor::SwResize => &cursors.sw_resize,
KnownCursor::WResize => &cursors.w_resize,
KnownCursor::EwResize => &cursors.ew_resize,
KnownCursor::NsResize => &cursors.ns_resize,
KnownCursor::NeswResize => &cursors.nesw_resize,
KnownCursor::NwseResize => &cursors.nwse_resize,
KnownCursor::ColResize => &cursors.col_resize,
KnownCursor::RowResize => &cursors.row_resize,
KnownCursor::AllScroll => &cursors.all_scroll,
KnownCursor::ZoomIn => &cursors.zoom_in,
KnownCursor::ZoomOut => &cursors.zoom_out,
};
self.set_cursor2(Some(tpl.instantiate(self.cursor_size.get())));
}

View file

@ -197,7 +197,7 @@ impl WlPointer {
}
};
if pointer_node.node_client_id() != Some(self.seat.client.id) {
log::warn!("ignoring wl_pointer.set_cursor (2)");
// log::warn!("ignoring wl_pointer.set_cursor (2)");
return Ok(());
}
// https://gitlab.freedesktop.org/wayland/wayland/-/issues/439

View file

@ -0,0 +1,136 @@
use {
crate::{
client::{Client, ClientError},
cursor::KnownCursor,
ifs::wl_seat::WlSeatGlobal,
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{wp_cursor_shape_device_v1::*, WpCursorShapeDeviceV1Id},
},
std::rc::Rc,
thiserror::Error,
};
const DEFAULT: u32 = 1;
const CONTEXT_MENU: u32 = 2;
const HELP: u32 = 3;
const POINTER: u32 = 4;
const PROGRESS: u32 = 5;
const WAIT: u32 = 6;
const CELL: u32 = 7;
const CROSSHAIR: u32 = 8;
const TEXT: u32 = 9;
const VERTICAL_TEXT: u32 = 10;
const ALIAS: u32 = 11;
const COPY: u32 = 12;
const MOVE: u32 = 13;
const NO_DROP: u32 = 14;
const NOT_ALLOWED: u32 = 15;
const GRAB: u32 = 16;
const GRABBING: u32 = 17;
const E_RESIZE: u32 = 18;
const N_RESIZE: u32 = 19;
const NE_RESIZE: u32 = 20;
const NW_RESIZE: u32 = 21;
const S_RESIZE: u32 = 22;
const SE_RESIZE: u32 = 23;
const SW_RESIZE: u32 = 24;
const W_RESIZE: u32 = 25;
const EW_RESIZE: u32 = 26;
const NS_RESIZE: u32 = 27;
const NESW_RESIZE: u32 = 28;
const NWSE_RESIZE: u32 = 29;
const COL_RESIZE: u32 = 30;
const ROW_RESIZE: u32 = 31;
const ALL_SCROLL: u32 = 32;
const ZOOM_IN: u32 = 33;
const ZOOM_OUT: u32 = 34;
pub struct WpCursorShapeDeviceV1 {
pub id: WpCursorShapeDeviceV1Id,
pub client: Rc<Client>,
pub seat: Rc<WlSeatGlobal>,
pub tracker: Tracker<Self>,
}
impl WpCursorShapeDeviceV1 {
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), WpCursorShapeDeviceV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
self.client.remove_obj(self)?;
Ok(())
}
fn set_shape(&self, parser: MsgParser<'_, '_>) -> Result<(), WpCursorShapeDeviceV1Error> {
let req: SetShape = self.client.parse(self, parser)?;
let cursor = match req.shape {
DEFAULT => KnownCursor::Default,
CONTEXT_MENU => KnownCursor::ContextMenu,
HELP => KnownCursor::Help,
POINTER => KnownCursor::Pointer,
PROGRESS => KnownCursor::Progress,
WAIT => KnownCursor::Wait,
CELL => KnownCursor::Cell,
CROSSHAIR => KnownCursor::Crosshair,
TEXT => KnownCursor::Text,
VERTICAL_TEXT => KnownCursor::VerticalText,
ALIAS => KnownCursor::Alias,
COPY => KnownCursor::Copy,
MOVE => KnownCursor::Move,
NO_DROP => KnownCursor::NoDrop,
NOT_ALLOWED => KnownCursor::NotAllowed,
GRAB => KnownCursor::Grab,
GRABBING => KnownCursor::Grabbing,
E_RESIZE => KnownCursor::EResize,
N_RESIZE => KnownCursor::NResize,
NE_RESIZE => KnownCursor::NeResize,
NW_RESIZE => KnownCursor::NwResize,
S_RESIZE => KnownCursor::SResize,
SE_RESIZE => KnownCursor::SeResize,
SW_RESIZE => KnownCursor::SwResize,
W_RESIZE => KnownCursor::WResize,
EW_RESIZE => KnownCursor::EwResize,
NS_RESIZE => KnownCursor::NsResize,
NESW_RESIZE => KnownCursor::NeswResize,
NWSE_RESIZE => KnownCursor::NwseResize,
COL_RESIZE => KnownCursor::ColResize,
ROW_RESIZE => KnownCursor::RowResize,
ALL_SCROLL => KnownCursor::AllScroll,
ZOOM_IN => KnownCursor::ZoomIn,
ZOOM_OUT => KnownCursor::ZoomOut,
_ => return Err(WpCursorShapeDeviceV1Error::UnknownShape(req.shape)),
};
let pointer_node = match self.seat.pointer_node() {
Some(n) => n,
_ => return Ok(()),
};
if pointer_node.node_client_id() != Some(self.client.id) {
return Ok(());
}
self.seat.set_known_cursor(cursor);
Ok(())
}
}
object_base! {
self = WpCursorShapeDeviceV1;
DESTROY => destroy,
SET_SHAPE => set_shape,
}
impl Object for WpCursorShapeDeviceV1 {}
simple_add_obj!(WpCursorShapeDeviceV1);
#[derive(Debug, Error)]
pub enum WpCursorShapeDeviceV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error("Shape {0} is unknown")]
UnknownShape(u32),
}
efrom!(WpCursorShapeDeviceV1Error, ClientError);
efrom!(WpCursorShapeDeviceV1Error, MsgParserError);

View file

@ -0,0 +1,119 @@
use {
crate::{
client::{Client, ClientError},
globals::{Global, GlobalName},
ifs::wp_cursor_shape_device_v1::WpCursorShapeDeviceV1,
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{wp_cursor_shape_manager_v1::*, WpCursorShapeManagerV1Id},
},
std::rc::Rc,
thiserror::Error,
};
pub struct WpCursorShapeManagerV1Global {
pub name: GlobalName,
}
impl WpCursorShapeManagerV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: WpCursorShapeManagerV1Id,
client: &Rc<Client>,
version: u32,
) -> Result<(), WpCursorShapeManagerV1Error> {
let mgr = Rc::new(WpCursorShapeManagerV1 {
id,
client: client.clone(),
tracker: Default::default(),
version,
});
track!(client, mgr);
client.add_client_obj(&mgr)?;
Ok(())
}
}
global_base!(
WpCursorShapeManagerV1Global,
WpCursorShapeManagerV1,
WpCursorShapeManagerV1Error
);
simple_add_global!(WpCursorShapeManagerV1Global);
impl Global for WpCursorShapeManagerV1Global {
fn singleton(&self) -> bool {
true
}
fn version(&self) -> u32 {
1
}
}
pub struct WpCursorShapeManagerV1 {
pub id: WpCursorShapeManagerV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub version: u32,
}
impl WpCursorShapeManagerV1 {
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), WpCursorShapeManagerV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
self.client.remove_obj(self)?;
Ok(())
}
fn get_pointer(&self, parser: MsgParser<'_, '_>) -> Result<(), WpCursorShapeManagerV1Error> {
let req: GetPointer = self.client.parse(self, parser)?;
let pointer = self.client.lookup(req.pointer)?;
let device = Rc::new(WpCursorShapeDeviceV1 {
id: req.cursor_shape_device,
client: self.client.clone(),
seat: pointer.seat.global.clone(),
tracker: Default::default(),
});
track!(self.client, device);
self.client.add_client_obj(&device)?;
Ok(())
}
fn get_tablet_tool_v2(
&self,
parser: MsgParser<'_, '_>,
) -> Result<(), WpCursorShapeManagerV1Error> {
let _req: GetTabletToolV2 = self.client.parse(self, parser)?;
Err(WpCursorShapeManagerV1Error::TabletToolNotSupported)
}
}
object_base! {
self = WpCursorShapeManagerV1;
DESTROY => destroy,
GET_POINTER => get_pointer,
GET_TABLET_TOOL_V2 => get_tablet_tool_v2,
}
impl Object for WpCursorShapeManagerV1 {}
simple_add_obj!(WpCursorShapeManagerV1);
#[derive(Debug, Error)]
pub enum WpCursorShapeManagerV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error("This compositor does not support tablet tools")]
TabletToolNotSupported,
}
efrom!(WpCursorShapeManagerV1Error, ClientError);
efrom!(WpCursorShapeManagerV1Error, MsgParserError);

View file

@ -577,7 +577,7 @@ impl ContainerNode {
if y < title_height + 1 {
KnownCursor::Default
} else {
KnownCursor::ResizeLeftRight
KnownCursor::EwResize
}
} else {
let mut cursor = KnownCursor::Default;
@ -585,7 +585,7 @@ impl ContainerNode {
let body = child.body.get();
if body.y1() > y {
if body.y1() - y > title_height + 1 {
cursor = KnownCursor::ResizeTopBottom
cursor = KnownCursor::NsResize
}
break;
}

View file

@ -320,14 +320,14 @@ impl FloatNode {
let op_type = OP_TYPES[id];
let new_cursor = match op_type {
OpType::Move => KnownCursor::Default,
OpType::ResizeLeft => KnownCursor::ResizeLeftRight,
OpType::ResizeTop => KnownCursor::ResizeTopBottom,
OpType::ResizeRight => KnownCursor::ResizeLeftRight,
OpType::ResizeBottom => KnownCursor::ResizeTopBottom,
OpType::ResizeTopLeft => KnownCursor::ResizeTopLeft,
OpType::ResizeTopRight => KnownCursor::ResizeTopRight,
OpType::ResizeBottomLeft => KnownCursor::ResizeBottomLeft,
OpType::ResizeBottomRight => KnownCursor::ResizeBottomRight,
OpType::ResizeLeft => KnownCursor::EwResize,
OpType::ResizeTop => KnownCursor::NsResize,
OpType::ResizeRight => KnownCursor::EwResize,
OpType::ResizeBottom => KnownCursor::NsResize,
OpType::ResizeTopLeft => KnownCursor::NwResize,
OpType::ResizeTopRight => KnownCursor::NeResize,
OpType::ResizeBottomLeft => KnownCursor::SwResize,
OpType::ResizeBottomRight => KnownCursor::SeResize,
};
seat_state.op_type = op_type;
if new_cursor != mem::replace(&mut seat_state.cursor, new_cursor) {