1a46c0ec8Sopenharmony_ci/* 2a46c0ec8Sopenharmony_ci * Copyright © 2014 Red Hat, Inc. 3a46c0ec8Sopenharmony_ci * 4a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10a46c0ec8Sopenharmony_ci * 11a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13a46c0ec8Sopenharmony_ci * Software. 14a46c0ec8Sopenharmony_ci * 15a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22a46c0ec8Sopenharmony_ci */ 23a46c0ec8Sopenharmony_ci#include <config.h> 24a46c0ec8Sopenharmony_ci 25a46c0ec8Sopenharmony_ci#include <linux/input.h> 26a46c0ec8Sopenharmony_ci 27a46c0ec8Sopenharmony_ci#include <assert.h> 28a46c0ec8Sopenharmony_ci#include <cairo.h> 29a46c0ec8Sopenharmony_ci#include <errno.h> 30a46c0ec8Sopenharmony_ci#include <fcntl.h> 31a46c0ec8Sopenharmony_ci#include <getopt.h> 32a46c0ec8Sopenharmony_ci#include <math.h> 33a46c0ec8Sopenharmony_ci#include <stdio.h> 34a46c0ec8Sopenharmony_ci#include <stdlib.h> 35a46c0ec8Sopenharmony_ci#include <stdarg.h> 36a46c0ec8Sopenharmony_ci#include <string.h> 37a46c0ec8Sopenharmony_ci#include <unistd.h> 38a46c0ec8Sopenharmony_ci 39a46c0ec8Sopenharmony_ci#include <gtk/gtk.h> 40a46c0ec8Sopenharmony_ci#include <glib.h> 41a46c0ec8Sopenharmony_ci#include <glib-unix.h> 42a46c0ec8Sopenharmony_ci#include <libevdev/libevdev.h> 43a46c0ec8Sopenharmony_ci 44a46c0ec8Sopenharmony_ci#include <libinput.h> 45a46c0ec8Sopenharmony_ci#include "util-strings.h" 46a46c0ec8Sopenharmony_ci#include "util-macros.h" 47a46c0ec8Sopenharmony_ci#include "util-list.h" 48a46c0ec8Sopenharmony_ci 49a46c0ec8Sopenharmony_ci#include "shared.h" 50a46c0ec8Sopenharmony_ci 51a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND 52a46c0ec8Sopenharmony_ci #include <wayland-client.h> 53a46c0ec8Sopenharmony_ci #include "pointer-constraints-unstable-v1-client-protocol.h" 54a46c0ec8Sopenharmony_ci #if HAVE_GTK4 55a46c0ec8Sopenharmony_ci #include <gdk/wayland/gdkwayland.h> 56a46c0ec8Sopenharmony_ci #else 57a46c0ec8Sopenharmony_ci #include <gdk/gdkwayland.h> 58a46c0ec8Sopenharmony_ci #endif 59a46c0ec8Sopenharmony_ci#endif 60a46c0ec8Sopenharmony_ci 61a46c0ec8Sopenharmony_ci#if HAVE_GTK_X11 62a46c0ec8Sopenharmony_ci #include <X11/X.h> 63a46c0ec8Sopenharmony_ci #include <X11/Xlib.h> 64a46c0ec8Sopenharmony_ci #if HAVE_GTK4 65a46c0ec8Sopenharmony_ci #include <gdk/x11/gdkx.h> 66a46c0ec8Sopenharmony_ci #else 67a46c0ec8Sopenharmony_ci #include <gdk/gdkx.h> 68a46c0ec8Sopenharmony_ci #endif 69a46c0ec8Sopenharmony_ci#endif 70a46c0ec8Sopenharmony_ci 71a46c0ec8Sopenharmony_ci#define clip(val_, min_, max_) min((max_), max((min_), (val_))) 72a46c0ec8Sopenharmony_ci 73a46c0ec8Sopenharmony_cienum touch_state { 74a46c0ec8Sopenharmony_ci TOUCH_ACTIVE, 75a46c0ec8Sopenharmony_ci TOUCH_ENDED, 76a46c0ec8Sopenharmony_ci TOUCH_CANCELLED, 77a46c0ec8Sopenharmony_ci}; 78a46c0ec8Sopenharmony_ci 79a46c0ec8Sopenharmony_cistruct touch { 80a46c0ec8Sopenharmony_ci enum touch_state state; 81a46c0ec8Sopenharmony_ci int x, y; 82a46c0ec8Sopenharmony_ci}; 83a46c0ec8Sopenharmony_ci 84a46c0ec8Sopenharmony_cistruct point { 85a46c0ec8Sopenharmony_ci double x, y; 86a46c0ec8Sopenharmony_ci}; 87a46c0ec8Sopenharmony_ci 88a46c0ec8Sopenharmony_cistruct evdev_device { 89a46c0ec8Sopenharmony_ci struct list node; 90a46c0ec8Sopenharmony_ci struct libevdev *evdev; 91a46c0ec8Sopenharmony_ci struct libinput_device *libinput_device; 92a46c0ec8Sopenharmony_ci int fd; 93a46c0ec8Sopenharmony_ci guint source_id; 94a46c0ec8Sopenharmony_ci}; 95a46c0ec8Sopenharmony_ci 96a46c0ec8Sopenharmony_cistruct window { 97a46c0ec8Sopenharmony_ci bool grab; 98a46c0ec8Sopenharmony_ci struct tools_options options; 99a46c0ec8Sopenharmony_ci struct list evdev_devices; 100a46c0ec8Sopenharmony_ci 101a46c0ec8Sopenharmony_ci GMainLoop *event_loop; 102a46c0ec8Sopenharmony_ci 103a46c0ec8Sopenharmony_ci GtkWidget *win; 104a46c0ec8Sopenharmony_ci GtkWidget *area; 105a46c0ec8Sopenharmony_ci int width, height; /* of window */ 106a46c0ec8Sopenharmony_ci 107a46c0ec8Sopenharmony_ci /* sprite position */ 108a46c0ec8Sopenharmony_ci struct point pointer; 109a46c0ec8Sopenharmony_ci struct point unaccelerated; 110a46c0ec8Sopenharmony_ci 111a46c0ec8Sopenharmony_ci /* these are for the delta coordinates, but they're not 112a46c0ec8Sopenharmony_ci * deltas, they are converted into abs positions */ 113a46c0ec8Sopenharmony_ci size_t ndeltas; 114a46c0ec8Sopenharmony_ci struct point deltas[64]; 115a46c0ec8Sopenharmony_ci 116a46c0ec8Sopenharmony_ci /* abs position */ 117a46c0ec8Sopenharmony_ci struct point abs; 118a46c0ec8Sopenharmony_ci 119a46c0ec8Sopenharmony_ci /* Wayland and X11 pointer locking */ 120a46c0ec8Sopenharmony_ci struct { 121a46c0ec8Sopenharmony_ci bool locked; 122a46c0ec8Sopenharmony_ci 123a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND 124a46c0ec8Sopenharmony_ci struct zwp_pointer_constraints_v1 *wayland_pointer_constraints; 125a46c0ec8Sopenharmony_ci struct zwp_locked_pointer_v1 *wayland_locked_pointer; 126a46c0ec8Sopenharmony_ci#endif 127a46c0ec8Sopenharmony_ci } lock_pointer; 128a46c0ec8Sopenharmony_ci 129a46c0ec8Sopenharmony_ci /* scroll bar positions */ 130a46c0ec8Sopenharmony_ci struct { 131a46c0ec8Sopenharmony_ci double vx, vy; 132a46c0ec8Sopenharmony_ci double hx, hy; 133a46c0ec8Sopenharmony_ci 134a46c0ec8Sopenharmony_ci double vx_discrete, vy_discrete; 135a46c0ec8Sopenharmony_ci double hx_discrete, hy_discrete; 136a46c0ec8Sopenharmony_ci } scroll; 137a46c0ec8Sopenharmony_ci 138a46c0ec8Sopenharmony_ci /* touch positions */ 139a46c0ec8Sopenharmony_ci struct touch touches[32]; 140a46c0ec8Sopenharmony_ci 141a46c0ec8Sopenharmony_ci /* l/m/r mouse buttons */ 142a46c0ec8Sopenharmony_ci struct { 143a46c0ec8Sopenharmony_ci bool l, m, r; 144a46c0ec8Sopenharmony_ci bool other; 145a46c0ec8Sopenharmony_ci const char *other_name; 146a46c0ec8Sopenharmony_ci } buttons; 147a46c0ec8Sopenharmony_ci 148a46c0ec8Sopenharmony_ci /* touchpad swipe */ 149a46c0ec8Sopenharmony_ci struct { 150a46c0ec8Sopenharmony_ci int nfingers; 151a46c0ec8Sopenharmony_ci double x, y; 152a46c0ec8Sopenharmony_ci } swipe; 153a46c0ec8Sopenharmony_ci 154a46c0ec8Sopenharmony_ci struct { 155a46c0ec8Sopenharmony_ci int nfingers; 156a46c0ec8Sopenharmony_ci double scale; 157a46c0ec8Sopenharmony_ci double angle; 158a46c0ec8Sopenharmony_ci double x, y; 159a46c0ec8Sopenharmony_ci } pinch; 160a46c0ec8Sopenharmony_ci 161a46c0ec8Sopenharmony_ci struct { 162a46c0ec8Sopenharmony_ci int nfingers; 163a46c0ec8Sopenharmony_ci bool active; 164a46c0ec8Sopenharmony_ci } hold; 165a46c0ec8Sopenharmony_ci 166a46c0ec8Sopenharmony_ci struct { 167a46c0ec8Sopenharmony_ci double x, y; 168a46c0ec8Sopenharmony_ci double x_in, y_in; 169a46c0ec8Sopenharmony_ci double x_down, y_down; 170a46c0ec8Sopenharmony_ci double x_up, y_up; 171a46c0ec8Sopenharmony_ci double pressure; 172a46c0ec8Sopenharmony_ci double distance; 173a46c0ec8Sopenharmony_ci double tilt_x, tilt_y; 174a46c0ec8Sopenharmony_ci double rotation; 175a46c0ec8Sopenharmony_ci double size_major, size_minor; 176a46c0ec8Sopenharmony_ci bool is_down; 177a46c0ec8Sopenharmony_ci 178a46c0ec8Sopenharmony_ci /* these are for the delta coordinates, but they're not 179a46c0ec8Sopenharmony_ci * deltas, they are converted into abs positions */ 180a46c0ec8Sopenharmony_ci size_t ndeltas; 181a46c0ec8Sopenharmony_ci struct point deltas[64]; 182a46c0ec8Sopenharmony_ci } tool; 183a46c0ec8Sopenharmony_ci 184a46c0ec8Sopenharmony_ci struct { 185a46c0ec8Sopenharmony_ci struct { 186a46c0ec8Sopenharmony_ci double position; 187a46c0ec8Sopenharmony_ci int number; 188a46c0ec8Sopenharmony_ci } ring; 189a46c0ec8Sopenharmony_ci struct { 190a46c0ec8Sopenharmony_ci double position; 191a46c0ec8Sopenharmony_ci int number; 192a46c0ec8Sopenharmony_ci } strip; 193a46c0ec8Sopenharmony_ci } pad; 194a46c0ec8Sopenharmony_ci 195a46c0ec8Sopenharmony_ci struct { 196a46c0ec8Sopenharmony_ci int rel_x, rel_y; /* REL_X/Y */ 197a46c0ec8Sopenharmony_ci int x, y; /* ABS_X/Y */ 198a46c0ec8Sopenharmony_ci struct { 199a46c0ec8Sopenharmony_ci int x, y; /* ABS_MT_POSITION_X/Y */ 200a46c0ec8Sopenharmony_ci bool active; 201a46c0ec8Sopenharmony_ci } slots[16]; 202a46c0ec8Sopenharmony_ci unsigned int slot; /* ABS_MT_SLOT */ 203a46c0ec8Sopenharmony_ci /* So we know when to re-fetch the abs axes */ 204a46c0ec8Sopenharmony_ci uintptr_t device, last_device; 205a46c0ec8Sopenharmony_ci } evdev; 206a46c0ec8Sopenharmony_ci 207a46c0ec8Sopenharmony_ci struct libinput_device *devices[50]; 208a46c0ec8Sopenharmony_ci}; 209a46c0ec8Sopenharmony_ci 210a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND 211a46c0ec8Sopenharmony_cistatic void 212a46c0ec8Sopenharmony_ciwayland_registry_global(void *data, 213a46c0ec8Sopenharmony_ci struct wl_registry *registry, 214a46c0ec8Sopenharmony_ci uint32_t name, 215a46c0ec8Sopenharmony_ci const char *interface, 216a46c0ec8Sopenharmony_ci uint32_t version) 217a46c0ec8Sopenharmony_ci{ 218a46c0ec8Sopenharmony_ci struct window *w = data; 219a46c0ec8Sopenharmony_ci 220a46c0ec8Sopenharmony_ci if (!g_strcmp0(interface, "zwp_pointer_constraints_v1")) { 221a46c0ec8Sopenharmony_ci w->lock_pointer.wayland_pointer_constraints = 222a46c0ec8Sopenharmony_ci wl_registry_bind(registry, 223a46c0ec8Sopenharmony_ci name, 224a46c0ec8Sopenharmony_ci &zwp_pointer_constraints_v1_interface, 225a46c0ec8Sopenharmony_ci 1); 226a46c0ec8Sopenharmony_ci } 227a46c0ec8Sopenharmony_ci} 228a46c0ec8Sopenharmony_ci 229a46c0ec8Sopenharmony_cistatic void 230a46c0ec8Sopenharmony_ciwayland_registry_global_remove(void *data, 231a46c0ec8Sopenharmony_ci struct wl_registry *wl_registry, 232a46c0ec8Sopenharmony_ci uint32_t name) 233a46c0ec8Sopenharmony_ci{ 234a46c0ec8Sopenharmony_ci 235a46c0ec8Sopenharmony_ci} 236a46c0ec8Sopenharmony_ci 237a46c0ec8Sopenharmony_cistruct wl_registry_listener registry_listener = { 238a46c0ec8Sopenharmony_ci wayland_registry_global, 239a46c0ec8Sopenharmony_ci wayland_registry_global_remove 240a46c0ec8Sopenharmony_ci}; 241a46c0ec8Sopenharmony_ci 242a46c0ec8Sopenharmony_cistatic bool 243a46c0ec8Sopenharmony_ciwayland_lock_pointer(struct window *w) 244a46c0ec8Sopenharmony_ci{ 245a46c0ec8Sopenharmony_ci GdkDisplay *gdk_display; 246a46c0ec8Sopenharmony_ci GdkSeat *gdk_seat; 247a46c0ec8Sopenharmony_ci GdkDevice *gdk_device; 248a46c0ec8Sopenharmony_ci struct wl_display *display; 249a46c0ec8Sopenharmony_ci struct wl_registry *registry; 250a46c0ec8Sopenharmony_ci struct wl_pointer *wayland_pointer; 251a46c0ec8Sopenharmony_ci struct wl_surface *surface; 252a46c0ec8Sopenharmony_ci 253a46c0ec8Sopenharmony_ci w->lock_pointer.wayland_pointer_constraints = NULL; 254a46c0ec8Sopenharmony_ci 255a46c0ec8Sopenharmony_ci gdk_display = gdk_display_get_default(); 256a46c0ec8Sopenharmony_ci display = gdk_wayland_display_get_wl_display(gdk_display); 257a46c0ec8Sopenharmony_ci 258a46c0ec8Sopenharmony_ci gdk_seat = gdk_display_get_default_seat(gdk_display); 259a46c0ec8Sopenharmony_ci gdk_device = gdk_seat_get_pointer(gdk_seat); 260a46c0ec8Sopenharmony_ci wayland_pointer = gdk_wayland_device_get_wl_pointer(gdk_device); 261a46c0ec8Sopenharmony_ci 262a46c0ec8Sopenharmony_ci registry = wl_display_get_registry(display); 263a46c0ec8Sopenharmony_ci wl_registry_add_listener(registry, ®istry_listener, w); 264a46c0ec8Sopenharmony_ci wl_display_roundtrip(display); 265a46c0ec8Sopenharmony_ci 266a46c0ec8Sopenharmony_ci if (!w->lock_pointer.wayland_pointer_constraints) 267a46c0ec8Sopenharmony_ci return false; 268a46c0ec8Sopenharmony_ci 269a46c0ec8Sopenharmony_ci#if HAVE_GTK4 270a46c0ec8Sopenharmony_ci GtkNative *window = gtk_widget_get_native(w->win); 271a46c0ec8Sopenharmony_ci GdkSurface *gdk_surface = gtk_native_get_surface(window); 272a46c0ec8Sopenharmony_ci surface = gdk_wayland_surface_get_wl_surface(gdk_surface); 273a46c0ec8Sopenharmony_ci#else 274a46c0ec8Sopenharmony_ci GdkWindow *window = gtk_widget_get_window(w->win); 275a46c0ec8Sopenharmony_ci surface = gdk_wayland_window_get_wl_surface(window); 276a46c0ec8Sopenharmony_ci#endif 277a46c0ec8Sopenharmony_ci 278a46c0ec8Sopenharmony_ci w->lock_pointer.wayland_locked_pointer = 279a46c0ec8Sopenharmony_ci zwp_pointer_constraints_v1_lock_pointer(w->lock_pointer.wayland_pointer_constraints, 280a46c0ec8Sopenharmony_ci surface, 281a46c0ec8Sopenharmony_ci wayland_pointer, 282a46c0ec8Sopenharmony_ci NULL, 283a46c0ec8Sopenharmony_ci ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); 284a46c0ec8Sopenharmony_ci 285a46c0ec8Sopenharmony_ci return true; 286a46c0ec8Sopenharmony_ci} 287a46c0ec8Sopenharmony_ci 288a46c0ec8Sopenharmony_cistatic void 289a46c0ec8Sopenharmony_ciwayland_unlock_pointer(struct window *w) 290a46c0ec8Sopenharmony_ci{ 291a46c0ec8Sopenharmony_ci w->lock_pointer.wayland_pointer_constraints = NULL; 292a46c0ec8Sopenharmony_ci zwp_locked_pointer_v1_destroy(w->lock_pointer.wayland_locked_pointer); 293a46c0ec8Sopenharmony_ci} 294a46c0ec8Sopenharmony_ci 295a46c0ec8Sopenharmony_cistatic inline bool 296a46c0ec8Sopenharmony_cibackend_is_wayland(void) 297a46c0ec8Sopenharmony_ci{ 298a46c0ec8Sopenharmony_ci return GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default()); 299a46c0ec8Sopenharmony_ci} 300a46c0ec8Sopenharmony_ci#endif /* HAVE_GTK_WAYLAND */ 301a46c0ec8Sopenharmony_ci 302a46c0ec8Sopenharmony_ci#if HAVE_GTK_X11 303a46c0ec8Sopenharmony_cistatic bool 304a46c0ec8Sopenharmony_cix_lock_pointer(struct window *w) 305a46c0ec8Sopenharmony_ci{ 306a46c0ec8Sopenharmony_ci Display *x_display; 307a46c0ec8Sopenharmony_ci Window x_win; 308a46c0ec8Sopenharmony_ci int result; 309a46c0ec8Sopenharmony_ci 310a46c0ec8Sopenharmony_ci x_display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 311a46c0ec8Sopenharmony_ci 312a46c0ec8Sopenharmony_ci#if HAVE_GTK4 313a46c0ec8Sopenharmony_ci GtkNative *window = gtk_widget_get_native(w->win); 314a46c0ec8Sopenharmony_ci GdkSurface *surface = gtk_native_get_surface(window); 315a46c0ec8Sopenharmony_ci x_win = GDK_SURFACE_XID(surface); 316a46c0ec8Sopenharmony_ci#else 317a46c0ec8Sopenharmony_ci GdkWindow *window = gtk_widget_get_window(w->win); 318a46c0ec8Sopenharmony_ci x_win = GDK_WINDOW_XID(window); 319a46c0ec8Sopenharmony_ci#endif 320a46c0ec8Sopenharmony_ci 321a46c0ec8Sopenharmony_ci result = XGrabPointer(x_display, x_win, 322a46c0ec8Sopenharmony_ci False, NoEventMask, 323a46c0ec8Sopenharmony_ci GrabModeAsync, GrabModeAsync, 324a46c0ec8Sopenharmony_ci x_win, 325a46c0ec8Sopenharmony_ci None, 326a46c0ec8Sopenharmony_ci CurrentTime); 327a46c0ec8Sopenharmony_ci return (result == GrabSuccess); 328a46c0ec8Sopenharmony_ci} 329a46c0ec8Sopenharmony_ci 330a46c0ec8Sopenharmony_cistatic void 331a46c0ec8Sopenharmony_cix_unlock_pointer(struct window *w) 332a46c0ec8Sopenharmony_ci{ 333a46c0ec8Sopenharmony_ci Display *x_display; 334a46c0ec8Sopenharmony_ci 335a46c0ec8Sopenharmony_ci x_display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 336a46c0ec8Sopenharmony_ci 337a46c0ec8Sopenharmony_ci XUngrabPointer(x_display, CurrentTime); 338a46c0ec8Sopenharmony_ci} 339a46c0ec8Sopenharmony_ci 340a46c0ec8Sopenharmony_cistatic inline bool 341a46c0ec8Sopenharmony_cibackend_is_x11(void) 342a46c0ec8Sopenharmony_ci{ 343a46c0ec8Sopenharmony_ci return GDK_IS_X11_DISPLAY(gdk_display_get_default()); 344a46c0ec8Sopenharmony_ci} 345a46c0ec8Sopenharmony_ci#endif /* HAVE_GTK_X11 */ 346a46c0ec8Sopenharmony_ci 347a46c0ec8Sopenharmony_cistatic bool 348a46c0ec8Sopenharmony_ciwindow_lock_pointer(struct window *w) 349a46c0ec8Sopenharmony_ci{ 350a46c0ec8Sopenharmony_ci if (w->lock_pointer.locked) 351a46c0ec8Sopenharmony_ci return true; 352a46c0ec8Sopenharmony_ci 353a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND 354a46c0ec8Sopenharmony_ci if (backend_is_wayland()) 355a46c0ec8Sopenharmony_ci w->lock_pointer.locked = wayland_lock_pointer(w); 356a46c0ec8Sopenharmony_ci#endif 357a46c0ec8Sopenharmony_ci 358a46c0ec8Sopenharmony_ci#if HAVE_GTK_X11 359a46c0ec8Sopenharmony_ci if (backend_is_x11()) 360a46c0ec8Sopenharmony_ci w->lock_pointer.locked = x_lock_pointer(w); 361a46c0ec8Sopenharmony_ci#endif 362a46c0ec8Sopenharmony_ci 363a46c0ec8Sopenharmony_ci return w->lock_pointer.locked; 364a46c0ec8Sopenharmony_ci} 365a46c0ec8Sopenharmony_ci 366a46c0ec8Sopenharmony_cistatic void 367a46c0ec8Sopenharmony_ciwindow_unlock_pointer(struct window *w) 368a46c0ec8Sopenharmony_ci{ 369a46c0ec8Sopenharmony_ci if (!w->lock_pointer.locked) 370a46c0ec8Sopenharmony_ci return; 371a46c0ec8Sopenharmony_ci 372a46c0ec8Sopenharmony_ci w->lock_pointer.locked = false; 373a46c0ec8Sopenharmony_ci 374a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND 375a46c0ec8Sopenharmony_ci if (backend_is_wayland()) 376a46c0ec8Sopenharmony_ci wayland_unlock_pointer(w); 377a46c0ec8Sopenharmony_ci#endif 378a46c0ec8Sopenharmony_ci 379a46c0ec8Sopenharmony_ci#if HAVE_GTK_X11 380a46c0ec8Sopenharmony_ci if (backend_is_x11()) 381a46c0ec8Sopenharmony_ci x_unlock_pointer(w); 382a46c0ec8Sopenharmony_ci#endif 383a46c0ec8Sopenharmony_ci} 384a46c0ec8Sopenharmony_ci 385a46c0ec8Sopenharmony_ciLIBINPUT_ATTRIBUTE_PRINTF(1, 2) 386a46c0ec8Sopenharmony_cistatic inline void 387a46c0ec8Sopenharmony_cimsg(const char *fmt, ...) 388a46c0ec8Sopenharmony_ci{ 389a46c0ec8Sopenharmony_ci va_list args; 390a46c0ec8Sopenharmony_ci printf("info: "); 391a46c0ec8Sopenharmony_ci 392a46c0ec8Sopenharmony_ci va_start(args, fmt); 393a46c0ec8Sopenharmony_ci vprintf(fmt, args); 394a46c0ec8Sopenharmony_ci va_end(args); 395a46c0ec8Sopenharmony_ci} 396a46c0ec8Sopenharmony_ci 397a46c0ec8Sopenharmony_cistatic inline void 398a46c0ec8Sopenharmony_cidraw_evdev_rel(struct window *w, cairo_t *cr) 399a46c0ec8Sopenharmony_ci{ 400a46c0ec8Sopenharmony_ci int center_x, center_y; 401a46c0ec8Sopenharmony_ci 402a46c0ec8Sopenharmony_ci cairo_save(cr); 403a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .2, .8); 404a46c0ec8Sopenharmony_ci center_x = w->width/2 - 400; 405a46c0ec8Sopenharmony_ci center_y = w->height/2; 406a46c0ec8Sopenharmony_ci 407a46c0ec8Sopenharmony_ci cairo_arc(cr, center_x, center_y, 10, 0, 2 * M_PI); 408a46c0ec8Sopenharmony_ci cairo_stroke(cr); 409a46c0ec8Sopenharmony_ci 410a46c0ec8Sopenharmony_ci if (w->evdev.rel_x) { 411a46c0ec8Sopenharmony_ci int dir = w->evdev.rel_x > 0 ? 1 : -1; 412a46c0ec8Sopenharmony_ci for (int i = 0; i < abs(w->evdev.rel_x); i++) { 413a46c0ec8Sopenharmony_ci cairo_move_to(cr, 414a46c0ec8Sopenharmony_ci center_x + (i + 1) * 20 * dir, 415a46c0ec8Sopenharmony_ci center_y - 20); 416a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 0, 40); 417a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 20 * dir, -20); 418a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, -20 * dir, -20); 419a46c0ec8Sopenharmony_ci cairo_fill(cr); 420a46c0ec8Sopenharmony_ci } 421a46c0ec8Sopenharmony_ci } 422a46c0ec8Sopenharmony_ci 423a46c0ec8Sopenharmony_ci if (w->evdev.rel_y) { 424a46c0ec8Sopenharmony_ci int dir = w->evdev.rel_y > 0 ? 1 : -1; 425a46c0ec8Sopenharmony_ci for (int i = 0; i < abs(w->evdev.rel_y); i++) { 426a46c0ec8Sopenharmony_ci cairo_move_to(cr, 427a46c0ec8Sopenharmony_ci center_x - 20, 428a46c0ec8Sopenharmony_ci center_y + (i + 1) * 20 * dir); 429a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 40, 0); 430a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, -20, 20 * dir); 431a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, -20, -20 * dir); 432a46c0ec8Sopenharmony_ci cairo_fill(cr); 433a46c0ec8Sopenharmony_ci } 434a46c0ec8Sopenharmony_ci } 435a46c0ec8Sopenharmony_ci 436a46c0ec8Sopenharmony_ci cairo_restore(cr); 437a46c0ec8Sopenharmony_ci} 438a46c0ec8Sopenharmony_ci 439a46c0ec8Sopenharmony_cistatic inline void 440a46c0ec8Sopenharmony_cidraw_evdev_abs(struct window *w, cairo_t *cr) 441a46c0ec8Sopenharmony_ci{ 442a46c0ec8Sopenharmony_ci static const struct input_absinfo *ax = NULL, *ay = NULL; 443a46c0ec8Sopenharmony_ci const int normalized_width = 200; 444a46c0ec8Sopenharmony_ci int outline_width = normalized_width, 445a46c0ec8Sopenharmony_ci outline_height = normalized_width * 0.75; 446a46c0ec8Sopenharmony_ci int center_x, center_y; 447a46c0ec8Sopenharmony_ci int width, height; 448a46c0ec8Sopenharmony_ci int x, y; 449a46c0ec8Sopenharmony_ci 450a46c0ec8Sopenharmony_ci cairo_save(cr); 451a46c0ec8Sopenharmony_ci 452a46c0ec8Sopenharmony_ci center_x = w->width/2 + 400; 453a46c0ec8Sopenharmony_ci center_y = w->height/2; 454a46c0ec8Sopenharmony_ci 455a46c0ec8Sopenharmony_ci /* Always the outline even if we didn't get any abs events yet so it 456a46c0ec8Sopenharmony_ci * doesn't just appear out of nowhere */ 457a46c0ec8Sopenharmony_ci if (w->evdev.device == 0) 458a46c0ec8Sopenharmony_ci goto draw_outline; 459a46c0ec8Sopenharmony_ci 460a46c0ec8Sopenharmony_ci /* device has changed, so the abs proportions/dimensions have 461a46c0ec8Sopenharmony_ci * changed. */ 462a46c0ec8Sopenharmony_ci if (w->evdev.device != w->evdev.last_device) { 463a46c0ec8Sopenharmony_ci struct evdev_device *d; 464a46c0ec8Sopenharmony_ci 465a46c0ec8Sopenharmony_ci ax = NULL; 466a46c0ec8Sopenharmony_ci ay = NULL; 467a46c0ec8Sopenharmony_ci 468a46c0ec8Sopenharmony_ci list_for_each(d, &w->evdev_devices, node) { 469a46c0ec8Sopenharmony_ci if ((uintptr_t)d->libinput_device != w->evdev.device) 470a46c0ec8Sopenharmony_ci continue; 471a46c0ec8Sopenharmony_ci 472a46c0ec8Sopenharmony_ci ax = libevdev_get_abs_info(d->evdev, ABS_X); 473a46c0ec8Sopenharmony_ci ay = libevdev_get_abs_info(d->evdev, ABS_Y); 474a46c0ec8Sopenharmony_ci w->evdev.last_device = w->evdev.device; 475a46c0ec8Sopenharmony_ci } 476a46c0ec8Sopenharmony_ci 477a46c0ec8Sopenharmony_ci } 478a46c0ec8Sopenharmony_ci if (ax == NULL || ay == NULL) 479a46c0ec8Sopenharmony_ci goto draw_outline; 480a46c0ec8Sopenharmony_ci 481a46c0ec8Sopenharmony_ci width = ax->maximum - ax->minimum; 482a46c0ec8Sopenharmony_ci height = ay->maximum - ay->minimum; 483a46c0ec8Sopenharmony_ci outline_height = 1.0 * height/width * normalized_width; 484a46c0ec8Sopenharmony_ci outline_width = normalized_width; 485a46c0ec8Sopenharmony_ci 486a46c0ec8Sopenharmony_ci x = 1.0 * (w->evdev.x - ax->minimum)/width * outline_width; 487a46c0ec8Sopenharmony_ci y = 1.0 * (w->evdev.y - ay->minimum)/height * outline_height; 488a46c0ec8Sopenharmony_ci x += center_x - outline_width/2; 489a46c0ec8Sopenharmony_ci y += center_y - outline_height/2; 490a46c0ec8Sopenharmony_ci cairo_arc(cr, x, y, 10, 0, 2 * M_PI); 491a46c0ec8Sopenharmony_ci cairo_fill(cr); 492a46c0ec8Sopenharmony_ci 493a46c0ec8Sopenharmony_ci for (size_t i = 0; i < ARRAY_LENGTH(w->evdev.slots); i++) { 494a46c0ec8Sopenharmony_ci if (!w->evdev.slots[i].active) 495a46c0ec8Sopenharmony_ci continue; 496a46c0ec8Sopenharmony_ci 497a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .2, .8); 498a46c0ec8Sopenharmony_ci x = w->evdev.slots[i].x; 499a46c0ec8Sopenharmony_ci y = w->evdev.slots[i].y; 500a46c0ec8Sopenharmony_ci x = 1.0 * (x - ax->minimum)/width * outline_width; 501a46c0ec8Sopenharmony_ci y = 1.0 * (y - ay->minimum)/height * outline_height; 502a46c0ec8Sopenharmony_ci x += center_x - outline_width/2; 503a46c0ec8Sopenharmony_ci y += center_y - outline_height/2; 504a46c0ec8Sopenharmony_ci cairo_arc(cr, x, y, 10, 0, 2 * M_PI); 505a46c0ec8Sopenharmony_ci cairo_fill(cr); 506a46c0ec8Sopenharmony_ci 507a46c0ec8Sopenharmony_ci char finger_text[3]; 508a46c0ec8Sopenharmony_ci cairo_text_extents_t finger_text_extents; 509a46c0ec8Sopenharmony_ci snprintf(finger_text, 3, "%zu", i); 510a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 1.f, 1.f, 1.f); 511a46c0ec8Sopenharmony_ci cairo_set_font_size(cr, 12.0); 512a46c0ec8Sopenharmony_ci cairo_text_extents(cr, finger_text, &finger_text_extents); 513a46c0ec8Sopenharmony_ci cairo_move_to(cr, x - finger_text_extents.width/2, 514a46c0ec8Sopenharmony_ci y + finger_text_extents.height/2); 515a46c0ec8Sopenharmony_ci cairo_show_text(cr, finger_text); 516a46c0ec8Sopenharmony_ci } 517a46c0ec8Sopenharmony_ci 518a46c0ec8Sopenharmony_cidraw_outline: 519a46c0ec8Sopenharmony_ci /* The touchpad outline */ 520a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .2, .8); 521a46c0ec8Sopenharmony_ci cairo_rectangle(cr, 522a46c0ec8Sopenharmony_ci center_x - outline_width/2, 523a46c0ec8Sopenharmony_ci center_y - outline_height/2, 524a46c0ec8Sopenharmony_ci outline_width, 525a46c0ec8Sopenharmony_ci outline_height); 526a46c0ec8Sopenharmony_ci cairo_stroke(cr); 527a46c0ec8Sopenharmony_ci cairo_restore(cr); 528a46c0ec8Sopenharmony_ci} 529a46c0ec8Sopenharmony_ci 530a46c0ec8Sopenharmony_cistatic inline void 531a46c0ec8Sopenharmony_cidraw_gestures(struct window *w, cairo_t *cr) 532a46c0ec8Sopenharmony_ci{ 533a46c0ec8Sopenharmony_ci int offset; 534a46c0ec8Sopenharmony_ci 535a46c0ec8Sopenharmony_ci /* swipe */ 536a46c0ec8Sopenharmony_ci cairo_save(cr); 537a46c0ec8Sopenharmony_ci cairo_translate(cr, w->swipe.x, w->swipe.y); 538a46c0ec8Sopenharmony_ci for (int i = 0; i < w->swipe.nfingers; i++) { 539a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .8, .8, .4); 540a46c0ec8Sopenharmony_ci cairo_arc(cr, (i - 2) * 40, 0, 20, 0, 2 * M_PI); 541a46c0ec8Sopenharmony_ci cairo_fill(cr); 542a46c0ec8Sopenharmony_ci } 543a46c0ec8Sopenharmony_ci 544a46c0ec8Sopenharmony_ci for (int i = 0; i < 4; i++) { /* 4 fg max */ 545a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 0, 0, 0); 546a46c0ec8Sopenharmony_ci cairo_arc(cr, (i - 2) * 40, 0, 20, 0, 2 * M_PI); 547a46c0ec8Sopenharmony_ci cairo_stroke(cr); 548a46c0ec8Sopenharmony_ci } 549a46c0ec8Sopenharmony_ci cairo_restore(cr); 550a46c0ec8Sopenharmony_ci 551a46c0ec8Sopenharmony_ci /* pinch */ 552a46c0ec8Sopenharmony_ci cairo_save(cr); 553a46c0ec8Sopenharmony_ci offset = w->pinch.scale * 100; 554a46c0ec8Sopenharmony_ci cairo_translate(cr, w->pinch.x, w->pinch.y); 555a46c0ec8Sopenharmony_ci cairo_rotate(cr, w->pinch.angle * M_PI/180.0); 556a46c0ec8Sopenharmony_ci if (w->pinch.nfingers > 0) { 557a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .4, .4, .8); 558a46c0ec8Sopenharmony_ci cairo_arc(cr, offset, -offset, 20, 0, 2 * M_PI); 559a46c0ec8Sopenharmony_ci cairo_arc(cr, -offset, offset, 20, 0, 2 * M_PI); 560a46c0ec8Sopenharmony_ci cairo_fill(cr); 561a46c0ec8Sopenharmony_ci } 562a46c0ec8Sopenharmony_ci 563a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 0, 0, 0); 564a46c0ec8Sopenharmony_ci cairo_arc(cr, offset, -offset, 20, 0, 2 * M_PI); 565a46c0ec8Sopenharmony_ci cairo_stroke(cr); 566a46c0ec8Sopenharmony_ci cairo_arc(cr, -offset, offset, 20, 0, 2 * M_PI); 567a46c0ec8Sopenharmony_ci cairo_stroke(cr); 568a46c0ec8Sopenharmony_ci 569a46c0ec8Sopenharmony_ci cairo_restore(cr); 570a46c0ec8Sopenharmony_ci 571a46c0ec8Sopenharmony_ci /* hold */ 572a46c0ec8Sopenharmony_ci cairo_save(cr); 573a46c0ec8Sopenharmony_ci cairo_translate(cr, w->width/2, w->height/2 + 100); 574a46c0ec8Sopenharmony_ci 575a46c0ec8Sopenharmony_ci for (int i = 4; i > 0; i--) { /* 4 fg max */ 576a46c0ec8Sopenharmony_ci double r, g, b, hold_alpha; 577a46c0ec8Sopenharmony_ci 578a46c0ec8Sopenharmony_ci r = .4 + .2 * (i % 2); 579a46c0ec8Sopenharmony_ci g = .2; 580a46c0ec8Sopenharmony_ci b = .2; 581a46c0ec8Sopenharmony_ci hold_alpha = (w->hold.active && i <= w->hold.nfingers) ? 1 : .5; 582a46c0ec8Sopenharmony_ci 583a46c0ec8Sopenharmony_ci cairo_set_source_rgba(cr, r, g, b, hold_alpha); 584a46c0ec8Sopenharmony_ci cairo_arc(cr, 0, 0, 20 * i, 0, 2 * M_PI); 585a46c0ec8Sopenharmony_ci cairo_fill(cr); 586a46c0ec8Sopenharmony_ci 587a46c0ec8Sopenharmony_ci cairo_set_source_rgba(cr, 0, 0, 0, hold_alpha); 588a46c0ec8Sopenharmony_ci cairo_arc(cr, 0, 0, 20 * i, 0, 2 * M_PI); 589a46c0ec8Sopenharmony_ci cairo_stroke(cr); 590a46c0ec8Sopenharmony_ci } 591a46c0ec8Sopenharmony_ci 592a46c0ec8Sopenharmony_ci cairo_restore(cr); 593a46c0ec8Sopenharmony_ci} 594a46c0ec8Sopenharmony_ci 595a46c0ec8Sopenharmony_cistatic inline void 596a46c0ec8Sopenharmony_cidraw_scrollbars(struct window *w, cairo_t *cr) 597a46c0ec8Sopenharmony_ci{ 598a46c0ec8Sopenharmony_ci 599a46c0ec8Sopenharmony_ci /* normal scrollbars */ 600a46c0ec8Sopenharmony_ci cairo_save(cr); 601a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .4, .8, 0); 602a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->scroll.vx - 10, w->scroll.vy - 20, 20, 40); 603a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->scroll.hx - 20, w->scroll.hy - 10, 40, 20); 604a46c0ec8Sopenharmony_ci cairo_fill(cr); 605a46c0ec8Sopenharmony_ci 606a46c0ec8Sopenharmony_ci /* discrete scrollbars */ 607a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .8, .4, 0); 608a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->scroll.vx_discrete - 5, w->scroll.vy_discrete - 10, 10, 20); 609a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->scroll.hx_discrete - 10, w->scroll.hy_discrete - 5, 20, 10); 610a46c0ec8Sopenharmony_ci cairo_fill(cr); 611a46c0ec8Sopenharmony_ci 612a46c0ec8Sopenharmony_ci cairo_restore(cr); 613a46c0ec8Sopenharmony_ci} 614a46c0ec8Sopenharmony_ci 615a46c0ec8Sopenharmony_cistatic inline void 616a46c0ec8Sopenharmony_cidraw_touchpoints(struct window *w, cairo_t *cr) 617a46c0ec8Sopenharmony_ci{ 618a46c0ec8Sopenharmony_ci cairo_save(cr); 619a46c0ec8Sopenharmony_ci ARRAY_FOR_EACH(w->touches, t) { 620a46c0ec8Sopenharmony_ci if (t->state == TOUCH_ACTIVE) 621a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .8, .2, .2); 622a46c0ec8Sopenharmony_ci else 623a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .8, .4, .4); 624a46c0ec8Sopenharmony_ci cairo_arc(cr, t->x, t->y, 10, 0, 2 * M_PI); 625a46c0ec8Sopenharmony_ci if (t->state == TOUCH_CANCELLED) 626a46c0ec8Sopenharmony_ci cairo_stroke(cr); 627a46c0ec8Sopenharmony_ci else 628a46c0ec8Sopenharmony_ci cairo_fill(cr); 629a46c0ec8Sopenharmony_ci } 630a46c0ec8Sopenharmony_ci cairo_restore(cr); 631a46c0ec8Sopenharmony_ci} 632a46c0ec8Sopenharmony_ci 633a46c0ec8Sopenharmony_cistatic inline void 634a46c0ec8Sopenharmony_cidraw_abs_pointer(struct window *w, cairo_t *cr) 635a46c0ec8Sopenharmony_ci{ 636a46c0ec8Sopenharmony_ci 637a46c0ec8Sopenharmony_ci cairo_save(cr); 638a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .4, .8); 639a46c0ec8Sopenharmony_ci cairo_arc(cr, w->abs.x, w->abs.y, 10, 0, 2 * M_PI); 640a46c0ec8Sopenharmony_ci cairo_fill(cr); 641a46c0ec8Sopenharmony_ci cairo_restore(cr); 642a46c0ec8Sopenharmony_ci} 643a46c0ec8Sopenharmony_ci 644a46c0ec8Sopenharmony_cistatic inline void 645a46c0ec8Sopenharmony_cidraw_text(cairo_t *cr, const char *text, double x, double y) 646a46c0ec8Sopenharmony_ci{ 647a46c0ec8Sopenharmony_ci cairo_text_extents_t te; 648a46c0ec8Sopenharmony_ci cairo_font_extents_t fe; 649a46c0ec8Sopenharmony_ci 650a46c0ec8Sopenharmony_ci cairo_text_extents(cr, text, &te); 651a46c0ec8Sopenharmony_ci cairo_font_extents(cr, &fe); 652a46c0ec8Sopenharmony_ci /* center of the rectangle */ 653a46c0ec8Sopenharmony_ci cairo_move_to(cr, x, y); 654a46c0ec8Sopenharmony_ci cairo_rel_move_to(cr, -te.width/2, -fe.descent + te.height/2); 655a46c0ec8Sopenharmony_ci cairo_show_text(cr, text); 656a46c0ec8Sopenharmony_ci} 657a46c0ec8Sopenharmony_ci 658a46c0ec8Sopenharmony_cistatic inline void 659a46c0ec8Sopenharmony_cidraw_other_button (struct window *w, cairo_t *cr) 660a46c0ec8Sopenharmony_ci{ 661a46c0ec8Sopenharmony_ci const char *name = w->buttons.other_name; 662a46c0ec8Sopenharmony_ci 663a46c0ec8Sopenharmony_ci cairo_save(cr); 664a46c0ec8Sopenharmony_ci 665a46c0ec8Sopenharmony_ci if (!w->buttons.other) 666a46c0ec8Sopenharmony_ci goto outline; 667a46c0ec8Sopenharmony_ci 668a46c0ec8Sopenharmony_ci if (!name) 669a46c0ec8Sopenharmony_ci name = "undefined"; 670a46c0ec8Sopenharmony_ci 671a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .8, .8); 672a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->width/2 - 40, w->height - 150, 80, 30); 673a46c0ec8Sopenharmony_ci cairo_fill(cr); 674a46c0ec8Sopenharmony_ci 675a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 0, 0, 0); 676a46c0ec8Sopenharmony_ci 677a46c0ec8Sopenharmony_ci draw_text(cr, name, w->width/2, w->height - 150 + 15); 678a46c0ec8Sopenharmony_ci 679a46c0ec8Sopenharmony_cioutline: 680a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 0, 0, 0); 681a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->width/2 - 40, w->height - 150, 80, 30); 682a46c0ec8Sopenharmony_ci cairo_stroke(cr); 683a46c0ec8Sopenharmony_ci cairo_restore(cr); 684a46c0ec8Sopenharmony_ci} 685a46c0ec8Sopenharmony_ci 686a46c0ec8Sopenharmony_cistatic inline void 687a46c0ec8Sopenharmony_cidraw_buttons(struct window *w, cairo_t *cr) 688a46c0ec8Sopenharmony_ci{ 689a46c0ec8Sopenharmony_ci cairo_save(cr); 690a46c0ec8Sopenharmony_ci 691a46c0ec8Sopenharmony_ci if (w->buttons.l || w->buttons.m || w->buttons.r) { 692a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .8, .8); 693a46c0ec8Sopenharmony_ci if (w->buttons.l) 694a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->width/2 - 100, w->height - 200, 70, 30); 695a46c0ec8Sopenharmony_ci if (w->buttons.m) 696a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->width/2 - 20, w->height - 200, 40, 30); 697a46c0ec8Sopenharmony_ci if (w->buttons.r) 698a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->width/2 + 30, w->height - 200, 70, 30); 699a46c0ec8Sopenharmony_ci cairo_fill(cr); 700a46c0ec8Sopenharmony_ci } 701a46c0ec8Sopenharmony_ci 702a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 0, 0, 0); 703a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->width/2 - 100, w->height - 200, 70, 30); 704a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->width/2 - 20, w->height - 200, 40, 30); 705a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->width/2 + 30, w->height - 200, 70, 30); 706a46c0ec8Sopenharmony_ci cairo_stroke(cr); 707a46c0ec8Sopenharmony_ci cairo_restore(cr); 708a46c0ec8Sopenharmony_ci 709a46c0ec8Sopenharmony_ci draw_other_button(w, cr); 710a46c0ec8Sopenharmony_ci} 711a46c0ec8Sopenharmony_ci 712a46c0ec8Sopenharmony_cistatic inline void 713a46c0ec8Sopenharmony_cidraw_pad(struct window *w, cairo_t *cr) 714a46c0ec8Sopenharmony_ci{ 715a46c0ec8Sopenharmony_ci double rx, ry; 716a46c0ec8Sopenharmony_ci double pos; 717a46c0ec8Sopenharmony_ci char number[3]; 718a46c0ec8Sopenharmony_ci 719a46c0ec8Sopenharmony_ci rx = w->width/2 - 200; 720a46c0ec8Sopenharmony_ci ry = w->height/2 + 100; 721a46c0ec8Sopenharmony_ci 722a46c0ec8Sopenharmony_ci cairo_save(cr); 723a46c0ec8Sopenharmony_ci /* outer ring */ 724a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .7, .7, .0); 725a46c0ec8Sopenharmony_ci cairo_arc(cr, rx, ry, 50, 0, 2 * M_PI); 726a46c0ec8Sopenharmony_ci cairo_fill(cr); 727a46c0ec8Sopenharmony_ci 728a46c0ec8Sopenharmony_ci /* inner ring */ 729a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 1., 1., 1.); 730a46c0ec8Sopenharmony_ci cairo_arc(cr, rx, ry, 30, 0, 2 * M_PI); 731a46c0ec8Sopenharmony_ci cairo_fill(cr); 732a46c0ec8Sopenharmony_ci 733a46c0ec8Sopenharmony_ci /* marker */ 734a46c0ec8Sopenharmony_ci /* libinput has degrees and 0 is north, cairo has radians and 0 is 735a46c0ec8Sopenharmony_ci * east */ 736a46c0ec8Sopenharmony_ci if (w->pad.ring.position != -1) { 737a46c0ec8Sopenharmony_ci pos = (w->pad.ring.position + 270) * M_PI/180.0; 738a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .0, .0, .0); 739a46c0ec8Sopenharmony_ci cairo_set_line_width(cr, 20); 740a46c0ec8Sopenharmony_ci cairo_arc(cr, rx, ry, 40, pos - M_PI/8 , pos + M_PI/8); 741a46c0ec8Sopenharmony_ci cairo_stroke(cr); 742a46c0ec8Sopenharmony_ci 743a46c0ec8Sopenharmony_ci snprintf(number, sizeof(number), "%d", w->pad.ring.number); 744a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .0, .0, .0); 745a46c0ec8Sopenharmony_ci draw_text(cr, number, rx, ry); 746a46c0ec8Sopenharmony_ci 747a46c0ec8Sopenharmony_ci } 748a46c0ec8Sopenharmony_ci 749a46c0ec8Sopenharmony_ci cairo_restore(cr); 750a46c0ec8Sopenharmony_ci 751a46c0ec8Sopenharmony_ci rx = w->width/2 - 300; 752a46c0ec8Sopenharmony_ci ry = w->height/2 + 50; 753a46c0ec8Sopenharmony_ci 754a46c0ec8Sopenharmony_ci cairo_save(cr); 755a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .7, .7, .0); 756a46c0ec8Sopenharmony_ci cairo_rectangle(cr, rx, ry, 20, 100); 757a46c0ec8Sopenharmony_ci cairo_fill(cr); 758a46c0ec8Sopenharmony_ci 759a46c0ec8Sopenharmony_ci if (w->pad.strip.position != -1) { 760a46c0ec8Sopenharmony_ci pos = w->pad.strip.position * 80; 761a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .0, .0, .0); 762a46c0ec8Sopenharmony_ci cairo_rectangle(cr, rx, ry + pos, 20, 20); 763a46c0ec8Sopenharmony_ci cairo_fill(cr); 764a46c0ec8Sopenharmony_ci 765a46c0ec8Sopenharmony_ci snprintf(number, sizeof(number), "%d", w->pad.strip.number); 766a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .0, .0, .0); 767a46c0ec8Sopenharmony_ci draw_text(cr, number, rx + 10, ry - 10); 768a46c0ec8Sopenharmony_ci } 769a46c0ec8Sopenharmony_ci 770a46c0ec8Sopenharmony_ci cairo_restore(cr); 771a46c0ec8Sopenharmony_ci} 772a46c0ec8Sopenharmony_ci 773a46c0ec8Sopenharmony_cistatic inline void 774a46c0ec8Sopenharmony_cidraw_tablet(struct window *w, cairo_t *cr) 775a46c0ec8Sopenharmony_ci{ 776a46c0ec8Sopenharmony_ci double x, y; 777a46c0ec8Sopenharmony_ci int first, last; 778a46c0ec8Sopenharmony_ci size_t mask; 779a46c0ec8Sopenharmony_ci int rx, ry; 780a46c0ec8Sopenharmony_ci 781a46c0ec8Sopenharmony_ci /* pressure/distance bars */ 782a46c0ec8Sopenharmony_ci rx = w->width/2 + 100; 783a46c0ec8Sopenharmony_ci ry = w->height/2 + 50; 784a46c0ec8Sopenharmony_ci cairo_save(cr); 785a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .6, .6); 786a46c0ec8Sopenharmony_ci cairo_rectangle(cr, rx, ry, 20, 100); 787a46c0ec8Sopenharmony_ci cairo_stroke(cr); 788a46c0ec8Sopenharmony_ci 789a46c0ec8Sopenharmony_ci if (w->tool.distance > 0) { 790a46c0ec8Sopenharmony_ci double pos = w->tool.distance * 100; 791a46c0ec8Sopenharmony_ci cairo_rectangle(cr, rx, ry + 100 - pos, 20, 5); 792a46c0ec8Sopenharmony_ci cairo_fill(cr); 793a46c0ec8Sopenharmony_ci } 794a46c0ec8Sopenharmony_ci if (w->tool.pressure > 0) { 795a46c0ec8Sopenharmony_ci double pos = w->tool.pressure * 100; 796a46c0ec8Sopenharmony_ci if (w->tool.is_down) 797a46c0ec8Sopenharmony_ci cairo_rectangle(cr, rx + 25, ry + 95, 5, 5); 798a46c0ec8Sopenharmony_ci cairo_rectangle(cr, rx, ry + 100 - pos, 20, pos); 799a46c0ec8Sopenharmony_ci cairo_fill(cr); 800a46c0ec8Sopenharmony_ci } 801a46c0ec8Sopenharmony_ci cairo_restore(cr); 802a46c0ec8Sopenharmony_ci 803a46c0ec8Sopenharmony_ci /* tablet tool, square for prox-in location */ 804a46c0ec8Sopenharmony_ci cairo_save(cr); 805a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .6, .6); 806a46c0ec8Sopenharmony_ci if (w->tool.x_in && w->tool.y_in) { 807a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->tool.x_in - 15, w->tool.y_in - 15, 30, 30); 808a46c0ec8Sopenharmony_ci cairo_stroke(cr); 809a46c0ec8Sopenharmony_ci } 810a46c0ec8Sopenharmony_ci 811a46c0ec8Sopenharmony_ci if (w->tool.x_down && w->tool.y_down) { 812a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->tool.x_down - 10, w->tool.y_down - 10, 20, 20); 813a46c0ec8Sopenharmony_ci cairo_stroke(cr); 814a46c0ec8Sopenharmony_ci } 815a46c0ec8Sopenharmony_ci 816a46c0ec8Sopenharmony_ci if (w->tool.x_up && w->tool.y_up) { 817a46c0ec8Sopenharmony_ci cairo_rectangle(cr, w->tool.x_up - 10, w->tool.y_up - 10, 20, 20); 818a46c0ec8Sopenharmony_ci cairo_stroke(cr); 819a46c0ec8Sopenharmony_ci } 820a46c0ec8Sopenharmony_ci 821a46c0ec8Sopenharmony_ci if (w->tool.pressure) 822a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .2, .8, .8); 823a46c0ec8Sopenharmony_ci 824a46c0ec8Sopenharmony_ci cairo_translate(cr, w->tool.x, w->tool.y); 825a46c0ec8Sopenharmony_ci /* scale of 2.5 is large enough to make the marker visible around the 826a46c0ec8Sopenharmony_ci physical totem */ 827a46c0ec8Sopenharmony_ci cairo_scale(cr, 828a46c0ec8Sopenharmony_ci 1.0 + w->tool.size_major * 2.5, 829a46c0ec8Sopenharmony_ci 1.0 + w->tool.size_minor * 2.5); 830a46c0ec8Sopenharmony_ci cairo_scale(cr, 1.0 + w->tool.tilt_x/30.0, 1.0 + w->tool.tilt_y/30.0); 831a46c0ec8Sopenharmony_ci if (w->tool.rotation) 832a46c0ec8Sopenharmony_ci cairo_rotate(cr, w->tool.rotation * M_PI/180.0); 833a46c0ec8Sopenharmony_ci if (w->tool.pressure) 834a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .8, .8, .2); 835a46c0ec8Sopenharmony_ci cairo_arc(cr, 0, 0, 836a46c0ec8Sopenharmony_ci 1 + 10 * max(w->tool.pressure, w->tool.distance), 837a46c0ec8Sopenharmony_ci 0, 2 * M_PI); 838a46c0ec8Sopenharmony_ci cairo_fill(cr); 839a46c0ec8Sopenharmony_ci cairo_restore(cr); 840a46c0ec8Sopenharmony_ci 841a46c0ec8Sopenharmony_ci /* The line to indicate the origin */ 842a46c0ec8Sopenharmony_ci if (w->tool.size_major) { 843a46c0ec8Sopenharmony_ci cairo_save(cr); 844a46c0ec8Sopenharmony_ci cairo_scale(cr, 1.0, 1.0); 845a46c0ec8Sopenharmony_ci cairo_translate(cr, w->tool.x, w->tool.y); 846a46c0ec8Sopenharmony_ci if (w->tool.rotation) 847a46c0ec8Sopenharmony_ci cairo_rotate(cr, w->tool.rotation * M_PI/180.0); 848a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .0, .0, .0); 849a46c0ec8Sopenharmony_ci cairo_move_to(cr, 0, 0); 850a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 0, -w->tool.size_major * 2.5); 851a46c0ec8Sopenharmony_ci cairo_stroke(cr); 852a46c0ec8Sopenharmony_ci cairo_restore(cr); 853a46c0ec8Sopenharmony_ci } 854a46c0ec8Sopenharmony_ci 855a46c0ec8Sopenharmony_ci /* tablet deltas */ 856a46c0ec8Sopenharmony_ci mask = ARRAY_LENGTH(w->tool.deltas); 857a46c0ec8Sopenharmony_ci first = max(w->tool.ndeltas + 1, mask) - mask; 858a46c0ec8Sopenharmony_ci last = w->tool.ndeltas; 859a46c0ec8Sopenharmony_ci 860a46c0ec8Sopenharmony_ci cairo_save(cr); 861a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .8, .8, .2); 862a46c0ec8Sopenharmony_ci 863a46c0ec8Sopenharmony_ci x = w->tool.deltas[first % mask].x; 864a46c0ec8Sopenharmony_ci y = w->tool.deltas[first % mask].y; 865a46c0ec8Sopenharmony_ci cairo_move_to(cr, x, y); 866a46c0ec8Sopenharmony_ci 867a46c0ec8Sopenharmony_ci for (int i = first + 1; i < last; i++) { 868a46c0ec8Sopenharmony_ci x = w->tool.deltas[i % mask].x; 869a46c0ec8Sopenharmony_ci y = w->tool.deltas[i % mask].y; 870a46c0ec8Sopenharmony_ci cairo_line_to(cr, x, y); 871a46c0ec8Sopenharmony_ci } 872a46c0ec8Sopenharmony_ci 873a46c0ec8Sopenharmony_ci cairo_stroke(cr); 874a46c0ec8Sopenharmony_ci cairo_restore(cr); 875a46c0ec8Sopenharmony_ci} 876a46c0ec8Sopenharmony_ci 877a46c0ec8Sopenharmony_cistatic inline void 878a46c0ec8Sopenharmony_cidraw_pointer(struct window *w, cairo_t *cr) 879a46c0ec8Sopenharmony_ci{ 880a46c0ec8Sopenharmony_ci double x, y; 881a46c0ec8Sopenharmony_ci int first, last; 882a46c0ec8Sopenharmony_ci size_t mask; 883a46c0ec8Sopenharmony_ci 884a46c0ec8Sopenharmony_ci /* draw pointer sprite */ 885a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 0, 0, 0); 886a46c0ec8Sopenharmony_ci cairo_save(cr); 887a46c0ec8Sopenharmony_ci cairo_move_to(cr, w->pointer.x, w->pointer.y); 888a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 10, 15); 889a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, -10, 0); 890a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 0, -15); 891a46c0ec8Sopenharmony_ci cairo_fill(cr); 892a46c0ec8Sopenharmony_ci 893a46c0ec8Sopenharmony_ci /* draw unaccelerated sprite */ 894a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); 895a46c0ec8Sopenharmony_ci cairo_save(cr); 896a46c0ec8Sopenharmony_ci cairo_move_to(cr, w->unaccelerated.x, w->unaccelerated.y); 897a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, -5, -10); 898a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 10, 0); 899a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, -5, 10); 900a46c0ec8Sopenharmony_ci cairo_fill(cr); 901a46c0ec8Sopenharmony_ci 902a46c0ec8Sopenharmony_ci /* pointer deltas */ 903a46c0ec8Sopenharmony_ci mask = ARRAY_LENGTH(w->deltas); 904a46c0ec8Sopenharmony_ci first = max(w->ndeltas + 1, mask) - mask; 905a46c0ec8Sopenharmony_ci last = w->ndeltas; 906a46c0ec8Sopenharmony_ci 907a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, .8, .5, .2); 908a46c0ec8Sopenharmony_ci 909a46c0ec8Sopenharmony_ci x = w->deltas[first % mask].x; 910a46c0ec8Sopenharmony_ci y = w->deltas[first % mask].y; 911a46c0ec8Sopenharmony_ci cairo_move_to(cr, x, y); 912a46c0ec8Sopenharmony_ci 913a46c0ec8Sopenharmony_ci for (int i = first + 1; i < last; i++) { 914a46c0ec8Sopenharmony_ci x = w->deltas[i % mask].x; 915a46c0ec8Sopenharmony_ci y = w->deltas[i % mask].y; 916a46c0ec8Sopenharmony_ci cairo_line_to(cr, x, y); 917a46c0ec8Sopenharmony_ci } 918a46c0ec8Sopenharmony_ci 919a46c0ec8Sopenharmony_ci cairo_stroke(cr); 920a46c0ec8Sopenharmony_ci cairo_restore(cr); 921a46c0ec8Sopenharmony_ci} 922a46c0ec8Sopenharmony_ci 923a46c0ec8Sopenharmony_cistatic inline void 924a46c0ec8Sopenharmony_cidraw_background(struct window *w, cairo_t *cr) 925a46c0ec8Sopenharmony_ci{ 926a46c0ec8Sopenharmony_ci int x1, x2, y1, y2, x3, y3, x4, y4; 927a46c0ec8Sopenharmony_ci int cols; 928a46c0ec8Sopenharmony_ci 929a46c0ec8Sopenharmony_ci /* 10px and 5px grids */ 930a46c0ec8Sopenharmony_ci cairo_save(cr); 931a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); 932a46c0ec8Sopenharmony_ci x1 = w->width/2 - 200; 933a46c0ec8Sopenharmony_ci y1 = w->height/2 - 200; 934a46c0ec8Sopenharmony_ci x2 = w->width/2 + 200; 935a46c0ec8Sopenharmony_ci y2 = w->height/2 - 200; 936a46c0ec8Sopenharmony_ci for (cols = 1; cols < 10; cols++) { 937a46c0ec8Sopenharmony_ci cairo_move_to(cr, x1 + 10 * cols, y1); 938a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 0, 100); 939a46c0ec8Sopenharmony_ci cairo_move_to(cr, x1, y1 + 10 * cols); 940a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 100, 0); 941a46c0ec8Sopenharmony_ci 942a46c0ec8Sopenharmony_ci cairo_move_to(cr, x2 + 5 * cols, y2); 943a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 0, 50); 944a46c0ec8Sopenharmony_ci cairo_move_to(cr, x2, y2 + 5 * cols); 945a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 50, 0); 946a46c0ec8Sopenharmony_ci } 947a46c0ec8Sopenharmony_ci 948a46c0ec8Sopenharmony_ci /* 3px horiz/vert bar codes */ 949a46c0ec8Sopenharmony_ci x3 = w->width/2 - 200; 950a46c0ec8Sopenharmony_ci y3 = w->height/2 + 200; 951a46c0ec8Sopenharmony_ci x4 = w->width/2 + 200; 952a46c0ec8Sopenharmony_ci y4 = w->height/2 + 100; 953a46c0ec8Sopenharmony_ci for (cols = 0; cols < 50; cols++) { 954a46c0ec8Sopenharmony_ci cairo_move_to(cr, x3 + 3 * cols, y3); 955a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 0, 20); 956a46c0ec8Sopenharmony_ci 957a46c0ec8Sopenharmony_ci cairo_move_to(cr, x4, y4 + 3 * cols); 958a46c0ec8Sopenharmony_ci cairo_rel_line_to(cr, 20, 0); 959a46c0ec8Sopenharmony_ci } 960a46c0ec8Sopenharmony_ci cairo_stroke(cr); 961a46c0ec8Sopenharmony_ci 962a46c0ec8Sopenharmony_ci /* round targets */ 963a46c0ec8Sopenharmony_ci for (int i = 0; i <= 3; i++) { 964a46c0ec8Sopenharmony_ci x1 = w->width * i/4.0; 965a46c0ec8Sopenharmony_ci x2 = w->width * i/4.0; 966a46c0ec8Sopenharmony_ci 967a46c0ec8Sopenharmony_ci y1 = w->height * 1.0/4.0; 968a46c0ec8Sopenharmony_ci y2 = w->height * 3.0/4.0; 969a46c0ec8Sopenharmony_ci 970a46c0ec8Sopenharmony_ci cairo_arc(cr, x1, y1, 10, 0, 2 * M_PI); 971a46c0ec8Sopenharmony_ci cairo_stroke(cr); 972a46c0ec8Sopenharmony_ci cairo_arc(cr, x2, y2, 10, 0, 2 * M_PI); 973a46c0ec8Sopenharmony_ci cairo_stroke(cr); 974a46c0ec8Sopenharmony_ci } 975a46c0ec8Sopenharmony_ci 976a46c0ec8Sopenharmony_ci cairo_restore(cr); 977a46c0ec8Sopenharmony_ci} 978a46c0ec8Sopenharmony_ci 979a46c0ec8Sopenharmony_cistatic gboolean 980a46c0ec8Sopenharmony_cidraw(GtkWidget *widget, cairo_t *cr, gpointer data) 981a46c0ec8Sopenharmony_ci{ 982a46c0ec8Sopenharmony_ci struct window *w = data; 983a46c0ec8Sopenharmony_ci 984a46c0ec8Sopenharmony_ci cairo_set_font_size(cr, 12.0); 985a46c0ec8Sopenharmony_ci cairo_set_source_rgb(cr, 1, 1, 1); 986a46c0ec8Sopenharmony_ci cairo_rectangle(cr, 0, 0, w->width, w->height); 987a46c0ec8Sopenharmony_ci cairo_fill(cr); 988a46c0ec8Sopenharmony_ci 989a46c0ec8Sopenharmony_ci draw_background(w, cr); 990a46c0ec8Sopenharmony_ci draw_evdev_rel(w, cr); 991a46c0ec8Sopenharmony_ci draw_evdev_abs(w, cr); 992a46c0ec8Sopenharmony_ci 993a46c0ec8Sopenharmony_ci draw_pad(w, cr); 994a46c0ec8Sopenharmony_ci draw_tablet(w, cr); 995a46c0ec8Sopenharmony_ci draw_gestures(w, cr); 996a46c0ec8Sopenharmony_ci draw_scrollbars(w, cr); 997a46c0ec8Sopenharmony_ci draw_touchpoints(w, cr); 998a46c0ec8Sopenharmony_ci draw_abs_pointer(w, cr); 999a46c0ec8Sopenharmony_ci draw_buttons(w, cr); 1000a46c0ec8Sopenharmony_ci draw_pointer(w, cr); 1001a46c0ec8Sopenharmony_ci 1002a46c0ec8Sopenharmony_ci return TRUE; 1003a46c0ec8Sopenharmony_ci} 1004a46c0ec8Sopenharmony_ci 1005a46c0ec8Sopenharmony_ci#if HAVE_GTK4 1006a46c0ec8Sopenharmony_cistatic void 1007a46c0ec8Sopenharmony_cidraw_gtk4(GtkDrawingArea *widget, 1008a46c0ec8Sopenharmony_ci cairo_t *cr, 1009a46c0ec8Sopenharmony_ci int width, 1010a46c0ec8Sopenharmony_ci int height, 1011a46c0ec8Sopenharmony_ci gpointer data) 1012a46c0ec8Sopenharmony_ci{ 1013a46c0ec8Sopenharmony_ci draw(GTK_WIDGET(widget), cr, data); 1014a46c0ec8Sopenharmony_ci} 1015a46c0ec8Sopenharmony_ci#endif 1016a46c0ec8Sopenharmony_ci 1017a46c0ec8Sopenharmony_cistatic void 1018a46c0ec8Sopenharmony_ciwindow_place_ui_elements(GtkWidget *widget, struct window *w) 1019a46c0ec8Sopenharmony_ci{ 1020a46c0ec8Sopenharmony_ci#if HAVE_GTK4 1021a46c0ec8Sopenharmony_ci w->width = gtk_widget_get_width(w->area); 1022a46c0ec8Sopenharmony_ci w->height = gtk_widget_get_height(w->area); 1023a46c0ec8Sopenharmony_ci#else 1024a46c0ec8Sopenharmony_ci gtk_window_get_size(GTK_WINDOW(widget), &w->width, &w->height); 1025a46c0ec8Sopenharmony_ci#endif 1026a46c0ec8Sopenharmony_ci 1027a46c0ec8Sopenharmony_ci w->pointer.x = w->width/2; 1028a46c0ec8Sopenharmony_ci w->pointer.y = w->height/2; 1029a46c0ec8Sopenharmony_ci w->unaccelerated.x = w->width/2; 1030a46c0ec8Sopenharmony_ci w->unaccelerated.y = w->height/2; 1031a46c0ec8Sopenharmony_ci w->deltas[0].x = w->pointer.x; 1032a46c0ec8Sopenharmony_ci w->deltas[0].y = w->pointer.y; 1033a46c0ec8Sopenharmony_ci 1034a46c0ec8Sopenharmony_ci w->scroll.vx = w->width/2; 1035a46c0ec8Sopenharmony_ci w->scroll.vy = w->height/2; 1036a46c0ec8Sopenharmony_ci w->scroll.hx = w->width/2; 1037a46c0ec8Sopenharmony_ci w->scroll.hy = w->height/2; 1038a46c0ec8Sopenharmony_ci w->scroll.vx_discrete = w->width/2; 1039a46c0ec8Sopenharmony_ci w->scroll.vy_discrete = w->height/2; 1040a46c0ec8Sopenharmony_ci w->scroll.hx_discrete = w->width/2; 1041a46c0ec8Sopenharmony_ci w->scroll.hy_discrete = w->height/2; 1042a46c0ec8Sopenharmony_ci 1043a46c0ec8Sopenharmony_ci w->swipe.x = w->width/2; 1044a46c0ec8Sopenharmony_ci w->swipe.y = w->height/2; 1045a46c0ec8Sopenharmony_ci 1046a46c0ec8Sopenharmony_ci w->pinch.scale = 1.0; 1047a46c0ec8Sopenharmony_ci w->pinch.x = w->width/2; 1048a46c0ec8Sopenharmony_ci w->pinch.y = w->height/2; 1049a46c0ec8Sopenharmony_ci} 1050a46c0ec8Sopenharmony_ci 1051a46c0ec8Sopenharmony_ci#if HAVE_GTK4 1052a46c0ec8Sopenharmony_cistatic void 1053a46c0ec8Sopenharmony_cimap_event_cb(GtkDrawingArea *widget, int width, int height, gpointer data) 1054a46c0ec8Sopenharmony_ci{ 1055a46c0ec8Sopenharmony_ci struct window *w = data; 1056a46c0ec8Sopenharmony_ci 1057a46c0ec8Sopenharmony_ci window_place_ui_elements(GTK_WIDGET(widget), w); 1058a46c0ec8Sopenharmony_ci 1059a46c0ec8Sopenharmony_ci gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(w->area), 1060a46c0ec8Sopenharmony_ci draw_gtk4, 1061a46c0ec8Sopenharmony_ci w, 1062a46c0ec8Sopenharmony_ci NULL); 1063a46c0ec8Sopenharmony_ci 1064a46c0ec8Sopenharmony_ci gtk_widget_set_cursor_from_name(w->win, "none"); 1065a46c0ec8Sopenharmony_ci 1066a46c0ec8Sopenharmony_ci window_lock_pointer(w); 1067a46c0ec8Sopenharmony_ci} 1068a46c0ec8Sopenharmony_ci#else 1069a46c0ec8Sopenharmony_cistatic void 1070a46c0ec8Sopenharmony_cimap_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) 1071a46c0ec8Sopenharmony_ci{ 1072a46c0ec8Sopenharmony_ci struct window *w = data; 1073a46c0ec8Sopenharmony_ci GdkDisplay *display; 1074a46c0ec8Sopenharmony_ci GdkWindow *window; 1075a46c0ec8Sopenharmony_ci 1076a46c0ec8Sopenharmony_ci window_place_ui_elements(widget, w); 1077a46c0ec8Sopenharmony_ci 1078a46c0ec8Sopenharmony_ci g_signal_connect(G_OBJECT(w->area), "draw", G_CALLBACK(draw), w); 1079a46c0ec8Sopenharmony_ci 1080a46c0ec8Sopenharmony_ci window = gdk_event_get_window(event); 1081a46c0ec8Sopenharmony_ci display = gdk_window_get_display(window); 1082a46c0ec8Sopenharmony_ci 1083a46c0ec8Sopenharmony_ci gdk_window_set_cursor(gtk_widget_get_window(w->win), 1084a46c0ec8Sopenharmony_ci gdk_cursor_new_for_display(display, 1085a46c0ec8Sopenharmony_ci GDK_BLANK_CURSOR)); 1086a46c0ec8Sopenharmony_ci 1087a46c0ec8Sopenharmony_ci window_lock_pointer(w); 1088a46c0ec8Sopenharmony_ci} 1089a46c0ec8Sopenharmony_ci#endif 1090a46c0ec8Sopenharmony_ci 1091a46c0ec8Sopenharmony_cistatic void 1092a46c0ec8Sopenharmony_ciwindow_quit(struct window *w) 1093a46c0ec8Sopenharmony_ci{ 1094a46c0ec8Sopenharmony_ci g_main_loop_quit(w->event_loop); 1095a46c0ec8Sopenharmony_ci} 1096a46c0ec8Sopenharmony_ci 1097a46c0ec8Sopenharmony_ci#if HAVE_GTK4 1098a46c0ec8Sopenharmony_cistatic gboolean 1099a46c0ec8Sopenharmony_ciwindow_delete_event_cb(GtkWindow *window, gpointer data) 1100a46c0ec8Sopenharmony_ci{ 1101a46c0ec8Sopenharmony_ci struct window *w = data; 1102a46c0ec8Sopenharmony_ci 1103a46c0ec8Sopenharmony_ci window_quit(w); 1104a46c0ec8Sopenharmony_ci 1105a46c0ec8Sopenharmony_ci return TRUE; 1106a46c0ec8Sopenharmony_ci} 1107a46c0ec8Sopenharmony_ci#else 1108a46c0ec8Sopenharmony_cistatic void 1109a46c0ec8Sopenharmony_ciwindow_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) 1110a46c0ec8Sopenharmony_ci{ 1111a46c0ec8Sopenharmony_ci struct window *w = data; 1112a46c0ec8Sopenharmony_ci 1113a46c0ec8Sopenharmony_ci window_quit(w); 1114a46c0ec8Sopenharmony_ci} 1115a46c0ec8Sopenharmony_ci#endif 1116a46c0ec8Sopenharmony_ci 1117a46c0ec8Sopenharmony_cistatic void 1118a46c0ec8Sopenharmony_ciwindow_init(struct window *w) 1119a46c0ec8Sopenharmony_ci{ 1120a46c0ec8Sopenharmony_ci list_init(&w->evdev_devices); 1121a46c0ec8Sopenharmony_ci 1122a46c0ec8Sopenharmony_ci#if HAVE_GTK4 1123a46c0ec8Sopenharmony_ci w->win = gtk_window_new(); 1124a46c0ec8Sopenharmony_ci#else 1125a46c0ec8Sopenharmony_ci w->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); 1126a46c0ec8Sopenharmony_ci#endif 1127a46c0ec8Sopenharmony_ci 1128a46c0ec8Sopenharmony_ci if (getenv("LIBINPUT_RUNNING_TEST_SUITE")) { 1129a46c0ec8Sopenharmony_ci#if HAVE_GTK4 1130a46c0ec8Sopenharmony_ci gtk_window_minimize(GTK_WINDOW(w->win)); 1131a46c0ec8Sopenharmony_ci#else 1132a46c0ec8Sopenharmony_ci gtk_window_iconify(GTK_WINDOW(w->win)); 1133a46c0ec8Sopenharmony_ci#endif 1134a46c0ec8Sopenharmony_ci } 1135a46c0ec8Sopenharmony_ci 1136a46c0ec8Sopenharmony_ci gtk_window_set_title(GTK_WINDOW(w->win), "libinput debugging tool"); 1137a46c0ec8Sopenharmony_ci gtk_window_set_default_size(GTK_WINDOW(w->win), 1024, 768); 1138a46c0ec8Sopenharmony_ci gtk_window_maximize(GTK_WINDOW(w->win)); 1139a46c0ec8Sopenharmony_ci gtk_window_set_resizable(GTK_WINDOW(w->win), TRUE); 1140a46c0ec8Sopenharmony_ci gtk_widget_realize(w->win); 1141a46c0ec8Sopenharmony_ci 1142a46c0ec8Sopenharmony_ci w->area = gtk_drawing_area_new(); 1143a46c0ec8Sopenharmony_ci 1144a46c0ec8Sopenharmony_ci#if HAVE_GTK4 1145a46c0ec8Sopenharmony_ci g_signal_connect(G_OBJECT(w->area), "resize", G_CALLBACK(map_event_cb), w); 1146a46c0ec8Sopenharmony_ci g_signal_connect(G_OBJECT(w->win), "close-request", G_CALLBACK(window_delete_event_cb), w); 1147a46c0ec8Sopenharmony_ci 1148a46c0ec8Sopenharmony_ci gtk_window_set_child(GTK_WINDOW(w->win), w->area); 1149a46c0ec8Sopenharmony_ci gtk_widget_set_visible(w->win, TRUE); 1150a46c0ec8Sopenharmony_ci#else 1151a46c0ec8Sopenharmony_ci g_signal_connect(G_OBJECT(w->win), "map-event", G_CALLBACK(map_event_cb), w); 1152a46c0ec8Sopenharmony_ci g_signal_connect(G_OBJECT(w->win), "delete-event", G_CALLBACK(window_delete_event_cb), w); 1153a46c0ec8Sopenharmony_ci 1154a46c0ec8Sopenharmony_ci gtk_widget_set_events(w->win, 0); 1155a46c0ec8Sopenharmony_ci gtk_widget_set_events(w->area, 0); 1156a46c0ec8Sopenharmony_ci 1157a46c0ec8Sopenharmony_ci gtk_container_add(GTK_CONTAINER(w->win), w->area); 1158a46c0ec8Sopenharmony_ci gtk_widget_show_all(w->win); 1159a46c0ec8Sopenharmony_ci#endif 1160a46c0ec8Sopenharmony_ci 1161a46c0ec8Sopenharmony_ci w->pad.ring.position = -1; 1162a46c0ec8Sopenharmony_ci w->pad.strip.position = -1; 1163a46c0ec8Sopenharmony_ci} 1164a46c0ec8Sopenharmony_ci 1165a46c0ec8Sopenharmony_cistatic void 1166a46c0ec8Sopenharmony_ciwindow_cleanup(struct window *w) 1167a46c0ec8Sopenharmony_ci{ 1168a46c0ec8Sopenharmony_ci ARRAY_FOR_EACH(w->devices, dev) { 1169a46c0ec8Sopenharmony_ci if (*dev) 1170a46c0ec8Sopenharmony_ci libinput_device_unref(*dev); 1171a46c0ec8Sopenharmony_ci } 1172a46c0ec8Sopenharmony_ci} 1173a46c0ec8Sopenharmony_ci 1174a46c0ec8Sopenharmony_cistatic void 1175a46c0ec8Sopenharmony_cichange_ptraccel(struct window *w, double amount) 1176a46c0ec8Sopenharmony_ci{ 1177a46c0ec8Sopenharmony_ci ARRAY_FOR_EACH(w->devices, dev) { 1178a46c0ec8Sopenharmony_ci double speed; 1179a46c0ec8Sopenharmony_ci enum libinput_config_status status; 1180a46c0ec8Sopenharmony_ci 1181a46c0ec8Sopenharmony_ci if (*dev == NULL) 1182a46c0ec8Sopenharmony_ci continue; 1183a46c0ec8Sopenharmony_ci 1184a46c0ec8Sopenharmony_ci if (!libinput_device_config_accel_is_available(*dev)) 1185a46c0ec8Sopenharmony_ci continue; 1186a46c0ec8Sopenharmony_ci 1187a46c0ec8Sopenharmony_ci speed = libinput_device_config_accel_get_speed(*dev); 1188a46c0ec8Sopenharmony_ci speed = clip(speed + amount, -1, 1); 1189a46c0ec8Sopenharmony_ci 1190a46c0ec8Sopenharmony_ci status = libinput_device_config_accel_set_speed(*dev, speed); 1191a46c0ec8Sopenharmony_ci 1192a46c0ec8Sopenharmony_ci if (status != LIBINPUT_CONFIG_STATUS_SUCCESS) { 1193a46c0ec8Sopenharmony_ci msg("%s: failed to change accel to %.2f (%s)\n", 1194a46c0ec8Sopenharmony_ci libinput_device_get_name(*dev), 1195a46c0ec8Sopenharmony_ci speed, 1196a46c0ec8Sopenharmony_ci libinput_config_status_to_str(status)); 1197a46c0ec8Sopenharmony_ci } else { 1198a46c0ec8Sopenharmony_ci printf("%s: speed is %.2f\n", 1199a46c0ec8Sopenharmony_ci libinput_device_get_name(*dev), 1200a46c0ec8Sopenharmony_ci speed); 1201a46c0ec8Sopenharmony_ci } 1202a46c0ec8Sopenharmony_ci 1203a46c0ec8Sopenharmony_ci } 1204a46c0ec8Sopenharmony_ci} 1205a46c0ec8Sopenharmony_ci 1206a46c0ec8Sopenharmony_cistatic int 1207a46c0ec8Sopenharmony_cihandle_event_evdev(GIOChannel *source, GIOCondition condition, gpointer data) 1208a46c0ec8Sopenharmony_ci{ 1209a46c0ec8Sopenharmony_ci struct libinput_device *dev = data; 1210a46c0ec8Sopenharmony_ci struct libinput *li = libinput_device_get_context(dev); 1211a46c0ec8Sopenharmony_ci struct window *w = libinput_get_user_data(li); 1212a46c0ec8Sopenharmony_ci struct evdev_device *d, 1213a46c0ec8Sopenharmony_ci *device = NULL; 1214a46c0ec8Sopenharmony_ci struct input_event e; 1215a46c0ec8Sopenharmony_ci int rc; 1216a46c0ec8Sopenharmony_ci 1217a46c0ec8Sopenharmony_ci list_for_each(d, &w->evdev_devices, node) { 1218a46c0ec8Sopenharmony_ci if (d->libinput_device == dev) { 1219a46c0ec8Sopenharmony_ci device = d; 1220a46c0ec8Sopenharmony_ci break; 1221a46c0ec8Sopenharmony_ci } 1222a46c0ec8Sopenharmony_ci } 1223a46c0ec8Sopenharmony_ci 1224a46c0ec8Sopenharmony_ci if (device == NULL) { 1225a46c0ec8Sopenharmony_ci msg("Unknown device: %s\n", libinput_device_get_name(dev)); 1226a46c0ec8Sopenharmony_ci return FALSE; 1227a46c0ec8Sopenharmony_ci } 1228a46c0ec8Sopenharmony_ci 1229a46c0ec8Sopenharmony_ci do { 1230a46c0ec8Sopenharmony_ci rc = libevdev_next_event(device->evdev, 1231a46c0ec8Sopenharmony_ci LIBEVDEV_READ_FLAG_NORMAL, 1232a46c0ec8Sopenharmony_ci &e); 1233a46c0ec8Sopenharmony_ci if (rc == -EAGAIN) { 1234a46c0ec8Sopenharmony_ci break; 1235a46c0ec8Sopenharmony_ci } else if (rc == LIBEVDEV_READ_STATUS_SYNC) { 1236a46c0ec8Sopenharmony_ci msg("SYN_DROPPED received\n"); 1237a46c0ec8Sopenharmony_ci goto out; 1238a46c0ec8Sopenharmony_ci } else if (rc != LIBEVDEV_READ_STATUS_SUCCESS) { 1239a46c0ec8Sopenharmony_ci msg("Error reading event: %s\n", strerror(-rc)); 1240a46c0ec8Sopenharmony_ci goto out; 1241a46c0ec8Sopenharmony_ci } 1242a46c0ec8Sopenharmony_ci 1243a46c0ec8Sopenharmony_ci#define EVENT(t_, c_) (t_ << 16 | c_) 1244a46c0ec8Sopenharmony_ci switch (EVENT(e.type, e.code)) { 1245a46c0ec8Sopenharmony_ci case EVENT(EV_REL, REL_X): 1246a46c0ec8Sopenharmony_ci w->evdev.rel_x = e.value; 1247a46c0ec8Sopenharmony_ci break; 1248a46c0ec8Sopenharmony_ci case EVENT(EV_REL, REL_Y): 1249a46c0ec8Sopenharmony_ci w->evdev.rel_y = e.value; 1250a46c0ec8Sopenharmony_ci break; 1251a46c0ec8Sopenharmony_ci case EVENT(EV_ABS, ABS_MT_SLOT): 1252a46c0ec8Sopenharmony_ci w->evdev.slot = min((unsigned int)e.value, 1253a46c0ec8Sopenharmony_ci ARRAY_LENGTH(w->evdev.slots) - 1); 1254a46c0ec8Sopenharmony_ci w->evdev.device = (uintptr_t)dev; 1255a46c0ec8Sopenharmony_ci break; 1256a46c0ec8Sopenharmony_ci case EVENT(EV_ABS, ABS_MT_TRACKING_ID): 1257a46c0ec8Sopenharmony_ci w->evdev.slots[w->evdev.slot].active = (e.value != -1); 1258a46c0ec8Sopenharmony_ci w->evdev.device = (uintptr_t)dev; 1259a46c0ec8Sopenharmony_ci break; 1260a46c0ec8Sopenharmony_ci case EVENT(EV_ABS, ABS_X): 1261a46c0ec8Sopenharmony_ci w->evdev.x = e.value; 1262a46c0ec8Sopenharmony_ci w->evdev.device = (uintptr_t)dev; 1263a46c0ec8Sopenharmony_ci break; 1264a46c0ec8Sopenharmony_ci case EVENT(EV_ABS, ABS_Y): 1265a46c0ec8Sopenharmony_ci w->evdev.y = e.value; 1266a46c0ec8Sopenharmony_ci w->evdev.device = (uintptr_t)dev; 1267a46c0ec8Sopenharmony_ci break; 1268a46c0ec8Sopenharmony_ci case EVENT(EV_ABS, ABS_MT_POSITION_X): 1269a46c0ec8Sopenharmony_ci w->evdev.slots[w->evdev.slot].x = e.value; 1270a46c0ec8Sopenharmony_ci w->evdev.device = (uintptr_t)dev; 1271a46c0ec8Sopenharmony_ci break; 1272a46c0ec8Sopenharmony_ci case EVENT(EV_ABS, ABS_MT_POSITION_Y): 1273a46c0ec8Sopenharmony_ci w->evdev.slots[w->evdev.slot].y = e.value; 1274a46c0ec8Sopenharmony_ci w->evdev.device = (uintptr_t)dev; 1275a46c0ec8Sopenharmony_ci break; 1276a46c0ec8Sopenharmony_ci } 1277a46c0ec8Sopenharmony_ci } while (rc == LIBEVDEV_READ_STATUS_SUCCESS); 1278a46c0ec8Sopenharmony_ci 1279a46c0ec8Sopenharmony_ci gtk_widget_queue_draw(w->area); 1280a46c0ec8Sopenharmony_ciout: 1281a46c0ec8Sopenharmony_ci return TRUE; 1282a46c0ec8Sopenharmony_ci} 1283a46c0ec8Sopenharmony_ci 1284a46c0ec8Sopenharmony_cistatic void 1285a46c0ec8Sopenharmony_ciregister_evdev_device(struct window *w, struct libinput_device *dev) 1286a46c0ec8Sopenharmony_ci{ 1287a46c0ec8Sopenharmony_ci GIOChannel *c; 1288a46c0ec8Sopenharmony_ci struct udev_device *ud; 1289a46c0ec8Sopenharmony_ci struct libevdev *evdev; 1290a46c0ec8Sopenharmony_ci const char *device_node; 1291a46c0ec8Sopenharmony_ci int fd; 1292a46c0ec8Sopenharmony_ci struct evdev_device *d; 1293a46c0ec8Sopenharmony_ci 1294a46c0ec8Sopenharmony_ci ud = libinput_device_get_udev_device(dev); 1295a46c0ec8Sopenharmony_ci device_node = udev_device_get_devnode(ud); 1296a46c0ec8Sopenharmony_ci 1297a46c0ec8Sopenharmony_ci fd = open(device_node, O_RDONLY|O_NONBLOCK); 1298a46c0ec8Sopenharmony_ci if (fd == -1) { 1299a46c0ec8Sopenharmony_ci msg("failed to open %s, evdev events unavailable\n", device_node); 1300a46c0ec8Sopenharmony_ci goto out; 1301a46c0ec8Sopenharmony_ci } 1302a46c0ec8Sopenharmony_ci 1303a46c0ec8Sopenharmony_ci if (libevdev_new_from_fd(fd, &evdev) != 0) { 1304a46c0ec8Sopenharmony_ci msg("failed to create context for %s, evdev events unavailable\n", 1305a46c0ec8Sopenharmony_ci device_node); 1306a46c0ec8Sopenharmony_ci goto out; 1307a46c0ec8Sopenharmony_ci } 1308a46c0ec8Sopenharmony_ci 1309a46c0ec8Sopenharmony_ci d = zalloc(sizeof *d); 1310a46c0ec8Sopenharmony_ci list_append(&w->evdev_devices, &d->node); 1311a46c0ec8Sopenharmony_ci d->fd = fd; 1312a46c0ec8Sopenharmony_ci d->evdev = evdev; 1313a46c0ec8Sopenharmony_ci d->libinput_device =libinput_device_ref(dev); 1314a46c0ec8Sopenharmony_ci 1315a46c0ec8Sopenharmony_ci c = g_io_channel_unix_new(fd); 1316a46c0ec8Sopenharmony_ci g_io_channel_set_encoding(c, NULL, NULL); 1317a46c0ec8Sopenharmony_ci d->source_id = g_io_add_watch(c, G_IO_IN, 1318a46c0ec8Sopenharmony_ci handle_event_evdev, 1319a46c0ec8Sopenharmony_ci d->libinput_device); 1320a46c0ec8Sopenharmony_ci fd = -1; 1321a46c0ec8Sopenharmony_ciout: 1322a46c0ec8Sopenharmony_ci close(fd); 1323a46c0ec8Sopenharmony_ci udev_device_unref(ud); 1324a46c0ec8Sopenharmony_ci} 1325a46c0ec8Sopenharmony_ci 1326a46c0ec8Sopenharmony_cistatic void 1327a46c0ec8Sopenharmony_ciunregister_evdev_device(struct window *w, struct libinput_device *dev) 1328a46c0ec8Sopenharmony_ci{ 1329a46c0ec8Sopenharmony_ci struct evdev_device *d; 1330a46c0ec8Sopenharmony_ci 1331a46c0ec8Sopenharmony_ci list_for_each_safe(d, &w->evdev_devices, node) { 1332a46c0ec8Sopenharmony_ci if (d->libinput_device != dev) 1333a46c0ec8Sopenharmony_ci continue; 1334a46c0ec8Sopenharmony_ci 1335a46c0ec8Sopenharmony_ci list_remove(&d->node); 1336a46c0ec8Sopenharmony_ci g_source_remove(d->source_id); 1337a46c0ec8Sopenharmony_ci free(libinput_device_get_user_data(d->libinput_device)); 1338a46c0ec8Sopenharmony_ci libinput_device_unref(d->libinput_device); 1339a46c0ec8Sopenharmony_ci libevdev_free(d->evdev); 1340a46c0ec8Sopenharmony_ci close(d->fd); 1341a46c0ec8Sopenharmony_ci free(d); 1342a46c0ec8Sopenharmony_ci w->evdev.last_device = 0; 1343a46c0ec8Sopenharmony_ci break; 1344a46c0ec8Sopenharmony_ci } 1345a46c0ec8Sopenharmony_ci} 1346a46c0ec8Sopenharmony_ci 1347a46c0ec8Sopenharmony_cistatic void 1348a46c0ec8Sopenharmony_cihandle_event_device_notify(struct libinput_event *ev) 1349a46c0ec8Sopenharmony_ci{ 1350a46c0ec8Sopenharmony_ci struct libinput_device *dev = libinput_event_get_device(ev); 1351a46c0ec8Sopenharmony_ci struct libinput *li; 1352a46c0ec8Sopenharmony_ci struct window *w; 1353a46c0ec8Sopenharmony_ci const char *type; 1354a46c0ec8Sopenharmony_ci 1355a46c0ec8Sopenharmony_ci li = libinput_event_get_context(ev); 1356a46c0ec8Sopenharmony_ci w = libinput_get_user_data(li); 1357a46c0ec8Sopenharmony_ci 1358a46c0ec8Sopenharmony_ci if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED) { 1359a46c0ec8Sopenharmony_ci type = "added"; 1360a46c0ec8Sopenharmony_ci register_evdev_device(w, dev); 1361a46c0ec8Sopenharmony_ci tools_device_apply_config(libinput_event_get_device(ev), 1362a46c0ec8Sopenharmony_ci &w->options); 1363a46c0ec8Sopenharmony_ci } else { 1364a46c0ec8Sopenharmony_ci type = "removed"; 1365a46c0ec8Sopenharmony_ci unregister_evdev_device(w, dev); 1366a46c0ec8Sopenharmony_ci } 1367a46c0ec8Sopenharmony_ci 1368a46c0ec8Sopenharmony_ci msg("%s %-30s %s\n", 1369a46c0ec8Sopenharmony_ci libinput_device_get_sysname(dev), 1370a46c0ec8Sopenharmony_ci libinput_device_get_name(dev), 1371a46c0ec8Sopenharmony_ci type); 1372a46c0ec8Sopenharmony_ci 1373a46c0ec8Sopenharmony_ci if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED) { 1374a46c0ec8Sopenharmony_ci ARRAY_FOR_EACH(w->devices, device) { 1375a46c0ec8Sopenharmony_ci if (*device == NULL) { 1376a46c0ec8Sopenharmony_ci *device = libinput_device_ref(dev); 1377a46c0ec8Sopenharmony_ci break; 1378a46c0ec8Sopenharmony_ci } 1379a46c0ec8Sopenharmony_ci } 1380a46c0ec8Sopenharmony_ci } else { 1381a46c0ec8Sopenharmony_ci ARRAY_FOR_EACH(w->devices, device) { 1382a46c0ec8Sopenharmony_ci if (*device == dev) { 1383a46c0ec8Sopenharmony_ci libinput_device_unref(*device); 1384a46c0ec8Sopenharmony_ci *device = NULL; 1385a46c0ec8Sopenharmony_ci break; 1386a46c0ec8Sopenharmony_ci } 1387a46c0ec8Sopenharmony_ci } 1388a46c0ec8Sopenharmony_ci } 1389a46c0ec8Sopenharmony_ci} 1390a46c0ec8Sopenharmony_ci 1391a46c0ec8Sopenharmony_cistatic void 1392a46c0ec8Sopenharmony_cihandle_event_motion(struct libinput_event *ev, struct window *w) 1393a46c0ec8Sopenharmony_ci{ 1394a46c0ec8Sopenharmony_ci struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); 1395a46c0ec8Sopenharmony_ci double dx = libinput_event_pointer_get_dx(p), 1396a46c0ec8Sopenharmony_ci dy = libinput_event_pointer_get_dy(p); 1397a46c0ec8Sopenharmony_ci double dx_unaccel = libinput_event_pointer_get_dx_unaccelerated(p), 1398a46c0ec8Sopenharmony_ci dy_unaccel = libinput_event_pointer_get_dy_unaccelerated(p); 1399a46c0ec8Sopenharmony_ci struct point point; 1400a46c0ec8Sopenharmony_ci const int mask = ARRAY_LENGTH(w->deltas); 1401a46c0ec8Sopenharmony_ci size_t idx; 1402a46c0ec8Sopenharmony_ci 1403a46c0ec8Sopenharmony_ci w->pointer.x = clip(w->pointer.x + dx, 0.0, w->width); 1404a46c0ec8Sopenharmony_ci w->pointer.y = clip(w->pointer.y + dy, 0.0, w->height); 1405a46c0ec8Sopenharmony_ci w->unaccelerated.x = clip(w->unaccelerated.x + dx_unaccel, 0.0, w->width); 1406a46c0ec8Sopenharmony_ci w->unaccelerated.y = clip(w->unaccelerated.y + dy_unaccel, 0.0, w->height); 1407a46c0ec8Sopenharmony_ci 1408a46c0ec8Sopenharmony_ci idx = w->ndeltas % mask; 1409a46c0ec8Sopenharmony_ci point = w->deltas[idx]; 1410a46c0ec8Sopenharmony_ci idx = (w->ndeltas + 1) % mask; 1411a46c0ec8Sopenharmony_ci point.x += dx_unaccel; 1412a46c0ec8Sopenharmony_ci point.y += dy_unaccel; 1413a46c0ec8Sopenharmony_ci w->deltas[idx] = point; 1414a46c0ec8Sopenharmony_ci w->ndeltas++; 1415a46c0ec8Sopenharmony_ci} 1416a46c0ec8Sopenharmony_ci 1417a46c0ec8Sopenharmony_cistatic void 1418a46c0ec8Sopenharmony_cihandle_event_absmotion(struct libinput_event *ev, struct window *w) 1419a46c0ec8Sopenharmony_ci{ 1420a46c0ec8Sopenharmony_ci struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); 1421a46c0ec8Sopenharmony_ci double x = libinput_event_pointer_get_absolute_x_transformed(p, w->width), 1422a46c0ec8Sopenharmony_ci y = libinput_event_pointer_get_absolute_y_transformed(p, w->height); 1423a46c0ec8Sopenharmony_ci 1424a46c0ec8Sopenharmony_ci w->abs.x = x; 1425a46c0ec8Sopenharmony_ci w->abs.y = y; 1426a46c0ec8Sopenharmony_ci} 1427a46c0ec8Sopenharmony_ci 1428a46c0ec8Sopenharmony_cistatic void 1429a46c0ec8Sopenharmony_cihandle_event_touch(struct libinput_event *ev, struct window *w) 1430a46c0ec8Sopenharmony_ci{ 1431a46c0ec8Sopenharmony_ci struct libinput_event_touch *t = libinput_event_get_touch_event(ev); 1432a46c0ec8Sopenharmony_ci int slot = libinput_event_touch_get_seat_slot(t); 1433a46c0ec8Sopenharmony_ci struct touch *touch; 1434a46c0ec8Sopenharmony_ci double x, y; 1435a46c0ec8Sopenharmony_ci 1436a46c0ec8Sopenharmony_ci if (slot == -1 || slot >= (int) ARRAY_LENGTH(w->touches)) 1437a46c0ec8Sopenharmony_ci return; 1438a46c0ec8Sopenharmony_ci 1439a46c0ec8Sopenharmony_ci touch = &w->touches[slot]; 1440a46c0ec8Sopenharmony_ci 1441a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(ev)) { 1442a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_UP: 1443a46c0ec8Sopenharmony_ci touch->state = TOUCH_ENDED; 1444a46c0ec8Sopenharmony_ci return; 1445a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_CANCEL: 1446a46c0ec8Sopenharmony_ci touch->state = TOUCH_CANCELLED; 1447a46c0ec8Sopenharmony_ci return; 1448a46c0ec8Sopenharmony_ci default: 1449a46c0ec8Sopenharmony_ci break; 1450a46c0ec8Sopenharmony_ci } 1451a46c0ec8Sopenharmony_ci 1452a46c0ec8Sopenharmony_ci x = libinput_event_touch_get_x_transformed(t, w->width), 1453a46c0ec8Sopenharmony_ci y = libinput_event_touch_get_y_transformed(t, w->height); 1454a46c0ec8Sopenharmony_ci 1455a46c0ec8Sopenharmony_ci touch->state = TOUCH_ACTIVE; 1456a46c0ec8Sopenharmony_ci touch->x = (int)x; 1457a46c0ec8Sopenharmony_ci touch->y = (int)y; 1458a46c0ec8Sopenharmony_ci} 1459a46c0ec8Sopenharmony_ci 1460a46c0ec8Sopenharmony_cistatic void 1461a46c0ec8Sopenharmony_cihandle_event_axis(struct libinput_event *ev, struct window *w) 1462a46c0ec8Sopenharmony_ci{ 1463a46c0ec8Sopenharmony_ci struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); 1464a46c0ec8Sopenharmony_ci double value; 1465a46c0ec8Sopenharmony_ci enum libinput_pointer_axis axis; 1466a46c0ec8Sopenharmony_ci enum libinput_event_type type; 1467a46c0ec8Sopenharmony_ci 1468a46c0ec8Sopenharmony_ci type = libinput_event_get_type(ev); 1469a46c0ec8Sopenharmony_ci 1470a46c0ec8Sopenharmony_ci axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL; 1471a46c0ec8Sopenharmony_ci if (libinput_event_pointer_has_axis(p, axis)) { 1472a46c0ec8Sopenharmony_ci value = libinput_event_pointer_get_scroll_value(p, axis); 1473a46c0ec8Sopenharmony_ci w->scroll.vy += value; 1474a46c0ec8Sopenharmony_ci w->scroll.vy = clip(w->scroll.vy, 0, w->height); 1475a46c0ec8Sopenharmony_ci 1476a46c0ec8Sopenharmony_ci if (type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL) { 1477a46c0ec8Sopenharmony_ci w->scroll.vy_discrete += value; 1478a46c0ec8Sopenharmony_ci w->scroll.vy_discrete = clip(w->scroll.vy_discrete, 0, w->height); 1479a46c0ec8Sopenharmony_ci } 1480a46c0ec8Sopenharmony_ci } 1481a46c0ec8Sopenharmony_ci 1482a46c0ec8Sopenharmony_ci axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL; 1483a46c0ec8Sopenharmony_ci if (libinput_event_pointer_has_axis(p, axis)) { 1484a46c0ec8Sopenharmony_ci value = libinput_event_pointer_get_scroll_value(p, axis); 1485a46c0ec8Sopenharmony_ci w->scroll.hx += value; 1486a46c0ec8Sopenharmony_ci w->scroll.hx = clip(w->scroll.hx, 0, w->width); 1487a46c0ec8Sopenharmony_ci 1488a46c0ec8Sopenharmony_ci if (type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL) { 1489a46c0ec8Sopenharmony_ci w->scroll.hx_discrete += value; 1490a46c0ec8Sopenharmony_ci w->scroll.hx_discrete = clip(w->scroll.hx_discrete, 0, w->width); 1491a46c0ec8Sopenharmony_ci } 1492a46c0ec8Sopenharmony_ci } 1493a46c0ec8Sopenharmony_ci} 1494a46c0ec8Sopenharmony_ci 1495a46c0ec8Sopenharmony_cistatic int 1496a46c0ec8Sopenharmony_cihandle_event_keyboard(struct libinput_event *ev, struct window *w) 1497a46c0ec8Sopenharmony_ci{ 1498a46c0ec8Sopenharmony_ci struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev); 1499a46c0ec8Sopenharmony_ci unsigned int key = libinput_event_keyboard_get_key(k); 1500a46c0ec8Sopenharmony_ci 1501a46c0ec8Sopenharmony_ci if (libinput_event_keyboard_get_key_state(k) == 1502a46c0ec8Sopenharmony_ci LIBINPUT_KEY_STATE_RELEASED) 1503a46c0ec8Sopenharmony_ci return 0; 1504a46c0ec8Sopenharmony_ci 1505a46c0ec8Sopenharmony_ci switch(key) { 1506a46c0ec8Sopenharmony_ci case KEY_ESC: 1507a46c0ec8Sopenharmony_ci return 1; 1508a46c0ec8Sopenharmony_ci case KEY_UP: 1509a46c0ec8Sopenharmony_ci change_ptraccel(w, 0.1); 1510a46c0ec8Sopenharmony_ci break; 1511a46c0ec8Sopenharmony_ci case KEY_DOWN: 1512a46c0ec8Sopenharmony_ci change_ptraccel(w, -0.1); 1513a46c0ec8Sopenharmony_ci break; 1514a46c0ec8Sopenharmony_ci default: 1515a46c0ec8Sopenharmony_ci break; 1516a46c0ec8Sopenharmony_ci } 1517a46c0ec8Sopenharmony_ci 1518a46c0ec8Sopenharmony_ci return 0; 1519a46c0ec8Sopenharmony_ci} 1520a46c0ec8Sopenharmony_ci 1521a46c0ec8Sopenharmony_cistatic void 1522a46c0ec8Sopenharmony_cihandle_event_button(struct libinput_event *ev, struct window *w) 1523a46c0ec8Sopenharmony_ci{ 1524a46c0ec8Sopenharmony_ci struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); 1525a46c0ec8Sopenharmony_ci unsigned int button = libinput_event_pointer_get_button(p); 1526a46c0ec8Sopenharmony_ci bool is_press; 1527a46c0ec8Sopenharmony_ci 1528a46c0ec8Sopenharmony_ci is_press = libinput_event_pointer_get_button_state(p) == LIBINPUT_BUTTON_STATE_PRESSED; 1529a46c0ec8Sopenharmony_ci 1530a46c0ec8Sopenharmony_ci switch (button) { 1531a46c0ec8Sopenharmony_ci case BTN_LEFT: 1532a46c0ec8Sopenharmony_ci w->buttons.l = is_press; 1533a46c0ec8Sopenharmony_ci break; 1534a46c0ec8Sopenharmony_ci case BTN_RIGHT: 1535a46c0ec8Sopenharmony_ci w->buttons.r = is_press; 1536a46c0ec8Sopenharmony_ci break; 1537a46c0ec8Sopenharmony_ci case BTN_MIDDLE: 1538a46c0ec8Sopenharmony_ci w->buttons.m = is_press; 1539a46c0ec8Sopenharmony_ci break; 1540a46c0ec8Sopenharmony_ci default: 1541a46c0ec8Sopenharmony_ci w->buttons.other = is_press; 1542a46c0ec8Sopenharmony_ci w->buttons.other_name = libevdev_event_code_get_name(EV_KEY, 1543a46c0ec8Sopenharmony_ci button); 1544a46c0ec8Sopenharmony_ci } 1545a46c0ec8Sopenharmony_ci 1546a46c0ec8Sopenharmony_ci} 1547a46c0ec8Sopenharmony_ci 1548a46c0ec8Sopenharmony_cistatic void 1549a46c0ec8Sopenharmony_cihandle_event_swipe(struct libinput_event *ev, struct window *w) 1550a46c0ec8Sopenharmony_ci{ 1551a46c0ec8Sopenharmony_ci struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev); 1552a46c0ec8Sopenharmony_ci int nfingers; 1553a46c0ec8Sopenharmony_ci double dx, dy; 1554a46c0ec8Sopenharmony_ci 1555a46c0ec8Sopenharmony_ci nfingers = libinput_event_gesture_get_finger_count(g); 1556a46c0ec8Sopenharmony_ci 1557a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(ev)) { 1558a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: 1559a46c0ec8Sopenharmony_ci w->swipe.nfingers = nfingers; 1560a46c0ec8Sopenharmony_ci w->swipe.x = w->width/2; 1561a46c0ec8Sopenharmony_ci w->swipe.y = w->height/2; 1562a46c0ec8Sopenharmony_ci break; 1563a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: 1564a46c0ec8Sopenharmony_ci dx = libinput_event_gesture_get_dx(g); 1565a46c0ec8Sopenharmony_ci dy = libinput_event_gesture_get_dy(g); 1566a46c0ec8Sopenharmony_ci w->swipe.x += dx; 1567a46c0ec8Sopenharmony_ci w->swipe.y += dy; 1568a46c0ec8Sopenharmony_ci break; 1569a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_END: 1570a46c0ec8Sopenharmony_ci w->swipe.nfingers = 0; 1571a46c0ec8Sopenharmony_ci w->swipe.x = w->width/2; 1572a46c0ec8Sopenharmony_ci w->swipe.y = w->height/2; 1573a46c0ec8Sopenharmony_ci break; 1574a46c0ec8Sopenharmony_ci default: 1575a46c0ec8Sopenharmony_ci abort(); 1576a46c0ec8Sopenharmony_ci } 1577a46c0ec8Sopenharmony_ci} 1578a46c0ec8Sopenharmony_ci 1579a46c0ec8Sopenharmony_cistatic void 1580a46c0ec8Sopenharmony_cihandle_event_pinch(struct libinput_event *ev, struct window *w) 1581a46c0ec8Sopenharmony_ci{ 1582a46c0ec8Sopenharmony_ci struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev); 1583a46c0ec8Sopenharmony_ci int nfingers; 1584a46c0ec8Sopenharmony_ci double dx, dy; 1585a46c0ec8Sopenharmony_ci 1586a46c0ec8Sopenharmony_ci nfingers = libinput_event_gesture_get_finger_count(g); 1587a46c0ec8Sopenharmony_ci 1588a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(ev)) { 1589a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: 1590a46c0ec8Sopenharmony_ci w->pinch.nfingers = nfingers; 1591a46c0ec8Sopenharmony_ci w->pinch.x = w->width/2; 1592a46c0ec8Sopenharmony_ci w->pinch.y = w->height/2; 1593a46c0ec8Sopenharmony_ci break; 1594a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: 1595a46c0ec8Sopenharmony_ci dx = libinput_event_gesture_get_dx(g); 1596a46c0ec8Sopenharmony_ci dy = libinput_event_gesture_get_dy(g); 1597a46c0ec8Sopenharmony_ci w->pinch.x += dx; 1598a46c0ec8Sopenharmony_ci w->pinch.y += dy; 1599a46c0ec8Sopenharmony_ci w->pinch.scale = libinput_event_gesture_get_scale(g); 1600a46c0ec8Sopenharmony_ci w->pinch.angle += libinput_event_gesture_get_angle_delta(g); 1601a46c0ec8Sopenharmony_ci break; 1602a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_END: 1603a46c0ec8Sopenharmony_ci w->pinch.nfingers = 0; 1604a46c0ec8Sopenharmony_ci w->pinch.x = w->width/2; 1605a46c0ec8Sopenharmony_ci w->pinch.y = w->height/2; 1606a46c0ec8Sopenharmony_ci w->pinch.angle = 0.0; 1607a46c0ec8Sopenharmony_ci w->pinch.scale = 1.0; 1608a46c0ec8Sopenharmony_ci break; 1609a46c0ec8Sopenharmony_ci default: 1610a46c0ec8Sopenharmony_ci abort(); 1611a46c0ec8Sopenharmony_ci } 1612a46c0ec8Sopenharmony_ci} 1613a46c0ec8Sopenharmony_ci 1614a46c0ec8Sopenharmony_cistatic void 1615a46c0ec8Sopenharmony_cihandle_event_hold(struct libinput_event *ev, struct window *w) 1616a46c0ec8Sopenharmony_ci{ 1617a46c0ec8Sopenharmony_ci struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev); 1618a46c0ec8Sopenharmony_ci int nfingers; 1619a46c0ec8Sopenharmony_ci 1620a46c0ec8Sopenharmony_ci nfingers = libinput_event_gesture_get_finger_count(g); 1621a46c0ec8Sopenharmony_ci 1622a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(ev)) { 1623a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN: 1624a46c0ec8Sopenharmony_ci w->hold.nfingers = nfingers; 1625a46c0ec8Sopenharmony_ci w->hold.active = true; 1626a46c0ec8Sopenharmony_ci break; 1627a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_HOLD_END: 1628a46c0ec8Sopenharmony_ci w->hold.nfingers = nfingers; 1629a46c0ec8Sopenharmony_ci w->hold.active = false; 1630a46c0ec8Sopenharmony_ci break; 1631a46c0ec8Sopenharmony_ci default: 1632a46c0ec8Sopenharmony_ci abort(); 1633a46c0ec8Sopenharmony_ci } 1634a46c0ec8Sopenharmony_ci} 1635a46c0ec8Sopenharmony_ci 1636a46c0ec8Sopenharmony_cistatic void 1637a46c0ec8Sopenharmony_cihandle_event_tablet(struct libinput_event *ev, struct window *w) 1638a46c0ec8Sopenharmony_ci{ 1639a46c0ec8Sopenharmony_ci struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(ev); 1640a46c0ec8Sopenharmony_ci double x, y; 1641a46c0ec8Sopenharmony_ci struct point point; 1642a46c0ec8Sopenharmony_ci int idx; 1643a46c0ec8Sopenharmony_ci const int mask = ARRAY_LENGTH(w->tool.deltas); 1644a46c0ec8Sopenharmony_ci bool is_press; 1645a46c0ec8Sopenharmony_ci unsigned int button; 1646a46c0ec8Sopenharmony_ci 1647a46c0ec8Sopenharmony_ci x = libinput_event_tablet_tool_get_x_transformed(t, w->width); 1648a46c0ec8Sopenharmony_ci y = libinput_event_tablet_tool_get_y_transformed(t, w->height); 1649a46c0ec8Sopenharmony_ci 1650a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(ev)) { 1651a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: 1652a46c0ec8Sopenharmony_ci if (libinput_event_tablet_tool_get_proximity_state(t) == 1653a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) { 1654a46c0ec8Sopenharmony_ci w->tool.x_in = 0; 1655a46c0ec8Sopenharmony_ci w->tool.y_in = 0; 1656a46c0ec8Sopenharmony_ci w->tool.x_down = 0; 1657a46c0ec8Sopenharmony_ci w->tool.y_down = 0; 1658a46c0ec8Sopenharmony_ci w->tool.x_up = 0; 1659a46c0ec8Sopenharmony_ci w->tool.y_up = 0; 1660a46c0ec8Sopenharmony_ci } else { 1661a46c0ec8Sopenharmony_ci w->tool.x_in = x; 1662a46c0ec8Sopenharmony_ci w->tool.y_in = y; 1663a46c0ec8Sopenharmony_ci w->tool.ndeltas = 0; 1664a46c0ec8Sopenharmony_ci w->tool.deltas[0].x = w->width/2; 1665a46c0ec8Sopenharmony_ci w->tool.deltas[0].y = w->height/2; 1666a46c0ec8Sopenharmony_ci } 1667a46c0ec8Sopenharmony_ci break; 1668a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_TIP: 1669a46c0ec8Sopenharmony_ci w->tool.pressure = libinput_event_tablet_tool_get_pressure(t); 1670a46c0ec8Sopenharmony_ci w->tool.distance = libinput_event_tablet_tool_get_distance(t); 1671a46c0ec8Sopenharmony_ci w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t); 1672a46c0ec8Sopenharmony_ci w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t); 1673a46c0ec8Sopenharmony_ci if (libinput_event_tablet_tool_get_tip_state(t) == 1674a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_TIP_DOWN) { 1675a46c0ec8Sopenharmony_ci w->tool.x_down = x; 1676a46c0ec8Sopenharmony_ci w->tool.y_down = y; 1677a46c0ec8Sopenharmony_ci w->tool.is_down = true; 1678a46c0ec8Sopenharmony_ci } else { 1679a46c0ec8Sopenharmony_ci w->tool.x_up = x; 1680a46c0ec8Sopenharmony_ci w->tool.y_up = y; 1681a46c0ec8Sopenharmony_ci w->tool.is_down = false; 1682a46c0ec8Sopenharmony_ci } 1683a46c0ec8Sopenharmony_ci _fallthrough_; 1684a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_AXIS: 1685a46c0ec8Sopenharmony_ci w->tool.x = x; 1686a46c0ec8Sopenharmony_ci w->tool.y = y; 1687a46c0ec8Sopenharmony_ci w->tool.pressure = libinput_event_tablet_tool_get_pressure(t); 1688a46c0ec8Sopenharmony_ci w->tool.distance = libinput_event_tablet_tool_get_distance(t); 1689a46c0ec8Sopenharmony_ci w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t); 1690a46c0ec8Sopenharmony_ci w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t); 1691a46c0ec8Sopenharmony_ci w->tool.rotation = libinput_event_tablet_tool_get_rotation(t); 1692a46c0ec8Sopenharmony_ci w->tool.size_major = libinput_event_tablet_tool_get_size_major(t); 1693a46c0ec8Sopenharmony_ci w->tool.size_minor = libinput_event_tablet_tool_get_size_minor(t); 1694a46c0ec8Sopenharmony_ci 1695a46c0ec8Sopenharmony_ci /* Add the delta to the last position and store them as abs 1696a46c0ec8Sopenharmony_ci * coordinates */ 1697a46c0ec8Sopenharmony_ci idx = w->tool.ndeltas % mask; 1698a46c0ec8Sopenharmony_ci point = w->tool.deltas[idx]; 1699a46c0ec8Sopenharmony_ci 1700a46c0ec8Sopenharmony_ci idx = (w->tool.ndeltas + 1) % mask; 1701a46c0ec8Sopenharmony_ci point.x += libinput_event_tablet_tool_get_dx(t); 1702a46c0ec8Sopenharmony_ci point.y += libinput_event_tablet_tool_get_dy(t); 1703a46c0ec8Sopenharmony_ci w->tool.deltas[idx] = point; 1704a46c0ec8Sopenharmony_ci w->tool.ndeltas++; 1705a46c0ec8Sopenharmony_ci break; 1706a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: 1707a46c0ec8Sopenharmony_ci is_press = libinput_event_tablet_tool_get_button_state(t) == LIBINPUT_BUTTON_STATE_PRESSED; 1708a46c0ec8Sopenharmony_ci button = libinput_event_tablet_tool_get_button(t); 1709a46c0ec8Sopenharmony_ci 1710a46c0ec8Sopenharmony_ci w->buttons.other = is_press; 1711a46c0ec8Sopenharmony_ci w->buttons.other_name = libevdev_event_code_get_name(EV_KEY, 1712a46c0ec8Sopenharmony_ci button); 1713a46c0ec8Sopenharmony_ci break; 1714a46c0ec8Sopenharmony_ci default: 1715a46c0ec8Sopenharmony_ci abort(); 1716a46c0ec8Sopenharmony_ci } 1717a46c0ec8Sopenharmony_ci} 1718a46c0ec8Sopenharmony_ci 1719a46c0ec8Sopenharmony_cistatic void 1720a46c0ec8Sopenharmony_cihandle_event_tablet_pad(struct libinput_event *ev, struct window *w) 1721a46c0ec8Sopenharmony_ci{ 1722a46c0ec8Sopenharmony_ci struct libinput_event_tablet_pad *p = libinput_event_get_tablet_pad_event(ev); 1723a46c0ec8Sopenharmony_ci bool is_press; 1724a46c0ec8Sopenharmony_ci unsigned int button; 1725a46c0ec8Sopenharmony_ci static const char *pad_buttons[] = { 1726a46c0ec8Sopenharmony_ci "Pad 0", "Pad 1", "Pad 2", "Pad 3", "Pad 4", "Pad 5", 1727a46c0ec8Sopenharmony_ci "Pad 6", "Pad 7", "Pad 8", "Pad 9", "Pad >= 10" 1728a46c0ec8Sopenharmony_ci }; 1729a46c0ec8Sopenharmony_ci double position; 1730a46c0ec8Sopenharmony_ci double number; 1731a46c0ec8Sopenharmony_ci 1732a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(ev)) { 1733a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_BUTTON: 1734a46c0ec8Sopenharmony_ci is_press = libinput_event_tablet_pad_get_button_state(p) == LIBINPUT_BUTTON_STATE_PRESSED; 1735a46c0ec8Sopenharmony_ci button = libinput_event_tablet_pad_get_button_number(p); 1736a46c0ec8Sopenharmony_ci w->buttons.other = is_press; 1737a46c0ec8Sopenharmony_ci w->buttons.other_name = pad_buttons[min(button, 10)]; 1738a46c0ec8Sopenharmony_ci break; 1739a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_RING: 1740a46c0ec8Sopenharmony_ci position = libinput_event_tablet_pad_get_ring_position(p); 1741a46c0ec8Sopenharmony_ci number = libinput_event_tablet_pad_get_ring_number(p); 1742a46c0ec8Sopenharmony_ci w->pad.ring.number = number; 1743a46c0ec8Sopenharmony_ci w->pad.ring.position = position; 1744a46c0ec8Sopenharmony_ci break; 1745a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_STRIP: 1746a46c0ec8Sopenharmony_ci position = libinput_event_tablet_pad_get_strip_position(p); 1747a46c0ec8Sopenharmony_ci number = libinput_event_tablet_pad_get_strip_number(p); 1748a46c0ec8Sopenharmony_ci w->pad.strip.number = number; 1749a46c0ec8Sopenharmony_ci w->pad.strip.position = position; 1750a46c0ec8Sopenharmony_ci break; 1751a46c0ec8Sopenharmony_ci default: 1752a46c0ec8Sopenharmony_ci abort(); 1753a46c0ec8Sopenharmony_ci } 1754a46c0ec8Sopenharmony_ci} 1755a46c0ec8Sopenharmony_ci 1756a46c0ec8Sopenharmony_cistatic gboolean 1757a46c0ec8Sopenharmony_cihandle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data) 1758a46c0ec8Sopenharmony_ci{ 1759a46c0ec8Sopenharmony_ci struct libinput *li = data; 1760a46c0ec8Sopenharmony_ci struct window *w = libinput_get_user_data(li); 1761a46c0ec8Sopenharmony_ci struct libinput_event *ev; 1762a46c0ec8Sopenharmony_ci 1763a46c0ec8Sopenharmony_ci tools_dispatch(li); 1764a46c0ec8Sopenharmony_ci 1765a46c0ec8Sopenharmony_ci while ((ev = libinput_get_event(li))) { 1766a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(ev)) { 1767a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_NONE: 1768a46c0ec8Sopenharmony_ci abort(); 1769a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_DEVICE_ADDED: 1770a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_DEVICE_REMOVED: 1771a46c0ec8Sopenharmony_ci handle_event_device_notify(ev); 1772a46c0ec8Sopenharmony_ci break; 1773a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_MOTION: 1774a46c0ec8Sopenharmony_ci handle_event_motion(ev, w); 1775a46c0ec8Sopenharmony_ci break; 1776a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: 1777a46c0ec8Sopenharmony_ci handle_event_absmotion(ev, w); 1778a46c0ec8Sopenharmony_ci break; 1779a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_DOWN: 1780a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_MOTION: 1781a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_UP: 1782a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_CANCEL: 1783a46c0ec8Sopenharmony_ci handle_event_touch(ev, w); 1784a46c0ec8Sopenharmony_ci break; 1785a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_FRAME: 1786a46c0ec8Sopenharmony_ci break; 1787a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_AXIS: 1788a46c0ec8Sopenharmony_ci /* ignore */ 1789a46c0ec8Sopenharmony_ci break; 1790a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL: 1791a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_SCROLL_FINGER: 1792a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS: 1793a46c0ec8Sopenharmony_ci handle_event_axis(ev, w); 1794a46c0ec8Sopenharmony_ci break; 1795a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_BUTTON: 1796a46c0ec8Sopenharmony_ci handle_event_button(ev, w); 1797a46c0ec8Sopenharmony_ci break; 1798a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_KEYBOARD_KEY: 1799a46c0ec8Sopenharmony_ci if (handle_event_keyboard(ev, w)) { 1800a46c0ec8Sopenharmony_ci libinput_event_destroy(ev); 1801a46c0ec8Sopenharmony_ci window_quit(w); 1802a46c0ec8Sopenharmony_ci return FALSE; 1803a46c0ec8Sopenharmony_ci } 1804a46c0ec8Sopenharmony_ci break; 1805a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: 1806a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: 1807a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_END: 1808a46c0ec8Sopenharmony_ci handle_event_swipe(ev, w); 1809a46c0ec8Sopenharmony_ci break; 1810a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: 1811a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: 1812a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_END: 1813a46c0ec8Sopenharmony_ci handle_event_pinch(ev, w); 1814a46c0ec8Sopenharmony_ci break; 1815a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN: 1816a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_HOLD_END: 1817a46c0ec8Sopenharmony_ci handle_event_hold(ev, w); 1818a46c0ec8Sopenharmony_ci break; 1819a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_AXIS: 1820a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: 1821a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_TIP: 1822a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: 1823a46c0ec8Sopenharmony_ci handle_event_tablet(ev, w); 1824a46c0ec8Sopenharmony_ci break; 1825a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_BUTTON: 1826a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_RING: 1827a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_STRIP: 1828a46c0ec8Sopenharmony_ci handle_event_tablet_pad(ev, w); 1829a46c0ec8Sopenharmony_ci break; 1830a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_KEY: 1831a46c0ec8Sopenharmony_ci break; 1832a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_SWITCH_TOGGLE: 1833a46c0ec8Sopenharmony_ci break; 1834a46c0ec8Sopenharmony_ci } 1835a46c0ec8Sopenharmony_ci 1836a46c0ec8Sopenharmony_ci libinput_event_destroy(ev); 1837a46c0ec8Sopenharmony_ci } 1838a46c0ec8Sopenharmony_ci gtk_widget_queue_draw(w->area); 1839a46c0ec8Sopenharmony_ci 1840a46c0ec8Sopenharmony_ci return TRUE; 1841a46c0ec8Sopenharmony_ci} 1842a46c0ec8Sopenharmony_ci 1843a46c0ec8Sopenharmony_cistatic void 1844a46c0ec8Sopenharmony_cisockets_init(struct libinput *li) 1845a46c0ec8Sopenharmony_ci{ 1846a46c0ec8Sopenharmony_ci GIOChannel *c = g_io_channel_unix_new(libinput_get_fd(li)); 1847a46c0ec8Sopenharmony_ci 1848a46c0ec8Sopenharmony_ci g_io_channel_set_encoding(c, NULL, NULL); 1849a46c0ec8Sopenharmony_ci g_io_add_watch(c, G_IO_IN, handle_event_libinput, li); 1850a46c0ec8Sopenharmony_ci} 1851a46c0ec8Sopenharmony_ci 1852a46c0ec8Sopenharmony_cistatic void 1853a46c0ec8Sopenharmony_ciusage(void) { 1854a46c0ec8Sopenharmony_ci printf("Usage: libinput debug-gui [options] [--udev <seat>|[--device] /dev/input/event0]\n"); 1855a46c0ec8Sopenharmony_ci} 1856a46c0ec8Sopenharmony_ci 1857a46c0ec8Sopenharmony_cistatic gboolean 1858a46c0ec8Sopenharmony_cisignal_handler(void *data) 1859a46c0ec8Sopenharmony_ci{ 1860a46c0ec8Sopenharmony_ci struct libinput *li = data; 1861a46c0ec8Sopenharmony_ci struct window *w = libinput_get_user_data(li); 1862a46c0ec8Sopenharmony_ci 1863a46c0ec8Sopenharmony_ci window_quit(w); 1864a46c0ec8Sopenharmony_ci 1865a46c0ec8Sopenharmony_ci return FALSE; 1866a46c0ec8Sopenharmony_ci} 1867a46c0ec8Sopenharmony_ci 1868a46c0ec8Sopenharmony_ciint 1869a46c0ec8Sopenharmony_cimain(int argc, char **argv) 1870a46c0ec8Sopenharmony_ci{ 1871a46c0ec8Sopenharmony_ci struct window w = {0}; 1872a46c0ec8Sopenharmony_ci struct tools_options options; 1873a46c0ec8Sopenharmony_ci struct libinput *li; 1874a46c0ec8Sopenharmony_ci enum tools_backend backend = BACKEND_NONE; 1875a46c0ec8Sopenharmony_ci const char *seat_or_device[2] = {"seat0", NULL}; 1876a46c0ec8Sopenharmony_ci bool verbose = false; 1877a46c0ec8Sopenharmony_ci bool gtk_init = false; 1878a46c0ec8Sopenharmony_ci 1879a46c0ec8Sopenharmony_ci#if HAVE_GTK4 1880a46c0ec8Sopenharmony_ci gtk_init = gtk_init_check(); 1881a46c0ec8Sopenharmony_ci#else 1882a46c0ec8Sopenharmony_ci gtk_init = gtk_init_check(&argc, &argv); 1883a46c0ec8Sopenharmony_ci#endif 1884a46c0ec8Sopenharmony_ci 1885a46c0ec8Sopenharmony_ci if (!gtk_init) 1886a46c0ec8Sopenharmony_ci return 77; 1887a46c0ec8Sopenharmony_ci 1888a46c0ec8Sopenharmony_ci tools_init_options(&options); 1889a46c0ec8Sopenharmony_ci 1890a46c0ec8Sopenharmony_ci while (1) { 1891a46c0ec8Sopenharmony_ci int c; 1892a46c0ec8Sopenharmony_ci int option_index = 0; 1893a46c0ec8Sopenharmony_ci enum { 1894a46c0ec8Sopenharmony_ci OPT_DEVICE = 1, 1895a46c0ec8Sopenharmony_ci OPT_UDEV, 1896a46c0ec8Sopenharmony_ci OPT_GRAB, 1897a46c0ec8Sopenharmony_ci OPT_VERBOSE, 1898a46c0ec8Sopenharmony_ci }; 1899a46c0ec8Sopenharmony_ci static struct option opts[] = { 1900a46c0ec8Sopenharmony_ci CONFIGURATION_OPTIONS, 1901a46c0ec8Sopenharmony_ci { "help", no_argument, 0, 'h' }, 1902a46c0ec8Sopenharmony_ci { "device", required_argument, 0, OPT_DEVICE }, 1903a46c0ec8Sopenharmony_ci { "udev", required_argument, 0, OPT_UDEV }, 1904a46c0ec8Sopenharmony_ci { "grab", no_argument, 0, OPT_GRAB }, 1905a46c0ec8Sopenharmony_ci { "verbose", no_argument, 0, OPT_VERBOSE }, 1906a46c0ec8Sopenharmony_ci { 0, 0, 0, 0} 1907a46c0ec8Sopenharmony_ci }; 1908a46c0ec8Sopenharmony_ci 1909a46c0ec8Sopenharmony_ci c = getopt_long(argc, argv, "h", opts, &option_index); 1910a46c0ec8Sopenharmony_ci if (c == -1) 1911a46c0ec8Sopenharmony_ci break; 1912a46c0ec8Sopenharmony_ci 1913a46c0ec8Sopenharmony_ci switch(c) { 1914a46c0ec8Sopenharmony_ci case '?': 1915a46c0ec8Sopenharmony_ci exit(EXIT_INVALID_USAGE); 1916a46c0ec8Sopenharmony_ci break; 1917a46c0ec8Sopenharmony_ci case 'h': 1918a46c0ec8Sopenharmony_ci usage(); 1919a46c0ec8Sopenharmony_ci exit(0); 1920a46c0ec8Sopenharmony_ci break; 1921a46c0ec8Sopenharmony_ci case OPT_DEVICE: 1922a46c0ec8Sopenharmony_ci backend = BACKEND_DEVICE; 1923a46c0ec8Sopenharmony_ci seat_or_device[0] = optarg; 1924a46c0ec8Sopenharmony_ci break; 1925a46c0ec8Sopenharmony_ci case OPT_UDEV: 1926a46c0ec8Sopenharmony_ci backend = BACKEND_UDEV; 1927a46c0ec8Sopenharmony_ci seat_or_device[0] = optarg; 1928a46c0ec8Sopenharmony_ci break; 1929a46c0ec8Sopenharmony_ci case OPT_GRAB: 1930a46c0ec8Sopenharmony_ci w.grab = true; 1931a46c0ec8Sopenharmony_ci break; 1932a46c0ec8Sopenharmony_ci case OPT_VERBOSE: 1933a46c0ec8Sopenharmony_ci verbose = true; 1934a46c0ec8Sopenharmony_ci break; 1935a46c0ec8Sopenharmony_ci default: 1936a46c0ec8Sopenharmony_ci if (tools_parse_option(c, optarg, &options) != 0) { 1937a46c0ec8Sopenharmony_ci usage(); 1938a46c0ec8Sopenharmony_ci return EXIT_INVALID_USAGE; 1939a46c0ec8Sopenharmony_ci } 1940a46c0ec8Sopenharmony_ci break; 1941a46c0ec8Sopenharmony_ci } 1942a46c0ec8Sopenharmony_ci 1943a46c0ec8Sopenharmony_ci } 1944a46c0ec8Sopenharmony_ci 1945a46c0ec8Sopenharmony_ci if (optind < argc) { 1946a46c0ec8Sopenharmony_ci if (optind < argc - 1 || backend != BACKEND_NONE) { 1947a46c0ec8Sopenharmony_ci usage(); 1948a46c0ec8Sopenharmony_ci return EXIT_INVALID_USAGE; 1949a46c0ec8Sopenharmony_ci } 1950a46c0ec8Sopenharmony_ci backend = BACKEND_DEVICE; 1951a46c0ec8Sopenharmony_ci seat_or_device[0] = argv[optind]; 1952a46c0ec8Sopenharmony_ci } else if (backend == BACKEND_NONE) { 1953a46c0ec8Sopenharmony_ci backend = BACKEND_UDEV; 1954a46c0ec8Sopenharmony_ci } 1955a46c0ec8Sopenharmony_ci 1956a46c0ec8Sopenharmony_ci li = tools_open_backend(backend, seat_or_device, verbose, &w.grab); 1957a46c0ec8Sopenharmony_ci if (!li) 1958a46c0ec8Sopenharmony_ci return EXIT_FAILURE; 1959a46c0ec8Sopenharmony_ci 1960a46c0ec8Sopenharmony_ci libinput_set_user_data(li, &w); 1961a46c0ec8Sopenharmony_ci 1962a46c0ec8Sopenharmony_ci g_unix_signal_add(SIGINT, signal_handler, li); 1963a46c0ec8Sopenharmony_ci 1964a46c0ec8Sopenharmony_ci window_init(&w); 1965a46c0ec8Sopenharmony_ci w.options = options; 1966a46c0ec8Sopenharmony_ci sockets_init(li); 1967a46c0ec8Sopenharmony_ci handle_event_libinput(NULL, 0, li); 1968a46c0ec8Sopenharmony_ci 1969a46c0ec8Sopenharmony_ci w.event_loop = g_main_loop_new(NULL, FALSE); 1970a46c0ec8Sopenharmony_ci g_main_loop_run(w.event_loop); 1971a46c0ec8Sopenharmony_ci 1972a46c0ec8Sopenharmony_ci window_unlock_pointer(&w); 1973a46c0ec8Sopenharmony_ci window_cleanup(&w); 1974a46c0ec8Sopenharmony_ci libinput_unref(li); 1975a46c0ec8Sopenharmony_ci 1976a46c0ec8Sopenharmony_ci return EXIT_SUCCESS; 1977a46c0ec8Sopenharmony_ci} 1978