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 <limits.h> |
33 | #include <stdlib.h> |
34 | #include <string.h> |
35 | #include <math.h> |
36 | |
37 | |
38 | // Check whether the display mode should be included in enumeration |
39 | // |
40 | static GLFWbool modeIsGood(const XRRModeInfo* mi) |
41 | { |
42 | return (mi->modeFlags & RR_Interlace) == 0; |
43 | } |
44 | |
45 | // Calculates the refresh rate, in Hz, from the specified RandR mode info |
46 | // |
47 | static int calculateRefreshRate(const XRRModeInfo* mi) |
48 | { |
49 | if (mi->hTotal && mi->vTotal) |
50 | return (int) round((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); |
51 | else |
52 | return 0; |
53 | } |
54 | |
55 | // Returns the mode info for a RandR mode XID |
56 | // |
57 | static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) |
58 | { |
59 | for (int i = 0; i < sr->nmode; i++) |
60 | { |
61 | if (sr->modes[i].id == id) |
62 | return sr->modes + i; |
63 | } |
64 | |
65 | return NULL; |
66 | } |
67 | |
68 | // Convert RandR mode info to GLFW video mode |
69 | // |
70 | static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi, |
71 | const XRRCrtcInfo* ci) |
72 | { |
73 | GLFWvidmode mode; |
74 | |
75 | if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) |
76 | { |
77 | mode.width = mi->height; |
78 | mode.height = mi->width; |
79 | } |
80 | else |
81 | { |
82 | mode.width = mi->width; |
83 | mode.height = mi->height; |
84 | } |
85 | |
86 | mode.refreshRate = calculateRefreshRate(mi); |
87 | |
88 | _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), |
89 | &mode.redBits, &mode.greenBits, &mode.blueBits); |
90 | |
91 | return mode; |
92 | } |
93 | |
94 | |
95 | ////////////////////////////////////////////////////////////////////////// |
96 | ////// GLFW internal API ////// |
97 | ////////////////////////////////////////////////////////////////////////// |
98 | |
99 | // Poll for changes in the set of connected monitors |
100 | // |
101 | void _glfwPollMonitorsX11(void) |
102 | { |
103 | if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) |
104 | { |
105 | int disconnectedCount, screenCount = 0; |
106 | _GLFWmonitor** disconnected = NULL; |
107 | XineramaScreenInfo* screens = NULL; |
108 | XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, |
109 | _glfw.x11.root); |
110 | RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, |
111 | _glfw.x11.root); |
112 | |
113 | if (_glfw.x11.xinerama.available) |
114 | screens = XineramaQueryScreens(_glfw.x11.display, &screenCount); |
115 | |
116 | disconnectedCount = _glfw.monitorCount; |
117 | if (disconnectedCount) |
118 | { |
119 | disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); |
120 | memcpy(disconnected, |
121 | _glfw.monitors, |
122 | _glfw.monitorCount * sizeof(_GLFWmonitor*)); |
123 | } |
124 | |
125 | for (int i = 0; i < sr->noutput; i++) |
126 | { |
127 | int j, type, widthMM, heightMM; |
128 | |
129 | XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]); |
130 | if (oi->connection != RR_Connected || oi->crtc == None) |
131 | { |
132 | XRRFreeOutputInfo(oi); |
133 | continue; |
134 | } |
135 | |
136 | for (j = 0; j < disconnectedCount; j++) |
137 | { |
138 | if (disconnected[j] && |
139 | disconnected[j]->x11.output == sr->outputs[i]) |
140 | { |
141 | disconnected[j] = NULL; |
142 | break; |
143 | } |
144 | } |
145 | |
146 | if (j < disconnectedCount) |
147 | { |
148 | XRRFreeOutputInfo(oi); |
149 | continue; |
150 | } |
151 | |
152 | XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); |
153 | if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) |
154 | { |
155 | widthMM = oi->mm_height; |
156 | heightMM = oi->mm_width; |
157 | } |
158 | else |
159 | { |
160 | widthMM = oi->mm_width; |
161 | heightMM = oi->mm_height; |
162 | } |
163 | |
164 | if (widthMM <= 0 || heightMM <= 0) |
165 | { |
166 | // HACK: If RandR does not provide a physical size, assume the |
167 | // X11 default 96 DPI and calculate from the CRTC viewport |
168 | // NOTE: These members are affected by rotation, unlike the mode |
169 | // info and output info members |
170 | widthMM = (int) (ci->width * 25.4f / 96.f); |
171 | heightMM = (int) (ci->height * 25.4f / 96.f); |
172 | } |
173 | |
174 | _GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM); |
175 | monitor->x11.output = sr->outputs[i]; |
176 | monitor->x11.crtc = oi->crtc; |
177 | |
178 | for (j = 0; j < screenCount; j++) |
179 | { |
180 | if (screens[j].x_org == ci->x && |
181 | screens[j].y_org == ci->y && |
182 | screens[j].width == ci->width && |
183 | screens[j].height == ci->height) |
184 | { |
185 | monitor->x11.index = j; |
186 | break; |
187 | } |
188 | } |
189 | |
190 | if (monitor->x11.output == primary) |
191 | type = _GLFW_INSERT_FIRST; |
192 | else |
193 | type = _GLFW_INSERT_LAST; |
194 | |
195 | _glfwInputMonitor(monitor, GLFW_CONNECTED, type); |
196 | |
197 | XRRFreeOutputInfo(oi); |
198 | XRRFreeCrtcInfo(ci); |
199 | } |
200 | |
201 | XRRFreeScreenResources(sr); |
202 | |
203 | if (screens) |
204 | XFree(screens); |
205 | |
206 | for (int i = 0; i < disconnectedCount; i++) |
207 | { |
208 | if (disconnected[i]) |
209 | _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); |
210 | } |
211 | |
212 | _glfw_free(disconnected); |
213 | } |
214 | else |
215 | { |
216 | const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); |
217 | const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); |
218 | |
219 | _glfwInputMonitor(_glfwAllocMonitor("Display" , widthMM, heightMM), |
220 | GLFW_CONNECTED, |
221 | _GLFW_INSERT_FIRST); |
222 | } |
223 | } |
224 | |
225 | // Set the current video mode for the specified monitor |
226 | // |
227 | void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) |
228 | { |
229 | if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) |
230 | { |
231 | GLFWvidmode current; |
232 | RRMode native = None; |
233 | |
234 | const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired); |
235 | _glfwGetVideoModeX11(monitor, ¤t); |
236 | if (_glfwCompareVideoModes(¤t, best) == 0) |
237 | return; |
238 | |
239 | XRRScreenResources* sr = |
240 | XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); |
241 | XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); |
242 | XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); |
243 | |
244 | for (int i = 0; i < oi->nmode; i++) |
245 | { |
246 | const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); |
247 | if (!modeIsGood(mi)) |
248 | continue; |
249 | |
250 | const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); |
251 | if (_glfwCompareVideoModes(best, &mode) == 0) |
252 | { |
253 | native = mi->id; |
254 | break; |
255 | } |
256 | } |
257 | |
258 | if (native) |
259 | { |
260 | if (monitor->x11.oldMode == None) |
261 | monitor->x11.oldMode = ci->mode; |
262 | |
263 | XRRSetCrtcConfig(_glfw.x11.display, |
264 | sr, monitor->x11.crtc, |
265 | CurrentTime, |
266 | ci->x, ci->y, |
267 | native, |
268 | ci->rotation, |
269 | ci->outputs, |
270 | ci->noutput); |
271 | } |
272 | |
273 | XRRFreeOutputInfo(oi); |
274 | XRRFreeCrtcInfo(ci); |
275 | XRRFreeScreenResources(sr); |
276 | } |
277 | } |
278 | |
279 | // Restore the saved (original) video mode for the specified monitor |
280 | // |
281 | void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) |
282 | { |
283 | if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) |
284 | { |
285 | if (monitor->x11.oldMode == None) |
286 | return; |
287 | |
288 | XRRScreenResources* sr = |
289 | XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); |
290 | XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); |
291 | |
292 | XRRSetCrtcConfig(_glfw.x11.display, |
293 | sr, monitor->x11.crtc, |
294 | CurrentTime, |
295 | ci->x, ci->y, |
296 | monitor->x11.oldMode, |
297 | ci->rotation, |
298 | ci->outputs, |
299 | ci->noutput); |
300 | |
301 | XRRFreeCrtcInfo(ci); |
302 | XRRFreeScreenResources(sr); |
303 | |
304 | monitor->x11.oldMode = None; |
305 | } |
306 | } |
307 | |
308 | |
309 | ////////////////////////////////////////////////////////////////////////// |
310 | ////// GLFW platform API ////// |
311 | ////////////////////////////////////////////////////////////////////////// |
312 | |
313 | void _glfwFreeMonitorX11(_GLFWmonitor* monitor) |
314 | { |
315 | } |
316 | |
317 | void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos) |
318 | { |
319 | if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) |
320 | { |
321 | XRRScreenResources* sr = |
322 | XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); |
323 | XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); |
324 | |
325 | if (ci) |
326 | { |
327 | if (xpos) |
328 | *xpos = ci->x; |
329 | if (ypos) |
330 | *ypos = ci->y; |
331 | |
332 | XRRFreeCrtcInfo(ci); |
333 | } |
334 | |
335 | XRRFreeScreenResources(sr); |
336 | } |
337 | } |
338 | |
339 | void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor, |
340 | float* xscale, float* yscale) |
341 | { |
342 | if (xscale) |
343 | *xscale = _glfw.x11.contentScaleX; |
344 | if (yscale) |
345 | *yscale = _glfw.x11.contentScaleY; |
346 | } |
347 | |
348 | void _glfwGetMonitorWorkareaX11(_GLFWmonitor* monitor, |
349 | int* xpos, int* ypos, |
350 | int* width, int* height) |
351 | { |
352 | int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0; |
353 | |
354 | if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) |
355 | { |
356 | XRRScreenResources* sr = |
357 | XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); |
358 | XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); |
359 | |
360 | areaX = ci->x; |
361 | areaY = ci->y; |
362 | |
363 | const XRRModeInfo* mi = getModeInfo(sr, ci->mode); |
364 | |
365 | if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) |
366 | { |
367 | areaWidth = mi->height; |
368 | areaHeight = mi->width; |
369 | } |
370 | else |
371 | { |
372 | areaWidth = mi->width; |
373 | areaHeight = mi->height; |
374 | } |
375 | |
376 | XRRFreeCrtcInfo(ci); |
377 | XRRFreeScreenResources(sr); |
378 | } |
379 | else |
380 | { |
381 | areaWidth = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); |
382 | areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); |
383 | } |
384 | |
385 | if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP) |
386 | { |
387 | Atom* extents = NULL; |
388 | Atom* desktop = NULL; |
389 | const unsigned long extentCount = |
390 | _glfwGetWindowPropertyX11(_glfw.x11.root, |
391 | _glfw.x11.NET_WORKAREA, |
392 | XA_CARDINAL, |
393 | (unsigned char**) &extents); |
394 | |
395 | if (_glfwGetWindowPropertyX11(_glfw.x11.root, |
396 | _glfw.x11.NET_CURRENT_DESKTOP, |
397 | XA_CARDINAL, |
398 | (unsigned char**) &desktop) > 0) |
399 | { |
400 | if (extentCount >= 4 && *desktop < extentCount / 4) |
401 | { |
402 | const int globalX = extents[*desktop * 4 + 0]; |
403 | const int globalY = extents[*desktop * 4 + 1]; |
404 | const int globalWidth = extents[*desktop * 4 + 2]; |
405 | const int globalHeight = extents[*desktop * 4 + 3]; |
406 | |
407 | if (areaX < globalX) |
408 | { |
409 | areaWidth -= globalX - areaX; |
410 | areaX = globalX; |
411 | } |
412 | |
413 | if (areaY < globalY) |
414 | { |
415 | areaHeight -= globalY - areaY; |
416 | areaY = globalY; |
417 | } |
418 | |
419 | if (areaX + areaWidth > globalX + globalWidth) |
420 | areaWidth = globalX - areaX + globalWidth; |
421 | if (areaY + areaHeight > globalY + globalHeight) |
422 | areaHeight = globalY - areaY + globalHeight; |
423 | } |
424 | } |
425 | |
426 | if (extents) |
427 | XFree(extents); |
428 | if (desktop) |
429 | XFree(desktop); |
430 | } |
431 | |
432 | if (xpos) |
433 | *xpos = areaX; |
434 | if (ypos) |
435 | *ypos = areaY; |
436 | if (width) |
437 | *width = areaWidth; |
438 | if (height) |
439 | *height = areaHeight; |
440 | } |
441 | |
442 | GLFWvidmode* _glfwGetVideoModesX11(_GLFWmonitor* monitor, int* count) |
443 | { |
444 | GLFWvidmode* result; |
445 | |
446 | *count = 0; |
447 | |
448 | if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) |
449 | { |
450 | XRRScreenResources* sr = |
451 | XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); |
452 | XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); |
453 | XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); |
454 | |
455 | result = _glfw_calloc(oi->nmode, sizeof(GLFWvidmode)); |
456 | |
457 | for (int i = 0; i < oi->nmode; i++) |
458 | { |
459 | const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); |
460 | if (!modeIsGood(mi)) |
461 | continue; |
462 | |
463 | const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); |
464 | int j; |
465 | |
466 | for (j = 0; j < *count; j++) |
467 | { |
468 | if (_glfwCompareVideoModes(result + j, &mode) == 0) |
469 | break; |
470 | } |
471 | |
472 | // Skip duplicate modes |
473 | if (j < *count) |
474 | continue; |
475 | |
476 | (*count)++; |
477 | result[*count - 1] = mode; |
478 | } |
479 | |
480 | XRRFreeOutputInfo(oi); |
481 | XRRFreeCrtcInfo(ci); |
482 | XRRFreeScreenResources(sr); |
483 | } |
484 | else |
485 | { |
486 | *count = 1; |
487 | result = _glfw_calloc(1, sizeof(GLFWvidmode)); |
488 | _glfwGetVideoModeX11(monitor, result); |
489 | } |
490 | |
491 | return result; |
492 | } |
493 | |
494 | void _glfwGetVideoModeX11(_GLFWmonitor* monitor, GLFWvidmode* mode) |
495 | { |
496 | if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) |
497 | { |
498 | XRRScreenResources* sr = |
499 | XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); |
500 | XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); |
501 | |
502 | if (ci) |
503 | { |
504 | const XRRModeInfo* mi = getModeInfo(sr, ci->mode); |
505 | if (mi) // mi can be NULL if the monitor has been disconnected |
506 | *mode = vidmodeFromModeInfo(mi, ci); |
507 | |
508 | XRRFreeCrtcInfo(ci); |
509 | } |
510 | |
511 | XRRFreeScreenResources(sr); |
512 | } |
513 | else |
514 | { |
515 | mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); |
516 | mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); |
517 | mode->refreshRate = 0; |
518 | |
519 | _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), |
520 | &mode->redBits, &mode->greenBits, &mode->blueBits); |
521 | } |
522 | } |
523 | |
524 | GLFWbool _glfwGetGammaRampX11(_GLFWmonitor* monitor, GLFWgammaramp* ramp) |
525 | { |
526 | if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) |
527 | { |
528 | const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, |
529 | monitor->x11.crtc); |
530 | XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, |
531 | monitor->x11.crtc); |
532 | |
533 | _glfwAllocGammaArrays(ramp, size); |
534 | |
535 | memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); |
536 | memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); |
537 | memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); |
538 | |
539 | XRRFreeGamma(gamma); |
540 | return GLFW_TRUE; |
541 | } |
542 | else if (_glfw.x11.vidmode.available) |
543 | { |
544 | int size; |
545 | XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); |
546 | |
547 | _glfwAllocGammaArrays(ramp, size); |
548 | |
549 | XF86VidModeGetGammaRamp(_glfw.x11.display, |
550 | _glfw.x11.screen, |
551 | ramp->size, ramp->red, ramp->green, ramp->blue); |
552 | return GLFW_TRUE; |
553 | } |
554 | else |
555 | { |
556 | _glfwInputError(GLFW_PLATFORM_ERROR, |
557 | "X11: Gamma ramp access not supported by server" ); |
558 | return GLFW_FALSE; |
559 | } |
560 | } |
561 | |
562 | void _glfwSetGammaRampX11(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) |
563 | { |
564 | if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) |
565 | { |
566 | if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size) |
567 | { |
568 | _glfwInputError(GLFW_PLATFORM_ERROR, |
569 | "X11: Gamma ramp size must match current ramp size" ); |
570 | return; |
571 | } |
572 | |
573 | XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); |
574 | |
575 | memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); |
576 | memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); |
577 | memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); |
578 | |
579 | XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); |
580 | XRRFreeGamma(gamma); |
581 | } |
582 | else if (_glfw.x11.vidmode.available) |
583 | { |
584 | XF86VidModeSetGammaRamp(_glfw.x11.display, |
585 | _glfw.x11.screen, |
586 | ramp->size, |
587 | (unsigned short*) ramp->red, |
588 | (unsigned short*) ramp->green, |
589 | (unsigned short*) ramp->blue); |
590 | } |
591 | else |
592 | { |
593 | _glfwInputError(GLFW_PLATFORM_ERROR, |
594 | "X11: Gamma ramp access not supported by server" ); |
595 | } |
596 | } |
597 | |
598 | |
599 | ////////////////////////////////////////////////////////////////////////// |
600 | ////// GLFW native API ////// |
601 | ////////////////////////////////////////////////////////////////////////// |
602 | |
603 | GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) |
604 | { |
605 | _GLFWmonitor* monitor = (_GLFWmonitor*) handle; |
606 | _GLFW_REQUIRE_INIT_OR_RETURN(None); |
607 | return monitor->x11.crtc; |
608 | } |
609 | |
610 | GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) |
611 | { |
612 | _GLFWmonitor* monitor = (_GLFWmonitor*) handle; |
613 | _GLFW_REQUIRE_INIT_OR_RETURN(None); |
614 | return monitor->x11.output; |
615 | } |
616 | |
617 | |