git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

src/server/libinput_config.rs (5.3K)

  1 // SPDX-FileCopyrightText: © 2026 The River Developers
  2 // SPDX-License-Identifier: GPL-3.0-only
  3 
  4 use crate::ffi;
  5 use crate::server::{Server, WlList, wl_list_insert, wl_list_remove};
  6 
  7 pub struct LibinputConfig {
  8     pub server: *mut Server,
  9     pub global: *mut ffi::wl_global,
 10     pub objects: ffi::wl_list,
 11     pub devices: ffi::wl_list,
 12 }
 13 
 14 pub struct LibinputConfigObject {
 15     pub config: *mut LibinputConfig,
 16     pub resource: *mut ffi::wl_resource,
 17     pub link: ffi::wl_list,
 18 }
 19 
 20 impl Default for LibinputConfig {
 21     fn default() -> Self {
 22         unsafe { std::mem::zeroed() }
 23     }
 24 }
 25 
 26 impl LibinputConfig {
 27     pub unsafe fn init(&mut self, server: *mut Server) -> Result<(), &'static str> {
 28         self.server = server;
 29         ffi::wl_list_init(&mut self.objects);
 30         ffi::wl_list_init(&mut self.devices);
 31 
 32         self.global = ffi::wl_global_create(
 33             (*server).wl_server,
 34             &ffi::river_libinput_config_v1_interface,
 35             2,
 36             self as *mut LibinputConfig as *mut _,
 37             Some(bind_libinput_config),
 38         );
 39         if self.global.is_null() {
 40             return Err("Failed to create river_libinput_config_v1 global");
 41         }
 42 
 43         Ok(())
 44     }
 45 
 46     pub unsafe fn deinit(&mut self) {
 47         if !self.global.is_null() {
 48             ffi::wl_global_destroy(self.global);
 49             self.global = std::ptr::null_mut();
 50         }
 51 
 52         let objects_head = &mut self.objects as *mut ffi::wl_list as *mut WlList;
 53         let mut curr = (*objects_head).next;
 54         while curr != objects_head {
 55             let next = (*curr).next;
 56             let obj = crate::container_of!(curr, LibinputConfigObject, link);
 57             ffi::wl_resource_destroy((*obj).resource);
 58             curr = next;
 59         }
 60     }
 61 }
 62 
 63 unsafe extern "C" fn bind_libinput_config(
 64     client: *mut ffi::wl_client,
 65     data: *mut std::ffi::c_void,
 66     version: u32,
 67     id: u32,
 68 ) {
 69     let config = data as *mut LibinputConfig;
 70     let resource = ffi::wl_resource_create(client, &ffi::river_libinput_config_v1_interface, version as i32, id);
 71     if resource.is_null() {
 72         ffi::wl_client_post_no_memory(client);
 73         return;
 74     }
 75 
 76     let obj = Box::into_raw(Box::new(LibinputConfigObject {
 77         config,
 78         resource,
 79         link: std::mem::zeroed(),
 80     }));
 81 
 82     ffi::wl_resource_set_implementation(
 83         resource,
 84         &LIBINPUT_CONFIG_INTERFACE as *const _ as *const _,
 85         obj as *mut _,
 86         Some(handle_object_destroy),
 87     );
 88 
 89     let list_head = &mut (*config).objects as *mut ffi::wl_list as *mut WlList;
 90     wl_list_insert((*list_head).prev, &mut (*obj).link as *mut ffi::wl_list as *mut WlList);
 91 
 92     let devices_head = &mut (*config).devices as *mut ffi::wl_list as *mut WlList;
 93     let mut curr = (*devices_head).next;
 94     while curr != devices_head {
 95         let next = (*curr).next;
 96         let dev = crate::container_of!(curr, crate::libinput_device::LibinputDevice, link);
 97         (*dev).create_object(resource);
 98         curr = next;
 99     }
100 }
101 
102 unsafe extern "C" fn handle_object_destroy(resource: *mut ffi::wl_resource) {
103     let obj = ffi::wl_resource_get_user_data(resource) as *mut LibinputConfigObject;
104     if !obj.is_null() {
105         wl_list_remove(&mut (*obj).link as *mut ffi::wl_list as *mut WlList);
106         let _ = Box::from_raw(obj);
107     }
108 }
109 
110 static LIBINPUT_CONFIG_INTERFACE: ffi::river_libinput_config_v1_interface = ffi::river_libinput_config_v1_interface {
111     stop: Some(libinput_config_stop),
112     destroy: Some(libinput_config_destroy),
113     create_accel_config: Some(libinput_config_create_accel_config),
114 };
115 
116 static LIBINPUT_CONFIG_INERT_INTERFACE: ffi::river_libinput_config_v1_interface = ffi::river_libinput_config_v1_interface {
117     stop: None,
118     destroy: Some(libinput_config_inert_destroy),
119     create_accel_config: None,
120 };
121 
122 unsafe extern "C" fn libinput_config_stop(_client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
123     let obj = ffi::wl_resource_get_user_data(resource) as *mut LibinputConfigObject;
124     if obj.is_null() {
125         return;
126     }
127 
128     wl_list_remove(&mut (*obj).link as *mut ffi::wl_list as *mut WlList);
129     ffi::wl_list_init(&mut (*obj).link);
130 
131     ffi::wl_resource_post_event(resource, 0); // finished event
132 
133     ffi::wl_resource_set_implementation(
134         resource,
135         &LIBINPUT_CONFIG_INERT_INTERFACE as *const _ as *const _,
136         obj as *mut _,
137         Some(handle_object_destroy),
138     );
139 }
140 
141 unsafe extern "C" fn libinput_config_destroy(_client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
142     ffi::wl_resource_post_error(
143         resource,
144         ffi::river_libinput_config_v1_error_RIVER_LIBINPUT_CONFIG_V1_ERROR_INVALID_DESTROY,
145         b"destroy before finished event sent\0".as_ptr() as *const _,
146     );
147 }
148 
149 unsafe extern "C" fn libinput_config_inert_destroy(_client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
150     ffi::wl_resource_destroy(resource);
151 }
152 
153 unsafe extern "C" fn libinput_config_create_accel_config(
154     client: *mut ffi::wl_client,
155     resource: *mut ffi::wl_resource,
156     id: u32,
157     profile: u32,
158 ) {
159     if let Err(e) = crate::libinput_accel_config::LibinputAccelConfig::create(
160         client,
161         ffi::wl_resource_get_version(resource) as u32,
162         id,
163         profile,
164     ) {
165         log::error!("Failed to create LibinputAccelConfig: {}", e);
166         ffi::wl_resource_post_no_memory(resource);
167     }
168 }