wl_init.c (46280B)
1 //======================================================================== 2 // GLFW 3.3 Wayland - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com> 5 // 6 // This software is provided 'as-is', without any express or implied 7 // warranty. In no event will the authors be held liable for any damages 8 // arising from the use of this software. 9 // 10 // Permission is granted to anyone to use this software for any purpose, 11 // including commercial applications, and to alter it and redistribute it 12 // freely, subject to the following restrictions: 13 // 14 // 1. The origin of this software must not be misrepresented; you must not 15 // claim that you wrote the original software. If you use this software 16 // in a product, an acknowledgment in the product documentation would 17 // be appreciated but is not required. 18 // 19 // 2. Altered source versions must be plainly marked as such, and must not 20 // be misrepresented as being the original software. 21 // 22 // 3. This notice may not be removed or altered from any source 23 // distribution. 24 // 25 //======================================================================== 26 // It is fine to use C99 in this file because it will not be built with VS 27 //======================================================================== 28 29 #include "internal.h" 30 31 #include <assert.h> 32 #include <errno.h> 33 #include <limits.h> 34 #include <linux/input.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <sys/mman.h> 39 #include <sys/timerfd.h> 40 #include <unistd.h> 41 #include <wayland-client.h> 42 43 44 static inline int min(int n1, int n2) 45 { 46 return n1 < n2 ? n1 : n2; 47 } 48 49 static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, 50 int* which) 51 { 52 int focus; 53 _GLFWwindow* window = _glfw.windowListHead; 54 if (!which) 55 which = &focus; 56 while (window) 57 { 58 if (surface == window->wl.decorations.top.surface) 59 { 60 *which = topDecoration; 61 break; 62 } 63 if (surface == window->wl.decorations.left.surface) 64 { 65 *which = leftDecoration; 66 break; 67 } 68 if (surface == window->wl.decorations.right.surface) 69 { 70 *which = rightDecoration; 71 break; 72 } 73 if (surface == window->wl.decorations.bottom.surface) 74 { 75 *which = bottomDecoration; 76 break; 77 } 78 window = window->next; 79 } 80 return window; 81 } 82 83 static void pointerHandleEnter(void* data, 84 struct wl_pointer* pointer, 85 uint32_t serial, 86 struct wl_surface* surface, 87 wl_fixed_t sx, 88 wl_fixed_t sy) 89 { 90 // Happens in the case we just destroyed the surface. 91 if (!surface) 92 return; 93 94 int focus = 0; 95 _GLFWwindow* window = wl_surface_get_user_data(surface); 96 if (!window) 97 { 98 window = findWindowFromDecorationSurface(surface, &focus); 99 if (!window) 100 return; 101 } 102 103 window->wl.decorations.focus = focus; 104 _glfw.wl.serial = serial; 105 _glfw.wl.pointerFocus = window; 106 107 window->wl.hovered = GLFW_TRUE; 108 109 _glfwPlatformSetCursor(window, window->wl.currentCursor); 110 _glfwInputCursorEnter(window, GLFW_TRUE); 111 } 112 113 static void pointerHandleLeave(void* data, 114 struct wl_pointer* pointer, 115 uint32_t serial, 116 struct wl_surface* surface) 117 { 118 _GLFWwindow* window = _glfw.wl.pointerFocus; 119 120 if (!window) 121 return; 122 123 window->wl.hovered = GLFW_FALSE; 124 125 _glfw.wl.serial = serial; 126 _glfw.wl.pointerFocus = NULL; 127 _glfwInputCursorEnter(window, GLFW_FALSE); 128 _glfw.wl.cursorPreviousName = NULL; 129 } 130 131 static void setCursor(_GLFWwindow* window, const char* name) 132 { 133 struct wl_buffer* buffer; 134 struct wl_cursor* cursor; 135 struct wl_cursor_image* image; 136 struct wl_surface* surface = _glfw.wl.cursorSurface; 137 struct wl_cursor_theme* theme = _glfw.wl.cursorTheme; 138 int scale = 1; 139 140 if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI) 141 { 142 // We only support up to scale=2 for now, since libwayland-cursor 143 // requires us to load a different theme for each size. 144 scale = 2; 145 theme = _glfw.wl.cursorThemeHiDPI; 146 } 147 148 cursor = wl_cursor_theme_get_cursor(theme, name); 149 if (!cursor) 150 { 151 _glfwInputError(GLFW_PLATFORM_ERROR, 152 "Wayland: Standard cursor not found"); 153 return; 154 } 155 // TODO: handle animated cursors too. 156 image = cursor->images[0]; 157 158 if (!image) 159 return; 160 161 buffer = wl_cursor_image_get_buffer(image); 162 if (!buffer) 163 return; 164 wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, 165 surface, 166 image->hotspot_x / scale, 167 image->hotspot_y / scale); 168 wl_surface_set_buffer_scale(surface, scale); 169 wl_surface_attach(surface, buffer, 0, 0); 170 wl_surface_damage(surface, 0, 0, 171 image->width, image->height); 172 wl_surface_commit(surface); 173 _glfw.wl.cursorPreviousName = name; 174 } 175 176 static void pointerHandleMotion(void* data, 177 struct wl_pointer* pointer, 178 uint32_t time, 179 wl_fixed_t sx, 180 wl_fixed_t sy) 181 { 182 _GLFWwindow* window = _glfw.wl.pointerFocus; 183 const char* cursorName = NULL; 184 double x, y; 185 186 if (!window) 187 return; 188 189 if (window->cursorMode == GLFW_CURSOR_DISABLED) 190 return; 191 x = wl_fixed_to_double(sx); 192 y = wl_fixed_to_double(sy); 193 194 switch (window->wl.decorations.focus) 195 { 196 case mainWindow: 197 window->wl.cursorPosX = x; 198 window->wl.cursorPosY = y; 199 _glfwInputCursorPos(window, x, y); 200 _glfw.wl.cursorPreviousName = NULL; 201 return; 202 case topDecoration: 203 if (y < _GLFW_DECORATION_WIDTH) 204 cursorName = "n-resize"; 205 else 206 cursorName = "left_ptr"; 207 break; 208 case leftDecoration: 209 if (y < _GLFW_DECORATION_WIDTH) 210 cursorName = "nw-resize"; 211 else 212 cursorName = "w-resize"; 213 break; 214 case rightDecoration: 215 if (y < _GLFW_DECORATION_WIDTH) 216 cursorName = "ne-resize"; 217 else 218 cursorName = "e-resize"; 219 break; 220 case bottomDecoration: 221 if (x < _GLFW_DECORATION_WIDTH) 222 cursorName = "sw-resize"; 223 else if (x > window->wl.width + _GLFW_DECORATION_WIDTH) 224 cursorName = "se-resize"; 225 else 226 cursorName = "s-resize"; 227 break; 228 default: 229 assert(0); 230 } 231 if (_glfw.wl.cursorPreviousName != cursorName) 232 setCursor(window, cursorName); 233 } 234 235 static void pointerHandleButton(void* data, 236 struct wl_pointer* pointer, 237 uint32_t serial, 238 uint32_t time, 239 uint32_t button, 240 uint32_t state) 241 { 242 _GLFWwindow* window = _glfw.wl.pointerFocus; 243 int glfwButton; 244 245 // Both xdg-shell and wl_shell use the same values. 246 uint32_t edges = WL_SHELL_SURFACE_RESIZE_NONE; 247 248 if (!window) 249 return; 250 if (button == BTN_LEFT) 251 { 252 switch (window->wl.decorations.focus) 253 { 254 case mainWindow: 255 break; 256 case topDecoration: 257 if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) 258 edges = WL_SHELL_SURFACE_RESIZE_TOP; 259 else 260 { 261 if (window->wl.xdg.toplevel) 262 xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial); 263 else 264 wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, serial); 265 } 266 break; 267 case leftDecoration: 268 if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) 269 edges = WL_SHELL_SURFACE_RESIZE_TOP_LEFT; 270 else 271 edges = WL_SHELL_SURFACE_RESIZE_LEFT; 272 break; 273 case rightDecoration: 274 if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) 275 edges = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT; 276 else 277 edges = WL_SHELL_SURFACE_RESIZE_RIGHT; 278 break; 279 case bottomDecoration: 280 if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH) 281 edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT; 282 else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH) 283 edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; 284 else 285 edges = WL_SHELL_SURFACE_RESIZE_BOTTOM; 286 break; 287 default: 288 assert(0); 289 } 290 if (edges != WL_SHELL_SURFACE_RESIZE_NONE) 291 { 292 if (window->wl.xdg.toplevel) 293 xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, 294 serial, edges); 295 else 296 wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat, 297 serial, edges); 298 } 299 } 300 else if (button == BTN_RIGHT) 301 { 302 if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel) 303 { 304 xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, 305 _glfw.wl.seat, serial, 306 window->wl.cursorPosX, 307 window->wl.cursorPosY); 308 return; 309 } 310 } 311 312 // Don’t pass the button to the user if it was related to a decoration. 313 if (window->wl.decorations.focus != mainWindow) 314 return; 315 316 _glfw.wl.serial = serial; 317 318 /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev 319 * codes. */ 320 glfwButton = button - BTN_LEFT; 321 322 _glfwInputMouseClick(window, 323 glfwButton, 324 state == WL_POINTER_BUTTON_STATE_PRESSED 325 ? GLFW_PRESS 326 : GLFW_RELEASE, 327 _glfw.wl.xkb.modifiers); 328 } 329 330 static void pointerHandleAxis(void* data, 331 struct wl_pointer* pointer, 332 uint32_t time, 333 uint32_t axis, 334 wl_fixed_t value) 335 { 336 _GLFWwindow* window = _glfw.wl.pointerFocus; 337 double x = 0.0, y = 0.0; 338 // Wayland scroll events are in pointer motion coordinate space (think two 339 // finger scroll). The factor 10 is commonly used to convert to "scroll 340 // step means 1.0. 341 const double scrollFactor = 1.0 / 10.0; 342 343 if (!window) 344 return; 345 346 assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL || 347 axis == WL_POINTER_AXIS_VERTICAL_SCROLL); 348 349 if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) 350 x = wl_fixed_to_double(value) * scrollFactor; 351 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) 352 y = wl_fixed_to_double(value) * scrollFactor; 353 354 _glfwInputScroll(window, x, y); 355 } 356 357 static const struct wl_pointer_listener pointerListener = { 358 pointerHandleEnter, 359 pointerHandleLeave, 360 pointerHandleMotion, 361 pointerHandleButton, 362 pointerHandleAxis, 363 }; 364 365 static void keyboardHandleKeymap(void* data, 366 struct wl_keyboard* keyboard, 367 uint32_t format, 368 int fd, 369 uint32_t size) 370 { 371 struct xkb_keymap* keymap; 372 struct xkb_state* state; 373 374 #ifdef HAVE_XKBCOMMON_COMPOSE_H 375 struct xkb_compose_table* composeTable; 376 struct xkb_compose_state* composeState; 377 #endif 378 379 char* mapStr; 380 const char* locale; 381 382 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) 383 { 384 close(fd); 385 return; 386 } 387 388 mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 389 if (mapStr == MAP_FAILED) { 390 close(fd); 391 return; 392 } 393 394 keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context, 395 mapStr, 396 XKB_KEYMAP_FORMAT_TEXT_V1, 397 0); 398 munmap(mapStr, size); 399 close(fd); 400 401 if (!keymap) 402 { 403 _glfwInputError(GLFW_PLATFORM_ERROR, 404 "Wayland: Failed to compile keymap"); 405 return; 406 } 407 408 state = xkb_state_new(keymap); 409 if (!state) 410 { 411 _glfwInputError(GLFW_PLATFORM_ERROR, 412 "Wayland: Failed to create XKB state"); 413 xkb_keymap_unref(keymap); 414 return; 415 } 416 417 // Look up the preferred locale, falling back to "C" as default. 418 locale = getenv("LC_ALL"); 419 if (!locale) 420 locale = getenv("LC_CTYPE"); 421 if (!locale) 422 locale = getenv("LANG"); 423 if (!locale) 424 locale = "C"; 425 426 #ifdef HAVE_XKBCOMMON_COMPOSE_H 427 composeTable = 428 xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, 429 XKB_COMPOSE_COMPILE_NO_FLAGS); 430 if (composeTable) 431 { 432 composeState = 433 xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS); 434 xkb_compose_table_unref(composeTable); 435 if (composeState) 436 _glfw.wl.xkb.composeState = composeState; 437 else 438 _glfwInputError(GLFW_PLATFORM_ERROR, 439 "Wayland: Failed to create XKB compose state"); 440 } 441 else 442 { 443 _glfwInputError(GLFW_PLATFORM_ERROR, 444 "Wayland: Failed to create XKB compose table"); 445 } 446 #endif 447 448 xkb_keymap_unref(_glfw.wl.xkb.keymap); 449 xkb_state_unref(_glfw.wl.xkb.state); 450 _glfw.wl.xkb.keymap = keymap; 451 _glfw.wl.xkb.state = state; 452 453 _glfw.wl.xkb.controlMask = 454 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control"); 455 _glfw.wl.xkb.altMask = 456 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); 457 _glfw.wl.xkb.shiftMask = 458 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); 459 _glfw.wl.xkb.superMask = 460 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); 461 _glfw.wl.xkb.capsLockMask = 462 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); 463 _glfw.wl.xkb.numLockMask = 464 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); 465 } 466 467 static void keyboardHandleEnter(void* data, 468 struct wl_keyboard* keyboard, 469 uint32_t serial, 470 struct wl_surface* surface, 471 struct wl_array* keys) 472 { 473 // Happens in the case we just destroyed the surface. 474 if (!surface) 475 return; 476 477 _GLFWwindow* window = wl_surface_get_user_data(surface); 478 if (!window) 479 { 480 window = findWindowFromDecorationSurface(surface, NULL); 481 if (!window) 482 return; 483 } 484 485 _glfw.wl.serial = serial; 486 _glfw.wl.keyboardFocus = window; 487 _glfwInputWindowFocus(window, GLFW_TRUE); 488 } 489 490 static void keyboardHandleLeave(void* data, 491 struct wl_keyboard* keyboard, 492 uint32_t serial, 493 struct wl_surface* surface) 494 { 495 _GLFWwindow* window = _glfw.wl.keyboardFocus; 496 497 if (!window) 498 return; 499 500 _glfw.wl.serial = serial; 501 _glfw.wl.keyboardFocus = NULL; 502 _glfwInputWindowFocus(window, GLFW_FALSE); 503 } 504 505 static int toGLFWKeyCode(uint32_t key) 506 { 507 if (key < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0])) 508 return _glfw.wl.keycodes[key]; 509 510 return GLFW_KEY_UNKNOWN; 511 } 512 513 #ifdef HAVE_XKBCOMMON_COMPOSE_H 514 static xkb_keysym_t composeSymbol(xkb_keysym_t sym) 515 { 516 if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) 517 return sym; 518 if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym) 519 != XKB_COMPOSE_FEED_ACCEPTED) 520 return sym; 521 switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState)) 522 { 523 case XKB_COMPOSE_COMPOSED: 524 return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState); 525 case XKB_COMPOSE_COMPOSING: 526 case XKB_COMPOSE_CANCELLED: 527 return XKB_KEY_NoSymbol; 528 case XKB_COMPOSE_NOTHING: 529 default: 530 return sym; 531 } 532 } 533 #endif 534 535 static GLFWbool inputChar(_GLFWwindow* window, uint32_t key) 536 { 537 uint32_t code, numSyms; 538 long cp; 539 const xkb_keysym_t *syms; 540 xkb_keysym_t sym; 541 542 code = key + 8; 543 numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms); 544 545 if (numSyms == 1) 546 { 547 #ifdef HAVE_XKBCOMMON_COMPOSE_H 548 sym = composeSymbol(syms[0]); 549 #else 550 sym = syms[0]; 551 #endif 552 cp = _glfwKeySym2Unicode(sym); 553 if (cp != -1) 554 { 555 const int mods = _glfw.wl.xkb.modifiers; 556 const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); 557 _glfwInputChar(window, cp, mods, plain); 558 } 559 } 560 561 return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, syms[0]); 562 } 563 564 static void keyboardHandleKey(void* data, 565 struct wl_keyboard* keyboard, 566 uint32_t serial, 567 uint32_t time, 568 uint32_t key, 569 uint32_t state) 570 { 571 int keyCode; 572 int action; 573 _GLFWwindow* window = _glfw.wl.keyboardFocus; 574 GLFWbool shouldRepeat; 575 struct itimerspec timer = {}; 576 577 if (!window) 578 return; 579 580 keyCode = toGLFWKeyCode(key); 581 action = state == WL_KEYBOARD_KEY_STATE_PRESSED 582 ? GLFW_PRESS : GLFW_RELEASE; 583 584 _glfw.wl.serial = serial; 585 _glfwInputKey(window, keyCode, key, action, 586 _glfw.wl.xkb.modifiers); 587 588 if (action == GLFW_PRESS) 589 { 590 shouldRepeat = inputChar(window, key); 591 592 if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0) 593 { 594 _glfw.wl.keyboardLastKey = keyCode; 595 _glfw.wl.keyboardLastScancode = key; 596 if (_glfw.wl.keyboardRepeatRate > 1) 597 timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyboardRepeatRate; 598 else 599 timer.it_interval.tv_sec = 1; 600 timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000; 601 timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000; 602 } 603 } 604 timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL); 605 } 606 607 static void keyboardHandleModifiers(void* data, 608 struct wl_keyboard* keyboard, 609 uint32_t serial, 610 uint32_t modsDepressed, 611 uint32_t modsLatched, 612 uint32_t modsLocked, 613 uint32_t group) 614 { 615 xkb_mod_mask_t mask; 616 unsigned int modifiers = 0; 617 618 _glfw.wl.serial = serial; 619 620 if (!_glfw.wl.xkb.keymap) 621 return; 622 623 xkb_state_update_mask(_glfw.wl.xkb.state, 624 modsDepressed, 625 modsLatched, 626 modsLocked, 627 0, 628 0, 629 group); 630 631 mask = xkb_state_serialize_mods(_glfw.wl.xkb.state, 632 XKB_STATE_MODS_DEPRESSED | 633 XKB_STATE_LAYOUT_DEPRESSED | 634 XKB_STATE_MODS_LATCHED | 635 XKB_STATE_LAYOUT_LATCHED); 636 if (mask & _glfw.wl.xkb.controlMask) 637 modifiers |= GLFW_MOD_CONTROL; 638 if (mask & _glfw.wl.xkb.altMask) 639 modifiers |= GLFW_MOD_ALT; 640 if (mask & _glfw.wl.xkb.shiftMask) 641 modifiers |= GLFW_MOD_SHIFT; 642 if (mask & _glfw.wl.xkb.superMask) 643 modifiers |= GLFW_MOD_SUPER; 644 if (mask & _glfw.wl.xkb.capsLockMask) 645 modifiers |= GLFW_MOD_CAPS_LOCK; 646 if (mask & _glfw.wl.xkb.numLockMask) 647 modifiers |= GLFW_MOD_NUM_LOCK; 648 _glfw.wl.xkb.modifiers = modifiers; 649 } 650 651 #ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 652 static void keyboardHandleRepeatInfo(void* data, 653 struct wl_keyboard* keyboard, 654 int32_t rate, 655 int32_t delay) 656 { 657 if (keyboard != _glfw.wl.keyboard) 658 return; 659 660 _glfw.wl.keyboardRepeatRate = rate; 661 _glfw.wl.keyboardRepeatDelay = delay; 662 } 663 #endif 664 665 static const struct wl_keyboard_listener keyboardListener = { 666 keyboardHandleKeymap, 667 keyboardHandleEnter, 668 keyboardHandleLeave, 669 keyboardHandleKey, 670 keyboardHandleModifiers, 671 #ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 672 keyboardHandleRepeatInfo, 673 #endif 674 }; 675 676 static void seatHandleCapabilities(void* data, 677 struct wl_seat* seat, 678 enum wl_seat_capability caps) 679 { 680 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer) 681 { 682 _glfw.wl.pointer = wl_seat_get_pointer(seat); 683 wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); 684 } 685 else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) 686 { 687 wl_pointer_destroy(_glfw.wl.pointer); 688 _glfw.wl.pointer = NULL; 689 } 690 691 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard) 692 { 693 _glfw.wl.keyboard = wl_seat_get_keyboard(seat); 694 wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); 695 } 696 else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) 697 { 698 wl_keyboard_destroy(_glfw.wl.keyboard); 699 _glfw.wl.keyboard = NULL; 700 } 701 } 702 703 static void seatHandleName(void* data, 704 struct wl_seat* seat, 705 const char* name) 706 { 707 } 708 709 static const struct wl_seat_listener seatListener = { 710 seatHandleCapabilities, 711 seatHandleName, 712 }; 713 714 static void dataOfferHandleOffer(void* data, 715 struct wl_data_offer* dataOffer, 716 const char* mimeType) 717 { 718 } 719 720 static const struct wl_data_offer_listener dataOfferListener = { 721 dataOfferHandleOffer, 722 }; 723 724 static void dataDeviceHandleDataOffer(void* data, 725 struct wl_data_device* dataDevice, 726 struct wl_data_offer* id) 727 { 728 if (_glfw.wl.dataOffer) 729 wl_data_offer_destroy(_glfw.wl.dataOffer); 730 731 _glfw.wl.dataOffer = id; 732 wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL); 733 } 734 735 static void dataDeviceHandleEnter(void* data, 736 struct wl_data_device* dataDevice, 737 uint32_t serial, 738 struct wl_surface *surface, 739 wl_fixed_t x, 740 wl_fixed_t y, 741 struct wl_data_offer *id) 742 { 743 } 744 745 static void dataDeviceHandleLeave(void* data, 746 struct wl_data_device* dataDevice) 747 { 748 } 749 750 static void dataDeviceHandleMotion(void* data, 751 struct wl_data_device* dataDevice, 752 uint32_t time, 753 wl_fixed_t x, 754 wl_fixed_t y) 755 { 756 } 757 758 static void dataDeviceHandleDrop(void* data, 759 struct wl_data_device* dataDevice) 760 { 761 } 762 763 static void dataDeviceHandleSelection(void* data, 764 struct wl_data_device* dataDevice, 765 struct wl_data_offer* id) 766 { 767 } 768 769 static const struct wl_data_device_listener dataDeviceListener = { 770 dataDeviceHandleDataOffer, 771 dataDeviceHandleEnter, 772 dataDeviceHandleLeave, 773 dataDeviceHandleMotion, 774 dataDeviceHandleDrop, 775 dataDeviceHandleSelection, 776 }; 777 778 static void wmBaseHandlePing(void* data, 779 struct xdg_wm_base* wmBase, 780 uint32_t serial) 781 { 782 xdg_wm_base_pong(wmBase, serial); 783 } 784 785 static const struct xdg_wm_base_listener wmBaseListener = { 786 wmBaseHandlePing 787 }; 788 789 static void registryHandleGlobal(void* data, 790 struct wl_registry* registry, 791 uint32_t name, 792 const char* interface, 793 uint32_t version) 794 { 795 if (strcmp(interface, "wl_compositor") == 0) 796 { 797 _glfw.wl.compositorVersion = min(3, version); 798 _glfw.wl.compositor = 799 wl_registry_bind(registry, name, &wl_compositor_interface, 800 _glfw.wl.compositorVersion); 801 } 802 else if (strcmp(interface, "wl_subcompositor") == 0) 803 { 804 _glfw.wl.subcompositor = 805 wl_registry_bind(registry, name, &wl_subcompositor_interface, 1); 806 } 807 else if (strcmp(interface, "wl_shm") == 0) 808 { 809 _glfw.wl.shm = 810 wl_registry_bind(registry, name, &wl_shm_interface, 1); 811 } 812 else if (strcmp(interface, "wl_shell") == 0) 813 { 814 _glfw.wl.shell = 815 wl_registry_bind(registry, name, &wl_shell_interface, 1); 816 } 817 else if (strcmp(interface, "wl_output") == 0) 818 { 819 _glfwAddOutputWayland(name, version); 820 } 821 else if (strcmp(interface, "wl_seat") == 0) 822 { 823 if (!_glfw.wl.seat) 824 { 825 _glfw.wl.seatVersion = min(4, version); 826 _glfw.wl.seat = 827 wl_registry_bind(registry, name, &wl_seat_interface, 828 _glfw.wl.seatVersion); 829 wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); 830 } 831 } 832 else if (strcmp(interface, "wl_data_device_manager") == 0) 833 { 834 if (!_glfw.wl.dataDeviceManager) 835 { 836 _glfw.wl.dataDeviceManager = 837 wl_registry_bind(registry, name, 838 &wl_data_device_manager_interface, 1); 839 } 840 } 841 else if (strcmp(interface, "xdg_wm_base") == 0) 842 { 843 _glfw.wl.wmBase = 844 wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); 845 xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL); 846 } 847 else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) 848 { 849 _glfw.wl.decorationManager = 850 wl_registry_bind(registry, name, 851 &zxdg_decoration_manager_v1_interface, 852 1); 853 } 854 else if (strcmp(interface, "wp_viewporter") == 0) 855 { 856 _glfw.wl.viewporter = 857 wl_registry_bind(registry, name, &wp_viewporter_interface, 1); 858 } 859 else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) 860 { 861 _glfw.wl.relativePointerManager = 862 wl_registry_bind(registry, name, 863 &zwp_relative_pointer_manager_v1_interface, 864 1); 865 } 866 else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) 867 { 868 _glfw.wl.pointerConstraints = 869 wl_registry_bind(registry, name, 870 &zwp_pointer_constraints_v1_interface, 871 1); 872 } 873 else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) 874 { 875 _glfw.wl.idleInhibitManager = 876 wl_registry_bind(registry, name, 877 &zwp_idle_inhibit_manager_v1_interface, 878 1); 879 } 880 } 881 882 static void registryHandleGlobalRemove(void *data, 883 struct wl_registry *registry, 884 uint32_t name) 885 { 886 int i; 887 _GLFWmonitor* monitor; 888 889 for (i = 0; i < _glfw.monitorCount; ++i) 890 { 891 monitor = _glfw.monitors[i]; 892 if (monitor->wl.name == name) 893 { 894 _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0); 895 return; 896 } 897 } 898 } 899 900 901 static const struct wl_registry_listener registryListener = { 902 registryHandleGlobal, 903 registryHandleGlobalRemove 904 }; 905 906 // Create key code translation tables 907 // 908 static void createKeyTables(void) 909 { 910 int scancode; 911 912 memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes)); 913 memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes)); 914 915 _glfw.wl.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; 916 _glfw.wl.keycodes[KEY_1] = GLFW_KEY_1; 917 _glfw.wl.keycodes[KEY_2] = GLFW_KEY_2; 918 _glfw.wl.keycodes[KEY_3] = GLFW_KEY_3; 919 _glfw.wl.keycodes[KEY_4] = GLFW_KEY_4; 920 _glfw.wl.keycodes[KEY_5] = GLFW_KEY_5; 921 _glfw.wl.keycodes[KEY_6] = GLFW_KEY_6; 922 _glfw.wl.keycodes[KEY_7] = GLFW_KEY_7; 923 _glfw.wl.keycodes[KEY_8] = GLFW_KEY_8; 924 _glfw.wl.keycodes[KEY_9] = GLFW_KEY_9; 925 _glfw.wl.keycodes[KEY_0] = GLFW_KEY_0; 926 _glfw.wl.keycodes[KEY_SPACE] = GLFW_KEY_SPACE; 927 _glfw.wl.keycodes[KEY_MINUS] = GLFW_KEY_MINUS; 928 _glfw.wl.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL; 929 _glfw.wl.keycodes[KEY_Q] = GLFW_KEY_Q; 930 _glfw.wl.keycodes[KEY_W] = GLFW_KEY_W; 931 _glfw.wl.keycodes[KEY_E] = GLFW_KEY_E; 932 _glfw.wl.keycodes[KEY_R] = GLFW_KEY_R; 933 _glfw.wl.keycodes[KEY_T] = GLFW_KEY_T; 934 _glfw.wl.keycodes[KEY_Y] = GLFW_KEY_Y; 935 _glfw.wl.keycodes[KEY_U] = GLFW_KEY_U; 936 _glfw.wl.keycodes[KEY_I] = GLFW_KEY_I; 937 _glfw.wl.keycodes[KEY_O] = GLFW_KEY_O; 938 _glfw.wl.keycodes[KEY_P] = GLFW_KEY_P; 939 _glfw.wl.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; 940 _glfw.wl.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; 941 _glfw.wl.keycodes[KEY_A] = GLFW_KEY_A; 942 _glfw.wl.keycodes[KEY_S] = GLFW_KEY_S; 943 _glfw.wl.keycodes[KEY_D] = GLFW_KEY_D; 944 _glfw.wl.keycodes[KEY_F] = GLFW_KEY_F; 945 _glfw.wl.keycodes[KEY_G] = GLFW_KEY_G; 946 _glfw.wl.keycodes[KEY_H] = GLFW_KEY_H; 947 _glfw.wl.keycodes[KEY_J] = GLFW_KEY_J; 948 _glfw.wl.keycodes[KEY_K] = GLFW_KEY_K; 949 _glfw.wl.keycodes[KEY_L] = GLFW_KEY_L; 950 _glfw.wl.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; 951 _glfw.wl.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; 952 _glfw.wl.keycodes[KEY_Z] = GLFW_KEY_Z; 953 _glfw.wl.keycodes[KEY_X] = GLFW_KEY_X; 954 _glfw.wl.keycodes[KEY_C] = GLFW_KEY_C; 955 _glfw.wl.keycodes[KEY_V] = GLFW_KEY_V; 956 _glfw.wl.keycodes[KEY_B] = GLFW_KEY_B; 957 _glfw.wl.keycodes[KEY_N] = GLFW_KEY_N; 958 _glfw.wl.keycodes[KEY_M] = GLFW_KEY_M; 959 _glfw.wl.keycodes[KEY_COMMA] = GLFW_KEY_COMMA; 960 _glfw.wl.keycodes[KEY_DOT] = GLFW_KEY_PERIOD; 961 _glfw.wl.keycodes[KEY_SLASH] = GLFW_KEY_SLASH; 962 _glfw.wl.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; 963 _glfw.wl.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE; 964 _glfw.wl.keycodes[KEY_TAB] = GLFW_KEY_TAB; 965 _glfw.wl.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; 966 _glfw.wl.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; 967 _glfw.wl.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; 968 _glfw.wl.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; 969 _glfw.wl.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; 970 _glfw.wl.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; 971 _glfw.wl.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; 972 _glfw.wl.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; 973 _glfw.wl.keycodes[KEY_MENU] = GLFW_KEY_MENU; 974 _glfw.wl.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; 975 _glfw.wl.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; 976 _glfw.wl.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; 977 _glfw.wl.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; 978 _glfw.wl.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE; 979 _glfw.wl.keycodes[KEY_DELETE] = GLFW_KEY_DELETE; 980 _glfw.wl.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; 981 _glfw.wl.keycodes[KEY_ENTER] = GLFW_KEY_ENTER; 982 _glfw.wl.keycodes[KEY_HOME] = GLFW_KEY_HOME; 983 _glfw.wl.keycodes[KEY_END] = GLFW_KEY_END; 984 _glfw.wl.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; 985 _glfw.wl.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; 986 _glfw.wl.keycodes[KEY_INSERT] = GLFW_KEY_INSERT; 987 _glfw.wl.keycodes[KEY_LEFT] = GLFW_KEY_LEFT; 988 _glfw.wl.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT; 989 _glfw.wl.keycodes[KEY_DOWN] = GLFW_KEY_DOWN; 990 _glfw.wl.keycodes[KEY_UP] = GLFW_KEY_UP; 991 _glfw.wl.keycodes[KEY_F1] = GLFW_KEY_F1; 992 _glfw.wl.keycodes[KEY_F2] = GLFW_KEY_F2; 993 _glfw.wl.keycodes[KEY_F3] = GLFW_KEY_F3; 994 _glfw.wl.keycodes[KEY_F4] = GLFW_KEY_F4; 995 _glfw.wl.keycodes[KEY_F5] = GLFW_KEY_F5; 996 _glfw.wl.keycodes[KEY_F6] = GLFW_KEY_F6; 997 _glfw.wl.keycodes[KEY_F7] = GLFW_KEY_F7; 998 _glfw.wl.keycodes[KEY_F8] = GLFW_KEY_F8; 999 _glfw.wl.keycodes[KEY_F9] = GLFW_KEY_F9; 1000 _glfw.wl.keycodes[KEY_F10] = GLFW_KEY_F10; 1001 _glfw.wl.keycodes[KEY_F11] = GLFW_KEY_F11; 1002 _glfw.wl.keycodes[KEY_F12] = GLFW_KEY_F12; 1003 _glfw.wl.keycodes[KEY_F13] = GLFW_KEY_F13; 1004 _glfw.wl.keycodes[KEY_F14] = GLFW_KEY_F14; 1005 _glfw.wl.keycodes[KEY_F15] = GLFW_KEY_F15; 1006 _glfw.wl.keycodes[KEY_F16] = GLFW_KEY_F16; 1007 _glfw.wl.keycodes[KEY_F17] = GLFW_KEY_F17; 1008 _glfw.wl.keycodes[KEY_F18] = GLFW_KEY_F18; 1009 _glfw.wl.keycodes[KEY_F19] = GLFW_KEY_F19; 1010 _glfw.wl.keycodes[KEY_F20] = GLFW_KEY_F20; 1011 _glfw.wl.keycodes[KEY_F21] = GLFW_KEY_F21; 1012 _glfw.wl.keycodes[KEY_F22] = GLFW_KEY_F22; 1013 _glfw.wl.keycodes[KEY_F23] = GLFW_KEY_F23; 1014 _glfw.wl.keycodes[KEY_F24] = GLFW_KEY_F24; 1015 _glfw.wl.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; 1016 _glfw.wl.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; 1017 _glfw.wl.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; 1018 _glfw.wl.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; 1019 _glfw.wl.keycodes[KEY_KP0] = GLFW_KEY_KP_0; 1020 _glfw.wl.keycodes[KEY_KP1] = GLFW_KEY_KP_1; 1021 _glfw.wl.keycodes[KEY_KP2] = GLFW_KEY_KP_2; 1022 _glfw.wl.keycodes[KEY_KP3] = GLFW_KEY_KP_3; 1023 _glfw.wl.keycodes[KEY_KP4] = GLFW_KEY_KP_4; 1024 _glfw.wl.keycodes[KEY_KP5] = GLFW_KEY_KP_5; 1025 _glfw.wl.keycodes[KEY_KP6] = GLFW_KEY_KP_6; 1026 _glfw.wl.keycodes[KEY_KP7] = GLFW_KEY_KP_7; 1027 _glfw.wl.keycodes[KEY_KP8] = GLFW_KEY_KP_8; 1028 _glfw.wl.keycodes[KEY_KP9] = GLFW_KEY_KP_9; 1029 _glfw.wl.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; 1030 _glfw.wl.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; 1031 _glfw.wl.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; 1032 1033 for (scancode = 0; scancode < 256; scancode++) 1034 { 1035 if (_glfw.wl.keycodes[scancode] > 0) 1036 _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode; 1037 } 1038 } 1039 1040 1041 ////////////////////////////////////////////////////////////////////////// 1042 ////// GLFW platform API ////// 1043 ////////////////////////////////////////////////////////////////////////// 1044 1045 int _glfwPlatformInit(void) 1046 { 1047 const char *cursorTheme; 1048 const char *cursorSizeStr; 1049 char *cursorSizeEnd; 1050 long cursorSizeLong; 1051 int cursorSize; 1052 1053 _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0"); 1054 if (!_glfw.wl.cursor.handle) 1055 { 1056 _glfwInputError(GLFW_PLATFORM_ERROR, 1057 "Wayland: Failed to open libwayland-cursor"); 1058 return GLFW_FALSE; 1059 } 1060 1061 _glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load) 1062 _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load"); 1063 _glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy) 1064 _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy"); 1065 _glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor) 1066 _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor"); 1067 _glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer) 1068 _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer"); 1069 1070 _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1"); 1071 if (!_glfw.wl.egl.handle) 1072 { 1073 _glfwInputError(GLFW_PLATFORM_ERROR, 1074 "Wayland: Failed to open libwayland-egl"); 1075 return GLFW_FALSE; 1076 } 1077 1078 _glfw.wl.egl.window_create = (PFN_wl_egl_window_create) 1079 _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create"); 1080 _glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy) 1081 _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy"); 1082 _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize) 1083 _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize"); 1084 1085 _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0"); 1086 if (!_glfw.wl.xkb.handle) 1087 { 1088 _glfwInputError(GLFW_PLATFORM_ERROR, 1089 "Wayland: Failed to open libxkbcommon"); 1090 return GLFW_FALSE; 1091 } 1092 1093 _glfw.wl.xkb.context_new = (PFN_xkb_context_new) 1094 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new"); 1095 _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref) 1096 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref"); 1097 _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string) 1098 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); 1099 _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref) 1100 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref"); 1101 _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index) 1102 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); 1103 _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats) 1104 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats"); 1105 _glfw.wl.xkb.state_new = (PFN_xkb_state_new) 1106 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new"); 1107 _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref) 1108 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref"); 1109 _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms) 1110 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); 1111 _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask) 1112 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); 1113 _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods) 1114 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); 1115 1116 #ifdef HAVE_XKBCOMMON_COMPOSE_H 1117 _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) 1118 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); 1119 _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) 1120 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); 1121 _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new) 1122 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new"); 1123 _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref) 1124 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref"); 1125 _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed) 1126 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed"); 1127 _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status) 1128 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); 1129 _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) 1130 _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); 1131 #endif 1132 1133 _glfw.wl.display = wl_display_connect(NULL); 1134 if (!_glfw.wl.display) 1135 { 1136 _glfwInputError(GLFW_PLATFORM_ERROR, 1137 "Wayland: Failed to connect to display"); 1138 return GLFW_FALSE; 1139 } 1140 1141 _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); 1142 wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); 1143 1144 createKeyTables(); 1145 1146 _glfw.wl.xkb.context = xkb_context_new(0); 1147 if (!_glfw.wl.xkb.context) 1148 { 1149 _glfwInputError(GLFW_PLATFORM_ERROR, 1150 "Wayland: Failed to initialize xkb context"); 1151 return GLFW_FALSE; 1152 } 1153 1154 // Sync so we got all registry objects 1155 wl_display_roundtrip(_glfw.wl.display); 1156 1157 // Sync so we got all initial output events 1158 wl_display_roundtrip(_glfw.wl.display); 1159 1160 #ifdef __linux__ 1161 if (!_glfwInitJoysticksLinux()) 1162 return GLFW_FALSE; 1163 #endif 1164 1165 _glfwInitTimerPOSIX(); 1166 1167 _glfw.wl.timerfd = -1; 1168 if (_glfw.wl.seatVersion >= 4) 1169 _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); 1170 1171 if (_glfw.wl.pointer && _glfw.wl.shm) 1172 { 1173 cursorTheme = getenv("XCURSOR_THEME"); 1174 cursorSizeStr = getenv("XCURSOR_SIZE"); 1175 cursorSize = 32; 1176 if (cursorSizeStr) 1177 { 1178 errno = 0; 1179 cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10); 1180 if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX) 1181 cursorSize = (int)cursorSizeLong; 1182 } 1183 _glfw.wl.cursorTheme = 1184 wl_cursor_theme_load(cursorTheme, cursorSize, _glfw.wl.shm); 1185 if (!_glfw.wl.cursorTheme) 1186 { 1187 _glfwInputError(GLFW_PLATFORM_ERROR, 1188 "Wayland: Unable to load default cursor theme"); 1189 return GLFW_FALSE; 1190 } 1191 // If this happens to be NULL, we just fallback to the scale=1 version. 1192 _glfw.wl.cursorThemeHiDPI = 1193 wl_cursor_theme_load(cursorTheme, 2 * cursorSize, _glfw.wl.shm); 1194 _glfw.wl.cursorSurface = 1195 wl_compositor_create_surface(_glfw.wl.compositor); 1196 _glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); 1197 } 1198 1199 if (_glfw.wl.seat && _glfw.wl.dataDeviceManager) 1200 { 1201 _glfw.wl.dataDevice = 1202 wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager, 1203 _glfw.wl.seat); 1204 wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL); 1205 _glfw.wl.clipboardString = malloc(4096); 1206 if (!_glfw.wl.clipboardString) 1207 { 1208 _glfwInputError(GLFW_PLATFORM_ERROR, 1209 "Wayland: Unable to allocate clipboard memory"); 1210 return GLFW_FALSE; 1211 } 1212 _glfw.wl.clipboardSize = 4096; 1213 } 1214 1215 return GLFW_TRUE; 1216 } 1217 1218 void _glfwPlatformTerminate(void) 1219 { 1220 #ifdef __linux__ 1221 _glfwTerminateJoysticksLinux(); 1222 #endif 1223 _glfwTerminateEGL(); 1224 if (_glfw.wl.egl.handle) 1225 { 1226 _glfw_dlclose(_glfw.wl.egl.handle); 1227 _glfw.wl.egl.handle = NULL; 1228 } 1229 1230 #ifdef HAVE_XKBCOMMON_COMPOSE_H 1231 if (_glfw.wl.xkb.composeState) 1232 xkb_compose_state_unref(_glfw.wl.xkb.composeState); 1233 #endif 1234 if (_glfw.wl.xkb.keymap) 1235 xkb_keymap_unref(_glfw.wl.xkb.keymap); 1236 if (_glfw.wl.xkb.state) 1237 xkb_state_unref(_glfw.wl.xkb.state); 1238 if (_glfw.wl.xkb.context) 1239 xkb_context_unref(_glfw.wl.xkb.context); 1240 if (_glfw.wl.xkb.handle) 1241 { 1242 _glfw_dlclose(_glfw.wl.xkb.handle); 1243 _glfw.wl.xkb.handle = NULL; 1244 } 1245 1246 if (_glfw.wl.cursorTheme) 1247 wl_cursor_theme_destroy(_glfw.wl.cursorTheme); 1248 if (_glfw.wl.cursorThemeHiDPI) 1249 wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI); 1250 if (_glfw.wl.cursor.handle) 1251 { 1252 _glfw_dlclose(_glfw.wl.cursor.handle); 1253 _glfw.wl.cursor.handle = NULL; 1254 } 1255 1256 if (_glfw.wl.cursorSurface) 1257 wl_surface_destroy(_glfw.wl.cursorSurface); 1258 if (_glfw.wl.subcompositor) 1259 wl_subcompositor_destroy(_glfw.wl.subcompositor); 1260 if (_glfw.wl.compositor) 1261 wl_compositor_destroy(_glfw.wl.compositor); 1262 if (_glfw.wl.shm) 1263 wl_shm_destroy(_glfw.wl.shm); 1264 if (_glfw.wl.shell) 1265 wl_shell_destroy(_glfw.wl.shell); 1266 if (_glfw.wl.viewporter) 1267 wp_viewporter_destroy(_glfw.wl.viewporter); 1268 if (_glfw.wl.decorationManager) 1269 zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager); 1270 if (_glfw.wl.wmBase) 1271 xdg_wm_base_destroy(_glfw.wl.wmBase); 1272 if (_glfw.wl.dataSource) 1273 wl_data_source_destroy(_glfw.wl.dataSource); 1274 if (_glfw.wl.dataDevice) 1275 wl_data_device_destroy(_glfw.wl.dataDevice); 1276 if (_glfw.wl.dataOffer) 1277 wl_data_offer_destroy(_glfw.wl.dataOffer); 1278 if (_glfw.wl.dataDeviceManager) 1279 wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager); 1280 if (_glfw.wl.pointer) 1281 wl_pointer_destroy(_glfw.wl.pointer); 1282 if (_glfw.wl.keyboard) 1283 wl_keyboard_destroy(_glfw.wl.keyboard); 1284 if (_glfw.wl.seat) 1285 wl_seat_destroy(_glfw.wl.seat); 1286 if (_glfw.wl.relativePointerManager) 1287 zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager); 1288 if (_glfw.wl.pointerConstraints) 1289 zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints); 1290 if (_glfw.wl.idleInhibitManager) 1291 zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager); 1292 if (_glfw.wl.registry) 1293 wl_registry_destroy(_glfw.wl.registry); 1294 if (_glfw.wl.display) 1295 { 1296 wl_display_flush(_glfw.wl.display); 1297 wl_display_disconnect(_glfw.wl.display); 1298 } 1299 1300 if (_glfw.wl.timerfd >= 0) 1301 close(_glfw.wl.timerfd); 1302 if (_glfw.wl.cursorTimerfd >= 0) 1303 close(_glfw.wl.cursorTimerfd); 1304 1305 if (_glfw.wl.clipboardString) 1306 free(_glfw.wl.clipboardString); 1307 if (_glfw.wl.clipboardSendString) 1308 free(_glfw.wl.clipboardSendString); 1309 } 1310 1311 const char* _glfwPlatformGetVersionString(void) 1312 { 1313 return _GLFW_VERSION_NUMBER " Wayland EGL OSMesa" 1314 #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) 1315 " clock_gettime" 1316 #else 1317 " gettimeofday" 1318 #endif 1319 " evdev" 1320 #if defined(_GLFW_BUILD_DLL) 1321 " shared" 1322 #endif 1323 ; 1324 }