]> git.sesse.net Git - pistorm/blob - raylib/external/glfw/src/window.c
[MEGA-WIP] Raylib-based RTG output
[pistorm] / raylib / external / glfw / src / window.c
1 //========================================================================
2 // GLFW 3.4 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
6 // Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 //    claim that you wrote the original software. If you use this software
18 //    in a product, an acknowledgment in the product documentation would
19 //    be appreciated but is not required.
20 //
21 // 2. Altered source versions must be plainly marked as such, and must not
22 //    be misrepresented as being the original software.
23 //
24 // 3. This notice may not be removed or altered from any source
25 //    distribution.
26 //
27 //========================================================================
28 // Please use C89 style variable declarations in this file because VS 2010
29 //========================================================================
30
31 #include "internal.h"
32
33 #include <assert.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <float.h>
37
38
39 //////////////////////////////////////////////////////////////////////////
40 //////                         GLFW event API                       //////
41 //////////////////////////////////////////////////////////////////////////
42
43 // Notifies shared code that a window has lost or received input focus
44 //
45 void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused)
46 {
47     if (window->callbacks.focus)
48         window->callbacks.focus((GLFWwindow*) window, focused);
49
50     if (!focused)
51     {
52         int key, button;
53
54         for (key = 0;  key <= GLFW_KEY_LAST;  key++)
55         {
56             if (window->keys[key] == GLFW_PRESS)
57             {
58                 const int scancode = _glfwPlatformGetKeyScancode(key);
59                 _glfwInputKey(window, key, scancode, GLFW_RELEASE, 0);
60             }
61         }
62
63         for (button = 0;  button <= GLFW_MOUSE_BUTTON_LAST;  button++)
64         {
65             if (window->mouseButtons[button] == GLFW_PRESS)
66                 _glfwInputMouseClick(window, button, GLFW_RELEASE, 0);
67         }
68     }
69 }
70
71 // Notifies shared code that a window has moved
72 // The position is specified in content area relative screen coordinates
73 //
74 void _glfwInputWindowPos(_GLFWwindow* window, int x, int y)
75 {
76     if (window->callbacks.pos)
77         window->callbacks.pos((GLFWwindow*) window, x, y);
78 }
79
80 // Notifies shared code that a window has been resized
81 // The size is specified in screen coordinates
82 //
83 void _glfwInputWindowSize(_GLFWwindow* window, int width, int height)
84 {
85     if (window->callbacks.size)
86         window->callbacks.size((GLFWwindow*) window, width, height);
87 }
88
89 // Notifies shared code that a window has been iconified or restored
90 //
91 void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified)
92 {
93     if (window->callbacks.iconify)
94         window->callbacks.iconify((GLFWwindow*) window, iconified);
95 }
96
97 // Notifies shared code that a window has been maximized or restored
98 //
99 void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized)
100 {
101     if (window->callbacks.maximize)
102         window->callbacks.maximize((GLFWwindow*) window, maximized);
103 }
104
105 // Notifies shared code that a window framebuffer has been resized
106 // The size is specified in pixels
107 //
108 void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height)
109 {
110     if (window->callbacks.fbsize)
111         window->callbacks.fbsize((GLFWwindow*) window, width, height);
112 }
113
114 // Notifies shared code that a window content scale has changed
115 // The scale is specified as the ratio between the current and default DPI
116 //
117 void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale)
118 {
119     if (window->callbacks.scale)
120         window->callbacks.scale((GLFWwindow*) window, xscale, yscale);
121 }
122
123 // Notifies shared code that the window contents needs updating
124 //
125 void _glfwInputWindowDamage(_GLFWwindow* window)
126 {
127     if (window->callbacks.refresh)
128         window->callbacks.refresh((GLFWwindow*) window);
129 }
130
131 // Notifies shared code that the user wishes to close a window
132 //
133 void _glfwInputWindowCloseRequest(_GLFWwindow* window)
134 {
135     window->shouldClose = GLFW_TRUE;
136
137     if (window->callbacks.close)
138         window->callbacks.close((GLFWwindow*) window);
139 }
140
141 // Notifies shared code that a window has changed its desired monitor
142 //
143 void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor)
144 {
145     window->monitor = monitor;
146 }
147
148 //////////////////////////////////////////////////////////////////////////
149 //////                        GLFW public API                       //////
150 //////////////////////////////////////////////////////////////////////////
151
152 GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
153                                      const char* title,
154                                      GLFWmonitor* monitor,
155                                      GLFWwindow* share)
156 {
157     _GLFWfbconfig fbconfig;
158     _GLFWctxconfig ctxconfig;
159     _GLFWwndconfig wndconfig;
160     _GLFWwindow* window;
161
162     assert(title != NULL);
163     assert(width >= 0);
164     assert(height >= 0);
165
166     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
167
168     if (width <= 0 || height <= 0)
169     {
170         _glfwInputError(GLFW_INVALID_VALUE,
171                         "Invalid window size %ix%i",
172                         width, height);
173
174         return NULL;
175     }
176
177     fbconfig  = _glfw.hints.framebuffer;
178     ctxconfig = _glfw.hints.context;
179     wndconfig = _glfw.hints.window;
180
181     wndconfig.width   = width;
182     wndconfig.height  = height;
183     wndconfig.title   = title;
184     ctxconfig.share   = (_GLFWwindow*) share;
185
186     if (!_glfwIsValidContextConfig(&ctxconfig))
187         return NULL;
188
189     window = calloc(1, sizeof(_GLFWwindow));
190     window->next = _glfw.windowListHead;
191     _glfw.windowListHead = window;
192
193     window->videoMode.width       = width;
194     window->videoMode.height      = height;
195     window->videoMode.redBits     = fbconfig.redBits;
196     window->videoMode.greenBits   = fbconfig.greenBits;
197     window->videoMode.blueBits    = fbconfig.blueBits;
198     window->videoMode.refreshRate = _glfw.hints.refreshRate;
199
200     window->monitor          = (_GLFWmonitor*) monitor;
201     window->resizable        = wndconfig.resizable;
202     window->decorated        = wndconfig.decorated;
203     window->autoIconify      = wndconfig.autoIconify;
204     window->floating         = wndconfig.floating;
205     window->focusOnShow      = wndconfig.focusOnShow;
206     window->mousePassthrough = wndconfig.mousePassthrough;
207     window->cursorMode       = GLFW_CURSOR_NORMAL;
208
209     window->minwidth    = GLFW_DONT_CARE;
210     window->minheight   = GLFW_DONT_CARE;
211     window->maxwidth    = GLFW_DONT_CARE;
212     window->maxheight   = GLFW_DONT_CARE;
213     window->numer       = GLFW_DONT_CARE;
214     window->denom       = GLFW_DONT_CARE;
215
216     // Open the actual window and create its context
217     if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig))
218     {
219         glfwDestroyWindow((GLFWwindow*) window);
220         return NULL;
221     }
222
223     if (ctxconfig.client != GLFW_NO_API)
224     {
225         if (!_glfwRefreshContextAttribs(window, &ctxconfig))
226         {
227             glfwDestroyWindow((GLFWwindow*) window);
228             return NULL;
229         }
230     }
231
232     if (wndconfig.mousePassthrough)
233         _glfwPlatformSetWindowMousePassthrough(window, GLFW_TRUE);
234
235     if (window->monitor)
236     {
237         if (wndconfig.centerCursor)
238             _glfwCenterCursorInContentArea(window);
239     }
240     else
241     {
242         if (wndconfig.visible)
243         {
244             _glfwPlatformShowWindow(window);
245             if (wndconfig.focused)
246                 _glfwPlatformFocusWindow(window);
247         }
248     }
249
250     return (GLFWwindow*) window;
251 }
252
253 void glfwDefaultWindowHints(void)
254 {
255     _GLFW_REQUIRE_INIT();
256
257     // The default is OpenGL with minimum version 1.0
258     memset(&_glfw.hints.context, 0, sizeof(_glfw.hints.context));
259     _glfw.hints.context.client = GLFW_OPENGL_API;
260     _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API;
261     _glfw.hints.context.major  = 1;
262     _glfw.hints.context.minor  = 0;
263
264     // The default is a focused, visible, resizable window with decorations
265     memset(&_glfw.hints.window, 0, sizeof(_glfw.hints.window));
266     _glfw.hints.window.resizable    = GLFW_TRUE;
267     _glfw.hints.window.visible      = GLFW_TRUE;
268     _glfw.hints.window.decorated    = GLFW_TRUE;
269     _glfw.hints.window.focused      = GLFW_TRUE;
270     _glfw.hints.window.autoIconify  = GLFW_TRUE;
271     _glfw.hints.window.centerCursor = GLFW_TRUE;
272     _glfw.hints.window.focusOnShow  = GLFW_TRUE;
273
274     // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil,
275     // double buffered
276     memset(&_glfw.hints.framebuffer, 0, sizeof(_glfw.hints.framebuffer));
277     _glfw.hints.framebuffer.redBits      = 8;
278     _glfw.hints.framebuffer.greenBits    = 8;
279     _glfw.hints.framebuffer.blueBits     = 8;
280     _glfw.hints.framebuffer.alphaBits    = 8;
281     _glfw.hints.framebuffer.depthBits    = 24;
282     _glfw.hints.framebuffer.stencilBits  = 8;
283     _glfw.hints.framebuffer.doublebuffer = GLFW_TRUE;
284
285     // The default is to select the highest available refresh rate
286     _glfw.hints.refreshRate = GLFW_DONT_CARE;
287
288     // The default is to use full Retina resolution framebuffers
289     _glfw.hints.window.ns.retina = GLFW_TRUE;
290 }
291
292 GLFWAPI void glfwWindowHint(int hint, int value)
293 {
294     _GLFW_REQUIRE_INIT();
295
296     switch (hint)
297     {
298         case GLFW_RED_BITS:
299             _glfw.hints.framebuffer.redBits = value;
300             return;
301         case GLFW_GREEN_BITS:
302             _glfw.hints.framebuffer.greenBits = value;
303             return;
304         case GLFW_BLUE_BITS:
305             _glfw.hints.framebuffer.blueBits = value;
306             return;
307         case GLFW_ALPHA_BITS:
308             _glfw.hints.framebuffer.alphaBits = value;
309             return;
310         case GLFW_DEPTH_BITS:
311             _glfw.hints.framebuffer.depthBits = value;
312             return;
313         case GLFW_STENCIL_BITS:
314             _glfw.hints.framebuffer.stencilBits = value;
315             return;
316         case GLFW_ACCUM_RED_BITS:
317             _glfw.hints.framebuffer.accumRedBits = value;
318             return;
319         case GLFW_ACCUM_GREEN_BITS:
320             _glfw.hints.framebuffer.accumGreenBits = value;
321             return;
322         case GLFW_ACCUM_BLUE_BITS:
323             _glfw.hints.framebuffer.accumBlueBits = value;
324             return;
325         case GLFW_ACCUM_ALPHA_BITS:
326             _glfw.hints.framebuffer.accumAlphaBits = value;
327             return;
328         case GLFW_AUX_BUFFERS:
329             _glfw.hints.framebuffer.auxBuffers = value;
330             return;
331         case GLFW_STEREO:
332             _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE;
333             return;
334         case GLFW_DOUBLEBUFFER:
335             _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE;
336             return;
337         case GLFW_TRANSPARENT_FRAMEBUFFER:
338             _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE;
339             return;
340         case GLFW_SAMPLES:
341             _glfw.hints.framebuffer.samples = value;
342             return;
343         case GLFW_SRGB_CAPABLE:
344             _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE;
345             return;
346         case GLFW_RESIZABLE:
347             _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE;
348             return;
349         case GLFW_DECORATED:
350             _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE;
351             return;
352         case GLFW_FOCUSED:
353             _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE;
354             return;
355         case GLFW_AUTO_ICONIFY:
356             _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE;
357             return;
358         case GLFW_FLOATING:
359             _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE;
360             return;
361         case GLFW_MAXIMIZED:
362             _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE;
363             return;
364         case GLFW_VISIBLE:
365             _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE;
366             return;
367         case GLFW_COCOA_RETINA_FRAMEBUFFER:
368             _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE;
369             return;
370         case GLFW_WIN32_KEYBOARD_MENU:
371             _glfw.hints.window.win32.keymenu = value ? GLFW_TRUE : GLFW_FALSE;
372             return;
373         case GLFW_COCOA_GRAPHICS_SWITCHING:
374             _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
375             return;
376         case GLFW_SCALE_TO_MONITOR:
377             _glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE;
378             return;
379         case GLFW_CENTER_CURSOR:
380             _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE;
381             return;
382         case GLFW_FOCUS_ON_SHOW:
383             _glfw.hints.window.focusOnShow = value ? GLFW_TRUE : GLFW_FALSE;
384             return;
385         case GLFW_MOUSE_PASSTHROUGH:
386             _glfw.hints.window.mousePassthrough = value ? GLFW_TRUE : GLFW_FALSE;
387             return;
388         case GLFW_CLIENT_API:
389             _glfw.hints.context.client = value;
390             return;
391         case GLFW_CONTEXT_CREATION_API:
392             _glfw.hints.context.source = value;
393             return;
394         case GLFW_CONTEXT_VERSION_MAJOR:
395             _glfw.hints.context.major = value;
396             return;
397         case GLFW_CONTEXT_VERSION_MINOR:
398             _glfw.hints.context.minor = value;
399             return;
400         case GLFW_CONTEXT_ROBUSTNESS:
401             _glfw.hints.context.robustness = value;
402             return;
403         case GLFW_OPENGL_FORWARD_COMPAT:
404             _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE;
405             return;
406         case GLFW_CONTEXT_DEBUG:
407             _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE;
408             return;
409         case GLFW_CONTEXT_NO_ERROR:
410             _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE;
411             return;
412         case GLFW_OPENGL_PROFILE:
413             _glfw.hints.context.profile = value;
414             return;
415         case GLFW_CONTEXT_RELEASE_BEHAVIOR:
416             _glfw.hints.context.release = value;
417             return;
418         case GLFW_REFRESH_RATE:
419             _glfw.hints.refreshRate = value;
420             return;
421     }
422
423     _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint);
424 }
425
426 GLFWAPI void glfwWindowHintString(int hint, const char* value)
427 {
428     assert(value != NULL);
429
430     _GLFW_REQUIRE_INIT();
431
432     switch (hint)
433     {
434         case GLFW_COCOA_FRAME_NAME:
435             strncpy(_glfw.hints.window.ns.frameName, value,
436                     sizeof(_glfw.hints.window.ns.frameName) - 1);
437             return;
438         case GLFW_X11_CLASS_NAME:
439             strncpy(_glfw.hints.window.x11.className, value,
440                     sizeof(_glfw.hints.window.x11.className) - 1);
441             return;
442         case GLFW_X11_INSTANCE_NAME:
443             strncpy(_glfw.hints.window.x11.instanceName, value,
444                     sizeof(_glfw.hints.window.x11.instanceName) - 1);
445             return;
446     }
447
448     _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint);
449 }
450
451 GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
452 {
453     _GLFWwindow* window = (_GLFWwindow*) handle;
454
455     _GLFW_REQUIRE_INIT();
456
457     // Allow closing of NULL (to match the behavior of free)
458     if (window == NULL)
459         return;
460
461     // Clear all callbacks to avoid exposing a half torn-down window object
462     memset(&window->callbacks, 0, sizeof(window->callbacks));
463
464     // The window's context must not be current on another thread when the
465     // window is destroyed
466     if (window == _glfwPlatformGetTls(&_glfw.contextSlot))
467         glfwMakeContextCurrent(NULL);
468
469     _glfwPlatformDestroyWindow(window);
470
471     // Unlink window from global linked list
472     {
473         _GLFWwindow** prev = &_glfw.windowListHead;
474
475         while (*prev != window)
476             prev = &((*prev)->next);
477
478         *prev = window->next;
479     }
480
481     free(window);
482 }
483
484 GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle)
485 {
486     _GLFWwindow* window = (_GLFWwindow*) handle;
487     assert(window != NULL);
488
489     _GLFW_REQUIRE_INIT_OR_RETURN(0);
490     return window->shouldClose;
491 }
492
493 GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value)
494 {
495     _GLFWwindow* window = (_GLFWwindow*) handle;
496     assert(window != NULL);
497
498     _GLFW_REQUIRE_INIT();
499     window->shouldClose = value;
500 }
501
502 GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title)
503 {
504     _GLFWwindow* window = (_GLFWwindow*) handle;
505     assert(window != NULL);
506     assert(title != NULL);
507
508     _GLFW_REQUIRE_INIT();
509     _glfwPlatformSetWindowTitle(window, title);
510 }
511
512 GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle,
513                                int count, const GLFWimage* images)
514 {
515     _GLFWwindow* window = (_GLFWwindow*) handle;
516     assert(window != NULL);
517     assert(count >= 0);
518     assert(count == 0 || images != NULL);
519
520     _GLFW_REQUIRE_INIT();
521     _glfwPlatformSetWindowIcon(window, count, images);
522 }
523
524 GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos)
525 {
526     _GLFWwindow* window = (_GLFWwindow*) handle;
527     assert(window != NULL);
528
529     if (xpos)
530         *xpos = 0;
531     if (ypos)
532         *ypos = 0;
533
534     _GLFW_REQUIRE_INIT();
535     _glfwPlatformGetWindowPos(window, xpos, ypos);
536 }
537
538 GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos)
539 {
540     _GLFWwindow* window = (_GLFWwindow*) handle;
541     assert(window != NULL);
542
543     _GLFW_REQUIRE_INIT();
544
545     if (window->monitor)
546         return;
547
548     _glfwPlatformSetWindowPos(window, xpos, ypos);
549 }
550
551 GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height)
552 {
553     _GLFWwindow* window = (_GLFWwindow*) handle;
554     assert(window != NULL);
555
556     if (width)
557         *width = 0;
558     if (height)
559         *height = 0;
560
561     _GLFW_REQUIRE_INIT();
562     _glfwPlatformGetWindowSize(window, width, height);
563 }
564
565 GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height)
566 {
567     _GLFWwindow* window = (_GLFWwindow*) handle;
568     assert(window != NULL);
569     assert(width >= 0);
570     assert(height >= 0);
571
572     _GLFW_REQUIRE_INIT();
573
574     window->videoMode.width  = width;
575     window->videoMode.height = height;
576
577     _glfwPlatformSetWindowSize(window, width, height);
578 }
579
580 GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle,
581                                      int minwidth, int minheight,
582                                      int maxwidth, int maxheight)
583 {
584     _GLFWwindow* window = (_GLFWwindow*) handle;
585     assert(window != NULL);
586
587     _GLFW_REQUIRE_INIT();
588
589     if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE)
590     {
591         if (minwidth < 0 || minheight < 0)
592         {
593             _glfwInputError(GLFW_INVALID_VALUE,
594                             "Invalid window minimum size %ix%i",
595                             minwidth, minheight);
596             return;
597         }
598     }
599
600     if (maxwidth != GLFW_DONT_CARE && maxheight != GLFW_DONT_CARE)
601     {
602         if (maxwidth < 0 || maxheight < 0 ||
603             maxwidth < minwidth || maxheight < minheight)
604         {
605             _glfwInputError(GLFW_INVALID_VALUE,
606                             "Invalid window maximum size %ix%i",
607                             maxwidth, maxheight);
608             return;
609         }
610     }
611
612     window->minwidth  = minwidth;
613     window->minheight = minheight;
614     window->maxwidth  = maxwidth;
615     window->maxheight = maxheight;
616
617     if (window->monitor || !window->resizable)
618         return;
619
620     _glfwPlatformSetWindowSizeLimits(window,
621                                      minwidth, minheight,
622                                      maxwidth, maxheight);
623 }
624
625 GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom)
626 {
627     _GLFWwindow* window = (_GLFWwindow*) handle;
628     assert(window != NULL);
629     assert(numer != 0);
630     assert(denom != 0);
631
632     _GLFW_REQUIRE_INIT();
633
634     if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE)
635     {
636         if (numer <= 0 || denom <= 0)
637         {
638             _glfwInputError(GLFW_INVALID_VALUE,
639                             "Invalid window aspect ratio %i:%i",
640                             numer, denom);
641             return;
642         }
643     }
644
645     window->numer = numer;
646     window->denom = denom;
647
648     if (window->monitor || !window->resizable)
649         return;
650
651     _glfwPlatformSetWindowAspectRatio(window, numer, denom);
652 }
653
654 GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height)
655 {
656     _GLFWwindow* window = (_GLFWwindow*) handle;
657     assert(window != NULL);
658
659     if (width)
660         *width = 0;
661     if (height)
662         *height = 0;
663
664     _GLFW_REQUIRE_INIT();
665     _glfwPlatformGetFramebufferSize(window, width, height);
666 }
667
668 GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle,
669                                     int* left, int* top,
670                                     int* right, int* bottom)
671 {
672     _GLFWwindow* window = (_GLFWwindow*) handle;
673     assert(window != NULL);
674
675     if (left)
676         *left = 0;
677     if (top)
678         *top = 0;
679     if (right)
680         *right = 0;
681     if (bottom)
682         *bottom = 0;
683
684     _GLFW_REQUIRE_INIT();
685     _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom);
686 }
687
688 GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle,
689                                        float* xscale, float* yscale)
690 {
691     _GLFWwindow* window = (_GLFWwindow*) handle;
692     assert(window != NULL);
693
694     if (xscale)
695         *xscale = 0.f;
696     if (yscale)
697         *yscale = 0.f;
698
699     _GLFW_REQUIRE_INIT();
700     _glfwPlatformGetWindowContentScale(window, xscale, yscale);
701 }
702
703 GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle)
704 {
705     _GLFWwindow* window = (_GLFWwindow*) handle;
706     assert(window != NULL);
707
708     _GLFW_REQUIRE_INIT_OR_RETURN(1.f);
709     return _glfwPlatformGetWindowOpacity(window);
710 }
711
712 GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity)
713 {
714     _GLFWwindow* window = (_GLFWwindow*) handle;
715     assert(window != NULL);
716     assert(opacity == opacity);
717     assert(opacity >= 0.f);
718     assert(opacity <= 1.f);
719
720     _GLFW_REQUIRE_INIT();
721
722     if (opacity != opacity || opacity < 0.f || opacity > 1.f)
723     {
724         _glfwInputError(GLFW_INVALID_VALUE, "Invalid window opacity %f", opacity);
725         return;
726     }
727
728     _glfwPlatformSetWindowOpacity(window, opacity);
729 }
730
731 GLFWAPI void glfwIconifyWindow(GLFWwindow* handle)
732 {
733     _GLFWwindow* window = (_GLFWwindow*) handle;
734     assert(window != NULL);
735
736     _GLFW_REQUIRE_INIT();
737     _glfwPlatformIconifyWindow(window);
738 }
739
740 GLFWAPI void glfwRestoreWindow(GLFWwindow* handle)
741 {
742     _GLFWwindow* window = (_GLFWwindow*) handle;
743     assert(window != NULL);
744
745     _GLFW_REQUIRE_INIT();
746     _glfwPlatformRestoreWindow(window);
747 }
748
749 GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle)
750 {
751     _GLFWwindow* window = (_GLFWwindow*) handle;
752     assert(window != NULL);
753
754     _GLFW_REQUIRE_INIT();
755
756     if (window->monitor)
757         return;
758
759     _glfwPlatformMaximizeWindow(window);
760 }
761
762 GLFWAPI void glfwShowWindow(GLFWwindow* handle)
763 {
764     _GLFWwindow* window = (_GLFWwindow*) handle;
765     assert(window != NULL);
766
767     _GLFW_REQUIRE_INIT();
768
769     if (window->monitor)
770         return;
771
772     _glfwPlatformShowWindow(window);
773
774     if (window->focusOnShow)
775         _glfwPlatformFocusWindow(window);
776 }
777
778 GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle)
779 {
780     _GLFWwindow* window = (_GLFWwindow*) handle;
781     assert(window != NULL);
782
783     _GLFW_REQUIRE_INIT();
784
785     _glfwPlatformRequestWindowAttention(window);
786 }
787
788 GLFWAPI void glfwHideWindow(GLFWwindow* handle)
789 {
790     _GLFWwindow* window = (_GLFWwindow*) handle;
791     assert(window != NULL);
792
793     _GLFW_REQUIRE_INIT();
794
795     if (window->monitor)
796         return;
797
798     _glfwPlatformHideWindow(window);
799 }
800
801 GLFWAPI void glfwFocusWindow(GLFWwindow* handle)
802 {
803     _GLFWwindow* window = (_GLFWwindow*) handle;
804     assert(window != NULL);
805
806     _GLFW_REQUIRE_INIT();
807
808     _glfwPlatformFocusWindow(window);
809 }
810
811 GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
812 {
813     _GLFWwindow* window = (_GLFWwindow*) handle;
814     assert(window != NULL);
815
816     _GLFW_REQUIRE_INIT_OR_RETURN(0);
817
818     switch (attrib)
819     {
820         case GLFW_FOCUSED:
821             return _glfwPlatformWindowFocused(window);
822         case GLFW_ICONIFIED:
823             return _glfwPlatformWindowIconified(window);
824         case GLFW_VISIBLE:
825             return _glfwPlatformWindowVisible(window);
826         case GLFW_MAXIMIZED:
827             return _glfwPlatformWindowMaximized(window);
828         case GLFW_HOVERED:
829             return _glfwPlatformWindowHovered(window);
830         case GLFW_FOCUS_ON_SHOW:
831             return window->focusOnShow;
832         case GLFW_MOUSE_PASSTHROUGH:
833             return window->mousePassthrough;
834         case GLFW_TRANSPARENT_FRAMEBUFFER:
835             return _glfwPlatformFramebufferTransparent(window);
836         case GLFW_RESIZABLE:
837             return window->resizable;
838         case GLFW_DECORATED:
839             return window->decorated;
840         case GLFW_FLOATING:
841             return window->floating;
842         case GLFW_AUTO_ICONIFY:
843             return window->autoIconify;
844         case GLFW_CLIENT_API:
845             return window->context.client;
846         case GLFW_CONTEXT_CREATION_API:
847             return window->context.source;
848         case GLFW_CONTEXT_VERSION_MAJOR:
849             return window->context.major;
850         case GLFW_CONTEXT_VERSION_MINOR:
851             return window->context.minor;
852         case GLFW_CONTEXT_REVISION:
853             return window->context.revision;
854         case GLFW_CONTEXT_ROBUSTNESS:
855             return window->context.robustness;
856         case GLFW_OPENGL_FORWARD_COMPAT:
857             return window->context.forward;
858         case GLFW_CONTEXT_DEBUG:
859             return window->context.debug;
860         case GLFW_OPENGL_PROFILE:
861             return window->context.profile;
862         case GLFW_CONTEXT_RELEASE_BEHAVIOR:
863             return window->context.release;
864         case GLFW_CONTEXT_NO_ERROR:
865             return window->context.noerror;
866     }
867
868     _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib);
869     return 0;
870 }
871
872 GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value)
873 {
874     _GLFWwindow* window = (_GLFWwindow*) handle;
875     assert(window != NULL);
876
877     _GLFW_REQUIRE_INIT();
878
879     value = value ? GLFW_TRUE : GLFW_FALSE;
880
881     if (attrib == GLFW_AUTO_ICONIFY)
882         window->autoIconify = value;
883     else if (attrib == GLFW_RESIZABLE)
884     {
885         if (window->resizable == value)
886             return;
887
888         window->resizable = value;
889         if (!window->monitor)
890             _glfwPlatformSetWindowResizable(window, value);
891     }
892     else if (attrib == GLFW_DECORATED)
893     {
894         if (window->decorated == value)
895             return;
896
897         window->decorated = value;
898         if (!window->monitor)
899             _glfwPlatformSetWindowDecorated(window, value);
900     }
901     else if (attrib == GLFW_FLOATING)
902     {
903         if (window->floating == value)
904             return;
905
906         window->floating = value;
907         if (!window->monitor)
908             _glfwPlatformSetWindowFloating(window, value);
909     }
910     else if (attrib == GLFW_FOCUS_ON_SHOW)
911         window->focusOnShow = value;
912     else if (attrib == GLFW_MOUSE_PASSTHROUGH)
913     {
914         if (window->mousePassthrough == value)
915             return;
916
917         window->mousePassthrough = value;
918         _glfwPlatformSetWindowMousePassthrough(window, value);
919     }
920     else
921         _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib);
922 }
923
924 GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle)
925 {
926     _GLFWwindow* window = (_GLFWwindow*) handle;
927     assert(window != NULL);
928
929     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
930     return (GLFWmonitor*) window->monitor;
931 }
932
933 GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh,
934                                   GLFWmonitor* mh,
935                                   int xpos, int ypos,
936                                   int width, int height,
937                                   int refreshRate)
938 {
939     _GLFWwindow* window = (_GLFWwindow*) wh;
940     _GLFWmonitor* monitor = (_GLFWmonitor*) mh;
941     assert(window != NULL);
942     assert(width >= 0);
943     assert(height >= 0);
944
945     _GLFW_REQUIRE_INIT();
946
947     if (width <= 0 || height <= 0)
948     {
949         _glfwInputError(GLFW_INVALID_VALUE,
950                         "Invalid window size %ix%i",
951                         width, height);
952         return;
953     }
954
955     if (refreshRate < 0 && refreshRate != GLFW_DONT_CARE)
956     {
957         _glfwInputError(GLFW_INVALID_VALUE,
958                         "Invalid refresh rate %i",
959                         refreshRate);
960         return;
961     }
962
963     window->videoMode.width       = width;
964     window->videoMode.height      = height;
965     window->videoMode.refreshRate = refreshRate;
966
967     _glfwPlatformSetWindowMonitor(window, monitor,
968                                   xpos, ypos, width, height,
969                                   refreshRate);
970 }
971
972 GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer)
973 {
974     _GLFWwindow* window = (_GLFWwindow*) handle;
975     assert(window != NULL);
976
977     _GLFW_REQUIRE_INIT();
978     window->userPointer = pointer;
979 }
980
981 GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle)
982 {
983     _GLFWwindow* window = (_GLFWwindow*) handle;
984     assert(window != NULL);
985
986     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
987     return window->userPointer;
988 }
989
990 GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle,
991                                                   GLFWwindowposfun cbfun)
992 {
993     _GLFWwindow* window = (_GLFWwindow*) handle;
994     assert(window != NULL);
995
996     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
997     _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun);
998     return cbfun;
999 }
1000
1001 GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle,
1002                                                     GLFWwindowsizefun cbfun)
1003 {
1004     _GLFWwindow* window = (_GLFWwindow*) handle;
1005     assert(window != NULL);
1006
1007     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1008     _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun);
1009     return cbfun;
1010 }
1011
1012 GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle,
1013                                                       GLFWwindowclosefun cbfun)
1014 {
1015     _GLFWwindow* window = (_GLFWwindow*) handle;
1016     assert(window != NULL);
1017
1018     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1019     _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun);
1020     return cbfun;
1021 }
1022
1023 GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle,
1024                                                           GLFWwindowrefreshfun cbfun)
1025 {
1026     _GLFWwindow* window = (_GLFWwindow*) handle;
1027     assert(window != NULL);
1028
1029     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1030     _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun);
1031     return cbfun;
1032 }
1033
1034 GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle,
1035                                                       GLFWwindowfocusfun cbfun)
1036 {
1037     _GLFWwindow* window = (_GLFWwindow*) handle;
1038     assert(window != NULL);
1039
1040     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1041     _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun);
1042     return cbfun;
1043 }
1044
1045 GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle,
1046                                                           GLFWwindowiconifyfun cbfun)
1047 {
1048     _GLFWwindow* window = (_GLFWwindow*) handle;
1049     assert(window != NULL);
1050
1051     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1052     _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun);
1053     return cbfun;
1054 }
1055
1056 GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle,
1057                                                             GLFWwindowmaximizefun cbfun)
1058 {
1059     _GLFWwindow* window = (_GLFWwindow*) handle;
1060     assert(window != NULL);
1061
1062     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1063     _GLFW_SWAP_POINTERS(window->callbacks.maximize, cbfun);
1064     return cbfun;
1065 }
1066
1067 GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle,
1068                                                               GLFWframebuffersizefun cbfun)
1069 {
1070     _GLFWwindow* window = (_GLFWwindow*) handle;
1071     assert(window != NULL);
1072
1073     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1074     _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun);
1075     return cbfun;
1076 }
1077
1078 GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* handle,
1079                                                                     GLFWwindowcontentscalefun cbfun)
1080 {
1081     _GLFWwindow* window = (_GLFWwindow*) handle;
1082     assert(window != NULL);
1083
1084     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1085     _GLFW_SWAP_POINTERS(window->callbacks.scale, cbfun);
1086     return cbfun;
1087 }
1088
1089 GLFWAPI void glfwPollEvents(void)
1090 {
1091     _GLFW_REQUIRE_INIT();
1092     _glfwPlatformPollEvents();
1093 }
1094
1095 GLFWAPI void glfwWaitEvents(void)
1096 {
1097     _GLFW_REQUIRE_INIT();
1098     _glfwPlatformWaitEvents();
1099 }
1100
1101 GLFWAPI void glfwWaitEventsTimeout(double timeout)
1102 {
1103     _GLFW_REQUIRE_INIT();
1104     assert(timeout == timeout);
1105     assert(timeout >= 0.0);
1106     assert(timeout <= DBL_MAX);
1107
1108     if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX)
1109     {
1110         _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout);
1111         return;
1112     }
1113
1114     _glfwPlatformWaitEventsTimeout(timeout);
1115 }
1116
1117 GLFWAPI void glfwPostEmptyEvent(void)
1118 {
1119     _GLFW_REQUIRE_INIT();
1120     _glfwPlatformPostEmptyEvent();
1121 }
1122