1 | //======================================================================== |
2 | // GLFW 3.4 - www.glfw.org |
3 | //------------------------------------------------------------------------ |
4 | // Copyright (c) 2002-2006 Marcus Geelnard |
5 | // Copyright (c) 2006-2019 Camilla Löwy <[email protected]> |
6 | // Copyright (c) 2012 Torsten Walluhn <[email protected]> |
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 = _glfw.platform.getKeyScancode(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 = _glfw_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->doublebuffer = fbconfig.doublebuffer; |
210 | |
211 | window->minwidth = GLFW_DONT_CARE; |
212 | window->minheight = GLFW_DONT_CARE; |
213 | window->maxwidth = GLFW_DONT_CARE; |
214 | window->maxheight = GLFW_DONT_CARE; |
215 | window->numer = GLFW_DONT_CARE; |
216 | window->denom = GLFW_DONT_CARE; |
217 | |
218 | // Open the actual window and create its context |
219 | if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig)) |
220 | { |
221 | glfwDestroyWindow((GLFWwindow*) window); |
222 | return NULL; |
223 | } |
224 | |
225 | if (ctxconfig.client != GLFW_NO_API) |
226 | { |
227 | if (!_glfwRefreshContextAttribs(window, &ctxconfig)) |
228 | { |
229 | glfwDestroyWindow((GLFWwindow*) window); |
230 | return NULL; |
231 | } |
232 | } |
233 | |
234 | if (wndconfig.mousePassthrough) |
235 | _glfw.platform.setWindowMousePassthrough(window, GLFW_TRUE); |
236 | |
237 | if (window->monitor) |
238 | { |
239 | if (wndconfig.centerCursor) |
240 | _glfwCenterCursorInContentArea(window); |
241 | } |
242 | else |
243 | { |
244 | if (wndconfig.visible) |
245 | { |
246 | _glfw.platform.showWindow(window); |
247 | if (wndconfig.focused) |
248 | _glfw.platform.focusWindow(window); |
249 | } |
250 | } |
251 | |
252 | return (GLFWwindow*) window; |
253 | } |
254 | |
255 | void glfwDefaultWindowHints(void) |
256 | { |
257 | _GLFW_REQUIRE_INIT(); |
258 | |
259 | // The default is OpenGL with minimum version 1.0 |
260 | memset(&_glfw.hints.context, 0, sizeof(_glfw.hints.context)); |
261 | _glfw.hints.context.client = GLFW_OPENGL_API; |
262 | _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API; |
263 | _glfw.hints.context.major = 1; |
264 | _glfw.hints.context.minor = 0; |
265 | |
266 | // The default is a focused, visible, resizable window with decorations |
267 | memset(&_glfw.hints.window, 0, sizeof(_glfw.hints.window)); |
268 | _glfw.hints.window.resizable = GLFW_TRUE; |
269 | _glfw.hints.window.visible = GLFW_TRUE; |
270 | _glfw.hints.window.decorated = GLFW_TRUE; |
271 | _glfw.hints.window.focused = GLFW_TRUE; |
272 | _glfw.hints.window.autoIconify = GLFW_TRUE; |
273 | _glfw.hints.window.centerCursor = GLFW_TRUE; |
274 | _glfw.hints.window.focusOnShow = GLFW_TRUE; |
275 | |
276 | // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, |
277 | // double buffered |
278 | memset(&_glfw.hints.framebuffer, 0, sizeof(_glfw.hints.framebuffer)); |
279 | _glfw.hints.framebuffer.redBits = 8; |
280 | _glfw.hints.framebuffer.greenBits = 8; |
281 | _glfw.hints.framebuffer.blueBits = 8; |
282 | _glfw.hints.framebuffer.alphaBits = 8; |
283 | _glfw.hints.framebuffer.depthBits = 24; |
284 | _glfw.hints.framebuffer.stencilBits = 8; |
285 | _glfw.hints.framebuffer.doublebuffer = GLFW_TRUE; |
286 | |
287 | // The default is to select the highest available refresh rate |
288 | _glfw.hints.refreshRate = GLFW_DONT_CARE; |
289 | |
290 | // The default is to use full Retina resolution framebuffers |
291 | _glfw.hints.window.ns.retina = GLFW_TRUE; |
292 | } |
293 | |
294 | GLFWAPI void glfwWindowHint(int hint, int value) |
295 | { |
296 | _GLFW_REQUIRE_INIT(); |
297 | |
298 | switch (hint) |
299 | { |
300 | case GLFW_RED_BITS: |
301 | _glfw.hints.framebuffer.redBits = value; |
302 | return; |
303 | case GLFW_GREEN_BITS: |
304 | _glfw.hints.framebuffer.greenBits = value; |
305 | return; |
306 | case GLFW_BLUE_BITS: |
307 | _glfw.hints.framebuffer.blueBits = value; |
308 | return; |
309 | case GLFW_ALPHA_BITS: |
310 | _glfw.hints.framebuffer.alphaBits = value; |
311 | return; |
312 | case GLFW_DEPTH_BITS: |
313 | _glfw.hints.framebuffer.depthBits = value; |
314 | return; |
315 | case GLFW_STENCIL_BITS: |
316 | _glfw.hints.framebuffer.stencilBits = value; |
317 | return; |
318 | case GLFW_ACCUM_RED_BITS: |
319 | _glfw.hints.framebuffer.accumRedBits = value; |
320 | return; |
321 | case GLFW_ACCUM_GREEN_BITS: |
322 | _glfw.hints.framebuffer.accumGreenBits = value; |
323 | return; |
324 | case GLFW_ACCUM_BLUE_BITS: |
325 | _glfw.hints.framebuffer.accumBlueBits = value; |
326 | return; |
327 | case GLFW_ACCUM_ALPHA_BITS: |
328 | _glfw.hints.framebuffer.accumAlphaBits = value; |
329 | return; |
330 | case GLFW_AUX_BUFFERS: |
331 | _glfw.hints.framebuffer.auxBuffers = value; |
332 | return; |
333 | case GLFW_STEREO: |
334 | _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE; |
335 | return; |
336 | case GLFW_DOUBLEBUFFER: |
337 | _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; |
338 | return; |
339 | case GLFW_TRANSPARENT_FRAMEBUFFER: |
340 | _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE; |
341 | return; |
342 | case GLFW_SAMPLES: |
343 | _glfw.hints.framebuffer.samples = value; |
344 | return; |
345 | case GLFW_SRGB_CAPABLE: |
346 | _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE; |
347 | return; |
348 | case GLFW_RESIZABLE: |
349 | _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE; |
350 | return; |
351 | case GLFW_DECORATED: |
352 | _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; |
353 | return; |
354 | case GLFW_FOCUSED: |
355 | _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; |
356 | return; |
357 | case GLFW_AUTO_ICONIFY: |
358 | _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE; |
359 | return; |
360 | case GLFW_FLOATING: |
361 | _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE; |
362 | return; |
363 | case GLFW_MAXIMIZED: |
364 | _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE; |
365 | return; |
366 | case GLFW_VISIBLE: |
367 | _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; |
368 | return; |
369 | case GLFW_COCOA_RETINA_FRAMEBUFFER: |
370 | _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; |
371 | return; |
372 | case GLFW_WIN32_KEYBOARD_MENU: |
373 | _glfw.hints.window.win32.keymenu = value ? GLFW_TRUE : GLFW_FALSE; |
374 | return; |
375 | case GLFW_COCOA_GRAPHICS_SWITCHING: |
376 | _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; |
377 | return; |
378 | case GLFW_SCALE_TO_MONITOR: |
379 | _glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE; |
380 | return; |
381 | case GLFW_CENTER_CURSOR: |
382 | _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; |
383 | return; |
384 | case GLFW_FOCUS_ON_SHOW: |
385 | _glfw.hints.window.focusOnShow = value ? GLFW_TRUE : GLFW_FALSE; |
386 | return; |
387 | case GLFW_MOUSE_PASSTHROUGH: |
388 | _glfw.hints.window.mousePassthrough = value ? GLFW_TRUE : GLFW_FALSE; |
389 | return; |
390 | case GLFW_CLIENT_API: |
391 | _glfw.hints.context.client = value; |
392 | return; |
393 | case GLFW_CONTEXT_CREATION_API: |
394 | _glfw.hints.context.source = value; |
395 | return; |
396 | case GLFW_CONTEXT_VERSION_MAJOR: |
397 | _glfw.hints.context.major = value; |
398 | return; |
399 | case GLFW_CONTEXT_VERSION_MINOR: |
400 | _glfw.hints.context.minor = value; |
401 | return; |
402 | case GLFW_CONTEXT_ROBUSTNESS: |
403 | _glfw.hints.context.robustness = value; |
404 | return; |
405 | case GLFW_OPENGL_FORWARD_COMPAT: |
406 | _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE; |
407 | return; |
408 | case GLFW_CONTEXT_DEBUG: |
409 | _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE; |
410 | return; |
411 | case GLFW_CONTEXT_NO_ERROR: |
412 | _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE; |
413 | return; |
414 | case GLFW_OPENGL_PROFILE: |
415 | _glfw.hints.context.profile = value; |
416 | return; |
417 | case GLFW_CONTEXT_RELEASE_BEHAVIOR: |
418 | _glfw.hints.context.release = value; |
419 | return; |
420 | case GLFW_REFRESH_RATE: |
421 | _glfw.hints.refreshRate = value; |
422 | return; |
423 | } |
424 | |
425 | _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X" , hint); |
426 | } |
427 | |
428 | GLFWAPI void glfwWindowHintString(int hint, const char* value) |
429 | { |
430 | assert(value != NULL); |
431 | |
432 | _GLFW_REQUIRE_INIT(); |
433 | |
434 | switch (hint) |
435 | { |
436 | case GLFW_COCOA_FRAME_NAME: |
437 | strncpy(_glfw.hints.window.ns.frameName, value, |
438 | sizeof(_glfw.hints.window.ns.frameName) - 1); |
439 | return; |
440 | case GLFW_X11_CLASS_NAME: |
441 | strncpy(_glfw.hints.window.x11.className, value, |
442 | sizeof(_glfw.hints.window.x11.className) - 1); |
443 | return; |
444 | case GLFW_X11_INSTANCE_NAME: |
445 | strncpy(_glfw.hints.window.x11.instanceName, value, |
446 | sizeof(_glfw.hints.window.x11.instanceName) - 1); |
447 | return; |
448 | } |
449 | |
450 | _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X" , hint); |
451 | } |
452 | |
453 | GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) |
454 | { |
455 | _GLFWwindow* window = (_GLFWwindow*) handle; |
456 | |
457 | _GLFW_REQUIRE_INIT(); |
458 | |
459 | // Allow closing of NULL (to match the behavior of free) |
460 | if (window == NULL) |
461 | return; |
462 | |
463 | // Clear all callbacks to avoid exposing a half torn-down window object |
464 | memset(&window->callbacks, 0, sizeof(window->callbacks)); |
465 | |
466 | // The window's context must not be current on another thread when the |
467 | // window is destroyed |
468 | if (window == _glfwPlatformGetTls(&_glfw.contextSlot)) |
469 | glfwMakeContextCurrent(NULL); |
470 | |
471 | _glfw.platform.destroyWindow(window); |
472 | |
473 | // Unlink window from global linked list |
474 | { |
475 | _GLFWwindow** prev = &_glfw.windowListHead; |
476 | |
477 | while (*prev != window) |
478 | prev = &((*prev)->next); |
479 | |
480 | *prev = window->next; |
481 | } |
482 | |
483 | _glfw_free(window); |
484 | } |
485 | |
486 | GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) |
487 | { |
488 | _GLFWwindow* window = (_GLFWwindow*) handle; |
489 | assert(window != NULL); |
490 | |
491 | _GLFW_REQUIRE_INIT_OR_RETURN(0); |
492 | return window->shouldClose; |
493 | } |
494 | |
495 | GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value) |
496 | { |
497 | _GLFWwindow* window = (_GLFWwindow*) handle; |
498 | assert(window != NULL); |
499 | |
500 | _GLFW_REQUIRE_INIT(); |
501 | window->shouldClose = value; |
502 | } |
503 | |
504 | GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) |
505 | { |
506 | _GLFWwindow* window = (_GLFWwindow*) handle; |
507 | assert(window != NULL); |
508 | assert(title != NULL); |
509 | |
510 | _GLFW_REQUIRE_INIT(); |
511 | _glfw.platform.setWindowTitle(window, title); |
512 | } |
513 | |
514 | GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, |
515 | int count, const GLFWimage* images) |
516 | { |
517 | _GLFWwindow* window = (_GLFWwindow*) handle; |
518 | assert(window != NULL); |
519 | assert(count >= 0); |
520 | assert(count == 0 || images != NULL); |
521 | |
522 | _GLFW_REQUIRE_INIT(); |
523 | _glfw.platform.setWindowIcon(window, count, images); |
524 | } |
525 | |
526 | GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) |
527 | { |
528 | _GLFWwindow* window = (_GLFWwindow*) handle; |
529 | assert(window != NULL); |
530 | |
531 | if (xpos) |
532 | *xpos = 0; |
533 | if (ypos) |
534 | *ypos = 0; |
535 | |
536 | _GLFW_REQUIRE_INIT(); |
537 | _glfw.platform.getWindowPos(window, xpos, ypos); |
538 | } |
539 | |
540 | GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) |
541 | { |
542 | _GLFWwindow* window = (_GLFWwindow*) handle; |
543 | assert(window != NULL); |
544 | |
545 | _GLFW_REQUIRE_INIT(); |
546 | |
547 | if (window->monitor) |
548 | return; |
549 | |
550 | _glfw.platform.setWindowPos(window, xpos, ypos); |
551 | } |
552 | |
553 | GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) |
554 | { |
555 | _GLFWwindow* window = (_GLFWwindow*) handle; |
556 | assert(window != NULL); |
557 | |
558 | if (width) |
559 | *width = 0; |
560 | if (height) |
561 | *height = 0; |
562 | |
563 | _GLFW_REQUIRE_INIT(); |
564 | _glfw.platform.getWindowSize(window, width, height); |
565 | } |
566 | |
567 | GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) |
568 | { |
569 | _GLFWwindow* window = (_GLFWwindow*) handle; |
570 | assert(window != NULL); |
571 | assert(width >= 0); |
572 | assert(height >= 0); |
573 | |
574 | _GLFW_REQUIRE_INIT(); |
575 | |
576 | window->videoMode.width = width; |
577 | window->videoMode.height = height; |
578 | |
579 | _glfw.platform.setWindowSize(window, width, height); |
580 | } |
581 | |
582 | GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, |
583 | int minwidth, int minheight, |
584 | int maxwidth, int maxheight) |
585 | { |
586 | _GLFWwindow* window = (_GLFWwindow*) handle; |
587 | assert(window != NULL); |
588 | |
589 | _GLFW_REQUIRE_INIT(); |
590 | |
591 | if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE) |
592 | { |
593 | if (minwidth < 0 || minheight < 0) |
594 | { |
595 | _glfwInputError(GLFW_INVALID_VALUE, |
596 | "Invalid window minimum size %ix%i" , |
597 | minwidth, minheight); |
598 | return; |
599 | } |
600 | } |
601 | |
602 | if (maxwidth != GLFW_DONT_CARE && maxheight != GLFW_DONT_CARE) |
603 | { |
604 | if (maxwidth < 0 || maxheight < 0 || |
605 | maxwidth < minwidth || maxheight < minheight) |
606 | { |
607 | _glfwInputError(GLFW_INVALID_VALUE, |
608 | "Invalid window maximum size %ix%i" , |
609 | maxwidth, maxheight); |
610 | return; |
611 | } |
612 | } |
613 | |
614 | window->minwidth = minwidth; |
615 | window->minheight = minheight; |
616 | window->maxwidth = maxwidth; |
617 | window->maxheight = maxheight; |
618 | |
619 | if (window->monitor || !window->resizable) |
620 | return; |
621 | |
622 | _glfw.platform.setWindowSizeLimits(window, |
623 | minwidth, minheight, |
624 | maxwidth, maxheight); |
625 | } |
626 | |
627 | GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) |
628 | { |
629 | _GLFWwindow* window = (_GLFWwindow*) handle; |
630 | assert(window != NULL); |
631 | assert(numer != 0); |
632 | assert(denom != 0); |
633 | |
634 | _GLFW_REQUIRE_INIT(); |
635 | |
636 | if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE) |
637 | { |
638 | if (numer <= 0 || denom <= 0) |
639 | { |
640 | _glfwInputError(GLFW_INVALID_VALUE, |
641 | "Invalid window aspect ratio %i:%i" , |
642 | numer, denom); |
643 | return; |
644 | } |
645 | } |
646 | |
647 | window->numer = numer; |
648 | window->denom = denom; |
649 | |
650 | if (window->monitor || !window->resizable) |
651 | return; |
652 | |
653 | _glfw.platform.setWindowAspectRatio(window, numer, denom); |
654 | } |
655 | |
656 | GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) |
657 | { |
658 | _GLFWwindow* window = (_GLFWwindow*) handle; |
659 | assert(window != NULL); |
660 | |
661 | if (width) |
662 | *width = 0; |
663 | if (height) |
664 | *height = 0; |
665 | |
666 | _GLFW_REQUIRE_INIT(); |
667 | _glfw.platform.getFramebufferSize(window, width, height); |
668 | } |
669 | |
670 | GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, |
671 | int* left, int* top, |
672 | int* right, int* bottom) |
673 | { |
674 | _GLFWwindow* window = (_GLFWwindow*) handle; |
675 | assert(window != NULL); |
676 | |
677 | if (left) |
678 | *left = 0; |
679 | if (top) |
680 | *top = 0; |
681 | if (right) |
682 | *right = 0; |
683 | if (bottom) |
684 | *bottom = 0; |
685 | |
686 | _GLFW_REQUIRE_INIT(); |
687 | _glfw.platform.getWindowFrameSize(window, left, top, right, bottom); |
688 | } |
689 | |
690 | GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, |
691 | float* xscale, float* yscale) |
692 | { |
693 | _GLFWwindow* window = (_GLFWwindow*) handle; |
694 | assert(window != NULL); |
695 | |
696 | if (xscale) |
697 | *xscale = 0.f; |
698 | if (yscale) |
699 | *yscale = 0.f; |
700 | |
701 | _GLFW_REQUIRE_INIT(); |
702 | _glfw.platform.getWindowContentScale(window, xscale, yscale); |
703 | } |
704 | |
705 | GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) |
706 | { |
707 | _GLFWwindow* window = (_GLFWwindow*) handle; |
708 | assert(window != NULL); |
709 | |
710 | _GLFW_REQUIRE_INIT_OR_RETURN(1.f); |
711 | return _glfw.platform.getWindowOpacity(window); |
712 | } |
713 | |
714 | GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) |
715 | { |
716 | _GLFWwindow* window = (_GLFWwindow*) handle; |
717 | assert(window != NULL); |
718 | assert(opacity == opacity); |
719 | assert(opacity >= 0.f); |
720 | assert(opacity <= 1.f); |
721 | |
722 | _GLFW_REQUIRE_INIT(); |
723 | |
724 | if (opacity != opacity || opacity < 0.f || opacity > 1.f) |
725 | { |
726 | _glfwInputError(GLFW_INVALID_VALUE, "Invalid window opacity %f" , opacity); |
727 | return; |
728 | } |
729 | |
730 | _glfw.platform.setWindowOpacity(window, opacity); |
731 | } |
732 | |
733 | GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) |
734 | { |
735 | _GLFWwindow* window = (_GLFWwindow*) handle; |
736 | assert(window != NULL); |
737 | |
738 | _GLFW_REQUIRE_INIT(); |
739 | _glfw.platform.iconifyWindow(window); |
740 | } |
741 | |
742 | GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) |
743 | { |
744 | _GLFWwindow* window = (_GLFWwindow*) handle; |
745 | assert(window != NULL); |
746 | |
747 | _GLFW_REQUIRE_INIT(); |
748 | _glfw.platform.restoreWindow(window); |
749 | } |
750 | |
751 | GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) |
752 | { |
753 | _GLFWwindow* window = (_GLFWwindow*) handle; |
754 | assert(window != NULL); |
755 | |
756 | _GLFW_REQUIRE_INIT(); |
757 | |
758 | if (window->monitor) |
759 | return; |
760 | |
761 | _glfw.platform.maximizeWindow(window); |
762 | } |
763 | |
764 | GLFWAPI void glfwShowWindow(GLFWwindow* handle) |
765 | { |
766 | _GLFWwindow* window = (_GLFWwindow*) handle; |
767 | assert(window != NULL); |
768 | |
769 | _GLFW_REQUIRE_INIT(); |
770 | |
771 | if (window->monitor) |
772 | return; |
773 | |
774 | _glfw.platform.showWindow(window); |
775 | |
776 | if (window->focusOnShow) |
777 | _glfw.platform.focusWindow(window); |
778 | } |
779 | |
780 | GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) |
781 | { |
782 | _GLFWwindow* window = (_GLFWwindow*) handle; |
783 | assert(window != NULL); |
784 | |
785 | _GLFW_REQUIRE_INIT(); |
786 | |
787 | _glfw.platform.requestWindowAttention(window); |
788 | } |
789 | |
790 | GLFWAPI void glfwHideWindow(GLFWwindow* handle) |
791 | { |
792 | _GLFWwindow* window = (_GLFWwindow*) handle; |
793 | assert(window != NULL); |
794 | |
795 | _GLFW_REQUIRE_INIT(); |
796 | |
797 | if (window->monitor) |
798 | return; |
799 | |
800 | _glfw.platform.hideWindow(window); |
801 | } |
802 | |
803 | GLFWAPI void glfwFocusWindow(GLFWwindow* handle) |
804 | { |
805 | _GLFWwindow* window = (_GLFWwindow*) handle; |
806 | assert(window != NULL); |
807 | |
808 | _GLFW_REQUIRE_INIT(); |
809 | |
810 | _glfw.platform.focusWindow(window); |
811 | } |
812 | |
813 | GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) |
814 | { |
815 | _GLFWwindow* window = (_GLFWwindow*) handle; |
816 | assert(window != NULL); |
817 | |
818 | _GLFW_REQUIRE_INIT_OR_RETURN(0); |
819 | |
820 | switch (attrib) |
821 | { |
822 | case GLFW_FOCUSED: |
823 | return _glfw.platform.windowFocused(window); |
824 | case GLFW_ICONIFIED: |
825 | return _glfw.platform.windowIconified(window); |
826 | case GLFW_VISIBLE: |
827 | return _glfw.platform.windowVisible(window); |
828 | case GLFW_MAXIMIZED: |
829 | return _glfw.platform.windowMaximized(window); |
830 | case GLFW_HOVERED: |
831 | return _glfw.platform.windowHovered(window); |
832 | case GLFW_FOCUS_ON_SHOW: |
833 | return window->focusOnShow; |
834 | case GLFW_MOUSE_PASSTHROUGH: |
835 | return window->mousePassthrough; |
836 | case GLFW_TRANSPARENT_FRAMEBUFFER: |
837 | return _glfw.platform.framebufferTransparent(window); |
838 | case GLFW_RESIZABLE: |
839 | return window->resizable; |
840 | case GLFW_DECORATED: |
841 | return window->decorated; |
842 | case GLFW_FLOATING: |
843 | return window->floating; |
844 | case GLFW_AUTO_ICONIFY: |
845 | return window->autoIconify; |
846 | case GLFW_DOUBLEBUFFER: |
847 | return window->doublebuffer; |
848 | case GLFW_CLIENT_API: |
849 | return window->context.client; |
850 | case GLFW_CONTEXT_CREATION_API: |
851 | return window->context.source; |
852 | case GLFW_CONTEXT_VERSION_MAJOR: |
853 | return window->context.major; |
854 | case GLFW_CONTEXT_VERSION_MINOR: |
855 | return window->context.minor; |
856 | case GLFW_CONTEXT_REVISION: |
857 | return window->context.revision; |
858 | case GLFW_CONTEXT_ROBUSTNESS: |
859 | return window->context.robustness; |
860 | case GLFW_OPENGL_FORWARD_COMPAT: |
861 | return window->context.forward; |
862 | case GLFW_CONTEXT_DEBUG: |
863 | return window->context.debug; |
864 | case GLFW_OPENGL_PROFILE: |
865 | return window->context.profile; |
866 | case GLFW_CONTEXT_RELEASE_BEHAVIOR: |
867 | return window->context.release; |
868 | case GLFW_CONTEXT_NO_ERROR: |
869 | return window->context.noerror; |
870 | } |
871 | |
872 | _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X" , attrib); |
873 | return 0; |
874 | } |
875 | |
876 | GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) |
877 | { |
878 | _GLFWwindow* window = (_GLFWwindow*) handle; |
879 | assert(window != NULL); |
880 | |
881 | _GLFW_REQUIRE_INIT(); |
882 | |
883 | value = value ? GLFW_TRUE : GLFW_FALSE; |
884 | |
885 | switch (attrib) |
886 | { |
887 | case GLFW_AUTO_ICONIFY: |
888 | window->autoIconify = value; |
889 | return; |
890 | |
891 | case GLFW_RESIZABLE: |
892 | window->resizable = value; |
893 | if (!window->monitor) |
894 | _glfw.platform.setWindowResizable(window, value); |
895 | return; |
896 | |
897 | case GLFW_DECORATED: |
898 | window->decorated = value; |
899 | if (!window->monitor) |
900 | _glfw.platform.setWindowDecorated(window, value); |
901 | return; |
902 | |
903 | case GLFW_FLOATING: |
904 | window->floating = value; |
905 | if (!window->monitor) |
906 | _glfw.platform.setWindowFloating(window, value); |
907 | return; |
908 | |
909 | case GLFW_FOCUS_ON_SHOW: |
910 | window->focusOnShow = value; |
911 | return; |
912 | |
913 | case GLFW_MOUSE_PASSTHROUGH: |
914 | window->mousePassthrough = value; |
915 | _glfw.platform.setWindowMousePassthrough(window, value); |
916 | return; |
917 | } |
918 | |
919 | _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X" , attrib); |
920 | } |
921 | |
922 | GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) |
923 | { |
924 | _GLFWwindow* window = (_GLFWwindow*) handle; |
925 | assert(window != NULL); |
926 | |
927 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
928 | return (GLFWmonitor*) window->monitor; |
929 | } |
930 | |
931 | GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, |
932 | GLFWmonitor* mh, |
933 | int xpos, int ypos, |
934 | int width, int height, |
935 | int refreshRate) |
936 | { |
937 | _GLFWwindow* window = (_GLFWwindow*) wh; |
938 | _GLFWmonitor* monitor = (_GLFWmonitor*) mh; |
939 | assert(window != NULL); |
940 | assert(width >= 0); |
941 | assert(height >= 0); |
942 | |
943 | _GLFW_REQUIRE_INIT(); |
944 | |
945 | if (width <= 0 || height <= 0) |
946 | { |
947 | _glfwInputError(GLFW_INVALID_VALUE, |
948 | "Invalid window size %ix%i" , |
949 | width, height); |
950 | return; |
951 | } |
952 | |
953 | if (refreshRate < 0 && refreshRate != GLFW_DONT_CARE) |
954 | { |
955 | _glfwInputError(GLFW_INVALID_VALUE, |
956 | "Invalid refresh rate %i" , |
957 | refreshRate); |
958 | return; |
959 | } |
960 | |
961 | window->videoMode.width = width; |
962 | window->videoMode.height = height; |
963 | window->videoMode.refreshRate = refreshRate; |
964 | |
965 | _glfw.platform.setWindowMonitor(window, monitor, |
966 | xpos, ypos, width, height, |
967 | refreshRate); |
968 | } |
969 | |
970 | GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) |
971 | { |
972 | _GLFWwindow* window = (_GLFWwindow*) handle; |
973 | assert(window != NULL); |
974 | |
975 | _GLFW_REQUIRE_INIT(); |
976 | window->userPointer = pointer; |
977 | } |
978 | |
979 | GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle) |
980 | { |
981 | _GLFWwindow* window = (_GLFWwindow*) handle; |
982 | assert(window != NULL); |
983 | |
984 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
985 | return window->userPointer; |
986 | } |
987 | |
988 | GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, |
989 | GLFWwindowposfun cbfun) |
990 | { |
991 | _GLFWwindow* window = (_GLFWwindow*) handle; |
992 | assert(window != NULL); |
993 | |
994 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
995 | _GLFW_SWAP(GLFWwindowposfun, window->callbacks.pos, cbfun); |
996 | return cbfun; |
997 | } |
998 | |
999 | GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, |
1000 | GLFWwindowsizefun cbfun) |
1001 | { |
1002 | _GLFWwindow* window = (_GLFWwindow*) handle; |
1003 | assert(window != NULL); |
1004 | |
1005 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
1006 | _GLFW_SWAP(GLFWwindowsizefun, window->callbacks.size, cbfun); |
1007 | return cbfun; |
1008 | } |
1009 | |
1010 | GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, |
1011 | GLFWwindowclosefun cbfun) |
1012 | { |
1013 | _GLFWwindow* window = (_GLFWwindow*) handle; |
1014 | assert(window != NULL); |
1015 | |
1016 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
1017 | _GLFW_SWAP(GLFWwindowclosefun, window->callbacks.close, cbfun); |
1018 | return cbfun; |
1019 | } |
1020 | |
1021 | GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, |
1022 | GLFWwindowrefreshfun cbfun) |
1023 | { |
1024 | _GLFWwindow* window = (_GLFWwindow*) handle; |
1025 | assert(window != NULL); |
1026 | |
1027 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
1028 | _GLFW_SWAP(GLFWwindowrefreshfun, window->callbacks.refresh, cbfun); |
1029 | return cbfun; |
1030 | } |
1031 | |
1032 | GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, |
1033 | GLFWwindowfocusfun cbfun) |
1034 | { |
1035 | _GLFWwindow* window = (_GLFWwindow*) handle; |
1036 | assert(window != NULL); |
1037 | |
1038 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
1039 | _GLFW_SWAP(GLFWwindowfocusfun, window->callbacks.focus, cbfun); |
1040 | return cbfun; |
1041 | } |
1042 | |
1043 | GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, |
1044 | GLFWwindowiconifyfun cbfun) |
1045 | { |
1046 | _GLFWwindow* window = (_GLFWwindow*) handle; |
1047 | assert(window != NULL); |
1048 | |
1049 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
1050 | _GLFW_SWAP(GLFWwindowiconifyfun, window->callbacks.iconify, cbfun); |
1051 | return cbfun; |
1052 | } |
1053 | |
1054 | GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle, |
1055 | GLFWwindowmaximizefun cbfun) |
1056 | { |
1057 | _GLFWwindow* window = (_GLFWwindow*) handle; |
1058 | assert(window != NULL); |
1059 | |
1060 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
1061 | _GLFW_SWAP(GLFWwindowmaximizefun, window->callbacks.maximize, cbfun); |
1062 | return cbfun; |
1063 | } |
1064 | |
1065 | GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle, |
1066 | GLFWframebuffersizefun cbfun) |
1067 | { |
1068 | _GLFWwindow* window = (_GLFWwindow*) handle; |
1069 | assert(window != NULL); |
1070 | |
1071 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
1072 | _GLFW_SWAP(GLFWframebuffersizefun, window->callbacks.fbsize, cbfun); |
1073 | return cbfun; |
1074 | } |
1075 | |
1076 | GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* handle, |
1077 | GLFWwindowcontentscalefun cbfun) |
1078 | { |
1079 | _GLFWwindow* window = (_GLFWwindow*) handle; |
1080 | assert(window != NULL); |
1081 | |
1082 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
1083 | _GLFW_SWAP(GLFWwindowcontentscalefun, window->callbacks.scale, cbfun); |
1084 | return cbfun; |
1085 | } |
1086 | |
1087 | GLFWAPI void glfwPollEvents(void) |
1088 | { |
1089 | _GLFW_REQUIRE_INIT(); |
1090 | _glfw.platform.pollEvents(); |
1091 | } |
1092 | |
1093 | GLFWAPI void glfwWaitEvents(void) |
1094 | { |
1095 | _GLFW_REQUIRE_INIT(); |
1096 | _glfw.platform.waitEvents(); |
1097 | } |
1098 | |
1099 | GLFWAPI void glfwWaitEventsTimeout(double timeout) |
1100 | { |
1101 | _GLFW_REQUIRE_INIT(); |
1102 | assert(timeout == timeout); |
1103 | assert(timeout >= 0.0); |
1104 | assert(timeout <= DBL_MAX); |
1105 | |
1106 | if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX) |
1107 | { |
1108 | _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f" , timeout); |
1109 | return; |
1110 | } |
1111 | |
1112 | _glfw.platform.waitEventsTimeout(timeout); |
1113 | } |
1114 | |
1115 | GLFWAPI void glfwPostEmptyEvent(void) |
1116 | { |
1117 | _GLFW_REQUIRE_INIT(); |
1118 | _glfw.platform.postEmptyEvent(); |
1119 | } |
1120 | |
1121 | |