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() {
3393 return 0.0;
3394 }
3395 match &(*event).payload {
3396 EventPayload::TabletTool(tablet) => tablet.dx,
3397 _ => 0.0,
3398 }
3399}
3400
3401#[no_mangle]
3402pub unsafe extern "C" fn libinput_event_tablet_tool_get_dy(event: *const LibinputEvent) -> f64 {
3403 if event.is_null() {
3404 return 0.0;
3405 }
3406 match &(*event).payload {
3407 EventPayload::TabletTool(tablet) => tablet.dy,
3408 _ => 0.0,
3409 }
3410}
3411
3412#[no_mangle]
3413pub unsafe extern "C" fn libinput_event_tablet_tool_get_pressure(
3414 event: *const LibinputEvent,
3415) -> f64 {
3416 if event.is_null() {
3417 return 0.0;
3418 }
3419 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3420 let range = tablet.pressure_max - tablet.pressure_min;
3421 if range > 0.0 {
3422 ((tablet.pressure - tablet.pressure_min) / range).clamp(0.0, 1.0)
3423 } else {
3424 0.0
3425 }
3426 } else {
3427 0.0
3428 }
3429}
3430
3431#[no_mangle]
3432pub unsafe extern "C" fn libinput_event_tablet_tool_get_x(event: *const LibinputEvent) -> f64 {
3433 if event.is_null() {
3434 return 0.0;
3435 }
3436 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3437 if tablet.x_resolution > 0.0 {
3438 (tablet.x - tablet.x_min) / tablet.x_resolution
3439 } else {
3440 tablet.x - tablet.x_min
3441 }
3442 } else {
3443 0.0
3444 }
3445}
3446
3447#[no_mangle]
3448pub unsafe extern "C" fn libinput_event_tablet_tool_get_y(event: *const LibinputEvent) -> f64 {
3449 if event.is_null() {
3450 return 0.0;
3451 }
3452 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3453 if tablet.y_resolution > 0.0 {
3454 (tablet.y - tablet.y_min) / tablet.y_resolution
3455 } else {
3456 tablet.y - tablet.y_min
3457 }
3458 } else {
3459 0.0
3460 }
3461}
3462
3463#[no_mangle]
3464pub unsafe extern "C" fn libinput_event_tablet_tool_get_proximity_state(
3465 event: *const LibinputEvent,
3466) -> u32 {
3467 if event.is_null() {
3468 return 0;
3469 }
3470 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3471 tablet.proximity_state
3472 } else {
3473 0
3474 }
3475}
3476
3477#[no_mangle]
3478pub unsafe extern "C" fn libinput_event_tablet_tool_get_rotation(
3479 event: *const LibinputEvent,
3480) -> f64 {
3481 if event.is_null() {
3482 return 0.0;
3483 }
3484 match &(*event).payload {
3485 EventPayload::TabletTool(tablet) => tablet.rotation,
3486 _ => 0.0,
3487 }
3488}
3489
3490#[no_mangle]
3491pub unsafe extern "C" fn libinput_event_tablet_tool_get_slider_position(
3492 event: *const LibinputEvent,
3493) -> f64 {
3494 if event.is_null() {
3495 return 0.0;
3496 }
3497 match &(*event).payload {
3498 EventPayload::TabletTool(tablet) => tablet.slider,
3499 _ => 0.0,
3500 }
3501}
3502
3503#[no_mangle]
3504pub unsafe extern "C" fn libinput_event_tablet_tool_get_wheel_delta(
3505 event: *const LibinputEvent,
3506) -> f64 {
3507 if event.is_null() {
3508 return 0.0;
3509 }
3510 match &(*event).payload {
3511 EventPayload::TabletTool(tablet) => tablet.wheel_delta,
3512 _ => 0.0,
3513 }
3514}
3515
3516#[no_mangle]
3517pub unsafe extern "C" fn libinput_event_tablet_tool_get_wheel_delta_discrete(
3518 event: *const LibinputEvent,
3519) -> i32 {
3520 if event.is_null() {
3521 return 0;
3522 }
3523 match &(*event).payload {
3524 EventPayload::TabletTool(tablet) => tablet.wheel_discrete,
3525 _ => 0,
3526 }
3527}
3528
3529#[no_mangle]
3530pub unsafe extern "C" fn libinput_event_tablet_tool_get_size_major(
3531 event: *const LibinputEvent,
3532) -> f64 {
3533 if event.is_null() {
3534 return 0.0;
3535 }
3536 match &(*event).payload {
3537 EventPayload::TabletTool(tablet) => tablet.size_major,
3538 _ => 0.0,
3539 }
3540}
3541
3542#[no_mangle]
3543pub unsafe extern "C" fn libinput_event_tablet_tool_get_size_minor(
3544 event: *const LibinputEvent,
3545) -> f64 {
3546 if event.is_null() {
3547 return 0.0;
3548 }
3549 match &(*event).payload {
3550 EventPayload::TabletTool(tablet) => tablet.size_minor,
3551 _ => 0.0,
3552 }
3553}
3554
3555#[no_mangle]
3556pub unsafe extern "C" fn libinput_event_tablet_tool_get_tilt_x(event: *const LibinputEvent) -> f64 {
3557 if event.is_null() {
3558 return 0.0;
3559 }
3560 match &(*event).payload {
3561 EventPayload::TabletTool(tablet) => tablet.tilt_x,
3562 _ => 0.0,
3563 }
3564}
3565
3566#[no_mangle]
3567pub unsafe extern "C" fn libinput_event_tablet_tool_get_tilt_y(event: *const LibinputEvent) -> f64 {
3568 if event.is_null() {
3569 return 0.0;
3570 }
3571 match &(*event).payload {
3572 EventPayload::TabletTool(tablet) => tablet.tilt_y,
3573 _ => 0.0,
3574 }
3575}
3576
3577#[no_mangle]
3578pub unsafe extern "C" fn libinput_event_tablet_tool_get_time_usec(
3579 event: *const LibinputEvent,
3580) -> u64 {
3581 if event.is_null() {
3582 return 0;
3583 }
3584 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3585 tablet.time_usec
3586 } else {
3587 0
3588 }
3589}
3590
3591#[no_mangle]
3592pub unsafe extern "C" fn libinput_event_tablet_tool_get_time(event: *const LibinputEvent) -> u32 {
3593 (libinput_event_tablet_tool_get_time_usec(event) / 1000) as u32
3594}
3595
3596#[no_mangle]
3597pub unsafe extern "C" fn libinput_event_tablet_tool_get_tip_state(
3598 event: *const LibinputEvent,
3599) -> u32 {
3600 if event.is_null() {
3601 return 0;
3602 }
3603 match &(*event).payload {
3604 EventPayload::TabletTool(tablet) => tablet.tip_state,
3605 _ => 0,
3606 }
3607}
3608
3609#[no_mangle]
3610pub unsafe extern "C" fn libinput_event_tablet_tool_get_tool(
3611 event: *const LibinputEvent,
3612) -> *mut libc::c_void {
3613 if event.is_null() {
3614 return std::ptr::null_mut();
3615 }
3616 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3617 tablet.tool.cast()
3618 } else {
3619 std::ptr::null_mut()
3620 }
3621}
3622
3623#[no_mangle]
3624pub unsafe extern "C" fn libinput_event_tablet_tool_get_x_transformed(
3625 event: *const LibinputEvent,
3626 width: u32,
3627) -> f64 {
3628 if event.is_null() {
3629 return 0.0;
3630 }
3631 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3632 let range = tablet.x_max - tablet.x_min + 1.0;
3633 if range > 0.0 {
3634 (tablet.x - tablet.x_min) * f64::from(width) / range
3635 } else {
3636 0.0
3637 }
3638 } else {
3639 0.0
3640 }
3641}
3642
3643#[no_mangle]
3644pub unsafe extern "C" fn libinput_event_tablet_tool_get_y_transformed(
3645 event: *const LibinputEvent,
3646 height: u32,
3647) -> f64 {
3648 if event.is_null() {
3649 return 0.0;
3650 }
3651 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3652 let range = tablet.y_max - tablet.y_min + 1.0;
3653 if range > 0.0 {
3654 (tablet.y - tablet.y_min) * f64::from(height) / range
3655 } else {
3656 0.0
3657 }
3658 } else {
3659 0.0
3660 }
3661}
3662
3663#[no_mangle]
3664pub unsafe extern "C" fn libinput_event_tablet_tool_x_has_changed(
3665 event: *const LibinputEvent,
3666) -> libc::c_int {
3667 if event.is_null() {
3668 return 0;
3669 }
3670 match &(*event).payload {
3671 EventPayload::TabletTool(tablet) => tablet.x_changed as libc::c_int,
3672 _ => 0,
3673 }
3674}
3675
3676#[no_mangle]
3677pub unsafe extern "C" fn libinput_event_tablet_tool_y_has_changed(
3678 event: *const LibinputEvent,
3679) -> libc::c_int {
3680 if event.is_null() {
3681 return 0;
3682 }
3683 match &(*event).payload {
3684 EventPayload::TabletTool(tablet) => tablet.y_changed as libc::c_int,
3685 _ => 0,
3686 }
3687}
3688
3689#[no_mangle]
3690pub unsafe extern "C" fn libinput_event_tablet_tool_pressure_has_changed(
3691 event: *const LibinputEvent,
3692) -> libc::c_int {
3693 if event.is_null() {
3694 return 0;
3695 }
3696 match &(*event).payload {
3697 EventPayload::TabletTool(tablet) => tablet.pressure_changed as libc::c_int,
3698 _ => 0,
3699 }
3700}
3701
3702#[no_mangle]
3703pub unsafe extern "C" fn libinput_event_tablet_tool_distance_has_changed(
3704 event: *const LibinputEvent,
3705) -> libc::c_int {
3706 if event.is_null() {
3707 return 0;
3708 }
3709 match &(*event).payload {
3710 EventPayload::TabletTool(tablet) => tablet.distance_changed as libc::c_int,
3711 _ => 0,
3712 }
3713}
3714
3715#[no_mangle]
3716pub unsafe extern "C" fn libinput_event_tablet_tool_tilt_x_has_changed(
3717 event: *const LibinputEvent,
3718) -> libc::c_int {
3719 if event.is_null() {
3720 return 0;
3721 }
3722 match &(*event).payload {
3723 EventPayload::TabletTool(tablet) => tablet.tilt_x_changed as libc::c_int,
3724 _ => 0,
3725 }
3726}
3727
3728#[no_mangle]
3729pub unsafe extern "C" fn libinput_event_tablet_tool_tilt_y_has_changed(
3730 event: *const LibinputEvent,
3731) -> libc::c_int {
3732 if event.is_null() {
3733 return 0;
3734 }
3735 match &(*event).payload {
3736 EventPayload::TabletTool(tablet) => tablet.tilt_y_changed as libc::c_int,
3737 _ => 0,
3738 }
3739}
3740
3741#[no_mangle]
3742pub unsafe extern "C" fn libinput_event_tablet_tool_rotation_has_changed(
3743 event: *const LibinputEvent,
3744) -> libc::c_int {
3745 if event.is_null() {
3746 return 0;
3747 }
3748 match &(*event).payload {
3749 EventPayload::TabletTool(tablet) => tablet.rotation_changed as libc::c_int,
3750 _ => 0,
3751 }
3752}
3753
3754#[no_mangle]
3755pub unsafe extern "C" fn libinput_event_tablet_tool_slider_has_changed(
3756 event: *const LibinputEvent,
3757) -> libc::c_int {
3758 if event.is_null() {
3759 return 0;
3760 }
3761 match &(*event).payload {
3762 EventPayload::TabletTool(tablet) => tablet.slider_changed as libc::c_int,
3763 _ => 0,
3764 }
3765}
3766
3767#[no_mangle]
3768pub unsafe extern "C" fn libinput_event_tablet_tool_wheel_has_changed(
3769 event: *const LibinputEvent,
3770) -> libc::c_int {
3771 if event.is_null() {
3772 return 0;
3773 }
3774 match &(*event).payload {
3775 EventPayload::TabletTool(tablet) => tablet.wheel_changed as libc::c_int,
3776 _ => 0,
3777 }
3778}
3779
3780#[no_mangle]
3781pub unsafe extern "C" fn libinput_event_tablet_tool_size_major_has_changed(
3782 event: *const LibinputEvent,
3783) -> libc::c_int {
3784 if event.is_null() {
3785 return 0;
3786 }
3787 match &(*event).payload {
3788 EventPayload::TabletTool(tablet) => tablet.size_major_changed as libc::c_int,
3789 _ => 0,
3790 }
3791}
3792
3793#[no_mangle]
3794pub unsafe extern "C" fn libinput_event_tablet_tool_size_minor_has_changed(
3795 event: *const LibinputEvent,
3796) -> libc::c_int {
3797 if event.is_null() {
3798 return 0;
3799 }
3800 match &(*event).payload {
3801 EventPayload::TabletTool(tablet) => tablet.size_minor_changed as libc::c_int,
3802 _ => 0,
3803 }
3804}
3805
3806#[no_mangle]
3807pub unsafe extern "C" fn libinput_plugin_system_append_default_paths(ctx: *mut LibinputContext) {
3808 if ctx.is_null() || (*ctx).plugins_loaded {
3809 return;
3810 }
3811 for path in ["/etc/libinput/plugins", "/usr/lib64/libinput/plugins"] {
3812 let path = std::ffi::CString::new(path).expect("static plugin path");
3813 if !(*ctx)
3814 .plugin_paths
3815 .iter()
3816 .any(|candidate| candidate.as_bytes() == path.as_bytes())
3817 {
3818 (*ctx).plugin_paths.push(path);
3819 }
3820 }
3821}
3822
3823#[no_mangle]
3824pub unsafe extern "C" fn libinput_plugin_system_append_path(
3825 ctx: *mut LibinputContext,
3826 path: *const libc::c_char,
3827) {
3828 if ctx.is_null() || path.is_null() || (*ctx).plugins_loaded {
3829 return;
3830 }
3831 let path = CStr::from_ptr(path);
3832 if (*ctx)
3833 .plugin_paths
3834 .iter()
3835 .any(|candidate| candidate.as_bytes() == path.to_bytes())
3836 {
3837 return;
3838 }
3839 if let Ok(path) = std::ffi::CString::new(path.to_bytes()) {
3840 (*ctx).plugin_paths.push(path);
3841 }
3842}
3843
3844#[no_mangle]
3845pub unsafe extern "C" fn libinput_plugin_system_load_plugins(
3846 ctx: *mut LibinputContext,
3847 _flags: libc::c_uint,
3848) -> libc::c_int {
3849 if ctx.is_null() {
3850 return -libc::EINVAL;
3851 }
3852 if (*ctx).plugins_loaded {
3853 return 0;
3854 }
3855 (*ctx).plugins_loaded = true;
3859 -libc::ENOSYS
3860}
3861
3862#[no_mangle]
3863pub unsafe extern "C" fn libinput_tablet_pad_mode_group_button_is_toggle(
3864 group: *const libc::c_void,
3865 button: u32,
3866) -> libc::c_int {
3867 if group.is_null() || button >= u32::BITS {
3868 return 0;
3869 }
3870 ((*group.cast::<LibinputTabletPadModeGroup>()).toggle_button_mask & (1_u32 << button) != 0)
3871 as libc::c_int
3872}
3873
3874#[no_mangle]
3875pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_index(
3876 group: *const libc::c_void,
3877) -> u32 {
3878 if group.is_null() {
3879 return 0;
3880 }
3881 (*group.cast::<LibinputTabletPadModeGroup>()).index
3882}
3883
3884#[no_mangle]
3885pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_mode(
3886 group: *const libc::c_void,
3887) -> u32 {
3888 if group.is_null() {
3889 return 0;
3890 }
3891 (*group.cast::<LibinputTabletPadModeGroup>()).current_mode
3892}
3893
3894#[no_mangle]
3895pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_num_modes(
3896 group: *const libc::c_void,
3897) -> u32 {
3898 if group.is_null() {
3899 return 0;
3900 }
3901 (*group.cast::<LibinputTabletPadModeGroup>()).num_modes
3902}
3903
3904#[no_mangle]
3905pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_button(
3906 group: *const libc::c_void,
3907 button: u32,
3908) -> libc::c_int {
3909 if group.is_null() {
3910 return 0;
3911 }
3912 if button >= u32::BITS {
3913 return 0;
3914 }
3915 ((*group.cast::<LibinputTabletPadModeGroup>()).button_mask & (1_u32 << button) != 0)
3916 as libc::c_int
3917}
3918
3919#[no_mangle]
3920pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_dial(
3921 group: *const libc::c_void,
3922 dial: u32,
3923) -> libc::c_int {
3924 if group.is_null() {
3925 return 0;
3926 }
3927 if dial >= u32::BITS {
3928 return 0;
3929 }
3930 ((*group.cast::<LibinputTabletPadModeGroup>()).dial_mask & (1_u32 << dial) != 0) as libc::c_int
3931}
3932
3933#[no_mangle]
3934pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_ring(
3935 group: *const libc::c_void,
3936 ring: u32,
3937) -> libc::c_int {
3938 if group.is_null() {
3939 return 0;
3940 }
3941 if ring >= u32::BITS {
3942 return 0;
3943 }
3944 ((*group.cast::<LibinputTabletPadModeGroup>()).ring_mask & (1_u32 << ring) != 0) as libc::c_int
3945}
3946
3947#[no_mangle]
3948pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_strip(
3949 group: *const libc::c_void,
3950 strip: u32,
3951) -> libc::c_int {
3952 if group.is_null() {
3953 return 0;
3954 }
3955 if strip >= u32::BITS {
3956 return 0;
3957 }
3958 ((*group.cast::<LibinputTabletPadModeGroup>()).strip_mask & (1_u32 << strip) != 0)
3959 as libc::c_int
3960}
3961
3962#[no_mangle]
3963pub unsafe extern "C" fn libinput_tablet_pad_mode_group_ref(
3964 group: *mut libc::c_void,
3965) -> *mut libc::c_void {
3966 if !group.is_null() {
3967 (*group.cast::<LibinputTabletPadModeGroup>())
3968 .refcount
3969 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
3970 }
3971 group
3972}
3973
3974#[no_mangle]
3975pub unsafe extern "C" fn libinput_tablet_pad_mode_group_unref(
3976 group: *mut libc::c_void,
3977) -> *mut libc::c_void {
3978 if group.is_null() {
3979 return std::ptr::null_mut();
3980 }
3981 let group = group.cast::<LibinputTabletPadModeGroup>();
3982 if (*group)
3983 .refcount
3984 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
3985 == 1
3986 {
3987 drop(Box::from_raw(group));
3988 std::ptr::null_mut()
3989 } else {
3990 group.cast()
3991 }
3992}
3993
3994#[no_mangle]
3995pub unsafe extern "C" fn libinput_tablet_pad_mode_group_set_user_data(
3996 group: *mut libc::c_void,
3997 data: *mut libc::c_void,
3998) {
3999 if !group.is_null() {
4000 (*group.cast::<LibinputTabletPadModeGroup>()).user_data = data;
4001 }
4002}
4003
4004#[no_mangle]
4005pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_user_data(
4006 group: *const libc::c_void,
4007) -> *mut libc::c_void {
4008 if group.is_null() {
4009 return std::ptr::null_mut();
4010 }
4011 (*group.cast::<LibinputTabletPadModeGroup>()).user_data
4012}
4013
4014#[no_mangle]
4015pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_is_available(
4016 tool: *const LibinputTabletTool,
4017) -> libc::c_int {
4018 (!tool.is_null() && (*tool).has_pressure) as libc::c_int
4019}
4020
4021#[no_mangle]
4022pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_set(
4023 tool: *mut LibinputTabletTool,
4024 minimum: f64,
4025 maximum: f64,
4026) -> u32 {
4027 if tool.is_null() || !(*tool).has_pressure {
4028 return 1;
4029 }
4030 if minimum < 0.0 || maximum > 1.0 || minimum >= maximum {
4031 return 2;
4032 }
4033 (*tool).wanted_pressure_range_minimum = minimum;
4034 (*tool).wanted_pressure_range_maximum = maximum;
4035 0
4036}
4037
4038#[no_mangle]
4039pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_minimum(
4040 tool: *const LibinputTabletTool,
4041) -> f64 {
4042 if tool.is_null() {
4043 0.0
4044 } else {
4045 (*tool).wanted_pressure_range_minimum
4046 }
4047}
4048
4049#[no_mangle]
4050pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_maximum(
4051 tool: *const LibinputTabletTool,
4052) -> f64 {
4053 if tool.is_null() {
4054 1.0
4055 } else {
4056 (*tool).wanted_pressure_range_maximum
4057 }
4058}
4059
4060#[no_mangle]
4061pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_default_minimum(
4062 _tool: *const libc::c_void,
4063) -> f64 {
4064 0.0
4065}
4066
4067#[no_mangle]
4068pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_default_maximum(
4069 _tool: *const libc::c_void,
4070) -> f64 {
4071 1.0
4072}
4073
4074#[no_mangle]
4075pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_modes(
4076 tool: *const libc::c_void,
4077) -> u32 {
4078 let tool = tool.cast::<LibinputTabletTool>();
4079 if tool.is_null() {
4080 0
4081 } else {
4082 (*tool).eraser_button_modes
4083 }
4084}
4085
4086#[no_mangle]
4087pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_set_mode(
4088 tool: *mut libc::c_void,
4089 mode: u32,
4090) -> u32 {
4091 let tool = tool.cast::<LibinputTabletTool>();
4092 if tool.is_null() || (mode != 0 && ((*tool).eraser_button_modes & mode) == 0) {
4093 return 1;
4094 }
4095 if !matches!(mode, 0 | 1) {
4096 return 2;
4097 }
4098 (*tool).wanted_eraser_button_mode = mode;
4099 if !(*tool).in_proximity {
4100 (*tool).eraser_button_mode = mode;
4101 }
4102 0
4103}
4104
4105#[no_mangle]
4106pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_mode(
4107 tool: *const libc::c_void,
4108) -> u32 {
4109 let tool = tool.cast::<LibinputTabletTool>();
4110 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4111 0
4112 } else {
4113 (*tool).wanted_eraser_button_mode
4114 }
4115}
4116
4117#[no_mangle]
4118pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_default_mode(
4119 _tool: *const libc::c_void,
4120) -> u32 {
4121 0
4122}
4123
4124#[no_mangle]
4125pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_set_button(
4126 tool: *mut libc::c_void,
4127 button: u32,
4128) -> u32 {
4129 let tool = tool.cast::<LibinputTabletTool>();
4130 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4131 return 1;
4132 }
4133 let is_button = matches!(button, 0x149 | 0x14b | 0x14c)
4134 || (0x100..0x140).contains(&button)
4135 || (0x150..=0x151).contains(&button)
4136 || (0x220..=0x223).contains(&button)
4137 || (0x2c0..=0x2e7).contains(&button);
4138 if !is_button {
4139 return 2;
4140 }
4141 (*tool).wanted_eraser_button = button;
4142 if !(*tool).in_proximity {
4143 (*tool).eraser_button = button;
4144 }
4145 0
4146}
4147
4148#[no_mangle]
4149pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_button(
4150 tool: *const libc::c_void,
4151) -> u32 {
4152 let tool = tool.cast::<LibinputTabletTool>();
4153 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4154 0
4155 } else {
4156 (*tool).wanted_eraser_button
4157 }
4158}
4159
4160#[no_mangle]
4161pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_default_button(
4162 tool: *const libc::c_void,
4163) -> u32 {
4164 let tool = tool.cast::<LibinputTabletTool>();
4165 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4166 0
4167 } else {
4168 (*tool).default_eraser_button
4169 }
4170}
4171
4172#[no_mangle]
4173pub unsafe extern "C" fn libinput_tablet_tool_get_name(
4174 tool: *const libc::c_void,
4175) -> *const libc::c_char {
4176 let tool = tool.cast::<LibinputTabletTool>();
4177 if tool.is_null() {
4178 return std::ptr::null();
4179 }
4180 let tool = tool.cast::<LibinputTabletTool>();
4181 let tool = tool as *mut LibinputTabletTool;
4182 if let Some(name) = (*tool).name.as_ref() {
4183 return name.as_ptr();
4184 }
4185 if let Some(name) = crate::backend::tablet_tool_name_for_id((*tool).tool_id) {
4186 (*tool).name = Some(name);
4187 (*tool)
4188 .name
4189 .as_ref()
4190 .map_or(std::ptr::null(), |name| name.as_ptr())
4191 } else {
4192 std::ptr::null()
4193 }
4194}
4195
4196#[no_mangle]
4197pub unsafe extern "C" fn libinput_tablet_tool_get_serial(tool: *const libc::c_void) -> u64 {
4198 let tool = tool.cast::<LibinputTabletTool>();
4199 if tool.is_null() {
4200 0
4201 } else {
4202 (*tool).serial
4203 }
4204}
4205
4206#[no_mangle]
4207pub unsafe extern "C" fn libinput_tablet_tool_get_tool_id(tool: *const libc::c_void) -> u64 {
4208 let tool = tool.cast::<LibinputTabletTool>();
4209 if tool.is_null() {
4210 0
4211 } else {
4212 (*tool).tool_id
4213 }
4214}
4215
4216#[no_mangle]
4217pub unsafe extern "C" fn libinput_tablet_tool_get_type(tool: *const libc::c_void) -> u32 {
4218 let tool = tool.cast::<LibinputTabletTool>();
4219 if tool.is_null() {
4220 0
4221 } else {
4222 (*tool).tool_type
4223 }
4224}
4225
4226#[no_mangle]
4227pub unsafe extern "C" fn libinput_tablet_tool_has_distance(
4228 tool: *const libc::c_void,
4229) -> libc::c_int {
4230 let tool = tool.cast::<LibinputTabletTool>();
4231 (!tool.is_null() && (*tool).has_distance) as libc::c_int
4232}
4233
4234#[no_mangle]
4235pub unsafe extern "C" fn libinput_tablet_tool_has_button(
4236 tool: *const libc::c_void,
4237 button: u32,
4238) -> libc::c_int {
4239 let tool = tool.cast::<LibinputTabletTool>();
4240 (!tool.is_null() && (*tool).buttons.contains(&button)) as libc::c_int
4241}
4242
4243#[no_mangle]
4244pub unsafe extern "C" fn libinput_tablet_tool_has_size(tool: *const libc::c_void) -> libc::c_int {
4245 let tool = tool.cast::<LibinputTabletTool>();
4246 (!tool.is_null() && (*tool).has_size) as libc::c_int
4247}
4248
4249#[no_mangle]
4250pub unsafe extern "C" fn libinput_tablet_tool_is_unique(tool: *const libc::c_void) -> libc::c_int {
4251 let tool = tool.cast::<LibinputTabletTool>();
4252 (!tool.is_null() && (*tool).serial != 0) as libc::c_int
4253}
4254
4255#[no_mangle]
4256pub unsafe extern "C" fn libinput_tablet_tool_set_user_data(
4257 tool: *mut libc::c_void,
4258 data: *mut libc::c_void,
4259) {
4260 let tool = tool.cast::<LibinputTabletTool>();
4261 if !tool.is_null() {
4262 (*tool).user_data = data;
4263 }
4264}
4265
4266#[no_mangle]
4267pub unsafe extern "C" fn libinput_tablet_tool_get_user_data(
4268 tool: *const libc::c_void,
4269) -> *mut libc::c_void {
4270 let tool = tool.cast::<LibinputTabletTool>();
4271 if tool.is_null() {
4272 std::ptr::null_mut()
4273 } else {
4274 (*tool).user_data
4275 }
4276}
4277
4278#[no_mangle]
4279pub unsafe extern "C" fn libinput_tablet_tool_has_pressure(
4280 tool: *const libc::c_void,
4281) -> libc::c_int {
4282 let tool = tool.cast::<LibinputTabletTool>();
4283 (!tool.is_null() && (*tool).has_pressure) as libc::c_int
4284}
4285
4286#[no_mangle]
4287pub unsafe extern "C" fn libinput_tablet_tool_has_rotation(
4288 tool: *const libc::c_void,
4289) -> libc::c_int {
4290 let tool = tool.cast::<LibinputTabletTool>();
4291 (!tool.is_null() && (*tool).has_rotation) as libc::c_int
4292}
4293
4294#[no_mangle]
4295pub unsafe extern "C" fn libinput_tablet_tool_has_slider(tool: *const libc::c_void) -> libc::c_int {
4296 let tool = tool.cast::<LibinputTabletTool>();
4297 (!tool.is_null() && (*tool).has_slider) as libc::c_int
4298}
4299
4300#[no_mangle]
4301pub unsafe extern "C" fn libinput_tablet_tool_has_tilt(tool: *const libc::c_void) -> libc::c_int {
4302 let tool = tool.cast::<LibinputTabletTool>();
4303 (!tool.is_null() && (*tool).has_tilt) as libc::c_int
4304}
4305
4306#[no_mangle]
4307pub unsafe extern "C" fn libinput_tablet_tool_has_wheel(tool: *const libc::c_void) -> libc::c_int {
4308 let tool = tool.cast::<LibinputTabletTool>();
4309 (!tool.is_null() && (*tool).has_wheel) as libc::c_int
4310}
4311
4312#[no_mangle]
4313pub unsafe extern "C" fn libinput_tablet_tool_ref(tool: *mut libc::c_void) -> *mut libc::c_void {
4314 let tablet_tool = tool.cast::<LibinputTabletTool>();
4315 if !tablet_tool.is_null() {
4316 (*tablet_tool)
4317 .refcount
4318 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
4319 }
4320 tool
4321}
4322
4323#[no_mangle]
4324pub unsafe extern "C" fn libinput_tablet_tool_unref(tool: *mut libc::c_void) -> *mut libc::c_void {
4325 let tablet_tool = tool.cast::<LibinputTabletTool>();
4326 if tablet_tool.is_null() {
4327 return std::ptr::null_mut();
4328 }
4329 if (*tablet_tool)
4330 .refcount
4331 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
4332 == 1
4333 {
4334 if !(*tablet_tool).device.is_null() {
4335 libinput_device_unref((*tablet_tool).device);
4336 (*tablet_tool).device = std::ptr::null_mut();
4337 }
4338 drop(Box::from_raw(tablet_tool));
4339 std::ptr::null_mut()
4340 } else {
4341 tool
4342 }
4343}
4344
4345#[no_mangle]
4350pub unsafe extern "C" fn libinput_suspend(ctx: *mut LibinputContext) {
4351 if ctx.is_null() {
4352 return;
4353 }
4354 let mut events = std::collections::VecDeque::new();
4355 if let Ok(mut backend) = (*ctx).backend.lock() {
4356 backend.suspend(ctx, &mut events);
4357 }
4358 enqueue_events(ctx, events);
4359}
4360
4361#[no_mangle]
4362pub unsafe extern "C" fn libinput_resume(ctx: *mut LibinputContext) -> libc::c_int {
4363 if ctx.is_null() {
4364 return -1;
4365 }
4366 let mut events = std::collections::VecDeque::new();
4367 let status = if let Ok(mut backend) = (*ctx).backend.lock() {
4368 backend.resume(ctx, &mut events)
4369 } else {
4370 return -1;
4371 };
4372 enqueue_events(ctx, events);
4373 if !(*ctx).event_queue.is_empty() {
4374 (*ctx).signal_fd();
4375 }
4376 status
4377}
4378
4379#[cfg(test)]
4380mod tests {
4381 use super::*;
4382
4383 unsafe extern "C" fn deny_open(
4384 _path: *const libc::c_char,
4385 _flags: libc::c_int,
4386 _user_data: *mut libc::c_void,
4387 ) -> libc::c_int {
4388 -libc::EACCES
4389 }
4390
4391 unsafe extern "C" fn close_fd(_fd: libc::c_int, _user_data: *mut libc::c_void) {}
4392
4393 static INTERFACE: LibinputInterface = LibinputInterface {
4394 open_restricted: Some(deny_open),
4395 close_restricted: Some(close_fd),
4396 };
4397
4398 #[test]
4399 fn udev_context_requires_interface_and_udev() {
4400 unsafe {
4401 let fake_udev = 1usize as *mut libc::c_void;
4402 assert!(libinput_udev_create_context(
4403 std::ptr::null(),
4404 std::ptr::null_mut(),
4405 fake_udev,
4406 )
4407 .is_null());
4408 assert!(libinput_udev_create_context(
4409 &INTERFACE,
4410 std::ptr::null_mut(),
4411 std::ptr::null_mut(),
4412 )
4413 .is_null());
4414 }
4415 }
4416
4417 #[test]
4418 fn seat_assignment_is_udev_only_and_happens_once() {
4419 unsafe {
4420 let fake_udev = 1usize as *mut libc::c_void;
4421 let seat = std::ffi::CString::new("seat0").unwrap();
4422 let udev_ctx =
4423 libinput_udev_create_context(&INTERFACE, std::ptr::null_mut(), fake_udev);
4424 assert!(!udev_ctx.is_null());
4425 assert_eq!(libinput_udev_assign_seat(udev_ctx, seat.as_ptr()), 0);
4426 assert_eq!(libinput_udev_assign_seat(udev_ctx, seat.as_ptr()), -1);
4427 libinput_unref(udev_ctx);
4428
4429 let path_ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4430 assert!(!path_ctx.is_null());
4431 assert_eq!(libinput_udev_assign_seat(path_ctx, seat.as_ptr()), -1);
4432 libinput_unref(path_ctx);
4433 }
4434 }
4435
4436 #[test]
4437 fn overlong_seat_name_does_not_assign_or_queue_devices() {
4438 unsafe {
4439 let fake_udev = 1usize as *mut libc::c_void;
4440 let seat = std::ffi::CString::new("a".repeat(257)).unwrap();
4441 let ctx = libinput_udev_create_context(&INTERFACE, std::ptr::null_mut(), fake_udev);
4442 assert!(!ctx.is_null());
4443
4444 assert_eq!(libinput_udev_assign_seat(ctx, seat.as_ptr()), -1);
4445 assert!(!(*ctx).seat_assigned);
4446 assert!((*ctx).event_queue.is_empty());
4447
4448 libinput_unref(ctx);
4449 }
4450 }
4451
4452 #[test]
4453 fn suspend_and_resume_are_null_safe() {
4454 unsafe {
4455 libinput_suspend(std::ptr::null_mut());
4456 assert_eq!(libinput_resume(std::ptr::null_mut()), -1);
4457 }
4458 }
4459
4460 #[test]
4461 fn dispatch_returns_negative_errno_on_epoll_failure() {
4462 unsafe {
4463 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4464 assert!(!ctx.is_null());
4465 libc::close((*ctx).epoll_fd);
4466 (*ctx).epoll_fd = -1;
4467 assert_eq!(libinput_dispatch(ctx), -libc::EBADF);
4468 libinput_unref(ctx);
4469 }
4470 }
4471
4472 #[test]
4473 fn shared_device_groups_preserve_identity_and_user_data() {
4474 unsafe {
4475 let first = Box::new(LibinputDevice::new(
4476 "first",
4477 "/dev/input/event0",
4478 std::ptr::null_mut(),
4479 std::ptr::null_mut(),
4480 ));
4481 let group = first.group;
4482 let mut second = Box::new(LibinputDevice::new(
4483 "second",
4484 "/dev/input/event1",
4485 std::ptr::null_mut(),
4486 std::ptr::null_mut(),
4487 ));
4488 second.share_group(group);
4489
4490 assert_eq!(second.group, group);
4491 assert_eq!(second.abi.group, group);
4492 assert_eq!(
4493 (*group).refcount.load(std::sync::atomic::Ordering::Relaxed),
4494 2
4495 );
4496 let marker = 0x5ausize as *mut libc::c_void;
4497 libinput_device_group_set_user_data(group.cast(), marker);
4498 assert_eq!(
4499 libinput_device_group_get_user_data(second.group.cast()),
4500 marker
4501 );
4502
4503 drop(second);
4504 assert_eq!(
4505 (*group).refcount.load(std::sync::atomic::Ordering::Relaxed),
4506 1
4507 );
4508 drop(first);
4509 }
4510 }
4511
4512 #[test]
4513 fn custom_acceleration_validates_and_copies_curves() {
4514 unsafe {
4515 assert!(libinput_config_accel_create(0).is_null());
4516 let config = libinput_config_accel_create(4);
4517 assert!(!config.is_null());
4518
4519 let one_point = [1.0];
4520 assert_eq!(
4521 libinput_config_accel_set_points(config, 1, 1.0, 1, one_point.as_ptr()),
4522 2
4523 );
4524 let points = [0.0, 2.0, 6.0];
4525 assert_eq!(
4526 libinput_config_accel_set_points(config, 1, 1.0, points.len(), points.as_ptr()),
4527 0
4528 );
4529 let scroll_points = [0.0, 3.0, 9.0];
4530 assert_eq!(
4531 libinput_config_accel_set_points(
4532 config,
4533 2,
4534 1.0,
4535 scroll_points.len(),
4536 scroll_points.as_ptr(),
4537 ),
4538 0
4539 );
4540
4541 let mut device = Box::new(LibinputDevice::new(
4542 "pointer",
4543 "/dev/input/event0",
4544 std::ptr::null_mut(),
4545 std::ptr::null_mut(),
4546 ));
4547 device.accel_available = true;
4548 assert_eq!(libinput_device_config_accel_apply(&mut *device, config), 0);
4549 libinput_config_accel_destroy(config);
4550
4551 let custom = device.accel_custom.as_mut().expect("custom config copied");
4552 let curve = custom.curve_mut(1).expect("motion curve copied");
4553 assert_eq!(curve.points, points);
4554 assert!((curve.factor(7.0, 0.0, 7_000) - 2.0).abs() < 1e-9);
4555 let scroll_curve = custom.curve_mut(2).expect("scroll curve copied");
4556 assert_eq!(scroll_curve.points, scroll_points);
4557 assert!((scroll_curve.factor(7.0, 0.0, 7_000) - 3.0).abs() < 1e-9);
4558 }
4559 }
4560
4561 #[test]
4562 fn custom_acceleration_uses_fallback_and_extrapolates() {
4563 let mut config = crate::ffi_types::AccelConfig::new(4);
4564 config.fallback = Some(crate::ffi_types::AccelCurve::new(1.0, vec![0.0, 1.0]));
4565 let curve = config.curve_mut(1).expect("fallback curve");
4566 assert!((curve.factor(14.0, 0.0, 7_000) - 1.0).abs() < 1e-9);
4567 }
4568
4569 #[test]
4570 fn plugin_paths_are_ordered_unique_and_frozen_after_load() {
4571 unsafe {
4572 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4573 let custom = std::ffi::CString::new("/tmp/plugins").unwrap();
4574 let empty = std::ffi::CString::new("").unwrap();
4575 libinput_plugin_system_append_path(ctx, custom.as_ptr());
4576 libinput_plugin_system_append_path(ctx, custom.as_ptr());
4577 libinput_plugin_system_append_path(ctx, empty.as_ptr());
4578 libinput_plugin_system_append_default_paths(ctx);
4579 assert_eq!((*ctx).plugin_paths.len(), 4);
4580 assert_eq!((&(*ctx).plugin_paths)[0].as_bytes(), b"/tmp/plugins");
4581 assert_eq!((&(*ctx).plugin_paths)[1].as_bytes(), b"");
4582 assert_eq!(
4583 libinput_plugin_system_load_plugins(ctx, u32::MAX),
4584 -libc::ENOSYS
4585 );
4586 let ignored = std::ffi::CString::new("/ignored").unwrap();
4587 libinput_plugin_system_append_path(ctx, ignored.as_ptr());
4588 assert_eq!((*ctx).plugin_paths.len(), 4);
4589 assert_eq!(libinput_plugin_system_load_plugins(ctx, 0), 0);
4590 libinput_unref(ctx);
4591 }
4592 }
4593
4594 #[test]
4595 fn queued_events_retain_devices_until_event_destroy() {
4596 unsafe {
4597 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4598 let device = Box::into_raw(Box::new(LibinputDevice::new(
4599 "keyboard",
4600 "/dev/input/event0",
4601 std::ptr::null_mut(),
4602 ctx,
4603 )));
4604 enqueue_event(
4605 ctx,
4606 LibinputEvent {
4607 event_type: LibinputEventType::LIBINPUT_EVENT_KEYBOARD_KEY,
4608 payload: EventPayload::KeyboardKey(crate::ffi_types::KeyboardKeyEvent {
4609 time_usec: 1,
4610 key: 30,
4611 state: 1,
4612 seat_key_count: 1,
4613 }),
4614 context: ctx,
4615 device,
4616 },
4617 );
4618 assert_eq!(
4619 (*device).refcount.load(std::sync::atomic::Ordering::SeqCst),
4620 2
4621 );
4622 let event = libinput_get_event(ctx);
4623 assert_eq!(libinput_event_get_device(event), device);
4624 libinput_event_destroy(event);
4625 assert_eq!(
4626 (*device).refcount.load(std::sync::atomic::Ordering::SeqCst),
4627 1
4628 );
4629 assert!(libinput_device_unref(device).is_null());
4630 libinput_unref(ctx);
4631 }
4632 }
4633
4634 #[test]
4635 fn ref_and_unref_return_the_upstream_object_lifecycle() {
4636 unsafe {
4637 let seat = Box::into_raw(Box::new(LibinputSeat {
4638 physical_name: std::ffi::CString::new("seat0").unwrap(),
4639 logical_name: std::ffi::CString::new("default").unwrap(),
4640 refcount: std::sync::atomic::AtomicI32::new(1),
4641 user_data: std::ptr::null_mut(),
4642 context: std::ptr::null_mut(),
4643 button_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4644 key_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4645 }));
4646 assert_eq!(libinput_seat_ref(seat.cast()), seat.cast());
4647 assert_eq!(libinput_seat_unref(seat.cast()), seat.cast());
4648 assert!(libinput_seat_unref(seat.cast()).is_null());
4649
4650 let group = Box::into_raw(Box::new(LibinputTabletPadModeGroup {
4651 refcount: std::sync::atomic::AtomicI32::new(1),
4652 user_data: std::ptr::null_mut(),
4653 device: std::ptr::null_mut(),
4654 index: 0,
4655 num_modes: 1,
4656 current_mode: 0,
4657 button_mask: 0,
4658 dial_mask: 0,
4659 ring_mask: 0,
4660 strip_mask: 0,
4661 toggle_button_mask: 0,
4662 toggle_modes: Vec::new(),
4663 }));
4664 assert_eq!(
4665 libinput_tablet_pad_mode_group_ref(group.cast()),
4666 group.cast()
4667 );
4668 assert_eq!(
4669 libinput_tablet_pad_mode_group_unref(group.cast()),
4670 group.cast()
4671 );
4672 assert!(libinput_tablet_pad_mode_group_unref(group.cast()).is_null());
4673 }
4674 }
4675
4676 #[test]
4677 fn devices_retain_their_seat_until_device_destruction() {
4678 unsafe {
4679 let seat = Box::into_raw(Box::new(LibinputSeat {
4680 physical_name: std::ffi::CString::new("seat0").unwrap(),
4681 logical_name: std::ffi::CString::new("default").unwrap(),
4682 refcount: std::sync::atomic::AtomicI32::new(1),
4683 user_data: std::ptr::null_mut(),
4684 context: std::ptr::null_mut(),
4685 button_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4686 key_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4687 }));
4688 let device = Box::into_raw(Box::new(LibinputDevice::new(
4689 "keyboard",
4690 "/dev/input/event0",
4691 seat,
4692 std::ptr::null_mut(),
4693 )));
4694 assert_eq!(
4695 (*seat).refcount.load(std::sync::atomic::Ordering::SeqCst),
4696 2
4697 );
4698 assert!(libinput_device_unref(device).is_null());
4699 assert_eq!(
4700 (*seat).refcount.load(std::sync::atomic::Ordering::SeqCst),
4701 1
4702 );
4703 assert!(libinput_seat_unref(seat.cast()).is_null());
4704 }
4705 }
4706
4707 #[test]
4708 fn config_status_strings_match_upstream() {
4709 unsafe {
4710 assert_eq!(
4711 std::ffi::CStr::from_ptr(libinput_config_status_to_str(0)).to_bytes(),
4712 b"Success"
4713 );
4714 assert_eq!(
4715 std::ffi::CStr::from_ptr(libinput_config_status_to_str(1)).to_bytes(),
4716 b"Unsupported configuration option"
4717 );
4718 assert_eq!(
4719 std::ffi::CStr::from_ptr(libinput_config_status_to_str(2)).to_bytes(),
4720 b"Invalid argument range"
4721 );
4722 assert!(libinput_config_status_to_str(3).is_null());
4723 }
4724 }
4725
4726 #[test]
4727 fn absolute_pointer_coordinates_snapshot_calibration_and_use_inclusive_ranges() {
4728 unsafe {
4729 let mut device = Box::new(LibinputDevice::new(
4730 "pointer",
4731 "/dev/input/event0",
4732 std::ptr::null_mut(),
4733 std::ptr::null_mut(),
4734 ));
4735 device.abs_x_resolution = Some(20);
4736 device.abs_y_resolution = Some(40);
4737 let event = LibinputEvent {
4738 event_type: LibinputEventType::LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
4739 payload: EventPayload::PointerMotionAbsolute(
4740 crate::ffi_types::PointerMotionAbsoluteEvent {
4741 time_usec: 1,
4742 abs_x: 110.0,
4743 abs_y: 220.0,
4744 x_min: 10.0,
4745 x_max: 1009.0,
4746 y_min: 20.0,
4747 y_max: 2019.0,
4748 calibration: [1.0, 0.0, 0.1, 0.0, 1.0, 0.0],
4749 },
4750 ),
4751 context: std::ptr::null_mut(),
4752 device: &mut *device,
4753 };
4754 device.calibration = [1.0, 0.0, 0.9, 0.0, 1.0, 0.0];
4755
4756 assert!((libinput_event_pointer_get_absolute_x(&event) - 10.0).abs() < 1e-6);
4757 assert_eq!(libinput_event_pointer_get_absolute_y(&event), 5.0);
4758 assert!(
4759 (libinput_event_pointer_get_absolute_x_transformed(&event, 100) - 20.0).abs()
4760 < 1e-6
4761 );
4762 assert_eq!(
4763 libinput_event_pointer_get_absolute_y_transformed(&event, 100),
4764 10.0
4765 );
4766 }
4767 }
4768
4769 #[test]
4770 fn touch_cancel_retains_slot_information() {
4771 unsafe {
4772 let event = LibinputEvent {
4773 event_type: LibinputEventType::LIBINPUT_EVENT_TOUCH_CANCEL,
4774 payload: EventPayload::TouchCancel(crate::ffi_types::TouchEvent {
4775 time_usec: 1,
4776 slot: 7,
4777 seat_slot: 11,
4778 x: 0.0,
4779 y: 0.0,
4780 calibration: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0],
4781 }),
4782 context: std::ptr::null_mut(),
4783 device: std::ptr::null_mut(),
4784 };
4785
4786 assert_eq!(libinput_event_touch_get_slot(&event), 7);
4787 assert_eq!(libinput_event_touch_get_seat_slot(&event), 11);
4788 }
4789 }
4790
4791 #[test]
4792 fn touch_coordinates_use_event_time_calibration() {
4793 unsafe {
4794 let mut device = Box::new(LibinputDevice::new(
4795 "touch",
4796 "/dev/input/event0",
4797 std::ptr::null_mut(),
4798 std::ptr::null_mut(),
4799 ));
4800 device.abs_x_range = Some((10, 1009));
4801 device.abs_y_range = Some((20, 2019));
4802 device.abs_x_resolution = Some(20);
4803 device.abs_y_resolution = Some(40);
4804 let event = LibinputEvent {
4805 event_type: LibinputEventType::LIBINPUT_EVENT_TOUCH_MOTION,
4806 payload: EventPayload::TouchMotion(crate::ffi_types::TouchEvent {
4807 time_usec: 1,
4808 slot: 0,
4809 seat_slot: 0,
4810 x: 110.0,
4811 y: 220.0,
4812 calibration: [1.0, 0.0, 0.1, 0.0, 1.0, 0.0],
4813 }),
4814 context: std::ptr::null_mut(),
4815 device: &mut *device,
4816 };
4817 device.calibration = [1.0, 0.0, 0.9, 0.0, 1.0, 0.0];
4818
4819 assert!((libinput_event_touch_get_x(&event) - 10.0).abs() < 1e-6);
4820 assert_eq!(libinput_event_touch_get_y(&event), 5.0);
4821 assert!((libinput_event_touch_get_x_transformed(&event, 100) - 20.0).abs() < 1e-6);
4822 assert_eq!(libinput_event_touch_get_y_transformed(&event, 100), 10.0);
4823 }
4824 }
4825
4826 #[test]
4827 fn tablet_tip_events_expose_axis_deltas() {
4828 unsafe {
4829 let event = LibinputEvent {
4830 event_type: LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_TIP,
4831 payload: EventPayload::TabletTool(crate::ffi_types::TabletToolEvent {
4832 time_usec: 1,
4833 tool: std::ptr::null_mut(),
4834 proximity_state: 0,
4835 x: 0.0,
4836 y: 0.0,
4837 dx: 2.5,
4838 dy: -1.5,
4839 x_min: 0.0,
4840 x_max: 1.0,
4841 y_min: 0.0,
4842 y_max: 1.0,
4843 x_resolution: 1.0,
4844 y_resolution: 1.0,
4845 x_changed: true,
4846 y_changed: true,
4847 pressure: 0.0,
4848 pressure_min: 0.0,
4849 pressure_max: 1.0,
4850 pressure_changed: false,
4851 distance: 0.0,
4852 distance_changed: false,
4853 tilt_x: 0.0,
4854 tilt_y: 0.0,
4855 tilt_x_changed: false,
4856 tilt_y_changed: false,
4857 rotation: 0.0,
4858 rotation_changed: false,
4859 slider: 0.0,
4860 slider_changed: false,
4861 wheel_delta: 0.0,
4862 wheel_discrete: 0,
4863 wheel_changed: false,
4864 size_major: 0.0,
4865 size_minor: 0.0,
4866 size_major_changed: false,
4867 size_minor_changed: false,
4868 tip_state: 1,
4869 button: 0,
4870 button_state: 0,
4871 seat_button_count: 0,
4872 }),
4873 context: std::ptr::null_mut(),
4874 device: std::ptr::null_mut(),
4875 };
4876
4877 assert_eq!(libinput_event_tablet_tool_get_dx(&event), 2.5);
4878 assert_eq!(libinput_event_tablet_tool_get_dy(&event), -1.5);
4879 }
4880 }
4881
4882 #[test]
4883 fn unsupported_configs_report_unsupported_before_invalid_values() {
4884 unsafe {
4885 let mut device = Box::new(LibinputDevice::new(
4886 "device",
4887 "/dev/input/event0",
4888 std::ptr::null_mut(),
4889 std::ptr::null_mut(),
4890 ));
4891
4892 assert_eq!(
4893 libinput_device_config_rotation_set_angle(&mut *device, 360),
4894 1
4895 );
4896 assert_eq!(
4897 libinput_device_config_rotation_set_angle(&mut *device, 0),
4898 0
4899 );
4900 assert_eq!(
4901 libinput_device_config_3fg_drag_set_enabled(&mut *device, u32::MAX),
4902 1
4903 );
4904 assert_eq!(libinput_device_pointer_has_button(&*device, u32::MAX), -1);
4905 assert_eq!(libinput_device_switch_has_switch(&*device, 1), -1);
4906 assert_eq!(libinput_device_switch_has_switch(&*device, u32::MAX), -1);
4907 }
4908 }
4909
4910 #[test]
4911 fn setting_a_null_log_handler_disables_the_default_handler() {
4912 unsafe {
4913 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4914 assert!((*ctx).default_log_handler_enabled);
4915 libinput_log_set_handler(ctx, None);
4916 assert!(!(*ctx).default_log_handler_enabled);
4917 libinput_unref(ctx);
4918 }
4919 }
4920}