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