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