Skip to main content

input/
lib.rs

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