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

src/server/libinput_accel_config.rs (5K)

  1 // SPDX-FileCopyrightText: © 2026 The River Developers
  2 // SPDX-License-Identifier: GPL-3.0-only
  3 
  4 use crate::ffi;
  5 
  6 pub struct LibinputAccelConfig {
  7     pub resource: *mut ffi::wl_resource,
  8     pub libinput: *mut ffi::libinput_config_accel,
  9 }
 10 
 11 impl LibinputAccelConfig {
 12     pub unsafe fn create(
 13         client: *mut ffi::wl_client,
 14         version: u32,
 15         id: u32,
 16         profile: u32,
 17     ) -> Result<*mut Self, &'static str> {
 18         let libinput = ffi::libinput_config_accel_create(profile);
 19         if libinput.is_null() {
 20             return Err("Failed to create libinput_config_accel");
 21         }
 22 
 23         let resource = ffi::wl_resource_create(
 24             client,
 25             &ffi::river_libinput_accel_config_v1_interface,
 26             version as i32,
 27             id,
 28         );
 29         if resource.is_null() {
 30             ffi::libinput_config_accel_destroy(libinput);
 31             return Err("Failed to create river_libinput_accel_config_v1 resource");
 32         }
 33 
 34         let accel_config = Box::into_raw(Box::new(Self {
 35             resource,
 36             libinput,
 37         }));
 38 
 39         ffi::wl_resource_set_implementation(
 40             resource,
 41             &ACCEL_CONFIG_INTERFACE as *const _ as *const _,
 42             accel_config as *mut _,
 43             Some(handle_accel_config_destroy_resource),
 44         );
 45 
 46         Ok(accel_config)
 47     }
 48 }
 49 
 50 unsafe extern "C" fn handle_accel_config_destroy_resource(resource: *mut ffi::wl_resource) {
 51     let accel_config = ffi::wl_resource_get_user_data(resource) as *mut LibinputAccelConfig;
 52     if !accel_config.is_null() {
 53         if !(*accel_config).libinput.is_null() {
 54             ffi::libinput_config_accel_destroy((*accel_config).libinput);
 55         }
 56         let _ = Box::from_raw(accel_config);
 57     }
 58 }
 59 
 60 static ACCEL_CONFIG_INTERFACE: ffi::river_libinput_accel_config_v1_interface = ffi::river_libinput_accel_config_v1_interface {
 61     destroy: Some(accel_config_destroy),
 62     set_points: Some(accel_config_set_points),
 63 };
 64 
 65 unsafe extern "C" fn accel_config_destroy(_client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
 66     ffi::wl_resource_destroy(resource);
 67 }
 68 
 69 unsafe extern "C" fn accel_config_set_points(
 70     client: *mut ffi::wl_client,
 71     resource: *mut ffi::wl_resource,
 72     result_id: u32,
 73     accel_type_raw: u32,
 74     step_arr: *mut ffi::wl_array,
 75     points_arr: *mut ffi::wl_array,
 76 ) {
 77     let accel_config = ffi::wl_resource_get_user_data(resource) as *mut LibinputAccelConfig;
 78     if accel_config.is_null() {
 79         return;
 80     }
 81 
 82     let accel_type = match accel_type_raw {
 83         0 => ffi::libinput_config_accel_type_LIBINPUT_ACCEL_TYPE_FALLBACK,
 84         1 => ffi::libinput_config_accel_type_LIBINPUT_ACCEL_TYPE_MOTION,
 85         2 => ffi::libinput_config_accel_type_LIBINPUT_ACCEL_TYPE_SCROLL,
 86         _ => {
 87             ffi::wl_resource_post_error(
 88                 resource,
 89                 ffi::river_libinput_accel_config_v1_error_RIVER_LIBINPUT_ACCEL_CONFIG_V1_ERROR_INVALID_ARG,
 90                 b"invalid accel_type enum value\0".as_ptr() as *const _,
 91             );
 92             return;
 93         }
 94     };
 95 
 96     if (*step_arr).size != std::mem::size_of::<f64>() as usize {
 97         ffi::wl_resource_post_error(
 98             resource,
 99             ffi::river_libinput_accel_config_v1_error_RIVER_LIBINPUT_ACCEL_CONFIG_V1_ERROR_INVALID_ARG,
100             b"invalid step argument\0".as_ptr() as *const _,
101         );
102         return;
103     }
104 
105     let step = *((*step_arr).data as *const f64);
106 
107     if (*points_arr).size == 0 || (*points_arr).size % std::mem::size_of::<f64>() as usize != 0 {
108         ffi::wl_resource_post_error(
109             resource,
110             ffi::river_libinput_accel_config_v1_error_RIVER_LIBINPUT_ACCEL_CONFIG_V1_ERROR_INVALID_ARG,
111             b"invalid points argument\0".as_ptr() as *const _,
112         );
113         return;
114     }
115 
116     let points_count = (*points_arr).size / std::mem::size_of::<f64>();
117     let points_ptr = (*points_arr).data as *const f64;
118 
119     let result_res = ffi::wl_resource_create(
120         client,
121         &ffi::river_libinput_result_v1_interface,
122         ffi::wl_resource_get_version(resource),
123         result_id,
124     );
125     if result_res.is_null() {
126         ffi::wl_client_post_no_memory(client);
127         return;
128     }
129 
130     let libinput = (*accel_config).libinput;
131     if libinput.is_null() {
132         ffi::wl_resource_post_event(result_res, 2); // invalid
133         ffi::wl_resource_destroy(result_res);
134         return;
135     }
136 
137     let status = ffi::libinput_config_accel_set_points(
138         libinput,
139         accel_type,
140         step,
141         points_count,
142         points_ptr,
143     );
144 
145     match status {
146         ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => {
147             ffi::wl_resource_post_event(result_res, 0); // success
148         }
149         ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => {
150             ffi::wl_resource_post_event(result_res, 1); // unsupported
151         }
152         _ => {
153             ffi::wl_resource_post_event(result_res, 2); // invalid
154         }
155     }
156     ffi::wl_resource_destroy(result_res);
157 }