1 /// Translated from C to D 2 module x11_init; 3 4 extern(C): @nogc: nothrow: __gshared: 5 6 //======================================================================== 7 // GLFW 3.3 X11 - www.glfw.org 8 //------------------------------------------------------------------------ 9 // Copyright (c) 2002-2006 Marcus Geelnard 10 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org> 11 // 12 // This software is provided 'as-is', without any express or implied 13 // warranty. In no event will the authors be held liable for any damages 14 // arising from the use of this software. 15 // 16 // Permission is granted to anyone to use this software for any purpose, 17 // including commercial applications, and to alter it and redistribute it 18 // freely, subject to the following restrictions: 19 // 20 // 1. The origin of this software must not be misrepresented; you must not 21 // claim that you wrote the original software. If you use this software 22 // in a product, an acknowledgment in the product documentation would 23 // be appreciated but is not required. 24 // 25 // 2. Altered source versions must be plainly marked as such, and must not 26 // be misrepresented as being the original software. 27 // 28 // 3. This notice may not be removed or altered from any source 29 // distribution. 30 // 31 //======================================================================== 32 // It is fine to use C99 in this file because it will not be built with VS 33 //======================================================================== 34 35 import glfw3.internal; 36 37 version(none) { 38 import x11.Xresource; 39 import x11.extensions.XKBsrv; 40 import x11.XKBlib; 41 } 42 43 import core.stdc.stdlib; 44 import core.stdc.string; 45 import core.stdc.limits; 46 import core.stdc.stdio; 47 import core.stdc.locale; 48 import core.stdc.config: c_long, c_ulong; 49 50 // Translate an X11 key code to a GLFW key code. 51 // 52 static int translateKeyCode(int scancode) { 53 int keySym; 54 55 // Valid key code range is [8,255], according to the Xlib manual 56 if (scancode < 8 || scancode > 255) 57 return GLFW_KEY_UNKNOWN; 58 59 if (_glfw.x11.xkb.available) 60 { 61 // Try secondary keysym, for numeric keypad keys 62 // Note: This way we always force "NumLock = ON", which is intentional 63 // since the returned key code should correspond to a physical 64 // location. 65 keySym = cast(int) XkbKeycodeToKeysym(_glfw.x11.display, cast(ubyte) scancode, cast(int) _glfw.x11.xkb.group, 1); 66 switch (keySym) 67 { 68 case XK_KP_0: return GLFW_KEY_KP_0; 69 case XK_KP_1: return GLFW_KEY_KP_1; 70 case XK_KP_2: return GLFW_KEY_KP_2; 71 case XK_KP_3: return GLFW_KEY_KP_3; 72 case XK_KP_4: return GLFW_KEY_KP_4; 73 case XK_KP_5: return GLFW_KEY_KP_5; 74 case XK_KP_6: return GLFW_KEY_KP_6; 75 case XK_KP_7: return GLFW_KEY_KP_7; 76 case XK_KP_8: return GLFW_KEY_KP_8; 77 case XK_KP_9: return GLFW_KEY_KP_9; 78 case XK_KP_Separator: 79 case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; 80 case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; 81 case XK_KP_Enter: return GLFW_KEY_KP_ENTER; 82 default: break; 83 } 84 85 // Now try primary keysym for function keys (non-printable keys) 86 // These should not depend on the current keyboard layout 87 keySym = cast(int) XkbKeycodeToKeysym(_glfw.x11.display, cast(ubyte) scancode, _glfw.x11.xkb.group, 0); 88 } 89 else 90 { 91 int dummy; 92 KeySym* keySyms; 93 94 keySyms = XGetKeyboardMapping(_glfw.x11.display, cast(ubyte) scancode, 1, &dummy); 95 keySym = cast(int) keySyms[0]; 96 XFree(keySyms); 97 } 98 99 switch (keySym) 100 { 101 case XK_Escape: return GLFW_KEY_ESCAPE; 102 case XK_Tab: return GLFW_KEY_TAB; 103 case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT; 104 case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT; 105 case XK_Control_L: return GLFW_KEY_LEFT_CONTROL; 106 case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL; 107 case XK_Meta_L: 108 case XK_Alt_L: return GLFW_KEY_LEFT_ALT; 109 case XK_Mode_switch: // Mapped to Alt_R on many keyboards 110 case XK_ISO_Level3_Shift: // AltGr on at least some machines 111 case XK_Meta_R: 112 case XK_Alt_R: return GLFW_KEY_RIGHT_ALT; 113 case XK_Super_L: return GLFW_KEY_LEFT_SUPER; 114 case XK_Super_R: return GLFW_KEY_RIGHT_SUPER; 115 case XK_Menu: return GLFW_KEY_MENU; 116 case XK_Num_Lock: return GLFW_KEY_NUM_LOCK; 117 case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; 118 case XK_Print: return GLFW_KEY_PRINT_SCREEN; 119 case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; 120 case XK_Pause: return GLFW_KEY_PAUSE; 121 case XK_Delete: return GLFW_KEY_DELETE; 122 case XK_BackSpace: return GLFW_KEY_BACKSPACE; 123 case XK_Return: return GLFW_KEY_ENTER; 124 case XK_Home: return GLFW_KEY_HOME; 125 case XK_End: return GLFW_KEY_END; 126 case XK_Page_Up: return GLFW_KEY_PAGE_UP; 127 case XK_Page_Down: return GLFW_KEY_PAGE_DOWN; 128 case XK_Insert: return GLFW_KEY_INSERT; 129 case XK_Left: return GLFW_KEY_LEFT; 130 case XK_Right: return GLFW_KEY_RIGHT; 131 case XK_Down: return GLFW_KEY_DOWN; 132 case XK_Up: return GLFW_KEY_UP; 133 case XK_F1: return GLFW_KEY_F1; 134 case XK_F2: return GLFW_KEY_F2; 135 case XK_F3: return GLFW_KEY_F3; 136 case XK_F4: return GLFW_KEY_F4; 137 case XK_F5: return GLFW_KEY_F5; 138 case XK_F6: return GLFW_KEY_F6; 139 case XK_F7: return GLFW_KEY_F7; 140 case XK_F8: return GLFW_KEY_F8; 141 case XK_F9: return GLFW_KEY_F9; 142 case XK_F10: return GLFW_KEY_F10; 143 case XK_F11: return GLFW_KEY_F11; 144 case XK_F12: return GLFW_KEY_F12; 145 case XK_F13: return GLFW_KEY_F13; 146 case XK_F14: return GLFW_KEY_F14; 147 case XK_F15: return GLFW_KEY_F15; 148 case XK_F16: return GLFW_KEY_F16; 149 case XK_F17: return GLFW_KEY_F17; 150 case XK_F18: return GLFW_KEY_F18; 151 case XK_F19: return GLFW_KEY_F19; 152 case XK_F20: return GLFW_KEY_F20; 153 case XK_F21: return GLFW_KEY_F21; 154 case XK_F22: return GLFW_KEY_F22; 155 case XK_F23: return GLFW_KEY_F23; 156 case XK_F24: return GLFW_KEY_F24; 157 case XK_F25: return GLFW_KEY_F25; 158 159 // Numeric keypad 160 case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; 161 case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; 162 case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; 163 case XK_KP_Add: return GLFW_KEY_KP_ADD; 164 165 // These should have been detected in secondary keysym test above! 166 case XK_KP_Insert: return GLFW_KEY_KP_0; 167 case XK_KP_End: return GLFW_KEY_KP_1; 168 case XK_KP_Down: return GLFW_KEY_KP_2; 169 case XK_KP_Page_Down: return GLFW_KEY_KP_3; 170 case XK_KP_Left: return GLFW_KEY_KP_4; 171 case XK_KP_Right: return GLFW_KEY_KP_6; 172 case XK_KP_Home: return GLFW_KEY_KP_7; 173 case XK_KP_Up: return GLFW_KEY_KP_8; 174 case XK_KP_Page_Up: return GLFW_KEY_KP_9; 175 case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL; 176 case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; 177 case XK_KP_Enter: return GLFW_KEY_KP_ENTER; 178 179 // Last resort: Check for printable keys (should not happen if the XKB 180 // extension is available). This will give a layout dependent mapping 181 // (which is wrong, and we may miss some keys, especially on non-US 182 // keyboards), but it's better than nothing... 183 case XK_a: return GLFW_KEY_A; 184 case XK_b: return GLFW_KEY_B; 185 case XK_c: return GLFW_KEY_C; 186 case XK_d: return GLFW_KEY_D; 187 case XK_e: return GLFW_KEY_E; 188 case XK_f: return GLFW_KEY_F; 189 case XK_g: return GLFW_KEY_G; 190 case XK_h: return GLFW_KEY_H; 191 case XK_i: return GLFW_KEY_I; 192 case XK_j: return GLFW_KEY_J; 193 case XK_k: return GLFW_KEY_K; 194 case XK_l: return GLFW_KEY_L; 195 case XK_m: return GLFW_KEY_M; 196 case XK_n: return GLFW_KEY_N; 197 case XK_o: return GLFW_KEY_O; 198 case XK_p: return GLFW_KEY_P; 199 case XK_q: return GLFW_KEY_Q; 200 case XK_r: return GLFW_KEY_R; 201 case XK_s: return GLFW_KEY_S; 202 case XK_t: return GLFW_KEY_T; 203 case XK_u: return GLFW_KEY_U; 204 case XK_v: return GLFW_KEY_V; 205 case XK_w: return GLFW_KEY_W; 206 case XK_x: return GLFW_KEY_X; 207 case XK_y: return GLFW_KEY_Y; 208 case XK_z: return GLFW_KEY_Z; 209 case XK_1: return GLFW_KEY_1; 210 case XK_2: return GLFW_KEY_2; 211 case XK_3: return GLFW_KEY_3; 212 case XK_4: return GLFW_KEY_4; 213 case XK_5: return GLFW_KEY_5; 214 case XK_6: return GLFW_KEY_6; 215 case XK_7: return GLFW_KEY_7; 216 case XK_8: return GLFW_KEY_8; 217 case XK_9: return GLFW_KEY_9; 218 case XK_0: return GLFW_KEY_0; 219 case XK_space: return GLFW_KEY_SPACE; 220 case XK_minus: return GLFW_KEY_MINUS; 221 case XK_equal: return GLFW_KEY_EQUAL; 222 case XK_bracketleft: return GLFW_KEY_LEFT_BRACKET; 223 case XK_bracketright: return GLFW_KEY_RIGHT_BRACKET; 224 case XK_backslash: return GLFW_KEY_BACKSLASH; 225 case XK_semicolon: return GLFW_KEY_SEMICOLON; 226 case XK_apostrophe: return GLFW_KEY_APOSTROPHE; 227 case XK_grave: return GLFW_KEY_GRAVE_ACCENT; 228 case XK_comma: return GLFW_KEY_COMMA; 229 case XK_period: return GLFW_KEY_PERIOD; 230 case XK_slash: return GLFW_KEY_SLASH; 231 case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts... 232 default: break; 233 } 234 235 // No matching translation was found 236 return GLFW_KEY_UNKNOWN; 237 } 238 239 // Create key code translation tables 240 // 241 static void createKeyTables() { 242 int scancode;int key; 243 244 memset(_glfw.x11.keycodes.ptr, -1, typeof(_glfw.x11.keycodes).sizeof); 245 memset(_glfw.x11.scancodes.ptr, -1, typeof(_glfw.x11.scancodes).sizeof); 246 247 if (_glfw.x11.xkb.available) 248 { 249 // Use XKB to determine physical key locations independently of the 250 // current keyboard layout 251 252 char[XkbKeyNameLength + 1] name; 253 XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); 254 XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); 255 256 // Find the X11 key code -> GLFW key code mapping 257 for (scancode = desc.min_key_code; scancode <= desc.max_key_code; scancode++) 258 { 259 memcpy(name.ptr, desc.names.keys[scancode].name.ptr, XkbKeyNameLength); 260 name[XkbKeyNameLength] = '\0'; 261 262 // Map the key name to a GLFW key code. Note: We only map printable 263 // keys here, and we use the US keyboard layout. The rest of the 264 // keys (function keys) are mapped using traditional KeySym 265 // translations. 266 if (strcmp(name.ptr, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; 267 else if (strcmp(name.ptr, "AE01") == 0) key = GLFW_KEY_1; 268 else if (strcmp(name.ptr, "AE02") == 0) key = GLFW_KEY_2; 269 else if (strcmp(name.ptr, "AE03") == 0) key = GLFW_KEY_3; 270 else if (strcmp(name.ptr, "AE04") == 0) key = GLFW_KEY_4; 271 else if (strcmp(name.ptr, "AE05") == 0) key = GLFW_KEY_5; 272 else if (strcmp(name.ptr, "AE06") == 0) key = GLFW_KEY_6; 273 else if (strcmp(name.ptr, "AE07") == 0) key = GLFW_KEY_7; 274 else if (strcmp(name.ptr, "AE08") == 0) key = GLFW_KEY_8; 275 else if (strcmp(name.ptr, "AE09") == 0) key = GLFW_KEY_9; 276 else if (strcmp(name.ptr, "AE10") == 0) key = GLFW_KEY_0; 277 else if (strcmp(name.ptr, "AE11") == 0) key = GLFW_KEY_MINUS; 278 else if (strcmp(name.ptr, "AE12") == 0) key = GLFW_KEY_EQUAL; 279 else if (strcmp(name.ptr, "AD01") == 0) key = GLFW_KEY_Q; 280 else if (strcmp(name.ptr, "AD02") == 0) key = GLFW_KEY_W; 281 else if (strcmp(name.ptr, "AD03") == 0) key = GLFW_KEY_E; 282 else if (strcmp(name.ptr, "AD04") == 0) key = GLFW_KEY_R; 283 else if (strcmp(name.ptr, "AD05") == 0) key = GLFW_KEY_T; 284 else if (strcmp(name.ptr, "AD06") == 0) key = GLFW_KEY_Y; 285 else if (strcmp(name.ptr, "AD07") == 0) key = GLFW_KEY_U; 286 else if (strcmp(name.ptr, "AD08") == 0) key = GLFW_KEY_I; 287 else if (strcmp(name.ptr, "AD09") == 0) key = GLFW_KEY_O; 288 else if (strcmp(name.ptr, "AD10") == 0) key = GLFW_KEY_P; 289 else if (strcmp(name.ptr, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; 290 else if (strcmp(name.ptr, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; 291 else if (strcmp(name.ptr, "AC01") == 0) key = GLFW_KEY_A; 292 else if (strcmp(name.ptr, "AC02") == 0) key = GLFW_KEY_S; 293 else if (strcmp(name.ptr, "AC03") == 0) key = GLFW_KEY_D; 294 else if (strcmp(name.ptr, "AC04") == 0) key = GLFW_KEY_F; 295 else if (strcmp(name.ptr, "AC05") == 0) key = GLFW_KEY_G; 296 else if (strcmp(name.ptr, "AC06") == 0) key = GLFW_KEY_H; 297 else if (strcmp(name.ptr, "AC07") == 0) key = GLFW_KEY_J; 298 else if (strcmp(name.ptr, "AC08") == 0) key = GLFW_KEY_K; 299 else if (strcmp(name.ptr, "AC09") == 0) key = GLFW_KEY_L; 300 else if (strcmp(name.ptr, "AC10") == 0) key = GLFW_KEY_SEMICOLON; 301 else if (strcmp(name.ptr, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; 302 else if (strcmp(name.ptr, "AB01") == 0) key = GLFW_KEY_Z; 303 else if (strcmp(name.ptr, "AB02") == 0) key = GLFW_KEY_X; 304 else if (strcmp(name.ptr, "AB03") == 0) key = GLFW_KEY_C; 305 else if (strcmp(name.ptr, "AB04") == 0) key = GLFW_KEY_V; 306 else if (strcmp(name.ptr, "AB05") == 0) key = GLFW_KEY_B; 307 else if (strcmp(name.ptr, "AB06") == 0) key = GLFW_KEY_N; 308 else if (strcmp(name.ptr, "AB07") == 0) key = GLFW_KEY_M; 309 else if (strcmp(name.ptr, "AB08") == 0) key = GLFW_KEY_COMMA; 310 else if (strcmp(name.ptr, "AB09") == 0) key = GLFW_KEY_PERIOD; 311 else if (strcmp(name.ptr, "AB10") == 0) key = GLFW_KEY_SLASH; 312 else if (strcmp(name.ptr, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; 313 else if (strcmp(name.ptr, "LSGT") == 0) key = GLFW_KEY_WORLD_1; 314 else key = GLFW_KEY_UNKNOWN; 315 316 if ((scancode >= 0) && (scancode < 256)) 317 _glfw.x11.keycodes[scancode] = key; 318 } 319 320 XkbFreeNames(desc, XkbKeyNamesMask, True); 321 XkbFreeKeyboard(desc, 0, True); 322 } 323 324 for (scancode = 0; scancode < 256; scancode++) 325 { 326 // Translate the un-translated key codes using traditional X11 KeySym 327 // lookups 328 if (_glfw.x11.keycodes[scancode] < 0) 329 _glfw.x11.keycodes[scancode] = translateKeyCode(scancode); 330 331 // Store the reverse translation for faster key name lookup 332 if (_glfw.x11.keycodes[scancode] > 0) 333 _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; 334 } 335 } 336 337 // Check whether the IM has a usable style 338 // 339 static GLFWbool hasUsableInputMethodStyle() { 340 GLFWbool found = GLFW_FALSE; 341 XIMStyles* styles = null; 342 343 if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, null) != null) 344 return GLFW_FALSE; 345 346 for (uint i = 0; i < styles.count_styles; i++) 347 { 348 if (styles.supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) 349 { 350 found = GLFW_TRUE; 351 break; 352 } 353 } 354 355 XFree(styles); 356 return found; 357 } 358 359 // Check whether the specified atom is supported 360 // 361 static Atom getSupportedAtom(Atom* supportedAtoms, c_ulong atomCount, const(char)* atomName) { 362 const(Atom) atom = XInternAtom(_glfw.x11.display, atomName, False); 363 364 for (uint i = 0; i < atomCount; i++) 365 { 366 if (supportedAtoms[i] == atom) 367 return atom; 368 } 369 370 return None; 371 } 372 373 // Check whether the running window manager is EWMH-compliant 374 // 375 static void detectEWMH() { 376 // First we read the _NET_SUPPORTING_WM_CHECK property on the root window 377 378 Window* windowFromRoot = null; 379 if (!_glfwGetWindowPropertyX11(_glfw.x11.root, 380 _glfw.x11.NET_SUPPORTING_WM_CHECK, 381 XA_WINDOW, 382 cast(ubyte**) &windowFromRoot)) 383 { 384 return; 385 } 386 387 _glfwGrabErrorHandlerX11(); 388 389 // If it exists, it should be the XID of a top-level window 390 // Then we look for the same property on that window 391 392 Window* windowFromChild = null; 393 if (!_glfwGetWindowPropertyX11(*windowFromRoot, 394 _glfw.x11.NET_SUPPORTING_WM_CHECK, 395 XA_WINDOW, 396 cast(ubyte**) &windowFromChild)) 397 { 398 XFree(windowFromRoot); 399 return; 400 } 401 402 _glfwReleaseErrorHandlerX11(); 403 404 // If the property exists, it should contain the XID of the window 405 406 if (*windowFromRoot != *windowFromChild) 407 { 408 XFree(windowFromRoot); 409 XFree(windowFromChild); 410 return; 411 } 412 413 XFree(windowFromRoot); 414 XFree(windowFromChild); 415 416 // We are now fairly sure that an EWMH-compliant WM is currently running 417 // We can now start querying the WM about what features it supports by 418 // looking in the _NET_SUPPORTED property on the root window 419 // It should contain a list of supported EWMH protocol and state atoms 420 421 Atom* supportedAtoms = null; 422 c_ulong atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root, 423 _glfw.x11.NET_SUPPORTED, 424 XA_ATOM, 425 cast(ubyte**) &supportedAtoms); 426 427 // See which of the atoms we support that are supported by the WM 428 429 _glfw.x11.NET_WM_STATE = 430 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); 431 _glfw.x11.NET_WM_STATE_ABOVE = 432 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); 433 _glfw.x11.NET_WM_STATE_FULLSCREEN = 434 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); 435 _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = 436 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); 437 _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = 438 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); 439 _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = 440 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); 441 _glfw.x11.NET_WM_FULLSCREEN_MONITORS = 442 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); 443 _glfw.x11.NET_WM_WINDOW_TYPE = 444 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); 445 _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = 446 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); 447 _glfw.x11.NET_WORKAREA = 448 getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA"); 449 _glfw.x11.NET_CURRENT_DESKTOP = 450 getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP"); 451 _glfw.x11.NET_ACTIVE_WINDOW = 452 getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); 453 _glfw.x11.NET_FRAME_EXTENTS = 454 getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); 455 _glfw.x11.NET_REQUEST_FRAME_EXTENTS = 456 getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); 457 458 if (supportedAtoms) 459 XFree(supportedAtoms); 460 } 461 462 // Look for and initialize supported X11 extensions 463 // 464 static GLFWbool initExtensions() { 465 _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1"); 466 if (_glfw.x11.vidmode.handle) 467 { 468 _glfw.x11.vidmode.QueryExtension = cast(PFN_XF86VidModeQueryExtension) 469 _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); 470 _glfw.x11.vidmode.GetGammaRamp = cast(PFN_XF86VidModeGetGammaRamp) 471 _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); 472 _glfw.x11.vidmode.SetGammaRamp = cast(PFN_XF86VidModeSetGammaRamp) 473 _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); 474 _glfw.x11.vidmode.GetGammaRampSize = cast(PFN_XF86VidModeGetGammaRampSize) 475 _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); 476 477 _glfw.x11.vidmode.available = 478 _glfw.x11.vidmode.QueryExtension(_glfw.x11.display, 479 &_glfw.x11.vidmode.eventBase, 480 &_glfw.x11.vidmode.errorBase); 481 } 482 483 version (Cygwin) { 484 _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so"); 485 } else { 486 _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6"); 487 } 488 if (_glfw.x11.xi.handle) 489 { 490 _glfw.x11.xi.QueryVersion = cast(PFN_XIQueryVersion) 491 _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); 492 _glfw.x11.xi.SelectEvents = cast(PFN_XISelectEvents) 493 _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents"); 494 495 if (XQueryExtension(_glfw.x11.display, 496 "XInputExtension".ptr, 497 &_glfw.x11.xi.majorOpcode, 498 &_glfw.x11.xi.eventBase, 499 &_glfw.x11.xi.errorBase)) 500 { 501 _glfw.x11.xi.major = 2; 502 _glfw.x11.xi.minor = 0; 503 504 if (_glfw.x11.xi.QueryVersion(_glfw.x11.display, 505 &_glfw.x11.xi.major, 506 &_glfw.x11.xi.minor) == XErrorCode.Success) 507 { 508 _glfw.x11.xi.available = GLFW_TRUE; 509 } 510 } 511 } 512 513 version (Cygwin) { 514 _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so"); 515 } else { 516 _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2"); 517 } 518 if (_glfw.x11.randr.handle) 519 { 520 _glfw.x11.randr.AllocGamma = cast(PFN_XRRAllocGamma) 521 _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); 522 _glfw.x11.randr.FreeGamma = cast(PFN_XRRFreeGamma) 523 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); 524 _glfw.x11.randr.FreeCrtcInfo = cast(PFN_XRRFreeCrtcInfo) 525 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); 526 _glfw.x11.randr.FreeGamma = cast(PFN_XRRFreeGamma) 527 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); 528 _glfw.x11.randr.FreeOutputInfo = cast(PFN_XRRFreeOutputInfo) 529 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); 530 _glfw.x11.randr.FreeScreenResources = cast(PFN_XRRFreeScreenResources) 531 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); 532 _glfw.x11.randr.GetCrtcGamma = cast(PFN_XRRGetCrtcGamma) 533 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); 534 _glfw.x11.randr.GetCrtcGammaSize = cast(PFN_XRRGetCrtcGammaSize) 535 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); 536 _glfw.x11.randr.GetCrtcInfo = cast(PFN_XRRGetCrtcInfo) 537 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); 538 _glfw.x11.randr.GetOutputInfo = cast(PFN_XRRGetOutputInfo) 539 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); 540 _glfw.x11.randr.GetOutputPrimary = cast(PFN_XRRGetOutputPrimary) 541 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); 542 _glfw.x11.randr.GetScreenResourcesCurrent = cast(PFN_XRRGetScreenResourcesCurrent) 543 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); 544 _glfw.x11.randr.QueryExtension = cast(PFN_XRRQueryExtension) 545 _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); 546 _glfw.x11.randr.QueryVersion = cast(PFN_XRRQueryVersion) 547 _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); 548 _glfw.x11.randr.SelectInput = cast(PFN_XRRSelectInput) 549 _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); 550 _glfw.x11.randr.SetCrtcConfig = cast(PFN_XRRSetCrtcConfig) 551 _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); 552 _glfw.x11.randr.SetCrtcGamma = cast(PFN_XRRSetCrtcGamma) 553 _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); 554 _glfw.x11.randr.UpdateConfiguration = cast(PFN_XRRUpdateConfiguration) 555 _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); 556 557 if (_glfw.x11.randr.QueryExtension(_glfw.x11.display, 558 &_glfw.x11.randr.eventBase, 559 &_glfw.x11.randr.errorBase)) 560 { 561 if (_glfw.x11.randr.QueryVersion(_glfw.x11.display, 562 &_glfw.x11.randr.major, 563 &_glfw.x11.randr.minor)) 564 { 565 // The GLFW RandR path requires at least version 1.3 566 if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) 567 _glfw.x11.randr.available = GLFW_TRUE; 568 } 569 else 570 { 571 _glfwInputError(GLFW_PLATFORM_ERROR, 572 "X11: Failed to query RandR version"); 573 } 574 } 575 } 576 577 if (_glfw.x11.randr.available) 578 { 579 XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, 580 _glfw.x11.root); 581 582 if (!sr.ncrtc || !_glfw.x11.randr.GetCrtcGammaSize(_glfw.x11.display, sr.crtcs[0])) 583 { 584 // This is likely an older Nvidia driver with broken gamma support 585 // Flag it as useless and fall back to xf86vm gamma, if available 586 _glfw.x11.randr.gammaBroken = GLFW_TRUE; 587 } 588 589 if (!sr.ncrtc) 590 { 591 // A system without CRTCs is likely a system with broken RandR 592 // Disable the RandR monitor path and fall back to core functions 593 _glfw.x11.randr.monitorBroken = GLFW_TRUE; 594 } 595 596 _glfw.x11.randr.FreeScreenResources(sr); 597 } 598 599 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 600 { 601 _glfw.x11.randr.SelectInput(_glfw.x11.display, _glfw.x11.root, 602 RROutputChangeNotifyMask); 603 } 604 605 version (Cygwin) { 606 _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so"); 607 } else { 608 _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1"); 609 } 610 if (_glfw.x11.xcursor.handle) 611 { 612 _glfw.x11.xcursor.ImageCreate = cast(PFN_XcursorImageCreate) 613 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); 614 _glfw.x11.xcursor.ImageDestroy = cast(PFN_XcursorImageDestroy) 615 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); 616 _glfw.x11.xcursor.ImageLoadCursor = cast(PFN_XcursorImageLoadCursor) 617 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); 618 } 619 620 version (Cygwin) { 621 _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so"); 622 } else { 623 _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1"); 624 } 625 if (_glfw.x11.xinerama.handle) 626 { 627 _glfw.x11.xinerama.IsActive = cast(PFN_XineramaIsActive) 628 _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); 629 _glfw.x11.xinerama.QueryExtension = cast(PFN_XineramaQueryExtension) 630 _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); 631 _glfw.x11.xinerama.QueryScreens = cast(PFN_XineramaQueryScreens) 632 _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); 633 634 if (_glfw.x11.xinerama.QueryExtension(_glfw.x11.display, 635 &_glfw.x11.xinerama.major, 636 &_glfw.x11.xinerama.minor)) 637 { 638 if (_glfw.x11.xinerama.IsActive(_glfw.x11.display)) 639 _glfw.x11.xinerama.available = GLFW_TRUE; 640 } 641 } 642 643 _glfw.x11.xkb.major = 1; 644 _glfw.x11.xkb.minor = 0; 645 _glfw.x11.xkb.available = 646 XkbQueryExtension(_glfw.x11.display, 647 &_glfw.x11.xkb.majorOpcode, 648 &_glfw.x11.xkb.eventBase, 649 &_glfw.x11.xkb.errorBase, 650 &_glfw.x11.xkb.major, 651 &_glfw.x11.xkb.minor); 652 653 if (_glfw.x11.xkb.available) 654 { 655 Bool supported; 656 657 if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) 658 { 659 if (supported) 660 _glfw.x11.xkb.detectable = GLFW_TRUE; 661 } 662 663 _glfw.x11.xkb.group = 0; 664 XkbStateRec state; 665 if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == XErrorCode.Success) 666 { 667 XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask); 668 _glfw.x11.xkb.group = cast(uint)state.group; 669 } 670 } 671 672 version (Cygwin) { 673 _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so"); 674 } else { 675 _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); 676 } 677 if (_glfw.x11.x11xcb.handle) 678 { 679 _glfw.x11.x11xcb.GetXCBConnection = cast(PFN_XGetXCBConnection) 680 _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); 681 } 682 683 version (Cygwin) { 684 _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so"); 685 } else { 686 _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); 687 } 688 if (_glfw.x11.xrender.handle) 689 { 690 _glfw.x11.xrender.QueryExtension = cast(PFN_XRenderQueryExtension) 691 _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); 692 _glfw.x11.xrender.QueryVersion = cast(PFN_XRenderQueryVersion) 693 _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); 694 _glfw.x11.xrender.FindVisualFormat = cast(PFN_XRenderFindVisualFormat) 695 _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); 696 697 if (_glfw.x11.xrender.QueryExtension(_glfw.x11.display, 698 &_glfw.x11.xrender.errorBase, 699 &_glfw.x11.xrender.eventBase)) 700 { 701 if (_glfw.x11.xrender.QueryVersion(_glfw.x11.display, 702 &_glfw.x11.xrender.major, 703 &_glfw.x11.xrender.minor)) 704 { 705 _glfw.x11.xrender.available = GLFW_TRUE; 706 } 707 } 708 } 709 710 // Update the key code LUT 711 // FIXME: We should listen to XkbMapNotify events to track changes to 712 // the keyboard mapping. 713 createKeyTables(); 714 715 // String format atoms 716 _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); 717 _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False); 718 _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); 719 720 // Custom selection property atom 721 _glfw.x11.GLFW_SELECTION = 722 XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); 723 724 // ICCCM standard clipboard atoms 725 _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); 726 _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); 727 _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False); 728 _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False); 729 _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); 730 731 // Clipboard manager atoms 732 _glfw.x11.CLIPBOARD_MANAGER = 733 XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); 734 _glfw.x11.SAVE_TARGETS = 735 XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); 736 737 // Xdnd (drag and drop) atoms 738 _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False); 739 _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); 740 _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); 741 _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False); 742 _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False); 743 _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False); 744 _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); 745 _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); 746 _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False); 747 _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False); 748 749 // ICCCM, EWMH and Motif window property atoms 750 // These can be set safely even without WM support 751 // The EWMH atoms that require WM support are handled in detectEWMH 752 _glfw.x11.WM_PROTOCOLS = 753 XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False); 754 _glfw.x11.WM_STATE = 755 XInternAtom(_glfw.x11.display, "WM_STATE", False); 756 _glfw.x11.WM_DELETE_WINDOW = 757 XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False); 758 _glfw.x11.NET_SUPPORTED = 759 XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); 760 _glfw.x11.NET_SUPPORTING_WM_CHECK = 761 XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); 762 _glfw.x11.NET_WM_ICON = 763 XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); 764 _glfw.x11.NET_WM_PING = 765 XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); 766 _glfw.x11.NET_WM_PID = 767 XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); 768 _glfw.x11.NET_WM_NAME = 769 XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); 770 _glfw.x11.NET_WM_ICON_NAME = 771 XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); 772 _glfw.x11.NET_WM_BYPASS_COMPOSITOR = 773 XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); 774 _glfw.x11.NET_WM_WINDOW_OPACITY = 775 XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False); 776 _glfw.x11.MOTIF_WM_HINTS = 777 XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); 778 779 // The compositing manager selection name contains the screen number 780 { 781 char[32] name; 782 snprintf(name.ptr, typeof(name).sizeof, "_NET_WM_CM_S%u", _glfw.x11.screen); 783 _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name.ptr, False); 784 } 785 786 // Detect whether an EWMH-conformant window manager is running 787 detectEWMH(); 788 789 return GLFW_TRUE; 790 } 791 792 // Retrieve system content scale via folklore heuristics 793 // 794 static void getSystemContentScale(float* xscale, float* yscale) { 795 // Start by assuming the default X11 DPI 796 // NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it 797 // would be set to 96, so assume that is the case if we cannot find it 798 float xdpi = 96.0f;float ydpi = 96.0f; 799 800 // NOTE: Basing the scale on Xft.dpi where available should provide the most 801 // consistent user experience (matches Qt, Gtk, etc), although not 802 // always the most accurate one 803 char* rms = XResourceManagerString(_glfw.x11.display); 804 if (rms) 805 { 806 XrmDatabase db = XrmGetStringDatabase(rms); 807 if (db) 808 { 809 XrmValue value; 810 char* type = null; 811 812 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) 813 { 814 if (type && strcmp(type, "String") == 0) 815 xdpi = ydpi = atof(value.addr); 816 } 817 818 XrmDestroyDatabase(db); 819 } 820 } 821 822 *xscale = xdpi / 96.0f; 823 *yscale = ydpi / 96.0f; 824 } 825 826 // Create a blank cursor for hidden and disabled cursor modes 827 // 828 static Cursor createHiddenCursor() { 829 ubyte[16 * 16 * 4] pixels = 0; 830 GLFWimage image = GLFWimage(16, 16, pixels.ptr); 831 return _glfwCreateCursorX11(&image, 0, 0); 832 } 833 834 // Create a helper window for IPC 835 // 836 static Window createHelperWindow() { 837 XSetWindowAttributes wa; 838 wa.event_mask = PropertyChangeMask; 839 840 return XCreateWindow(_glfw.x11.display, _glfw.x11.root, 841 0, 0, 1, 1, 0, 0, 842 InputOnly, 843 DefaultVisual(_glfw.x11.display, _glfw.x11.screen), 844 CWEventMask, &wa); 845 } 846 847 // X error handler 848 // 849 static int errorHandler(Display* display, XErrorEvent* event) { 850 _glfw.x11.errorCode = event.error_code; 851 return 0; 852 } 853 854 855 ////////////////////////////////////////////////////////////////////////// 856 ////// GLFW internal API ////// 857 ////////////////////////////////////////////////////////////////////////// 858 859 // Sets the X error handler callback 860 // 861 void _glfwGrabErrorHandlerX11() { 862 _glfw.x11.errorCode = XErrorCode.Success; 863 XSetErrorHandler(&errorHandler); 864 } 865 866 // Clears the X error handler callback 867 // 868 void _glfwReleaseErrorHandlerX11() { 869 // Synchronize to make sure all commands are processed 870 XSync(_glfw.x11.display, False); 871 XSetErrorHandler(null); 872 } 873 874 // Reports the specified error, appending information about the last X error 875 // 876 void _glfwInputErrorX11(int error, const(char)* message) { 877 char[_GLFW_MESSAGE_SIZE] buffer; 878 XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode, 879 buffer.ptr, typeof(buffer).sizeof); 880 881 _glfwInputError(error, "%s: %s", message, buffer.ptr); 882 } 883 884 // Creates a native cursor object from the specified image and hotspot 885 // 886 Cursor _glfwCreateCursorX11(const(GLFWimage)* image, int xhot, int yhot) { 887 int i; 888 Cursor cursor; 889 890 if (!_glfw.x11.xcursor.handle) 891 return None; 892 893 XcursorImage* native = _glfw.x11.xcursor.ImageCreate(image.width, image.height); 894 if (native == null) 895 return None; 896 897 native.xhot = xhot; 898 native.yhot = yhot; 899 900 ubyte* source = cast(ubyte*) image.pixels; 901 XcursorPixel* target = native.pixels; 902 903 for (i = 0; i < image.width * image.height; i++, target++, source += 4) 904 { 905 uint alpha = source[3]; 906 907 *target = (alpha << 24) | 908 (cast(ubyte) ((source[0] * alpha) / 255) << 16) | 909 (cast(ubyte) ((source[1] * alpha) / 255) << 8) | 910 (cast(ubyte) ((source[2] * alpha) / 255) << 0); 911 } 912 913 cursor = _glfw.x11.xcursor.ImageLoadCursor(_glfw.x11.display, native); 914 _glfw.x11.xcursor.ImageDestroy(native); 915 916 return cursor; 917 } 918 919 920 ////////////////////////////////////////////////////////////////////////// 921 ////// GLFW platform API ////// 922 ////////////////////////////////////////////////////////////////////////// 923 924 int _glfwPlatformInit() { 925 version (X_HAVE_UTF8_STRING) {} else { 926 // HACK: If the current locale is "C" and the Xlib UTF-8 functions are 927 // unavailable, apply the environment's locale in the hope that it's 928 // both available and not "C" 929 // This is done because the "C" locale breaks wide character input, 930 // which is what we fall back on when UTF-8 support is missing 931 if (strcmp(setlocale(LC_CTYPE, null), "C") == 0) 932 setlocale(LC_CTYPE, ""); 933 } 934 935 XInitThreads(); 936 XrmInitialize(); 937 938 _glfw.x11.display = XOpenDisplay(null); 939 if (!_glfw.x11.display) 940 { 941 const(char)* display = getenv("DISPLAY"); 942 if (display) 943 { 944 _glfwInputError(GLFW_PLATFORM_ERROR, 945 "X11: Failed to open display %s", display); 946 } 947 else 948 { 949 _glfwInputError(GLFW_PLATFORM_ERROR, 950 "X11: The DISPLAY environment variable is missing"); 951 } 952 953 return GLFW_FALSE; 954 } 955 956 _glfw.x11.screen = DefaultScreen(_glfw.x11.display); 957 _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); 958 _glfw.x11.context = XUniqueContext(); 959 960 getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); 961 962 if (!initExtensions()) 963 return GLFW_FALSE; 964 965 _glfw.x11.helperWindowHandle = createHelperWindow(); 966 _glfw.x11.hiddenCursorHandle = createHiddenCursor(); 967 968 if (XSupportsLocale()) 969 { 970 XSetLocaleModifiers(""); 971 972 _glfw.x11.im = XOpenIM(_glfw.x11.display, null, null, null); 973 if (_glfw.x11.im) 974 { 975 if (!hasUsableInputMethodStyle()) 976 { 977 XCloseIM(_glfw.x11.im); 978 _glfw.x11.im = null; 979 } 980 } 981 } 982 983 version (linux) { 984 if (!_glfwInitJoysticksLinux()) 985 return GLFW_FALSE; 986 } 987 988 _glfwInitTimerPOSIX(); 989 990 _glfwPollMonitorsX11(); 991 return GLFW_TRUE; 992 } 993 994 void _glfwPlatformTerminate() { 995 if (_glfw.x11.helperWindowHandle) 996 { 997 if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == 998 _glfw.x11.helperWindowHandle) 999 { 1000 _glfwPushSelectionToManagerX11(); 1001 } 1002 1003 XDestroyWindow(_glfw.x11.display, _glfw.x11.helperWindowHandle); 1004 _glfw.x11.helperWindowHandle = None; 1005 } 1006 1007 if (_glfw.x11.hiddenCursorHandle) 1008 { 1009 XFreeCursor(_glfw.x11.display, _glfw.x11.hiddenCursorHandle); 1010 _glfw.x11.hiddenCursorHandle = cast(Cursor) 0; 1011 } 1012 1013 free(_glfw.x11.primarySelectionString); 1014 free(_glfw.x11.clipboardString); 1015 1016 if (_glfw.x11.im) 1017 { 1018 XCloseIM(_glfw.x11.im); 1019 _glfw.x11.im = null; 1020 } 1021 1022 if (_glfw.x11.display) 1023 { 1024 XCloseDisplay(_glfw.x11.display); 1025 _glfw.x11.display = null; 1026 } 1027 1028 if (_glfw.x11.x11xcb.handle) 1029 { 1030 _glfw_dlclose(_glfw.x11.x11xcb.handle); 1031 _glfw.x11.x11xcb.handle = null; 1032 } 1033 1034 if (_glfw.x11.xcursor.handle) 1035 { 1036 _glfw_dlclose(_glfw.x11.xcursor.handle); 1037 _glfw.x11.xcursor.handle = null; 1038 } 1039 1040 if (_glfw.x11.randr.handle) 1041 { 1042 _glfw_dlclose(_glfw.x11.randr.handle); 1043 _glfw.x11.randr.handle = null; 1044 } 1045 1046 if (_glfw.x11.xinerama.handle) 1047 { 1048 _glfw_dlclose(_glfw.x11.xinerama.handle); 1049 _glfw.x11.xinerama.handle = null; 1050 } 1051 1052 if (_glfw.x11.xrender.handle) 1053 { 1054 _glfw_dlclose(_glfw.x11.xrender.handle); 1055 _glfw.x11.xrender.handle = null; 1056 } 1057 1058 if (_glfw.x11.vidmode.handle) 1059 { 1060 _glfw_dlclose(_glfw.x11.vidmode.handle); 1061 _glfw.x11.vidmode.handle = null; 1062 } 1063 1064 if (_glfw.x11.xi.handle) 1065 { 1066 _glfw_dlclose(_glfw.x11.xi.handle); 1067 _glfw.x11.xi.handle = null; 1068 } 1069 1070 // NOTE: These need to be unloaded after XCloseDisplay, as they register 1071 // cleanup callbacks that get called by that function 1072 _glfwTerminateEGL(); 1073 _glfwTerminateGLX(); 1074 1075 version (linux) { 1076 _glfwTerminateJoysticksLinux(); 1077 } 1078 } 1079 1080 const(char)* _glfwPlatformGetVersionString() { 1081 version (linux) { 1082 enum evdev = " evdev"; 1083 } else { 1084 enum evdev = ""; 1085 } 1086 version (_GLFW_BUILD_DLL) { 1087 enum dllStr = " shared"; 1088 } else { 1089 enum dllStr = ""; 1090 } 1091 return _GLFW_VERSION_NUMBER ~ " X11 GLX EGL OSMesa" ~ evdev ~ dllStr; 1092 }