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