Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
src/server/drag_icon.rs (3K)
1 // SPDX-FileCopyrightText: © 2024 The River Developers
2 // SPDX-License-Identifier: GPL-3.0-only
3
4 use crate::ffi;
5 use crate::cursor::Cursor;
6 use crate::server::{WlListener, wl_listener_remove, wl_signal_add};
7
8 #[repr(C)]
9 pub struct DragIcon {
10 pub wlr_drag_icon: *mut ffi::wlr_drag_icon,
11 pub scene_drag_icon: *mut ffi::wlr_scene_tree,
12 pub destroy: ffi::wl_listener,
13 }
14
15 impl DragIcon {
16 pub unsafe fn create(
17 wlr_drag_icon: *mut ffi::wlr_drag_icon,
18 cursor: *mut Cursor,
19 ) -> Result<(), &'static str> {
20 let server = (*(*cursor).seat).server;
21
22 let scene_drag_icon = ffi::wlr_scene_drag_icon_create((*server).scene.drag_icons, wlr_drag_icon);
23 if scene_drag_icon.is_null() {
24 return Err("Failed to create scene drag icon");
25 }
26
27 let drag_icon = Box::new(Self {
28 wlr_drag_icon,
29 scene_drag_icon,
30 destroy: std::mem::zeroed(),
31 });
32 let raw = Box::into_raw(drag_icon);
33
34 ffi::river_scene_node_set_data(
35 scene_drag_icon as *mut ffi::wlr_scene_node,
36 raw as *mut std::ffi::c_void,
37 );
38
39 let drag_icon_ref = &mut *raw;
40 drag_icon_ref.update_position(cursor);
41
42 let destroy_listener = &mut drag_icon_ref.destroy as *mut ffi::wl_listener as *mut WlListener;
43 (*destroy_listener).notify = Some(handle_destroy);
44 wl_signal_add(
45 &mut (*wlr_drag_icon).events.destroy as *mut ffi::wl_signal,
46 &mut drag_icon_ref.destroy,
47 );
48
49 Ok(())
50 }
51
52 pub unsafe fn update_position(&mut self, cursor: *mut Cursor) {
53 let grab_type = ffi::river_wlr_drag_get_grab_type((*self.wlr_drag_icon).drag);
54 match grab_type {
55 ffi::wlr_drag_grab_type_WLR_DRAG_GRAB_KEYBOARD => {
56 // unreachable
57 }
58 ffi::wlr_drag_grab_type_WLR_DRAG_GRAB_KEYBOARD_POINTER => {
59 let x = (*cursor).x();
60 let y = (*cursor).y();
61 ffi::wlr_scene_node_set_position(
62 self.scene_drag_icon as *mut ffi::wlr_scene_node,
63 x as i32,
64 y as i32,
65 );
66 }
67 ffi::wlr_drag_grab_type_WLR_DRAG_GRAB_KEYBOARD_TOUCH => {
68 let touch_id = ffi::river_wlr_drag_get_touch_id((*self.wlr_drag_icon).drag);
69 if let Some(&(lx, ly)) = (*cursor).touch_points.get(&touch_id) {
70 ffi::wlr_scene_node_set_position(
71 self.scene_drag_icon as *mut ffi::wlr_scene_node,
72 lx as i32,
73 ly as i32,
74 );
75 }
76 }
77 _ => {}
78 }
79 }
80 }
81
82 unsafe extern "C" fn handle_destroy(
83 listener: *mut ffi::wl_listener,
84 _data: *mut std::ffi::c_void,
85 ) {
86 let drag_icon_ptr = crate::container_of!(listener, DragIcon, destroy);
87 let mut drag_icon = Box::from_raw(drag_icon_ptr);
88 wl_listener_remove(&mut drag_icon.destroy);
89 }