revolver

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

x11_init.c (56843B)


      1 //========================================================================
      2 // GLFW 3.4 X11 - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2002-2006 Marcus Geelnard
      5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
      6 //
      7 // This software is provided 'as-is', without any express or implied
      8 // warranty. In no event will the authors be held liable for any damages
      9 // arising from the use of this software.
     10 //
     11 // Permission is granted to anyone to use this software for any purpose,
     12 // including commercial applications, and to alter it and redistribute it
     13 // freely, subject to the following restrictions:
     14 //
     15 // 1. The origin of this software must not be misrepresented; you must not
     16 //    claim that you wrote the original software. If you use this software
     17 //    in a product, an acknowledgment in the product documentation would
     18 //    be appreciated but is not required.
     19 //
     20 // 2. Altered source versions must be plainly marked as such, and must not
     21 //    be misrepresented as being the original software.
     22 //
     23 // 3. This notice may not be removed or altered from any source
     24 //    distribution.
     25 //
     26 //========================================================================
     27 // It is fine to use C99 in this file because it will not be built with VS
     28 //========================================================================
     29 
     30 #include "internal.h"
     31 
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <limits.h>
     35 #include <stdio.h>
     36 #include <locale.h>
     37 #include <unistd.h>
     38 
     39 
     40 // Translate an X11 key code to a GLFW key code.
     41 //
     42 static int translateKeyCode(int scancode)
     43 {
     44     int keySym;
     45 
     46     // Valid key code range is  [8,255], according to the Xlib manual
     47     if (scancode < 8 || scancode > 255)
     48         return GLFW_KEY_UNKNOWN;
     49 
     50     if (_glfw.x11.xkb.available)
     51     {
     52         // Try secondary keysym, for numeric keypad keys
     53         // Note: This way we always force "NumLock = ON", which is intentional
     54         // since the returned key code should correspond to a physical
     55         // location.
     56         keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 1);
     57         switch (keySym)
     58         {
     59             case XK_KP_0:           return GLFW_KEY_KP_0;
     60             case XK_KP_1:           return GLFW_KEY_KP_1;
     61             case XK_KP_2:           return GLFW_KEY_KP_2;
     62             case XK_KP_3:           return GLFW_KEY_KP_3;
     63             case XK_KP_4:           return GLFW_KEY_KP_4;
     64             case XK_KP_5:           return GLFW_KEY_KP_5;
     65             case XK_KP_6:           return GLFW_KEY_KP_6;
     66             case XK_KP_7:           return GLFW_KEY_KP_7;
     67             case XK_KP_8:           return GLFW_KEY_KP_8;
     68             case XK_KP_9:           return GLFW_KEY_KP_9;
     69             case XK_KP_Separator:
     70             case XK_KP_Decimal:     return GLFW_KEY_KP_DECIMAL;
     71             case XK_KP_Equal:       return GLFW_KEY_KP_EQUAL;
     72             case XK_KP_Enter:       return GLFW_KEY_KP_ENTER;
     73             default:                break;
     74         }
     75 
     76         // Now try primary keysym for function keys (non-printable keys)
     77         // These should not depend on the current keyboard layout
     78         keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0);
     79     }
     80     else
     81     {
     82         int dummy;
     83         KeySym* keySyms;
     84 
     85         keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy);
     86         keySym = keySyms[0];
     87         XFree(keySyms);
     88     }
     89 
     90     switch (keySym)
     91     {
     92         case XK_Escape:         return GLFW_KEY_ESCAPE;
     93         case XK_Tab:            return GLFW_KEY_TAB;
     94         case XK_Shift_L:        return GLFW_KEY_LEFT_SHIFT;
     95         case XK_Shift_R:        return GLFW_KEY_RIGHT_SHIFT;
     96         case XK_Control_L:      return GLFW_KEY_LEFT_CONTROL;
     97         case XK_Control_R:      return GLFW_KEY_RIGHT_CONTROL;
     98         case XK_Meta_L:
     99         case XK_Alt_L:          return GLFW_KEY_LEFT_ALT;
    100         case XK_Mode_switch: // Mapped to Alt_R on many keyboards
    101         case XK_ISO_Level3_Shift: // AltGr on at least some machines
    102         case XK_Meta_R:
    103         case XK_Alt_R:          return GLFW_KEY_RIGHT_ALT;
    104         case XK_Super_L:        return GLFW_KEY_LEFT_SUPER;
    105         case XK_Super_R:        return GLFW_KEY_RIGHT_SUPER;
    106         case XK_Menu:           return GLFW_KEY_MENU;
    107         case XK_Num_Lock:       return GLFW_KEY_NUM_LOCK;
    108         case XK_Caps_Lock:      return GLFW_KEY_CAPS_LOCK;
    109         case XK_Print:          return GLFW_KEY_PRINT_SCREEN;
    110         case XK_Scroll_Lock:    return GLFW_KEY_SCROLL_LOCK;
    111         case XK_Pause:          return GLFW_KEY_PAUSE;
    112         case XK_Delete:         return GLFW_KEY_DELETE;
    113         case XK_BackSpace:      return GLFW_KEY_BACKSPACE;
    114         case XK_Return:         return GLFW_KEY_ENTER;
    115         case XK_Home:           return GLFW_KEY_HOME;
    116         case XK_End:            return GLFW_KEY_END;
    117         case XK_Page_Up:        return GLFW_KEY_PAGE_UP;
    118         case XK_Page_Down:      return GLFW_KEY_PAGE_DOWN;
    119         case XK_Insert:         return GLFW_KEY_INSERT;
    120         case XK_Left:           return GLFW_KEY_LEFT;
    121         case XK_Right:          return GLFW_KEY_RIGHT;
    122         case XK_Down:           return GLFW_KEY_DOWN;
    123         case XK_Up:             return GLFW_KEY_UP;
    124         case XK_F1:             return GLFW_KEY_F1;
    125         case XK_F2:             return GLFW_KEY_F2;
    126         case XK_F3:             return GLFW_KEY_F3;
    127         case XK_F4:             return GLFW_KEY_F4;
    128         case XK_F5:             return GLFW_KEY_F5;
    129         case XK_F6:             return GLFW_KEY_F6;
    130         case XK_F7:             return GLFW_KEY_F7;
    131         case XK_F8:             return GLFW_KEY_F8;
    132         case XK_F9:             return GLFW_KEY_F9;
    133         case XK_F10:            return GLFW_KEY_F10;
    134         case XK_F11:            return GLFW_KEY_F11;
    135         case XK_F12:            return GLFW_KEY_F12;
    136         case XK_F13:            return GLFW_KEY_F13;
    137         case XK_F14:            return GLFW_KEY_F14;
    138         case XK_F15:            return GLFW_KEY_F15;
    139         case XK_F16:            return GLFW_KEY_F16;
    140         case XK_F17:            return GLFW_KEY_F17;
    141         case XK_F18:            return GLFW_KEY_F18;
    142         case XK_F19:            return GLFW_KEY_F19;
    143         case XK_F20:            return GLFW_KEY_F20;
    144         case XK_F21:            return GLFW_KEY_F21;
    145         case XK_F22:            return GLFW_KEY_F22;
    146         case XK_F23:            return GLFW_KEY_F23;
    147         case XK_F24:            return GLFW_KEY_F24;
    148         case XK_F25:            return GLFW_KEY_F25;
    149 
    150         // Numeric keypad
    151         case XK_KP_Divide:      return GLFW_KEY_KP_DIVIDE;
    152         case XK_KP_Multiply:    return GLFW_KEY_KP_MULTIPLY;
    153         case XK_KP_Subtract:    return GLFW_KEY_KP_SUBTRACT;
    154         case XK_KP_Add:         return GLFW_KEY_KP_ADD;
    155 
    156         // These should have been detected in secondary keysym test above!
    157         case XK_KP_Insert:      return GLFW_KEY_KP_0;
    158         case XK_KP_End:         return GLFW_KEY_KP_1;
    159         case XK_KP_Down:        return GLFW_KEY_KP_2;
    160         case XK_KP_Page_Down:   return GLFW_KEY_KP_3;
    161         case XK_KP_Left:        return GLFW_KEY_KP_4;
    162         case XK_KP_Right:       return GLFW_KEY_KP_6;
    163         case XK_KP_Home:        return GLFW_KEY_KP_7;
    164         case XK_KP_Up:          return GLFW_KEY_KP_8;
    165         case XK_KP_Page_Up:     return GLFW_KEY_KP_9;
    166         case XK_KP_Delete:      return GLFW_KEY_KP_DECIMAL;
    167         case XK_KP_Equal:       return GLFW_KEY_KP_EQUAL;
    168         case XK_KP_Enter:       return GLFW_KEY_KP_ENTER;
    169 
    170         // Last resort: Check for printable keys (should not happen if the XKB
    171         // extension is available). This will give a layout dependent mapping
    172         // (which is wrong, and we may miss some keys, especially on non-US
    173         // keyboards), but it's better than nothing...
    174         case XK_a:              return GLFW_KEY_A;
    175         case XK_b:              return GLFW_KEY_B;
    176         case XK_c:              return GLFW_KEY_C;
    177         case XK_d:              return GLFW_KEY_D;
    178         case XK_e:              return GLFW_KEY_E;
    179         case XK_f:              return GLFW_KEY_F;
    180         case XK_g:              return GLFW_KEY_G;
    181         case XK_h:              return GLFW_KEY_H;
    182         case XK_i:              return GLFW_KEY_I;
    183         case XK_j:              return GLFW_KEY_J;
    184         case XK_k:              return GLFW_KEY_K;
    185         case XK_l:              return GLFW_KEY_L;
    186         case XK_m:              return GLFW_KEY_M;
    187         case XK_n:              return GLFW_KEY_N;
    188         case XK_o:              return GLFW_KEY_O;
    189         case XK_p:              return GLFW_KEY_P;
    190         case XK_q:              return GLFW_KEY_Q;
    191         case XK_r:              return GLFW_KEY_R;
    192         case XK_s:              return GLFW_KEY_S;
    193         case XK_t:              return GLFW_KEY_T;
    194         case XK_u:              return GLFW_KEY_U;
    195         case XK_v:              return GLFW_KEY_V;
    196         case XK_w:              return GLFW_KEY_W;
    197         case XK_x:              return GLFW_KEY_X;
    198         case XK_y:              return GLFW_KEY_Y;
    199         case XK_z:              return GLFW_KEY_Z;
    200         case XK_1:              return GLFW_KEY_1;
    201         case XK_2:              return GLFW_KEY_2;
    202         case XK_3:              return GLFW_KEY_3;
    203         case XK_4:              return GLFW_KEY_4;
    204         case XK_5:              return GLFW_KEY_5;
    205         case XK_6:              return GLFW_KEY_6;
    206         case XK_7:              return GLFW_KEY_7;
    207         case XK_8:              return GLFW_KEY_8;
    208         case XK_9:              return GLFW_KEY_9;
    209         case XK_0:              return GLFW_KEY_0;
    210         case XK_space:          return GLFW_KEY_SPACE;
    211         case XK_minus:          return GLFW_KEY_MINUS;
    212         case XK_equal:          return GLFW_KEY_EQUAL;
    213         case XK_bracketleft:    return GLFW_KEY_LEFT_BRACKET;
    214         case XK_bracketright:   return GLFW_KEY_RIGHT_BRACKET;
    215         case XK_backslash:      return GLFW_KEY_BACKSLASH;
    216         case XK_semicolon:      return GLFW_KEY_SEMICOLON;
    217         case XK_apostrophe:     return GLFW_KEY_APOSTROPHE;
    218         case XK_grave:          return GLFW_KEY_GRAVE_ACCENT;
    219         case XK_comma:          return GLFW_KEY_COMMA;
    220         case XK_period:         return GLFW_KEY_PERIOD;
    221         case XK_slash:          return GLFW_KEY_SLASH;
    222         case XK_less:           return GLFW_KEY_WORLD_1; // At least in some layouts...
    223         default:                break;
    224     }
    225 
    226     // No matching translation was found
    227     return GLFW_KEY_UNKNOWN;
    228 }
    229 
    230 // Create key code translation tables
    231 //
    232 static void createKeyTables(void)
    233 {
    234     int scancode, key;
    235 
    236     memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes));
    237     memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes));
    238 
    239     if (_glfw.x11.xkb.available)
    240     {
    241         // Use XKB to determine physical key locations independently of the
    242         // current keyboard layout
    243 
    244         char name[XkbKeyNameLength + 1];
    245         XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd);
    246         XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc);
    247 
    248         // Find the X11 key code -> GLFW key code mapping
    249         for (scancode = desc->min_key_code;  scancode <= desc->max_key_code;  scancode++)
    250         {
    251             memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength);
    252             name[XkbKeyNameLength] = '\0';
    253 
    254             // Map the key name to a GLFW key code. Note: We only map printable
    255             // keys here, and we use the US keyboard layout. The rest of the
    256             // keys (function keys) are mapped using traditional KeySym
    257             // translations.
    258             if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT;
    259             else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1;
    260             else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2;
    261             else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3;
    262             else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4;
    263             else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5;
    264             else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6;
    265             else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7;
    266             else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8;
    267             else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9;
    268             else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0;
    269             else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS;
    270             else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL;
    271             else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q;
    272             else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W;
    273             else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E;
    274             else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R;
    275             else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T;
    276             else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y;
    277             else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U;
    278             else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I;
    279             else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O;
    280             else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P;
    281             else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET;
    282             else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET;
    283             else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A;
    284             else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S;
    285             else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D;
    286             else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F;
    287             else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G;
    288             else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H;
    289             else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J;
    290             else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K;
    291             else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L;
    292             else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON;
    293             else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE;
    294             else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z;
    295             else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X;
    296             else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C;
    297             else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V;
    298             else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B;
    299             else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N;
    300             else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M;
    301             else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA;
    302             else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD;
    303             else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH;
    304             else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH;
    305             else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1;
    306             else key = GLFW_KEY_UNKNOWN;
    307 
    308             if ((scancode >= 0) && (scancode < 256))
    309                 _glfw.x11.keycodes[scancode] = key;
    310         }
    311 
    312         XkbFreeNames(desc, XkbKeyNamesMask, True);
    313         XkbFreeKeyboard(desc, 0, True);
    314     }
    315 
    316     for (scancode = 0;  scancode < 256;  scancode++)
    317     {
    318         // Translate the un-translated key codes using traditional X11 KeySym
    319         // lookups
    320         if (_glfw.x11.keycodes[scancode] < 0)
    321             _glfw.x11.keycodes[scancode] = translateKeyCode(scancode);
    322 
    323         // Store the reverse translation for faster key name lookup
    324         if (_glfw.x11.keycodes[scancode] > 0)
    325             _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode;
    326     }
    327 }
    328 
    329 // Check whether the IM has a usable style
    330 //
    331 static GLFWbool hasUsableInputMethodStyle(void)
    332 {
    333     GLFWbool found = GLFW_FALSE;
    334     XIMStyles* styles = NULL;
    335 
    336     if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
    337         return GLFW_FALSE;
    338 
    339     for (unsigned int i = 0;  i < styles->count_styles;  i++)
    340     {
    341         if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing))
    342         {
    343             found = GLFW_TRUE;
    344             break;
    345         }
    346     }
    347 
    348     XFree(styles);
    349     return found;
    350 }
    351 
    352 static void inputMethodDestroyCallback(XIM im, XPointer clientData, XPointer callData)
    353 {
    354     _glfw.x11.im = NULL;
    355 }
    356 
    357 static void inputMethodInstantiateCallback(Display* display,
    358                                            XPointer clientData,
    359                                            XPointer callData)
    360 {
    361     if (_glfw.x11.im)
    362         return;
    363 
    364     _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL);
    365     if (_glfw.x11.im)
    366     {
    367         if (!hasUsableInputMethodStyle())
    368         {
    369             XCloseIM(_glfw.x11.im);
    370             _glfw.x11.im = NULL;
    371         }
    372     }
    373 
    374     if (_glfw.x11.im)
    375     {
    376         XIMCallback callback;
    377         callback.callback = (XIMProc) inputMethodDestroyCallback;
    378         callback.client_data = NULL;
    379         XSetIMValues(_glfw.x11.im, XNDestroyCallback, &callback, NULL);
    380 
    381         for (_GLFWwindow* window = _glfw.windowListHead;  window;  window = window->next)
    382             _glfwCreateInputContextX11(window);
    383     }
    384 }
    385 
    386 // Check whether the specified atom is supported
    387 //
    388 static Atom getSupportedAtom(Atom* supportedAtoms,
    389                              unsigned long atomCount,
    390                              const char* atomName)
    391 {
    392     const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
    393 
    394     for (unsigned int i = 0;  i < atomCount;  i++)
    395     {
    396         if (supportedAtoms[i] == atom)
    397             return atom;
    398     }
    399 
    400     return None;
    401 }
    402 
    403 // Check whether the running window manager is EWMH-compliant
    404 //
    405 static void detectEWMH(void)
    406 {
    407     // First we read the _NET_SUPPORTING_WM_CHECK property on the root window
    408 
    409     Window* windowFromRoot = NULL;
    410     if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
    411                                    _glfw.x11.NET_SUPPORTING_WM_CHECK,
    412                                    XA_WINDOW,
    413                                    (unsigned char**) &windowFromRoot))
    414     {
    415         return;
    416     }
    417 
    418     _glfwGrabErrorHandlerX11();
    419 
    420     // If it exists, it should be the XID of a top-level window
    421     // Then we look for the same property on that window
    422 
    423     Window* windowFromChild = NULL;
    424     if (!_glfwGetWindowPropertyX11(*windowFromRoot,
    425                                    _glfw.x11.NET_SUPPORTING_WM_CHECK,
    426                                    XA_WINDOW,
    427                                    (unsigned char**) &windowFromChild))
    428     {
    429         XFree(windowFromRoot);
    430         return;
    431     }
    432 
    433     _glfwReleaseErrorHandlerX11();
    434 
    435     // If the property exists, it should contain the XID of the window
    436 
    437     if (*windowFromRoot != *windowFromChild)
    438     {
    439         XFree(windowFromRoot);
    440         XFree(windowFromChild);
    441         return;
    442     }
    443 
    444     XFree(windowFromRoot);
    445     XFree(windowFromChild);
    446 
    447     // We are now fairly sure that an EWMH-compliant WM is currently running
    448     // We can now start querying the WM about what features it supports by
    449     // looking in the _NET_SUPPORTED property on the root window
    450     // It should contain a list of supported EWMH protocol and state atoms
    451 
    452     Atom* supportedAtoms = NULL;
    453     const unsigned long atomCount =
    454         _glfwGetWindowPropertyX11(_glfw.x11.root,
    455                                   _glfw.x11.NET_SUPPORTED,
    456                                   XA_ATOM,
    457                                   (unsigned char**) &supportedAtoms);
    458 
    459     // See which of the atoms we support that are supported by the WM
    460 
    461     _glfw.x11.NET_WM_STATE =
    462         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
    463     _glfw.x11.NET_WM_STATE_ABOVE =
    464         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
    465     _glfw.x11.NET_WM_STATE_FULLSCREEN =
    466         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
    467     _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT =
    468         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");
    469     _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ =
    470         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");
    471     _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION =
    472         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION");
    473     _glfw.x11.NET_WM_FULLSCREEN_MONITORS =
    474         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
    475     _glfw.x11.NET_WM_WINDOW_TYPE =
    476         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
    477     _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =
    478         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
    479     _glfw.x11.NET_WORKAREA =
    480         getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA");
    481     _glfw.x11.NET_CURRENT_DESKTOP =
    482         getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP");
    483     _glfw.x11.NET_ACTIVE_WINDOW =
    484         getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
    485     _glfw.x11.NET_FRAME_EXTENTS =
    486         getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");
    487     _glfw.x11.NET_REQUEST_FRAME_EXTENTS =
    488         getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
    489 
    490     if (supportedAtoms)
    491         XFree(supportedAtoms);
    492 }
    493 
    494 // Look for and initialize supported X11 extensions
    495 //
    496 static GLFWbool initExtensions(void)
    497 {
    498     _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1");
    499     if (_glfw.x11.vidmode.handle)
    500     {
    501         _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension)
    502             _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
    503         _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp)
    504             _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
    505         _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp)
    506             _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp");
    507         _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize)
    508             _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize");
    509 
    510         _glfw.x11.vidmode.available =
    511             XF86VidModeQueryExtension(_glfw.x11.display,
    512                                       &_glfw.x11.vidmode.eventBase,
    513                                       &_glfw.x11.vidmode.errorBase);
    514     }
    515 
    516 #if defined(__CYGWIN__)
    517     _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so");
    518 #else
    519     _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6");
    520 #endif
    521     if (_glfw.x11.xi.handle)
    522     {
    523         _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion)
    524             _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion");
    525         _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
    526             _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents");
    527 
    528         if (XQueryExtension(_glfw.x11.display,
    529                             "XInputExtension",
    530                             &_glfw.x11.xi.majorOpcode,
    531                             &_glfw.x11.xi.eventBase,
    532                             &_glfw.x11.xi.errorBase))
    533         {
    534             _glfw.x11.xi.major = 2;
    535             _glfw.x11.xi.minor = 0;
    536 
    537             if (XIQueryVersion(_glfw.x11.display,
    538                                &_glfw.x11.xi.major,
    539                                &_glfw.x11.xi.minor) == Success)
    540             {
    541                 _glfw.x11.xi.available = GLFW_TRUE;
    542             }
    543         }
    544     }
    545 
    546 #if defined(__CYGWIN__)
    547     _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so");
    548 #else
    549     _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2");
    550 #endif
    551     if (_glfw.x11.randr.handle)
    552     {
    553         _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma)
    554             _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma");
    555         _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
    556             _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
    557         _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo)
    558             _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo");
    559         _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
    560             _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
    561         _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo)
    562             _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo");
    563         _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources)
    564             _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources");
    565         _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma)
    566             _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma");
    567         _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize)
    568             _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
    569         _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo)
    570             _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo");
    571         _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo)
    572             _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo");
    573         _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary)
    574             _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary");
    575         _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent)
    576             _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent");
    577         _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension)
    578             _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension");
    579         _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion)
    580             _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion");
    581         _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput)
    582             _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput");
    583         _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig)
    584             _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig");
    585         _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma)
    586             _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma");
    587         _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration)
    588             _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration");
    589 
    590         if (XRRQueryExtension(_glfw.x11.display,
    591                               &_glfw.x11.randr.eventBase,
    592                               &_glfw.x11.randr.errorBase))
    593         {
    594             if (XRRQueryVersion(_glfw.x11.display,
    595                                 &_glfw.x11.randr.major,
    596                                 &_glfw.x11.randr.minor))
    597             {
    598                 // The GLFW RandR path requires at least version 1.3
    599                 if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3)
    600                     _glfw.x11.randr.available = GLFW_TRUE;
    601             }
    602             else
    603             {
    604                 _glfwInputError(GLFW_PLATFORM_ERROR,
    605                                 "X11: Failed to query RandR version");
    606             }
    607         }
    608     }
    609 
    610     if (_glfw.x11.randr.available)
    611     {
    612         XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
    613                                                               _glfw.x11.root);
    614 
    615         if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0]))
    616         {
    617             // This is likely an older Nvidia driver with broken gamma support
    618             // Flag it as useless and fall back to xf86vm gamma, if available
    619             _glfw.x11.randr.gammaBroken = GLFW_TRUE;
    620         }
    621 
    622         if (!sr->ncrtc)
    623         {
    624             // A system without CRTCs is likely a system with broken RandR
    625             // Disable the RandR monitor path and fall back to core functions
    626             _glfw.x11.randr.monitorBroken = GLFW_TRUE;
    627         }
    628 
    629         XRRFreeScreenResources(sr);
    630     }
    631 
    632     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    633     {
    634         XRRSelectInput(_glfw.x11.display, _glfw.x11.root,
    635                        RROutputChangeNotifyMask);
    636     }
    637 
    638 #if defined(__CYGWIN__)
    639     _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so");
    640 #else
    641     _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1");
    642 #endif
    643     if (_glfw.x11.xcursor.handle)
    644     {
    645         _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate)
    646             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate");
    647         _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy)
    648             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
    649         _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
    650             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
    651         _glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme)
    652             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetTheme");
    653         _glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize)
    654             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize");
    655         _glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage)
    656             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage");
    657     }
    658 
    659 #if defined(__CYGWIN__)
    660     _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so");
    661 #else
    662     _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1");
    663 #endif
    664     if (_glfw.x11.xinerama.handle)
    665     {
    666         _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive)
    667             _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive");
    668         _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension)
    669             _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension");
    670         _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens)
    671             _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens");
    672 
    673         if (XineramaQueryExtension(_glfw.x11.display,
    674                                    &_glfw.x11.xinerama.major,
    675                                    &_glfw.x11.xinerama.minor))
    676         {
    677             if (XineramaIsActive(_glfw.x11.display))
    678                 _glfw.x11.xinerama.available = GLFW_TRUE;
    679         }
    680     }
    681 
    682     _glfw.x11.xkb.major = 1;
    683     _glfw.x11.xkb.minor = 0;
    684     _glfw.x11.xkb.available =
    685         XkbQueryExtension(_glfw.x11.display,
    686                           &_glfw.x11.xkb.majorOpcode,
    687                           &_glfw.x11.xkb.eventBase,
    688                           &_glfw.x11.xkb.errorBase,
    689                           &_glfw.x11.xkb.major,
    690                           &_glfw.x11.xkb.minor);
    691 
    692     if (_glfw.x11.xkb.available)
    693     {
    694         Bool supported;
    695 
    696         if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported))
    697         {
    698             if (supported)
    699                 _glfw.x11.xkb.detectable = GLFW_TRUE;
    700         }
    701 
    702         _glfw.x11.xkb.group = 0;
    703         XkbStateRec state;
    704         if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success)
    705         {
    706             XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask);
    707             _glfw.x11.xkb.group = (unsigned int)state.group;
    708         }
    709     }
    710 
    711 #if defined(__CYGWIN__)
    712     _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so");
    713 #else
    714     _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1");
    715 #endif
    716     if (_glfw.x11.x11xcb.handle)
    717     {
    718         _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection)
    719             _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
    720     }
    721 
    722 #if defined(__CYGWIN__)
    723     _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so");
    724 #else
    725     _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1");
    726 #endif
    727     if (_glfw.x11.xrender.handle)
    728     {
    729         _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension)
    730             _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension");
    731         _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion)
    732             _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion");
    733         _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat)
    734             _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat");
    735 
    736         if (XRenderQueryExtension(_glfw.x11.display,
    737                                   &_glfw.x11.xrender.errorBase,
    738                                   &_glfw.x11.xrender.eventBase))
    739         {
    740             if (XRenderQueryVersion(_glfw.x11.display,
    741                                     &_glfw.x11.xrender.major,
    742                                     &_glfw.x11.xrender.minor))
    743             {
    744                 _glfw.x11.xrender.available = GLFW_TRUE;
    745             }
    746         }
    747     }
    748 
    749     // Update the key code LUT
    750     // FIXME: We should listen to XkbMapNotify events to track changes to
    751     // the keyboard mapping.
    752     createKeyTables();
    753 
    754     // String format atoms
    755     _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
    756     _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
    757     _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);
    758 
    759     // Custom selection property atom
    760     _glfw.x11.GLFW_SELECTION =
    761         XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False);
    762 
    763     // ICCCM standard clipboard atoms
    764     _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
    765     _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
    766     _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False);
    767     _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False);
    768     _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
    769 
    770     // Clipboard manager atoms
    771     _glfw.x11.CLIPBOARD_MANAGER =
    772         XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False);
    773     _glfw.x11.SAVE_TARGETS =
    774         XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
    775 
    776     // Xdnd (drag and drop) atoms
    777     _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False);
    778     _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
    779     _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
    780     _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False);
    781     _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
    782     _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
    783     _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
    784     _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
    785     _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
    786     _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);
    787 
    788     // ICCCM, EWMH and Motif window property atoms
    789     // These can be set safely even without WM support
    790     // The EWMH atoms that require WM support are handled in detectEWMH
    791     _glfw.x11.WM_PROTOCOLS =
    792         XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False);
    793     _glfw.x11.WM_STATE =
    794         XInternAtom(_glfw.x11.display, "WM_STATE", False);
    795     _glfw.x11.WM_DELETE_WINDOW =
    796         XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
    797     _glfw.x11.NET_SUPPORTED =
    798         XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
    799     _glfw.x11.NET_SUPPORTING_WM_CHECK =
    800         XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
    801     _glfw.x11.NET_WM_ICON =
    802         XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
    803     _glfw.x11.NET_WM_PING =
    804         XInternAtom(_glfw.x11.display, "_NET_WM_PING", False);
    805     _glfw.x11.NET_WM_PID =
    806         XInternAtom(_glfw.x11.display, "_NET_WM_PID", False);
    807     _glfw.x11.NET_WM_NAME =
    808         XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False);
    809     _glfw.x11.NET_WM_ICON_NAME =
    810         XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False);
    811     _glfw.x11.NET_WM_BYPASS_COMPOSITOR =
    812         XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False);
    813     _glfw.x11.NET_WM_WINDOW_OPACITY =
    814         XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False);
    815     _glfw.x11.MOTIF_WM_HINTS =
    816         XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);
    817 
    818     // The compositing manager selection name contains the screen number
    819     {
    820         char name[32];
    821         snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen);
    822         _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False);
    823     }
    824 
    825     // Detect whether an EWMH-conformant window manager is running
    826     detectEWMH();
    827 
    828     return GLFW_TRUE;
    829 }
    830 
    831 // Retrieve system content scale via folklore heuristics
    832 //
    833 static void getSystemContentScale(float* xscale, float* yscale)
    834 {
    835     // Start by assuming the default X11 DPI
    836     // NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it
    837     //       would be set to 96, so assume that is the case if we cannot find it
    838     float xdpi = 96.f, ydpi = 96.f;
    839 
    840     // NOTE: Basing the scale on Xft.dpi where available should provide the most
    841     //       consistent user experience (matches Qt, Gtk, etc), although not
    842     //       always the most accurate one
    843     char* rms = XResourceManagerString(_glfw.x11.display);
    844     if (rms)
    845     {
    846         XrmDatabase db = XrmGetStringDatabase(rms);
    847         if (db)
    848         {
    849             XrmValue value;
    850             char* type = NULL;
    851 
    852             if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value))
    853             {
    854                 if (type && strcmp(type, "String") == 0)
    855                     xdpi = ydpi = atof(value.addr);
    856             }
    857 
    858             XrmDestroyDatabase(db);
    859         }
    860     }
    861 
    862     *xscale = xdpi / 96.f;
    863     *yscale = ydpi / 96.f;
    864 }
    865 
    866 // Create a blank cursor for hidden and disabled cursor modes
    867 //
    868 static Cursor createHiddenCursor(void)
    869 {
    870     unsigned char pixels[16 * 16 * 4] = { 0 };
    871     GLFWimage image = { 16, 16, pixels };
    872     return _glfwCreateCursorX11(&image, 0, 0);
    873 }
    874 
    875 // Create a helper window for IPC
    876 //
    877 static Window createHelperWindow(void)
    878 {
    879     XSetWindowAttributes wa;
    880     wa.event_mask = PropertyChangeMask;
    881 
    882     return XCreateWindow(_glfw.x11.display, _glfw.x11.root,
    883                          0, 0, 1, 1, 0, 0,
    884                          InputOnly,
    885                          DefaultVisual(_glfw.x11.display, _glfw.x11.screen),
    886                          CWEventMask, &wa);
    887 }
    888 
    889 // X error handler
    890 //
    891 static int errorHandler(Display *display, XErrorEvent* event)
    892 {
    893     _glfw.x11.errorCode = event->error_code;
    894     return 0;
    895 }
    896 
    897 
    898 //////////////////////////////////////////////////////////////////////////
    899 //////                       GLFW internal API                      //////
    900 //////////////////////////////////////////////////////////////////////////
    901 
    902 // Sets the X error handler callback
    903 //
    904 void _glfwGrabErrorHandlerX11(void)
    905 {
    906     _glfw.x11.errorCode = Success;
    907     XSetErrorHandler(errorHandler);
    908 }
    909 
    910 // Clears the X error handler callback
    911 //
    912 void _glfwReleaseErrorHandlerX11(void)
    913 {
    914     // Synchronize to make sure all commands are processed
    915     XSync(_glfw.x11.display, False);
    916     XSetErrorHandler(NULL);
    917 }
    918 
    919 // Reports the specified error, appending information about the last X error
    920 //
    921 void _glfwInputErrorX11(int error, const char* message)
    922 {
    923     char buffer[_GLFW_MESSAGE_SIZE];
    924     XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode,
    925                   buffer, sizeof(buffer));
    926 
    927     _glfwInputError(error, "%s: %s", message, buffer);
    928 }
    929 
    930 // Creates a native cursor object from the specified image and hotspot
    931 //
    932 Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot)
    933 {
    934     int i;
    935     Cursor cursor;
    936 
    937     if (!_glfw.x11.xcursor.handle)
    938         return None;
    939 
    940     XcursorImage* native = XcursorImageCreate(image->width, image->height);
    941     if (native == NULL)
    942         return None;
    943 
    944     native->xhot = xhot;
    945     native->yhot = yhot;
    946 
    947     unsigned char* source = (unsigned char*) image->pixels;
    948     XcursorPixel* target = native->pixels;
    949 
    950     for (i = 0;  i < image->width * image->height;  i++, target++, source += 4)
    951     {
    952         unsigned int alpha = source[3];
    953 
    954         *target = (alpha << 24) |
    955                   ((unsigned char) ((source[0] * alpha) / 255) << 16) |
    956                   ((unsigned char) ((source[1] * alpha) / 255) <<  8) |
    957                   ((unsigned char) ((source[2] * alpha) / 255) <<  0);
    958     }
    959 
    960     cursor = XcursorImageLoadCursor(_glfw.x11.display, native);
    961     XcursorImageDestroy(native);
    962 
    963     return cursor;
    964 }
    965 
    966 
    967 //////////////////////////////////////////////////////////////////////////
    968 //////                       GLFW platform API                      //////
    969 //////////////////////////////////////////////////////////////////////////
    970 
    971 int _glfwPlatformInit(void)
    972 {
    973     // HACK: If the application has left the locale as "C" then both wide
    974     //       character text input and explicit UTF-8 input via XIM will break
    975     //       This sets the CTYPE part of the current locale from the environment
    976     //       in the hope that it is set to something more sane than "C"
    977     if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0)
    978         setlocale(LC_CTYPE, "");
    979 
    980 #if defined(__CYGWIN__)
    981     _glfw.x11.xlib.handle = _glfw_dlopen("libX11-6.so");
    982 #else
    983     _glfw.x11.xlib.handle = _glfw_dlopen("libX11.so.6");
    984 #endif
    985     if (!_glfw.x11.xlib.handle)
    986     {
    987         _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib");
    988         return GLFW_FALSE;
    989     }
    990 
    991     _glfw.x11.xlib.AllocClassHint = (PFN_XAllocClassHint)
    992         _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocClassHint");
    993     _glfw.x11.xlib.AllocSizeHints = (PFN_XAllocSizeHints)
    994         _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocSizeHints");
    995     _glfw.x11.xlib.AllocWMHints = (PFN_XAllocWMHints)
    996         _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocWMHints");
    997     _glfw.x11.xlib.ChangeProperty = (PFN_XChangeProperty)
    998         _glfw_dlsym(_glfw.x11.xlib.handle, "XChangeProperty");
    999     _glfw.x11.xlib.ChangeWindowAttributes = (PFN_XChangeWindowAttributes)
   1000         _glfw_dlsym(_glfw.x11.xlib.handle, "XChangeWindowAttributes");
   1001     _glfw.x11.xlib.CheckIfEvent = (PFN_XCheckIfEvent)
   1002         _glfw_dlsym(_glfw.x11.xlib.handle, "XCheckIfEvent");
   1003     _glfw.x11.xlib.CheckTypedWindowEvent = (PFN_XCheckTypedWindowEvent)
   1004         _glfw_dlsym(_glfw.x11.xlib.handle, "XCheckTypedWindowEvent");
   1005     _glfw.x11.xlib.CloseDisplay = (PFN_XCloseDisplay)
   1006         _glfw_dlsym(_glfw.x11.xlib.handle, "XCloseDisplay");
   1007     _glfw.x11.xlib.CloseIM = (PFN_XCloseIM)
   1008         _glfw_dlsym(_glfw.x11.xlib.handle, "XCloseIM");
   1009     _glfw.x11.xlib.ConvertSelection = (PFN_XConvertSelection)
   1010         _glfw_dlsym(_glfw.x11.xlib.handle, "XConvertSelection");
   1011     _glfw.x11.xlib.CreateColormap = (PFN_XCreateColormap)
   1012         _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateColormap");
   1013     _glfw.x11.xlib.CreateFontCursor = (PFN_XCreateFontCursor)
   1014         _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateFontCursor");
   1015     _glfw.x11.xlib.CreateIC = (PFN_XCreateIC)
   1016         _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateIC");
   1017     _glfw.x11.xlib.CreateWindow = (PFN_XCreateWindow)
   1018         _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateWindow");
   1019     _glfw.x11.xlib.DefineCursor = (PFN_XDefineCursor)
   1020         _glfw_dlsym(_glfw.x11.xlib.handle, "XDefineCursor");
   1021     _glfw.x11.xlib.DeleteContext = (PFN_XDeleteContext)
   1022         _glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteContext");
   1023     _glfw.x11.xlib.DeleteProperty = (PFN_XDeleteProperty)
   1024         _glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteProperty");
   1025     _glfw.x11.xlib.DestroyIC = (PFN_XDestroyIC)
   1026         _glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyIC");
   1027     _glfw.x11.xlib.DestroyWindow = (PFN_XDestroyWindow)
   1028         _glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyWindow");
   1029     _glfw.x11.xlib.EventsQueued = (PFN_XEventsQueued)
   1030         _glfw_dlsym(_glfw.x11.xlib.handle, "XEventsQueued");
   1031     _glfw.x11.xlib.FilterEvent = (PFN_XFilterEvent)
   1032         _glfw_dlsym(_glfw.x11.xlib.handle, "XFilterEvent");
   1033     _glfw.x11.xlib.FindContext = (PFN_XFindContext)
   1034         _glfw_dlsym(_glfw.x11.xlib.handle, "XFindContext");
   1035     _glfw.x11.xlib.Flush = (PFN_XFlush)
   1036         _glfw_dlsym(_glfw.x11.xlib.handle, "XFlush");
   1037     _glfw.x11.xlib.Free = (PFN_XFree)
   1038         _glfw_dlsym(_glfw.x11.xlib.handle, "XFree");
   1039     _glfw.x11.xlib.FreeColormap = (PFN_XFreeColormap)
   1040         _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeColormap");
   1041     _glfw.x11.xlib.FreeCursor = (PFN_XFreeCursor)
   1042         _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeCursor");
   1043     _glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData)
   1044         _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeEventData");
   1045     _glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText)
   1046         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetErrorText");
   1047     _glfw.x11.xlib.GetEventData = (PFN_XGetEventData)
   1048         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetEventData");
   1049     _glfw.x11.xlib.GetICValues = (PFN_XGetICValues)
   1050         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetICValues");
   1051     _glfw.x11.xlib.GetIMValues = (PFN_XGetIMValues)
   1052         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetIMValues");
   1053     _glfw.x11.xlib.GetInputFocus = (PFN_XGetInputFocus)
   1054         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetInputFocus");
   1055     _glfw.x11.xlib.GetKeyboardMapping = (PFN_XGetKeyboardMapping)
   1056         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetKeyboardMapping");
   1057     _glfw.x11.xlib.GetScreenSaver = (PFN_XGetScreenSaver)
   1058         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetScreenSaver");
   1059     _glfw.x11.xlib.GetSelectionOwner = (PFN_XGetSelectionOwner)
   1060         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetSelectionOwner");
   1061     _glfw.x11.xlib.GetVisualInfo = (PFN_XGetVisualInfo)
   1062         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetVisualInfo");
   1063     _glfw.x11.xlib.GetWMNormalHints = (PFN_XGetWMNormalHints)
   1064         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWMNormalHints");
   1065     _glfw.x11.xlib.GetWindowAttributes = (PFN_XGetWindowAttributes)
   1066         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWindowAttributes");
   1067     _glfw.x11.xlib.GetWindowProperty = (PFN_XGetWindowProperty)
   1068         _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWindowProperty");
   1069     _glfw.x11.xlib.GrabPointer = (PFN_XGrabPointer)
   1070         _glfw_dlsym(_glfw.x11.xlib.handle, "XGrabPointer");
   1071     _glfw.x11.xlib.IconifyWindow = (PFN_XIconifyWindow)
   1072         _glfw_dlsym(_glfw.x11.xlib.handle, "XIconifyWindow");
   1073     _glfw.x11.xlib.InitThreads = (PFN_XInitThreads)
   1074         _glfw_dlsym(_glfw.x11.xlib.handle, "XInitThreads");
   1075     _glfw.x11.xlib.InternAtom = (PFN_XInternAtom)
   1076         _glfw_dlsym(_glfw.x11.xlib.handle, "XInternAtom");
   1077     _glfw.x11.xlib.LookupString = (PFN_XLookupString)
   1078         _glfw_dlsym(_glfw.x11.xlib.handle, "XLookupString");
   1079     _glfw.x11.xlib.MapRaised = (PFN_XMapRaised)
   1080         _glfw_dlsym(_glfw.x11.xlib.handle, "XMapRaised");
   1081     _glfw.x11.xlib.MapWindow = (PFN_XMapWindow)
   1082         _glfw_dlsym(_glfw.x11.xlib.handle, "XMapWindow");
   1083     _glfw.x11.xlib.MoveResizeWindow = (PFN_XMoveResizeWindow)
   1084         _glfw_dlsym(_glfw.x11.xlib.handle, "XMoveResizeWindow");
   1085     _glfw.x11.xlib.MoveWindow = (PFN_XMoveWindow)
   1086         _glfw_dlsym(_glfw.x11.xlib.handle, "XMoveWindow");
   1087     _glfw.x11.xlib.NextEvent = (PFN_XNextEvent)
   1088         _glfw_dlsym(_glfw.x11.xlib.handle, "XNextEvent");
   1089     _glfw.x11.xlib.OpenDisplay = (PFN_XOpenDisplay)
   1090         _glfw_dlsym(_glfw.x11.xlib.handle, "XOpenDisplay");
   1091     _glfw.x11.xlib.OpenIM = (PFN_XOpenIM)
   1092         _glfw_dlsym(_glfw.x11.xlib.handle, "XOpenIM");
   1093     _glfw.x11.xlib.PeekEvent = (PFN_XPeekEvent)
   1094         _glfw_dlsym(_glfw.x11.xlib.handle, "XPeekEvent");
   1095     _glfw.x11.xlib.Pending = (PFN_XPending)
   1096         _glfw_dlsym(_glfw.x11.xlib.handle, "XPending");
   1097     _glfw.x11.xlib.QueryExtension = (PFN_XQueryExtension)
   1098         _glfw_dlsym(_glfw.x11.xlib.handle, "XQueryExtension");
   1099     _glfw.x11.xlib.QueryPointer = (PFN_XQueryPointer)
   1100         _glfw_dlsym(_glfw.x11.xlib.handle, "XQueryPointer");
   1101     _glfw.x11.xlib.RaiseWindow = (PFN_XRaiseWindow)
   1102         _glfw_dlsym(_glfw.x11.xlib.handle, "XRaiseWindow");
   1103     _glfw.x11.xlib.RegisterIMInstantiateCallback = (PFN_XRegisterIMInstantiateCallback)
   1104         _glfw_dlsym(_glfw.x11.xlib.handle, "XRegisterIMInstantiateCallback");
   1105     _glfw.x11.xlib.ResizeWindow = (PFN_XResizeWindow)
   1106         _glfw_dlsym(_glfw.x11.xlib.handle, "XResizeWindow");
   1107     _glfw.x11.xlib.ResourceManagerString = (PFN_XResourceManagerString)
   1108         _glfw_dlsym(_glfw.x11.xlib.handle, "XResourceManagerString");
   1109     _glfw.x11.xlib.SaveContext = (PFN_XSaveContext)
   1110         _glfw_dlsym(_glfw.x11.xlib.handle, "XSaveContext");
   1111     _glfw.x11.xlib.SelectInput = (PFN_XSelectInput)
   1112         _glfw_dlsym(_glfw.x11.xlib.handle, "XSelectInput");
   1113     _glfw.x11.xlib.SendEvent = (PFN_XSendEvent)
   1114         _glfw_dlsym(_glfw.x11.xlib.handle, "XSendEvent");
   1115     _glfw.x11.xlib.SetClassHint = (PFN_XSetClassHint)
   1116         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetClassHint");
   1117     _glfw.x11.xlib.SetErrorHandler = (PFN_XSetErrorHandler)
   1118         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetErrorHandler");
   1119     _glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus)
   1120         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetICFocus");
   1121     _glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues)
   1122         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetIMValues");
   1123     _glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus)
   1124         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetInputFocus");
   1125     _glfw.x11.xlib.SetLocaleModifiers = (PFN_XSetLocaleModifiers)
   1126         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetLocaleModifiers");
   1127     _glfw.x11.xlib.SetScreenSaver = (PFN_XSetScreenSaver)
   1128         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetScreenSaver");
   1129     _glfw.x11.xlib.SetSelectionOwner = (PFN_XSetSelectionOwner)
   1130         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetSelectionOwner");
   1131     _glfw.x11.xlib.SetWMHints = (PFN_XSetWMHints)
   1132         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMHints");
   1133     _glfw.x11.xlib.SetWMNormalHints = (PFN_XSetWMNormalHints)
   1134         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMNormalHints");
   1135     _glfw.x11.xlib.SetWMProtocols = (PFN_XSetWMProtocols)
   1136         _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMProtocols");
   1137     _glfw.x11.xlib.SupportsLocale = (PFN_XSupportsLocale)
   1138         _glfw_dlsym(_glfw.x11.xlib.handle, "XSupportsLocale");
   1139     _glfw.x11.xlib.Sync = (PFN_XSync)
   1140         _glfw_dlsym(_glfw.x11.xlib.handle, "XSync");
   1141     _glfw.x11.xlib.TranslateCoordinates = (PFN_XTranslateCoordinates)
   1142         _glfw_dlsym(_glfw.x11.xlib.handle, "XTranslateCoordinates");
   1143     _glfw.x11.xlib.UndefineCursor = (PFN_XUndefineCursor)
   1144         _glfw_dlsym(_glfw.x11.xlib.handle, "XUndefineCursor");
   1145     _glfw.x11.xlib.UngrabPointer = (PFN_XUngrabPointer)
   1146         _glfw_dlsym(_glfw.x11.xlib.handle, "XUngrabPointer");
   1147     _glfw.x11.xlib.UnmapWindow = (PFN_XUnmapWindow)
   1148         _glfw_dlsym(_glfw.x11.xlib.handle, "XUnmapWindow");
   1149     _glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus)
   1150         _glfw_dlsym(_glfw.x11.xlib.handle, "XUnsetICFocus");
   1151     _glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual)
   1152         _glfw_dlsym(_glfw.x11.xlib.handle, "XVisualIDFromVisual");
   1153     _glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer)
   1154         _glfw_dlsym(_glfw.x11.xlib.handle, "XWarpPointer");
   1155     _glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard)
   1156         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeKeyboard");
   1157     _glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames)
   1158         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeNames");
   1159     _glfw.x11.xkb.GetMap = (PFN_XkbGetMap)
   1160         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetMap");
   1161     _glfw.x11.xkb.GetNames = (PFN_XkbGetNames)
   1162         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetNames");
   1163     _glfw.x11.xkb.GetState = (PFN_XkbGetState)
   1164         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetState");
   1165     _glfw.x11.xkb.KeycodeToKeysym = (PFN_XkbKeycodeToKeysym)
   1166         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbKeycodeToKeysym");
   1167     _glfw.x11.xkb.QueryExtension = (PFN_XkbQueryExtension)
   1168         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbQueryExtension");
   1169     _glfw.x11.xkb.SelectEventDetails = (PFN_XkbSelectEventDetails)
   1170         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbSelectEventDetails");
   1171     _glfw.x11.xkb.SetDetectableAutoRepeat = (PFN_XkbSetDetectableAutoRepeat)
   1172         _glfw_dlsym(_glfw.x11.xlib.handle, "XkbSetDetectableAutoRepeat");
   1173     _glfw.x11.xrm.DestroyDatabase = (PFN_XrmDestroyDatabase)
   1174         _glfw_dlsym(_glfw.x11.xlib.handle, "XrmDestroyDatabase");
   1175     _glfw.x11.xrm.GetResource = (PFN_XrmGetResource)
   1176         _glfw_dlsym(_glfw.x11.xlib.handle, "XrmGetResource");
   1177     _glfw.x11.xrm.GetStringDatabase = (PFN_XrmGetStringDatabase)
   1178         _glfw_dlsym(_glfw.x11.xlib.handle, "XrmGetStringDatabase");
   1179     _glfw.x11.xrm.Initialize = (PFN_XrmInitialize)
   1180         _glfw_dlsym(_glfw.x11.xlib.handle, "XrmInitialize");
   1181     _glfw.x11.xrm.UniqueQuark = (PFN_XrmUniqueQuark)
   1182         _glfw_dlsym(_glfw.x11.xlib.handle, "XrmUniqueQuark");
   1183     _glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback)
   1184         _glfw_dlsym(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback");
   1185     _glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString)
   1186         _glfw_dlsym(_glfw.x11.xlib.handle, "Xutf8LookupString");
   1187     _glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties)
   1188         _glfw_dlsym(_glfw.x11.xlib.handle, "Xutf8SetWMProperties");
   1189 
   1190     XInitThreads();
   1191     XrmInitialize();
   1192 
   1193     _glfw.x11.display = XOpenDisplay(NULL);
   1194     if (!_glfw.x11.display)
   1195     {
   1196         const char* display = getenv("DISPLAY");
   1197         if (display)
   1198         {
   1199             _glfwInputError(GLFW_PLATFORM_ERROR,
   1200                             "X11: Failed to open display %s", display);
   1201         }
   1202         else
   1203         {
   1204             _glfwInputError(GLFW_PLATFORM_ERROR,
   1205                             "X11: The DISPLAY environment variable is missing");
   1206         }
   1207 
   1208         return GLFW_FALSE;
   1209     }
   1210 
   1211     _glfw.x11.screen = DefaultScreen(_glfw.x11.display);
   1212     _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen);
   1213     _glfw.x11.context = XUniqueContext();
   1214 
   1215     getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY);
   1216 
   1217     if (!initExtensions())
   1218         return GLFW_FALSE;
   1219 
   1220     _glfw.x11.helperWindowHandle = createHelperWindow();
   1221     _glfw.x11.hiddenCursorHandle = createHiddenCursor();
   1222 
   1223     if (XSupportsLocale())
   1224     {
   1225         XSetLocaleModifiers("");
   1226 
   1227         // If an IM is already present our callback will be called right away
   1228         XRegisterIMInstantiateCallback(_glfw.x11.display,
   1229                                        NULL, NULL, NULL,
   1230                                        inputMethodInstantiateCallback,
   1231                                        NULL);
   1232     }
   1233 
   1234 #if defined(__linux__)
   1235     if (!_glfwInitJoysticksLinux())
   1236         return GLFW_FALSE;
   1237 #endif
   1238 
   1239     _glfwInitTimerPOSIX();
   1240 
   1241     _glfwPollMonitorsX11();
   1242     return GLFW_TRUE;
   1243 }
   1244 
   1245 void _glfwPlatformTerminate(void)
   1246 {
   1247     if (_glfw.x11.helperWindowHandle)
   1248     {
   1249         if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) ==
   1250             _glfw.x11.helperWindowHandle)
   1251         {
   1252             _glfwPushSelectionToManagerX11();
   1253         }
   1254 
   1255         XDestroyWindow(_glfw.x11.display, _glfw.x11.helperWindowHandle);
   1256         _glfw.x11.helperWindowHandle = None;
   1257     }
   1258 
   1259     if (_glfw.x11.hiddenCursorHandle)
   1260     {
   1261         XFreeCursor(_glfw.x11.display, _glfw.x11.hiddenCursorHandle);
   1262         _glfw.x11.hiddenCursorHandle = (Cursor) 0;
   1263     }
   1264 
   1265     free(_glfw.x11.primarySelectionString);
   1266     free(_glfw.x11.clipboardString);
   1267 
   1268     XUnregisterIMInstantiateCallback(_glfw.x11.display,
   1269                                      NULL, NULL, NULL,
   1270                                      inputMethodInstantiateCallback,
   1271                                      NULL);
   1272 
   1273     if (_glfw.x11.im)
   1274     {
   1275         XCloseIM(_glfw.x11.im);
   1276         _glfw.x11.im = NULL;
   1277     }
   1278 
   1279     if (_glfw.x11.display)
   1280     {
   1281         XCloseDisplay(_glfw.x11.display);
   1282         _glfw.x11.display = NULL;
   1283     }
   1284 
   1285     if (_glfw.x11.x11xcb.handle)
   1286     {
   1287         _glfw_dlclose(_glfw.x11.x11xcb.handle);
   1288         _glfw.x11.x11xcb.handle = NULL;
   1289     }
   1290 
   1291     if (_glfw.x11.xcursor.handle)
   1292     {
   1293         _glfw_dlclose(_glfw.x11.xcursor.handle);
   1294         _glfw.x11.xcursor.handle = NULL;
   1295     }
   1296 
   1297     if (_glfw.x11.randr.handle)
   1298     {
   1299         _glfw_dlclose(_glfw.x11.randr.handle);
   1300         _glfw.x11.randr.handle = NULL;
   1301     }
   1302 
   1303     if (_glfw.x11.xinerama.handle)
   1304     {
   1305         _glfw_dlclose(_glfw.x11.xinerama.handle);
   1306         _glfw.x11.xinerama.handle = NULL;
   1307     }
   1308 
   1309     if (_glfw.x11.xrender.handle)
   1310     {
   1311         _glfw_dlclose(_glfw.x11.xrender.handle);
   1312         _glfw.x11.xrender.handle = NULL;
   1313     }
   1314 
   1315     if (_glfw.x11.vidmode.handle)
   1316     {
   1317         _glfw_dlclose(_glfw.x11.vidmode.handle);
   1318         _glfw.x11.vidmode.handle = NULL;
   1319     }
   1320 
   1321     if (_glfw.x11.xi.handle)
   1322     {
   1323         _glfw_dlclose(_glfw.x11.xi.handle);
   1324         _glfw.x11.xi.handle = NULL;
   1325     }
   1326 
   1327     // NOTE: These need to be unloaded after XCloseDisplay, as they register
   1328     //       cleanup callbacks that get called by that function
   1329     _glfwTerminateEGL();
   1330     _glfwTerminateGLX();
   1331 
   1332 #if defined(__linux__)
   1333     _glfwTerminateJoysticksLinux();
   1334 #endif
   1335 
   1336     if (_glfw.x11.xlib.handle)
   1337     {
   1338         _glfw_dlclose(_glfw.x11.xlib.handle);
   1339         _glfw.x11.xlib.handle = NULL;
   1340     }
   1341 }
   1342 
   1343 const char* _glfwPlatformGetVersionString(void)
   1344 {
   1345     return _GLFW_VERSION_NUMBER " X11 GLX EGL OSMesa"
   1346 #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
   1347         " clock_gettime"
   1348 #else
   1349         " gettimeofday"
   1350 #endif
   1351 #if defined(__linux__)
   1352         " evdev"
   1353 #endif
   1354 #if defined(_GLFW_BUILD_DLL)
   1355         " shared"
   1356 #endif
   1357         ;
   1358 }
   1359