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_touch_get_touch_count(
1225 dev: *const LibinputDevice,
1226) -> libc::c_int {
1227 if dev.is_null() || !(*dev).has_touch {
1228 return -1;
1229 }
1230 (*dev).touch_count
1231}
1232
1233#[no_mangle]
1234pub unsafe extern "C" fn libinput_device_has_capability(
1235 dev: *const LibinputDevice,
1236 capability: u32,
1237) -> libc::c_int {
1238 if dev.is_null() {
1239 return 0;
1240 }
1241 let has = match capability {
1242 0 => (*dev).has_keyboard,
1243 1 => (*dev).has_pointer,
1244 2 => (*dev).has_touch,
1245 3 => (*dev).has_tablet,
1246 4 => (*dev).has_tablet_pad,
1247 5 => (*dev).has_gesture,
1248 6 => (*dev).has_switch,
1249 _ => false,
1250 };
1251 has as libc::c_int
1252}
1253
1254#[no_mangle]
1259pub unsafe extern "C" fn libinput_device_config_tap_get_finger_count(
1260 dev: *const LibinputDevice,
1261) -> libc::c_int {
1262 if dev.is_null() {
1263 return 0;
1264 }
1265 (*dev).tap_finger_count
1266}
1267
1268#[no_mangle]
1269pub unsafe extern "C" fn libinput_device_config_tap_set_enabled(
1270 dev: *mut LibinputDevice,
1271 enabled: u32,
1272) -> u32 {
1273 if dev.is_null() {
1274 return 1;
1275 }
1276 if enabled > 1 {
1277 return 2;
1278 }
1279 if (*dev).tap_finger_count == 0 {
1280 return if enabled == 0 { 0 } else { 1 };
1281 }
1282 (*dev).tap_enabled = enabled != 0;
1283 0
1284}
1285
1286#[no_mangle]
1287pub unsafe extern "C" fn libinput_device_config_tap_get_enabled(dev: *const LibinputDevice) -> u32 {
1288 if dev.is_null() {
1289 return 0;
1290 }
1291 (*dev).tap_enabled as u32
1292}
1293
1294#[no_mangle]
1295pub unsafe extern "C" fn libinput_device_config_tap_get_default_enabled(
1296 dev: *const LibinputDevice,
1297) -> u32 {
1298 if dev.is_null() {
1299 return 0;
1300 }
1301 (*dev).tap_default_enabled as u32
1302}
1303
1304#[no_mangle]
1305pub unsafe extern "C" fn libinput_device_config_tap_set_drag_enabled(
1306 dev: *mut LibinputDevice,
1307 enabled: u32,
1308) -> u32 {
1309 if dev.is_null() {
1310 return 1;
1311 }
1312 if enabled > 1 {
1313 return 2;
1314 }
1315 if (*dev).tap_finger_count == 0 {
1316 return if enabled == 0 { 0 } else { 1 };
1317 }
1318 (*dev).tap_drag_enabled = enabled != 0;
1319 0
1320}
1321
1322#[no_mangle]
1323pub unsafe extern "C" fn libinput_device_config_tap_get_drag_enabled(
1324 dev: *const LibinputDevice,
1325) -> u32 {
1326 if dev.is_null() {
1327 return 0;
1328 }
1329 (*dev).tap_drag_enabled as u32
1330}
1331
1332#[no_mangle]
1333pub unsafe extern "C" fn libinput_device_config_tap_get_default_drag_enabled(
1334 dev: *const LibinputDevice,
1335) -> u32 {
1336 if dev.is_null() {
1337 return 0;
1338 }
1339 ((*dev).tap_finger_count != 0) as u32
1340}
1341
1342#[no_mangle]
1343pub unsafe extern "C" fn libinput_device_config_tap_set_drag_lock_enabled(
1344 dev: *mut LibinputDevice,
1345 enabled: u32,
1346) -> u32 {
1347 if dev.is_null() {
1348 return 1;
1349 }
1350 if enabled > 2 {
1351 return 2;
1352 }
1353 if (*dev).tap_finger_count == 0 {
1354 return if enabled == 0 { 0 } else { 1 };
1355 }
1356 (*dev).tap_drag_lock_enabled = if enabled == 1 { 1 } else { enabled };
1357 0
1358}
1359
1360#[no_mangle]
1361pub unsafe extern "C" fn libinput_device_config_tap_get_drag_lock_enabled(
1362 dev: *const LibinputDevice,
1363) -> u32 {
1364 if dev.is_null() {
1365 return 0;
1366 }
1367 (*dev).tap_drag_lock_enabled
1368}
1369
1370#[no_mangle]
1372pub unsafe extern "C" fn libinput_device_config_tap_set_button_map(
1373 dev: *mut LibinputDevice,
1374 map: u32,
1375) -> u32 {
1376 if dev.is_null() {
1377 return 1;
1378 }
1379 if map > 1 {
1380 return 2;
1381 }
1382 if (*dev).tap_finger_count == 0 {
1383 return 1;
1384 }
1385 (*dev).tap_button_map = map;
1386 0
1387}
1388
1389#[no_mangle]
1390pub unsafe extern "C" fn libinput_device_config_tap_get_button_map(
1391 dev: *const LibinputDevice,
1392) -> u32 {
1393 if dev.is_null() {
1394 return 0;
1395 }
1396 (*dev).tap_button_map
1397}
1398
1399#[no_mangle]
1400pub unsafe extern "C" fn libinput_device_config_tap_get_default_button_map(
1401 _dev: *const LibinputDevice,
1402) -> u32 {
1403 0
1404} #[no_mangle]
1407pub unsafe extern "C" fn libinput_device_config_3fg_drag_get_finger_count(
1408 dev: *const LibinputDevice,
1409) -> libc::c_int {
1410 if dev.is_null() || !(*dev).has_gesture {
1411 return 0;
1412 }
1413 (*dev).mt_slot_count
1414}
1415
1416#[no_mangle]
1417pub unsafe extern "C" fn libinput_device_config_3fg_drag_set_enabled(
1418 dev: *mut LibinputDevice,
1419 enable: u32,
1420) -> u32 {
1421 if dev.is_null() {
1422 return 1;
1423 }
1424 if !matches!(enable, 0..=2) {
1425 return 2;
1426 }
1427 if libinput_device_config_3fg_drag_get_finger_count(dev) < 3 {
1428 return 1;
1429 }
1430 (*dev).drag_3fg_enabled = enable;
1431 0
1432}
1433
1434#[no_mangle]
1435pub unsafe extern "C" fn libinput_device_config_3fg_drag_get_enabled(
1436 dev: *const LibinputDevice,
1437) -> u32 {
1438 if dev.is_null() {
1439 return 0;
1440 }
1441 (*dev).drag_3fg_enabled
1442}
1443
1444#[no_mangle]
1445pub unsafe extern "C" fn libinput_device_config_3fg_drag_get_default_enabled(
1446 _dev: *const LibinputDevice,
1447) -> u32 {
1448 0
1449}
1450
1451#[no_mangle]
1456pub unsafe extern "C" fn libinput_config_accel_create(profile: u32) -> *mut libc::c_void {
1457 if !matches!(profile, 1 | 2 | 4) {
1458 return std::ptr::null_mut();
1459 }
1460 Box::into_raw(Box::new(crate::ffi_types::AccelConfig::new(profile))) as *mut libc::c_void
1461}
1462
1463#[no_mangle]
1464pub unsafe extern "C" fn libinput_config_accel_destroy(accel_config: *mut libc::c_void) {
1465 if !accel_config.is_null() {
1466 drop(Box::from_raw(
1467 accel_config as *mut crate::ffi_types::AccelConfig,
1468 ));
1469 }
1470}
1471
1472#[no_mangle]
1473pub unsafe extern "C" fn libinput_config_accel_set_points(
1474 accel_config: *mut libc::c_void,
1475 accel_type: u32,
1476 step: f64,
1477 npoints: libc::size_t,
1478 points: *const f64,
1479) -> u32 {
1480 if accel_config.is_null()
1481 || points.is_null()
1482 || !step.is_finite()
1483 || step <= 0.0
1484 || step > 10_000.0
1485 || !(2..=64).contains(&npoints)
1486 {
1487 return 2;
1488 }
1489 let config = &mut *(accel_config as *mut crate::ffi_types::AccelConfig);
1490 if config.profile != 4 || !matches!(accel_type, 0..=2) {
1491 return 2;
1492 }
1493 let points = std::slice::from_raw_parts(points, npoints);
1494 if points
1495 .iter()
1496 .any(|point| !point.is_finite() || *point < 0.0 || *point > 10_000.0)
1497 {
1498 return 2;
1499 }
1500 let curve = crate::ffi_types::AccelCurve::new(step, points.to_vec());
1501 match accel_type {
1502 0 => config.fallback = Some(curve),
1503 1 => config.motion = Some(curve),
1504 2 => config.scroll = Some(curve),
1505 _ => unreachable!(),
1506 }
1507 0
1508}
1509
1510#[no_mangle]
1511pub unsafe extern "C" fn libinput_device_config_accel_apply(
1512 dev: *mut LibinputDevice,
1513 accel_config: *mut libc::c_void,
1514) -> u32 {
1515 if dev.is_null() || accel_config.is_null() {
1516 return 2;
1517 }
1518 if !(*dev).accel_available {
1519 return 1;
1520 }
1521 let config = &*(accel_config as *const crate::ffi_types::AccelConfig);
1522 let profile = config.profile;
1523 if profile & libinput_device_config_accel_get_profiles(dev) == 0 {
1524 return 1;
1525 }
1526 (*dev).accel_profile = profile;
1527 (*dev).accel_speed = 0.0;
1528 (*dev).accel_custom = (profile == 4).then(|| config.clone());
1529 0
1530}
1531
1532#[no_mangle]
1533pub unsafe extern "C" fn libinput_device_config_accel_is_available(
1534 dev: *const LibinputDevice,
1535) -> libc::c_int {
1536 if dev.is_null() {
1537 return 0;
1538 }
1539 (*dev).accel_available as libc::c_int
1540}
1541
1542#[no_mangle]
1543pub unsafe extern "C" fn libinput_device_config_accel_set_speed(
1544 dev: *mut LibinputDevice,
1545 speed: f64,
1546) -> u32 {
1547 if dev.is_null() {
1548 return 1;
1549 }
1550 if !speed.is_finite() || !(-1.0..=1.0).contains(&speed) {
1551 return 2;
1552 }
1553 if !(*dev).accel_available {
1554 return 1;
1555 }
1556 (*dev).accel_speed = speed;
1557 0
1558}
1559
1560#[no_mangle]
1561pub unsafe extern "C" fn libinput_device_config_accel_get_speed(dev: *const LibinputDevice) -> f64 {
1562 if dev.is_null() {
1563 return 0.0;
1564 }
1565 (*dev).accel_speed
1566}
1567
1568#[no_mangle]
1569pub unsafe extern "C" fn libinput_device_config_accel_get_default_speed(
1570 _dev: *const LibinputDevice,
1571) -> f64 {
1572 0.0
1573}
1574
1575#[no_mangle]
1576pub unsafe extern "C" fn libinput_device_config_accel_get_profiles(
1577 dev: *const LibinputDevice,
1578) -> u32 {
1579 if dev.is_null() {
1580 return 0;
1581 }
1582 if (*dev).accel_available
1583 && !((*dev).has_tablet && !(*dev).has_gesture && !(*dev).has_tablet_pad)
1584 {
1585 0b111
1586 } else {
1587 0
1588 }
1589}
1590
1591#[no_mangle]
1592pub unsafe extern "C" fn libinput_device_config_accel_set_profile(
1593 dev: *mut LibinputDevice,
1594 profile: u32,
1595) -> u32 {
1596 if dev.is_null() {
1597 return 1;
1598 }
1599 if profile == 0 || profile & !0b111 != 0 || profile.count_ones() != 1 {
1600 return 2;
1601 }
1602 if profile & libinput_device_config_accel_get_profiles(dev) == 0 {
1603 return 1;
1604 }
1605 (*dev).accel_profile = profile;
1606 (*dev).accel_custom = if profile == 4 {
1607 Some(crate::ffi_types::AccelConfig::new(profile))
1608 } else {
1609 None
1610 };
1611 0
1612}
1613
1614#[no_mangle]
1615pub unsafe extern "C" fn libinput_device_config_accel_get_profile(
1616 dev: *const LibinputDevice,
1617) -> u32 {
1618 if dev.is_null() {
1619 return 0;
1620 }
1621 if (*dev).accel_available
1622 && !((*dev).has_tablet && !(*dev).has_gesture && !(*dev).has_tablet_pad)
1623 {
1624 (*dev).accel_profile
1625 } else {
1626 0
1627 }
1628}
1629
1630#[no_mangle]
1631pub unsafe extern "C" fn libinput_device_config_accel_get_default_profile(
1632 dev: *const LibinputDevice,
1633) -> u32 {
1634 if dev.is_null()
1635 || !(*dev).accel_available
1636 || ((*dev).has_tablet && !(*dev).has_gesture && !(*dev).has_tablet_pad)
1637 {
1638 0
1639 } else {
1640 2
1641 }
1642}
1643
1644#[no_mangle]
1649pub unsafe extern "C" fn libinput_device_config_scroll_has_natural_scroll(
1650 dev: *const LibinputDevice,
1651) -> libc::c_int {
1652 if dev.is_null() {
1653 return 0;
1654 }
1655 (*dev).has_pointer as libc::c_int
1656}
1657
1658#[no_mangle]
1659pub unsafe extern "C" fn libinput_device_config_scroll_set_natural_scroll_enabled(
1660 dev: *mut LibinputDevice,
1661 enabled: libc::c_int,
1662) -> u32 {
1663 if dev.is_null() || !(*dev).has_pointer {
1664 return 1;
1665 }
1666 (*dev).natural_scroll = enabled != 0;
1667 0
1668}
1669
1670#[no_mangle]
1671pub unsafe extern "C" fn libinput_device_config_scroll_get_natural_scroll_enabled(
1672 dev: *const LibinputDevice,
1673) -> libc::c_int {
1674 if dev.is_null() {
1675 return 0;
1676 }
1677 (*dev).natural_scroll as libc::c_int
1678}
1679
1680#[no_mangle]
1681pub unsafe extern "C" fn libinput_device_config_scroll_get_default_natural_scroll_enabled(
1682 dev: *const LibinputDevice,
1683) -> libc::c_int {
1684 if dev.is_null() {
1685 return 0;
1686 }
1687 ((*dev).scroll_methods & 2 != 0 && (*dev).vendor_id == 0x05ac) as libc::c_int
1688}
1689
1690#[no_mangle]
1695pub unsafe extern "C" fn libinput_device_config_left_handed_is_available(
1696 dev: *const LibinputDevice,
1697) -> libc::c_int {
1698 if dev.is_null() {
1699 return 0;
1700 }
1701 (*dev).left_handed_available as libc::c_int
1702}
1703
1704#[no_mangle]
1705pub unsafe extern "C" fn libinput_device_config_left_handed_set(
1706 dev: *mut LibinputDevice,
1707 enabled: libc::c_int,
1708) -> u32 {
1709 if dev.is_null() || !(*dev).left_handed_available {
1710 return 1;
1711 }
1712 (*dev).left_handed = enabled != 0;
1713 0
1714}
1715
1716#[no_mangle]
1717pub unsafe extern "C" fn libinput_device_config_left_handed_get(
1718 dev: *const LibinputDevice,
1719) -> libc::c_int {
1720 if dev.is_null() {
1721 return 0;
1722 }
1723 (*dev).left_handed as libc::c_int
1724}
1725
1726#[no_mangle]
1727pub unsafe extern "C" fn libinput_device_config_left_handed_get_default(
1728 _dev: *const LibinputDevice,
1729) -> libc::c_int {
1730 0
1731}
1732
1733#[no_mangle]
1738pub unsafe extern "C" fn libinput_device_config_scroll_get_methods(
1739 dev: *const LibinputDevice,
1740) -> u32 {
1741 if dev.is_null() {
1742 return 0;
1743 }
1744 (*dev).scroll_methods
1745}
1746
1747#[no_mangle]
1748pub unsafe extern "C" fn libinput_device_config_scroll_set_method(
1749 dev: *mut LibinputDevice,
1750 method: u32,
1751) -> u32 {
1752 if dev.is_null() {
1753 return 1;
1754 }
1755 if !matches!(method, 0 | 1 | 2 | 4) {
1756 return 2;
1757 }
1758 if method != 0 && method & (*dev).scroll_methods == 0 {
1759 return 1;
1760 }
1761 if (*dev).scroll_method == method {
1762 return 0;
1763 }
1764 let ctx = (*dev).context;
1765 if !ctx.is_null() {
1766 let mut events = std::collections::VecDeque::new();
1767 if let Ok(mut backend) = (*ctx).backend.try_lock() {
1768 backend.stop_scroll_for_device(ctx, dev, &mut events);
1769 }
1770 enqueue_events(ctx, events);
1771 }
1772 (*dev).scroll_method = method;
1773 0
1774}
1775
1776#[no_mangle]
1777pub unsafe extern "C" fn libinput_device_config_scroll_get_method(
1778 dev: *const LibinputDevice,
1779) -> u32 {
1780 if dev.is_null() {
1781 return 0;
1782 }
1783 (*dev).scroll_method
1784}
1785
1786#[no_mangle]
1787pub unsafe extern "C" fn libinput_device_config_scroll_get_default_method(
1788 dev: *const LibinputDevice,
1789) -> u32 {
1790 if dev.is_null() {
1791 0
1792 } else {
1793 (*dev).scroll_default_method
1794 }
1795}
1796
1797#[no_mangle]
1798pub unsafe extern "C" fn libinput_device_config_scroll_set_button(
1799 dev: *mut LibinputDevice,
1800 button: u32,
1801) -> u32 {
1802 if dev.is_null() || !(*dev).supports_button_scroll {
1803 return 1;
1804 }
1805 if button != 0
1806 && match u16::try_from(button) {
1807 Ok(button) => !(*dev).event_codes.contains(&button),
1808 Err(_) => true,
1809 }
1810 {
1811 return 2;
1812 }
1813 (*dev).scroll_button = button;
1814 0
1815}
1816
1817#[no_mangle]
1818pub unsafe extern "C" fn libinput_device_config_scroll_get_button(
1819 dev: *const LibinputDevice,
1820) -> u32 {
1821 if dev.is_null() || !(*dev).supports_button_scroll {
1822 0
1823 } else {
1824 (*dev).scroll_button
1825 }
1826}
1827
1828#[no_mangle]
1829pub unsafe extern "C" fn libinput_device_config_scroll_set_button_lock(
1830 dev: *mut LibinputDevice,
1831 state: u32,
1832) -> u32 {
1833 if dev.is_null() || !(*dev).supports_button_scroll {
1834 return 1;
1835 }
1836 if state > 1 {
1837 return 2;
1838 }
1839 (*dev).scroll_button_lock = state;
1840 0
1841}
1842
1843#[no_mangle]
1844pub unsafe extern "C" fn libinput_device_config_scroll_get_button_lock(
1845 dev: *const LibinputDevice,
1846) -> u32 {
1847 if dev.is_null() || !(*dev).supports_button_scroll {
1848 0
1849 } else {
1850 (*dev).scroll_button_lock
1851 }
1852}
1853
1854#[no_mangle]
1855pub unsafe extern "C" fn libinput_device_config_scroll_get_default_button_lock(
1856 _dev: *const LibinputDevice,
1857) -> u32 {
1858 0
1859}
1860
1861#[no_mangle]
1866pub unsafe extern "C" fn libinput_device_config_click_get_methods(
1867 dev: *const LibinputDevice,
1868) -> u32 {
1869 if dev.is_null() {
1870 return 0;
1871 }
1872 (*dev).click_methods
1873}
1874
1875#[no_mangle]
1876pub unsafe extern "C" fn libinput_device_config_click_set_method(
1877 dev: *mut LibinputDevice,
1878 method: u32,
1879) -> u32 {
1880 if dev.is_null() {
1881 return 1;
1882 }
1883 if !matches!(method, 0..=2) {
1884 return 2;
1885 }
1886 if method != 0 && method & (*dev).click_methods == 0 {
1887 return 1;
1888 }
1889 (*dev).click_method = method;
1890 0
1891}
1892
1893#[no_mangle]
1894pub unsafe extern "C" fn libinput_device_config_click_get_method(
1895 dev: *const LibinputDevice,
1896) -> u32 {
1897 if dev.is_null() {
1898 return 0;
1899 }
1900 (*dev).click_method
1901}
1902
1903#[no_mangle]
1904pub unsafe extern "C" fn libinput_device_config_click_get_default_method(
1905 dev: *const LibinputDevice,
1906) -> u32 {
1907 if dev.is_null() {
1908 0
1909 } else {
1910 (*dev).click_default_method
1911 }
1912}
1913
1914#[no_mangle]
1915pub unsafe extern "C" fn libinput_device_config_click_set_clickfinger_button_map(
1916 dev: *mut LibinputDevice,
1917 map: u32,
1918) -> u32 {
1919 if dev.is_null() {
1920 return 1;
1921 }
1922 if !matches!(map, 0 | 1) {
1923 return 2;
1924 }
1925 if (*dev).click_methods & 2 == 0 {
1926 return 1;
1927 }
1928 (*dev).clickfinger_button_map = map;
1929 0
1930}
1931
1932#[no_mangle]
1933pub unsafe extern "C" fn libinput_device_config_click_get_clickfinger_button_map(
1934 dev: *const LibinputDevice,
1935) -> u32 {
1936 if dev.is_null() || (*dev).click_methods & 2 == 0 {
1937 0
1938 } else {
1939 (*dev).clickfinger_button_map
1940 }
1941}
1942
1943#[no_mangle]
1944pub unsafe extern "C" fn libinput_device_config_click_get_default_clickfinger_button_map(
1945 dev: *const LibinputDevice,
1946) -> u32 {
1947 if dev.is_null() || (*dev).click_methods & 2 == 0 {
1948 0
1949 } else {
1950 (*dev).clickfinger_default_button_map
1951 }
1952}
1953
1954#[no_mangle]
1959pub unsafe extern "C" fn libinput_device_config_middle_emulation_is_available(
1960 dev: *const LibinputDevice,
1961) -> libc::c_int {
1962 if dev.is_null() {
1963 return 0;
1964 }
1965 (*dev).middle_emulation_available as libc::c_int
1966}
1967
1968#[no_mangle]
1969pub unsafe extern "C" fn libinput_device_config_middle_emulation_set_enabled(
1970 dev: *mut LibinputDevice,
1971 enabled: u32,
1972) -> u32 {
1973 if dev.is_null() {
1974 return 1;
1975 }
1976 if enabled > 1 {
1977 return 2;
1978 }
1979 if enabled == 1 && !(*dev).middle_emulation_available {
1980 return 1;
1981 }
1982 (*dev).middle_emulation = enabled != 0;
1983 0
1984}
1985
1986#[no_mangle]
1987pub unsafe extern "C" fn libinput_device_config_middle_emulation_get_enabled(
1988 dev: *const LibinputDevice,
1989) -> u32 {
1990 if dev.is_null() || !(*dev).middle_emulation_available {
1991 return 0;
1992 }
1993 (*dev).middle_emulation as u32
1994}
1995
1996#[no_mangle]
1997pub unsafe extern "C" fn libinput_device_config_middle_emulation_get_default_enabled(
1998 dev: *const LibinputDevice,
1999) -> u32 {
2000 if dev.is_null() || !(*dev).middle_emulation_available {
2001 return 0;
2002 }
2003 (*dev).middle_emulation_default as u32
2004}
2005
2006#[no_mangle]
2011pub unsafe extern "C" fn libinput_device_config_dwt_is_available(
2012 dev: *const LibinputDevice,
2013) -> libc::c_int {
2014 (!dev.is_null() && (*dev).dwt_available) as libc::c_int
2015}
2016
2017#[no_mangle]
2018pub unsafe extern "C" fn libinput_device_config_dwt_set_enabled(
2019 dev: *mut LibinputDevice,
2020 enabled: u32,
2021) -> u32 {
2022 if dev.is_null() {
2023 return 1;
2024 }
2025 if !matches!(enabled, 0 | 1) {
2026 return 2;
2027 }
2028 if !(*dev).dwt_available {
2029 return if enabled == 0 { 0 } else { 1 };
2030 }
2031 (*dev).dwt_enabled = enabled == 1;
2032 0
2033}
2034
2035#[no_mangle]
2036pub unsafe extern "C" fn libinput_device_config_dwt_get_enabled(dev: *const LibinputDevice) -> u32 {
2037 if dev.is_null() || !(*dev).dwt_available {
2038 return 0;
2039 }
2040 (*dev).dwt_enabled as u32
2041}
2042
2043#[no_mangle]
2044pub unsafe extern "C" fn libinput_device_config_dwt_get_default_enabled(
2045 dev: *const LibinputDevice,
2046) -> u32 {
2047 (!dev.is_null() && (*dev).dwt_available) as u32
2048}
2049
2050#[no_mangle]
2051pub unsafe extern "C" fn libinput_device_config_dwt_set_timeout(
2052 dev: *mut LibinputDevice,
2053 millis: u32,
2054) -> u32 {
2055 if dev.is_null() {
2056 return 1;
2057 }
2058 if millis == 0 {
2059 return 2;
2060 }
2061 if !(*dev).dwt_available {
2062 return 1;
2063 }
2064 if !(100..=5000).contains(&millis) {
2065 return 2;
2066 }
2067 (*dev).dwt_timeout = millis;
2068 0
2069}
2070
2071#[no_mangle]
2072pub unsafe extern "C" fn libinput_device_config_dwt_get_timeout(dev: *const LibinputDevice) -> u32 {
2073 if dev.is_null() || !(*dev).dwt_available {
2074 0
2075 } else {
2076 (*dev).dwt_timeout
2077 }
2078}
2079
2080#[no_mangle]
2081pub unsafe extern "C" fn libinput_device_config_dwt_get_default_timeout(
2082 dev: *const LibinputDevice,
2083) -> u32 {
2084 if !dev.is_null() && (*dev).dwt_available {
2085 500
2086 } else {
2087 0
2088 }
2089}
2090
2091#[no_mangle]
2092pub unsafe extern "C" fn libinput_device_config_dwtp_is_available(
2093 dev: *const LibinputDevice,
2094) -> libc::c_int {
2095 (!dev.is_null() && (*dev).dwtp_available) as libc::c_int
2096}
2097
2098#[no_mangle]
2099pub unsafe extern "C" fn libinput_device_config_dwtp_set_enabled(
2100 dev: *mut LibinputDevice,
2101 enabled: u32,
2102) -> u32 {
2103 if dev.is_null() {
2104 return 1;
2105 }
2106 if !matches!(enabled, 0 | 1) {
2107 return 2;
2108 }
2109 if !(*dev).dwtp_available {
2110 return if enabled == 0 { 0 } else { 1 };
2111 }
2112 (*dev).dwtp_enabled = enabled == 1;
2113 0
2114}
2115
2116#[no_mangle]
2117pub unsafe extern "C" fn libinput_device_config_dwtp_get_enabled(
2118 dev: *const LibinputDevice,
2119) -> u32 {
2120 if dev.is_null() || !(*dev).dwtp_available {
2121 0
2122 } else {
2123 (*dev).dwtp_enabled as u32
2124 }
2125}
2126
2127#[no_mangle]
2128pub unsafe extern "C" fn libinput_device_config_dwtp_get_default_enabled(
2129 dev: *const LibinputDevice,
2130) -> u32 {
2131 (!dev.is_null() && (*dev).dwtp_available) as u32
2132}
2133
2134#[no_mangle]
2135pub unsafe extern "C" fn libinput_device_config_dwtp_set_timeout(
2136 dev: *mut LibinputDevice,
2137 millis: u32,
2138) -> u32 {
2139 if dev.is_null() {
2140 return 1;
2141 }
2142 if millis == 0 {
2143 return 2;
2144 }
2145 if !(*dev).dwtp_available {
2146 return 1;
2147 }
2148 if !(100..=5000).contains(&millis) {
2149 return 2;
2150 }
2151 (*dev).dwtp_timeout = millis;
2152 0
2153}
2154
2155#[no_mangle]
2156pub unsafe extern "C" fn libinput_device_config_dwtp_get_timeout(
2157 dev: *const LibinputDevice,
2158) -> u32 {
2159 if dev.is_null() || !(*dev).dwtp_available {
2160 0
2161 } else {
2162 (*dev).dwtp_timeout
2163 }
2164}
2165
2166#[no_mangle]
2167pub unsafe extern "C" fn libinput_device_config_dwtp_get_default_timeout(
2168 dev: *const LibinputDevice,
2169) -> u32 {
2170 if !dev.is_null() && (*dev).dwtp_available {
2171 300
2172 } else {
2173 0
2174 }
2175}
2176
2177#[no_mangle]
2182pub unsafe extern "C" fn libinput_device_config_calibration_has_matrix(
2183 dev: *const LibinputDevice,
2184) -> libc::c_int {
2185 if dev.is_null() {
2186 return 0;
2187 }
2188 (*dev).calibration_available as libc::c_int
2189}
2190
2191#[no_mangle]
2192pub unsafe extern "C" fn libinput_device_config_calibration_set_matrix(
2193 dev: *mut LibinputDevice,
2194 matrix: *const f32,
2195) -> u32 {
2196 if dev.is_null() || matrix.is_null() || !(*dev).calibration_available {
2197 return 1;
2198 }
2199 (*dev)
2200 .calibration
2201 .copy_from_slice(std::slice::from_raw_parts(matrix, 6));
2202 0
2203}
2204
2205#[no_mangle]
2206pub unsafe extern "C" fn libinput_device_config_calibration_get_matrix(
2207 dev: *const LibinputDevice,
2208 matrix: *mut f32,
2209) -> libc::c_int {
2210 if dev.is_null() || matrix.is_null() || !(*dev).calibration_available {
2211 return 0;
2212 }
2213 std::slice::from_raw_parts_mut(matrix, 6).copy_from_slice(&(*dev).calibration);
2214 ((*dev).calibration != [1.0_f32, 0.0, 0.0, 0.0, 1.0, 0.0]) as libc::c_int
2215}
2216
2217#[no_mangle]
2218pub unsafe extern "C" fn libinput_device_config_calibration_get_default_matrix(
2219 dev: *const LibinputDevice,
2220 matrix: *mut f32,
2221) -> libc::c_int {
2222 if dev.is_null() || matrix.is_null() || !(*dev).calibration_available {
2223 return 0;
2224 }
2225 std::slice::from_raw_parts_mut(matrix, 6).copy_from_slice(&(*dev).default_calibration);
2226 ((*dev).default_calibration != [1.0_f32, 0.0, 0.0, 0.0, 1.0, 0.0]) as libc::c_int
2227}
2228
2229#[no_mangle]
2234pub unsafe extern "C" fn libinput_device_get_seat(dev: *const LibinputDevice) -> *mut libc::c_void {
2235 if dev.is_null() {
2236 return std::ptr::null_mut();
2237 }
2238 (*dev).seat as *mut libc::c_void
2239}
2240
2241#[no_mangle]
2242pub unsafe extern "C" fn libinput_device_set_seat_logical_name(
2243 dev: *mut LibinputDevice,
2244 name: *const libc::c_char,
2245) -> libc::c_int {
2246 if dev.is_null() || name.is_null() || (*dev).seat.is_null() {
2247 return -1;
2248 }
2249 let name = CStr::from_ptr(name);
2250 if name.to_bytes().is_empty() || name.to_bytes().len() > 255 {
2251 return -1;
2252 }
2253 if (*(*dev).seat).logical_name.as_c_str() == name {
2254 return 0;
2255 }
2256 let Ok(logical_name) = std::ffi::CString::new(name.to_bytes()) else {
2257 return -1;
2258 };
2259 let ctx = (*dev).context;
2260 if ctx.is_null() {
2261 return -1;
2262 }
2263 let physical_name = (*(*dev).seat).physical_name.clone();
2264 let new_seat = (*ctx)
2265 .seats
2266 .iter()
2267 .copied()
2268 .find(|seat| {
2269 !seat.is_null()
2270 && (**seat).physical_name == physical_name
2271 && (**seat).logical_name == logical_name
2272 })
2273 .unwrap_or_else(|| {
2274 let seat = Box::into_raw(Box::new(LibinputSeat {
2275 physical_name,
2276 logical_name,
2277 refcount: std::sync::atomic::AtomicI32::new(1),
2278 user_data: std::ptr::null_mut(),
2279 context: ctx,
2280 button_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
2281 key_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
2282 }));
2283 (*ctx).seats.push(seat);
2284 seat
2285 });
2286
2287 let path = std::path::PathBuf::from((*dev).devnode.to_string_lossy().into_owned());
2288 let mut removed = std::collections::VecDeque::new();
2289 let mut added = Vec::new();
2290 let replaced = if let Ok(mut backend) = (*ctx).backend.lock() {
2291 if backend.remove_device(ctx, dev, &mut removed) {
2292 backend.try_open(ctx, &path, &mut added);
2293 true
2294 } else {
2295 false
2296 }
2297 } else {
2298 false
2299 };
2300 let Some(replacement) = added.first().map(|event| event.device) else {
2301 return -1;
2302 };
2303 if !replaced || replacement.is_null() {
2304 return -1;
2305 }
2306 (*ctx).devices.retain(|candidate| *candidate != dev);
2307 libinput_device_unref(dev);
2308 let old_seat = (*replacement).seat;
2309 if old_seat != new_seat {
2310 libinput_seat_ref(new_seat.cast());
2311 (*replacement).seat = new_seat;
2312 (*replacement).abi.seat = new_seat;
2313 libinput_seat_unref(old_seat.cast());
2314 }
2315 enqueue_events(ctx, removed);
2316 enqueue_events(ctx, added);
2317 (*ctx).signal_fd();
2318 0
2319}
2320
2321#[no_mangle]
2322pub unsafe extern "C" fn libinput_seat_get_physical_name(
2323 seat: *const libc::c_void,
2324) -> *const libc::c_char {
2325 if seat.is_null() {
2326 return std::ptr::null();
2327 }
2328 (*(seat as *const LibinputSeat)).physical_name.as_ptr()
2329}
2330
2331#[no_mangle]
2332pub unsafe extern "C" fn libinput_seat_get_logical_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)).logical_name.as_ptr()
2339}
2340
2341#[no_mangle]
2342pub unsafe extern "C" fn libinput_seat_get_context(
2343 seat: *const libc::c_void,
2344) -> *mut LibinputContext {
2345 if seat.is_null() {
2346 return std::ptr::null_mut();
2347 }
2348 (*(seat as *const LibinputSeat)).context
2349}
2350
2351#[no_mangle]
2352pub unsafe extern "C" fn libinput_seat_ref(seat: *mut libc::c_void) -> *mut libc::c_void {
2353 if !seat.is_null() {
2354 (*(seat as *mut LibinputSeat))
2355 .refcount
2356 .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
2357 }
2358 seat
2359}
2360
2361#[no_mangle]
2362pub unsafe extern "C" fn libinput_seat_unref(seat: *mut libc::c_void) -> *mut libc::c_void {
2363 if seat.is_null() {
2364 return std::ptr::null_mut();
2365 }
2366 let seat = seat as *mut LibinputSeat;
2367 if (*seat)
2368 .refcount
2369 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
2370 == 1
2371 {
2372 drop(Box::from_raw(seat));
2373 std::ptr::null_mut()
2374 } else {
2375 seat.cast()
2376 }
2377}
2378
2379#[no_mangle]
2380pub unsafe extern "C" fn libinput_seat_set_user_data(
2381 seat: *mut libc::c_void,
2382 data: *mut libc::c_void,
2383) {
2384 if !seat.is_null() {
2385 (*(seat as *mut LibinputSeat)).user_data = data;
2386 }
2387}
2388
2389#[no_mangle]
2390pub unsafe extern "C" fn libinput_seat_get_user_data(
2391 seat: *const libc::c_void,
2392) -> *mut libc::c_void {
2393 if seat.is_null() {
2394 return std::ptr::null_mut();
2395 }
2396 (*(seat as *const LibinputSeat)).user_data
2397}
2398
2399#[no_mangle]
2404pub unsafe extern "C" fn libinput_config_status_to_str(status: u32) -> *const libc::c_char {
2405 match status {
2406 0 => b"success\0".as_ptr().cast(),
2407 1 => b"unsupported\0".as_ptr().cast(),
2408 2 => b"invalid\0".as_ptr().cast(),
2409 _ => std::ptr::null(),
2410 }
2411}
2412
2413#[no_mangle]
2418pub unsafe extern "C" fn libinput_log_set_priority(ctx: *mut LibinputContext, priority: u32) {
2419 if !ctx.is_null() {
2420 (*ctx).log_priority = priority;
2421 }
2422}
2423
2424#[no_mangle]
2425pub unsafe extern "C" fn libinput_log_get_priority(ctx: *const LibinputContext) -> u32 {
2426 if ctx.is_null() {
2427 return 30;
2428 }
2429 (*ctx).log_priority
2430}
2431
2432#[no_mangle]
2433pub unsafe extern "C" fn libinput_log_set_handler(
2434 ctx: *mut LibinputContext,
2435 handler: Option<
2436 unsafe extern "C" fn(
2437 ctx: *mut LibinputContext,
2438 priority: u32,
2439 format: *const libc::c_char,
2440 args: *mut libc::c_void,
2441 ),
2442 >,
2443) {
2444 if ctx.is_null() {
2445 return;
2446 }
2447 (*ctx).log_handler = handler;
2448}
2449
2450#[no_mangle]
2455pub unsafe extern "C" fn libinput_set_user_data(
2456 ctx: *mut LibinputContext,
2457 data: *mut libc::c_void,
2458) {
2459 if ctx.is_null() {
2460 return;
2461 }
2462 (*ctx).user_data = data;
2463}
2464
2465#[no_mangle]
2466pub unsafe extern "C" fn libinput_get_user_data(ctx: *const LibinputContext) -> *mut libc::c_void {
2467 if ctx.is_null() {
2468 return std::ptr::null_mut();
2469 }
2470 (*ctx).user_data
2471}
2472
2473#[no_mangle]
2474pub unsafe extern "C" fn libinput_device_set_user_data(
2475 dev: *mut LibinputDevice,
2476 data: *mut libc::c_void,
2477) {
2478 if dev.is_null() {
2479 return;
2480 }
2481 (*dev).user_data = data;
2482 (*dev).abi.user_data = data;
2483}
2484
2485#[no_mangle]
2486pub unsafe extern "C" fn libinput_device_get_user_data(
2487 dev: *const LibinputDevice,
2488) -> *mut libc::c_void {
2489 if dev.is_null() {
2490 return std::ptr::null_mut();
2491 }
2492 (*dev).user_data
2493}
2494
2495#[no_mangle]
2500pub unsafe extern "C" fn libinput_device_config_area_has_rectangle(
2501 dev: *const LibinputDevice,
2502) -> libc::c_int {
2503 if dev.is_null() {
2504 return 0;
2505 }
2506 (*dev).area_available as libc::c_int
2507}
2508
2509#[no_mangle]
2510pub unsafe extern "C" fn libinput_device_config_area_set_rectangle(
2511 dev: *mut LibinputDevice,
2512 rectangle: *const LibinputConfigAreaRectangle,
2513) -> u32 {
2514 if dev.is_null() || !(*dev).area_available {
2515 return 1;
2516 }
2517 if rectangle.is_null() {
2518 return 2;
2519 }
2520 let rectangle = &*rectangle;
2521 if rectangle.x1 >= rectangle.x2
2522 || rectangle.y1 >= rectangle.y2
2523 || rectangle.x1 < 0.0
2524 || rectangle.x2 > 1.0
2525 || rectangle.y1 < 0.0
2526 || rectangle.y2 > 1.0
2527 {
2528 return 2;
2529 }
2530 (*dev).wanted_area = [rectangle.x1, rectangle.y1, rectangle.x2, rectangle.y2];
2531 if !(*dev).tablet_in_proximity {
2532 (*dev).area = (*dev).wanted_area;
2533 }
2534 0
2535}
2536
2537#[no_mangle]
2538pub unsafe extern "C" fn libinput_device_config_area_get_rectangle(
2539 dev: *const LibinputDevice,
2540) -> LibinputConfigAreaRectangle {
2541 let area = if dev.is_null() || !(*dev).area_available {
2542 [0.0, 0.0, 1.0, 1.0]
2543 } else {
2544 (*dev).area
2545 };
2546 LibinputConfigAreaRectangle {
2547 x1: area[0],
2548 y1: area[1],
2549 x2: area[2],
2550 y2: area[3],
2551 }
2552}
2553
2554#[no_mangle]
2555pub unsafe extern "C" fn libinput_device_config_area_get_default_rectangle(
2556 _dev: *const LibinputDevice,
2557) -> LibinputConfigAreaRectangle {
2558 LibinputConfigAreaRectangle {
2559 x1: 0.0,
2560 y1: 0.0,
2561 x2: 1.0,
2562 y2: 1.0,
2563 }
2564}
2565
2566#[no_mangle]
2567pub unsafe extern "C" fn libinput_device_config_rotation_is_available(
2568 dev: *const LibinputDevice,
2569) -> libc::c_int {
2570 if dev.is_null() {
2571 return 0;
2572 }
2573 (*dev).rotation_available as libc::c_int
2574}
2575
2576#[no_mangle]
2577pub unsafe extern "C" fn libinput_device_config_rotation_set_angle(
2578 dev: *mut LibinputDevice,
2579 degrees_cw: u32,
2580) -> u32 {
2581 if dev.is_null() {
2582 return 1;
2583 }
2584 if degrees_cw >= 360 {
2585 return 2;
2586 }
2587 if !(*dev).rotation_available && degrees_cw != 0 {
2588 return 1;
2589 }
2590 (*dev).rotation_angle = degrees_cw;
2591 0
2592}
2593
2594#[no_mangle]
2595pub unsafe extern "C" fn libinput_device_config_rotation_get_angle(
2596 dev: *const LibinputDevice,
2597) -> u32 {
2598 if dev.is_null() {
2599 0
2600 } else {
2601 (*dev).rotation_angle
2602 }
2603}
2604
2605#[no_mangle]
2606pub unsafe extern "C" fn libinput_device_config_rotation_get_default_angle(
2607 _dev: *const LibinputDevice,
2608) -> u32 {
2609 0
2610}
2611
2612#[no_mangle]
2613pub unsafe extern "C" fn libinput_device_config_scroll_get_default_button(
2614 dev: *const LibinputDevice,
2615) -> u32 {
2616 if dev.is_null() || !(*dev).supports_button_scroll {
2617 0
2618 } else {
2619 (*dev).scroll_default_button
2620 }
2621}
2622
2623#[no_mangle]
2624pub unsafe extern "C" fn libinput_device_config_send_events_get_modes(
2625 dev: *const LibinputDevice,
2626) -> u32 {
2627 if dev.is_null() {
2628 return 0;
2629 }
2630 (*dev).send_events_modes
2631}
2632
2633#[no_mangle]
2634pub unsafe extern "C" fn libinput_device_config_send_events_set_mode(
2635 dev: *mut LibinputDevice,
2636 mode: u32,
2637) -> u32 {
2638 if dev.is_null() {
2639 return 1;
2640 }
2641 let supported = (*dev).send_events_modes;
2642 if mode & !supported != 0 {
2643 return 1;
2644 }
2645 let previous = (*dev).send_events_mode;
2646 let next = if mode & 1 != 0 { 1 } else { mode };
2647 (*dev).send_events_mode = next;
2648 if previous != next && matches!(next, 1 | 2) {
2649 let ctx = (*dev).context;
2650 if !ctx.is_null() {
2651 let mut events = std::collections::VecDeque::new();
2652 if let Ok(mut backend) = (*ctx).backend.lock() {
2653 if next == 1 || backend.has_external_mouse() {
2654 backend.release_active_inputs(ctx, dev, &mut events);
2655 }
2656 }
2657 enqueue_events(ctx, events);
2658 }
2659 }
2660 0
2661}
2662
2663#[no_mangle]
2664pub unsafe extern "C" fn libinput_device_config_send_events_get_mode(
2665 dev: *const LibinputDevice,
2666) -> u32 {
2667 if dev.is_null() {
2668 return 0;
2669 }
2670 (*dev).send_events_mode
2671}
2672
2673#[no_mangle]
2674pub unsafe extern "C" fn libinput_device_config_send_events_get_default_mode(
2675 _dev: *const LibinputDevice,
2676) -> u32 {
2677 0
2678}
2679
2680#[no_mangle]
2681pub unsafe extern "C" fn libinput_device_config_tap_get_default_drag_lock_enabled(
2682 _dev: *const LibinputDevice,
2683) -> u32 {
2684 0
2685}
2686
2687#[no_mangle]
2688pub unsafe extern "C" fn libinput_device_get_device_group(
2689 dev: *const LibinputDevice,
2690) -> *mut libc::c_void {
2691 if dev.is_null() {
2692 return std::ptr::null_mut();
2693 }
2694 (*dev).group.cast()
2695}
2696
2697#[no_mangle]
2698pub unsafe extern "C" fn libinput_device_group_ref(group: *mut libc::c_void) -> *mut libc::c_void {
2699 if group.is_null() {
2700 return std::ptr::null_mut();
2701 }
2702 let group = group.cast::<LibinputDeviceGroup>();
2703 (*group)
2704 .refcount
2705 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2706 group.cast()
2707}
2708
2709#[no_mangle]
2710pub unsafe extern "C" fn libinput_device_group_unref(
2711 group: *mut libc::c_void,
2712) -> *mut libc::c_void {
2713 if group.is_null() {
2714 return std::ptr::null_mut();
2715 }
2716 let group = group.cast::<LibinputDeviceGroup>();
2717 if (*group)
2718 .refcount
2719 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
2720 == 1
2721 {
2722 drop(Box::from_raw(group));
2723 std::ptr::null_mut()
2724 } else {
2725 group.cast()
2726 }
2727}
2728
2729#[no_mangle]
2730pub unsafe extern "C" fn libinput_device_group_set_user_data(
2731 group: *mut libc::c_void,
2732 data: *mut libc::c_void,
2733) {
2734 if !group.is_null() {
2735 (*group.cast::<LibinputDeviceGroup>()).user_data = data;
2736 }
2737}
2738
2739#[no_mangle]
2740pub unsafe extern "C" fn libinput_device_group_get_user_data(
2741 group: *const libc::c_void,
2742) -> *mut libc::c_void {
2743 if group.is_null() {
2744 return std::ptr::null_mut();
2745 }
2746 (*group.cast::<LibinputDeviceGroup>()).user_data
2747}
2748
2749#[no_mangle]
2750pub unsafe extern "C" fn libinput_device_get_id_bustype(dev: *const LibinputDevice) -> u32 {
2751 if dev.is_null() {
2752 return 0;
2753 }
2754 (*dev).bus_type
2755}
2756
2757#[no_mangle]
2758pub unsafe extern "C" fn libinput_device_get_size(
2759 dev: *const LibinputDevice,
2760 width: *mut f64,
2761 height: *mut f64,
2762) -> libc::c_int {
2763 if dev.is_null() || width.is_null() || height.is_null() {
2764 return 0;
2765 }
2766 match ((*dev).width_mm, (*dev).height_mm) {
2767 (Some(w), Some(h)) => {
2768 *width = w;
2769 *height = h;
2770 0
2771 }
2772 _ => -1,
2773 }
2774}
2775
2776#[no_mangle]
2777pub unsafe extern "C" fn libinput_device_get_udev_device(
2778 dev: *const LibinputDevice,
2779) -> *mut libc::c_void {
2780 if dev.is_null() || (*dev).udev_device.is_null() {
2781 return std::ptr::null_mut();
2782 }
2783 udev::udev_device_ref((*dev).udev_device)
2784}
2785
2786#[no_mangle]
2787pub unsafe extern "C" fn libinput_device_keyboard_has_key(
2788 dev: *const LibinputDevice,
2789 key: u32,
2790) -> libc::c_int {
2791 if dev.is_null() || !(*dev).has_keyboard {
2792 return -1;
2793 }
2794 if key > u16::MAX as u32 {
2795 return 0;
2796 }
2797 (*dev).event_codes.contains(&(key as u16)) as libc::c_int
2798}
2799
2800#[no_mangle]
2801pub unsafe extern "C" fn libinput_device_led_update(dev: *mut LibinputDevice, leds: u32) {
2802 if dev.is_null() || (*dev).context.is_null() {
2803 return;
2804 }
2805 let ctx = (*dev).context;
2806 if let Ok(mut backend) = (*ctx).backend.lock() {
2807 backend.update_leds(dev, leds);
2808 }
2809}
2810
2811#[no_mangle]
2812pub unsafe extern "C" fn libinput_device_pointer_has_button(
2813 dev: *const LibinputDevice,
2814 button: u32,
2815) -> libc::c_int {
2816 if dev.is_null() || button > u16::MAX as u32 {
2817 return 0;
2818 }
2819 if !(*dev).has_pointer {
2820 return -1;
2821 }
2822 (*dev).event_codes.contains(&(button as u16)) as libc::c_int
2823}
2824
2825#[no_mangle]
2826pub unsafe extern "C" fn libinput_device_switch_has_switch(
2827 dev: *const LibinputDevice,
2828 sw: u32,
2829) -> libc::c_int {
2830 if dev.is_null() {
2831 return 0;
2832 }
2833 if !(*dev).has_switch {
2834 return 0;
2835 }
2836 let kernel_code = match sw {
2837 1 => 0,
2838 2 => 1,
2839 3 => 10,
2840 _ => return 0,
2841 };
2842 (*dev).switch_codes.contains(&kernel_code) as libc::c_int
2843}
2844
2845#[no_mangle]
2846pub unsafe extern "C" fn libinput_device_tablet_pad_get_mode_group(
2847 dev: *const LibinputDevice,
2848 index: u32,
2849) -> *mut libc::c_void {
2850 if dev.is_null() || !(*dev).has_tablet_pad {
2851 return std::ptr::null_mut();
2852 }
2853 (*dev)
2854 .tablet_pad_mode_groups
2855 .iter()
2856 .copied()
2857 .find(|group| !group.is_null() && (**group).index == index)
2858 .unwrap_or(std::ptr::null_mut())
2859 .cast()
2860}
2861
2862#[no_mangle]
2863pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_buttons(
2864 dev: *const LibinputDevice,
2865) -> u32 {
2866 if dev.is_null() || !(*dev).has_tablet_pad {
2867 return u32::MAX;
2868 }
2869 (*dev).tablet_pad_button_codes.len() as u32
2870}
2871
2872#[no_mangle]
2873pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_dials(
2874 dev: *const LibinputDevice,
2875) -> u32 {
2876 if dev.is_null() || !(*dev).has_tablet_pad {
2877 return u32::MAX;
2878 }
2879 (*dev).tablet_pad_num_dials
2880}
2881
2882#[no_mangle]
2883pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_mode_groups(
2884 dev: *const LibinputDevice,
2885) -> u32 {
2886 if dev.is_null() || !(*dev).has_tablet_pad {
2887 return u32::MAX;
2888 }
2889 (*dev).tablet_pad_mode_groups.len() as u32
2890}
2891
2892#[no_mangle]
2893pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_rings(
2894 dev: *const LibinputDevice,
2895) -> u32 {
2896 if dev.is_null() || !(*dev).has_tablet_pad {
2897 return u32::MAX;
2898 }
2899 (*dev).tablet_pad_num_rings
2900}
2901
2902#[no_mangle]
2903pub unsafe extern "C" fn libinput_device_tablet_pad_get_num_strips(
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_strips
2910}
2911
2912#[no_mangle]
2913pub unsafe extern "C" fn libinput_device_tablet_pad_has_key(
2914 dev: *const LibinputDevice,
2915 code: u32,
2916) -> libc::c_int {
2917 if dev.is_null() || !(*dev).has_tablet_pad {
2918 return -1;
2919 }
2920 (code <= u16::MAX as u32 && (*dev).event_codes.contains(&(code as u16))) as libc::c_int
2921}
2922
2923#[no_mangle]
2924pub unsafe extern "C" fn libinput_event_get_tablet_pad_event(
2925 event: *mut LibinputEvent,
2926) -> *mut LibinputEvent {
2927 if event.is_null() {
2928 return std::ptr::null_mut();
2929 }
2930 match (*event).event_type {
2931 LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_BUTTON
2932 | LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_RING
2933 | LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_STRIP
2934 | LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_KEY
2935 | LibinputEventType::LIBINPUT_EVENT_TABLET_PAD_DIAL => event,
2936 _ => std::ptr::null_mut(),
2937 }
2938}
2939
2940#[no_mangle]
2941pub unsafe extern "C" fn libinput_event_tablet_pad_get_base_event(
2942 event: *mut LibinputEvent,
2943) -> *mut LibinputEvent {
2944 event
2945}
2946
2947#[no_mangle]
2948pub unsafe extern "C" fn libinput_event_get_tablet_tool_event(
2949 event: *mut LibinputEvent,
2950) -> *mut LibinputEvent {
2951 if event.is_null() {
2952 return std::ptr::null_mut();
2953 }
2954 match (*event).event_type {
2955 LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_AXIS
2956 | LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY
2957 | LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_TIP
2958 | LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_BUTTON => event,
2959 _ => std::ptr::null_mut(),
2960 }
2961}
2962
2963#[no_mangle]
2964pub unsafe extern "C" fn libinput_event_tablet_tool_get_base_event(
2965 event: *mut LibinputEvent,
2966) -> *mut LibinputEvent {
2967 event
2968}
2969
2970#[no_mangle]
2971pub unsafe extern "C" fn libinput_event_pointer_get_absolute_x_transformed(
2972 event: *const LibinputEvent,
2973 width: u32,
2974) -> f64 {
2975 if event.is_null() {
2976 return 0.0;
2977 }
2978 if let EventPayload::PointerMotionAbsolute(e) = &(*event).payload {
2979 let range = e.x_max - e.x_min;
2980 if range > 0.0 {
2981 (e.abs_x - e.x_min) * f64::from(width) / range
2982 } else {
2983 0.0
2984 }
2985 } else {
2986 0.0
2987 }
2988}
2989
2990#[no_mangle]
2991pub unsafe extern "C" fn libinput_event_pointer_get_absolute_y_transformed(
2992 event: *const LibinputEvent,
2993 height: u32,
2994) -> f64 {
2995 if event.is_null() {
2996 return 0.0;
2997 }
2998 if let EventPayload::PointerMotionAbsolute(e) = &(*event).payload {
2999 let range = e.y_max - e.y_min;
3000 if range > 0.0 {
3001 (e.abs_y - e.y_min) * f64::from(height) / range
3002 } else {
3003 0.0
3004 }
3005 } else {
3006 0.0
3007 }
3008}
3009
3010#[no_mangle]
3011pub unsafe extern "C" fn libinput_event_pointer_get_scroll_value(
3012 event: *const LibinputEvent,
3013 axis: u32,
3014) -> f64 {
3015 libinput_event_pointer_get_axis_value(event, axis)
3016}
3017
3018#[no_mangle]
3019pub unsafe extern "C" fn libinput_event_pointer_get_scroll_value_v120(
3020 event: *const LibinputEvent,
3021 axis: u32,
3022) -> f64 {
3023 if event.is_null() {
3024 return 0.0;
3025 }
3026 if let EventPayload::PointerAxis(e) = &(*event).payload {
3027 return e.value_v120(axis);
3028 }
3029 0.0
3030}
3031
3032#[no_mangle]
3033pub unsafe extern "C" fn libinput_event_switch_get_time_usec(event: *const LibinputEvent) -> u64 {
3034 if event.is_null() {
3035 return 0;
3036 }
3037 if let EventPayload::SwitchToggle(e) = &(*event).payload {
3038 e.time_usec
3039 } else {
3040 0
3041 }
3042}
3043
3044#[no_mangle]
3045pub unsafe extern "C" fn libinput_event_switch_get_time(event: *const LibinputEvent) -> u32 {
3046 (libinput_event_switch_get_time_usec(event) / 1000) as u32
3047}
3048
3049#[no_mangle]
3050pub unsafe extern "C" fn libinput_event_tablet_pad_get_button_number(
3051 event: *const LibinputEvent,
3052) -> u32 {
3053 if event.is_null() {
3054 return 0;
3055 }
3056 match &(*event).payload {
3057 EventPayload::TabletPad(pad) => pad.button,
3058 _ => 0,
3059 }
3060}
3061
3062#[no_mangle]
3063pub unsafe extern "C" fn libinput_event_tablet_pad_get_button_state(
3064 event: *const LibinputEvent,
3065) -> u32 {
3066 if event.is_null() {
3067 return 0;
3068 }
3069 match &(*event).payload {
3070 EventPayload::TabletPad(pad) => pad.button_state,
3071 _ => 0,
3072 }
3073}
3074
3075#[no_mangle]
3076pub unsafe extern "C" fn libinput_event_tablet_pad_get_key(event: *const LibinputEvent) -> u32 {
3077 if event.is_null() {
3078 return 0;
3079 }
3080 match &(*event).payload {
3081 EventPayload::TabletPad(pad) => pad.key,
3082 _ => 0,
3083 }
3084}
3085
3086#[no_mangle]
3087pub unsafe extern "C" fn libinput_event_tablet_pad_get_key_state(
3088 event: *const LibinputEvent,
3089) -> u32 {
3090 if event.is_null() {
3091 return 0;
3092 }
3093 match &(*event).payload {
3094 EventPayload::TabletPad(pad) => pad.key_state,
3095 _ => 0,
3096 }
3097}
3098
3099#[no_mangle]
3100pub unsafe extern "C" fn libinput_event_tablet_pad_get_dial_delta_v120(
3101 event: *const LibinputEvent,
3102) -> f64 {
3103 if event.is_null() {
3104 return 0.0;
3105 }
3106 match &(*event).payload {
3107 EventPayload::TabletPad(pad) => pad.dial_delta_v120,
3108 _ => 0.0,
3109 }
3110}
3111
3112#[no_mangle]
3113pub unsafe extern "C" fn libinput_event_tablet_pad_get_dial_number(
3114 event: *const LibinputEvent,
3115) -> u32 {
3116 if event.is_null() {
3117 return 0;
3118 }
3119 match &(*event).payload {
3120 EventPayload::TabletPad(pad) => pad.dial_number,
3121 _ => 0,
3122 }
3123}
3124
3125#[no_mangle]
3126pub unsafe extern "C" fn libinput_event_tablet_pad_get_mode(event: *const LibinputEvent) -> u32 {
3127 if event.is_null() {
3128 return 0;
3129 }
3130 match &(*event).payload {
3131 EventPayload::TabletPad(pad) => pad.mode,
3132 _ => 0,
3133 }
3134}
3135
3136#[no_mangle]
3137pub unsafe extern "C" fn libinput_event_tablet_pad_get_mode_group(
3138 event: *const LibinputEvent,
3139) -> *mut libc::c_void {
3140 if event.is_null() {
3141 return std::ptr::null_mut();
3142 }
3143 match &(*event).payload {
3144 EventPayload::TabletPad(pad) => pad.mode_group.cast(),
3145 _ => std::ptr::null_mut(),
3146 }
3147}
3148
3149#[no_mangle]
3150pub unsafe extern "C" fn libinput_event_tablet_pad_get_ring_number(
3151 event: *const LibinputEvent,
3152) -> u32 {
3153 if event.is_null() {
3154 return 0;
3155 }
3156 match &(*event).payload {
3157 EventPayload::TabletPad(pad) => pad.ring_number,
3158 _ => 0,
3159 }
3160}
3161
3162#[no_mangle]
3163pub unsafe extern "C" fn libinput_event_tablet_pad_get_ring_position(
3164 event: *const LibinputEvent,
3165) -> f64 {
3166 if event.is_null() {
3167 return 0.0;
3168 }
3169 match &(*event).payload {
3170 EventPayload::TabletPad(pad) => pad.ring_position,
3171 _ => 0.0,
3172 }
3173}
3174
3175#[no_mangle]
3176pub unsafe extern "C" fn libinput_event_tablet_pad_get_ring_source(
3177 event: *const LibinputEvent,
3178) -> u32 {
3179 if event.is_null() {
3180 return 0;
3181 }
3182 match &(*event).payload {
3183 EventPayload::TabletPad(pad) => pad.ring_source,
3184 _ => 0,
3185 }
3186}
3187
3188#[no_mangle]
3189pub unsafe extern "C" fn libinput_event_tablet_pad_get_strip_number(
3190 event: *const LibinputEvent,
3191) -> u32 {
3192 if event.is_null() {
3193 return 0;
3194 }
3195 match &(*event).payload {
3196 EventPayload::TabletPad(pad) => pad.strip_number,
3197 _ => 0,
3198 }
3199}
3200
3201#[no_mangle]
3202pub unsafe extern "C" fn libinput_event_tablet_pad_get_strip_position(
3203 event: *const LibinputEvent,
3204) -> f64 {
3205 if event.is_null() {
3206 return 0.0;
3207 }
3208 match &(*event).payload {
3209 EventPayload::TabletPad(pad) => pad.strip_position,
3210 _ => 0.0,
3211 }
3212}
3213
3214#[no_mangle]
3215pub unsafe extern "C" fn libinput_event_tablet_pad_get_strip_source(
3216 event: *const LibinputEvent,
3217) -> u32 {
3218 if event.is_null() {
3219 return 0;
3220 }
3221 match &(*event).payload {
3222 EventPayload::TabletPad(pad) => pad.strip_source,
3223 _ => 0,
3224 }
3225}
3226
3227#[no_mangle]
3228pub unsafe extern "C" fn libinput_event_tablet_pad_get_time_usec(
3229 event: *const LibinputEvent,
3230) -> u64 {
3231 if event.is_null() {
3232 return 0;
3233 }
3234 match &(*event).payload {
3235 EventPayload::TabletPad(pad) => pad.time_usec,
3236 _ => 0,
3237 }
3238}
3239
3240#[no_mangle]
3241pub unsafe extern "C" fn libinput_event_tablet_pad_get_time(event: *const LibinputEvent) -> u32 {
3242 (libinput_event_tablet_pad_get_time_usec(event) / 1000) as u32
3243}
3244
3245#[no_mangle]
3246pub unsafe extern "C" fn libinput_event_tablet_tool_get_button(event: *const LibinputEvent) -> u32 {
3247 if event.is_null() {
3248 return 0;
3249 }
3250 match &(*event).payload {
3251 EventPayload::TabletTool(tablet) => tablet.button,
3252 _ => 0,
3253 }
3254}
3255
3256#[no_mangle]
3257pub unsafe extern "C" fn libinput_event_tablet_tool_get_button_state(
3258 event: *const LibinputEvent,
3259) -> u32 {
3260 if event.is_null() {
3261 return 0;
3262 }
3263 match &(*event).payload {
3264 EventPayload::TabletTool(tablet) => tablet.button_state,
3265 _ => 0,
3266 }
3267}
3268
3269#[no_mangle]
3270pub unsafe extern "C" fn libinput_event_tablet_tool_get_seat_button_count(
3271 event: *const LibinputEvent,
3272) -> u32 {
3273 if event.is_null() {
3274 return 0;
3275 }
3276 match &(*event).payload {
3277 EventPayload::TabletTool(tablet) => tablet.seat_button_count,
3278 _ => 0,
3279 }
3280}
3281
3282#[no_mangle]
3283pub unsafe extern "C" fn libinput_event_tablet_tool_get_distance(
3284 event: *const LibinputEvent,
3285) -> f64 {
3286 if event.is_null() {
3287 return 0.0;
3288 }
3289 match &(*event).payload {
3290 EventPayload::TabletTool(tablet) => tablet.distance,
3291 _ => 0.0,
3292 }
3293}
3294
3295#[no_mangle]
3296pub unsafe extern "C" fn libinput_event_tablet_tool_get_dx(event: *const LibinputEvent) -> f64 {
3297 if event.is_null() || (*event).event_type != LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_AXIS
3298 {
3299 return 0.0;
3300 }
3301 match &(*event).payload {
3302 EventPayload::TabletTool(tablet) => tablet.dx,
3303 _ => 0.0,
3304 }
3305}
3306
3307#[no_mangle]
3308pub unsafe extern "C" fn libinput_event_tablet_tool_get_dy(event: *const LibinputEvent) -> f64 {
3309 if event.is_null() || (*event).event_type != LibinputEventType::LIBINPUT_EVENT_TABLET_TOOL_AXIS
3310 {
3311 return 0.0;
3312 }
3313 match &(*event).payload {
3314 EventPayload::TabletTool(tablet) => tablet.dy,
3315 _ => 0.0,
3316 }
3317}
3318
3319#[no_mangle]
3320pub unsafe extern "C" fn libinput_event_tablet_tool_get_pressure(
3321 event: *const LibinputEvent,
3322) -> f64 {
3323 if event.is_null() {
3324 return 0.0;
3325 }
3326 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3327 let range = tablet.pressure_max - tablet.pressure_min;
3328 if range > 0.0 {
3329 ((tablet.pressure - tablet.pressure_min) / range).clamp(0.0, 1.0)
3330 } else {
3331 0.0
3332 }
3333 } else {
3334 0.0
3335 }
3336}
3337
3338#[no_mangle]
3339pub unsafe extern "C" fn libinput_event_tablet_tool_get_x(event: *const LibinputEvent) -> f64 {
3340 if event.is_null() {
3341 return 0.0;
3342 }
3343 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3344 if tablet.x_resolution > 0.0 {
3345 (tablet.x - tablet.x_min) / tablet.x_resolution
3346 } else {
3347 tablet.x - tablet.x_min
3348 }
3349 } else {
3350 0.0
3351 }
3352}
3353
3354#[no_mangle]
3355pub unsafe extern "C" fn libinput_event_tablet_tool_get_y(event: *const LibinputEvent) -> f64 {
3356 if event.is_null() {
3357 return 0.0;
3358 }
3359 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3360 if tablet.y_resolution > 0.0 {
3361 (tablet.y - tablet.y_min) / tablet.y_resolution
3362 } else {
3363 tablet.y - tablet.y_min
3364 }
3365 } else {
3366 0.0
3367 }
3368}
3369
3370#[no_mangle]
3371pub unsafe extern "C" fn libinput_event_tablet_tool_get_proximity_state(
3372 event: *const LibinputEvent,
3373) -> u32 {
3374 if event.is_null() {
3375 return 0;
3376 }
3377 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3378 tablet.proximity_state
3379 } else {
3380 0
3381 }
3382}
3383
3384#[no_mangle]
3385pub unsafe extern "C" fn libinput_event_tablet_tool_get_rotation(
3386 event: *const LibinputEvent,
3387) -> f64 {
3388 if event.is_null() {
3389 return 0.0;
3390 }
3391 match &(*event).payload {
3392 EventPayload::TabletTool(tablet) => tablet.rotation,
3393 _ => 0.0,
3394 }
3395}
3396
3397#[no_mangle]
3398pub unsafe extern "C" fn libinput_event_tablet_tool_get_slider_position(
3399 event: *const LibinputEvent,
3400) -> f64 {
3401 if event.is_null() {
3402 return 0.0;
3403 }
3404 match &(*event).payload {
3405 EventPayload::TabletTool(tablet) => tablet.slider,
3406 _ => 0.0,
3407 }
3408}
3409
3410#[no_mangle]
3411pub unsafe extern "C" fn libinput_event_tablet_tool_get_wheel_delta(
3412 event: *const LibinputEvent,
3413) -> f64 {
3414 if event.is_null() {
3415 return 0.0;
3416 }
3417 match &(*event).payload {
3418 EventPayload::TabletTool(tablet) => tablet.wheel_delta,
3419 _ => 0.0,
3420 }
3421}
3422
3423#[no_mangle]
3424pub unsafe extern "C" fn libinput_event_tablet_tool_get_wheel_delta_discrete(
3425 event: *const LibinputEvent,
3426) -> i32 {
3427 if event.is_null() {
3428 return 0;
3429 }
3430 match &(*event).payload {
3431 EventPayload::TabletTool(tablet) => tablet.wheel_discrete,
3432 _ => 0,
3433 }
3434}
3435
3436#[no_mangle]
3437pub unsafe extern "C" fn libinput_event_tablet_tool_get_size_major(
3438 event: *const LibinputEvent,
3439) -> f64 {
3440 if event.is_null() {
3441 return 0.0;
3442 }
3443 match &(*event).payload {
3444 EventPayload::TabletTool(tablet) => tablet.size_major,
3445 _ => 0.0,
3446 }
3447}
3448
3449#[no_mangle]
3450pub unsafe extern "C" fn libinput_event_tablet_tool_get_size_minor(
3451 event: *const LibinputEvent,
3452) -> f64 {
3453 if event.is_null() {
3454 return 0.0;
3455 }
3456 match &(*event).payload {
3457 EventPayload::TabletTool(tablet) => tablet.size_minor,
3458 _ => 0.0,
3459 }
3460}
3461
3462#[no_mangle]
3463pub unsafe extern "C" fn libinput_event_tablet_tool_get_tilt_x(event: *const LibinputEvent) -> f64 {
3464 if event.is_null() {
3465 return 0.0;
3466 }
3467 match &(*event).payload {
3468 EventPayload::TabletTool(tablet) => tablet.tilt_x,
3469 _ => 0.0,
3470 }
3471}
3472
3473#[no_mangle]
3474pub unsafe extern "C" fn libinput_event_tablet_tool_get_tilt_y(event: *const LibinputEvent) -> f64 {
3475 if event.is_null() {
3476 return 0.0;
3477 }
3478 match &(*event).payload {
3479 EventPayload::TabletTool(tablet) => tablet.tilt_y,
3480 _ => 0.0,
3481 }
3482}
3483
3484#[no_mangle]
3485pub unsafe extern "C" fn libinput_event_tablet_tool_get_time_usec(
3486 event: *const LibinputEvent,
3487) -> u64 {
3488 if event.is_null() {
3489 return 0;
3490 }
3491 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3492 tablet.time_usec
3493 } else {
3494 0
3495 }
3496}
3497
3498#[no_mangle]
3499pub unsafe extern "C" fn libinput_event_tablet_tool_get_time(event: *const LibinputEvent) -> u32 {
3500 (libinput_event_tablet_tool_get_time_usec(event) / 1000) as u32
3501}
3502
3503#[no_mangle]
3504pub unsafe extern "C" fn libinput_event_tablet_tool_get_tip_state(
3505 event: *const LibinputEvent,
3506) -> u32 {
3507 if event.is_null() {
3508 return 0;
3509 }
3510 match &(*event).payload {
3511 EventPayload::TabletTool(tablet) => tablet.tip_state,
3512 _ => 0,
3513 }
3514}
3515
3516#[no_mangle]
3517pub unsafe extern "C" fn libinput_event_tablet_tool_get_tool(
3518 event: *const LibinputEvent,
3519) -> *mut libc::c_void {
3520 if event.is_null() {
3521 return std::ptr::null_mut();
3522 }
3523 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3524 tablet.tool.cast()
3525 } else {
3526 std::ptr::null_mut()
3527 }
3528}
3529
3530#[no_mangle]
3531pub unsafe extern "C" fn libinput_event_tablet_tool_get_x_transformed(
3532 event: *const LibinputEvent,
3533 width: u32,
3534) -> f64 {
3535 if event.is_null() {
3536 return 0.0;
3537 }
3538 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3539 let range = tablet.x_max - tablet.x_min + 1.0;
3540 if range > 0.0 {
3541 (tablet.x - tablet.x_min) * f64::from(width) / range
3542 } else {
3543 0.0
3544 }
3545 } else {
3546 0.0
3547 }
3548}
3549
3550#[no_mangle]
3551pub unsafe extern "C" fn libinput_event_tablet_tool_get_y_transformed(
3552 event: *const LibinputEvent,
3553 height: u32,
3554) -> f64 {
3555 if event.is_null() {
3556 return 0.0;
3557 }
3558 if let EventPayload::TabletTool(tablet) = &(*event).payload {
3559 let range = tablet.y_max - tablet.y_min + 1.0;
3560 if range > 0.0 {
3561 (tablet.y - tablet.y_min) * f64::from(height) / range
3562 } else {
3563 0.0
3564 }
3565 } else {
3566 0.0
3567 }
3568}
3569
3570#[no_mangle]
3571pub unsafe extern "C" fn libinput_event_tablet_tool_x_has_changed(
3572 event: *const LibinputEvent,
3573) -> libc::c_int {
3574 if event.is_null() {
3575 return 0;
3576 }
3577 match &(*event).payload {
3578 EventPayload::TabletTool(tablet) => tablet.x_changed as libc::c_int,
3579 _ => 0,
3580 }
3581}
3582
3583#[no_mangle]
3584pub unsafe extern "C" fn libinput_event_tablet_tool_y_has_changed(
3585 event: *const LibinputEvent,
3586) -> libc::c_int {
3587 if event.is_null() {
3588 return 0;
3589 }
3590 match &(*event).payload {
3591 EventPayload::TabletTool(tablet) => tablet.y_changed as libc::c_int,
3592 _ => 0,
3593 }
3594}
3595
3596#[no_mangle]
3597pub unsafe extern "C" fn libinput_event_tablet_tool_pressure_has_changed(
3598 event: *const LibinputEvent,
3599) -> libc::c_int {
3600 if event.is_null() {
3601 return 0;
3602 }
3603 match &(*event).payload {
3604 EventPayload::TabletTool(tablet) => tablet.pressure_changed as libc::c_int,
3605 _ => 0,
3606 }
3607}
3608
3609#[no_mangle]
3610pub unsafe extern "C" fn libinput_event_tablet_tool_distance_has_changed(
3611 event: *const LibinputEvent,
3612) -> libc::c_int {
3613 if event.is_null() {
3614 return 0;
3615 }
3616 match &(*event).payload {
3617 EventPayload::TabletTool(tablet) => tablet.distance_changed as libc::c_int,
3618 _ => 0,
3619 }
3620}
3621
3622#[no_mangle]
3623pub unsafe extern "C" fn libinput_event_tablet_tool_tilt_x_has_changed(
3624 event: *const LibinputEvent,
3625) -> libc::c_int {
3626 if event.is_null() {
3627 return 0;
3628 }
3629 match &(*event).payload {
3630 EventPayload::TabletTool(tablet) => tablet.tilt_x_changed as libc::c_int,
3631 _ => 0,
3632 }
3633}
3634
3635#[no_mangle]
3636pub unsafe extern "C" fn libinput_event_tablet_tool_tilt_y_has_changed(
3637 event: *const LibinputEvent,
3638) -> libc::c_int {
3639 if event.is_null() {
3640 return 0;
3641 }
3642 match &(*event).payload {
3643 EventPayload::TabletTool(tablet) => tablet.tilt_y_changed as libc::c_int,
3644 _ => 0,
3645 }
3646}
3647
3648#[no_mangle]
3649pub unsafe extern "C" fn libinput_event_tablet_tool_rotation_has_changed(
3650 event: *const LibinputEvent,
3651) -> libc::c_int {
3652 if event.is_null() {
3653 return 0;
3654 }
3655 match &(*event).payload {
3656 EventPayload::TabletTool(tablet) => tablet.rotation_changed as libc::c_int,
3657 _ => 0,
3658 }
3659}
3660
3661#[no_mangle]
3662pub unsafe extern "C" fn libinput_event_tablet_tool_slider_has_changed(
3663 event: *const LibinputEvent,
3664) -> libc::c_int {
3665 if event.is_null() {
3666 return 0;
3667 }
3668 match &(*event).payload {
3669 EventPayload::TabletTool(tablet) => tablet.slider_changed as libc::c_int,
3670 _ => 0,
3671 }
3672}
3673
3674#[no_mangle]
3675pub unsafe extern "C" fn libinput_event_tablet_tool_wheel_has_changed(
3676 event: *const LibinputEvent,
3677) -> libc::c_int {
3678 if event.is_null() {
3679 return 0;
3680 }
3681 match &(*event).payload {
3682 EventPayload::TabletTool(tablet) => tablet.wheel_changed as libc::c_int,
3683 _ => 0,
3684 }
3685}
3686
3687#[no_mangle]
3688pub unsafe extern "C" fn libinput_event_tablet_tool_size_major_has_changed(
3689 event: *const LibinputEvent,
3690) -> libc::c_int {
3691 if event.is_null() {
3692 return 0;
3693 }
3694 match &(*event).payload {
3695 EventPayload::TabletTool(tablet) => tablet.size_major_changed as libc::c_int,
3696 _ => 0,
3697 }
3698}
3699
3700#[no_mangle]
3701pub unsafe extern "C" fn libinput_event_tablet_tool_size_minor_has_changed(
3702 event: *const LibinputEvent,
3703) -> libc::c_int {
3704 if event.is_null() {
3705 return 0;
3706 }
3707 match &(*event).payload {
3708 EventPayload::TabletTool(tablet) => tablet.size_minor_changed as libc::c_int,
3709 _ => 0,
3710 }
3711}
3712
3713#[no_mangle]
3714pub unsafe extern "C" fn libinput_plugin_system_append_default_paths(ctx: *mut LibinputContext) {
3715 if ctx.is_null() || (*ctx).plugins_loaded {
3716 return;
3717 }
3718 for path in ["/etc/libinput/plugins", "/usr/lib64/libinput/plugins"] {
3719 let path = std::ffi::CString::new(path).expect("static plugin path");
3720 if !(*ctx)
3721 .plugin_paths
3722 .iter()
3723 .any(|candidate| candidate.as_bytes() == path.as_bytes())
3724 {
3725 (*ctx).plugin_paths.push(path);
3726 }
3727 }
3728}
3729
3730#[no_mangle]
3731pub unsafe extern "C" fn libinput_plugin_system_append_path(
3732 ctx: *mut LibinputContext,
3733 path: *const libc::c_char,
3734) {
3735 if ctx.is_null() || path.is_null() || (*ctx).plugins_loaded {
3736 return;
3737 }
3738 let path = CStr::from_ptr(path);
3739 if path.to_bytes().is_empty()
3740 || (*ctx)
3741 .plugin_paths
3742 .iter()
3743 .any(|candidate| candidate.as_bytes() == path.to_bytes())
3744 {
3745 return;
3746 }
3747 if let Ok(path) = std::ffi::CString::new(path.to_bytes()) {
3748 (*ctx).plugin_paths.push(path);
3749 }
3750}
3751
3752#[no_mangle]
3753pub unsafe extern "C" fn libinput_plugin_system_load_plugins(
3754 ctx: *mut LibinputContext,
3755 flags: libc::c_uint,
3756) -> libc::c_int {
3757 if ctx.is_null() || flags != 0 {
3758 return -libc::EINVAL;
3759 }
3760 if (*ctx).plugins_loaded {
3761 return 0;
3762 }
3763 (*ctx).plugins_loaded = true;
3767 -libc::ENOSYS
3768}
3769
3770#[no_mangle]
3771pub unsafe extern "C" fn libinput_tablet_pad_mode_group_button_is_toggle(
3772 group: *const libc::c_void,
3773 button: u32,
3774) -> libc::c_int {
3775 if group.is_null() || button >= u32::BITS {
3776 return 0;
3777 }
3778 ((*group.cast::<LibinputTabletPadModeGroup>()).toggle_button_mask & (1_u32 << button) != 0)
3779 as libc::c_int
3780}
3781
3782#[no_mangle]
3783pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_index(
3784 group: *const libc::c_void,
3785) -> u32 {
3786 if group.is_null() {
3787 return 0;
3788 }
3789 (*group.cast::<LibinputTabletPadModeGroup>()).index
3790}
3791
3792#[no_mangle]
3793pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_mode(
3794 group: *const libc::c_void,
3795) -> u32 {
3796 if group.is_null() {
3797 return 0;
3798 }
3799 (*group.cast::<LibinputTabletPadModeGroup>()).current_mode
3800}
3801
3802#[no_mangle]
3803pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_num_modes(
3804 group: *const libc::c_void,
3805) -> u32 {
3806 if group.is_null() {
3807 return 0;
3808 }
3809 (*group.cast::<LibinputTabletPadModeGroup>()).num_modes
3810}
3811
3812#[no_mangle]
3813pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_button(
3814 group: *const libc::c_void,
3815 button: u32,
3816) -> libc::c_int {
3817 if group.is_null() {
3818 return 0;
3819 }
3820 if button >= u32::BITS {
3821 return 0;
3822 }
3823 ((*group.cast::<LibinputTabletPadModeGroup>()).button_mask & (1_u32 << button) != 0)
3824 as libc::c_int
3825}
3826
3827#[no_mangle]
3828pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_dial(
3829 group: *const libc::c_void,
3830 dial: u32,
3831) -> libc::c_int {
3832 if group.is_null() {
3833 return 0;
3834 }
3835 if dial >= u32::BITS {
3836 return 0;
3837 }
3838 ((*group.cast::<LibinputTabletPadModeGroup>()).dial_mask & (1_u32 << dial) != 0) as libc::c_int
3839}
3840
3841#[no_mangle]
3842pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_ring(
3843 group: *const libc::c_void,
3844 ring: u32,
3845) -> libc::c_int {
3846 if group.is_null() {
3847 return 0;
3848 }
3849 if ring >= u32::BITS {
3850 return 0;
3851 }
3852 ((*group.cast::<LibinputTabletPadModeGroup>()).ring_mask & (1_u32 << ring) != 0) as libc::c_int
3853}
3854
3855#[no_mangle]
3856pub unsafe extern "C" fn libinput_tablet_pad_mode_group_has_strip(
3857 group: *const libc::c_void,
3858 strip: u32,
3859) -> libc::c_int {
3860 if group.is_null() {
3861 return 0;
3862 }
3863 if strip >= u32::BITS {
3864 return 0;
3865 }
3866 ((*group.cast::<LibinputTabletPadModeGroup>()).strip_mask & (1_u32 << strip) != 0)
3867 as libc::c_int
3868}
3869
3870#[no_mangle]
3871pub unsafe extern "C" fn libinput_tablet_pad_mode_group_ref(
3872 group: *mut libc::c_void,
3873) -> *mut libc::c_void {
3874 if !group.is_null() {
3875 (*group.cast::<LibinputTabletPadModeGroup>())
3876 .refcount
3877 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
3878 }
3879 group
3880}
3881
3882#[no_mangle]
3883pub unsafe extern "C" fn libinput_tablet_pad_mode_group_unref(
3884 group: *mut libc::c_void,
3885) -> *mut libc::c_void {
3886 if group.is_null() {
3887 return std::ptr::null_mut();
3888 }
3889 let group = group.cast::<LibinputTabletPadModeGroup>();
3890 if (*group)
3891 .refcount
3892 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
3893 == 1
3894 {
3895 drop(Box::from_raw(group));
3896 std::ptr::null_mut()
3897 } else {
3898 group.cast()
3899 }
3900}
3901
3902#[no_mangle]
3903pub unsafe extern "C" fn libinput_tablet_pad_mode_group_set_user_data(
3904 group: *mut libc::c_void,
3905 data: *mut libc::c_void,
3906) {
3907 if !group.is_null() {
3908 (*group.cast::<LibinputTabletPadModeGroup>()).user_data = data;
3909 }
3910}
3911
3912#[no_mangle]
3913pub unsafe extern "C" fn libinput_tablet_pad_mode_group_get_user_data(
3914 group: *const libc::c_void,
3915) -> *mut libc::c_void {
3916 if group.is_null() {
3917 return std::ptr::null_mut();
3918 }
3919 (*group.cast::<LibinputTabletPadModeGroup>()).user_data
3920}
3921
3922#[no_mangle]
3923pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_is_available(
3924 tool: *const LibinputTabletTool,
3925) -> libc::c_int {
3926 (!tool.is_null() && (*tool).has_pressure) as libc::c_int
3927}
3928
3929#[no_mangle]
3930pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_set(
3931 tool: *mut LibinputTabletTool,
3932 minimum: f64,
3933 maximum: f64,
3934) -> u32 {
3935 if tool.is_null() || !(*tool).has_pressure {
3936 return 1;
3937 }
3938 if minimum < 0.0 || maximum > 1.0 || minimum >= maximum {
3939 return 2;
3940 }
3941 (*tool).wanted_pressure_range_minimum = minimum;
3942 (*tool).wanted_pressure_range_maximum = maximum;
3943 0
3944}
3945
3946#[no_mangle]
3947pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_minimum(
3948 tool: *const LibinputTabletTool,
3949) -> f64 {
3950 if tool.is_null() {
3951 0.0
3952 } else {
3953 (*tool).wanted_pressure_range_minimum
3954 }
3955}
3956
3957#[no_mangle]
3958pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_maximum(
3959 tool: *const LibinputTabletTool,
3960) -> f64 {
3961 if tool.is_null() {
3962 1.0
3963 } else {
3964 (*tool).wanted_pressure_range_maximum
3965 }
3966}
3967
3968#[no_mangle]
3969pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_default_minimum(
3970 _tool: *const libc::c_void,
3971) -> f64 {
3972 0.0
3973}
3974
3975#[no_mangle]
3976pub unsafe extern "C" fn libinput_tablet_tool_config_pressure_range_get_default_maximum(
3977 _tool: *const libc::c_void,
3978) -> f64 {
3979 1.0
3980}
3981
3982#[no_mangle]
3983pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_modes(
3984 tool: *const libc::c_void,
3985) -> u32 {
3986 let tool = tool.cast::<LibinputTabletTool>();
3987 if tool.is_null() {
3988 0
3989 } else {
3990 (*tool).eraser_button_modes
3991 }
3992}
3993
3994#[no_mangle]
3995pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_set_mode(
3996 tool: *mut libc::c_void,
3997 mode: u32,
3998) -> u32 {
3999 let tool = tool.cast::<LibinputTabletTool>();
4000 if tool.is_null() || (mode != 0 && ((*tool).eraser_button_modes & mode) == 0) {
4001 return 1;
4002 }
4003 if !matches!(mode, 0 | 1) {
4004 return 2;
4005 }
4006 (*tool).wanted_eraser_button_mode = mode;
4007 if !(*tool).in_proximity {
4008 (*tool).eraser_button_mode = mode;
4009 }
4010 0
4011}
4012
4013#[no_mangle]
4014pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_mode(
4015 tool: *const libc::c_void,
4016) -> u32 {
4017 let tool = tool.cast::<LibinputTabletTool>();
4018 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4019 0
4020 } else {
4021 (*tool).wanted_eraser_button_mode
4022 }
4023}
4024
4025#[no_mangle]
4026pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_default_mode(
4027 _tool: *const libc::c_void,
4028) -> u32 {
4029 0
4030}
4031
4032#[no_mangle]
4033pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_set_button(
4034 tool: *mut libc::c_void,
4035 button: u32,
4036) -> u32 {
4037 let tool = tool.cast::<LibinputTabletTool>();
4038 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4039 return 1;
4040 }
4041 let is_button = matches!(button, 0x149 | 0x14b | 0x14c)
4042 || (0x100..0x140).contains(&button)
4043 || (0x150..=0x151).contains(&button)
4044 || (0x220..=0x223).contains(&button)
4045 || (0x2c0..=0x2e7).contains(&button);
4046 if !is_button {
4047 return 2;
4048 }
4049 (*tool).wanted_eraser_button = button;
4050 if !(*tool).in_proximity {
4051 (*tool).eraser_button = button;
4052 }
4053 0
4054}
4055
4056#[no_mangle]
4057pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_button(
4058 tool: *const libc::c_void,
4059) -> u32 {
4060 let tool = tool.cast::<LibinputTabletTool>();
4061 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4062 0
4063 } else {
4064 (*tool).wanted_eraser_button
4065 }
4066}
4067
4068#[no_mangle]
4069pub unsafe extern "C" fn libinput_tablet_tool_config_eraser_button_get_default_button(
4070 tool: *const libc::c_void,
4071) -> u32 {
4072 let tool = tool.cast::<LibinputTabletTool>();
4073 if tool.is_null() || (*tool).eraser_button_modes == 0 {
4074 0
4075 } else {
4076 (*tool).default_eraser_button
4077 }
4078}
4079
4080#[no_mangle]
4081pub unsafe extern "C" fn libinput_tablet_tool_get_name(
4082 tool: *const libc::c_void,
4083) -> *const libc::c_char {
4084 let tool = tool.cast::<LibinputTabletTool>();
4085 if tool.is_null() {
4086 return std::ptr::null();
4087 }
4088 let tool = tool.cast::<LibinputTabletTool>();
4089 let tool = tool as *mut LibinputTabletTool;
4090 if let Some(name) = (*tool).name.as_ref() {
4091 return name.as_ptr();
4092 }
4093 if let Some(name) = crate::backend::tablet_tool_name_for_id((*tool).tool_id) {
4094 (*tool).name = Some(name);
4095 (*tool)
4096 .name
4097 .as_ref()
4098 .map_or(std::ptr::null(), |name| name.as_ptr())
4099 } else {
4100 std::ptr::null()
4101 }
4102}
4103
4104#[no_mangle]
4105pub unsafe extern "C" fn libinput_tablet_tool_get_serial(tool: *const libc::c_void) -> u64 {
4106 let tool = tool.cast::<LibinputTabletTool>();
4107 if tool.is_null() {
4108 0
4109 } else {
4110 (*tool).serial
4111 }
4112}
4113
4114#[no_mangle]
4115pub unsafe extern "C" fn libinput_tablet_tool_get_tool_id(tool: *const libc::c_void) -> u64 {
4116 let tool = tool.cast::<LibinputTabletTool>();
4117 if tool.is_null() {
4118 0
4119 } else {
4120 (*tool).tool_id
4121 }
4122}
4123
4124#[no_mangle]
4125pub unsafe extern "C" fn libinput_tablet_tool_get_type(tool: *const libc::c_void) -> u32 {
4126 let tool = tool.cast::<LibinputTabletTool>();
4127 if tool.is_null() {
4128 0
4129 } else {
4130 (*tool).tool_type
4131 }
4132}
4133
4134#[no_mangle]
4135pub unsafe extern "C" fn libinput_tablet_tool_has_distance(
4136 tool: *const libc::c_void,
4137) -> libc::c_int {
4138 let tool = tool.cast::<LibinputTabletTool>();
4139 (!tool.is_null() && (*tool).has_distance) as libc::c_int
4140}
4141
4142#[no_mangle]
4143pub unsafe extern "C" fn libinput_tablet_tool_has_button(
4144 tool: *const libc::c_void,
4145 button: u32,
4146) -> libc::c_int {
4147 let tool = tool.cast::<LibinputTabletTool>();
4148 (!tool.is_null() && (*tool).buttons.contains(&button)) as libc::c_int
4149}
4150
4151#[no_mangle]
4152pub unsafe extern "C" fn libinput_tablet_tool_has_size(tool: *const libc::c_void) -> libc::c_int {
4153 let tool = tool.cast::<LibinputTabletTool>();
4154 (!tool.is_null() && (*tool).has_size) as libc::c_int
4155}
4156
4157#[no_mangle]
4158pub unsafe extern "C" fn libinput_tablet_tool_is_unique(tool: *const libc::c_void) -> libc::c_int {
4159 let tool = tool.cast::<LibinputTabletTool>();
4160 (!tool.is_null() && (*tool).serial != 0) as libc::c_int
4161}
4162
4163#[no_mangle]
4164pub unsafe extern "C" fn libinput_tablet_tool_set_user_data(
4165 tool: *mut libc::c_void,
4166 data: *mut libc::c_void,
4167) {
4168 let tool = tool.cast::<LibinputTabletTool>();
4169 if !tool.is_null() {
4170 (*tool).user_data = data;
4171 }
4172}
4173
4174#[no_mangle]
4175pub unsafe extern "C" fn libinput_tablet_tool_get_user_data(
4176 tool: *const libc::c_void,
4177) -> *mut libc::c_void {
4178 let tool = tool.cast::<LibinputTabletTool>();
4179 if tool.is_null() {
4180 std::ptr::null_mut()
4181 } else {
4182 (*tool).user_data
4183 }
4184}
4185
4186#[no_mangle]
4187pub unsafe extern "C" fn libinput_tablet_tool_has_pressure(
4188 tool: *const libc::c_void,
4189) -> libc::c_int {
4190 let tool = tool.cast::<LibinputTabletTool>();
4191 (!tool.is_null() && (*tool).has_pressure) as libc::c_int
4192}
4193
4194#[no_mangle]
4195pub unsafe extern "C" fn libinput_tablet_tool_has_rotation(
4196 tool: *const libc::c_void,
4197) -> libc::c_int {
4198 let tool = tool.cast::<LibinputTabletTool>();
4199 (!tool.is_null() && (*tool).has_rotation) as libc::c_int
4200}
4201
4202#[no_mangle]
4203pub unsafe extern "C" fn libinput_tablet_tool_has_slider(tool: *const libc::c_void) -> libc::c_int {
4204 let tool = tool.cast::<LibinputTabletTool>();
4205 (!tool.is_null() && (*tool).has_slider) as libc::c_int
4206}
4207
4208#[no_mangle]
4209pub unsafe extern "C" fn libinput_tablet_tool_has_tilt(tool: *const libc::c_void) -> libc::c_int {
4210 let tool = tool.cast::<LibinputTabletTool>();
4211 (!tool.is_null() && (*tool).has_tilt) as libc::c_int
4212}
4213
4214#[no_mangle]
4215pub unsafe extern "C" fn libinput_tablet_tool_has_wheel(tool: *const libc::c_void) -> libc::c_int {
4216 let tool = tool.cast::<LibinputTabletTool>();
4217 (!tool.is_null() && (*tool).has_wheel) as libc::c_int
4218}
4219
4220#[no_mangle]
4221pub unsafe extern "C" fn libinput_tablet_tool_ref(tool: *mut libc::c_void) -> *mut libc::c_void {
4222 let tablet_tool = tool.cast::<LibinputTabletTool>();
4223 if !tablet_tool.is_null() {
4224 (*tablet_tool)
4225 .refcount
4226 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
4227 }
4228 tool
4229}
4230
4231#[no_mangle]
4232pub unsafe extern "C" fn libinput_tablet_tool_unref(tool: *mut libc::c_void) -> *mut libc::c_void {
4233 let tablet_tool = tool.cast::<LibinputTabletTool>();
4234 if tablet_tool.is_null() {
4235 return std::ptr::null_mut();
4236 }
4237 if (*tablet_tool)
4238 .refcount
4239 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel)
4240 == 1
4241 {
4242 if !(*tablet_tool).device.is_null() {
4243 libinput_device_unref((*tablet_tool).device);
4244 (*tablet_tool).device = std::ptr::null_mut();
4245 }
4246 drop(Box::from_raw(tablet_tool));
4247 std::ptr::null_mut()
4248 } else {
4249 tool
4250 }
4251}
4252
4253#[no_mangle]
4258pub unsafe extern "C" fn libinput_suspend(ctx: *mut LibinputContext) {
4259 if ctx.is_null() {
4260 return;
4261 }
4262 let mut events = std::collections::VecDeque::new();
4263 if let Ok(mut backend) = (*ctx).backend.lock() {
4264 backend.suspend(ctx, &mut events);
4265 }
4266 enqueue_events(ctx, events);
4267}
4268
4269#[no_mangle]
4270pub unsafe extern "C" fn libinput_resume(ctx: *mut LibinputContext) -> libc::c_int {
4271 if ctx.is_null() {
4272 return -1;
4273 }
4274 let mut events = std::collections::VecDeque::new();
4275 let status = if let Ok(mut backend) = (*ctx).backend.lock() {
4276 backend.resume(ctx, &mut events)
4277 } else {
4278 return -1;
4279 };
4280 enqueue_events(ctx, events);
4281 if !(*ctx).event_queue.is_empty() {
4282 (*ctx).signal_fd();
4283 }
4284 status
4285}
4286
4287#[cfg(test)]
4288mod tests {
4289 use super::*;
4290
4291 unsafe extern "C" fn deny_open(
4292 _path: *const libc::c_char,
4293 _flags: libc::c_int,
4294 _user_data: *mut libc::c_void,
4295 ) -> libc::c_int {
4296 -libc::EACCES
4297 }
4298
4299 unsafe extern "C" fn close_fd(_fd: libc::c_int, _user_data: *mut libc::c_void) {}
4300
4301 static INTERFACE: LibinputInterface = LibinputInterface {
4302 open_restricted: Some(deny_open),
4303 close_restricted: Some(close_fd),
4304 };
4305
4306 #[test]
4307 fn udev_context_requires_interface_and_udev() {
4308 unsafe {
4309 let fake_udev = 1usize as *mut libc::c_void;
4310 assert!(libinput_udev_create_context(
4311 std::ptr::null(),
4312 std::ptr::null_mut(),
4313 fake_udev,
4314 )
4315 .is_null());
4316 assert!(libinput_udev_create_context(
4317 &INTERFACE,
4318 std::ptr::null_mut(),
4319 std::ptr::null_mut(),
4320 )
4321 .is_null());
4322 }
4323 }
4324
4325 #[test]
4326 fn seat_assignment_is_udev_only_and_happens_once() {
4327 unsafe {
4328 let fake_udev = 1usize as *mut libc::c_void;
4329 let seat = std::ffi::CString::new("seat0").unwrap();
4330 let udev_ctx =
4331 libinput_udev_create_context(&INTERFACE, std::ptr::null_mut(), fake_udev);
4332 assert!(!udev_ctx.is_null());
4333 assert_eq!(libinput_udev_assign_seat(udev_ctx, seat.as_ptr()), 0);
4334 assert_eq!(libinput_udev_assign_seat(udev_ctx, seat.as_ptr()), -1);
4335 libinput_unref(udev_ctx);
4336
4337 let path_ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4338 assert!(!path_ctx.is_null());
4339 assert_eq!(libinput_udev_assign_seat(path_ctx, seat.as_ptr()), -1);
4340 libinput_unref(path_ctx);
4341 }
4342 }
4343
4344 #[test]
4345 fn overlong_seat_name_does_not_assign_or_queue_devices() {
4346 unsafe {
4347 let fake_udev = 1usize as *mut libc::c_void;
4348 let seat = std::ffi::CString::new("a".repeat(257)).unwrap();
4349 let ctx = libinput_udev_create_context(&INTERFACE, std::ptr::null_mut(), fake_udev);
4350 assert!(!ctx.is_null());
4351
4352 assert_eq!(libinput_udev_assign_seat(ctx, seat.as_ptr()), -1);
4353 assert!(!(*ctx).seat_assigned);
4354 assert!((*ctx).event_queue.is_empty());
4355
4356 libinput_unref(ctx);
4357 }
4358 }
4359
4360 #[test]
4361 fn suspend_and_resume_are_null_safe() {
4362 unsafe {
4363 libinput_suspend(std::ptr::null_mut());
4364 assert_eq!(libinput_resume(std::ptr::null_mut()), -1);
4365 }
4366 }
4367
4368 #[test]
4369 fn shared_device_groups_preserve_identity_and_user_data() {
4370 unsafe {
4371 let first = Box::new(LibinputDevice::new(
4372 "first",
4373 "/dev/input/event0",
4374 std::ptr::null_mut(),
4375 std::ptr::null_mut(),
4376 ));
4377 let group = first.group;
4378 let mut second = Box::new(LibinputDevice::new(
4379 "second",
4380 "/dev/input/event1",
4381 std::ptr::null_mut(),
4382 std::ptr::null_mut(),
4383 ));
4384 second.share_group(group);
4385
4386 assert_eq!(second.group, group);
4387 assert_eq!(second.abi.group, group);
4388 assert_eq!(
4389 (*group).refcount.load(std::sync::atomic::Ordering::Relaxed),
4390 2
4391 );
4392 let marker = 0x5ausize as *mut libc::c_void;
4393 libinput_device_group_set_user_data(group.cast(), marker);
4394 assert_eq!(
4395 libinput_device_group_get_user_data(second.group.cast()),
4396 marker
4397 );
4398
4399 drop(second);
4400 assert_eq!(
4401 (*group).refcount.load(std::sync::atomic::Ordering::Relaxed),
4402 1
4403 );
4404 drop(first);
4405 }
4406 }
4407
4408 #[test]
4409 fn custom_acceleration_validates_and_copies_curves() {
4410 unsafe {
4411 assert!(libinput_config_accel_create(0).is_null());
4412 let config = libinput_config_accel_create(4);
4413 assert!(!config.is_null());
4414
4415 let one_point = [1.0];
4416 assert_eq!(
4417 libinput_config_accel_set_points(config, 1, 1.0, 1, one_point.as_ptr()),
4418 2
4419 );
4420 let points = [0.0, 2.0, 6.0];
4421 assert_eq!(
4422 libinput_config_accel_set_points(config, 1, 1.0, points.len(), points.as_ptr()),
4423 0
4424 );
4425 let scroll_points = [0.0, 3.0, 9.0];
4426 assert_eq!(
4427 libinput_config_accel_set_points(
4428 config,
4429 2,
4430 1.0,
4431 scroll_points.len(),
4432 scroll_points.as_ptr(),
4433 ),
4434 0
4435 );
4436
4437 let mut device = Box::new(LibinputDevice::new(
4438 "pointer",
4439 "/dev/input/event0",
4440 std::ptr::null_mut(),
4441 std::ptr::null_mut(),
4442 ));
4443 device.accel_available = true;
4444 assert_eq!(libinput_device_config_accel_apply(&mut *device, config), 0);
4445 libinput_config_accel_destroy(config);
4446
4447 let custom = device.accel_custom.as_mut().expect("custom config copied");
4448 let curve = custom.curve_mut(1).expect("motion curve copied");
4449 assert_eq!(curve.points, points);
4450 assert!((curve.factor(7.0, 0.0, 7_000) - 2.0).abs() < 1e-9);
4451 let scroll_curve = custom.curve_mut(2).expect("scroll curve copied");
4452 assert_eq!(scroll_curve.points, scroll_points);
4453 assert!((scroll_curve.factor(7.0, 0.0, 7_000) - 3.0).abs() < 1e-9);
4454 }
4455 }
4456
4457 #[test]
4458 fn custom_acceleration_uses_fallback_and_extrapolates() {
4459 let mut config = crate::ffi_types::AccelConfig::new(4);
4460 config.fallback = Some(crate::ffi_types::AccelCurve::new(1.0, vec![0.0, 1.0]));
4461 let curve = config.curve_mut(1).expect("fallback curve");
4462 assert!((curve.factor(14.0, 0.0, 7_000) - 1.0).abs() < 1e-9);
4463 }
4464
4465 #[test]
4466 fn plugin_paths_are_ordered_unique_and_frozen_after_load() {
4467 unsafe {
4468 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4469 let custom = std::ffi::CString::new("/tmp/plugins").unwrap();
4470 libinput_plugin_system_append_path(ctx, custom.as_ptr());
4471 libinput_plugin_system_append_path(ctx, custom.as_ptr());
4472 libinput_plugin_system_append_default_paths(ctx);
4473 assert_eq!((*ctx).plugin_paths.len(), 3);
4474 assert_eq!((&(*ctx).plugin_paths)[0].as_bytes(), b"/tmp/plugins");
4475 assert_eq!(libinput_plugin_system_load_plugins(ctx, 0), -libc::ENOSYS);
4476 let ignored = std::ffi::CString::new("/ignored").unwrap();
4477 libinput_plugin_system_append_path(ctx, ignored.as_ptr());
4478 assert_eq!((*ctx).plugin_paths.len(), 3);
4479 assert_eq!(libinput_plugin_system_load_plugins(ctx, 0), 0);
4480 libinput_unref(ctx);
4481 }
4482 }
4483
4484 #[test]
4485 fn queued_events_retain_devices_until_event_destroy() {
4486 unsafe {
4487 let ctx = libinput_path_create_context(&INTERFACE, std::ptr::null_mut());
4488 let device = Box::into_raw(Box::new(LibinputDevice::new(
4489 "keyboard",
4490 "/dev/input/event0",
4491 std::ptr::null_mut(),
4492 ctx,
4493 )));
4494 enqueue_event(
4495 ctx,
4496 LibinputEvent {
4497 event_type: LibinputEventType::LIBINPUT_EVENT_KEYBOARD_KEY,
4498 payload: EventPayload::KeyboardKey(crate::ffi_types::KeyboardKeyEvent {
4499 time_usec: 1,
4500 key: 30,
4501 state: 1,
4502 seat_key_count: 1,
4503 }),
4504 context: ctx,
4505 device,
4506 },
4507 );
4508 assert_eq!(
4509 (*device).refcount.load(std::sync::atomic::Ordering::SeqCst),
4510 2
4511 );
4512 let event = libinput_get_event(ctx);
4513 assert_eq!(libinput_event_get_device(event), device);
4514 libinput_event_destroy(event);
4515 assert_eq!(
4516 (*device).refcount.load(std::sync::atomic::Ordering::SeqCst),
4517 1
4518 );
4519 assert!(libinput_device_unref(device).is_null());
4520 libinput_unref(ctx);
4521 }
4522 }
4523
4524 #[test]
4525 fn ref_and_unref_return_the_upstream_object_lifecycle() {
4526 unsafe {
4527 let seat = Box::into_raw(Box::new(LibinputSeat {
4528 physical_name: std::ffi::CString::new("seat0").unwrap(),
4529 logical_name: std::ffi::CString::new("default").unwrap(),
4530 refcount: std::sync::atomic::AtomicI32::new(1),
4531 user_data: std::ptr::null_mut(),
4532 context: std::ptr::null_mut(),
4533 button_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4534 key_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4535 }));
4536 assert_eq!(libinput_seat_ref(seat.cast()), seat.cast());
4537 assert_eq!(libinput_seat_unref(seat.cast()), seat.cast());
4538 assert!(libinput_seat_unref(seat.cast()).is_null());
4539
4540 let group = Box::into_raw(Box::new(LibinputTabletPadModeGroup {
4541 refcount: std::sync::atomic::AtomicI32::new(1),
4542 user_data: std::ptr::null_mut(),
4543 device: std::ptr::null_mut(),
4544 index: 0,
4545 num_modes: 1,
4546 current_mode: 0,
4547 button_mask: 0,
4548 dial_mask: 0,
4549 ring_mask: 0,
4550 strip_mask: 0,
4551 toggle_button_mask: 0,
4552 toggle_modes: Vec::new(),
4553 }));
4554 assert_eq!(
4555 libinput_tablet_pad_mode_group_ref(group.cast()),
4556 group.cast()
4557 );
4558 assert_eq!(
4559 libinput_tablet_pad_mode_group_unref(group.cast()),
4560 group.cast()
4561 );
4562 assert!(libinput_tablet_pad_mode_group_unref(group.cast()).is_null());
4563 }
4564 }
4565
4566 #[test]
4567 fn devices_retain_their_seat_until_device_destruction() {
4568 unsafe {
4569 let seat = Box::into_raw(Box::new(LibinputSeat {
4570 physical_name: std::ffi::CString::new("seat0").unwrap(),
4571 logical_name: std::ffi::CString::new("default").unwrap(),
4572 refcount: std::sync::atomic::AtomicI32::new(1),
4573 user_data: std::ptr::null_mut(),
4574 context: std::ptr::null_mut(),
4575 button_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4576 key_counts: std::sync::Mutex::new(crate::evtrans::empty_seat_code_counts()),
4577 }));
4578 let device = Box::into_raw(Box::new(LibinputDevice::new(
4579 "keyboard",
4580 "/dev/input/event0",
4581 seat,
4582 std::ptr::null_mut(),
4583 )));
4584 assert_eq!(
4585 (*seat).refcount.load(std::sync::atomic::Ordering::SeqCst),
4586 2
4587 );
4588 assert!(libinput_device_unref(device).is_null());
4589 assert_eq!(
4590 (*seat).refcount.load(std::sync::atomic::Ordering::SeqCst),
4591 1
4592 );
4593 assert!(libinput_seat_unref(seat.cast()).is_null());
4594 }
4595 }
4596}