git.lucas.co / cce-compositor
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 }