1#![allow(non_snake_case, clippy::missing_safety_doc)]
8
9mod backend;
10pub mod capforge;
11pub mod chwd_input;
12#[doc(hidden)]
13pub mod elan_recover;
14pub mod evdev;
15mod evtrans;
16mod ffi_types;
17mod hwdetect;
18mod motion;
19mod quirks;
20mod tpad;
21mod udev;
22#[doc(hidden)]
23pub mod udev_callout;
24
25use crate::ffi_types::{
26 BackendKind, EventPayload, LibinputContext, LibinputDevice, LibinputDeviceGroup, LibinputEvent,
27 LibinputEventType, LibinputInterface, LibinputSeat, LibinputTabletPadModeGroup,
28 LibinputTabletTool,
29};
30
31use std::ffi::CStr;
32use std::os::unix::io::RawFd;
33
34extern "C" {
35 fn input_emit_log(
36 handler: *mut libc::c_void,
37 context: *mut libc::c_void,
38 priority: u32,
39 format: *const libc::c_char,
40 ...
41 );
42}
43
44#[repr(C)]
45pub struct LibinputConfigAreaRectangle {
46 pub x1: f64,
47 pub y1: f64,
48 pub x2: f64,
49 pub y2: f64,
50}
51
52unsafe fn populate_events(ctx: *mut LibinputContext) {
57 if ctx.is_null() {
58 return;
59 }
60 let ctx_ref = &mut *ctx;
61 let mut tmp: std::collections::VecDeque<LibinputEvent> = std::collections::VecDeque::new();
62 if let Ok(mut backend) = ctx_ref.backend.lock() {
63 backend.drain_into_queue(ctx, &mut tmp);
64 }
65 enqueue_events(ctx, tmp);
66}
67
68unsafe fn enqueue_event(ctx: *mut LibinputContext, event: LibinputEvent) {
69 if !event.device.is_null()
70 && event.event_type != LibinputEventType::LIBINPUT_EVENT_DEVICE_REMOVED
71 {
72 libinput_device_ref(event.device);
73 }
74 (*ctx).event_queue.push_back(event);
75}
76
77unsafe fn enqueue_events(
78 ctx: *mut LibinputContext,
79 events: impl IntoIterator<Item = LibinputEvent>,
80) {
81 for event in events {
82 enqueue_event(ctx, event);
83 }
84}
85
86unsafe fn emit_log(ctx: *mut LibinputContext, priority: u32, label: &str, message: &str) {
87 if ctx.is_null() || (*ctx).log_priority > priority {
88 return;
89 }
90
91 let Some(handler) = (*ctx).log_handler else {
92 if (*ctx).default_log_handler_enabled {
93 eprintln!("libinput {label}: {message}");
94 }
95 return;
96 };
97 let Ok(message) = std::ffi::CString::new(format!("{}\n", message.replace('%', "%%"))) else {
98 return;
99 };
100 input_emit_log(
101 handler as *mut libc::c_void,
102 ctx.cast(),
103 priority,
104 message.as_ptr(),
105 );
106}
107
108pub(crate) unsafe fn emit_debug_log(ctx: *mut LibinputContext, message: &str) {
109 emit_log(ctx, 10, "debug", message);
110}
111
112pub(crate) unsafe fn emit_error_log(ctx: *mut LibinputContext, message: &str) {
113 emit_log(ctx, 30, "error", message);
114}
115
116pub(crate) unsafe fn emit_info_log(ctx: *mut LibinputContext, message: &str) {
117 emit_log(ctx, 20, "info", message);
118}
119
120#[no_mangle]
125pub unsafe extern "C" fn libinput_udev_create_context(
126 interface: *const LibinputInterface,
127 user_data: *mut libc::c_void,
128 udev: *mut libc::c_void,
129) -> *mut LibinputContext {
130 if interface.is_null() || udev.is_null() {
131 return std::ptr::null_mut();
132 }
133 let ctx = Box::into_raw(Box::new(LibinputContext::new(
134 interface,
135 user_data,
136 BackendKind::Udev,
137 )));
138 (*(*ctx).seat).context = ctx;
139 ctx
140}
141
142#[no_mangle]
143pub unsafe extern "C" fn libinput_path_create_context(
144 interface: *const LibinputInterface,
145 user_data: *mut libc::c_void,
146) -> *mut LibinputContext {
147 if interface.is_null() {
148 return std::ptr::null_mut();
149 }
150 let ctx = Box::into_raw(Box::new(LibinputContext::new(
151 interface,
152 user_data,
153 BackendKind::Path,
154 )));
155 (*(*ctx).seat).context = ctx;
156 ctx
157}
158
159#[no_mangle]
160pub unsafe extern "C" fn libinput_ref(ctx: *mut LibinputContext) -> *mut LibinputContext {
161 if ctx.is_null() {
162 return std::ptr::null_mut();
163 }
164 (*ctx).inc_ref();
165 ctx
166}
167
168#[no_mangle]
169pub unsafe extern "C" fn libinput_unref(ctx: *mut LibinputContext) -> *mut LibinputContext {
170 if ctx.is_null() {
171 return std::ptr::null_mut();
172 }
173 if (*ctx).dec_ref() == 0 {
174 drop(Box::from_raw(ctx));
175 return std::ptr::null_mut();
176 }
177 ctx
178}
179
180#[no_mangle]
181pub unsafe extern "C" fn libinput_udev_assign_seat(
182 ctx: *mut LibinputContext,
183 seat_name: *const libc::c_char,
184) -> libc::c_int {
185 if ctx.is_null()
186 || seat_name.is_null()
187 || (*ctx).backend_kind != BackendKind::Udev
188 || (*ctx).seat_assigned
189 {
190 return -1;
191 }
192 let seat_name = CStr::from_ptr(seat_name);
193 if seat_name.to_bytes().len() > 255 {
194 return -1;
195 }
196 let name = seat_name.to_string_lossy().into_owned();
197 if let Ok(cname) = std::ffi::CString::new(name) {
198 (*(*ctx).seat).physical_name = cname;
199 }
200 (*ctx).seat_assigned = true;
201 (*ctx).plugins_loaded = true;
202 let mut tmp: Vec<LibinputEvent> = Vec::new();
203 if let Ok(mut backend) = (*ctx).backend.lock() {
204 backend.scan_and_open(ctx, &mut tmp);
205 }
206 for ev in tmp {
207 enqueue_event(ctx, ev);
208 }
209 0
210}
211
212#[no_mangle]
213pub unsafe extern "C" fn libinput_path_add_device(
214 ctx: *mut LibinputContext,
215 path: *const libc::c_char,
216) -> *mut LibinputDevice {
217 if ctx.is_null() || path.is_null() || (*ctx).backend_kind != BackendKind::Path {
218 return std::ptr::null_mut();
219 }
220 let path = CStr::from_ptr(path);
221 if path.to_bytes().len() > libc::PATH_MAX as usize {
222 emit_error_log(
223 ctx,
224 &format!(
225 "client bug: Unexpected path, limited to {} characters.",
226 libc::PATH_MAX
227 ),
228 );
229 return std::ptr::null_mut();
230 }
231 let devnode = path.to_string_lossy().into_owned();
232 (*ctx).plugins_loaded = true;
233 let p = std::path::PathBuf::from(&devnode);
234 use std::os::unix::fs::FileTypeExt;
235 if !p
236 .metadata()
237 .is_ok_and(|metadata| metadata.file_type().is_char_device())
238 {
239 emit_error_log(ctx, "failed to add device");
240 return std::ptr::null_mut();
241 }
242 let mut tmp: Vec<LibinputEvent> = Vec::new();
243 let old_len = (*ctx).devices.len();
244 if let Ok(mut backend) = (*ctx).backend.lock() {
245 backend.try_open(ctx, &p, &mut tmp);
246 }
247 for ev in tmp {
248 enqueue_event(ctx, ev);
249 }
250 if (*ctx).devices.len() == old_len + 1 {
251 if let Ok(mut backend) = (*ctx).backend.lock() {
252 backend.remember_path(&p);
253 }
254 emit_info_log(ctx, "device added");
255 (&(*ctx).devices)[old_len]
256 } else {
257 emit_error_log(ctx, "failed to add device");
258 std::ptr::null_mut()
259 }
260}
261
262#[no_mangle]
263pub unsafe extern "C" fn libinput_path_remove_device(dev: *mut LibinputDevice) {
264 if dev.is_null() {
265 return;
266 }
267 let ctx = (*dev).context;
268 if ctx.is_null() || (*ctx).backend_kind != BackendKind::Path {
269 return;
270 }
271 let path = std::path::PathBuf::from((*dev).devnode.to_string_lossy().into_owned());
272 let mut events = std::collections::VecDeque::new();
273 let removed = if let Ok(mut backend) = (*ctx).backend.lock() {
274 backend.forget_path(&path);
275 backend.remove_device(ctx, dev, &mut events)
276 } else {
277 false
278 };
279 if removed {
280 (*ctx).devices.retain(|candidate| *candidate != dev);
281 enqueue_events(ctx, events);
282 libinput_device_unref(dev);
283 }
284}
285
286#[no_mangle]
291pub unsafe extern "C" fn libinput_get_fd(ctx: *mut LibinputContext) -> RawFd {
292 if ctx.is_null() {
293 return -1;
294 }
295 (*ctx).epoll_fd
296}
297
298#[no_mangle]
299pub unsafe extern "C" fn libinput_dispatch(ctx: *mut LibinputContext) -> libc::c_int {
300 if ctx.is_null() {
301 return -1;
302 }
303 let mut events: [libc::epoll_event; 16] = std::mem::zeroed();
304 if libc::epoll_wait((*ctx).epoll_fd, events.as_mut_ptr(), 16, 0) < 0 {
305 return -std::io::Error::last_os_error()
306 .raw_os_error()
307 .unwrap_or(libc::EIO);
308 }
309 (*ctx).drain_fd();
310 populate_events(ctx);
311 0
312}
313
314#[no_mangle]
319pub unsafe extern "C" fn libinput_get_event(ctx: *mut LibinputContext) -> *mut LibinputEvent {
320 if ctx.is_null() {
321 return std::ptr::null_mut();
322 }
323 match (*ctx).event_queue.pop_front() {
324 Some(ev) => Box::into_raw(Box::new(ev)),
325 None => std::ptr::null_mut(),
326 }
327}
328
329#[no_mangle]
330pub unsafe extern "C" fn libinput_next_event_type(ctx: *mut LibinputContext) -> LibinputEventType {
331 if ctx.is_null() {
332 return LibinputEventType::LIBINPUT_EVENT_NONE;
333 }
334 (*ctx)
335 .event_queue
336 .front()
337 .map(|e| e.event_type)
338 .unwrap_or(LibinputEventType::LIBINPUT_EVENT_NONE)
339}
340
341#[no_mangle]
342pub unsafe extern "C" fn libinput_event_destroy(event: *mut LibinputEvent) {
343 if !event.is_null() {
344 let mut event = Box::from_raw(event);
345 event.release_queued_device_ref();
346 }
347}
348
349#[no_mangle]
350pub unsafe extern "C" fn libinput_event_get_type(event: *const LibinputEvent) -> LibinputEventType {
351 if event.is_null() {
352 return LibinputEventType::LIBINPUT_EVENT_NONE;
353 }
354 (*event).event_type
355}
356
357#[no_mangle]
358pub unsafe extern "C" fn libinput_event_get_context(
359 event: *const LibinputEvent,
360) -> *mut LibinputContext {
361 if event.is_null() {
362 return std::ptr::null_mut();
363 }
364 (*event).context
365}
366
367#[no_mangle]
368pub unsafe extern "C" fn libinput_event_get_device(
369 event: *const LibinputEvent,
370) -> *mut LibinputDevice {
371 if event.is_null() {
372 return std::ptr::null_mut();
373 }
374 (*event).device
375}
376
377#[no_mangle]
378pub unsafe extern "C" fn libinput_event_get_device_notify_event(
379 event: *mut LibinputEvent,
380) -> *mut LibinputEvent {
381 if event.is_null() {
382 return std::ptr::null_mut();
383 }
384 match (*event).event_type {
385 LibinputEventType::LIBINPUT_EVENT_DEVICE_ADDED
386 | LibinputEventType::LIBINPUT_EVENT_DEVICE_REMOVED => event,
387 _ => std::ptr::null_mut(),
388 }
389}
390
391#[no_mangle]
392pub unsafe extern "C" fn libinput_event_device_notify_get_base_event(
393 event: *mut LibinputEvent,
394) -> *mut LibinputEvent {
395 event
396}
397
398fn apply_absolute_calibration(
403 x: f64,
404 y: f64,
405 x_min: f64,
406 x_max: f64,
407 y_min: f64,
408 y_max: f64,
409 matrix: [f32; 6],
410) -> (f64, f64) {
411 let x_range = x_max - x_min + 1.0;
412 let y_range = y_max - y_min + 1.0;
413 if x_range <= 0.0 || y_range <= 0.0 {
414 return (x, y);
415 }
416 let normalized_x = (x - x_min) / x_range;
417 let normalized_y = (y - y_min) / y_range;
418 let matrix = matrix.map(f64::from);
419 (
420 (matrix[0] * normalized_x + matrix[1] * normalized_y + matrix[2]) * x_range + x_min,
421 (matrix[3] * normalized_x + matrix[4] * normalized_y + matrix[5]) * y_range + y_min,
422 )
423}
424
425#[no_mangle]
426pub unsafe extern "C" fn libinput_event_get_pointer_event(
427 event: *mut LibinputEvent,
428) -> *mut LibinputEvent {
429 if event.is_null() {
430 return std::ptr::null_mut();
431 }
432 match (*event).event_type {
433 LibinputEventType::LIBINPUT_EVENT_POINTER_MOTION
434 | LibinputEventType::LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE
435 | LibinputEventType::LIBINPUT_EVENT_POINTER_BUTTON
436 | LibinputEventType::LIBINPUT_EVENT_POINTER_AXIS
437 | LibinputEventType::LIBINPUT_EVENT_POINTER_SCROLL_WHEEL
438 | LibinputEventType::LIBINPUT_EVENT_POINTER_SCROLL_FINGER
439 | LibinputEventType::LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS => event,
440 _ => std::ptr::null_mut(),
441 }
442}
443
444#[no_mangle]
445pub unsafe extern "C" fn libinput_event_pointer_get_base_event(
446 event: *mut LibinputEvent,
447) -> *mut LibinputEvent {
448 event
449}
450
451#[no_mangle]
452pub unsafe extern "C" fn libinput_event_pointer_get_time(event: *const LibinputEvent) -> u32 {
453 if event.is_null() {
454 return 0;
455 }
456 match &(*event).payload {
457 EventPayload::PointerMotion(e) => (e.time_usec / 1000) as u32,
458 EventPayload::PointerMotionAbsolute(e) => (e.time_usec / 1000) as u32,
459 EventPayload::PointerButton(e) => (e.time_usec / 1000) as u32,
460 EventPayload::PointerAxis(e) => (e.time_usec / 1000) as u32,
461 _ => 0,
462 }
463}
464
465#[no_mangle]
466pub unsafe extern "C" fn libinput_event_pointer_get_time_usec(event: *const LibinputEvent) -> u64 {
467 if event.is_null() {
468 return 0;
469 }
470 match &(*event).payload {
471 EventPayload::PointerMotion(e) => e.time_usec,
472 EventPayload::PointerMotionAbsolute(e) => e.time_usec,
473 EventPayload::PointerButton(e) => e.time_usec,
474 EventPayload::PointerAxis(e) => e.time_usec,
475 _ => 0,
476 }
477}
478
479#[no_mangle]
480pub unsafe extern "C" fn libinput_event_pointer_get_dx(event: *const LibinputEvent) -> f64 {
481 if event.is_null() {
482 return 0.0;
483 }
484 if let EventPayload::PointerMotion(e) = &(*event).payload {
485 e.dx
486 } else {
487 0.0
488 }
489}
490
491#[no_mangle]
492pub unsafe extern "C" fn libinput_event_pointer_get_dy(event: *const LibinputEvent) -> f64 {
493 if event.is_null() {
494 return 0.0;
495 }
496 if let EventPayload::PointerMotion(e) = &(*event).payload {
497 e.dy
498 } else {
499 0.0
500 }
501}
502
503#[no_mangle]
504pub unsafe extern "C" fn libinput_event_pointer_get_dx_unaccelerated(
505 event: *const LibinputEvent,
506) -> f64 {
507 if event.is_null() {
508 return 0.0;
509 }
510 if let EventPayload::PointerMotion(e) = &(*event).payload {
511 e.dx_unaccel
512 } else {
513 0.0
514 }
515}
516
517#[no_mangle]
518pub unsafe extern "C" fn libinput_event_pointer_get_dy_unaccelerated(
519 event: *const LibinputEvent,
520) -> f64 {
521 if event.is_null() {
522 return 0.0;
523 }
524 if let EventPayload::PointerMotion(e) = &(*event).payload {
525 e.dy_unaccel
526 } else {
527 0.0
528 }
529}
530
531#[no_mangle]
532pub unsafe extern "C" fn libinput_event_pointer_get_absolute_x(event: *const LibinputEvent) -> f64 {
533 if event.is_null() {
534 return 0.0;
535 }
536 if let EventPayload::PointerMotionAbsolute(e) = &(*event).payload {
537 let (x, _) = apply_absolute_calibration(
538 e.abs_x,
539 e.abs_y,
540 e.x_min,
541 e.x_max,
542 e.y_min,
543 e.y_max,
544 e.calibration,
545 );
546 let resolution = if (*event).device.is_null() {
547 None
548 } else {
549 (*(*event).device).abs_x_resolution
550 };
551 resolution
552 .filter(|resolution| *resolution > 0)
553 .map_or(x - e.x_min, |resolution| {
554 (x - e.x_min) / f64::from(resolution)
555 })
556 } else {
557 0.0
558 }
559}
560
561#[no_mangle]
562pub unsafe extern "C" fn libinput_event_pointer_get_absolute_y(event: *const LibinputEvent) -> f64 {
563 if event.is_null() {
564 return 0.0;
565 }
566 if let EventPayload::PointerMotionAbsolute(e) = &(*event).payload {
567 let (_, y) = apply_absolute_calibration(
568 e.abs_x,
569 e.abs_y,
570 e.x_min,
571 e.x_max,
572 e.y_min,
573 e.y_max,
574 e.calibration,
575 );
576 let resolution = if (*event).device.is_null() {
577 None
578 } else {
579 (*(*event).device).abs_y_resolution
580 };
581 resolution
582 .filter(|resolution| *resolution > 0)
583 .map_or(y - e.y_min, |resolution| {
584 (y - e.y_min) / f64::from(resolution)
585 })
586 } else {
587 0.0
588 }
589}
590
591#[no_mangle]
592pub unsafe extern "C" fn libinput_event_pointer_get_button(event: *const LibinputEvent) -> u32 {
593 if event.is_null() {
594 return 0;
595 }
596 if let EventPayload::PointerButton(e) = &(*event).payload {
597 e.button
598 } else {
599 0
600 }
601}
602
603#[no_mangle]
604pub unsafe extern "C" fn libinput_event_pointer_get_button_state(
605 event: *const LibinputEvent,
606) -> u32 {
607 if event.is_null() {
608 return 0;
609 }
610 if let EventPayload::PointerButton(e) = &(*event).payload {
611 e.state
612 } else {
613 0
614 }
615}
616
617#[no_mangle]
618pub unsafe extern "C" fn libinput_event_pointer_get_seat_button_count(
619 event: *const LibinputEvent,
620) -> u32 {
621 if event.is_null() {
622 return 0;
623 }
624 if let EventPayload::PointerButton(e) = &(*event).payload {
625 e.seat_button_count
626 } else {
627 0
628 }
629}
630
631#[no_mangle]
632pub unsafe extern "C" fn libinput_event_pointer_get_axis_value(
633 event: *const LibinputEvent,
634 axis: u32,
635) -> f64 {
636 if event.is_null() {
637 return 0.0;
638 }
639 if let EventPayload::PointerAxis(e) = &(*event).payload {
640 e.value(axis)
641 } else {
642 0.0
643 }
644}
645
646#[no_mangle]
647pub unsafe extern "C" fn libinput_event_pointer_get_axis_value_discrete(
648 event: *const LibinputEvent,
649 axis: u32,
650) -> f64 {
651 if event.is_null() {
652 return 0.0;
653 }
654 if let EventPayload::PointerAxis(e) = &(*event).payload {
655 e.value_discrete(axis) as f64
656 } else {
657 0.0
658 }
659}
660
661#[no_mangle]
662pub unsafe extern "C" fn libinput_event_pointer_get_axis_source(
663 event: *const LibinputEvent,
664) -> u32 {
665 if event.is_null() {
666 return 0;
667 }
668 if let EventPayload::PointerAxis(e) = &(*event).payload {
669 e.source
670 } else {
671 0
672 }
673}
674
675#[no_mangle]
676pub unsafe extern "C" fn libinput_event_pointer_has_axis(
677 event: *const LibinputEvent,
678 axis: u32,
679) -> libc::c_int {
680 if event.is_null() {
681 return 0;
682 }
683 matches!(&(*event).payload, EventPayload::PointerAxis(e) if e.has_axis(axis)) as libc::c_int
684}
685
686#[no_mangle]
691pub unsafe extern "C" fn libinput_event_get_keyboard_event(
692 event: *mut LibinputEvent,
693) -> *mut LibinputEvent {
694 if event.is_null() {
695 return std::ptr::null_mut();
696 }
697 if (*event).event_type == LibinputEventType::LIBINPUT_EVENT_KEYBOARD_KEY {
698 event
699 } else {
700 std::ptr::null_mut()
701 }
702}
703
704#[no_mangle]
705pub unsafe extern "C" fn libinput_event_keyboard_get_base_event(
706 event: *mut LibinputEvent,
707) -> *mut LibinputEvent {
708 event
709}
710
711#[no_mangle]
712pub unsafe extern "C" fn libinput_event_keyboard_get_time(event: *const LibinputEvent) -> u32 {
713 if event.is_null() {
714 return 0;
715 }
716 if let EventPayload::KeyboardKey(e) = &(*event).payload {
717 (e.time_usec / 1000) as u32
718 } else {
719 0
720 }
721}
722
723#[no_mangle]
724pub unsafe extern "C" fn libinput_event_keyboard_get_time_usec(event: *const LibinputEvent) -> u64 {
725 if event.is_null() {
726 return 0;
727 }
728 if let EventPayload::KeyboardKey(e) = &(*event).payload {
729 e.time_usec
730 } else {
731 0
732 }
733}
734
735#[no_mangle]
736pub unsafe extern "C" fn libinput_event_keyboard_get_key(event: *const LibinputEvent) -> u32 {
737 if event.is_null() {
738 return 0;
739 }
740 if let EventPayload::KeyboardKey(e) = &(*event).payload {
741 e.key
742 } else {
743 0
744 }
745}
746
747#[no_mangle]
748pub unsafe extern "C" fn libinput_event_keyboard_get_key_state(event: *const LibinputEvent) -> u32 {
749 if event.is_null() {
750 return 0;
751 }
752 if let EventPayload::KeyboardKey(e) = &(*event).payload {
753 e.state
754 } else {
755 0
756 }
757}
758
759#[no_mangle]
760pub unsafe extern "C" fn libinput_event_keyboard_get_seat_key_count(
761 event: *const LibinputEvent,
762) -> u32 {
763 if event.is_null() {
764 return 0;
765 }
766 if let EventPayload::KeyboardKey(e) = &(*event).payload {
767 e.seat_key_count
768 } else {
769 0
770 }
771}
772
773#[no_mangle]
778pub unsafe extern "C" fn libinput_event_get_touch_event(
779 event: *mut LibinputEvent,
780) -> *mut LibinputEvent {
781 if event.is_null() {
782 return std::ptr::null_mut();
783 }
784 match (*event).event_type {
785 LibinputEventType::LIBINPUT_EVENT_TOUCH_DOWN
786 | LibinputEventType::LIBINPUT_EVENT_TOUCH_UP
787 | LibinputEventType::LIBINPUT_EVENT_TOUCH_MOTION
788 | LibinputEventType::LIBINPUT_EVENT_TOUCH_CANCEL
789 | LibinputEventType::LIBINPUT_EVENT_TOUCH_FRAME => event,
790 _ => std::ptr::null_mut(),
791 }
792}
793
794#[no_mangle]
795pub unsafe extern "C" fn libinput_event_touch_get_base_event(
796 event: *mut LibinputEvent,
797) -> *mut LibinputEvent {
798 event
799}
800
801#[no_mangle]
802pub unsafe extern "C" fn libinput_event_touch_get_time(event: *const LibinputEvent) -> u32 {
803 if event.is_null() {
804 return 0;
805 }
806 match &(*event).payload {
807 EventPayload::TouchDown(e)
808 | EventPayload::TouchUp(e)
809 | EventPayload::TouchMotion(e)
810 | EventPayload::TouchCancel(e) => (e.time_usec / 1000) as u32,
811 EventPayload::TouchFrame { time_usec } => (*time_usec / 1000) as u32,
812 _ => 0,
813 }
814}
815
816#[no_mangle]
817pub unsafe extern "C" fn libinput_event_touch_get_time_usec(event: *const LibinputEvent) -> u64 {
818 if event.is_null() {
819 return 0;
820 }
821 match &(*event).payload {
822 EventPayload::TouchDown(e)
823 | EventPayload::TouchUp(e)
824 | EventPayload::TouchMotion(e)
825 | EventPayload::TouchCancel(e) => e.time_usec,
826 EventPayload::TouchFrame { time_usec } => *time_usec,
827 _ => 0,
828 }
829}
830
831#[no_mangle]
832pub unsafe extern "C" fn libinput_event_touch_get_slot(event: *const LibinputEvent) -> i32 {
833 if event.is_null() {
834 return -1;
835 }
836 match &(*event).payload {
837 EventPayload::TouchDown(e)
838 | EventPayload::TouchMotion(e)
839 | EventPayload::TouchUp(e)
840 | EventPayload::TouchCancel(e) => e.slot,
841 _ => -1,
842 }
843}
844
845#[no_mangle]
846pub unsafe extern "C" fn libinput_event_touch_get_seat_slot(event: *const LibinputEvent) -> i32 {
847 if event.is_null() {
848 return -1;
849 }
850 match &(*event).payload {
851 EventPayload::TouchDown(e)
852 | EventPayload::TouchMotion(e)
853 | EventPayload::TouchUp(e)
854 | EventPayload::TouchCancel(e) => e.seat_slot,
855 _ => -1,
856 }
857}
858
859#[no_mangle]
860pub unsafe extern "C" fn libinput_event_touch_get_x(event: *const LibinputEvent) -> f64 {
861 if event.is_null() {
862 return 0.0;
863 }
864 match &(*event).payload {
865 EventPayload::TouchDown(e) | EventPayload::TouchMotion(e) => {
866 let device = (*event).device;
867 if !device.is_null() {
868 if let (Some((x_min, x_max)), Some((y_min, y_max)), Some(resolution)) = (
869 (*device).abs_x_range,
870 (*device).abs_y_range,
871 (*device).abs_x_resolution,
872 ) {
873 let (x, _) = apply_absolute_calibration(
874 e.x,
875 e.y,
876 x_min.into(),
877 x_max.into(),
878 y_min.into(),
879 y_max.into(),
880 e.calibration,
881 );
882 return (x - f64::from(x_min)) / f64::from(resolution);
883 }
884 }
885 e.x
886 }
887 _ => 0.0,
888 }
889}
890
891#[no_mangle]
892pub unsafe extern "C" fn libinput_event_touch_get_y(event: *const LibinputEvent) -> f64 {
893 if event.is_null() {
894 return 0.0;
895 }
896 match &(*event).payload {
897 EventPayload::TouchDown(e) | EventPayload::TouchMotion(e) => {
898 let device = (*event).device;
899 if !device.is_null() {
900 if let (Some((x_min, x_max)), Some((y_min, y_max)), Some(resolution)) = (
901 (*device).abs_x_range,
902 (*device).abs_y_range,
903 (*device).abs_y_resolution,
904 ) {
905 let (_, y) = apply_absolute_calibration(
906 e.x,
907 e.y,
908 x_min.into(),
909 x_max.into(),
910 y_min.into(),
911 y_max.into(),
912 e.calibration,
913 );
914 return (y - f64::from(y_min)) / f64::from(resolution);
915 }
916 }
917 e.y
918 }
919 _ => 0.0,
920 }
921}
922
923unsafe fn transformed_touch_coordinates(event: *const LibinputEvent) -> Option<(f64, f64)> {
924 let touch = match &(*event).payload {
925 EventPayload::TouchDown(e) | EventPayload::TouchMotion(e) => e,
926 _ => return None,
927 };
928 let device = (*event).device;
929 if device.is_null() {
930 return None;
931 }
932 let ((xmin, xmax), (ymin, ymax)) = ((*device).abs_x_range?, (*device).abs_y_range?);
933 let x_span = (xmax as i64 - xmin as i64 + 1).max(1) as f64;
934 let y_span = (ymax as i64 - ymin as i64 + 1).max(1) as f64;
935 let (x, y) = apply_absolute_calibration(
936 touch.x,
937 touch.y,
938 xmin.into(),
939 xmax.into(),
940 ymin.into(),
941 ymax.into(),
942 touch.calibration,
943 );
944 Some((
945 (x - f64::from(xmin)) / x_span,
946 (y - f64::from(ymin)) / y_span,
947 ))
948}
949
950#[no_mangle]
951pub unsafe extern "C" fn libinput_event_touch_get_x_transformed(
952 event: *const LibinputEvent,
953 width: u32,
954) -> f64 {
955 if event.is_null() {
956 return 0.0;
957 }
958 transformed_touch_coordinates(event)
959 .map(|(x, _)| x * width as f64)
960 .unwrap_or(0.0)
961}
962
963#[no_mangle]
964pub unsafe extern "C" fn libinput_event_touch_get_y_transformed(
965 event: *const LibinputEvent,
966 height: u32,
967) -> f64 {
968 if event.is_null() {
969 return 0.0;
970 }
971 transformed_touch_coordinates(event)
972 .map(|(_, y)| y * height as f64)
973 .unwrap_or(0.0)
974}
975
976#[no_mangle]
981pub unsafe extern "C" fn libinput_event_get_gesture_event(
982 event: *mut LibinputEvent,
983) -> *mut LibinputEvent {
984 if event.is_null() {
985 return std::ptr::null_mut();
986 }
987 match (*event).event_type {
988 LibinputEventType::LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN
989 | LibinputEventType::LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE
990 | LibinputEventType::LIBINPUT_EVENT_GESTURE_SWIPE_END
991 | LibinputEventType::LIBINPUT_EVENT_GESTURE_PINCH_BEGIN
992 | LibinputEventType::LIBINPUT_EVENT_GESTURE_PINCH_UPDATE
993 | LibinputEventType::LIBINPUT_EVENT_GESTURE_PINCH_END
994 | LibinputEventType::LIBINPUT_EVENT_GESTURE_HOLD_BEGIN
995 | LibinputEventType::LIBINPUT_EVENT_GESTURE_HOLD_END => event,
996 _ => std::ptr::null_mut(),
997 }
998}
999
1000#[no_mangle]
1001pub unsafe extern "C" fn libinput_event_gesture_get_base_event(
1002 event: *mut LibinputEvent,
1003) -> *mut LibinputEvent {
1004 event
1005}
1006
1007#[no_mangle]
1008pub unsafe extern "C" fn libinput_event_gesture_get_time(event: *const LibinputEvent) -> u32 {
1009 if event.is_null() {
1010 return 0;
1011 }
1012 match &(*event).payload {
1013 EventPayload::GestureSwipeBegin(e)
1014 | EventPayload::GestureSwipeUpdate(e)
1015 | EventPayload::GestureSwipeEnd(e)
1016 | EventPayload::GesturePinchBegin(e)
1017 | EventPayload::GesturePinchUpdate(e)
1018 | EventPayload::GesturePinchEnd(e)
1019 | EventPayload::GestureHoldBegin(e)
1020 | EventPayload::GestureHoldEnd(e) => (e.time_usec / 1000) as u32,
1021 _ => 0,
1022 }
1023}
1024
1025#[no_mangle]
1026pub unsafe extern "C" fn libinput_event_gesture_get_time_usec(event: *const LibinputEvent) -> u64 {
1027 if event.is_null() {
1028 return 0;
1029 }
1030 match &(*event).payload {
1031 EventPayload::GestureSwipeBegin(e)
1032 | EventPayload::GestureSwipeUpdate(e)
1033 | EventPayload::GestureSwipeEnd(e)
1034 | EventPayload::GesturePinchBegin(e)
1035 | EventPayload::GesturePinchUpdate(e)
1036 | EventPayload::GesturePinchEnd(e)
1037 | EventPayload::GestureHoldBegin(e)
1038 | EventPayload::GestureHoldEnd(e) => e.time_usec,
1039 _ => 0,
1040 }
1041}
1042
1043#[no_mangle]
1044pub unsafe extern "C" fn libinput_event_gesture_get_finger_count(
1045 event: *const LibinputEvent,
1046) -> libc::c_int {
1047 if event.is_null() {
1048 return 0;
1049 }
1050 match &(*event).payload {
1051 EventPayload::GestureSwipeBegin(e)
1052 | EventPayload::GestureSwipeUpdate(e)
1053 | EventPayload::GestureSwipeEnd(e)
1054 | EventPayload::GesturePinchBegin(e)
1055 | EventPayload::GesturePinchUpdate(e)
1056 | EventPayload::GesturePinchEnd(e)
1057 | EventPayload::GestureHoldBegin(e)
1058 | EventPayload::GestureHoldEnd(e) => e.finger_count,
1059 _ => 0,
1060 }
1061}
1062
1063#[no_mangle]
1064pub unsafe extern "C" fn libinput_event_gesture_get_dx(event: *const LibinputEvent) -> f64 {
1065 if event.is_null() {
1066 return 0.0;
1067 }
1068 match &(*event).payload {
1069 EventPayload::GestureSwipeUpdate(e) | EventPayload::GesturePinchUpdate(e) => e.dx,
1070 _ => 0.0,
1071 }
1072}
1073
1074#[no_mangle]
1075pub unsafe extern "C" fn libinput_event_gesture_get_dy(event: *const LibinputEvent) -> f64 {
1076 if event.is_null() {
1077 return 0.0;
1078 }
1079 match &(*event).payload {
1080 EventPayload::GestureSwipeUpdate(e) | EventPayload::GesturePinchUpdate(e) => e.dy,
1081 _ => 0.0,
1082 }
1083}
1084
1085#[no_mangle]
1086pub unsafe extern "C" fn libinput_event_gesture_get_dx_unaccelerated(
1087 event: *const LibinputEvent,
1088) -> f64 {
1089 if event.is_null() {
1090 return 0.0;
1091 }
1092 match &(*event).payload {
1093 EventPayload::GestureSwipeUpdate(e) | EventPayload::GesturePinchUpdate(e) => e.dx_unaccel,
1094 _ => 0.0,
1095 }
1096}
1097
1098#[no_mangle]
1099pub unsafe extern "C" fn libinput_event_gesture_get_dy_unaccelerated(
1100 event: *const LibinputEvent,
1101) -> f64 {
1102 if event.is_null() {
1103 return 0.0;
1104 }
1105 match &(*event).payload {
1106 EventPayload::GestureSwipeUpdate(e) | EventPayload::GesturePinchUpdate(e) => e.dy_unaccel,
1107 _ => 0.0,
1108 }
1109}
1110
1111#[no_mangle]
1112pub unsafe extern "C" fn libinput_event_gesture_get_scale(event: *const LibinputEvent) -> f64 {
1113 if event.is_null() {
1114 return 1.0;
1115 }
1116 match &(*event).payload {
1117 EventPayload::GesturePinchUpdate(e) | EventPayload::GesturePinchEnd(e) => e.scale,
1118 _ => 1.0,
1119 }
1120}
1121
1122#[no_mangle]
1123pub unsafe extern "C" fn libinput_event_gesture_get_angle_delta(
1124 event: *const LibinputEvent,
1125) -> f64 {
1126 if event.is_null() {
1127 return 0.0;
1128 }
1129 match &(*event).payload {
1130 EventPayload::GesturePinchUpdate(e) => e.angle,
1131 _ => 0.0,
1132 }
1133}
1134
1135#[no_mangle]
1136pub unsafe extern "C" fn libinput_event_gesture_get_cancelled(
1137 event: *const LibinputEvent,
1138) -> libc::c_int {
1139 if event.is_null() {
1140 return 0;
1141 }
1142 match &(*event).payload {
1143 EventPayload::GestureSwipeEnd(e)
1144 | EventPayload::GesturePinchEnd(e)
1145 | EventPayload::GestureHoldEnd(e) => e.cancelled as libc::c_int,
1146 _ => 0,
1147 }
1148}
1149
1150#[no_mangle]
1155pub unsafe extern "C" fn libinput_event_get_switch_event(
1156 event: *mut LibinputEvent,
1157) -> *mut LibinputEvent {
1158 if event.is_null() {
1159 return std::ptr::null_mut();
1160 }
1161 if (*event).event_type == LibinputEventType::LIBINPUT_EVENT_SWITCH_TOGGLE {
1162 event
1163 } else {
1164 std::ptr::null_mut()
1165 }
1166}
1167
1168#[no_mangle]
1169pub unsafe extern "C" fn libinput_event_switch_get_base_event(
1170 event: *mut LibinputEvent,
1171) -> *mut LibinputEvent {
1172 event
1173}
1174
1175#[no_mangle]
1176pub unsafe extern "C" fn libinput_event_switch_get_switch(event: *const LibinputEvent) -> u32 {
1177 if event.is_null() {
1178 return 0;
1179 }
1180 if let EventPayload::SwitchToggle(e) = &(*event).payload {
1181 e.switch
1182 } else {
1183 0
1184 }
1185}
1186
1187#[no_mangle]
1188pub unsafe extern "C" fn libinput_event_switch_get_switch_state(
1189 event: *const LibinputEvent,
1190) -> u32 {
1191 if event.is_null() {
1192 return 0;
1193 }
1194 if let EventPayload::SwitchToggle(e) = &(*event).payload {
1195 e.state
1196 } else {
1197 0
1198 }
1199}
1200
1201#[no_mangle]
1206pub unsafe extern "C" fn libinput_device_ref(dev: *mut LibinputDevice) -> *mut LibinputDevice {
1207 if dev.is_null() {
1208 return std::ptr::null_mut();
1209 }
1210 let current = (*dev)
1211 .refcount
1212 .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
1213 (*dev).abi.refcount = current + 1;
1214 dev
1215}
1216
1217#[no_mangle]
1218pub unsafe extern "C" fn libinput_device_unref(dev: *mut LibinputDevice) -> *mut LibinputDevice {
1219 if dev.is_null() {
1220 return std::ptr::null_mut();
1221 }
1222 let remaining = (*dev)
1223 .refcount
1224 .fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
1225 - 1;
1226 (*dev).abi.refcount = remaining;
1227 if remaining <= 0 {
1228 drop(Box::from_raw(dev));
1229 std::ptr::null_mut()
1230 } else {
1231 dev
1232 }
1233}
1234
1235#[no_mangle]
1236pub unsafe extern "C" fn libinput_device_get_name(
1237 dev: *const LibinputDevice,
1238) -> *const libc::c_char {
1239 if dev.is_null() {
1240 return std::ptr::null();
1241 }
1242 (*dev).name.as_ptr()
1243}
1244
1245#[no_mangle]
1246pub unsafe extern "C" fn libinput_device_get_sysname(
1247 dev: *const LibinputDevice,
1248) -> *const libc::c_char {
1249 if dev.is_null() {
1250 return std::ptr::null();
1251 }
1252 (*dev).sysname.as_ptr()
1253}
1254
1255#[no_mangle]
1256pub unsafe extern "C" fn libinput_device_get_output_name(
1257 dev: *const LibinputDevice,
1258) -> *const libc::c_char {
1259 if dev.is_null() {
1260 return std::ptr::null();
1261 }
1262 (*dev)
1263 .output_name
1264 .as_ref()
1265 .map_or(std::ptr::null(), |name| name.as_ptr())
1266}
1267
1268#[no_mangle]
1269pub unsafe extern "C" fn libinput_device_get_id_vendor(dev: *const LibinputDevice) -> libc::c_uint {
1270 if dev.is_null() {
1271 return 0;
1272 }
1273 (*dev).vendor_id
1274}
1275
1276#[no_mangle]
1277pub unsafe extern "C" fn libinput_device_get_id_product(
1278 dev: *const LibinputDevice,
1279) -> libc::c_uint {
1280 if dev.is_null() {
1281 return 0;
1282 }
1283 (*dev).product_id
1284}
1285
1286#[no_mangle]
1287pub unsafe extern "C" fn libinput_device_get_context(
1288 dev: *const LibinputDevice,
1289) -> *mut LibinputContext {
1290 if dev.is_null() {
1291 return std::ptr::null_mut();
1292 }
1293 (*dev).context
1294}
1295
1296#[no_mangle]
1297pub unsafe extern "C" fn libinput_device_touch_get_touch_count(
1298 dev: *const LibinputDevice,
1299) -> libc::c_int {
1300 if dev.is_null() || !(*dev).has_touch {
1301 return -1;
1302 }
1303 (*dev).touch_count
1304}
1305
1306#[no_mangle]
1307pub unsafe extern "C" fn libinput_device_has_capability(
1308 dev: *const LibinputDevice,
1309 capability: u32,
1310) -> libc::c_int {
1311 if dev.is_null() {
1312 return 0;
1313 }
1314 let has = match capability {
1315 0 => (*dev).has_keyboard,
1316 1 => (*dev).has_pointer,
1317 2 => (*dev).has_touch,
1318 3 => (*dev).has_tablet,
1319 4 => (*dev).has_tablet_pad,
1320 5 => (*dev).has_gesture,
1321 6 => (*dev).has_switch,
1322 _ => false,
1323 };
1324 has as libc::c_int
1325}
1326
1327#[no_mangle]
1332pub unsafe extern "C" fn libinput_device_config_tap_get_finger_count(
1333 dev: *const LibinputDevice,
1334) -> libc::c_int {
1335 if dev.is_null() {
1336 return 0;
1337 }
1338 (*dev).tap_finger_count
1339}
1340
1341#[no_mangle]
1342pub unsafe extern "C" fn libinput_device_config_tap_set_enabled(
1343 dev: *mut LibinputDevice,
1344 enabled: u32,
1345) -> u32 {
1346 if dev.is_null() {
1347 return 1;
1348 }
1349 if enabled > 1 {
1350 return 2;
1351 }
1352 if (*dev).tap_finger_count == 0 {
1353 return if enabled == 0 { 0 } else { 1 };
1354 }
1355 (*dev).tap_enabled = enabled != 0;
1356 0
1357}
1358
1359#[no_mangle]
1360pub unsafe extern "C" fn libinput_device_config_tap_get_enabled(dev: *const LibinputDevice) -> u32 {
1361 if dev.is_null() {
1362 return 0;
1363 }
1364 (*dev).tap_enabled as u32
1365}
1366
1367#[no_mangle]
1368pub unsafe extern "C" fn libinput_device_config_tap_get_default_enabled(
1369 dev: *const LibinputDevice,
1370) -> u32 {
1371 if dev.is_null() {
1372 return 0;
1373 }
1374 (*dev).tap_default_enabled as u32
1375}
1376
1377#[no_mangle]
1378pub unsafe extern "C" fn libinput_device_config_tap_set_drag_enabled(
1379 dev: *mut LibinputDevice,
1380 enabled: u32,
1381) -> u32 {
1382 if dev.is_null() {
1383 return 1;
1384 }
1385 if enabled > 1 {
1386 return 2;
1387 }
1388 if (*dev).tap_finger_count == 0 {
1389 return if enabled == 0 { 0 } else { 1 };
1390 }
1391 (*dev).tap_drag_enabled = enabled != 0;
1392 0
1393}
1394
1395#[no_mangle]
1396pub unsafe extern "C" fn libinput_device_config_tap_get_drag_enabled(
1397 dev: *const LibinputDevice,
1398) -> u32 {
1399 if dev.is_null() {
1400 return 0;
1401 }
1402 (*dev).tap_drag_enabled as u32
1403}
1404
1405#[no_mangle]
1406pub unsafe extern "C" fn libinput_device_config_tap_get_default_drag_enabled(
1407 dev: *const LibinputDevice,
1408) -> u32 {
1409 if dev.is_null() {
1410 return 0;
1411 }
1412 ((*dev).tap_finger_count != 0) as u32
1413}
1414
1415#[no_mangle]
1416pub unsafe extern "C" fn libinput_device_config_tap_set_drag_lock_enabled(
1417 dev: *mut LibinputDevice,
1418 enabled: u32,
1419) -> u32 {
1420 if dev.is_null() {
1421 return 1;
1422 }
1423 if enabled > 2 {
1424 return 2;
1425 }
1426 if (*dev).tap_finger_count == 0 {
1427 return if enabled == 0 { 0 } else { 1 };
1428 }
1429 (*dev).tap_drag_lock_enabled = if enabled == 1 { 1 } else { enabled };
1430 0
1431}
1432
1433#[no_mangle]
1434pub unsafe extern "C" fn libinput_device_config_tap_get_drag_lock_enabled(
1435 dev: *const LibinputDevice,
1436) -> u32 {
1437 if dev.is_null() {
1438 return 0;
1439 }
1440 (*dev).tap_drag_lock_enabled
1441}
1442
1443#[no_mangle]
1445pub unsafe extern "C" fn libinput_device_config_tap_set_button_map(
1446 dev: *mut LibinputDevice,
1447 map: u32,
1448) -> u32 {
1449 if dev.is_null() {
1450 return 1;
1451 }
1452 if map > 1 {
1453 return 2;
1454 }
1455 if (*dev).tap_finger_count == 0 {
1456 return 1;
1457 }
1458 (*dev).tap_button_map = map;
1459 0
1460}
1461
1462#[no_mangle]
1463pub unsafe extern "C" fn libinput_device_config_tap_get_button_map(
1464 dev: *const LibinputDevice,
1465) -> u32 {
1466 if dev.is_null() {
1467 return 0;
1468 }
1469 (*dev).tap_button_map
1470}
1471
1472#[no_mangle]
1473pub unsafe extern "C" fn libinput_device_config_tap_get_default_button_map(
1474 _dev: *const LibinputDevice,
1475) -> u32 {
1476 0
1477} #[no_mangle]
1480pub unsafe extern "C" fn libinput_device_config_3fg_drag_get_finger_count(
1481 dev: *const LibinputDevice,
1482) -> libc::c_int {
1483 if dev.is_null() || !(*dev).has_gesture {
1484 return 0;
1485 }
1486 (*dev).mt_slot_count
1487}
1488
1489#[no_mangle]
1490pub unsafe extern "C" fn libinput_device_config_3fg_drag_set_enabled(
1491 dev: *mut LibinputDevice,
1492 enable: u32,
1493) -> u32 {
1494 if dev.is_null() {
1495 return 1;
1496 }
1497 if libinput_device_config_3fg_drag_get_finger_count(dev) < 3 {
1498 return 1;
1499 }
1500 if !matches!(enable, 0..=2) {
1501 return 2;
1502 }
1503 (*dev).drag_3fg_enabled = enable;
1504 0
1505}
1506
1507#[no_mangle]
1508pub unsafe extern "C" fn libinput_device_config_3fg_drag_get_enabled(
1509 dev: *const LibinputDevice,
1510) -> u32 {
1511 if dev.is_null() {
1512 return 0;
1513 }
1514 (*dev).drag_3fg_enabled
1515}
1516
1517#[no_mangle]
1518pub unsafe extern "C" fn libinput_device_config_3fg_drag_get_default_enabled(
1519 _dev: *const LibinputDevice,
1520) -> u32 {
1521 0
1522}
1523
1524#[no_mangle]
1529pub unsafe extern "C" fn libinput_config_accel_create(profile: u32) -> *mut libc::c_void {
1530 if !matches!(profile, 1 | 2 | 4) {
1531 return std::ptr::null_mut();
1532 }
1533 Box::into_raw(Box::new(crate::ffi_types::AccelConfig::new(profile))) as *mut libc::c_void
1534}
1535
1536#[no_mangle]
1537pub unsafe extern "C" fn libinput_config_accel_destroy(accel_config: *mut libc::c_void) {
1538 if !accel_config.is_null() {
1539 drop(Box::from_raw(
1540 accel_config as *mut crate::ffi_types::AccelConfig,
1541 ));
1542 }
1543}
1544
1545#[no_mangle]
1546pub unsafe extern "C" fn libinput_config_accel_set_points(
1547 accel_config: *mut libc::c_void,
1548 accel_type: u32,
1549 step: f64,
1550 npoints: libc::size_t,
1551 points: *const f64,
1552) -> u32 {
1553 if accel_config.is_null()
1554 || points.is_null()
1555 || !step.is_finite()
1556 || step <= 0.0
1557 || step > 10_000.0
1558 || !(2..=64).contains(&npoints)
1559 {
1560 return 2;
1561 }
1562 let config = &mut *(accel_config as *mut crate::ffi_types::AccelConfig);
1563 if config.profile != 4 || !matches!(accel_type, 0..=2) {
1564 return 2;
1565 }
1566 let points = std::slice::from_raw_parts(points, npoints);
1567 if points
1568 .iter()
1569 .any(|point| !point.is_finite() || *point < 0.0 || *point > 10_000.0)
1570 {
1571 return 2;
1572 }
1573 let curve = crate::ffi_types::AccelCurve::new(step, points.to_vec());
1574 match accel_type {
1575 0 => config.fallback = Some(curve),
1576 1 => config.motion = Some(curve),
1577 2 => config.scroll = Some(curve),
1578 _ => unreachable!(),
1579 }
1580 0
1581}
1582
1583#[no_mangle]
1584pub unsafe extern "C" fn libinput_device_config_accel_apply(
1585 dev: *mut LibinputDevice,
1586 accel_config: *mut libc::c_void,
1587) -> u32 {
1588 if dev.is_null() || accel_config.is_null() {
1589 return 2;
1590 }
1591 if !(*dev).accel_available {
1592 return 1;
1593 }
1594 let config = &*(accel_config as *const crate::ffi_types::AccelConfig);
1595 let profile = config.profile;
1596 if profile & libinput_device_config_accel_get_profiles(dev) == 0 {
1597 return 1;
1598 }
1599 (*dev).accel_profile = profile;
1600 (*dev).accel_speed = 0.0;
1601 (*dev).accel_custom = (profile == 4).then(|| config.clone());
1602 0
1603}
1604
1605#[no_mangle]
1606pub unsafe extern "C" fn libinput_device_config_accel_is_available(
1607 dev: *const LibinputDevice,
1608) -> libc::c_int {
1609 if dev.is_null() {
1610 return 0;
1611 }
1612 (*dev).accel_available as libc::c_int
1613}
1614
1615#[no_mangle]
1616pub unsafe extern "C" fn libinput_device_config_accel_set_speed(
1617 dev: *mut LibinputDevice,
1618 speed: f64,
1619) -> u32 {
1620 if dev.is_null() {
1621 return 1;
1622 }
1623 if !speed.is_finite() || !(-1.0..=1.0).contains(&speed) {
1624 return 2;
1625 }
1626 if !(*dev).accel_available {
1627 return 1;
1628 }
1629 (*dev).accel_speed = speed;
1630 0
1631}
1632
1633#[no_mangle]
1634pub unsafe extern "C" fn libinput_device_config_accel_get_speed(dev: *const LibinputDevice) -> f64 {
1635 if dev.is_null() {
1636 return 0.0;
1637 }
1638 (*dev).accel_speed
1639}
1640
1641#[no_mangle]
1642pub unsafe extern "C" fn libinput_device_config_accel_get_default_speed(
1643 _dev: *const LibinputDevice,
1644) -> f64 {
1645 0.0
1646}
1647
1648#[no_mangle]
1649pub unsafe extern "C" fn libinput_device_config_accel_get_profiles(
1650 dev: *const LibinputDevice,
1651) -> u32 {
1652 if dev.is_null() {
1653 return 0;
1654 }
1655 if (*dev).accel_available
1656 && !((*dev).has_tablet && !(*dev).has_gesture && !(*dev).has_tablet_pad)
1657 {
1658 0b111
1659 } else {
1660 0
1661 }
1662}
1663
1664#[no_mangle]
1665pub unsafe extern "C" fn libinput_device_config_accel_set_profile(
1666 dev: *mut LibinputDevice,
1667 profile: u32,
1668) -> u32 {
1669 if dev.is_null() {
1670 return 1;
1671 }
1672 if profile == 0 || profile & !0b111 != 0 || profile.count_ones() != 1 {
1673 return 2;
1674 }
1675 if profile & libinput_device_config_accel_get_profiles(dev) == 0 {
1676 return 1;
1677 }
1678 (*dev).accel_profile = profile;
1679 (*dev).accel_custom = if profile == 4 {
1680 Some(crate::ffi_types::AccelConfig::new(profile))
1681 } else {
1682 None
1683 };
1684 0
1685}
1686
1687#[no_mangle]
1688pub unsafe extern "C" fn libinput_device_config_accel_get_profile(
1689 dev: *const LibinputDevice,
1690) -> u32 {
1691 if dev.is_null() {
1692 return 0;
1693 }
1694 if (*dev).accel_available
1695 && !((*dev).has_tablet && !(*dev).has_gesture && !(*dev).has_tablet_pad)
1696 {
1697 (*dev).accel_profile
1698 } else {
1699 0
1700 }
1701}
1702
1703#[no_mangle]
1704pub unsafe extern "C" fn libinput_device_config_accel_get_default_profile(
1705 dev: *const LibinputDevice,
1706) -> u32 {
1707 if dev.is_null()
1708 || !(*dev).accel_available
1709 || ((*dev).has_tablet && !(*dev).has_gesture && !(*dev).has_tablet_pad)
1710 {
1711 0
1712 } else {
1713 2
1714 }
1715}
1716
1717#[no_mangle]
1722pub unsafe extern "C" fn libinput_device_config_scroll_has_natural_scroll(
1723 dev: *const LibinputDevice,
1724) -> libc::c_int {
1725 if dev.is_null() {
1726 return 0;
1727 }
1728 (*dev).has_pointer as libc::c_int
1729}
1730
1731#[no_mangle]
1732pub unsafe extern "C" fn libinput_device_config_scroll_set_natural_scroll_enabled(
1733 dev: *mut LibinputDevice,
1734 enabled: libc::c_int,
1735) -> u32 {
1736 if dev.is_null() || !(*dev).has_pointer {
1737 return 1;
1738 }
1739 (*dev).natural_scroll = enabled != 0;
1740 0
1741}
1742
1743#[no_mangle]
1744pub unsafe extern "C" fn libinput_device_config_scroll_get_natural_scroll_enabled(
1745 dev: *const LibinputDevice,
1746) -> libc::c_int {
1747 if dev.is_null() {
1748 return 0;
1749 }
1750 (*dev).natural_scroll as libc::c_int
1751}
1752
1753#[no_mangle]
1754pub unsafe extern "C" fn libinput_device_config_scroll_get_default_natural_scroll_enabled(
1755 dev: *const LibinputDevice,
1756) -> libc::c_int {
1757 if dev.is_null() {
1758 return 0;
1759 }
1760 ((*dev).scroll_methods & 2 != 0 && (*dev).vendor_id == 0x05ac) as libc::c_int
1761}
1762
1763#[no_mangle]
1768pub unsafe extern "C" fn libinput_device_config_left_handed_is_available(
1769 dev: *const LibinputDevice,
1770) -> libc::c_int {
1771 if dev.is_null() {
1772 return 0;
1773 }
1774 (*dev).left_handed_available as libc::c_int
1775}
1776
1777#[no_mangle]
1778pub unsafe extern "C" fn libinput_device_config_left_handed_set(
1779 dev: *mut LibinputDevice,
1780 enabled: libc::c_int,
1781) -> u32 {
1782 if dev.is_null() || !(*dev).left_handed_available {
1783 return 1;
1784 }
1785 (*dev).left_handed = enabled != 0;
1786 0
1787}
1788
1789#[no_mangle]
1790pub unsafe extern "C" fn libinput_device_config_left_handed_get(
1791 dev: *const LibinputDevice,
1792) -> libc::c_int {
1793 if dev.is_null() {
1794 return 0;
1795 }
1796 (*dev).left_handed as libc::c_int
1797}
1798
1799#[no_mangle]
1800pub unsafe extern "C" fn libinput_device_config_left_handed_get_default(
1801 _dev: *const LibinputDevice,
1802) -> libc::c_int {
1803 0
1804}
1805
1806#[no_mangle]
1811pub unsafe extern "C" fn libinput_device_config_scroll_get_methods(
1812 dev: *const LibinputDevice,
1813) -> u32 {
1814 if dev.is_null() {
1815 return 0;
1816 }
1817 (*dev).scroll_methods
1818}
1819
1820#[no_mangle]
1821pub unsafe extern "C" fn libinput_device_config_scroll_set_method(
1822 dev: *mut LibinputDevice,
1823 method: u32,
1824) -> u32 {
1825 if dev.is_null() {
1826 return 1;
1827 }
1828 if !matches!(method, 0 | 1 | 2 | 4) {
1829 return 2;
1830 }
1831 if method != 0 && method & (*dev).scroll_methods == 0 {
1832 return 1;
1833 }
1834 if (*dev).scroll_method == method {
1835 return 0;
1836 }
1837 let ctx = (*dev).context;
1838 if !ctx.is_null() {
1839 let mut events = std::collections::VecDeque::new();
1840 if let Ok(mut backend) = (*ctx).backend.try_lock() {
1841 backend.stop_scroll_for_device(ctx, dev, &mut events);
1842 }
1843 enqueue_events(ctx, events);
1844 }
1845 (*dev).scroll_method = method;
1846 0
1847}
1848
1849#[no_mangle]
1850pub unsafe extern "C" fn libinput_device_config_scroll_get_method(
1851 dev: *const LibinputDevice,
1852) -> u32 {
1853 if dev.is_null() {
1854 return 0;
1855 }
1856 (*dev).scroll_method
1857}
1858
1859#[no_mangle]
1860pub unsafe extern "C" fn libinput_device_config_scroll_get_default_method(
1861 dev: *const LibinputDevice,
1862) -> u32 {
1863 if dev.is_null() {
1864 0
1865 } else {
1866 (*dev).scroll_default_method
1867 }
1868}
1869
1870#[no_mangle]
1871pub unsafe extern "C" fn libinput_device_config_scroll_set_button(
1872 dev: *mut LibinputDevice,
1873 button: u32,
1874) -> u32 {
1875 if dev.is_null() || !(*dev).supports_button_scroll {
1876 return 1;
1877 }
1878 if button != 0
1879 && match u16::try_from(button) {
1880 Ok(button) => !(*dev).event_codes.contains(&button),
1881 Err(_) => true,
1882 }
1883 {
1884 return 2;
1885 }
1886 (*dev).scroll_button = button;
1887 0
1888}
1889
1890#[no_mangle]
1891pub unsafe extern "C" fn libinput_device_config_scroll_get_button(
1892 dev: *const LibinputDevice,
1893) -> u32 {
1894 if dev.is_null() || !(*dev).supports_button_scroll {
1895 0
1896 } else {
1897 (*dev).scroll_button
1898 }
1899}
1900
1901#[no_mangle]
1902pub unsafe extern "C" fn libinput_device_config_scroll_set_button_lock(
1903 dev: *mut LibinputDevice,
1904 state: u32,
1905) -> u32 {
1906 if dev.is_null() || !(*dev).supports_button_scroll {
1907 return 1;
1908 }
1909 if state > 1 {
1910 return 2;
1911 }
1912 (*dev).scroll_button_lock = state;
1913 0
1914}
1915
1916#[no_mangle]
1917pub unsafe extern "C" fn libinput_device_config_scroll_get_button_lock(
1918 dev: *const LibinputDevice,
1919) -> u32 {
1920 if dev.is_null() || !(*dev).supports_button_scroll {
1921 0
1922 } else {
1923 (*dev).scroll_button_lock
1924 }
1925}
1926
1927#[no_mangle]
1928pub unsafe extern "C" fn libinput_device_config_scroll_get_default_button_lock(
1929 _dev: *const LibinputDevice,
1930) -> u32 {
1931 0
1932}
1933
1934#[no_mangle]
1939pub unsafe extern "C" fn libinput_device_config_click_get_methods(
1940 dev: *const LibinputDevice,
1941) -> u32 {
1942 if dev.is_null() {
1943 return 0;
1944 }
1945 (*dev).click_methods
1946}
1947
1948#[no_mangle]
1949pub unsafe extern "C" fn libinput_device_config_click_set_method(
1950 dev: *mut LibinputDevice,
1951 method: u32,
1952) -> u32 {
1953 if dev.is_null() {
1954 return 1;
1955 }
1956 if !matches!(method, 0..=2) {
1957 return 2;
1958 }
1959 if method != 0 && method & (*dev).click_methods == 0 {
1960 return 1;
1961 }
1962 (*dev).click_method = method;
1963 0
1964}
1965
1966#[no_mangle]
1967pub unsafe extern "C" fn libinput_device_config_click_get_method(
1968 dev: *const LibinputDevice,
1969) -> u32 {
1970 if dev.is_null() {
1971 return 0;
1972 }
1973 (*dev).click_method
1974}
1975
1976#[no_mangle]
1977pub unsafe extern "C" fn libinput_device_config_click_get_default_method(
1978 dev: *const LibinputDevice,
1979) -> u32 {
1980 if dev.is_null() {
1981 0
1982 } else {
1983 (*dev).click_default_method
1984 }
1985}
1986
1987#[no_mangle]
1988pub unsafe extern "C" fn libinput_device_config_click_set_clickfinger_button_map(
1989 dev: *mut LibinputDevice,
1990 map: u32,
1991) -> u32 {
1992 if dev.is_null() {
1993 return 1;
1994 }
1995 if !matches!(map, 0 | 1) {
1996 return 2;
1997 }
1998 if (*dev).click_methods & 2 == 0 {
1999 return 1;
2000 }
2001 (*dev).clickfinger_button_map = map;
2002 0
2003}
2004
2005#[no_mangle]
2006pub unsafe extern "C" fn libinput_device_config_click_get_clickfinger_button_map(
2007 dev: *const LibinputDevice,
2008) -> u32 {
2009 if dev.is_null() || (*dev).click_methods & 2 == 0 {
2010 0
2011 } else {
2012 (*dev).clickfinger_button_map
2013 }
2014}
2015
2016#[no_mangle]
2017pub unsafe extern "C" fn libinput_device_config_click_get_default_clickfinger_button_map(
2018 dev: *const LibinputDevice,
2019) -> u32 {
2020 if dev.is_null() || (*dev).click_methods & 2 == 0 {
2021 0
2022 } else {
2023 (*dev).clickfinger_default_button_map
2024 }
2025}
2026
2027#[no_mangle]
2032pub unsafe extern "C" fn libinput_device_config_middle_emulation_is_available(
2033 dev: *const LibinputDevice,
2034) -> libc::c_int {
2035 if dev.is_null() {
2036 return 0;
2037 }
2038 (*dev).middle_emulation_available as libc::c_int
2039}
2040
2041#[no_mangle]
2042pub unsafe extern "C" fn libinput_device_config_middle_emulation_set_enabled(
2043 dev: *mut LibinputDevice,
2044 enabled: u32,
2045) -> u32 {
2046 if dev.is_null() {
2047 return 1;
2048 }
2049 if enabled > 1 {
2050 return 2;
2051 }
2052 if enabled == 1 && !(*dev).middle_emulation_available {
2053 return 1;
2054 }
2055 (*dev).middle_emulation = enabled != 0;
2056 0
2057}
2058
2059#[no_mangle]
2060pub unsafe extern "C" fn libinput_device_config_middle_emulation_get_enabled(
2061 dev: *const LibinputDevice,
2062) -> u32 {
2063 if dev.is_null() || !(*dev).middle_emulation_available {
2064 return 0;
2065 }
2066 (*dev).middle_emulation as u32
2067}
2068
2069#[no_mangle]
2070pub unsafe extern "C" fn libinput_device_config_middle_emulation_get_default_enabled(
2071 dev: *const LibinputDevice,
2072) -> u32 {
2073 if dev.is_null() || !(*dev).middle_emulation_available {
2074 return 0;
2075 }
2076 (*dev).middle_emulation_default as u32
2077}
2078
2079#[no_mangle]
2084pub unsafe extern "C" fn libinput_device_config_dwt_is_available(
2085 dev: *const LibinputDevice,
2086) -> libc::c_int {
2087 (!dev.is_null() && (*dev).dwt_available) as libc::c_int
2088}
2089
2090#[no_mangle]
2091pub unsafe extern "C" fn libinput_device_config_dwt_set_enabled(
2092 dev: *mut LibinputDevice,
2093 enabled: u32,
2094) -> u32 {
2095 if dev.is_null() {
2096 return 1;
2097 }
2098 if !matches!(enabled, 0 | 1) {
2099 return 2;
2100 }
2101 if !(*dev).dwt_available {
2102 return if enabled == 0 { 0 } else { 1 };
2103 }
2104 (*dev).dwt_enabled = enabled == 1;
2105 0
2106}
2107
2108#[no_mangle]
2109pub unsafe extern "C" fn libinput_device_config_dwt_get_enabled(dev: *const LibinputDevice) -> u32 {
2110 if dev.is_null() || !(*dev).dwt_available {
2111 return 0;
2112 }
2113 (*dev).dwt_enabled as u32
2114}
2115
2116#[no_mangle]
2117pub unsafe extern "C" fn libinput_device_config_dwt_get_default_enabled(
2118 dev: *const LibinputDevice,
2119) -> u32 {
2120 (!dev.is_null() && (*dev).dwt_available) as u32
2121}
2122
2123#[no_mangle]
2124pub unsafe extern "C" fn libinput_device_config_dwt_set_timeout(
2125 dev: *mut LibinputDevice,
2126 millis: u32,
2127) -> u32 {
2128 if dev.is_null() {
2129 return 1;
2130 }
2131 if millis == 0 {
2132 return 2;
2133 }
2134 if !(*dev).dwt_available {
2135 return 1;
2136 }
2137 if !(100..=5000).contains(&millis) {
2138 return 2;
2139 }
2140 (*dev).dwt_timeout = millis;
2141 0
2142}
2143
2144#[no_mangle]
2145pub unsafe extern "C" fn libinput_device_config_dwt_get_timeout(dev: *const LibinputDevice) -> u32 {
2146 if dev.is_null() || !(*dev).dwt_available {
2147 0
2148 } else {
2149 (*dev).dwt_timeout
2150 }
2151}
2152
2153#[no_mangle]
2154pub unsafe extern "C" fn libinput_device_config_dwt_get_default_timeout(
2155 dev: *const LibinputDevice,
2156) -> u32 {
2157 if !dev.is_null() && (*dev).dwt_available {
2158 500
2159 } else {
2160 0
2161 }
2162}
2163
2164#[no_mangle]
2165pub unsafe extern "C" fn libinput_device_config_dwtp_is_available(
2166 dev: *const LibinputDevice,
2167) -> libc::c_int {
2168 (!dev.is_null() && (*dev).dwtp_available) as libc::c_int
2169}
2170
2171#[no_mangle]
2172pub unsafe extern "C" fn libinput_device_config_dwtp_set_enabled(
2173 dev: *mut LibinputDevice,
2174 enabled: u32,
2175) -> u32 {
2176 if dev.is_null() {
2177 return 1;
2178 }
2179 if !matches!(enabled, 0 | 1) {
2180 return 2;
2181 }
2182 if !(*dev).dwtp_available {
2183 return if enabled == 0 { 0 } else { 1 };
2184 }
2185 (*dev).dwtp_enabled = enabled == 1;
2186 0
2187}
2188
2189#[no_mangle]
2190pub unsafe extern "C" fn libinput_device_config_dwtp_get_enabled(
2191 dev: *const LibinputDevice,
2192) -> u32 {
2193 if dev.is_null() || !(*dev).dwtp_available {
2194 0
2195 } else {
2196 (*dev).dwtp_enabled as u32
2197 }
2198}
2199
2200#[no_mangle]
2201pub unsafe extern "C" fn libinput_device_config_dwtp_get_default_enabled(
2202 dev: *const LibinputDevice,
2203) -> u32 {
2204 (!dev.is_null() && (*dev).dwtp_available) as u32
2205}
2206
2207#[no_mangle]
2208pub unsafe extern "C" fn libinput_device_config_dwtp_set_timeout(
2209 dev: *mut LibinputDevice,
2210 millis: u32,
2211) -> u32 {
2212 if dev.is_null() {
2213 return 1;
2214 }
2215 if millis == 0 {
2216 return 2;
2217 }
2218 if !(*dev).dwtp_available {
2219 return 1;
2220 }
2221 if !(100..=5000).contains(&millis) {
2222 return 2;
2223 }
2224 (*dev).dwtp_timeout = millis;
2225 0
2226}
2227
2228#[no_mangle]
2229pub unsafe extern "C" fn libinput_device_config_dwtp_get_timeout(
2230 dev: *const LibinputDevice,
2231) -> u32 {
2232 if dev.is_null() || !(*dev).dwtp_available {
2233 0
2234 } else {
2235 (*dev).dwtp_timeout
2236 }
2237}
2238
2239#[no_mangle]
2240pub unsafe extern "C" fn libinput_device_config_dwtp_get_default_timeout(
2241 dev: *const LibinputDevice,
2242) -> u32 {
2243 if !dev.is_null() && (*dev).dwtp_available {
2244 300
2245 } else {
2246 0
2247 }
2248}
2249
2250#[no_mangle]
2255pub unsafe extern "C" fn libinput_device_config_calibration_has_matrix(
2256 dev: *const LibinputDevice,
2257) -> libc::c_int {
2258 if dev.is_null() {
2259 return 0;
2260 }
2261 (*dev).calibration_available as libc::c_int
2262}
2263
2264#[no_mangle]
2265pub unsafe extern "C" fn libinput_device_config_calibration_set_matrix(
2266 dev: *mut LibinputDevice,
2267 matrix: *const f32,
2268) -> u32 {
2269 if dev.is_null() || matrix.is_null() || !(*dev).calibration_available {
2270 return 1;
2271 }
2272 (*dev)
2273 .calibration
2274 .copy_from_slice(std::slice::from_raw_parts(matrix, 6));
2275 0
2276}
2277
2278#[no_mangle]
2279pub unsafe extern "C" fn libinput_device_config_calibration_get_matrix(
2280 dev: *const LibinputDevice,
2281 matrix: *mut f32,
2282) -> libc::c_int {
2283 if dev.is_null() || matrix.is_null() || !(*dev).calibration_available {
2284 return 0;
2285 }
2286 std::slice::from_raw_parts_mut(matrix, 6).copy_from_slice(&(*dev).calibration);
2287 ((*dev).calibration != [1.0_f32, 0.0, 0.0, 0.0, 1.0, 0.0]) as libc::c_int
2288}
2289
2290#[no_mangle]
2291pub unsafe extern "C" fn libinput_device_config_calibration_get_default_matrix(
2292 dev: *const LibinputDevice,
2293 matrix: *mut f32,
2294) -> libc::c_int {
2295 if dev.is_null() || matrix.is_null() || !(*dev).calibration_available {
2296 return 0;
2297 }
2298 std::slice::from_raw_parts_mut(matrix, 6).copy_from_slice(&(*dev).default_calibration);
2299 ((*dev).default_calibration != [1.0_f32, 0.0, 0.0, 0.0, 1.0, 0.0]) as libc::c_int
2300}
2301
2302#[no_mangle]
2307pub unsafe extern "C" fn libinput_device_get_seat(dev: *const LibinputDevice) -> *mut libc::c_void {
2308 if dev.is_null() {
2309 return std::ptr::null_mut();
2310 }
2311 (*dev).seat as *mut libc::c_void
2312}
2313
2314#[no_mangle]
2315pub unsafe extern "C" fn libinput_device_set_seat_logical_name(
2316 dev: *mut LibinputDevice,
2317 name: *const libc::c_char,
2318) -> libc::c_int {
2319 if dev.is_null() || name.is_null() || (*dev).seat.is_null() {
2320 return -1;
2321 }
2322 let name = CStr::from_ptr(name);
2323 if name.to_bytes().is_empty() || name.to_bytes().len() > 255 {
2324 return -1;
2325 }
2326 if (*(*dev).seat).logical_name.as_c_str() == name {
2327 return 0;
2328 }
2329 let Ok(logical_name) = std::ffi::CString::new(name.to_bytes()) else {
2330 return -1;
2331 };
2332 let ctx = (*dev).context;
2333 if ctx.is_null() {
2334 return -1;
2335 }
2336 let physical_name = (*(*dev).seat).physical_name.clone();
2337 let new_seat = (*ctx)
2338 .seats
2339 .iter()
2340 .copied()
2341 .find(|seat| {
2342 !seat.is_null()
2343 && (**seat).physical_name == physical_name
2344 && (**seat).logical_name == logical_name
2345 })
2346 .unwrap_or_else(|| {
2347 let seat = Box::into_raw(Box::new(LibinputSeat {
2348 physical_name,
2349 logical_name,
2350 refcount: std::sync::atomic::AtomicI32::new(1),
2351 user_data: std::ptr::null_mut(),
2352 context: ctx,
2353 button_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
2354 key_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
2355 }));
2356 (*ctx).seats.push(seat);
2357 seat
2358 });
2359
2360 let path = std::path::PathBuf::from((*dev).devnode.to_string_lossy().into_owned());
2361 let mut removed = std::collections::VecDeque::new();
2362 let mut added = Vec::new();
2363 let replaced = if let Ok(mut backend) = (*ctx).backend.lock() {
2364 if backend.remove_device(ctx, dev, &mut removed) {
2365 backend.try_open(ctx, &path, &mut added);
2366 true
2367 } else {
2368 false
2369 }
2370 } else {
2371 false
2372 };
2373 let Some(replacement) = added.first().map(|event| event.device) else {
2374 return -1;
2375 };
2376 if !replaced || replacement.is_null() {
2377 return -1;
2378 }
2379 (*ctx).devices.retain(|candidate| *candidate != dev);
2380 libinput_device_unref(dev);
2381 let old_seat = (*replacement).seat;
2382 if old_seat != new_seat {
2383 libinput_seat_ref(new_seat.cast());
2384 (*replacement).seat = new_seat;
2385 (*replacement).abi.seat = new_seat;
2386 libinput_seat_unref(old_seat.cast());
2387 }
2388 enqueue_events(ctx, removed);
2389 enqueue_events(ctx, added);
2390 (*ctx).signal_fd();
2391 0
2392}
2393
2394#[no_mangle]
2395pub unsafe extern "C" fn libinput_seat_get_physical_name(
2396 seat: *const libc::c_void,
2397) -> *const libc::c_char {
2398 if seat.is_null() {
2399 return std::ptr::null();
2400 }
2401 (*(seat as *const LibinputSeat)).physical_name.as_ptr()
2402}
2403
2404#[no_mangle]
2405pub unsafe extern "C" fn libinput_seat_get_logical_name(
2406 seat: *const libc::c_void,
2407) -> *const libc::c_char {
2408 if seat.is_null() {
2409 return std::ptr::null();
2410 }
2411 (*(seat as *const LibinputSeat)).logical_name.as_ptr()
2412}
2413
2414#[no_mangle]
2415pub unsafe extern "C" fn libinput_seat_get_context(
2416 seat: *const libc::c_void,
2417) -> *mut LibinputContext {
2418 if seat.is_null() {
2419 return std::ptr::null_mut();
2420 }
2421 (*(seat as *const LibinputSeat)).context
2422}
2423
2424#[no_mangle]
2425pub unsafe extern "C" fn libinput_seat_ref(seat: *mut libc::c_void) -> *mut libc::c_void {
2426 if !seat.is_null() {
2427 (*(seat as *mut LibinputSeat))
2428 .refcount
2429 .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
2430 }
2431 seat
2432}
2433
2434#[no_mangle]
2435pub unsafe extern "C" fn libinput_seat_unref(seat: *mut libc::c_void) -> *mut libc::c_void {
2436 if seat.is_null() {
2437 return std::ptr::null_mut();
2438 }
2439 let seat = seat as *mut LibinputSeat;
2440 if (*seat)
2441 .refcount
2442 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
2443 == 1
2444 {
2445 drop(Box::from_raw(seat));
2446 std::ptr::null_mut()
2447 } else {
2448 seat.cast()
2449 }
2450}
2451
2452#[no_mangle]
2453pub unsafe extern "C" fn libinput_seat_set_user_data(
2454 seat: *mut libc::c_void,
2455 data: *mut libc::c_void,
2456) {
2457 if !seat.is_null() {
2458 (*(seat as *mut LibinputSeat)).user_data = data;
2459 }
2460}
2461
2462#[no_mangle]
2463pub unsafe extern "C" fn libinput_seat_get_user_data(
2464 seat: *const libc::c_void,
2465) -> *mut libc::c_void {
2466 if seat.is_null() {
2467 return std::ptr::null_mut();
2468 }
2469 (*(seat as *const LibinputSeat)).user_data
2470}
2471
2472#[no_mangle]
2477pub unsafe extern "C" fn libinput_config_status_to_str(status: u32) -> *const libc::c_char {
2478 match status {
2479 0 => b"Success\0".as_ptr().cast(),
2480 1 => b"Unsupported configuration option\0".as_ptr().cast(),
2481 2 => b"Invalid argument range\0".as_ptr().cast(),
2482 _ => std::ptr::null(),
2483 }
2484}
2485
2486#[no_mangle]
2491pub unsafe extern "C" fn libinput_log_set_priority(ctx: *mut LibinputContext, priority: u32) {
2492 if !ctx.is_null() {
2493 (*ctx).log_priority = priority;
2494 }
2495}
2496
2497#[no_mangle]
2498pub unsafe extern "C" fn libinput_log_get_priority(ctx: *const LibinputContext) -> u32 {
2499 if ctx.is_null() {
2500 return 30;
2501 }
2502 (*ctx).log_priority
2503}
2504
2505#[no_mangle]
2506pub unsafe extern "C" fn libinput_log_set_handler(
2507 ctx: *mut LibinputContext,
2508 handler: Option<
2509 unsafe extern "C" fn(
2510 ctx: *mut LibinputContext,
2511 priority: u32,
2512 format: *const libc::c_char,
2513 args: *mut libc::c_void,
2514 ),
2515 >,
2516) {
2517 if ctx.is_null() {
2518 return;
2519 }
2520 (*ctx).default_log_handler_enabled = false;
2521 (*ctx).log_handler = handler;
2522}
2523
2524#[no_mangle]
2529pub unsafe extern "C" fn libinput_set_user_data(
2530 ctx: *mut LibinputContext,
2531 data: *mut libc::c_void,
2532) {
2533 if ctx.is_null() {
2534 return;
2535 }
2536 (*ctx).user_data = data;
2537}
2538
2539#[no_mangle]
2540pub unsafe extern "C" fn libinput_get_user_data(ctx: *const LibinputContext) -> *mut libc::c_void {
2541 if ctx.is_null() {
2542 return std::ptr::null_mut();
2543 }
2544 (*ctx).user_data
2545}
2546
2547#[no_mangle]
2548pub unsafe extern "C" fn libinput_device_set_user_data(
2549 dev: *mut LibinputDevice,
2550 data: *mut libc::c_void,
2551) {
2552 if dev.is_null() {
2553 return;
2554 }
2555 (*dev).user_data = data;
2556 (*dev).abi.user_data = data;
2557}
2558
2559#[no_mangle]
2560pub unsafe extern "C" fn libinput_device_get_user_data(
2561 dev: *const LibinputDevice,
2562) -> *mut libc::c_void {
2563 if dev.is_null() {
2564 return std::ptr::null_mut();
2565 }
2566 (*dev).user_data
2567}
2568
2569#[no_mangle]
2574pub unsafe extern "C" fn libinput_device_config_area_has_rectangle(
2575 dev: *const LibinputDevice,
2576) -> libc::c_int {
2577 if dev.is_null() {
2578 return 0;
2579 }
2580 (*dev).area_available as libc::c_int
2581}
2582
2583#[no_mangle]
2584pub unsafe extern "C" fn libinput_device_config_area_set_rectangle(
2585 dev: *mut LibinputDevice,
2586 rectangle: *const LibinputConfigAreaRectangle,
2587) -> u32 {
2588 if dev.is_null() || !(*dev).area_available {
2589 return 1;
2590 }
2591 if rectangle.is_null() {
2592 return 2;
2593 }
2594 let rectangle = &*rectangle;
2595 if rectangle.x1 >= rectangle.x2
2596 || rectangle.y1 >= rectangle.y2
2597 || rectangle.x1 < 0.0
2598 || rectangle.x2 > 1.0
2599 || rectangle.y1 < 0.0
2600 || rectangle.y2 > 1.0
2601 {
2602 return 2;
2603 }
2604 (*dev).wanted_area = [rectangle.x1, rectangle.y1, rectangle.x2, rectangle.y2];
2605 if !(*dev).tablet_in_proximity {
2606 (*dev).area = (*dev).wanted_area;
2607 }
2608 0
2609}
2610
2611#[no_mangle]
2612pub unsafe extern "C" fn libinput_device_config_area_get_rectangle(
2613 dev: *const LibinputDevice,
2614) -> LibinputConfigAreaRectangle {
2615 let area = if dev.is_null() || !(*dev).area_available {
2616 [0.0, 0.0, 1.0, 1.0]
2617 } else {
2618 (*dev).area
2619 };
2620 LibinputConfigAreaRectangle {
2621 x1: area[0],
2622 y1: area[1],
2623 x2: area[2],
2624 y2: area[3],
2625 }
2626}
2627
2628#[no_mangle]
2629pub unsafe extern "C" fn libinput_device_config_area_get_default_rectangle(
2630 _dev: *const LibinputDevice,
2631) -> LibinputConfigAreaRectangle {
2632 LibinputConfigAreaRectangle {
2633 x1: 0.0,
2634 y1: 0.0,
2635 x2: 1.0,
2636 y2: 1.0,
2637 }
2638}
2639
2640#[no_mangle]
2641pub unsafe extern "C" fn libinput_device_config_rotation_is_available(
2642 dev: *const LibinputDevice,
2643) -> libc::c_int {
2644 if dev.is_null() {
2645 return 0;
2646 }
2647 (*dev).rotation_available as libc::c_int
2648}
2649
2650#[no_mangle]
2651pub unsafe extern "C" fn libinput_device_config_rotation_set_angle(
2652 dev: *mut LibinputDevice,
2653 degrees_cw: u32,
2654) -> u32 {
2655 if dev.is_null() {
2656 return 1;
2657 }
2658 if !(*dev).rotation_available {
2659 return if degrees_cw == 0 { 0 } else { 1 };
2660 }
2661 if degrees_cw >= 360 {
2662 return 2;
2663 }
2664 (*dev).rotation_angle = degrees_cw;
2665 0
2666}
2667
2668#[no_mangle]
2669pub unsafe extern "C" fn libinput_device_config_rotation_get_angle(
2670 dev: *const LibinputDevice,
2671) -> u32 {
2672 if dev.is_null() {
2673 0
2674 } else {
2675 (*dev).rotation_angle
2676 }
2677}
2678
2679#[no_mangle]
2680pub unsafe extern "C" fn libinput_device_config_rotation_get_default_angle(
2681 _dev: *const LibinputDevice,
2682) -> u32 {
2683 0
2684}
2685
2686#[no_mangle]
2687pub unsafe extern "C" fn libinput_device_config_scroll_get_default_button(
2688 dev: *const LibinputDevice,
2689) -> u32 {
2690 if dev.is_null() || !(*dev).supports_button_scroll {
2691 0
2692 } else {
2693 (*dev).scroll_default_button
2694 }
2695}
2696
2697#[no_mangle]
2698pub unsafe extern "C" fn libinput_device_config_send_events_get_modes(
2699 dev: *const LibinputDevice,
2700) -> u32 {
2701 if dev.is_null() {
2702 return 0;
2703 }
2704 (*dev).send_events_modes
2705}
2706
2707#[no_mangle]
2708pub unsafe extern "C" fn libinput_device_config_send_events_set_mode(
2709 dev: *mut LibinputDevice,
2710 mode: u32,
2711) -> u32 {
2712 if dev.is_null() {
2713 return 1;
2714 }
2715 let supported = (*dev).send_events_modes;
2716 if mode & !supported != 0 {
2717 return 1;
2718 }
2719 let previous = (*dev).send_events_mode;
2720 let next = if mode & 1 != 0 { 1 } else { mode };
2721 (*dev).send_events_mode = next;
2722 if previous != next && matches!(next, 1 | 2) {
2723 let ctx = (*dev).context;
2724 if !ctx.is_null() {
2725 let mut events = std::collections::VecDeque::new();
2726 if let Ok(mut backend) = (*ctx).backend.lock() {
2727 if next == 1 || backend.has_external_mouse() {
2728 backend.release_active_inputs(ctx, dev, &mut events);
2729 }
2730 }
2731 enqueue_events(ctx, events);
2732 }
2733 }
2734 0
2735}
2736
2737#[no_mangle]
2738pub unsafe extern "C" fn libinput_device_config_send_events_get_mode(
2739 dev: *const LibinputDevice,
2740) -> u32 {
2741 if dev.is_null() {
2742 return 0;
2743 }
2744 (*dev).send_events_mode
2745}
2746
2747#[no_mangle]
2748pub unsafe extern "C" fn libinput_device_config_send_events_get_default_mode(
2749 _dev: *const LibinputDevice,
2750) -> u32 {
2751 0
2752}
2753
2754#[no_mangle]
2755pub unsafe extern "C" fn libinput_device_config_tap_get_default_drag_lock_enabled(
2756 _dev: *const LibinputDevice,
2757) -> u32 {
2758 0
2759}
2760
2761#[no_mangle]
2762pub unsafe extern "C" fn libinput_device_get_device_group(
2763 dev: *const LibinputDevice,
2764) -> *mut libc::c_void {
2765 if dev.is_null() {
2766 return std::ptr::null_mut();
2767 }
2768 (*dev).group.cast()
2769}
2770
2771#[no_mangle]
2772pub unsafe extern "C" fn libinput_device_group_ref(group: *mut libc::c_void) -> *mut libc::c_void {
2773 if group.is_null() {
2774 return std::ptr::null_mut();
2775 }
2776 let group = group.cast::<LibinputDeviceGroup>();
2777 (*group)
2778 .refcount
2779 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2780 group.cast()
2781}
2782
2783#[no_mangle]
2784pub unsafe extern "C" fn libinput_device_group_unref(
2785 group: *mut libc::c_void,
2786) -> *mut libc::c_void {
2787 if group.is_null() {
2788 return std::ptr::null_mut();
2789 }
2790 let group = group.cast::<LibinputDeviceGroup>();
2791 if (*group)
2792 .refcount
2793 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
2794 == 1
2795 {
2796 drop(Box::from_raw(group));
2797 std::ptr::null_mut()
2798 } else {
2799 group.cast()
2800 }
2801}
2802
2803#[no_mangle]
2804pub unsafe extern "C" fn libinput_device_group_set_user_data(
2805 group: *mut libc::c_void,
2806 data: *mut libc::c_void,
2807) {
2808 if !group.is_null() {
2809 (*group.cast::<LibinputDeviceGroup>()).user_data = data;
2810 }
2811}
2812
2813#[no_mangle]
2814pub unsafe extern "C" fn libinput_device_group_get_user_data(
2815 group: *const libc::c_void,
2816) -> *mut libc::c_void {
2817 if group.is_null() {
2818 return std::ptr::null_mut();
2819 }
2820 (*group.cast::<LibinputDeviceGroup>()).user_data
2821}
2822
2823#[no_mangle]
2824pub unsafe extern "C" fn libinput_device_get_id_bustype(dev: *const LibinputDevice) -> u32 {
2825 if dev.is_null() {
2826 return 0;
2827 }
2828 (*dev).bus_type
2829}
2830
2831#[no_mangle]
2832pub unsafe extern "C" fn libinput_device_get_size(
2833 dev: *const LibinputDevice,
2834 width: *mut f64,
2835 height: *mut f64,
2836) -> libc::c_int {
2837 if dev.is_null() || width.is_null() || height.is_null() {
2838 return 0;
2839 }
2840 match ((*dev).width_mm, (*dev).height_mm) {
2841 (Some(w), Some(h)) => {
2842 *width = w;
2843 *height = h;
2844 0
2845 }
2846 _ => -1,
2847 }
2848}
2849
2850#[no_mangle]
2851pub unsafe extern "C" fn libinput_device_get_udev_device(
2852 dev: *const LibinputDevice,
2853) -> *mut libc::c_void {
2854 if dev.is_null() || (*dev).udev_device.is_null() {
2855 return std::ptr::null_mut();
2856 }
2857 udev::udev_device_ref((*dev).udev_device)
2858}
2859
2860#[no_mangle]
2861pub unsafe extern "C" fn libinput_device_keyboard_has_key(
2862 dev: *const LibinputDevice,
2863 key: u32,
2864) -> libc::c_int {
2865 if dev.is_null() || !(*dev).has_keyboard {
2866 return -1;
2867 }
2868 if key > u16::MAX as u32 {
2869 return 0;
2870 }
2871 (*dev).event_codes.contains(&(key as u16)) as libc::c_int
2872}
2873
2874#[no_mangle]
2875pub unsafe extern "C" fn libinput_device_led_update(dev: *mut LibinputDevice, leds: u32) {
2876 if dev.is_null() || (*dev).context.is_null() {
2877 return;
2878 }
2879 let ctx = (*dev).context;
2880 if let Ok(mut backend) = (*ctx).backend.lock() {
2881 backend.update_leds(dev, leds);
2882 }
2883}
2884
2885#[no_mangle]
2886pub unsafe extern "C" fn libinput_device_pointer_has_button(
2887 dev: *const LibinputDevice,
2888 button: u32,
2889) -> libc::c_int {
2890 if dev.is_null() {
2891 return 0;
2892 }
2893 if !(*dev).has_pointer {
2894 return -1;
2895 }
2896 if button > u16::MAX as u32 {
2897 return 0;
2898 }
2899 (*dev).event_codes.contains(&(button as u16)) as libc::c_int
2900}
2901
2902#[no_mangle]
2903pub unsafe extern "C" fn libinput_device_switch_has_switch(
2904 dev: *const LibinputDevice,
2905 sw: u32,
2906) -> libc::c_int {
2907 if dev.is_null() {
2908 return -1;
2909 }
2910 if !(*dev).has_switch {
2911 return -1;
2912 }
2913 let kernel_code = match sw {
2914 1 => 0,
2915 2 => 1,
2916 3 => 10,
2917 _ => return -1,
2918 };
2919 (*dev).switch_codes.contains(&kernel_code) as libc::c_int
2920}
2921
2922#[no_mangle]
2923pub unsafe extern "C" fn libinput_device_tablet_pad_get_mode_group(
2924 dev: *const LibinputDevice,
2925 index: u32,
2926) -> *mut libc::c_void {
2927 if dev.is_null() || !(*dev).has_tablet_pad {
2928 return std::ptr::null_mut();
2929 }
2930 (*dev)
2931 .tablet_pad_mode_groups
2932 .iter()
2933 .copied()
2934 .find(|group| !group.is_null() && (**group).index == index)
2935 .unwrap_or(std::ptr::null_mut())
2936 .cast()
2937}
2938
2939#[no_mangle]
2940pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_buttons(
2941 dev: *const LibinputDevice,
2942) -> u32 {
2943 if dev.is_null() || !(*dev).has_tablet_pad {
2944 return u32::MAX;
2945 }
2946 (*dev).tablet_pad_button_codes.len() as u32
2947}
2948
2949#[no_mangle]
2950pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_dials(
2951 dev: *const LibinputDevice,
2952) -> u32 {
2953 if dev.is_null() || !(*dev).has_tablet_pad {
2954 return u32::MAX;
2955 }
2956 (*dev).tablet_pad_num_dials
2957}
2958
2959#[no_mangle]
2960pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_mode_groups(
2961 dev: *const LibinputDevice,
2962) -> u32 {
2963 if dev.is_null() || !(*dev).has_tablet_pad {
2964 return u32::MAX;
2965 }
2966 (*dev).tablet_pad_mode_groups.len() as u32
2967}
2968
2969#[no_mangle]
2970pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_rings(
2971 dev: *const LibinputDevice,
2972) -> u32 {
2973 if dev.is_null() || !(*dev).has_tablet_pad {
2974 return u32::MAX;
2975 }
2976 (*dev).tablet_pad_num_rings
2977}
2978
2979#[no_mangle]
2980pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_strips(
2981 dev: *const LibinputDevice,
2982) -> u32 {
2983 if dev.is_null() || !(*dev).has_tablet_pad {
2984 return u32::MAX;
2985 }
2986 (*dev).tablet_pad_num_strips
2987}
2988
2989#[no_mangle]
2990pub unsafe extern "C" fn libinput_device_tablet_pad_has_key(
2991 dev: *const LibinputDevice,
2992 code: u32,
2993) -> libc::c_int {
2994 if dev.is_null() || !(*dev).has_tablet_pad {
2995 return -1;
2996 }
2997 (code <= u16::MAX as u32 && (*dev).event_codes.contains(&(code as u16))) as libc::c_int
2998}
2999
3000#[no_mangle]
3001pub unsafe extern "C" fn libinput_event_get_tablet_pad_event(
3002 event: *mut LibinputEvent,
3003) -> *mut LibinputEvent {
3004 if event.is_null() {
3005 return std::ptr::null_mut();
3006 }
3007 match (*event).event_type {
3008 LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_BUTTON
3009 | LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_RING
3010 | LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_STRIP
3011 | LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_KEY
3012 | LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_DIAL => event,
3013 _ => std::ptr::null_mut(),
3014 }
3015}
3016
3017#[no_mangle]
3018pub unsafe extern "C" fn libinput_event_tablet_pad_get_base_event(
3019 event: *mut LibinputEvent,
3020) -> *mut LibinputEvent {
3021 event
3022}
3023
3024#[no_mangle]
3025pub unsafe extern "C" fn libinput_event_get_tablet_tool_event(
3026 event: *mut LibinputEvent,
3027) -> *mut LibinputEvent {
3028 if event.is_null() {
3029 return std::ptr::null_mut();
3030 }
3031 match (*event).event_type {
3032 LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_AXIS
3033 | LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY
3034 | LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_TIP
3035 | LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_BUTTON => event,
3036 _ => std::ptr::null_mut(),
3037 }
3038}
3039
3040#[no_mangle]
3041pub unsafe extern "C" fn libinput_event_tablet_tool_get_base_event(
3042 event: *mut LibinputEvent,
3043) -> *mut LibinputEvent {
3044 event
3045}
3046
3047#[no_mangle]
3048pub unsafe extern "C" fn libinput_event_pointer_get_absolute_x_transformed(
3049 event: *const LibinputEvent,
3050 width: u32,
3051) -> f64 {
3052 if event.is_null() {
3053 return 0.0;
3054 }
3055 if let EventPayload::PointerMotionAbsolute(e) = &(*event).payload {
3056 let (x, _) = apply_absolute_calibration(
3057 e.abs_x,
3058 e.abs_y,
3059 e.x_min,
3060 e.x_max,
3061 e.y_min,
3062 e.y_max,
3063 e.calibration,
3064 );
3065 let range = e.x_max - e.x_min + 1.0;
3066 if range > 0.0 {
3067 (x - e.x_min) * f64::from(width) / range
3068 } else {
3069 0.0
3070 }
3071 } else {
3072 0.0
3073 }
3074}
3075
3076#[no_mangle]
3077pub unsafe extern "C" fn libinput_event_pointer_get_absolute_y_transformed(
3078 event: *const LibinputEvent,
3079 height: u32,
3080) -> f64 {
3081 if event.is_null() {
3082 return 0.0;
3083 }
3084 if let EventPayload::PointerMotionAbsolute(e) = &(*event).payload {
3085 let (_, y) = apply_absolute_calibration(
3086 e.abs_x,
3087 e.abs_y,
3088 e.x_min,
3089 e.x_max,
3090 e.y_min,
3091 e.y_max,
3092 e.calibration,
3093 );
3094 let range = e.y_max - e.y_min + 1.0;
3095 if range > 0.0 {
3096 (y - e.y_min) * f64::from(height) / range
3097 } else {
3098 0.0
3099 }
3100 } else {
3101 0.0
3102 }
3103}
3104
3105#[no_mangle]
3106pub unsafe extern "C" fn libinput_event_pointer_get_scroll_value(
3107 event: *const LibinputEvent,
3108 axis: u32,
3109) -> f64 {
3110 libinput_event_pointer_get_axis_value(event, axis)
3111}
3112
3113#[no_mangle]
3114pub unsafe extern "C" fn libinput_event_pointer_get_scroll_value_v120(
3115 event: *const LibinputEvent,
3116 axis: u32,
3117) -> f64 {
3118 if event.is_null() {
3119 return 0.0;
3120 }
3121 if let EventPayload::PointerAxis(e) = &(*event).payload {
3122 return e.value_v120(axis);
3123 }
3124 0.0
3125}
3126
3127#[no_mangle]
3128pub unsafe extern "C" fn libinput_event_switch_get_time_usec(event: *const LibinputEvent) -> u64 {
3129 if event.is_null() {
3130 return 0;
3131 }
3132 if let EventPayload::SwitchToggle(e) = &(*event).payload {
3133 e.time_usec
3134 } else {
3135 0
3136 }
3137}
3138
3139#[no_mangle]
3140pub unsafe extern "C" fn libinput_event_switch_get_time(event: *const LibinputEvent) -> u32 {
3141 (libinput_event_switch_get_time_usec(event) / 1000) as u32
3142}
3143
3144#[no_mangle]
3145pub unsafe extern "C" fn libinput_event_tablet_pad_get_button_number(
3146 event: *const LibinputEvent,
3147) -> u32 {
3148 if event.is_null() {
3149 return 0;
3150 }
3151 match &(*event).payload {
3152 EventPayload::TabletPad(pad) => pad.button,
3153 _ => 0,
3154 }
3155}
3156
3157#[no_mangle]
3158pub unsafe extern "C" fn libinput_event_tablet_pad_get_button_state(
3159 event: *const LibinputEvent,
3160) -> u32 {
3161 if event.is_null() {
3162 return 0;
3163 }
3164 match &(*event).payload {
3165 EventPayload::TabletPad(pad) => pad.button_state,
3166 _ => 0,
3167 }
3168}
3169
3170#[no_mangle]
3171pub unsafe extern "C" fn libinput_event_tablet_pad_get_key(event: *const LibinputEvent) -> u32 {
3172 if event.is_null() {
3173 return 0;
3174 }
3175 match &(*event).payload {
3176 EventPayload::TabletPad(pad) => pad.key,
3177 _ => 0,
3178 }
3179}
3180
3181#[no_mangle]
3182pub unsafe extern "C" fn libinput_event_tablet_pad_get_key_state(
3183 event: *const LibinputEvent,
3184) -> u32 {
3185 if event.is_null() {
3186 return 0;
3187 }
3188 match &(*event).payload {
3189 EventPayload::TabletPad(pad) => pad.key_state,
3190 _ => 0,
3191 }
3192}
3193
3194#[no_mangle]
3195pub unsafe extern "C" fn libinput_event_tablet_pad_get_dial_delta_v120(
3196 event: *const LibinputEvent,
3197) -> f64 {
3198 if event.is_null() {
3199 return 0.0;
3200 }
3201 match &(*event).payload {
3202 EventPayload::TabletPad(pad) => pad.dial_delta_v120,
3203 _ => 0.0,
3204 }
3205}
3206
3207#[no_mangle]
3208pub unsafe extern "C" fn libinput_event_tablet_pad_get_dial_number(
3209 event: *const LibinputEvent,
3210) -> u32 {
3211 if event.is_null() {
3212 return 0;
3213 }
3214 match &(*event).payload {
3215 EventPayload::TabletPad(pad) => pad.dial_number,
3216 _ => 0,
3217 }
3218}
3219
3220#[no_mangle]
3221pub unsafe extern "C" fn libinput_event_tablet_pad_get_mode(event: *const LibinputEvent) -> u32 {
3222 if event.is_null() {
3223 return 0;
3224 }
3225 match &(*event).payload {
3226 EventPayload::TabletPad(pad) => pad.mode,
3227 _ => 0,
3228 }
3229}
3230
3231#[no_mangle]
3232pub unsafe extern "C" fn libinput_event_tablet_pad_get_mode_group(
3233 event: *const LibinputEvent,
3234) -> *mut libc::c_void {
3235 if event.is_null() {
3236 return std::ptr::null_mut();
3237 }
3238 match &(*event).payload {
3239 EventPayload::TabletPad(pad) => pad.mode_group.cast(),
3240 _ => std::ptr::null_mut(),
3241 }
3242}
3243
3244#[no_mangle]
3245pub unsafe extern "C" fn libinput_event_tablet_pad_get_ring_number(
3246 event: *const LibinputEvent,
3247) -> u32 {
3248 if event.is_null() {
3249 return 0;
3250 }
3251 match &(*event).payload {
3252 EventPayload::TabletPad(pad) => pad.ring_number,
3253 _ => 0,
3254 }
3255}
3256
3257#[no_mangle]
3258pub unsafe extern "C" fn libinput_event_tablet_pad_get_ring_position(
3259 event: *const LibinputEvent,
3260) -> f64 {
3261 if event.is_null() {
3262 return 0.0;
3263 }
3264 match &(*event).payload {
3265 EventPayload::TabletPad(pad) => pad.ring_position,
3266 _ => 0.0,
3267 }
3268}
3269
3270#[no_mangle]
3271pub unsafe extern "C" fn libinput_event_tablet_pad_get_ring_source(
3272 event: *const LibinputEvent,
3273) -> u32 {
3274 if event.is_null() {
3275 return 0;
3276 }
3277 match &(*event).payload {
3278 EventPayload::TabletPad(pad) => pad.ring_source,
3279 _ => 0,
3280 }
3281}
3282
3283#[no_mangle]
3284pub unsafe extern "C" fn libinput_event_tablet_pad_get_strip_number(
3285 event: *const LibinputEvent,
3286) -> u32 {
3287 if event.is_null() {
3288 return 0;
3289 }
3290 match &(*event).payload {
3291 EventPayload::TabletPad(pad) => pad.strip_number,
3292 _ => 0,
3293 }
3294}
3295
3296#[no_mangle]
3297pub unsafe extern "C" fn libinput_event_tablet_pad_get_strip_position(
3298 event: *const LibinputEvent,
3299) -> f64 {
3300 if event.is_null() {
3301 return 0.0;
3302 }
3303 match &(*event).payload {
3304 EventPayload::TabletPad(pad) => pad.strip_position,
3305 _ => 0.0,
3306 }
3307}
3308
3309#[no_mangle]
3310pub unsafe extern "C" fn libinput_event_tablet_pad_get_strip_source(
3311 event: *const LibinputEvent,
3312) -> u32 {
3313 if event.is_null() {
3314 return 0;
3315 }
3316 match &(*event).payload {
3317 EventPayload::TabletPad(pad) => pad.strip_source,
3318 _ => 0,
3319 }
3320}
3321
3322#[no_mangle]
3323pub unsafe extern "C" fn libinput_event_tablet_pad_get_time_usec(
3324 event: *const LibinputEvent,
3325) -> u64 {
3326 if event.is_null() {
3327 return 0;
3328 }
3329 match &(*event).payload {
3330 EventPayload::TabletPad(pad) => pad.time_usec,
3331 _ => 0,
3332 }
3333}
3334
3335#[no_mangle]
3336pub unsafe extern "C" fn libinput_event_tablet_pad_get_time(event: *const LibinputEvent) -> u32 {
3337 (libinput_event_tablet_pad_get_time_usec(event) / 1000) as u32
3338}
3339
3340#[no_mangle]
3341pub unsafe extern "C" fn libinput_event_tablet_tool_get_button(event: *const LibinputEvent) -> u32 {
3342 if event.is_null() {
3343 return 0;
3344 }
3345 match &(*event).payload {
3346 EventPayload::TabletTool(tablet) => tablet.button,
3347 _ => 0,
3348 }
3349}
3350
3351#[no_mangle]
3352pub unsafe extern "C" fn libinput_event_tablet_tool_get_button_state(
3353 event: *const LibinputEvent,
3354) -> u32 {
3355 if event.is_null() {
3356 return 0;
3357 }
3358 match &(*event).payload {
3359 EventPayload::TabletTool(tablet) => tablet.button_state,
3360 _ => 0,
3361 }
3362}
3363
3364#[no_mangle]
3365pub unsafe extern "C" fn libinput_event_tablet_tool_get_seat_button_count(
3366 event: *const LibinputEvent,
3367) -> u32 {
3368 if event.is_null() {
3369 return 0;
3370 }
3371 match &(*event).payload {
3372 EventPayload::TabletTool(tablet) => tablet.seat_button_count,
3373 _ => 0,
3374 }
3375}
3376
3377#[no_mangle]
3378pub unsafe extern "C" fn libinput_event_tablet_tool_get_distance(
3379 event: *const LibinputEvent,
3380) -> f64 {
3381 if event.is_null() {
3382 return 0.0;
3383 }
3384 match &(*event).payload {
3385 EventPayload::TabletTool(tablet) => tablet.distance,
3386 _ => 0.0,
3387 }
3388}
3389
3390#[no_mangle]
3391pub unsafe extern "C" fn libinput_event_tablet_tool_get_dx(event: *const LibinputEvent) -> f64 {
3392 if event.is_null() || (*event).event_type != LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_AXIS
3393 {
3394 return 0.0;
3395 }
3396 match &(*event).payload {
3397 EventPayload::TabletTool(tablet) => tablet.dx,
3398 _ => 0.0,
3399 }
3400}
3401
3402#[no_mangle]
3403pub unsafe extern "C" fn libinput_event_tablet_tool_get_dy(event: *const LibinputEvent) -> f64 {
3404 if event.is_null() || (*event).event_type != LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_AXIS
3405 {
3406 return 0.0;
3407 }
3408 match &(*event).payload {
3409 EventPayload::TabletTool(tablet) => tablet.dy,
3410 _ => 0.0,
3411 }
3412}
3413
3414#[no_mangle]
3415pub unsafe extern "C" fn libinput_event_tablet_tool_get_pressure(
3416 event: *const LibinputEvent,
3417) -> f64 {
3418 if event.is_null() {
3419 return 0.0;
3420 }
3421 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3422 let range = tablet.pressure_max - tablet.pressure_min;
3423 if range > 0.0 {
3424 ((tablet.pressure - tablet.pressure_min) / range).clamp(0.0, 1.0)
3425 } else {
3426 0.0
3427 }
3428 } else {
3429 0.0
3430 }
3431}
3432
3433#[no_mangle]
3434pub unsafe extern "C" fn libinput_event_tablet_tool_get_x(event: *const LibinputEvent) -> f64 {
3435 if event.is_null() {
3436 return 0.0;
3437 }
3438 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3439 if tablet.x_resolution > 0.0 {
3440 (tablet.x - tablet.x_min) / tablet.x_resolution
3441 } else {
3442 tablet.x - tablet.x_min
3443 }
3444 } else {
3445 0.0
3446 }
3447}
3448
3449#[no_mangle]
3450pub unsafe extern "C" fn libinput_event_tablet_tool_get_y(event: *const LibinputEvent) -> f64 {
3451 if event.is_null() {
3452 return 0.0;
3453 }
3454 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3455 if tablet.y_resolution > 0.0 {
3456 (tablet.y - tablet.y_min) / tablet.y_resolution
3457 } else {
3458 tablet.y - tablet.y_min
3459 }
3460 } else {
3461 0.0
3462 }
3463}
3464
3465#[no_mangle]
3466pub unsafe extern "C" fn libinput_event_tablet_tool_get_proximity_state(
3467 event: *const LibinputEvent,
3468) -> u32 {
3469 if event.is_null() {
3470 return 0;
3471 }
3472 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3473 tablet.proximity_state
3474 } else {
3475 0
3476 }
3477}
3478
3479#[no_mangle]
3480pub unsafe extern "C" fn libinput_event_tablet_tool_get_rotation(
3481 event: *const LibinputEvent,
3482) -> f64 {
3483 if event.is_null() {
3484 return 0.0;
3485 }
3486 match &(*event).payload {
3487 EventPayload::TabletTool(tablet) => tablet.rotation,
3488 _ => 0.0,
3489 }
3490}
3491
3492#[no_mangle]
3493pub unsafe extern "C" fn libinput_event_tablet_tool_get_slider_position(
3494 event: *const LibinputEvent,
3495) -> f64 {
3496 if event.is_null() {
3497 return 0.0;
3498 }
3499 match &(*event).payload {
3500 EventPayload::TabletTool(tablet) => tablet.slider,
3501 _ => 0.0,
3502 }
3503}
3504
3505#[no_mangle]
3506pub unsafe extern "C" fn libinput_event_tablet_tool_get_wheel_delta(
3507 event: *const LibinputEvent,
3508) -> f64 {
3509 if event.is_null() {
3510 return 0.0;
3511 }
3512 match &(*event).payload {
3513 EventPayload::TabletTool(tablet) => tablet.wheel_delta,
3514 _ => 0.0,
3515 }
3516}
3517
3518#[no_mangle]
3519pub unsafe extern "C" fn libinput_event_tablet_tool_get_wheel_delta_discrete(
3520 event: *const LibinputEvent,
3521) -> i32 {
3522 if event.is_null() {
3523 return 0;
3524 }
3525 match &(*event).payload {
3526 EventPayload::TabletTool(tablet) => tablet.wheel_discrete,
3527 _ => 0,
3528 }
3529}
3530
3531#[no_mangle]
3532pub unsafe extern "C" fn libinput_event_tablet_tool_get_size_major(
3533 event: *const LibinputEvent,
3534) -> f64 {
3535 if event.is_null() {
3536 return 0.0;
3537 }
3538 match &(*event).payload {
3539 EventPayload::TabletTool(tablet) => tablet.size_major,
3540 _ => 0.0,
3541 }
3542}
3543
3544#[no_mangle]
3545pub unsafe extern "C" fn libinput_event_tablet_tool_get_size_minor(
3546 event: *const LibinputEvent,
3547) -> f64 {
3548 if event.is_null() {
3549 return 0.0;
3550 }
3551 match &(*event).payload {
3552 EventPayload::TabletTool(tablet) => tablet.size_minor,
3553 _ => 0.0,
3554 }
3555}
3556
3557#[no_mangle]
3558pub unsafe extern "C" fn libinput_event_tablet_tool_get_tilt_x(event: *const LibinputEvent) -> f64 {
3559 if event.is_null() {
3560 return 0.0;
3561 }
3562 match &(*event).payload {
3563 EventPayload::TabletTool(tablet) => tablet.tilt_x,
3564 _ => 0.0,
3565 }
3566}
3567
3568#[no_mangle]
3569pub unsafe extern "C" fn libinput_event_tablet_tool_get_tilt_y(event: *const LibinputEvent) -> f64 {
3570 if event.is_null() {
3571 return 0.0;
3572 }
3573 match &(*event).payload {
3574 EventPayload::TabletTool(tablet) => tablet.tilt_y,
3575 _ => 0.0,
3576 }
3577}
3578
3579#[no_mangle]
3580pub unsafe extern "C" fn libinput_event_tablet_tool_get_time_usec(
3581 event: *const LibinputEvent,
3582) -> u64 {
3583 if event.is_null() {
3584 return 0;
3585 }
3586 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3587 tablet.time_usec
3588 } else {
3589 0
3590 }
3591}
3592
3593#[no_mangle]
3594pub unsafe extern "C" fn libinput_event_tablet_tool_get_time(event: *const LibinputEvent) -> u32 {
3595 (libinput_event_tablet_tool_get_time_usec(event) / 1000) as u32
3596}
3597
3598#[no_mangle]
3599pub unsafe extern "C" fn libinput_event_tablet_tool_get_tip_state(
3600 event: *const LibinputEvent,
3601) -> u32 {
3602 if event.is_null() {
3603 return 0;
3604 }
3605 match &(*event).payload {
3606 EventPayload::TabletTool(tablet) => tablet.tip_state,
3607 _ => 0,
3608 }
3609}
3610
3611#[no_mangle]
3612pub unsafe extern "C" fn libinput_event_tablet_tool_get_tool(
3613 event: *const LibinputEvent,
3614) -> *mut libc::c_void {
3615 if event.is_null() {
3616 return std::ptr::null_mut();
3617 }
3618 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3619 tablet.tool.cast()
3620 } else {
3621 std::ptr::null_mut()
3622 }
3623}
3624
3625#[no_mangle]
3626pub unsafe extern "C" fn libinput_event_tablet_tool_get_x_transformed(
3627 event: *const LibinputEvent,
3628 width: u32,
3629) -> f64 {
3630 if event.is_null() {
3631 return 0.0;
3632 }
3633 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3634 let range = tablet.x_max - tablet.x_min + 1.0;
3635 if range > 0.0 {
3636 (tablet.x - tablet.x_min) * f64::from(width) / range
3637 } else {
3638 0.0
3639 }
3640 } else {
3641 0.0
3642 }
3643}
3644
3645#[no_mangle]
3646pub unsafe extern "C" fn libinput_event_tablet_tool_get_y_transformed(
3647 event: *const LibinputEvent,
3648 height: u32,
3649) -> f64 {
3650 if event.is_null() {
3651 return 0.0;
3652 }
3653 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3654 let range = tablet.y_max - tablet.y_min + 1.0;
3655 if range > 0.0 {
3656 (tablet.y - tablet.y_min) * f64::from(height) / range
3657 } else {
3658 0.0
3659 }
3660 } else {
3661 0.0
3662 }
3663}
3664
3665#[no_mangle]
3666pub unsafe extern "C" fn libinput_event_tablet_tool_x_has_changed(
3667 event: *const LibinputEvent,
3668) -> libc::c_int {
3669 if event.is_null() {
3670 return 0;
3671 }
3672 match &(*event).payload {
3673 EventPayload::TabletTool(tablet) => tablet.x_changed as libc::c_int,
3674 _ => 0,
3675 }
3676}
3677
3678#[no_mangle]
3679pub unsafe extern "C" fn libinput_event_tablet_tool_y_has_changed(
3680 event: *const LibinputEvent,
3681) -> libc::c_int {
3682 if event.is_null() {
3683 return 0;
3684 }
3685 match &(*event).payload {
3686 EventPayload::TabletTool(tablet) => tablet.y_changed as libc::c_int,
3687 _ => 0,
3688 }
3689}
3690
3691#[no_mangle]
3692pub unsafe extern "C" fn libinput_event_tablet_tool_pressure_has_changed(
3693 event: *const LibinputEvent,
3694) -> libc::c_int {
3695 if event.is_null() {
3696 return 0;
3697 }
3698 match &(*event).payload {
3699 EventPayload::TabletTool(tablet) => tablet.pressure_changed as libc::c_int,
3700 _ => 0,
3701 }
3702}
3703
3704#[no_mangle]
3705pub unsafe extern "C" fn libinput_event_tablet_tool_distance_has_changed(
3706 event: *const LibinputEvent,
3707) -> libc::c_int {
3708 if event.is_null() {
3709 return 0;
3710 }
3711 match &(*event).payload {
3712 EventPayload::TabletTool(tablet) => tablet.distance_changed as libc::c_int,
3713 _ => 0,
3714 }
3715}
3716
3717#[no_mangle]
3718pub unsafe extern "C" fn libinput_event_tablet_tool_tilt_x_has_changed(
3719 event: *const LibinputEvent,
3720) -> libc::c_int {
3721 if event.is_null() {
3722 return 0;
3723 }
3724 match &(*event).payload {
3725 EventPayload::TabletTool(tablet) => tablet.tilt_x_changed as libc::c_int,
3726 _ => 0,
3727 }
3728}
3729
3730#[no_mangle]
3731pub unsafe extern "C" fn libinput_event_tablet_tool_tilt_y_has_changed(
3732 event: *const LibinputEvent,
3733) -> libc::c_int {
3734 if event.is_null() {
3735 return 0;
3736 }
3737 match &(*event).payload {
3738 EventPayload::TabletTool(tablet) => tablet.tilt_y_changed as libc::c_int,
3739 _ => 0,
3740 }
3741}
3742
3743#[no_mangle]
3744pub unsafe extern "C" fn libinput_event_tablet_tool_rotation_has_changed(
3745 event: *const LibinputEvent,
3746) -> libc::c_int {
3747 if event.is_null() {
3748 return 0;
3749 }
3750 match &(*event).payload {
3751 EventPayload::TabletTool(tablet) => tablet.rotation_changed as libc::c_int,
3752 _ => 0,
3753 }
3754}
3755
3756#[no_mangle]
3757pub unsafe extern "C" fn libinput_event_tablet_tool_slider_has_changed(
3758 event: *const LibinputEvent,
3759) -> libc::c_int {
3760 if event.is_null() {
3761 return 0;
3762 }
3763 match &(*event).payload {
3764 EventPayload::TabletTool(tablet) => tablet.slider_changed as libc::c_int,
3765 _ => 0,
3766 }
3767}
3768
3769#[no_mangle]
3770pub unsafe extern "C" fn libinput_event_tablet_tool_wheel_has_changed(
3771 event: *const LibinputEvent,
3772) -> libc::c_int {
3773 if event.is_null() {
3774 return 0;
3775 }
3776 match &(*event).payload {
3777 EventPayload::TabletTool(tablet) => tablet.wheel_changed as libc::c_int,
3778 _ => 0,
3779 }
3780}
3781
3782#[no_mangle]
3783pub unsafe extern "C" fn libinput_event_tablet_tool_size_major_has_changed(
3784 event: *const LibinputEvent,
3785) -> libc::c_int {
3786 if event.is_null() {
3787 return 0;
3788 }
3789 match &(*event).payload {
3790 EventPayload::TabletTool(tablet) => tablet.size_major_changed as libc::c_int,
3791 _ => 0,
3792 }
3793}
3794
3795#[no_mangle]
3796pub unsafe extern "C" fn libinput_event_tablet_tool_size_minor_has_changed(
3797 event: *const LibinputEvent,
3798) -> libc::c_int {
3799 if event.is_null() {
3800 return 0;
3801 }
3802 match &(*event).payload {
3803 EventPayload::TabletTool(tablet) => tablet.size_minor_changed as libc::c_int,
3804 _ => 0,
3805 }
3806}
3807
3808#[no_mangle]
3809pub unsafe extern "C" fn libinput_plugin_system_append_default_paths(ctx: *mut LibinputContext) {
3810 if ctx.is_null() || (*ctx).plugins_loaded {
3811 return;
3812 }
3813 for path in ["/etc/libinput/plugins", "/usr/lib64/libinput/plugins"] {
3814 let path = std::ffi::CString::new(path).expect("static plugin path");
3815 if !(*ctx)
3816 .plugin_paths
3817 .iter()
3818 .any(|candidate| candidate.as_bytes() == path.as_bytes())
3819 {
3820 (*ctx).plugin_paths.push(path);
3821 }
3822 }
3823}
3824
3825#[no_mangle]
3826pub unsafe extern "C" fn libinput_plugin_system_append_path(
3827 ctx: *mut LibinputContext,
3828 path: *const libc::c_char,
3829) {
3830 if ctx.is_null() || path.is_null() || (*ctx).plugins_loaded {
3831 return;
3832 }
3833 let path = CStr::from_ptr(path);
3834 if (*ctx)
3835 .plugin_paths
3836 .iter()
3837 .any(|candidate| candidate.as_bytes() == path.to_bytes())
3838 {
3839 return;
3840 }
3841 if let Ok(path) = std::ffi::CString::new(path.to_bytes()) {
3842 (*ctx).plugin_paths.push(path);
3843 }
3844}
3845
3846#[no_mangle]
3847pub unsafe extern "C" fn libinput_plugin_system_load_plugins(
3848 ctx: *mut LibinputContext,
3849 _flags: libc::c_uint,
3850) -> libc::c_int {
3851 if ctx.is_null() {
3852 return -libc::EINVAL;
3853 }
3854 if (*ctx).plugins_loaded {
3855 return 0;
3856 }
3857 (*ctx).plugins_loaded = true;
3861 -libc::ENOSYS
3862}
3863
3864#[no_mangle]
3865pub unsafe extern "C" fn libinput_tablet_pad_mode_group_button_is_toggle(
3866 group: *const libc::c_void,
3867 button: u32,
3868) -> libc::c_int {
3869 if group.is_null() || button >= u32::BITS {
3870 return 0;
3871 }
3872 ((*group.cast::<LibinputTabletPadModeGroup>()).toggle_button_mask & (1_u32 << button) != 0)
3873 as libc::c_int
3874}
3875
3876#[no_mangle]
3877pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_index(
3878 group: *const libc::c_void,
3879) -> u32 {
3880 if group.is_null() {
3881 return 0;
3882 }
3883 (*group.cast::<LibinputTabletPadModeGroup>()).index
3884}
3885
3886#[no_mangle]
3887pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_mode(
3888 group: *const libc::c_void,
3889) -> u32 {
3890 if group.is_null() {
3891 return 0;
3892 }
3893 (*group.cast::<LibinputTabletPadModeGroup>()).current_mode
3894}
3895
3896#[no_mangle]
3897pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_num_modes(
3898 group: *const libc::c_void,
3899) -> u32 {
3900 if group.is_null() {
3901 return 0;
3902 }
3903 (*group.cast::<LibinputTabletPadModeGroup>()).num_modes
3904}
3905
3906#[no_mangle]
3907pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_button(
3908 group: *const libc::c_void,
3909 button: u32,
3910) -> libc::c_int {
3911 if group.is_null() {
3912 return 0;
3913 }
3914 if button >= u32::BITS {
3915 return 0;
3916 }
3917 ((*group.cast::<LibinputTabletPadModeGroup>()).button_mask & (1_u32 << button) != 0)
3918 as libc::c_int
3919}
3920
3921#[no_mangle]
3922pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_dial(
3923 group: *const libc::c_void,
3924 dial: u32,
3925) -> libc::c_int {
3926 if group.is_null() {
3927 return 0;
3928 }
3929 if dial >= u32::BITS {
3930 return 0;
3931 }
3932 ((*group.cast::<LibinputTabletPadModeGroup>()).dial_mask & (1_u32 << dial) != 0) as libc::c_int
3933}
3934
3935#[no_mangle]
3936pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_ring(
3937 group: *const libc::c_void,
3938 ring: u32,
3939) -> libc::c_int {
3940 if group.is_null() {
3941 return 0;
3942 }
3943 if ring >= u32::BITS {
3944 return 0;
3945 }
3946 ((*group.cast::<LibinputTabletPadModeGroup>()).ring_mask & (1_u32 << ring) != 0) as libc::c_int
3947}
3948
3949#[no_mangle]
3950pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_strip(
3951 group: *const libc::c_void,
3952 strip: u32,
3953) -> libc::c_int {
3954 if group.is_null() {
3955 return 0;
3956 }
3957 if strip >= u32::BITS {
3958 return 0;
3959 }
3960 ((*group.cast::<LibinputTabletPadModeGroup>()).strip_mask & (1_u32 << strip) != 0)
3961 as libc::c_int
3962}
3963
3964#[no_mangle]
3965pub unsafe extern "C" fn libinput_tablet_pad_mode_group_ref(
3966 group: *mut libc::c_void,
3967) -> *mut libc::c_void {
3968 if !group.is_null() {
3969 (*group.cast::<LibinputTabletPadModeGroup>())
3970 .refcount
3971 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
3972 }
3973 group
3974}
3975
3976#[no_mangle]
3977pub unsafe extern "C" fn libinput_tablet_pad_mode_group_unref(
3978 group: *mut libc::c_void,
3979) -> *mut libc::c_void {
3980 if group.is_null() {
3981 return std::ptr::null_mut();
3982 }
3983 let group = group.cast::<LibinputTabletPadModeGroup>();
3984 if (*group)
3985 .refcount
3986 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
3987 == 1
3988 {
3989 drop(Box::from_raw(group));
3990 std::ptr::null_mut()
3991 } else {
3992 group.cast()
3993 }
3994}
3995
3996#[no_mangle]
3997pub unsafe extern "C" fn libinput_tablet_pad_mode_group_set_user_data(
3998 group: *mut libc::c_void,
3999 data: *mut libc::c_void,
4000) {
4001 if !group.is_null() {
4002 (*group.cast::<LibinputTabletPadModeGroup>()).user_data = data;
4003 }
4004}
4005
4006#[no_mangle]
4007pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_user_data(
4008 group: *const libc::c_void,
4009) -> *mut libc::c_void {
4010 if group.is_null() {
4011 return std::ptr::null_mut();
4012 }
4013 (*group.cast::<LibinputTabletPadModeGroup>()).user_data
4014}
4015
4016#[no_mangle]
4017pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_is_available(
4018 tool: *const LibinputTabletTool,
4019) -> libc::c_int {
4020 (!tool.is_null() && (*tool).has_pressure) as libc::c_int
4021}
4022
4023#[no_mangle]
4024pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_set(
4025 tool: *mut LibinputTabletTool,
4026 minimum: f64,
4027 maximum: f64,
4028) -> u32 {
4029 if tool.is_null() || !(*tool).has_pressure {
4030 return 1;
4031 }
4032 if minimum < 0.0 || maximum > 1.0 || minimum >= maximum {
4033 return 2;
4034 }
4035 (*tool).wanted_pressure_range_minimum = minimum;
4036 (*tool).wanted_pressure_range_maximum = maximum;
4037 0
4038}
4039
4040#[no_mangle]
4041pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_minimum(
4042 tool: *const LibinputTabletTool,
4043) -> f64 {
4044 if tool.is_null() {
4045 0.0
4046 } else {
4047 (*tool).wanted_pressure_range_minimum
4048 }
4049}
4050
4051#[no_mangle]
4052pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_maximum(
4053 tool: *const LibinputTabletTool,
4054) -> f64 {
4055 if tool.is_null() {
4056 1.0
4057 } else {
4058 (*tool).wanted_pressure_range_maximum
4059 }
4060}
4061
4062#[no_mangle]
4063pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_default_minimum(
4064 _tool: *const libc::c_void,
4065) -> f64 {
4066 0.0
4067}
4068
4069#[no_mangle]
4070pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_default_maximum(
4071 _tool: *const libc::c_void,
4072) -> f64 {
4073 1.0
4074}
4075
4076#[no_mangle]
4077pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_modes(
4078 tool: *const libc::c_void,
4079) -> u32 {
4080 let tool = tool.cast::<LibinputTabletTool>();
4081 if tool.is_null() {
4082 0
4083 } else {
4084 (*tool).eraser_button_modes
4085 }
4086}
4087
4088#[no_mangle]
4089pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_set_mode(
4090 tool: *mut libc::c_void,
4091 mode: u32,
4092) -> u32 {
4093 let tool = tool.cast::<LibinputTabletTool>();
4094 if tool.is_null() || (mode != 0 && ((*tool).eraser_button_modes & mode) == 0) {
4095 return 1;
4096 }
4097 if !matches!(mode, 0 | 1) {
4098 return 2;
4099 }
4100 (*tool).wanted_eraser_button_mode = mode;
4101 if !(*tool).in_proximity {
4102 (*tool).eraser_button_mode = mode;
4103 }
4104 0
4105}
4106
4107#[no_mangle]
4108pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_mode(
4109 tool: *const libc::c_void,
4110) -> u32 {
4111 let tool = tool.cast::<LibinputTabletTool>();
4112 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4113 0
4114 } else {
4115 (*tool).wanted_eraser_button_mode
4116 }
4117}
4118
4119#[no_mangle]
4120pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_default_mode(
4121 _tool: *const libc::c_void,
4122) -> u32 {
4123 0
4124}
4125
4126#[no_mangle]
4127pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_set_button(
4128 tool: *mut libc::c_void,
4129 button: u32,
4130) -> u32 {
4131 let tool = tool.cast::<LibinputTabletTool>();
4132 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4133 return 1;
4134 }
4135 let is_button = matches!(button, 0x149 | 0x14b | 0x14c)
4136 || (0x100..0x140).contains(&button)
4137 || (0x150..=0x151).contains(&button)
4138 || (0x220..=0x223).contains(&button)
4139 || (0x2c0..=0x2e7).contains(&button);
4140 if !is_button {
4141 return 2;
4142 }
4143 (*tool).wanted_eraser_button = button;
4144 if !(*tool).in_proximity {
4145 (*tool).eraser_button = button;
4146 }
4147 0
4148}
4149
4150#[no_mangle]
4151pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_button(
4152 tool: *const libc::c_void,
4153) -> u32 {
4154 let tool = tool.cast::<LibinputTabletTool>();
4155 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4156 0
4157 } else {
4158 (*tool).wanted_eraser_button
4159 }
4160}
4161
4162#[no_mangle]
4163pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_default_button(
4164 tool: *const libc::c_void,
4165) -> u32 {
4166 let tool = tool.cast::<LibinputTabletTool>();
4167 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4168 0
4169 } else {
4170 (*tool).default_eraser_button
4171 }
4172}
4173
4174#[no_mangle]
4175pub unsafe extern "C" fn libinput_tablet_tool_get_name(
4176 tool: *const libc::c_void,
4177) -> *const libc::c_char {
4178 let tool = tool.cast::<LibinputTabletTool>();
4179 if tool.is_null() {
4180 return std::ptr::null();
4181 }
4182 let tool = tool.cast::<LibinputTabletTool>();
4183 let tool = tool as *mut LibinputTabletTool;
4184 if let Some(name) = (*tool).name.as_ref() {
4185 return name.as_ptr();
4186 }
4187 if let Some(name) = crate::backend::tablet_tool_name_for_id((*tool).tool_id) {
4188 (*tool).name = Some(name);
4189 (*tool)
4190 .name
4191 .as_ref()
4192 .map_or(std::ptr::null(), |name| name.as_ptr())
4193 } else {
4194 std::ptr::null()
4195 }
4196}
4197
4198#[no_mangle]
4199pub unsafe extern "C" fn libinput_tablet_tool_get_serial(tool: *const libc::c_void) -> u64 {
4200 let tool = tool.cast::<LibinputTabletTool>();
4201 if tool.is_null() {
4202 0
4203 } else {
4204 (*tool).serial
4205 }
4206}
4207
4208#[no_mangle]
4209pub unsafe extern "C" fn libinput_tablet_tool_get_tool_id(tool: *const libc::c_void) -> u64 {
4210 let tool = tool.cast::<LibinputTabletTool>();
4211 if tool.is_null() {
4212 0
4213 } else {
4214 (*tool).tool_id
4215 }
4216}
4217
4218#[no_mangle]
4219pub unsafe extern "C" fn libinput_tablet_tool_get_type(tool: *const libc::c_void) -> u32 {
4220 let tool = tool.cast::<LibinputTabletTool>();
4221 if tool.is_null() {
4222 0
4223 } else {
4224 (*tool).tool_type
4225 }
4226}
4227
4228#[no_mangle]
4229pub unsafe extern "C" fn libinput_tablet_tool_has_distance(
4230 tool: *const libc::c_void,
4231) -> libc::c_int {
4232 let tool = tool.cast::<LibinputTabletTool>();
4233 (!tool.is_null() && (*tool).has_distance) as libc::c_int
4234}
4235
4236#[no_mangle]
4237pub unsafe extern "C" fn libinput_tablet_tool_has_button(
4238 tool: *const libc::c_void,
4239 button: u32,
4240) -> libc::c_int {
4241 let tool = tool.cast::<LibinputTabletTool>();
4242 (!tool.is_null() && (*tool).buttons.contains(&button)) as libc::c_int
4243}
4244
4245#[no_mangle]
4246pub unsafe extern "C" fn libinput_tablet_tool_has_size(tool: *const libc::c_void) -> libc::c_int {
4247 let tool = tool.cast::<LibinputTabletTool>();
4248 (!tool.is_null() && (*tool).has_size) as libc::c_int
4249}
4250
4251#[no_mangle]
4252pub unsafe extern "C" fn libinput_tablet_tool_is_unique(tool: *const libc::c_void) -> libc::c_int {
4253 let tool = tool.cast::<LibinputTabletTool>();
4254 (!tool.is_null() && (*tool).serial != 0) as libc::c_int
4255}
4256
4257#[no_mangle]
4258pub unsafe extern "C" fn libinput_tablet_tool_set_user_data(
4259 tool: *mut libc::c_void,
4260 data: *mut libc::c_void,
4261) {
4262 let tool = tool.cast::<LibinputTabletTool>();
4263 if !tool.is_null() {
4264 (*tool).user_data = data;
4265 }
4266}
4267
4268#[no_mangle]
4269pub unsafe extern "C" fn libinput_tablet_tool_get_user_data(
4270 tool: *const libc::c_void,
4271) -> *mut libc::c_void {
4272 let tool = tool.cast::<LibinputTabletTool>();
4273 if tool.is_null() {
4274 std::ptr::null_mut()
4275 } else {
4276 (*tool).user_data
4277 }
4278}
4279
4280#[no_mangle]
4281pub unsafe extern "C" fn libinput_tablet_tool_has_pressure(
4282 tool: *const libc::c_void,
4283) -> libc::c_int {
4284 let tool = tool.cast::<LibinputTabletTool>();
4285 (!tool.is_null() && (*tool).has_pressure) as libc::c_int
4286}
4287
4288#[no_mangle]
4289pub unsafe extern "C" fn libinput_tablet_tool_has_rotation(
4290 tool: *const libc::c_void,
4291) -> libc::c_int {
4292 let tool = tool.cast::<LibinputTabletTool>();
4293 (!tool.is_null() && (*tool).has_rotation) as libc::c_int
4294}
4295
4296#[no_mangle]
4297pub unsafe extern "C" fn libinput_tablet_tool_has_slider(tool: *const libc::c_void) -> libc::c_int {
4298 let tool = tool.cast::<LibinputTabletTool>();
4299 (!tool.is_null() && (*tool).has_slider) as libc::c_int
4300}
4301
4302#[no_mangle]
4303pub unsafe extern "C" fn libinput_tablet_tool_has_tilt(tool: *const libc::c_void) -> libc::c_int {
4304 let tool = tool.cast::<LibinputTabletTool>();
4305 (!tool.is_null() && (*tool).has_tilt) as libc::c_int
4306}
4307
4308#[no_mangle]
4309pub unsafe extern "C" fn libinput_tablet_tool_has_wheel(tool: *const libc::c_void) -> libc::c_int {
4310 let tool = tool.cast::<LibinputTabletTool>();
4311 (!tool.is_null() && (*tool).has_wheel) as libc::c_int
4312}
4313
4314#[no_mangle]
4315pub unsafe extern "C" fn libinput_tablet_tool_ref(tool: *mut libc::c_void) -> *mut libc::c_void {
4316 let tablet_tool = tool.cast::<LibinputTabletTool>();
4317 if !tablet_tool.is_null() {
4318 (*tablet_tool)
4319 .refcount
4320 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
4321 }
4322 tool
4323}
4324
4325#[no_mangle]
4326pub unsafe extern "C" fn libinput_tablet_tool_unref(tool: *mut libc::c_void) -> *mut libc::c_void {
4327 let tablet_tool = tool.cast::<LibinputTabletTool>();
4328 if tablet_tool.is_null() {
4329 return std::ptr::null_mut();
4330 }
4331 if (*tablet_tool)
4332 .refcount
4333 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
4334 == 1
4335 {
4336 if !(*tablet_tool).device.is_null() {
4337 libinput_device_unref((*tablet_tool).device);
4338 (*tablet_tool).device = std::ptr::null_mut();
4339 }
4340 drop(Box::from_raw(tablet_tool));
4341 std::ptr::null_mut()
4342 } else {
4343 tool
4344 }
4345}
4346
4347#[no_mangle]
4352pub unsafe extern "C" fn libinput_suspend(ctx: *mut LibinputContext) {
4353 if ctx.is_null() {
4354 return;
4355 }
4356 let mut events = std::collections::VecDeque::new();
4357 if let Ok(mut backend) = (*ctx).backend.lock() {
4358 backend.suspend(ctx, &mut events);
4359 }
4360 enqueue_events(ctx, events);
4361}
4362
4363#[no_mangle]
4364pub unsafe extern "C" fn libinput_resume(ctx: *mut LibinputContext) -> libc::c_int {
4365 if ctx.is_null() {
4366 return -1;
4367 }
4368 let mut events = std::collections::VecDeque::new();
4369 let status = if let Ok(mut backend) = (*ctx).backend.lock() {
4370 backend.resume(ctx, &mut events)
4371 } else {
4372 return -1;
4373 };
4374 enqueue_events(ctx, events);
4375 if !(*ctx).event_queue.is_empty() {
4376 (*ctx).signal_fd();
4377 }
4378 status
4379}
4380
4381#[cfg(test)]
4382mod tests {
4383 use super::*;
4384
4385 unsafe extern "C" fn deny_open(
4386 _path: *const libc::c_char,
4387 _flags: libc::c_int,
4388 _user_data: *mut libc::c_void,
4389 ) -> libc::c_int {
4390 -libc::EACCES
4391 }
4392
4393 unsafe extern "C" fn close_fd(_fd: libc::c_int, _user_data: *mut libc::c_void) {}
4394
4395 static INTERFACE: LibinputInterface = LibinputInterface {
4396 open_restricted: Some(deny_open),
4397 close_restricted: Some(close_fd),
4398 };
4399
4400 #[test]
4401 fn udev_context_requires_interface_and_udev() {
4402 unsafe {
4403 let fake_udev = 1usize as *mut libc::c_void;
4404 assert!(libinput_udev_create_context(
4405 std::ptr::null(),
4406 std::ptr::null_mut(),
4407 fake_udev,
4408 )
4409 .is_null());
4410 assert!(libinput_udev_create_context(
4411 &INTERFACE,
4412 std::ptr::null_mut(),
4413 std::ptr::null_mut(),
4414 )
4415 .is_null());
4416 }
4417 }
4418
4419 #[test]
4420 fn seat_assignment_is_udev_only_and_happens_once() {
4421 unsafe {
4422 let fake_udev = 1usize as *mut libc::c_void;
4423 let seat = std::ffi::CString::new("seat0").unwrap();
4424 let udev_ctx =
4425 libinput_udev_create_context(&INTERFACE, std::ptr::null_mut(), fake_udev);
4426 assert!(!udev_ctx.is_null());
4427 assert_eq!(libinput_udev_assign_seat(udev_ctx, seat.as_ptr()), 0);
4428 assert_eq!(libinput_udev_assign_seat(udev_ctx, seat.as_ptr()), -1);
4429 libinput_unref(udev_ctx);
4430
4431 let path_ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4432 assert!(!path_ctx.is_null());
4433 assert_eq!(libinput_udev_assign_seat(path_ctx, seat.as_ptr()), -1);
4434 libinput_unref(path_ctx);
4435 }
4436 }
4437
4438 #[test]
4439 fn overlong_seat_name_does_not_assign_or_queue_devices() {
4440 unsafe {
4441 let fake_udev = 1usize as *mut libc::c_void;
4442 let seat = std::ffi::CString::new("a".repeat(257)).unwrap();
4443 let ctx = libinput_udev_create_context(&INTERFACE, std::ptr::null_mut(), fake_udev);
4444 assert!(!ctx.is_null());
4445
4446 assert_eq!(libinput_udev_assign_seat(ctx, seat.as_ptr()), -1);
4447 assert!(!(*ctx).seat_assigned);
4448 assert!((*ctx).event_queue.is_empty());
4449
4450 libinput_unref(ctx);
4451 }
4452 }
4453
4454 #[test]
4455 fn suspend_and_resume_are_null_safe() {
4456 unsafe {
4457 libinput_suspend(std::ptr::null_mut());
4458 assert_eq!(libinput_resume(std::ptr::null_mut()), -1);
4459 }
4460 }
4461
4462 #[test]
4463 fn dispatch_returns_negative_errno_on_epoll_failure() {
4464 unsafe {
4465 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4466 assert!(!ctx.is_null());
4467 libc::close((*ctx).epoll_fd);
4468 (*ctx).epoll_fd = -1;
4469 assert_eq!(libinput_dispatch(ctx), -libc::EBADF);
4470 libinput_unref(ctx);
4471 }
4472 }
4473
4474 #[test]
4475 fn shared_device_groups_preserve_identity_and_user_data() {
4476 unsafe {
4477 let first = Box::new(LibinputDevice::new(
4478 "first",
4479 "/dev/input/event0",
4480 std::ptr::null_mut(),
4481 std::ptr::null_mut(),
4482 ));
4483 let group = first.group;
4484 let mut second = Box::new(LibinputDevice::new(
4485 "second",
4486 "/dev/input/event1",
4487 std::ptr::null_mut(),
4488 std::ptr::null_mut(),
4489 ));
4490 second.share_group(group);
4491
4492 assert_eq!(second.group, group);
4493 assert_eq!(second.abi.group, group);
4494 assert_eq!(
4495 (*group).refcount.load(std::sync::atomic::Ordering::Relaxed),
4496 2
4497 );
4498 let marker = 0x5ausize as *mut libc::c_void;
4499 libinput_device_group_set_user_data(group.cast(), marker);
4500 assert_eq!(
4501 libinput_device_group_get_user_data(second.group.cast()),
4502 marker
4503 );
4504
4505 drop(second);
4506 assert_eq!(
4507 (*group).refcount.load(std::sync::atomic::Ordering::Relaxed),
4508 1
4509 );
4510 drop(first);
4511 }
4512 }
4513
4514 #[test]
4515 fn custom_acceleration_validates_and_copies_curves() {
4516 unsafe {
4517 assert!(libinput_config_accel_create(0).is_null());
4518 let config = libinput_config_accel_create(4);
4519 assert!(!config.is_null());
4520
4521 let one_point = [1.0];
4522 assert_eq!(
4523 libinput_config_accel_set_points(config, 1, 1.0, 1, one_point.as_ptr()),
4524 2
4525 );
4526 let points = [0.0, 2.0, 6.0];
4527 assert_eq!(
4528 libinput_config_accel_set_points(config, 1, 1.0, points.len(), points.as_ptr()),
4529 0
4530 );
4531 let scroll_points = [0.0, 3.0, 9.0];
4532 assert_eq!(
4533 libinput_config_accel_set_points(
4534 config,
4535 2,
4536 1.0,
4537 scroll_points.len(),
4538 scroll_points.as_ptr(),
4539 ),
4540 0
4541 );
4542
4543 let mut device = Box::new(LibinputDevice::new(
4544 "pointer",
4545 "/dev/input/event0",
4546 std::ptr::null_mut(),
4547 std::ptr::null_mut(),
4548 ));
4549 device.accel_available = true;
4550 assert_eq!(libinput_device_config_accel_apply(&mut *device, config), 0);
4551 libinput_config_accel_destroy(config);
4552
4553 let custom = device.accel_custom.as_mut().expect("custom config copied");
4554 let curve = custom.curve_mut(1).expect("motion curve copied");
4555 assert_eq!(curve.points, points);
4556 assert!((curve.factor(7.0, 0.0, 7_000) - 2.0).abs() < 1e-9);
4557 let scroll_curve = custom.curve_mut(2).expect("scroll curve copied");
4558 assert_eq!(scroll_curve.points, scroll_points);
4559 assert!((scroll_curve.factor(7.0, 0.0, 7_000) - 3.0).abs() < 1e-9);
4560 }
4561 }
4562
4563 #[test]
4564 fn custom_acceleration_uses_fallback_and_extrapolates() {
4565 let mut config = crate::ffi_types::AccelConfig::new(4);
4566 config.fallback = Some(crate::ffi_types::AccelCurve::new(1.0, vec![0.0, 1.0]));
4567 let curve = config.curve_mut(1).expect("fallback curve");
4568 assert!((curve.factor(14.0, 0.0, 7_000) - 1.0).abs() < 1e-9);
4569 }
4570
4571 #[test]
4572 fn plugin_paths_are_ordered_unique_and_frozen_after_load() {
4573 unsafe {
4574 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4575 let custom = std::ffi::CString::new("/tmp/plugins").unwrap();
4576 let empty = std::ffi::CString::new("").unwrap();
4577 libinput_plugin_system_append_path(ctx, custom.as_ptr());
4578 libinput_plugin_system_append_path(ctx, custom.as_ptr());
4579 libinput_plugin_system_append_path(ctx, empty.as_ptr());
4580 libinput_plugin_system_append_default_paths(ctx);
4581 assert_eq!((*ctx).plugin_paths.len(), 4);
4582 assert_eq!((&(*ctx).plugin_paths)[0].as_bytes(), b"/tmp/plugins");
4583 assert_eq!((&(*ctx).plugin_paths)[1].as_bytes(), b"");
4584 assert_eq!(
4585 libinput_plugin_system_load_plugins(ctx, u32::MAX),
4586 -libc::ENOSYS
4587 );
4588 let ignored = std::ffi::CString::new("/ignored").unwrap();
4589 libinput_plugin_system_append_path(ctx, ignored.as_ptr());
4590 assert_eq!((*ctx).plugin_paths.len(), 4);
4591 assert_eq!(libinput_plugin_system_load_plugins(ctx, 0), 0);
4592 libinput_unref(ctx);
4593 }
4594 }
4595
4596 #[test]
4597 fn queued_events_retain_devices_until_event_destroy() {
4598 unsafe {
4599 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4600 let device = Box::into_raw(Box::new(LibinputDevice::new(
4601 "keyboard",
4602 "/dev/input/event0",
4603 std::ptr::null_mut(),
4604 ctx,
4605 )));
4606 enqueue_event(
4607 ctx,
4608 LibinputEvent {
4609 event_type: LibinputEventType::LIBINPUT_EVENT_KEYBOARD_KEY,
4610 payload: EventPayload::KeyboardKey(crate::ffi_types::KeyboardKeyEvent {
4611 time_usec: 1,
4612 key: 30,
4613 state: 1,
4614 seat_key_count: 1,
4615 }),
4616 context: ctx,
4617 device,
4618 },
4619 );
4620 assert_eq!(
4621 (*device).refcount.load(std::sync::atomic::Ordering::SeqCst),
4622 2
4623 );
4624 let event = libinput_get_event(ctx);
4625 assert_eq!(libinput_event_get_device(event), device);
4626 libinput_event_destroy(event);
4627 assert_eq!(
4628 (*device).refcount.load(std::sync::atomic::Ordering::SeqCst),
4629 1
4630 );
4631 assert!(libinput_device_unref(device).is_null());
4632 libinput_unref(ctx);
4633 }
4634 }
4635
4636 #[test]
4637 fn ref_and_unref_return_the_upstream_object_lifecycle() {
4638 unsafe {
4639 let seat = Box::into_raw(Box::new(LibinputSeat {
4640 physical_name: std::ffi::CString::new("seat0").unwrap(),
4641 logical_name: std::ffi::CString::new("default").unwrap(),
4642 refcount: std::sync::atomic::AtomicI32::new(1),
4643 user_data: std::ptr::null_mut(),
4644 context: std::ptr::null_mut(),
4645 button_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4646 key_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4647 }));
4648 assert_eq!(libinput_seat_ref(seat.cast()), seat.cast());
4649 assert_eq!(libinput_seat_unref(seat.cast()), seat.cast());
4650 assert!(libinput_seat_unref(seat.cast()).is_null());
4651
4652 let group = Box::into_raw(Box::new(LibinputTabletPadModeGroup {
4653 refcount: std::sync::atomic::AtomicI32::new(1),
4654 user_data: std::ptr::null_mut(),
4655 device: std::ptr::null_mut(),
4656 index: 0,
4657 num_modes: 1,
4658 current_mode: 0,
4659 button_mask: 0,
4660 dial_mask: 0,
4661 ring_mask: 0,
4662 strip_mask: 0,
4663 toggle_button_mask: 0,
4664 toggle_modes: Vec::new(),
4665 }));
4666 assert_eq!(
4667 libinput_tablet_pad_mode_group_ref(group.cast()),
4668 group.cast()
4669 );
4670 assert_eq!(
4671 libinput_tablet_pad_mode_group_unref(group.cast()),
4672 group.cast()
4673 );
4674 assert!(libinput_tablet_pad_mode_group_unref(group.cast()).is_null());
4675 }
4676 }
4677
4678 #[test]
4679 fn devices_retain_their_seat_until_device_destruction() {
4680 unsafe {
4681 let seat = Box::into_raw(Box::new(LibinputSeat {
4682 physical_name: std::ffi::CString::new("seat0").unwrap(),
4683 logical_name: std::ffi::CString::new("default").unwrap(),
4684 refcount: std::sync::atomic::AtomicI32::new(1),
4685 user_data: std::ptr::null_mut(),
4686 context: std::ptr::null_mut(),
4687 button_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4688 key_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4689 }));
4690 let device = Box::into_raw(Box::new(LibinputDevice::new(
4691 "keyboard",
4692 "/dev/input/event0",
4693 seat,
4694 std::ptr::null_mut(),
4695 )));
4696 assert_eq!(
4697 (*seat).refcount.load(std::sync::atomic::Ordering::SeqCst),
4698 2
4699 );
4700 assert!(libinput_device_unref(device).is_null());
4701 assert_eq!(
4702 (*seat).refcount.load(std::sync::atomic::Ordering::SeqCst),
4703 1
4704 );
4705 assert!(libinput_seat_unref(seat.cast()).is_null());
4706 }
4707 }
4708
4709 #[test]
4710 fn config_status_strings_match_upstream() {
4711 unsafe {
4712 assert_eq!(
4713 std::ffi::CStr::from_ptr(libinput_config_status_to_str(0)).to_bytes(),
4714 b"Success"
4715 );
4716 assert_eq!(
4717 std::ffi::CStr::from_ptr(libinput_config_status_to_str(1)).to_bytes(),
4718 b"Unsupported configuration option"
4719 );
4720 assert_eq!(
4721 std::ffi::CStr::from_ptr(libinput_config_status_to_str(2)).to_bytes(),
4722 b"Invalid argument range"
4723 );
4724 assert!(libinput_config_status_to_str(3).is_null());
4725 }
4726 }
4727
4728 #[test]
4729 fn absolute_pointer_coordinates_snapshot_calibration_and_use_inclusive_ranges() {
4730 unsafe {
4731 let mut device = Box::new(LibinputDevice::new(
4732 "pointer",
4733 "/dev/input/event0",
4734 std::ptr::null_mut(),
4735 std::ptr::null_mut(),
4736 ));
4737 device.abs_x_resolution = Some(20);
4738 device.abs_y_resolution = Some(40);
4739 let event = LibinputEvent {
4740 event_type: LibinputEventType::LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
4741 payload: EventPayload::PointerMotionAbsolute(
4742 crate::ffi_types::PointerMotionAbsoluteEvent {
4743 time_usec: 1,
4744 abs_x: 110.0,
4745 abs_y: 220.0,
4746 x_min: 10.0,
4747 x_max: 1009.0,
4748 y_min: 20.0,
4749 y_max: 2019.0,
4750 calibration: [1.0, 0.0, 0.1, 0.0, 1.0, 0.0],
4751 },
4752 ),
4753 context: std::ptr::null_mut(),
4754 device: &mut *device,
4755 };
4756 device.calibration = [1.0, 0.0, 0.9, 0.0, 1.0, 0.0];
4757
4758 assert!((libinput_event_pointer_get_absolute_x(&event) - 10.0).abs() < 1e-6);
4759 assert_eq!(libinput_event_pointer_get_absolute_y(&event), 5.0);
4760 assert!(
4761 (libinput_event_pointer_get_absolute_x_transformed(&event, 100) - 20.0).abs()
4762 < 1e-6
4763 );
4764 assert_eq!(
4765 libinput_event_pointer_get_absolute_y_transformed(&event, 100),
4766 10.0
4767 );
4768 }
4769 }
4770
4771 #[test]
4772 fn touch_cancel_retains_slot_information() {
4773 unsafe {
4774 let event = LibinputEvent {
4775 event_type: LibinputEventType::LIBINPUT_EVENT_TOUCH_CANCEL,
4776 payload: EventPayload::TouchCancel(crate::ffi_types::TouchEvent {
4777 time_usec: 1,
4778 slot: 7,
4779 seat_slot: 11,
4780 x: 0.0,
4781 y: 0.0,
4782 calibration: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0],
4783 }),
4784 context: std::ptr::null_mut(),
4785 device: std::ptr::null_mut(),
4786 };
4787
4788 assert_eq!(libinput_event_touch_get_slot(&event), 7);
4789 assert_eq!(libinput_event_touch_get_seat_slot(&event), 11);
4790 }
4791 }
4792
4793 #[test]
4794 fn touch_coordinates_use_event_time_calibration() {
4795 unsafe {
4796 let mut device = Box::new(LibinputDevice::new(
4797 "touch",
4798 "/dev/input/event0",
4799 std::ptr::null_mut(),
4800 std::ptr::null_mut(),
4801 ));
4802 device.abs_x_range = Some((10, 1009));
4803 device.abs_y_range = Some((20, 2019));
4804 device.abs_x_resolution = Some(20);
4805 device.abs_y_resolution = Some(40);
4806 let event = LibinputEvent {
4807 event_type: LibinputEventType::LIBINPUT_EVENT_TOUCH_MOTION,
4808 payload: EventPayload::TouchMotion(crate::ffi_types::TouchEvent {
4809 time_usec: 1,
4810 slot: 0,
4811 seat_slot: 0,
4812 x: 110.0,
4813 y: 220.0,
4814 calibration: [1.0, 0.0, 0.1, 0.0, 1.0, 0.0],
4815 }),
4816 context: std::ptr::null_mut(),
4817 device: &mut *device,
4818 };
4819 device.calibration = [1.0, 0.0, 0.9, 0.0, 1.0, 0.0];
4820
4821 assert!((libinput_event_touch_get_x(&event) - 10.0).abs() < 1e-6);
4822 assert_eq!(libinput_event_touch_get_y(&event), 5.0);
4823 assert!((libinput_event_touch_get_x_transformed(&event, 100) - 20.0).abs() < 1e-6);
4824 assert_eq!(libinput_event_touch_get_y_transformed(&event, 100), 10.0);
4825 }
4826 }
4827
4828 #[test]
4829 fn tablet_deltas_are_exposed_only_for_axis_events() {
4830 unsafe {
4831 let mut event = LibinputEvent {
4832 event_type: LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_AXIS,
4833 payload: EventPayload::TabletTool(crate::ffi_types::TabletToolEvent {
4834 time_usec: 1,
4835 tool: std::ptr::null_mut(),
4836 proximity_state: 0,
4837 x: 0.0,
4838 y: 0.0,
4839 dx: 2.5,
4840 dy: -1.5,
4841 x_min: 0.0,
4842 x_max: 1.0,
4843 y_min: 0.0,
4844 y_max: 1.0,
4845 x_resolution: 1.0,
4846 y_resolution: 1.0,
4847 x_changed: true,
4848 y_changed: true,
4849 pressure: 0.0,
4850 pressure_min: 0.0,
4851 pressure_max: 1.0,
4852 pressure_changed: false,
4853 distance: 0.0,
4854 distance_changed: false,
4855 tilt_x: 0.0,
4856 tilt_y: 0.0,
4857 tilt_x_changed: false,
4858 tilt_y_changed: false,
4859 rotation: 0.0,
4860 rotation_changed: false,
4861 slider: 0.0,
4862 slider_changed: false,
4863 wheel_delta: 0.0,
4864 wheel_discrete: 0,
4865 wheel_changed: false,
4866 size_major: 0.0,
4867 size_minor: 0.0,
4868 size_major_changed: false,
4869 size_minor_changed: false,
4870 tip_state: 1,
4871 button: 0,
4872 button_state: 0,
4873 seat_button_count: 0,
4874 }),
4875 context: std::ptr::null_mut(),
4876 device: std::ptr::null_mut(),
4877 };
4878
4879 assert_eq!(libinput_event_tablet_tool_get_dx(&event), 2.5);
4880 assert_eq!(libinput_event_tablet_tool_get_dy(&event), -1.5);
4881
4882 for event_type in [
4883 LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY,
4884 LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_TIP,
4885 LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
4886 ] {
4887 event.event_type = event_type;
4888 assert_eq!(libinput_event_tablet_tool_get_dx(&event), 0.0);
4889 assert_eq!(libinput_event_tablet_tool_get_dy(&event), 0.0);
4890 }
4891 }
4892 }
4893
4894 #[test]
4895 fn unsupported_configs_report_unsupported_before_invalid_values() {
4896 unsafe {
4897 let mut device = Box::new(LibinputDevice::new(
4898 "device",
4899 "/dev/input/event0",
4900 std::ptr::null_mut(),
4901 std::ptr::null_mut(),
4902 ));
4903
4904 assert_eq!(
4905 libinput_device_config_rotation_set_angle(&mut *device, 360),
4906 1
4907 );
4908 assert_eq!(
4909 libinput_device_config_rotation_set_angle(&mut *device, 0),
4910 0
4911 );
4912 assert_eq!(
4913 libinput_device_config_3fg_drag_set_enabled(&mut *device, u32::MAX),
4914 1
4915 );
4916 assert_eq!(libinput_device_pointer_has_button(&*device, u32::MAX), -1);
4917 assert_eq!(libinput_device_switch_has_switch(&*device, 1), -1);
4918 assert_eq!(libinput_device_switch_has_switch(&*device, u32::MAX), -1);
4919 }
4920 }
4921
4922 #[test]
4923 fn setting_a_null_log_handler_disables_the_default_handler() {
4924 unsafe {
4925 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4926 assert!((*ctx).default_log_handler_enabled);
4927 libinput_log_set_handler(ctx, None);
4928 assert!(!(*ctx).default_log_handler_enabled);
4929 libinput_unref(ctx);
4930 }
4931 }
4932}