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