Atlas - SDL_waylandevents.c

Home / ext / SDL2 / src / video / wayland Lines: 4 | Size: 33775 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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_assert.h" 28#include "SDL_log.h" 29 30#include "../../core/unix/SDL_poll.h" 31#include "../../events/SDL_sysevents.h" 32#include "../../events/SDL_events_c.h" 33#include "../../events/scancodes_xfree86.h" 34 35#include "SDL_waylandvideo.h" 36#include "SDL_waylandevents_c.h" 37#include "SDL_waylandwindow.h" 38 39#include "SDL_waylanddyn.h" 40 41#include "pointer-constraints-unstable-v1-client-protocol.h" 42#include "relative-pointer-unstable-v1-client-protocol.h" 43#include "xdg-shell-client-protocol.h" 44#include "xdg-shell-unstable-v6-client-protocol.h" 45 46#include <linux/input.h> 47#include <sys/select.h> 48#include <sys/mman.h> 49#include <poll.h> 50#include <unistd.h> 51#include <xkbcommon/xkbcommon.h> 52 53struct SDL_WaylandInput { 54 SDL_VideoData *display; 55 struct wl_seat *seat; 56 struct wl_pointer *pointer; 57 struct wl_touch *touch; 58 struct wl_keyboard *keyboard; 59 SDL_WaylandDataDevice *data_device; 60 struct zwp_relative_pointer_v1 *relative_pointer; 61 SDL_WindowData *pointer_focus; 62 SDL_WindowData *keyboard_focus; 63 64 /* Last motion location */ 65 wl_fixed_t sx_w; 66 wl_fixed_t sy_w; 67 68 double dx_frac; 69 double dy_frac; 70 71 struct { 72 struct xkb_keymap *keymap; 73 struct xkb_state *state; 74 } xkb; 75}; 76 77struct SDL_WaylandTouchPoint { 78 SDL_TouchID id; 79 float x; 80 float y; 81 struct wl_surface* surface; 82 83 struct SDL_WaylandTouchPoint* prev; 84 struct SDL_WaylandTouchPoint* next; 85}; 86 87struct SDL_WaylandTouchPointList { 88 struct SDL_WaylandTouchPoint* head; 89 struct SDL_WaylandTouchPoint* tail; 90}; 91 92static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL}; 93 94static void 95touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface) 96{ 97 struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint)); 98 99 tp->id = id; 100 tp->x = x; 101 tp->y = y; 102 tp->surface = surface; 103 104 if (touch_points.tail) { 105 touch_points.tail->next = tp; 106 tp->prev = touch_points.tail; 107 } else { 108 touch_points.head = tp; 109 tp->prev = NULL; 110 } 111 112 touch_points.tail = tp; 113 tp->next = NULL; 114} 115 116static void 117touch_update(SDL_TouchID id, float x, float y) 118{ 119 struct SDL_WaylandTouchPoint* tp = touch_points.head; 120 121 while (tp) { 122 if (tp->id == id) { 123 tp->x = x; 124 tp->y = y; 125 } 126 127 tp = tp->next; 128 } 129} 130 131static void 132touch_del(SDL_TouchID id, float* x, float* y) 133{ 134 struct SDL_WaylandTouchPoint* tp = touch_points.head; 135 136 while (tp) { 137 if (tp->id == id) { 138 *x = tp->x; 139 *y = tp->y; 140 141 if (tp->prev) { 142 tp->prev->next = tp->next; 143 } else { 144 touch_points.head = tp->next; 145 } 146 147 if (tp->next) { 148 tp->next->prev = tp->prev; 149 } else { 150 touch_points.tail = tp->prev; 151 } 152 153 SDL_free(tp); 154 } 155 156 tp = tp->next; 157 } 158} 159 160static struct wl_surface* 161touch_surface(SDL_TouchID id) 162{ 163 struct SDL_WaylandTouchPoint* tp = touch_points.head; 164 165 while (tp) { 166 if (tp->id == id) { 167 return tp->surface; 168 } 169 170 tp = tp->next; 171 } 172 173 return NULL; 174} 175 176void 177Wayland_PumpEvents(_THIS) 178{ 179 SDL_VideoData *d = _this->driverdata; 180 181 if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) { 182 WAYLAND_wl_display_dispatch(d->display); 183 } 184 else 185 { 186 WAYLAND_wl_display_dispatch_pending(d->display); 187 } 188} 189 190static void 191pointer_handle_enter(void *data, struct wl_pointer *pointer, 192 uint32_t serial, struct wl_surface *surface, 193 wl_fixed_t sx_w, wl_fixed_t sy_w) 194{ 195 struct SDL_WaylandInput *input = data; 196 SDL_WindowData *window; 197 198 if (!surface) { 199 /* enter event for a window we've just destroyed */ 200 return; 201 } 202 203 /* This handler will be called twice in Wayland 1.4 204 * Once for the window surface which has valid user data 205 * and again for the mouse cursor surface which does not have valid user data 206 * We ignore the later 207 */ 208 209 window = (SDL_WindowData *)wl_surface_get_user_data(surface); 210 211 if (window) { 212 input->pointer_focus = window; 213 SDL_SetMouseFocus(window->sdlwindow); 214 } 215} 216 217static void 218pointer_handle_leave(void *data, struct wl_pointer *pointer, 219 uint32_t serial, struct wl_surface *surface) 220{ 221 struct SDL_WaylandInput *input = data; 222 223 if (input->pointer_focus) { 224 SDL_SetMouseFocus(NULL); 225 input->pointer_focus = NULL; 226 } 227} 228 229static void 230pointer_handle_motion(void *data, struct wl_pointer *pointer, 231 uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) 232{ 233 struct SDL_WaylandInput *input = data; 234 SDL_WindowData *window = input->pointer_focus; 235 input->sx_w = sx_w; 236 input->sy_w = sy_w; 237 if (input->pointer_focus) { 238 const int sx = wl_fixed_to_int(sx_w); 239 const int sy = wl_fixed_to_int(sy_w); 240 SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy); 241 } 242} 243 244static SDL_bool 245ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) 246{ 247 SDL_WindowData *window_data = input->pointer_focus; 248 SDL_Window *window = window_data->sdlwindow; 249 250 if (window->hit_test) { 251 const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) }; 252 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); 253 254 static const uint32_t directions_wl[] = { 255 WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP, 256 WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT, 257 WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM, 258 WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT 259 }; 260 261 /* the names are different (ZXDG_TOPLEVEL_V6_RESIZE_EDGE_* vs 262 WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */ 263 const uint32_t *directions_zxdg = directions_wl; 264 265 switch (rc) { 266 case SDL_HITTEST_DRAGGABLE: 267 if (input->display->shell.xdg) { 268 xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial); 269 } else if (input->display->shell.zxdg) { 270 zxdg_toplevel_v6_move(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial); 271 } else { 272 wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial); 273 } 274 return SDL_TRUE; 275 276 case SDL_HITTEST_RESIZE_TOPLEFT: 277 case SDL_HITTEST_RESIZE_TOP: 278 case SDL_HITTEST_RESIZE_TOPRIGHT: 279 case SDL_HITTEST_RESIZE_RIGHT: 280 case SDL_HITTEST_RESIZE_BOTTOMRIGHT: 281 case SDL_HITTEST_RESIZE_BOTTOM: 282 case SDL_HITTEST_RESIZE_BOTTOMLEFT: 283 case SDL_HITTEST_RESIZE_LEFT: 284 if (input->display->shell.xdg) { 285 xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]); 286 } else if (input->display->shell.zxdg) { 287 zxdg_toplevel_v6_resize(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]); 288 } else { 289 wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions_wl[rc - SDL_HITTEST_RESIZE_TOPLEFT]); 290 } 291 return SDL_TRUE; 292 293 default: return SDL_FALSE; 294 } 295 } 296 297 return SDL_FALSE; 298} 299 300static void 301pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial, 302 uint32_t time, uint32_t button, uint32_t state_w) 303{ 304 SDL_WindowData *window = input->pointer_focus; 305 enum wl_pointer_button_state state = state_w; 306 uint32_t sdl_button; 307 308 if (input->pointer_focus) { 309 switch (button) { 310 case BTN_LEFT: 311 sdl_button = SDL_BUTTON_LEFT; 312 if (ProcessHitTest(input, serial)) { 313 return; /* don't pass this event on to app. */ 314 } 315 break; 316 case BTN_MIDDLE: 317 sdl_button = SDL_BUTTON_MIDDLE; 318 break; 319 case BTN_RIGHT: 320 sdl_button = SDL_BUTTON_RIGHT; 321 break; 322 case BTN_SIDE: 323 sdl_button = SDL_BUTTON_X1; 324 break; 325 case BTN_EXTRA: 326 sdl_button = SDL_BUTTON_X2; 327 break; 328 default: 329 return; 330 } 331 332 Wayland_data_device_set_serial(input->data_device, serial); 333 334 SDL_SendMouseButton(window->sdlwindow, 0, 335 state ? SDL_PRESSED : SDL_RELEASED, sdl_button); 336 } 337} 338 339static void 340pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, 341 uint32_t time, uint32_t button, uint32_t state_w) 342{ 343 struct SDL_WaylandInput *input = data; 344 345 pointer_handle_button_common(input, serial, time, button, state_w); 346} 347 348static void 349pointer_handle_axis_common(struct SDL_WaylandInput *input, 350 uint32_t time, uint32_t axis, wl_fixed_t value) 351{ 352 SDL_WindowData *window = input->pointer_focus; 353 enum wl_pointer_axis a = axis; 354 float x, y; 355 356 if (input->pointer_focus) { 357 switch (a) { 358 case WL_POINTER_AXIS_VERTICAL_SCROLL: 359 x = 0; 360 y = 0 - (float)wl_fixed_to_double(value); 361 break; 362 case WL_POINTER_AXIS_HORIZONTAL_SCROLL: 363 x = 0 - (float)wl_fixed_to_double(value); 364 y = 0; 365 break; 366 default: 367 return; 368 } 369 370 SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL); 371 } 372} 373 374static void 375pointer_handle_axis(void *data, struct wl_pointer *pointer, 376 uint32_t time, uint32_t axis, wl_fixed_t value) 377{ 378 struct SDL_WaylandInput *input = data; 379 380 pointer_handle_axis_common(input, time, axis, value); 381} 382 383static const struct wl_pointer_listener pointer_listener = { 384 pointer_handle_enter, 385 pointer_handle_leave, 386 pointer_handle_motion, 387 pointer_handle_button, 388 pointer_handle_axis, 389 NULL, /* frame */ 390 NULL, /* axis_source */ 391 NULL, /* axis_stop */ 392 NULL, /* axis_discrete */ 393}; 394 395static void 396touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial, 397 unsigned int timestamp, struct wl_surface *surface, 398 int id, wl_fixed_t fx, wl_fixed_t fy) 399{ 400 float x, y; 401 SDL_WindowData* window; 402 403 window = (SDL_WindowData *)wl_surface_get_user_data(surface); 404 405 x = wl_fixed_to_double(fx) / window->sdlwindow->w; 406 y = wl_fixed_to_double(fy) / window->sdlwindow->h; 407 408 touch_add(id, x, y, surface); 409 SDL_SendTouch(1, (SDL_FingerID)id, SDL_TRUE, x, y, 1.0f); 410} 411 412static void 413touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial, 414 unsigned int timestamp, int id) 415{ 416 float x = 0, y = 0; 417 418 touch_del(id, &x, &y); 419 SDL_SendTouch(1, (SDL_FingerID)id, SDL_FALSE, x, y, 0.0f); 420} 421 422static void 423touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp, 424 int id, wl_fixed_t fx, wl_fixed_t fy) 425{ 426 float x, y; 427 SDL_WindowData* window; 428 429 window = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id)); 430 431 x = wl_fixed_to_double(fx) / window->sdlwindow->w; 432 y = wl_fixed_to_double(fy) / window->sdlwindow->h; 433 434 touch_update(id, x, y); 435 SDL_SendTouchMotion(1, (SDL_FingerID)id, x, y, 1.0f); 436} 437 438static void 439touch_handler_frame(void *data, struct wl_touch *touch) 440{ 441 442} 443 444static void 445touch_handler_cancel(void *data, struct wl_touch *touch) 446{ 447 448} 449 450static const struct wl_touch_listener touch_listener = { 451 touch_handler_down, 452 touch_handler_up, 453 touch_handler_motion, 454 touch_handler_frame, 455 touch_handler_cancel, 456 NULL, /* shape */ 457 NULL, /* orientation */ 458}; 459 460static void 461keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, 462 uint32_t format, int fd, uint32_t size) 463{ 464 struct SDL_WaylandInput *input = data; 465 char *map_str; 466 467 if (!data) { 468 close(fd); 469 return; 470 } 471 472 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { 473 close(fd); 474 return; 475 } 476 477 map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 478 if (map_str == MAP_FAILED) { 479 close(fd); 480 return; 481 } 482 483 input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context, 484 map_str, 485 XKB_KEYMAP_FORMAT_TEXT_V1, 486 0); 487 munmap(map_str, size); 488 close(fd); 489 490 if (!input->xkb.keymap) { 491 fprintf(stderr, "failed to compile keymap\n"); 492 return; 493 } 494 495 input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap); 496 if (!input->xkb.state) { 497 fprintf(stderr, "failed to create XKB state\n"); 498 WAYLAND_xkb_keymap_unref(input->xkb.keymap); 499 input->xkb.keymap = NULL; 500 return; 501 } 502} 503 504static void 505keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, 506 uint32_t serial, struct wl_surface *surface, 507 struct wl_array *keys) 508{ 509 struct SDL_WaylandInput *input = data; 510 SDL_WindowData *window; 511 512 if (!surface) { 513 /* enter event for a window we've just destroyed */ 514 return; 515 } 516 517 window = wl_surface_get_user_data(surface); 518 519 if (window) { 520 input->keyboard_focus = window; 521 window->keyboard_device = input; 522 SDL_SetKeyboardFocus(window->sdlwindow); 523 } 524} 525 526static void 527keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, 528 uint32_t serial, struct wl_surface *surface) 529{ 530 SDL_SetKeyboardFocus(NULL); 531} 532 533static void 534keyboard_handle_key(void *data, struct wl_keyboard *keyboard, 535 uint32_t serial, uint32_t time, uint32_t key, 536 uint32_t state_w) 537{ 538 struct SDL_WaylandInput *input = data; 539 SDL_WindowData *window = input->keyboard_focus; 540 enum wl_keyboard_key_state state = state_w; 541 const xkb_keysym_t *syms; 542 uint32_t scancode; 543 char text[8]; 544 int size; 545 546 if (key < SDL_arraysize(xfree86_scancode_table2)) { 547 scancode = xfree86_scancode_table2[key]; 548 549 // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT? 550 if (scancode != SDL_SCANCODE_UNKNOWN) 551 SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ? 552 SDL_PRESSED : SDL_RELEASED, scancode); 553 } 554 555 if (!window || window->keyboard_device != input || !input->xkb.state) 556 return; 557 558 // TODO can this happen? 559 if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) 560 return; 561 562 if (state) { 563 size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text); 564 565 if (size > 0) { 566 text[size] = 0; 567 568 Wayland_data_device_set_serial(input->data_device, serial); 569 570 SDL_SendKeyboardText(text); 571 } 572 } 573} 574 575static void 576keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, 577 uint32_t serial, uint32_t mods_depressed, 578 uint32_t mods_latched, uint32_t mods_locked, 579 uint32_t group) 580{ 581 struct SDL_WaylandInput *input = data; 582 583 WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, 584 mods_locked, 0, 0, group); 585} 586 587static const struct wl_keyboard_listener keyboard_listener = { 588 keyboard_handle_keymap, 589 keyboard_handle_enter, 590 keyboard_handle_leave, 591 keyboard_handle_key, 592 keyboard_handle_modifiers, 593 NULL, /* repeat_info */ 594}; 595 596static void 597seat_handle_capabilities(void *data, struct wl_seat *seat, 598 enum wl_seat_capability caps) 599{ 600 struct SDL_WaylandInput *input = data; 601 602 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) { 603 input->pointer = wl_seat_get_pointer(seat); 604 input->display->pointer = input->pointer; 605 wl_pointer_set_user_data(input->pointer, input); 606 wl_pointer_add_listener(input->pointer, &pointer_listener, 607 input); 608 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { 609 wl_pointer_destroy(input->pointer); 610 input->pointer = NULL; 611 input->display->pointer = NULL; 612 } 613 614 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) { 615 SDL_AddTouch(1, "wayland_touch"); 616 input->touch = wl_seat_get_touch(seat); 617 wl_touch_set_user_data(input->touch, input); 618 wl_touch_add_listener(input->touch, &touch_listener, 619 input); 620 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) { 621 SDL_DelTouch(1); 622 wl_touch_destroy(input->touch); 623 input->touch = NULL; 624 } 625 626 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) { 627 input->keyboard = wl_seat_get_keyboard(seat); 628 wl_keyboard_set_user_data(input->keyboard, input); 629 wl_keyboard_add_listener(input->keyboard, &keyboard_listener, 630 input); 631 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) { 632 wl_keyboard_destroy(input->keyboard); 633 input->keyboard = NULL; 634 } 635} 636 637static const struct wl_seat_listener seat_listener = { 638 seat_handle_capabilities, 639 NULL, /* name */ 640}; 641 642static void 643data_source_handle_target(void *data, struct wl_data_source *wl_data_source, 644 const char *mime_type) 645{ 646} 647 648static void 649data_source_handle_send(void *data, struct wl_data_source *wl_data_source, 650 const char *mime_type, int32_t fd) 651{ 652 Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd); 653} 654 655static void 656data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source) 657{ 658 Wayland_data_source_destroy(data); 659} 660 661static void 662data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source) 663{ 664} 665 666static void 667data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source) 668{ 669} 670 671static void 672data_source_handle_action(void *data, struct wl_data_source *wl_data_source, 673 uint32_t dnd_action) 674{ 675} 676 677static const struct wl_data_source_listener data_source_listener = { 678 data_source_handle_target, 679 data_source_handle_send, 680 data_source_handle_cancelled, 681 data_source_handle_dnd_drop_performed, // Version 3 682 data_source_handle_dnd_finished, // Version 3 683 data_source_handle_action, // Version 3 684}; 685 686SDL_WaylandDataSource* 687Wayland_data_source_create(_THIS) 688{ 689 SDL_WaylandDataSource *data_source = NULL; 690 SDL_VideoData *driver_data = NULL; 691 struct wl_data_source *id = NULL; 692 693 if (_this == NULL || _this->driverdata == NULL) { 694 SDL_SetError("Video driver uninitialized"); 695 } else { 696 driver_data = _this->driverdata; 697 698 if (driver_data->data_device_manager != NULL) { 699 id = wl_data_device_manager_create_data_source( 700 driver_data->data_device_manager); 701 } 702 703 if (id == NULL) { 704 SDL_SetError("Wayland unable to create data source"); 705 } else { 706 data_source = SDL_calloc(1, sizeof *data_source); 707 if (data_source == NULL) { 708 SDL_OutOfMemory(); 709 wl_data_source_destroy(id); 710 } else { 711 WAYLAND_wl_list_init(&(data_source->mimes)); 712 data_source->source = id; 713 wl_data_source_set_user_data(id, data_source); 714 wl_data_source_add_listener(id, &data_source_listener, 715 data_source); 716 } 717 } 718 } 719 return data_source; 720} 721 722static void 723data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer, 724 const char *mime_type) 725{ 726 SDL_WaylandDataOffer *offer = data; 727 Wayland_data_offer_add_mime(offer, mime_type); 728} 729 730static void 731data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer, 732 uint32_t source_actions) 733{ 734} 735 736static void 737data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer, 738 uint32_t dnd_action) 739{ 740} 741 742static const struct wl_data_offer_listener data_offer_listener = { 743 data_offer_handle_offer, 744 data_offer_handle_source_actions, // Version 3 745 data_offer_handle_actions, // Version 3 746}; 747 748static void 749data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device, 750 struct wl_data_offer *id) 751{ 752 SDL_WaylandDataOffer *data_offer = NULL; 753 754 data_offer = SDL_calloc(1, sizeof *data_offer); 755 if (data_offer == NULL) { 756 SDL_OutOfMemory(); 757 } else { 758 data_offer->offer = id; 759 data_offer->data_device = data; 760 WAYLAND_wl_list_init(&(data_offer->mimes)); 761 wl_data_offer_set_user_data(id, data_offer); 762 wl_data_offer_add_listener(id, &data_offer_listener, data_offer); 763 } 764} 765 766static void 767data_device_handle_enter(void *data, struct wl_data_device *wl_data_device, 768 uint32_t serial, struct wl_surface *surface, 769 wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id) 770{ 771 SDL_WaylandDataDevice *data_device = data; 772 SDL_bool has_mime = SDL_FALSE; 773 uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; 774 775 data_device->drag_serial = serial; 776 777 if (id != NULL) { 778 data_device->drag_offer = wl_data_offer_get_user_data(id); 779 780 /* TODO: SDL Support more mime types */ 781 has_mime = Wayland_data_offer_has_mime( 782 data_device->drag_offer, FILE_MIME); 783 784 /* If drag_mime is NULL this will decline the offer */ 785 wl_data_offer_accept(id, serial, 786 (has_mime == SDL_TRUE) ? FILE_MIME : NULL); 787 788 /* SDL only supports "copy" style drag and drop */ 789 if (has_mime == SDL_TRUE) { 790 dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; 791 } 792 wl_data_offer_set_actions(data_device->drag_offer->offer, 793 dnd_action, dnd_action); 794 } 795} 796 797static void 798data_device_handle_leave(void *data, struct wl_data_device *wl_data_device) 799{ 800 SDL_WaylandDataDevice *data_device = data; 801 SDL_WaylandDataOffer *offer = NULL; 802 803 if (data_device->selection_offer != NULL) { 804 data_device->selection_offer = NULL; 805 Wayland_data_offer_destroy(offer); 806 } 807} 808 809static void 810data_device_handle_motion(void *data, struct wl_data_device *wl_data_device, 811 uint32_t time, wl_fixed_t x, wl_fixed_t y) 812{ 813} 814 815static void 816data_device_handle_drop(void *data, struct wl_data_device *wl_data_device) 817{ 818 SDL_WaylandDataDevice *data_device = data; 819 void *buffer = NULL; 820 size_t length = 0; 821 822 const char *current_uri = NULL; 823 const char *last_char = NULL; 824 char *current_char = NULL; 825 826 if (data_device->drag_offer != NULL) { 827 /* TODO: SDL Support more mime types */ 828 buffer = Wayland_data_offer_receive(data_device->drag_offer, 829 &length, FILE_MIME, SDL_FALSE); 830 831 /* uri-list */ 832 current_uri = (const char *)buffer; 833 last_char = (const char *)buffer + length; 834 for (current_char = buffer; current_char < last_char; ++current_char) { 835 if (*current_char == '\n' || *current_char == 0) { 836 if (*current_uri != 0 && *current_uri != '#') { 837 *current_char = 0; 838 SDL_SendDropFile(NULL, current_uri); 839 } 840 current_uri = (const char *)current_char + 1; 841 } 842 } 843 844 SDL_free(buffer); 845 } 846} 847 848static void 849data_device_handle_selection(void *data, struct wl_data_device *wl_data_device, 850 struct wl_data_offer *id) 851{ 852 SDL_WaylandDataDevice *data_device = data; 853 SDL_WaylandDataOffer *offer = NULL; 854 855 if (id != NULL) { 856 offer = wl_data_offer_get_user_data(id); 857 } 858 859 if (data_device->selection_offer != offer) { 860 Wayland_data_offer_destroy(data_device->selection_offer); 861 data_device->selection_offer = offer; 862 } 863 864 SDL_SendClipboardUpdate(); 865} 866 867static const struct wl_data_device_listener data_device_listener = { 868 data_device_handle_data_offer, 869 data_device_handle_enter, 870 data_device_handle_leave, 871 data_device_handle_motion, 872 data_device_handle_drop, 873 data_device_handle_selection 874}; 875 876void 877Wayland_display_add_input(SDL_VideoData *d, uint32_t id) 878{ 879 struct SDL_WaylandInput *input; 880 SDL_WaylandDataDevice *data_device = NULL; 881 882 input = SDL_calloc(1, sizeof *input); 883 if (input == NULL) 884 return; 885 886 input->display = d; 887 input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1); 888 input->sx_w = wl_fixed_from_int(0); 889 input->sy_w = wl_fixed_from_int(0); 890 d->input = input; 891 892 if (d->data_device_manager != NULL) { 893 data_device = SDL_calloc(1, sizeof *data_device); 894 if (data_device == NULL) { 895 return; 896 } 897 898 data_device->data_device = wl_data_device_manager_get_data_device( 899 d->data_device_manager, input->seat 900 ); 901 data_device->video_data = d; 902 903 if (data_device->data_device == NULL) { 904 SDL_free(data_device); 905 } else { 906 wl_data_device_set_user_data(data_device->data_device, data_device); 907 wl_data_device_add_listener(data_device->data_device, 908 &data_device_listener, data_device); 909 input->data_device = data_device; 910 } 911 } 912 913 wl_seat_add_listener(input->seat, &seat_listener, input); 914 wl_seat_set_user_data(input->seat, input); 915 916 WAYLAND_wl_display_flush(d->display); 917} 918 919void Wayland_display_destroy_input(SDL_VideoData *d) 920{ 921 struct SDL_WaylandInput *input = d->input; 922 923 if (!input) 924 return; 925 926 if (input->data_device != NULL) { 927 Wayland_data_device_clear_selection(input->data_device); 928 if (input->data_device->selection_offer != NULL) { 929 Wayland_data_offer_destroy(input->data_device->selection_offer); 930 } 931 if (input->data_device->drag_offer != NULL) { 932 Wayland_data_offer_destroy(input->data_device->drag_offer); 933 } 934 if (input->data_device->data_device != NULL) { 935 wl_data_device_release(input->data_device->data_device); 936 } 937 SDL_free(input->data_device); 938 } 939 940 if (input->keyboard) 941 wl_keyboard_destroy(input->keyboard); 942 943 if (input->pointer) 944 wl_pointer_destroy(input->pointer); 945 946 if (input->touch) { 947 SDL_DelTouch(1); 948 wl_touch_destroy(input->touch); 949 } 950 951 if (input->seat) 952 wl_seat_destroy(input->seat); 953 954 if (input->xkb.state) 955 WAYLAND_xkb_state_unref(input->xkb.state); 956 957 if (input->xkb.keymap) 958 WAYLAND_xkb_keymap_unref(input->xkb.keymap); 959 960 SDL_free(input); 961 d->input = NULL; 962} 963 964SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input) 965{ 966 if (input == NULL) { 967 return NULL; 968 } 969 970 return input->data_device; 971} 972 973/* !!! FIXME: just merge these into display_handle_global(). */ 974void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id) 975{ 976 d->relative_pointer_manager = 977 wl_registry_bind(d->registry, id, 978 &zwp_relative_pointer_manager_v1_interface, 1); 979} 980 981void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d) 982{ 983 if (d->relative_pointer_manager) 984 zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager); 985} 986 987void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id) 988{ 989 d->pointer_constraints = 990 wl_registry_bind(d->registry, id, 991 &zwp_pointer_constraints_v1_interface, 1); 992} 993 994void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d) 995{ 996 if (d->pointer_constraints) 997 zwp_pointer_constraints_v1_destroy(d->pointer_constraints); 998} 999 1000static void 1001relative_pointer_handle_relative_motion(void *data, 1002 struct zwp_relative_pointer_v1 *pointer, 1003 uint32_t time_hi, 1004 uint32_t time_lo, 1005 wl_fixed_t dx_w, 1006 wl_fixed_t dy_w, 1007 wl_fixed_t dx_unaccel_w, 1008 wl_fixed_t dy_unaccel_w) 1009{ 1010 struct SDL_WaylandInput *input = data; 1011 SDL_VideoData *d = input->display; 1012 SDL_WindowData *window = input->pointer_focus; 1013 double dx_unaccel; 1014 double dy_unaccel; 1015 double dx; 1016 double dy; 1017 1018 dx_unaccel = wl_fixed_to_double(dx_unaccel_w); 1019 dy_unaccel = wl_fixed_to_double(dy_unaccel_w); 1020 1021 /* Add left over fraction from last event. */ 1022 dx_unaccel += input->dx_frac; 1023 dy_unaccel += input->dy_frac; 1024 1025 input->dx_frac = modf(dx_unaccel, &dx); 1026 input->dy_frac = modf(dy_unaccel, &dy); 1027 1028 if (input->pointer_focus && d->relative_mouse_mode) { 1029 SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy); 1030 } 1031} 1032 1033static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = { 1034 relative_pointer_handle_relative_motion, 1035}; 1036 1037static void 1038locked_pointer_locked(void *data, 1039 struct zwp_locked_pointer_v1 *locked_pointer) 1040{ 1041} 1042 1043static void 1044locked_pointer_unlocked(void *data, 1045 struct zwp_locked_pointer_v1 *locked_pointer) 1046{ 1047} 1048 1049static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = { 1050 locked_pointer_locked, 1051 locked_pointer_unlocked, 1052}; 1053 1054static void 1055lock_pointer_to_window(SDL_Window *window, 1056 struct SDL_WaylandInput *input) 1057{ 1058 SDL_WindowData *w = window->driverdata; 1059 SDL_VideoData *d = input->display; 1060 struct zwp_locked_pointer_v1 *locked_pointer; 1061 1062 if (w->locked_pointer) 1063 return; 1064 1065 locked_pointer = 1066 zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints, 1067 w->surface, 1068 input->pointer, 1069 NULL, 1070 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); 1071 zwp_locked_pointer_v1_add_listener(locked_pointer, 1072 &locked_pointer_listener, 1073 window); 1074 1075 w->locked_pointer = locked_pointer; 1076} 1077 1078int Wayland_input_lock_pointer(struct SDL_WaylandInput *input) 1079{ 1080 SDL_VideoDevice *vd = SDL_GetVideoDevice(); 1081 SDL_VideoData *d = input->display; 1082 SDL_Window *window; 1083 struct zwp_relative_pointer_v1 *relative_pointer; 1084 1085 if (!d->relative_pointer_manager) 1086 return -1; 1087 1088 if (!d->pointer_constraints) 1089 return -1; 1090 1091 if (!input->relative_pointer) { 1092 relative_pointer = 1093 zwp_relative_pointer_manager_v1_get_relative_pointer( 1094 d->relative_pointer_manager, 1095 input->pointer); 1096 zwp_relative_pointer_v1_add_listener(relative_pointer, 1097 &relative_pointer_listener, 1098 input); 1099 input->relative_pointer = relative_pointer; 1100 } 1101 1102 for (window = vd->windows; window; window = window->next) 1103 lock_pointer_to_window(window, input); 1104 1105 d->relative_mouse_mode = 1; 1106 1107 return 0; 1108} 1109 1110int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input) 1111{ 1112 SDL_VideoDevice *vd = SDL_GetVideoDevice(); 1113 SDL_VideoData *d = input->display; 1114 SDL_Window *window; 1115 SDL_WindowData *w; 1116 1117 for (window = vd->windows; window; window = window->next) { 1118 w = window->driverdata; 1119 if (w->locked_pointer) 1120 zwp_locked_pointer_v1_destroy(w->locked_pointer); 1121 w->locked_pointer = NULL; 1122 } 1123 1124 zwp_relative_pointer_v1_destroy(input->relative_pointer); 1125 input->relative_pointer = NULL; 1126 1127 d->relative_mouse_mode = 0; 1128 1129 return 0; 1130} 1131 1132#endif /* SDL_VIDEO_DRIVER_WAYLAND */ 1133 1134/* vi: set ts=4 sw=4 expandtab: */ 1135
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.