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