SDL_waylandevents.c (43985B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20 */ 21 22 #include "../../SDL_internal.h" 23 24 #if SDL_VIDEO_DRIVER_WAYLAND 25 26 #include "SDL_stdinc.h" 27 #include "SDL_timer.h" 28 29 #include "../../core/unix/SDL_poll.h" 30 #include "../../events/SDL_sysevents.h" 31 #include "../../events/SDL_events_c.h" 32 #include "../../events/scancodes_xfree86.h" 33 34 #include "SDL_waylandvideo.h" 35 #include "SDL_waylandevents_c.h" 36 #include "SDL_waylandwindow.h" 37 38 #include "SDL_waylanddyn.h" 39 40 #include "pointer-constraints-unstable-v1-client-protocol.h" 41 #include "relative-pointer-unstable-v1-client-protocol.h" 42 #include "xdg-shell-client-protocol.h" 43 #include "xdg-shell-unstable-v6-client-protocol.h" 44 45 #ifdef SDL_INPUT_LINUXEV 46 #include <linux/input.h> 47 #else 48 #define BTN_LEFT (0x110) 49 #define BTN_RIGHT (0x111) 50 #define BTN_MIDDLE (0x112) 51 #define BTN_SIDE (0x113) 52 #define BTN_EXTRA (0x114) 53 #endif 54 #include <sys/select.h> 55 #include <sys/mman.h> 56 #include <poll.h> 57 #include <unistd.h> 58 #include <xkbcommon/xkbcommon.h> 59 60 typedef struct { 61 // repeat_rate in range of [1, 1000] 62 int32_t repeat_rate; 63 int32_t repeat_delay; 64 SDL_bool is_initialized; 65 66 SDL_bool is_key_down; 67 uint32_t next_repeat_ms; 68 uint32_t scancode; 69 char text[8]; 70 } SDL_WaylandKeyboardRepeat; 71 72 struct SDL_WaylandInput { 73 SDL_VideoData *display; 74 struct wl_seat *seat; 75 struct wl_pointer *pointer; 76 struct wl_touch *touch; 77 struct wl_keyboard *keyboard; 78 SDL_WaylandDataDevice *data_device; 79 struct zwp_relative_pointer_v1 *relative_pointer; 80 struct zwp_confined_pointer_v1 *confined_pointer; 81 SDL_Window *confined_pointer_window; 82 SDL_WindowData *pointer_focus; 83 SDL_WindowData *keyboard_focus; 84 85 /* Last motion location */ 86 wl_fixed_t sx_w; 87 wl_fixed_t sy_w; 88 89 double dx_frac; 90 double dy_frac; 91 92 struct { 93 struct xkb_keymap *keymap; 94 struct xkb_state *state; 95 } xkb; 96 97 /* information about axis events on current frame */ 98 struct { 99 SDL_bool is_x_discrete; 100 float x; 101 102 SDL_bool is_y_discrete; 103 float y; 104 } pointer_curr_axis_info; 105 106 SDL_WaylandKeyboardRepeat keyboard_repeat; 107 }; 108 109 struct SDL_WaylandTouchPoint { 110 SDL_TouchID id; 111 float x; 112 float y; 113 struct wl_surface* surface; 114 115 struct SDL_WaylandTouchPoint* prev; 116 struct SDL_WaylandTouchPoint* next; 117 }; 118 119 struct SDL_WaylandTouchPointList { 120 struct SDL_WaylandTouchPoint* head; 121 struct SDL_WaylandTouchPoint* tail; 122 }; 123 124 static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL}; 125 126 static void 127 touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface) 128 { 129 struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint)); 130 131 tp->id = id; 132 tp->x = x; 133 tp->y = y; 134 tp->surface = surface; 135 136 if (touch_points.tail) { 137 touch_points.tail->next = tp; 138 tp->prev = touch_points.tail; 139 } else { 140 touch_points.head = tp; 141 tp->prev = NULL; 142 } 143 144 touch_points.tail = tp; 145 tp->next = NULL; 146 } 147 148 static void 149 touch_update(SDL_TouchID id, float x, float y) 150 { 151 struct SDL_WaylandTouchPoint* tp = touch_points.head; 152 153 while (tp) { 154 if (tp->id == id) { 155 tp->x = x; 156 tp->y = y; 157 } 158 159 tp = tp->next; 160 } 161 } 162 163 static void 164 touch_del(SDL_TouchID id, float* x, float* y, struct wl_surface **surface) 165 { 166 struct SDL_WaylandTouchPoint* tp = touch_points.head; 167 168 while (tp) { 169 if (tp->id == id) { 170 *x = tp->x; 171 *y = tp->y; 172 *surface = tp->surface; 173 174 if (tp->prev) { 175 tp->prev->next = tp->next; 176 } else { 177 touch_points.head = tp->next; 178 } 179 180 if (tp->next) { 181 tp->next->prev = tp->prev; 182 } else { 183 touch_points.tail = tp->prev; 184 } 185 186 { 187 struct SDL_WaylandTouchPoint *next = tp->next; 188 SDL_free(tp); 189 tp = next; 190 } 191 } else { 192 tp = tp->next; 193 } 194 } 195 } 196 197 static struct wl_surface* 198 touch_surface(SDL_TouchID id) 199 { 200 struct SDL_WaylandTouchPoint* tp = touch_points.head; 201 202 while (tp) { 203 if (tp->id == id) { 204 return tp->surface; 205 } 206 207 tp = tp->next; 208 } 209 210 return NULL; 211 } 212 213 /* Returns the time till next repeat, or 0 if no key is down. */ 214 static void 215 keyboard_repeat_handle(SDL_WaylandKeyboardRepeat* repeat_info, uint32_t now) 216 { 217 if (!repeat_info->is_key_down || !repeat_info->is_initialized) { 218 return; 219 } 220 while (repeat_info->next_repeat_ms <= now) { 221 if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) { 222 SDL_SendKeyboardKey(SDL_PRESSED, repeat_info->scancode); 223 } 224 if (repeat_info->text[0]) { 225 SDL_SendKeyboardText(repeat_info->text); 226 } 227 repeat_info->next_repeat_ms += 1000 / repeat_info->repeat_rate; 228 } 229 } 230 231 static void 232 keyboard_repeat_clear(SDL_WaylandKeyboardRepeat* repeat_info) { 233 if (!repeat_info->is_initialized) { 234 return; 235 } 236 repeat_info->is_key_down = SDL_FALSE; 237 } 238 239 static void 240 keyboard_repeat_set(SDL_WaylandKeyboardRepeat* repeat_info, 241 uint32_t scancode, SDL_bool has_text, char text[8]) { 242 if (!repeat_info->is_initialized) { 243 return; 244 } 245 repeat_info->is_key_down = SDL_TRUE; 246 repeat_info->next_repeat_ms = SDL_GetTicks() + repeat_info->repeat_delay; 247 repeat_info->scancode = scancode; 248 if (has_text) { 249 memcpy(repeat_info->text, text, 8); 250 } else { 251 repeat_info->text[0] = '\0'; 252 } 253 } 254 255 void 256 Wayland_PumpEvents(_THIS) 257 { 258 SDL_VideoData *d = _this->driverdata; 259 struct SDL_WaylandInput *input = d->input; 260 int err; 261 262 WAYLAND_wl_display_flush(d->display); 263 264 if (input) { 265 uint32_t now = SDL_GetTicks(); 266 keyboard_repeat_handle(&input->keyboard_repeat, now); 267 } 268 269 if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) { 270 err = WAYLAND_wl_display_dispatch(d->display); 271 } else { 272 err = WAYLAND_wl_display_dispatch_pending(d->display); 273 } 274 if (err == -1 && !d->display_disconnected) { 275 /* Something has failed with the Wayland connection -- for example, 276 * the compositor may have shut down and closed its end of the socket, 277 * or there is a library-specific error. No recovery is possible. */ 278 d->display_disconnected = 1; 279 /* Only send a single quit message, as application shutdown might call 280 * SDL_PumpEvents */ 281 SDL_SendQuit(); 282 } 283 } 284 285 static void 286 pointer_handle_motion(void *data, struct wl_pointer *pointer, 287 uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) 288 { 289 struct SDL_WaylandInput *input = data; 290 SDL_WindowData *window = input->pointer_focus; 291 input->sx_w = sx_w; 292 input->sy_w = sy_w; 293 if (input->pointer_focus) { 294 const int sx = wl_fixed_to_int(sx_w); 295 const int sy = wl_fixed_to_int(sy_w); 296 SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy); 297 } 298 } 299 300 static void 301 pointer_handle_enter(void *data, struct wl_pointer *pointer, 302 uint32_t serial, struct wl_surface *surface, 303 wl_fixed_t sx_w, wl_fixed_t sy_w) 304 { 305 struct SDL_WaylandInput *input = data; 306 SDL_WindowData *window; 307 308 if (!surface) { 309 /* enter event for a window we've just destroyed */ 310 return; 311 } 312 313 /* This handler will be called twice in Wayland 1.4 314 * Once for the window surface which has valid user data 315 * and again for the mouse cursor surface which does not have valid user data 316 * We ignore the later 317 */ 318 319 window = (SDL_WindowData *)wl_surface_get_user_data(surface); 320 321 if (window) { 322 input->pointer_focus = window; 323 SDL_SetMouseFocus(window->sdlwindow); 324 /* In the case of e.g. a pointer confine warp, we may receive an enter 325 * event with no following motion event, but with the new coordinates 326 * as part of the enter event. */ 327 pointer_handle_motion(data, pointer, serial, sx_w, sy_w); 328 } 329 } 330 331 static void 332 pointer_handle_leave(void *data, struct wl_pointer *pointer, 333 uint32_t serial, struct wl_surface *surface) 334 { 335 struct SDL_WaylandInput *input = data; 336 337 if (input->pointer_focus) { 338 SDL_SetMouseFocus(NULL); 339 input->pointer_focus = NULL; 340 } 341 } 342 343 static SDL_bool 344 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) 345 { 346 SDL_WindowData *window_data = input->pointer_focus; 347 SDL_Window *window = window_data->sdlwindow; 348 349 if (window->hit_test) { 350 const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) }; 351 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); 352 353 static const uint32_t directions_wl[] = { 354 WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP, 355 WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT, 356 WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM, 357 WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT 358 }; 359 360 /* the names are different (ZXDG_TOPLEVEL_V6_RESIZE_EDGE_* vs 361 WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */ 362 const uint32_t *directions_zxdg = directions_wl; 363 364 switch (rc) { 365 case SDL_HITTEST_DRAGGABLE: 366 if (input->display->shell.xdg) { 367 xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial); 368 } else if (input->display->shell.zxdg) { 369 zxdg_toplevel_v6_move(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial); 370 } else { 371 wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial); 372 } 373 return SDL_TRUE; 374 375 case SDL_HITTEST_RESIZE_TOPLEFT: 376 case SDL_HITTEST_RESIZE_TOP: 377 case SDL_HITTEST_RESIZE_TOPRIGHT: 378 case SDL_HITTEST_RESIZE_RIGHT: 379 case SDL_HITTEST_RESIZE_BOTTOMRIGHT: 380 case SDL_HITTEST_RESIZE_BOTTOM: 381 case SDL_HITTEST_RESIZE_BOTTOMLEFT: 382 case SDL_HITTEST_RESIZE_LEFT: 383 if (input->display->shell.xdg) { 384 xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]); 385 } else if (input->display->shell.zxdg) { 386 zxdg_toplevel_v6_resize(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]); 387 } else { 388 wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions_wl[rc - SDL_HITTEST_RESIZE_TOPLEFT]); 389 } 390 return SDL_TRUE; 391 392 default: return SDL_FALSE; 393 } 394 } 395 396 return SDL_FALSE; 397 } 398 399 static void 400 pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial, 401 uint32_t time, uint32_t button, uint32_t state_w) 402 { 403 SDL_WindowData *window = input->pointer_focus; 404 enum wl_pointer_button_state state = state_w; 405 uint32_t sdl_button; 406 407 if (input->pointer_focus) { 408 switch (button) { 409 case BTN_LEFT: 410 sdl_button = SDL_BUTTON_LEFT; 411 if (ProcessHitTest(input, serial)) { 412 return; /* don't pass this event on to app. */ 413 } 414 break; 415 case BTN_MIDDLE: 416 sdl_button = SDL_BUTTON_MIDDLE; 417 break; 418 case BTN_RIGHT: 419 sdl_button = SDL_BUTTON_RIGHT; 420 break; 421 case BTN_SIDE: 422 sdl_button = SDL_BUTTON_X1; 423 break; 424 case BTN_EXTRA: 425 sdl_button = SDL_BUTTON_X2; 426 break; 427 default: 428 return; 429 } 430 431 Wayland_data_device_set_serial(input->data_device, serial); 432 433 SDL_SendMouseButton(window->sdlwindow, 0, 434 state ? SDL_PRESSED : SDL_RELEASED, sdl_button); 435 } 436 } 437 438 static void 439 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, 440 uint32_t time, uint32_t button, uint32_t state_w) 441 { 442 struct SDL_WaylandInput *input = data; 443 444 pointer_handle_button_common(input, serial, time, button, state_w); 445 } 446 447 static void 448 pointer_handle_axis_common_v1(struct SDL_WaylandInput *input, 449 uint32_t time, uint32_t axis, wl_fixed_t value) 450 { 451 SDL_WindowData *window = input->pointer_focus; 452 enum wl_pointer_axis a = axis; 453 float x, y; 454 455 if (input->pointer_focus) { 456 switch (a) { 457 case WL_POINTER_AXIS_VERTICAL_SCROLL: 458 x = 0; 459 y = 0 - (float)wl_fixed_to_double(value); 460 break; 461 case WL_POINTER_AXIS_HORIZONTAL_SCROLL: 462 x = 0 - (float)wl_fixed_to_double(value); 463 y = 0; 464 break; 465 default: 466 return; 467 } 468 469 SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL); 470 } 471 } 472 473 static void 474 pointer_handle_axis_common(struct SDL_WaylandInput *input, SDL_bool discrete, 475 uint32_t axis, wl_fixed_t value) 476 { 477 enum wl_pointer_axis a = axis; 478 479 if (input->pointer_focus) { 480 switch (a) { 481 case WL_POINTER_AXIS_VERTICAL_SCROLL: 482 if (discrete) { 483 /* this is a discrete axis event so we process it and flag 484 * to ignore future continuous axis events in this frame */ 485 input->pointer_curr_axis_info.is_y_discrete = SDL_TRUE; 486 } else if(input->pointer_curr_axis_info.is_y_discrete) { 487 /* this is a continuous axis event and we have already 488 * processed a discrete axis event before so we ignore it */ 489 break; 490 } 491 input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value); 492 break; 493 case WL_POINTER_AXIS_HORIZONTAL_SCROLL: 494 if (discrete) { 495 /* this is a discrete axis event so we process it and flag 496 * to ignore future continuous axis events in this frame */ 497 input->pointer_curr_axis_info.is_x_discrete = SDL_TRUE; 498 } else if(input->pointer_curr_axis_info.is_x_discrete) { 499 /* this is a continuous axis event and we have already 500 * processed a discrete axis event before so we ignore it */ 501 break; 502 } 503 input->pointer_curr_axis_info.x = 0 - (float)wl_fixed_to_double(value); 504 break; 505 } 506 } 507 } 508 509 static void 510 pointer_handle_axis(void *data, struct wl_pointer *pointer, 511 uint32_t time, uint32_t axis, wl_fixed_t value) 512 { 513 struct SDL_WaylandInput *input = data; 514 515 if(wl_seat_get_version(input->seat) >= 5) 516 pointer_handle_axis_common(input, SDL_FALSE, axis, value); 517 else 518 pointer_handle_axis_common_v1(input, time, axis, value); 519 } 520 521 static void 522 pointer_handle_frame(void *data, struct wl_pointer *pointer) 523 { 524 struct SDL_WaylandInput *input = data; 525 SDL_WindowData *window = input->pointer_focus; 526 float x = input->pointer_curr_axis_info.x, y = input->pointer_curr_axis_info.y; 527 528 /* clear pointer_curr_axis_info for next frame */ 529 memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info); 530 531 if(x == 0.0f && y == 0.0f) 532 return; 533 else 534 SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL); 535 } 536 537 static void 538 pointer_handle_axis_source(void *data, struct wl_pointer *pointer, 539 uint32_t axis_source) 540 { 541 /* unimplemented */ 542 } 543 544 static void 545 pointer_handle_axis_stop(void *data, struct wl_pointer *pointer, 546 uint32_t time, uint32_t axis) 547 { 548 /* unimplemented */ 549 } 550 551 static void 552 pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer, 553 uint32_t axis, int32_t discrete) 554 { 555 struct SDL_WaylandInput *input = data; 556 557 pointer_handle_axis_common(input, SDL_TRUE, axis, wl_fixed_from_int(discrete)); 558 } 559 560 561 static const struct wl_pointer_listener pointer_listener = { 562 pointer_handle_enter, 563 pointer_handle_leave, 564 pointer_handle_motion, 565 pointer_handle_button, 566 pointer_handle_axis, 567 pointer_handle_frame, // Version 5 568 pointer_handle_axis_source, // Version 5 569 pointer_handle_axis_stop, // Version 5 570 pointer_handle_axis_discrete, // Version 5 571 }; 572 573 static void 574 touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial, 575 unsigned int timestamp, struct wl_surface *surface, 576 int id, wl_fixed_t fx, wl_fixed_t fy) 577 { 578 SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface); 579 const double dblx = wl_fixed_to_double(fx); 580 const double dbly = wl_fixed_to_double(fy); 581 const float x = dblx / window_data->sdlwindow->w; 582 const float y = dbly / window_data->sdlwindow->h; 583 584 touch_add(id, x, y, surface); 585 586 SDL_SendTouch(1, (SDL_FingerID)id, window_data->sdlwindow, SDL_TRUE, x, y, 1.0f); 587 } 588 589 static void 590 touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial, 591 unsigned int timestamp, int id) 592 { 593 float x = 0, y = 0; 594 struct wl_surface *surface = NULL; 595 SDL_Window *window = NULL; 596 597 touch_del(id, &x, &y, &surface); 598 599 if (surface) { 600 SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface); 601 window = window_data->sdlwindow; 602 } 603 604 SDL_SendTouch(1, (SDL_FingerID)id, window, SDL_FALSE, x, y, 0.0f); 605 } 606 607 static void 608 touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp, 609 int id, wl_fixed_t fx, wl_fixed_t fy) 610 { 611 SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id)); 612 const double dblx = wl_fixed_to_double(fx); 613 const double dbly = wl_fixed_to_double(fy); 614 const float x = dblx / window_data->sdlwindow->w; 615 const float y = dbly / window_data->sdlwindow->h; 616 617 touch_update(id, x, y); 618 SDL_SendTouchMotion(1, (SDL_FingerID)id, window_data->sdlwindow, x, y, 1.0f); 619 } 620 621 static void 622 touch_handler_frame(void *data, struct wl_touch *touch) 623 { 624 625 } 626 627 static void 628 touch_handler_cancel(void *data, struct wl_touch *touch) 629 { 630 631 } 632 633 static const struct wl_touch_listener touch_listener = { 634 touch_handler_down, 635 touch_handler_up, 636 touch_handler_motion, 637 touch_handler_frame, 638 touch_handler_cancel, 639 NULL, /* shape */ 640 NULL, /* orientation */ 641 }; 642 643 static void 644 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, 645 uint32_t format, int fd, uint32_t size) 646 { 647 struct SDL_WaylandInput *input = data; 648 char *map_str; 649 650 if (!data) { 651 close(fd); 652 return; 653 } 654 655 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { 656 close(fd); 657 return; 658 } 659 660 map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 661 if (map_str == MAP_FAILED) { 662 close(fd); 663 return; 664 } 665 666 input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context, 667 map_str, 668 XKB_KEYMAP_FORMAT_TEXT_V1, 669 0); 670 munmap(map_str, size); 671 close(fd); 672 673 if (!input->xkb.keymap) { 674 fprintf(stderr, "failed to compile keymap\n"); 675 return; 676 } 677 678 input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap); 679 if (!input->xkb.state) { 680 fprintf(stderr, "failed to create XKB state\n"); 681 WAYLAND_xkb_keymap_unref(input->xkb.keymap); 682 input->xkb.keymap = NULL; 683 return; 684 } 685 } 686 687 static void 688 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, 689 uint32_t serial, struct wl_surface *surface, 690 struct wl_array *keys) 691 { 692 struct SDL_WaylandInput *input = data; 693 SDL_WindowData *window; 694 695 if (!surface) { 696 /* enter event for a window we've just destroyed */ 697 return; 698 } 699 700 window = wl_surface_get_user_data(surface); 701 702 if (window) { 703 input->keyboard_focus = window; 704 window->keyboard_device = input; 705 SDL_SetKeyboardFocus(window->sdlwindow); 706 } 707 } 708 709 static void 710 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, 711 uint32_t serial, struct wl_surface *surface) 712 { 713 SDL_SetKeyboardFocus(NULL); 714 } 715 716 static SDL_bool 717 keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key) 718 { 719 SDL_WindowData *window = input->keyboard_focus; 720 const xkb_keysym_t *syms; 721 722 if (!window || window->keyboard_device != input || !input->xkb.state) { 723 return SDL_FALSE; 724 } 725 726 // TODO can this happen? 727 if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) { 728 return SDL_FALSE; 729 } 730 731 return WAYLAND_xkb_keysym_to_utf8(syms[0], text, 8) > 0; 732 } 733 734 static void 735 keyboard_handle_key(void *data, struct wl_keyboard *keyboard, 736 uint32_t serial, uint32_t time, uint32_t key, 737 uint32_t state_w) 738 { 739 struct SDL_WaylandInput *input = data; 740 enum wl_keyboard_key_state state = state_w; 741 uint32_t scancode = SDL_SCANCODE_UNKNOWN; 742 char text[8]; 743 744 if (key < SDL_arraysize(xfree86_scancode_table2)) { 745 scancode = xfree86_scancode_table2[key]; 746 747 if (scancode != SDL_SCANCODE_UNKNOWN) { 748 SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ? 749 SDL_PRESSED : SDL_RELEASED, scancode); 750 } 751 } 752 753 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { 754 SDL_bool has_text = keyboard_input_get_text(text, input, key); 755 if (has_text) { 756 Wayland_data_device_set_serial(input->data_device, serial); 757 SDL_SendKeyboardText(text); 758 } 759 keyboard_repeat_set(&input->keyboard_repeat, scancode, has_text, text); 760 } else { 761 keyboard_repeat_clear(&input->keyboard_repeat); 762 } 763 } 764 765 static void 766 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, 767 uint32_t serial, uint32_t mods_depressed, 768 uint32_t mods_latched, uint32_t mods_locked, 769 uint32_t group) 770 { 771 struct SDL_WaylandInput *input = data; 772 773 WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, 774 mods_locked, 0, 0, group); 775 } 776 777 static void 778 keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, 779 int32_t rate, int32_t delay) 780 { 781 struct SDL_WaylandInput *input = data; 782 input->keyboard_repeat.repeat_rate = SDL_max(0, SDL_min(rate, 1000)); 783 input->keyboard_repeat.repeat_delay = delay; 784 input->keyboard_repeat.is_initialized = SDL_TRUE; 785 } 786 787 static const struct wl_keyboard_listener keyboard_listener = { 788 keyboard_handle_keymap, 789 keyboard_handle_enter, 790 keyboard_handle_leave, 791 keyboard_handle_key, 792 keyboard_handle_modifiers, 793 keyboard_handle_repeat_info, // Version 4 794 }; 795 796 static void 797 seat_handle_capabilities(void *data, struct wl_seat *seat, 798 enum wl_seat_capability caps) 799 { 800 struct SDL_WaylandInput *input = data; 801 802 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) { 803 input->pointer = wl_seat_get_pointer(seat); 804 memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info); 805 input->display->pointer = input->pointer; 806 wl_pointer_set_user_data(input->pointer, input); 807 wl_pointer_add_listener(input->pointer, &pointer_listener, 808 input); 809 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { 810 wl_pointer_destroy(input->pointer); 811 input->pointer = NULL; 812 input->display->pointer = NULL; 813 } 814 815 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) { 816 SDL_AddTouch(1, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch"); 817 input->touch = wl_seat_get_touch(seat); 818 wl_touch_set_user_data(input->touch, input); 819 wl_touch_add_listener(input->touch, &touch_listener, 820 input); 821 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) { 822 SDL_DelTouch(1); 823 wl_touch_destroy(input->touch); 824 input->touch = NULL; 825 } 826 827 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) { 828 input->keyboard = wl_seat_get_keyboard(seat); 829 wl_keyboard_set_user_data(input->keyboard, input); 830 wl_keyboard_add_listener(input->keyboard, &keyboard_listener, 831 input); 832 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) { 833 wl_keyboard_destroy(input->keyboard); 834 input->keyboard = NULL; 835 } 836 } 837 838 static void 839 seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) 840 { 841 /* unimplemented */ 842 } 843 844 static const struct wl_seat_listener seat_listener = { 845 seat_handle_capabilities, 846 seat_handle_name, // Version 2 847 }; 848 849 static void 850 data_source_handle_target(void *data, struct wl_data_source *wl_data_source, 851 const char *mime_type) 852 { 853 } 854 855 static void 856 data_source_handle_send(void *data, struct wl_data_source *wl_data_source, 857 const char *mime_type, int32_t fd) 858 { 859 Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd); 860 } 861 862 static void 863 data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source) 864 { 865 Wayland_data_source_destroy(data); 866 } 867 868 static void 869 data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source) 870 { 871 } 872 873 static void 874 data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source) 875 { 876 } 877 878 static void 879 data_source_handle_action(void *data, struct wl_data_source *wl_data_source, 880 uint32_t dnd_action) 881 { 882 } 883 884 static const struct wl_data_source_listener data_source_listener = { 885 data_source_handle_target, 886 data_source_handle_send, 887 data_source_handle_cancelled, 888 data_source_handle_dnd_drop_performed, // Version 3 889 data_source_handle_dnd_finished, // Version 3 890 data_source_handle_action, // Version 3 891 }; 892 893 SDL_WaylandDataSource* 894 Wayland_data_source_create(_THIS) 895 { 896 SDL_WaylandDataSource *data_source = NULL; 897 SDL_VideoData *driver_data = NULL; 898 struct wl_data_source *id = NULL; 899 900 if (_this == NULL || _this->driverdata == NULL) { 901 SDL_SetError("Video driver uninitialized"); 902 } else { 903 driver_data = _this->driverdata; 904 905 if (driver_data->data_device_manager != NULL) { 906 id = wl_data_device_manager_create_data_source( 907 driver_data->data_device_manager); 908 } 909 910 if (id == NULL) { 911 SDL_SetError("Wayland unable to create data source"); 912 } else { 913 data_source = SDL_calloc(1, sizeof *data_source); 914 if (data_source == NULL) { 915 SDL_OutOfMemory(); 916 wl_data_source_destroy(id); 917 } else { 918 WAYLAND_wl_list_init(&(data_source->mimes)); 919 data_source->source = id; 920 wl_data_source_set_user_data(id, data_source); 921 wl_data_source_add_listener(id, &data_source_listener, 922 data_source); 923 } 924 } 925 } 926 return data_source; 927 } 928 929 static void 930 data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer, 931 const char *mime_type) 932 { 933 SDL_WaylandDataOffer *offer = data; 934 Wayland_data_offer_add_mime(offer, mime_type); 935 } 936 937 static void 938 data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer, 939 uint32_t source_actions) 940 { 941 } 942 943 static void 944 data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer, 945 uint32_t dnd_action) 946 { 947 } 948 949 static const struct wl_data_offer_listener data_offer_listener = { 950 data_offer_handle_offer, 951 data_offer_handle_source_actions, // Version 3 952 data_offer_handle_actions, // Version 3 953 }; 954 955 static void 956 data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device, 957 struct wl_data_offer *id) 958 { 959 SDL_WaylandDataOffer *data_offer = NULL; 960 961 data_offer = SDL_calloc(1, sizeof *data_offer); 962 if (data_offer == NULL) { 963 SDL_OutOfMemory(); 964 } else { 965 data_offer->offer = id; 966 data_offer->data_device = data; 967 WAYLAND_wl_list_init(&(data_offer->mimes)); 968 wl_data_offer_set_user_data(id, data_offer); 969 wl_data_offer_add_listener(id, &data_offer_listener, data_offer); 970 } 971 } 972 973 static void 974 data_device_handle_enter(void *data, struct wl_data_device *wl_data_device, 975 uint32_t serial, struct wl_surface *surface, 976 wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id) 977 { 978 SDL_WaylandDataDevice *data_device = data; 979 SDL_bool has_mime = SDL_FALSE; 980 uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; 981 982 data_device->drag_serial = serial; 983 984 if (id != NULL) { 985 data_device->drag_offer = wl_data_offer_get_user_data(id); 986 987 /* TODO: SDL Support more mime types */ 988 has_mime = Wayland_data_offer_has_mime( 989 data_device->drag_offer, FILE_MIME); 990 991 /* If drag_mime is NULL this will decline the offer */ 992 wl_data_offer_accept(id, serial, 993 (has_mime == SDL_TRUE) ? FILE_MIME : NULL); 994 995 /* SDL only supports "copy" style drag and drop */ 996 if (has_mime == SDL_TRUE) { 997 dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; 998 } 999 if (wl_data_offer_get_version(data_device->drag_offer->offer) >= 3) { 1000 wl_data_offer_set_actions(data_device->drag_offer->offer, 1001 dnd_action, dnd_action); 1002 } 1003 } 1004 } 1005 1006 static void 1007 data_device_handle_leave(void *data, struct wl_data_device *wl_data_device) 1008 { 1009 SDL_WaylandDataDevice *data_device = data; 1010 SDL_WaylandDataOffer *offer = NULL; 1011 1012 if (data_device->selection_offer != NULL) { 1013 data_device->selection_offer = NULL; 1014 Wayland_data_offer_destroy(offer); 1015 } 1016 } 1017 1018 static void 1019 data_device_handle_motion(void *data, struct wl_data_device *wl_data_device, 1020 uint32_t time, wl_fixed_t x, wl_fixed_t y) 1021 { 1022 } 1023 1024 static void 1025 data_device_handle_drop(void *data, struct wl_data_device *wl_data_device) 1026 { 1027 SDL_WaylandDataDevice *data_device = data; 1028 void *buffer = NULL; 1029 size_t length = 0; 1030 1031 const char *current_uri = NULL; 1032 const char *last_char = NULL; 1033 char *current_char = NULL; 1034 1035 if (data_device->drag_offer != NULL) { 1036 /* TODO: SDL Support more mime types */ 1037 buffer = Wayland_data_offer_receive(data_device->drag_offer, 1038 &length, FILE_MIME, SDL_FALSE); 1039 1040 /* uri-list */ 1041 current_uri = (const char *)buffer; 1042 last_char = (const char *)buffer + length; 1043 for (current_char = buffer; current_char < last_char; ++current_char) { 1044 if (*current_char == '\n' || *current_char == 0) { 1045 if (*current_uri != 0 && *current_uri != '#') { 1046 *current_char = 0; 1047 SDL_SendDropFile(NULL, current_uri); 1048 } 1049 current_uri = (const char *)current_char + 1; 1050 } 1051 } 1052 1053 SDL_free(buffer); 1054 } 1055 } 1056 1057 static void 1058 data_device_handle_selection(void *data, struct wl_data_device *wl_data_device, 1059 struct wl_data_offer *id) 1060 { 1061 SDL_WaylandDataDevice *data_device = data; 1062 SDL_WaylandDataOffer *offer = NULL; 1063 1064 if (id != NULL) { 1065 offer = wl_data_offer_get_user_data(id); 1066 } 1067 1068 if (data_device->selection_offer != offer) { 1069 Wayland_data_offer_destroy(data_device->selection_offer); 1070 data_device->selection_offer = offer; 1071 } 1072 1073 SDL_SendClipboardUpdate(); 1074 } 1075 1076 static const struct wl_data_device_listener data_device_listener = { 1077 data_device_handle_data_offer, 1078 data_device_handle_enter, 1079 data_device_handle_leave, 1080 data_device_handle_motion, 1081 data_device_handle_drop, 1082 data_device_handle_selection 1083 }; 1084 1085 void 1086 Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) 1087 { 1088 struct SDL_WaylandInput *input; 1089 SDL_WaylandDataDevice *data_device = NULL; 1090 1091 input = SDL_calloc(1, sizeof *input); 1092 if (input == NULL) 1093 return; 1094 1095 input->display = d; 1096 input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version)); 1097 input->sx_w = wl_fixed_from_int(0); 1098 input->sy_w = wl_fixed_from_int(0); 1099 d->input = input; 1100 1101 if (d->data_device_manager != NULL) { 1102 data_device = SDL_calloc(1, sizeof *data_device); 1103 if (data_device == NULL) { 1104 return; 1105 } 1106 1107 data_device->data_device = wl_data_device_manager_get_data_device( 1108 d->data_device_manager, input->seat 1109 ); 1110 data_device->video_data = d; 1111 1112 if (data_device->data_device == NULL) { 1113 SDL_free(data_device); 1114 } else { 1115 wl_data_device_set_user_data(data_device->data_device, data_device); 1116 wl_data_device_add_listener(data_device->data_device, 1117 &data_device_listener, data_device); 1118 input->data_device = data_device; 1119 } 1120 } 1121 1122 wl_seat_add_listener(input->seat, &seat_listener, input); 1123 wl_seat_set_user_data(input->seat, input); 1124 1125 WAYLAND_wl_display_flush(d->display); 1126 } 1127 1128 void Wayland_display_destroy_input(SDL_VideoData *d) 1129 { 1130 struct SDL_WaylandInput *input = d->input; 1131 1132 if (!input) 1133 return; 1134 1135 if (input->data_device != NULL) { 1136 Wayland_data_device_clear_selection(input->data_device); 1137 if (input->data_device->selection_offer != NULL) { 1138 Wayland_data_offer_destroy(input->data_device->selection_offer); 1139 } 1140 if (input->data_device->drag_offer != NULL) { 1141 Wayland_data_offer_destroy(input->data_device->drag_offer); 1142 } 1143 if (input->data_device->data_device != NULL) { 1144 wl_data_device_release(input->data_device->data_device); 1145 } 1146 SDL_free(input->data_device); 1147 } 1148 1149 if (input->keyboard) 1150 wl_keyboard_destroy(input->keyboard); 1151 1152 if (input->pointer) 1153 wl_pointer_destroy(input->pointer); 1154 1155 if (input->touch) { 1156 SDL_DelTouch(1); 1157 wl_touch_destroy(input->touch); 1158 } 1159 1160 if (input->seat) 1161 wl_seat_destroy(input->seat); 1162 1163 if (input->xkb.state) 1164 WAYLAND_xkb_state_unref(input->xkb.state); 1165 1166 if (input->xkb.keymap) 1167 WAYLAND_xkb_keymap_unref(input->xkb.keymap); 1168 1169 SDL_free(input); 1170 d->input = NULL; 1171 } 1172 1173 SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input) 1174 { 1175 if (input == NULL) { 1176 return NULL; 1177 } 1178 1179 return input->data_device; 1180 } 1181 1182 /* !!! FIXME: just merge these into display_handle_global(). */ 1183 void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id) 1184 { 1185 d->relative_pointer_manager = 1186 wl_registry_bind(d->registry, id, 1187 &zwp_relative_pointer_manager_v1_interface, 1); 1188 } 1189 1190 void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d) 1191 { 1192 if (d->relative_pointer_manager) 1193 zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager); 1194 } 1195 1196 void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id) 1197 { 1198 d->pointer_constraints = 1199 wl_registry_bind(d->registry, id, 1200 &zwp_pointer_constraints_v1_interface, 1); 1201 } 1202 1203 void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d) 1204 { 1205 if (d->pointer_constraints) 1206 zwp_pointer_constraints_v1_destroy(d->pointer_constraints); 1207 } 1208 1209 static void 1210 relative_pointer_handle_relative_motion(void *data, 1211 struct zwp_relative_pointer_v1 *pointer, 1212 uint32_t time_hi, 1213 uint32_t time_lo, 1214 wl_fixed_t dx_w, 1215 wl_fixed_t dy_w, 1216 wl_fixed_t dx_unaccel_w, 1217 wl_fixed_t dy_unaccel_w) 1218 { 1219 struct SDL_WaylandInput *input = data; 1220 SDL_VideoData *d = input->display; 1221 SDL_WindowData *window = input->pointer_focus; 1222 double dx_unaccel; 1223 double dy_unaccel; 1224 double dx; 1225 double dy; 1226 1227 dx_unaccel = wl_fixed_to_double(dx_unaccel_w); 1228 dy_unaccel = wl_fixed_to_double(dy_unaccel_w); 1229 1230 /* Add left over fraction from last event. */ 1231 dx_unaccel += input->dx_frac; 1232 dy_unaccel += input->dy_frac; 1233 1234 input->dx_frac = modf(dx_unaccel, &dx); 1235 input->dy_frac = modf(dy_unaccel, &dy); 1236 1237 if (input->pointer_focus && d->relative_mouse_mode) { 1238 SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy); 1239 } 1240 } 1241 1242 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = { 1243 relative_pointer_handle_relative_motion, 1244 }; 1245 1246 static void 1247 locked_pointer_locked(void *data, 1248 struct zwp_locked_pointer_v1 *locked_pointer) 1249 { 1250 } 1251 1252 static void 1253 locked_pointer_unlocked(void *data, 1254 struct zwp_locked_pointer_v1 *locked_pointer) 1255 { 1256 } 1257 1258 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = { 1259 locked_pointer_locked, 1260 locked_pointer_unlocked, 1261 }; 1262 1263 static void 1264 lock_pointer_to_window(SDL_Window *window, 1265 struct SDL_WaylandInput *input) 1266 { 1267 SDL_WindowData *w = window->driverdata; 1268 SDL_VideoData *d = input->display; 1269 struct zwp_locked_pointer_v1 *locked_pointer; 1270 1271 if (w->locked_pointer) 1272 return; 1273 1274 locked_pointer = 1275 zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints, 1276 w->surface, 1277 input->pointer, 1278 NULL, 1279 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); 1280 zwp_locked_pointer_v1_add_listener(locked_pointer, 1281 &locked_pointer_listener, 1282 window); 1283 1284 w->locked_pointer = locked_pointer; 1285 } 1286 1287 static void pointer_confine_destroy(struct SDL_WaylandInput *input) 1288 { 1289 if (input->confined_pointer) { 1290 zwp_confined_pointer_v1_destroy(input->confined_pointer); 1291 input->confined_pointer = NULL; 1292 } 1293 } 1294 1295 int Wayland_input_lock_pointer(struct SDL_WaylandInput *input) 1296 { 1297 SDL_VideoDevice *vd = SDL_GetVideoDevice(); 1298 SDL_VideoData *d = input->display; 1299 SDL_Window *window; 1300 struct zwp_relative_pointer_v1 *relative_pointer; 1301 1302 if (!d->relative_pointer_manager) 1303 return -1; 1304 1305 if (!d->pointer_constraints) 1306 return -1; 1307 1308 if (!input->pointer) 1309 return -1; 1310 1311 /* If we have a pointer confine active, we must destroy it here because 1312 * creating a locked pointer otherwise would be a protocol error. */ 1313 pointer_confine_destroy(input); 1314 1315 if (!input->relative_pointer) { 1316 relative_pointer = 1317 zwp_relative_pointer_manager_v1_get_relative_pointer( 1318 d->relative_pointer_manager, 1319 input->pointer); 1320 zwp_relative_pointer_v1_add_listener(relative_pointer, 1321 &relative_pointer_listener, 1322 input); 1323 input->relative_pointer = relative_pointer; 1324 } 1325 1326 for (window = vd->windows; window; window = window->next) 1327 lock_pointer_to_window(window, input); 1328 1329 d->relative_mouse_mode = 1; 1330 1331 return 0; 1332 } 1333 1334 int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input) 1335 { 1336 SDL_VideoDevice *vd = SDL_GetVideoDevice(); 1337 SDL_VideoData *d = input->display; 1338 SDL_Window *window; 1339 SDL_WindowData *w; 1340 1341 for (window = vd->windows; window; window = window->next) { 1342 w = window->driverdata; 1343 if (w->locked_pointer) 1344 zwp_locked_pointer_v1_destroy(w->locked_pointer); 1345 w->locked_pointer = NULL; 1346 } 1347 1348 zwp_relative_pointer_v1_destroy(input->relative_pointer); 1349 input->relative_pointer = NULL; 1350 1351 d->relative_mouse_mode = 0; 1352 1353 if (input->confined_pointer_window) 1354 Wayland_input_confine_pointer(input->confined_pointer_window, input); 1355 1356 return 0; 1357 } 1358 1359 static void 1360 confined_pointer_confined(void *data, 1361 struct zwp_confined_pointer_v1 *confined_pointer) 1362 { 1363 } 1364 1365 static void 1366 confined_pointer_unconfined(void *data, 1367 struct zwp_confined_pointer_v1 *confined_pointer) 1368 { 1369 } 1370 1371 static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = { 1372 confined_pointer_confined, 1373 confined_pointer_unconfined, 1374 }; 1375 1376 int Wayland_input_confine_pointer(SDL_Window *window, struct SDL_WaylandInput *input) 1377 { 1378 SDL_WindowData *w = window->driverdata; 1379 SDL_VideoData *d = input->display; 1380 struct zwp_confined_pointer_v1 *confined_pointer; 1381 1382 if (!d->pointer_constraints) 1383 return -1; 1384 1385 if (!input->pointer) 1386 return -1; 1387 1388 /* A confine may already be active, in which case we should destroy it and 1389 * create a new one. */ 1390 if (input->confined_pointer) 1391 Wayland_input_unconfine_pointer(input); 1392 1393 input->confined_pointer_window = window; 1394 1395 /* We cannot create a confine if the pointer is already locked. Defer until 1396 * the pointer is unlocked. */ 1397 if (d->relative_mouse_mode) 1398 return 0; 1399 1400 confined_pointer = 1401 zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints, 1402 w->surface, 1403 input->pointer, 1404 NULL, 1405 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); 1406 zwp_confined_pointer_v1_add_listener(confined_pointer, 1407 &confined_pointer_listener, 1408 window); 1409 1410 input->confined_pointer = confined_pointer; 1411 return 0; 1412 } 1413 1414 int Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input) 1415 { 1416 pointer_confine_destroy(input); 1417 input->confined_pointer_window = NULL; 1418 return 0; 1419 } 1420 1421 #endif /* SDL_VIDEO_DRIVER_WAYLAND */ 1422 1423 /* vi: set ts=4 sw=4 expandtab: */