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 }