comparison mupdf-source/thirdparty/freeglut/src/mswin/fg_main_mswin.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*
2 * fg_main_mswin.c
3 *
4 * The Windows-specific mouse cursor related stuff.
5 *
6 * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
7 * Written by John F. Fay, <fayjf@sourceforge.net>
8 * Creation date: Sat Jan 21, 2012
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 #include <GL/freeglut.h>
29 #include "../fg_internal.h"
30
31 #ifndef MAPVK_VK_TO_CHAR
32 #define MAPVK_VK_TO_CHAR 2
33 #endif
34
35 extern void fghRedrawWindow ( SFG_Window *window );
36 extern void fghRedrawWindowAndChildren ( SFG_Window *window );
37 extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify);
38 extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify);
39 extern void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
40 extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
41
42 extern void fgNewWGLCreateContext( SFG_Window* window );
43 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
44 unsigned char layer_type );
45
46 extern void fgPlatformCheckMenuDeactivate(HWND newFocusWnd);
47
48 #ifdef WM_TOUCH
49 typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
50 typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
51 static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
52 static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
53 #endif
54
55 #ifdef _WIN32_WCE
56 typedef struct GXDisplayProperties GXDisplayProperties;
57 typedef struct GXKeyList GXKeyList;
58 #include <gx.h>
59
60 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
61 typedef int (*GXOPENINPUT)();
62
63 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
64 GXOPENINPUT GXOpenInput_ = NULL;
65
66 struct GXKeyList gxKeyList;
67 #endif /* _WIN32_WCE */
68
69 #ifdef _DEBUG
70 /*
71 * WM_ message to string, for debugging
72 * This is taken from the 8.0 SDK, so Windows 8 API and everything earlier is included
73 */
74 struct WM_MESSAGE_MAP
75 {
76 UINT nMsg;
77 LPCSTR lpszMsg;
78 };
79 #define DEFINE_MESSAGE(wm){ wm, #wm }
80 static struct WM_MESSAGE_MAP allMessages[] =
81 {
82 DEFINE_MESSAGE(WM_NULL),
83 DEFINE_MESSAGE(WM_CREATE),
84 DEFINE_MESSAGE(WM_DESTROY),
85 DEFINE_MESSAGE(WM_MOVE),
86 DEFINE_MESSAGE(WM_SIZE),
87
88 DEFINE_MESSAGE(WM_ACTIVATE),
89 DEFINE_MESSAGE(WM_SETFOCUS),
90 DEFINE_MESSAGE(WM_KILLFOCUS),
91 DEFINE_MESSAGE(WM_ENABLE),
92 DEFINE_MESSAGE(WM_SETREDRAW),
93 DEFINE_MESSAGE(WM_SETTEXT),
94 DEFINE_MESSAGE(WM_GETTEXT),
95 DEFINE_MESSAGE(WM_GETTEXTLENGTH),
96 DEFINE_MESSAGE(WM_PAINT),
97 DEFINE_MESSAGE(WM_CLOSE),
98 # ifndef _WIN32_WCE
99 DEFINE_MESSAGE(WM_QUERYENDSESSION),
100 DEFINE_MESSAGE(WM_QUERYOPEN),
101 DEFINE_MESSAGE(WM_ENDSESSION),
102 # endif
103 DEFINE_MESSAGE(WM_QUIT),
104 DEFINE_MESSAGE(WM_ERASEBKGND),
105 DEFINE_MESSAGE(WM_SYSCOLORCHANGE),
106 DEFINE_MESSAGE(WM_SHOWWINDOW),
107 DEFINE_MESSAGE(WM_WININICHANGE),
108
109 DEFINE_MESSAGE(WM_DEVMODECHANGE),
110 DEFINE_MESSAGE(WM_ACTIVATEAPP),
111 DEFINE_MESSAGE(WM_FONTCHANGE),
112 DEFINE_MESSAGE(WM_TIMECHANGE),
113 DEFINE_MESSAGE(WM_CANCELMODE),
114 DEFINE_MESSAGE(WM_SETCURSOR),
115 DEFINE_MESSAGE(WM_MOUSEACTIVATE),
116 DEFINE_MESSAGE(WM_CHILDACTIVATE),
117 DEFINE_MESSAGE(WM_QUEUESYNC),
118
119 DEFINE_MESSAGE(WM_GETMINMAXINFO),
120
121 DEFINE_MESSAGE(WM_PAINTICON),
122 DEFINE_MESSAGE(WM_ICONERASEBKGND),
123 DEFINE_MESSAGE(WM_NEXTDLGCTL),
124 DEFINE_MESSAGE(WM_SPOOLERSTATUS),
125 DEFINE_MESSAGE(WM_DRAWITEM),
126 DEFINE_MESSAGE(WM_MEASUREITEM),
127 DEFINE_MESSAGE(WM_DELETEITEM),
128 DEFINE_MESSAGE(WM_VKEYTOITEM),
129 DEFINE_MESSAGE(WM_CHARTOITEM),
130 DEFINE_MESSAGE(WM_SETFONT),
131 DEFINE_MESSAGE(WM_GETFONT),
132 DEFINE_MESSAGE(WM_SETHOTKEY),
133 DEFINE_MESSAGE(WM_GETHOTKEY),
134 DEFINE_MESSAGE(WM_QUERYDRAGICON),
135 DEFINE_MESSAGE(WM_COMPAREITEM),
136 # if(WINVER >= 0x0500)
137 # ifndef _WIN32_WCE
138 DEFINE_MESSAGE(WM_GETOBJECT),
139 # endif
140 # endif /* WINVER >= 0x0500 */
141 DEFINE_MESSAGE(WM_COMPACTING),
142 DEFINE_MESSAGE(WM_COMMNOTIFY),
143 DEFINE_MESSAGE(WM_WINDOWPOSCHANGING),
144 DEFINE_MESSAGE(WM_WINDOWPOSCHANGED),
145
146 DEFINE_MESSAGE(WM_POWER),
147
148 DEFINE_MESSAGE(WM_COPYDATA),
149 DEFINE_MESSAGE(WM_CANCELJOURNAL),
150
151 # if(WINVER >= 0x0400)
152 DEFINE_MESSAGE(WM_NOTIFY),
153 DEFINE_MESSAGE(WM_INPUTLANGCHANGEREQUEST),
154 DEFINE_MESSAGE(WM_INPUTLANGCHANGE),
155 DEFINE_MESSAGE(WM_TCARD),
156 DEFINE_MESSAGE(WM_HELP),
157 DEFINE_MESSAGE(WM_USERCHANGED),
158 DEFINE_MESSAGE(WM_NOTIFYFORMAT),
159
160 DEFINE_MESSAGE(WM_CONTEXTMENU),
161 DEFINE_MESSAGE(WM_STYLECHANGING),
162 DEFINE_MESSAGE(WM_STYLECHANGED),
163 DEFINE_MESSAGE(WM_DISPLAYCHANGE),
164 DEFINE_MESSAGE(WM_GETICON),
165 DEFINE_MESSAGE(WM_SETICON),
166 # endif /* WINVER >= 0x0400 */
167
168 DEFINE_MESSAGE(WM_NCCREATE),
169 DEFINE_MESSAGE(WM_NCDESTROY),
170 DEFINE_MESSAGE(WM_NCCALCSIZE),
171 DEFINE_MESSAGE(WM_NCHITTEST),
172 DEFINE_MESSAGE(WM_NCPAINT),
173 DEFINE_MESSAGE(WM_NCACTIVATE),
174 DEFINE_MESSAGE(WM_GETDLGCODE),
175 # ifndef _WIN32_WCE
176 DEFINE_MESSAGE(WM_SYNCPAINT),
177 # endif
178 DEFINE_MESSAGE(WM_NCMOUSEMOVE),
179 DEFINE_MESSAGE(WM_NCLBUTTONDOWN),
180 DEFINE_MESSAGE(WM_NCLBUTTONUP),
181 DEFINE_MESSAGE(WM_NCLBUTTONDBLCLK),
182 DEFINE_MESSAGE(WM_NCRBUTTONDOWN),
183 DEFINE_MESSAGE(WM_NCRBUTTONUP),
184 DEFINE_MESSAGE(WM_NCRBUTTONDBLCLK),
185 DEFINE_MESSAGE(WM_NCMBUTTONDOWN),
186 DEFINE_MESSAGE(WM_NCMBUTTONUP),
187 DEFINE_MESSAGE(WM_NCMBUTTONDBLCLK),
188
189
190
191 # if(_WIN32_WINNT >= 0x0500) && defined(WM_NCXBUTTONDOWN)
192 DEFINE_MESSAGE(WM_NCXBUTTONDOWN),
193 DEFINE_MESSAGE(WM_NCXBUTTONUP),
194 DEFINE_MESSAGE(WM_NCXBUTTONDBLCLK),
195 # endif /* _WIN32_WINNT >= 0x0500 */
196
197
198 # if(_WIN32_WINNT >= 0x0501)
199 DEFINE_MESSAGE(WM_INPUT_DEVICE_CHANGE),
200 # endif /* _WIN32_WINNT >= 0x0501 */
201
202 # if(_WIN32_WINNT >= 0x0501)
203 DEFINE_MESSAGE(WM_INPUT),
204 # endif /* _WIN32_WINNT >= 0x0501 */
205
206 DEFINE_MESSAGE(WM_KEYDOWN),
207 DEFINE_MESSAGE(WM_KEYUP),
208 DEFINE_MESSAGE(WM_CHAR),
209 DEFINE_MESSAGE(WM_DEADCHAR),
210 DEFINE_MESSAGE(WM_SYSKEYDOWN),
211 DEFINE_MESSAGE(WM_SYSKEYUP),
212 DEFINE_MESSAGE(WM_SYSCHAR),
213 DEFINE_MESSAGE(WM_SYSDEADCHAR),
214 # if(_WIN32_WINNT >= 0x0501)
215 DEFINE_MESSAGE(WM_UNICHAR),
216 # endif /* _WIN32_WINNT >= 0x0501 */
217
218 # if(WINVER >= 0x0400)
219 DEFINE_MESSAGE(WM_IME_STARTCOMPOSITION),
220 DEFINE_MESSAGE(WM_IME_ENDCOMPOSITION),
221 DEFINE_MESSAGE(WM_IME_COMPOSITION),
222 DEFINE_MESSAGE(WM_IME_KEYLAST),
223 # endif /* WINVER >= 0x0400 */
224
225 DEFINE_MESSAGE(WM_INITDIALOG),
226 DEFINE_MESSAGE(WM_COMMAND),
227 DEFINE_MESSAGE(WM_SYSCOMMAND),
228 DEFINE_MESSAGE(WM_TIMER),
229 DEFINE_MESSAGE(WM_HSCROLL),
230 DEFINE_MESSAGE(WM_VSCROLL),
231 DEFINE_MESSAGE(WM_INITMENU),
232 DEFINE_MESSAGE(WM_INITMENUPOPUP),
233 # if(WINVER >= 0x0601)
234 DEFINE_MESSAGE(WM_GESTURE),
235 DEFINE_MESSAGE(WM_GESTURENOTIFY),
236 # endif /* WINVER >= 0x0601 */
237 DEFINE_MESSAGE(WM_MENUSELECT),
238 DEFINE_MESSAGE(WM_MENUCHAR),
239 DEFINE_MESSAGE(WM_ENTERIDLE),
240 # if(WINVER >= 0x0500)
241 # ifndef _WIN32_WCE
242 DEFINE_MESSAGE(WM_MENURBUTTONUP),
243 DEFINE_MESSAGE(WM_MENUDRAG),
244 DEFINE_MESSAGE(WM_MENUGETOBJECT),
245 DEFINE_MESSAGE(WM_UNINITMENUPOPUP),
246 DEFINE_MESSAGE(WM_MENUCOMMAND),
247
248 # if(_WIN32_WINNT >= 0x0500) && defined(WM_CHANGEUISTATE)
249 DEFINE_MESSAGE(WM_CHANGEUISTATE),
250 DEFINE_MESSAGE(WM_UPDATEUISTATE),
251 DEFINE_MESSAGE(WM_QUERYUISTATE),
252 # endif /* _WIN32_WINNT >= 0x0500 */
253
254 # endif
255 # endif /* WINVER >= 0x0500 */
256
257 DEFINE_MESSAGE(WM_CTLCOLORMSGBOX),
258 DEFINE_MESSAGE(WM_CTLCOLOREDIT),
259 DEFINE_MESSAGE(WM_CTLCOLORLISTBOX),
260 DEFINE_MESSAGE(WM_CTLCOLORBTN),
261 DEFINE_MESSAGE(WM_CTLCOLORDLG),
262 DEFINE_MESSAGE(WM_CTLCOLORSCROLLBAR),
263 DEFINE_MESSAGE(WM_CTLCOLORSTATIC),
264 # define MN_GETHMENU 0x01E1
265
266 DEFINE_MESSAGE(WM_MOUSEMOVE),
267 DEFINE_MESSAGE(WM_LBUTTONDOWN),
268 DEFINE_MESSAGE(WM_LBUTTONUP),
269 DEFINE_MESSAGE(WM_LBUTTONDBLCLK),
270 DEFINE_MESSAGE(WM_RBUTTONDOWN),
271 DEFINE_MESSAGE(WM_RBUTTONUP),
272 DEFINE_MESSAGE(WM_RBUTTONDBLCLK),
273 DEFINE_MESSAGE(WM_MBUTTONDOWN),
274 DEFINE_MESSAGE(WM_MBUTTONUP),
275 DEFINE_MESSAGE(WM_MBUTTONDBLCLK),
276 # if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
277 DEFINE_MESSAGE(WM_MOUSEWHEEL),
278 # endif
279 # if (_WIN32_WINNT >= 0x0500) && defined(WM_XBUTTONDOWN)
280 DEFINE_MESSAGE(WM_XBUTTONDOWN),
281 DEFINE_MESSAGE(WM_XBUTTONUP),
282 DEFINE_MESSAGE(WM_XBUTTONDBLCLK),
283 # endif
284 # if (_WIN32_WINNT >= 0x0600)
285 DEFINE_MESSAGE(WM_MOUSEHWHEEL),
286 # endif
287
288
289
290 DEFINE_MESSAGE(WM_PARENTNOTIFY),
291 DEFINE_MESSAGE(WM_ENTERMENULOOP),
292 DEFINE_MESSAGE(WM_EXITMENULOOP),
293
294 # if(WINVER >= 0x0400)
295 DEFINE_MESSAGE(WM_NEXTMENU),
296 DEFINE_MESSAGE(WM_SIZING),
297 DEFINE_MESSAGE(WM_CAPTURECHANGED),
298 DEFINE_MESSAGE(WM_MOVING),
299 # endif /* WINVER >= 0x0400 */
300
301 # if(WINVER >= 0x0400)
302 DEFINE_MESSAGE(WM_POWERBROADCAST),
303 DEFINE_MESSAGE(WM_DEVICECHANGE),
304 # endif /* WINVER >= 0x0400 */
305
306 DEFINE_MESSAGE(WM_MDICREATE),
307 DEFINE_MESSAGE(WM_MDIDESTROY),
308 DEFINE_MESSAGE(WM_MDIACTIVATE),
309 DEFINE_MESSAGE(WM_MDIRESTORE),
310 DEFINE_MESSAGE(WM_MDINEXT),
311 DEFINE_MESSAGE(WM_MDIMAXIMIZE),
312 DEFINE_MESSAGE(WM_MDITILE),
313 DEFINE_MESSAGE(WM_MDICASCADE),
314 DEFINE_MESSAGE(WM_MDIICONARRANGE),
315 DEFINE_MESSAGE(WM_MDIGETACTIVE),
316
317
318 DEFINE_MESSAGE(WM_MDISETMENU),
319 DEFINE_MESSAGE(WM_ENTERSIZEMOVE),
320 DEFINE_MESSAGE(WM_EXITSIZEMOVE),
321 DEFINE_MESSAGE(WM_DROPFILES),
322 DEFINE_MESSAGE(WM_MDIREFRESHMENU),
323
324 # if(WINVER >= 0x0602)
325 DEFINE_MESSAGE(WM_POINTERDEVICECHANGE),
326 DEFINE_MESSAGE(WM_POINTERDEVICEINRANGE),
327 DEFINE_MESSAGE(WM_POINTERDEVICEOUTOFRANGE),
328 # endif /* WINVER >= 0x0602 */
329
330 # if(WINVER >= 0x0601)
331 DEFINE_MESSAGE(WM_TOUCH),
332 # endif /* WINVER >= 0x0601 */
333
334 # if(WINVER >= 0x0602)
335 DEFINE_MESSAGE(WM_NCPOINTERUPDATE),
336 DEFINE_MESSAGE(WM_NCPOINTERDOWN),
337 DEFINE_MESSAGE(WM_NCPOINTERUP),
338 DEFINE_MESSAGE(WM_POINTERUPDATE),
339 DEFINE_MESSAGE(WM_POINTERDOWN),
340 DEFINE_MESSAGE(WM_POINTERUP),
341 DEFINE_MESSAGE(WM_POINTERENTER),
342 DEFINE_MESSAGE(WM_POINTERLEAVE),
343 DEFINE_MESSAGE(WM_POINTERACTIVATE),
344 DEFINE_MESSAGE(WM_POINTERCAPTURECHANGED),
345 DEFINE_MESSAGE(WM_TOUCHHITTESTING),
346 DEFINE_MESSAGE(WM_POINTERWHEEL),
347 DEFINE_MESSAGE(WM_POINTERHWHEEL),
348 # endif /* WINVER >= 0x0602 */
349
350
351 # if(WINVER >= 0x0400)
352 DEFINE_MESSAGE(WM_IME_SETCONTEXT),
353 DEFINE_MESSAGE(WM_IME_NOTIFY),
354 DEFINE_MESSAGE(WM_IME_CONTROL),
355 DEFINE_MESSAGE(WM_IME_COMPOSITIONFULL),
356 DEFINE_MESSAGE(WM_IME_SELECT),
357 DEFINE_MESSAGE(WM_IME_CHAR),
358 # endif /* WINVER >= 0x0400 */
359 # if(WINVER >= 0x0500)
360 DEFINE_MESSAGE(WM_IME_REQUEST),
361 # endif /* WINVER >= 0x0500 */
362 # if(WINVER >= 0x0400)
363 DEFINE_MESSAGE(WM_IME_KEYDOWN),
364 DEFINE_MESSAGE(WM_IME_KEYUP),
365 # endif /* WINVER >= 0x0400 */
366
367 # if((_WIN32_WINNT >= 0x0400) || (WINVER >= 0x0500))
368 DEFINE_MESSAGE(WM_MOUSEHOVER),
369 DEFINE_MESSAGE(WM_MOUSELEAVE),
370 # endif
371 # if(WINVER >= 0x0500) && defined(WM_NCMOUSEHOVER)
372 DEFINE_MESSAGE(WM_NCMOUSEHOVER),
373 DEFINE_MESSAGE(WM_NCMOUSELEAVE),
374 # endif /* WINVER >= 0x0500 */
375
376 # if(_WIN32_WINNT >= 0x0501)
377 DEFINE_MESSAGE(WM_WTSSESSION_CHANGE),
378 # endif /* _WIN32_WINNT >= 0x0501 */
379
380 DEFINE_MESSAGE(WM_CUT),
381 DEFINE_MESSAGE(WM_COPY),
382 DEFINE_MESSAGE(WM_PASTE),
383 DEFINE_MESSAGE(WM_CLEAR),
384 DEFINE_MESSAGE(WM_UNDO),
385 DEFINE_MESSAGE(WM_RENDERFORMAT),
386 DEFINE_MESSAGE(WM_RENDERALLFORMATS),
387 DEFINE_MESSAGE(WM_DESTROYCLIPBOARD),
388 DEFINE_MESSAGE(WM_DRAWCLIPBOARD),
389 DEFINE_MESSAGE(WM_PAINTCLIPBOARD),
390 DEFINE_MESSAGE(WM_VSCROLLCLIPBOARD),
391 DEFINE_MESSAGE(WM_SIZECLIPBOARD),
392 DEFINE_MESSAGE(WM_ASKCBFORMATNAME),
393 DEFINE_MESSAGE(WM_CHANGECBCHAIN),
394 DEFINE_MESSAGE(WM_HSCROLLCLIPBOARD),
395 DEFINE_MESSAGE(WM_QUERYNEWPALETTE),
396 DEFINE_MESSAGE(WM_PALETTEISCHANGING),
397 DEFINE_MESSAGE(WM_PALETTECHANGED),
398 DEFINE_MESSAGE(WM_HOTKEY),
399
400 # if(WINVER >= 0x0400)
401 DEFINE_MESSAGE(WM_PRINT),
402 DEFINE_MESSAGE(WM_PRINTCLIENT),
403 # endif /* WINVER >= 0x0400 */
404
405 # if(_WIN32_WINNT >= 0x0500) && defined(WM_APPCOMMAND)
406 DEFINE_MESSAGE(WM_APPCOMMAND),
407 # endif /* _WIN32_WINNT >= 0x0500 */
408
409 # if(_WIN32_WINNT >= 0x0501)
410 DEFINE_MESSAGE(WM_THEMECHANGED),
411 # endif /* _WIN32_WINNT >= 0x0501 */
412
413
414 # if(_WIN32_WINNT >= 0x0501)
415 DEFINE_MESSAGE(WM_CLIPBOARDUPDATE),
416 # endif /* _WIN32_WINNT >= 0x0501 */
417
418 # if(_WIN32_WINNT >= 0x0600)
419 DEFINE_MESSAGE(WM_DWMCOMPOSITIONCHANGED),
420 DEFINE_MESSAGE(WM_DWMNCRENDERINGCHANGED),
421 DEFINE_MESSAGE(WM_DWMCOLORIZATIONCOLORCHANGED),
422 DEFINE_MESSAGE(WM_DWMWINDOWMAXIMIZEDCHANGE),
423 # endif /* _WIN32_WINNT >= 0x0600 */
424
425 # if(_WIN32_WINNT >= 0x0601)
426 DEFINE_MESSAGE(WM_DWMSENDICONICTHUMBNAIL),
427 DEFINE_MESSAGE(WM_DWMSENDICONICLIVEPREVIEWBITMAP),
428 # endif /* _WIN32_WINNT >= 0x0601 */
429
430
431 # if(WINVER >= 0x0600)
432 DEFINE_MESSAGE(WM_GETTITLEBARINFOEX),
433 # endif /* WINVER >= 0x0600 */
434 { 0, NULL, } /* end of message list */
435 };
436 #undef DEFINE_MESSAGE
437
438 char* WMMsg2Str(DWORD dwMessage)
439 {
440 struct WM_MESSAGE_MAP* pMapMsg = allMessages;
441 for (/*null*/; pMapMsg->lpszMsg != NULL; pMapMsg++)
442 {
443 if (pMapMsg->nMsg == dwMessage )
444 {
445 return (char *)pMapMsg->lpszMsg;
446 }
447 }
448 return "";
449 }
450 #endif /* _DEBUG */
451
452
453 /* Get system time, taking special precautions against 32bit timer wrap.
454 We use timeGetTime and not GetTickCount because of its better stability,
455 and because we can increase its granularity (to 1 ms in
456 fgPlatformInitialize). For that reason we can't use GetTickCount64 which
457 wouldn't have the wrap issue.
458 Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html)
459 */
460 static fg_time_t lastTime32 = 0;
461 static fg_time_t timeEpoch = 0;
462 void fgPlatformInitSystemTime()
463 {
464 #if defined(_WIN32_WCE)
465 lastTime32 = GetTickCount();
466 #else
467 lastTime32 = timeGetTime();
468 #endif
469 }
470 fg_time_t fgPlatformSystemTime ( void )
471 {
472 fg_time_t currTime32;
473 #if defined(_WIN32_WCE)
474 currTime32 = GetTickCount();
475 #else
476 currTime32 = timeGetTime();
477 #endif
478 /* Check if we just wrapped */
479 if (currTime32 < lastTime32)
480 timeEpoch++;
481
482 lastTime32 = currTime32;
483
484 return currTime32 | timeEpoch << 32;
485 }
486
487 extern char *fgClipboardBuffer[3];
488
489 void fgPlatformSetClipboard(int selection, const char *text)
490 {
491 if (selection == GLUT_PRIMARY)
492 {
493 free(fgClipboardBuffer[GLUT_PRIMARY]);
494 fgClipboardBuffer[GLUT_PRIMARY] = strdup(text);
495 }
496 else if (selection == GLUT_SECONDARY)
497 {
498 free(fgClipboardBuffer[GLUT_SECONDARY]);
499 fgClipboardBuffer[GLUT_SECONDARY] = strdup(text);
500 }
501 else if (selection == GLUT_CLIPBOARD && text)
502 {
503 int n = MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
504 if (n > 0)
505 {
506 HANDLE object = GlobalAlloc(0, n * sizeof(WCHAR));
507 if (object)
508 {
509 WCHAR *wtext = GlobalLock(object);
510 if (wtext)
511 {
512 MultiByteToWideChar(CP_UTF8, 0, text, -1, wtext, n);
513 GlobalUnlock(object);
514 if (OpenClipboard(NULL))
515 {
516 EmptyClipboard();
517 SetClipboardData(CF_UNICODETEXT, object);
518 CloseClipboard();
519 object = NULL; /* it is now owned by the system */
520 }
521 }
522 GlobalFree(object);
523 }
524 }
525 }
526 }
527
528 const char *fgPlatformGetClipboard(int selection)
529 {
530 if (selection == GLUT_PRIMARY)
531 return fgClipboardBuffer[GLUT_PRIMARY];
532 if (selection == GLUT_SECONDARY)
533 return fgClipboardBuffer[GLUT_SECONDARY];
534 if (selection == GLUT_CLIPBOARD)
535 {
536 free(fgClipboardBuffer[GLUT_CLIPBOARD]);
537 fgClipboardBuffer[GLUT_CLIPBOARD] = NULL;
538 if (OpenClipboard(NULL))
539 {
540 HANDLE object = GetClipboardData(CF_UNICODETEXT);
541 if (object)
542 {
543 WCHAR *wtext = GlobalLock(object);
544 if (wtext)
545 {
546 int n = WideCharToMultiByte(CP_UTF8, 0, wtext, -1, NULL, 0, NULL, NULL);
547 if (n > 0)
548 {
549 char *text = malloc(n);
550 fgClipboardBuffer[GLUT_CLIPBOARD] = text;
551 WideCharToMultiByte(CP_UTF8, 0, wtext, -1, text, n, NULL, NULL);
552 }
553 GlobalUnlock(object);
554 }
555 }
556 CloseClipboard();
557 }
558 return fgClipboardBuffer[GLUT_CLIPBOARD];
559 }
560 return NULL;
561 }
562
563 void fgPlatformSleepForEvents( fg_time_t msec )
564 {
565 MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
566 }
567
568
569 void fgPlatformProcessSingleEvent ( void )
570 {
571 MSG stMsg;
572
573 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
574
575 while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
576 {
577 if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
578 {
579 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
580 {
581 fgDeinitialize( );
582 exit( 0 );
583 }
584 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
585 fgState.ExecState = GLUT_EXEC_STATE_STOP;
586
587 return;
588 }
589
590 TranslateMessage( &stMsg );
591 DispatchMessage( &stMsg );
592 }
593 }
594
595
596
597 static void fghPlatformOnWindowStatusNotify(SFG_Window *window, GLboolean visState, GLboolean forceNotify)
598 {
599 GLboolean notify = GL_FALSE;
600 SFG_Window* child;
601
602 if (window->State.Visible != visState)
603 {
604 window->State.Visible = visState;
605
606 /* If top level window (not a subwindow/child), and icon title text available, switch titles based on visibility state */
607 if (!window->Parent && window->State.pWState.IconTitle)
608 {
609 if (visState)
610 /* visible, set window title */
611 SetWindowText( window->Window.Handle, window->State.pWState.WindowTitle );
612 else
613 /* not visible, set icon title */
614 SetWindowText( window->Window.Handle, window->State.pWState.IconTitle );
615 }
616
617 notify = GL_TRUE;
618 }
619
620 if (notify || forceNotify)
621 {
622 SFG_Window *saved_window = fgStructure.CurrentWindow;
623
624 /* On win32 we only have two states, window displayed and window not displayed (iconified)
625 * We map these to GLUT_FULLY_RETAINED and GLUT_HIDDEN respectively.
626 */
627 INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
628 fgSetWindow( saved_window );
629 }
630
631 /* Also set windowStatus/visibility state for children */
632 for( child = ( SFG_Window * )window->Children.First;
633 child;
634 child = ( SFG_Window * )child->Node.Next )
635 {
636 fghPlatformOnWindowStatusNotify(child, visState, GL_FALSE); /* No need to propagate forceNotify. Childs get this from their own INIT_WORK */
637 }
638 }
639
640 void fgPlatformMainLoopPreliminaryWork ( void )
641 {
642 /* no-op */
643 }
644
645
646 /*
647 * Determine a GLUT modifier mask based on MS-WINDOWS system info.
648 */
649 static int fgPlatformGetModifiers (void)
650 {
651 return
652 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) ||
653 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
654 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
655 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) |
656 ( ( ( GetKeyState( VK_LMENU ) < 0 ) ||
657 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
658 }
659
660 /* Check whether a button (VK_*BUTTON) is currently depressed. Returns
661 * non-zero (not necessarily 1) if yes. */
662 static SHORT fgGetKeyState(int vKey)
663 {
664 /* MSDN says: "If the high-order bit is 1, the key is down; otherwise, it is up". */
665 return GetKeyState(vKey) & 0xFF00;
666 }
667
668 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
669 {
670 static unsigned char lControl = 0, lShift = 0, lAlt = 0,
671 rControl = 0, rShift = 0, rAlt = 0;
672
673 int keypress = -1;
674
675 /* if keydown, check for repeat */
676 /* If repeat is globally switched off, it cannot be switched back on per window.
677 * But if it is globally switched on, it can be switched off per window. This matches
678 * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
679 * global state switch.
680 */
681 if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
682 return 1;
683
684 /* Remember the current modifiers state so user can query it from their callback */
685 fgState.Modifiers = fgPlatformGetModifiers( );
686
687 /* Convert the Win32 keystroke codes to GLUTtish way */
688 # define FG_KEY(a,b) case a: keypress = b; break;
689
690 switch( wParam )
691 {
692 FG_KEY( VK_F1, GLUT_KEY_F1 );
693 FG_KEY( VK_F2, GLUT_KEY_F2 );
694 FG_KEY( VK_F3, GLUT_KEY_F3 );
695 FG_KEY( VK_F4, GLUT_KEY_F4 );
696 FG_KEY( VK_F5, GLUT_KEY_F5 );
697 FG_KEY( VK_F6, GLUT_KEY_F6 );
698 FG_KEY( VK_F7, GLUT_KEY_F7 );
699 FG_KEY( VK_F8, GLUT_KEY_F8 );
700 FG_KEY( VK_F9, GLUT_KEY_F9 );
701 FG_KEY( VK_F10, GLUT_KEY_F10 );
702 FG_KEY( VK_F11, GLUT_KEY_F11 );
703 FG_KEY( VK_F12, GLUT_KEY_F12 );
704 FG_KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
705 FG_KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
706 FG_KEY( VK_HOME, GLUT_KEY_HOME );
707 FG_KEY( VK_END, GLUT_KEY_END );
708 FG_KEY( VK_LEFT, GLUT_KEY_LEFT );
709 FG_KEY( VK_UP, GLUT_KEY_UP );
710 FG_KEY( VK_RIGHT, GLUT_KEY_RIGHT );
711 FG_KEY( VK_DOWN, GLUT_KEY_DOWN );
712 FG_KEY( VK_INSERT, GLUT_KEY_INSERT );
713
714 /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
715 * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
716 * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
717 */
718 #define FG_KEY_EVENT(winKey,glutKey,keyStateVar)\
719 if (!keyStateVar && fgGetKeyState ( winKey ))\
720 {\
721 keypress = glutKey;\
722 keyStateVar = 1;\
723 }\
724 else if (keyStateVar && !fgGetKeyState ( winKey ))\
725 {\
726 keypress = glutKey;\
727 keyStateVar = 0;\
728 }
729 case VK_CONTROL:
730 FG_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
731 FG_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
732 break;
733 case VK_SHIFT:
734 FG_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
735 FG_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
736 break;
737 case VK_MENU:
738 FG_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
739 FG_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
740 break;
741 #undef KEY_EVENT
742
743 case VK_DELETE:
744 /* The delete key should be treated as an ASCII keypress: */
745 if (keydown)
746 {
747 INVOKE_WCB( *window, KeyboardDown,
748 ( 127, window->State.MouseX, window->State.MouseY )
749 );
750 INVOKE_WCB( *window, KeyboardExt,
751 ( 127, window->State.MouseX, window->State.MouseY )
752 );
753 INVOKE_WCB( *window, Keyboard,
754 ( 127, window->State.MouseX, window->State.MouseY )
755 );
756 }
757 else
758 INVOKE_WCB( *window, KeyboardUp,
759 ( 127, window->State.MouseX, window->State.MouseY )
760 );
761 break;
762
763 #if !defined(_WIN32_WCE)
764 default:
765 /* Mapped characters are handled with the WM_CHAR message. Handle low-level ASCII press/release callbacks here. */
766 {
767 UINT ascii = (UINT)MapVirtualKey((UINT)wParam, MAPVK_VK_TO_CHAR);
768 if (ascii >= 32 && ascii < 256)
769 {
770 /* Always send lowercase (unshifted) values */
771 if (ascii >= 'A' && ascii <= 'Z')
772 ascii = ascii - 'A' + 'a';
773 if (keydown)
774 INVOKE_WCB(*window, KeyboardDown, ((unsigned char)ascii, window->State.MouseX, window->State.MouseY) );
775 else
776 INVOKE_WCB(*window, KeyboardUp, ((unsigned char)ascii, window->State.MouseX, window->State.MouseY) );
777 }
778 }
779 #endif
780 }
781
782 #if defined(_WIN32_WCE)
783 if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
784 {
785 if(wParam==(unsigned)gxKeyList.vkRight)
786 keypress = GLUT_KEY_RIGHT;
787 else if(wParam==(unsigned)gxKeyList.vkLeft)
788 keypress = GLUT_KEY_LEFT;
789 else if(wParam==(unsigned)gxKeyList.vkUp)
790 keypress = GLUT_KEY_UP;
791 else if(wParam==(unsigned)gxKeyList.vkDown)
792 keypress = GLUT_KEY_DOWN;
793 else if(wParam==(unsigned)gxKeyList.vkA)
794 keypress = GLUT_KEY_F1;
795 else if(wParam==(unsigned)gxKeyList.vkB)
796 keypress = GLUT_KEY_F2;
797 else if(wParam==(unsigned)gxKeyList.vkC)
798 keypress = GLUT_KEY_F3;
799 else if(wParam==(unsigned)gxKeyList.vkStart)
800 keypress = GLUT_KEY_F4;
801 }
802 #endif
803
804 if( keypress != -1 )
805 if (keydown)
806 INVOKE_WCB( *window, Special,
807 ( keypress,
808 window->State.MouseX, window->State.MouseY )
809 );
810 else
811 INVOKE_WCB( *window, SpecialUp,
812 ( keypress,
813 window->State.MouseX, window->State.MouseY )
814 );
815
816 fgState.Modifiers = INVALID_MODIFIERS;
817
818 /* SYSKEY events should be sent to default window proc for system to handle them */
819 if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
820 return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
821 else
822 return 1;
823 }
824
825 SFG_Window* fghWindowUnderCursor(SFG_Window *window)
826 {
827 /* Check if the current window that the mouse is over is a child window
828 * of the window the message was sent to. Some events only sent to main window,
829 * and when handling some messages, we need to make sure that we process
830 * callbacks on the child window instead. This mirrors how GLUT does things.
831 * returns either the original window or the found child.
832 */
833 if (window && window->Children.First) /* This window has childs */
834 {
835 HWND hwnd;
836 SFG_Window* child_window;
837
838 /* Get mouse position at time of message */
839 DWORD mouse_pos_dw = GetMessagePos();
840 POINT mouse_pos;
841 mouse_pos.x = GET_X_LPARAM(mouse_pos_dw);
842 mouse_pos.y = GET_Y_LPARAM(mouse_pos_dw);
843 ScreenToClient( window->Window.Handle, &mouse_pos );
844
845 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
846 if (hwnd && hwnd!=window->Window.Handle) /* can be NULL if mouse outside parent by the time we get here, or can be same as parent if we didn't find a child */
847 {
848 child_window = fgWindowByHandle(hwnd);
849 if (child_window) /* Verify we got a FreeGLUT window */
850 {
851 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
852 window = fghWindowUnderCursor(child_window);
853 }
854 }
855 }
856
857 return window;
858 }
859
860 /*
861 * The window procedure for handling Win32 events
862 */
863 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
864 {
865 SFG_Window *window;
866 LRESULT lRet = 1;
867 static int setCaptureActive = 0;
868
869 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
870
871 window = fgWindowByHandle( hWnd );
872
873 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
874 return DefWindowProc( hWnd, uMsg, wParam, lParam );
875
876 /* printf ( "Window %3d message %s (<%04x>) %12d %12d\n", window?window->ID:0,
877 WMMsg2Str(uMsg), uMsg, wParam, lParam ); */
878
879 switch( uMsg )
880 {
881 case WM_CREATE:
882 /* The window structure is passed as the creation structure parameter... */
883 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
884 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
885 "fgPlatformWindowProc" );
886
887 window->Window.Handle = hWnd;
888 window->Window.pContext.Device = GetDC( hWnd );
889 if( window->IsMenu )
890 {
891 unsigned int current_DisplayMode = fgState.DisplayMode;
892 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
893 #if !defined(_WIN32_WCE)
894 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
895 #endif
896 fgState.DisplayMode = current_DisplayMode;
897
898 if( fgStructure.MenuContext )
899 wglMakeCurrent( window->Window.pContext.Device,
900 fgStructure.MenuContext->MContext
901 );
902 else
903 {
904 fgStructure.MenuContext =
905 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
906 fgStructure.MenuContext->MContext =
907 wglCreateContext( window->Window.pContext.Device );
908 }
909
910 /* window->Window.Context = wglGetCurrentContext (); */
911 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
912 }
913 else
914 {
915 #if !defined(_WIN32_WCE)
916 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
917 #endif
918
919 if( ! fgState.UseCurrentContext )
920 window->Window.Context =
921 wglCreateContext( window->Window.pContext.Device );
922 else
923 {
924 window->Window.Context = wglGetCurrentContext( );
925 if( ! window->Window.Context )
926 window->Window.Context =
927 wglCreateContext( window->Window.pContext.Device );
928 }
929
930 #if !defined(_WIN32_WCE)
931 fgNewWGLCreateContext( window );
932 #endif
933 }
934
935 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
936
937 #if defined(_WIN32_WCE)
938 /* Take over button handling */
939 {
940 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
941 if (dxDllLib)
942 {
943 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
944 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
945 }
946
947 if(GXOpenInput_)
948 (*GXOpenInput_)();
949 if(GXGetDefaultKeys_)
950 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
951 }
952
953 #endif /* defined(_WIN32_WCE) */
954 break;
955
956 case WM_SIZE:
957 /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */
958
959 /* Update visibility state of the window */
960 if (wParam==SIZE_MINIMIZED)
961 fghPlatformOnWindowStatusNotify(window,GL_FALSE,GL_FALSE);
962 else if (wParam==SIZE_RESTORED && !window->State.Visible)
963 fghPlatformOnWindowStatusNotify(window,GL_TRUE,GL_FALSE);
964
965 /* Check window visible, we don't want do anything when we get a WM_SIZE because the user or glutIconifyWindow minimized the window */
966 if( window->State.Visible )
967 {
968 int width, height;
969 #if defined(_WIN32_WCE)
970 width = HIWORD(lParam);
971 height = LOWORD(lParam);
972 #else
973 width = LOWORD(lParam);
974 height = HIWORD(lParam);
975 #endif /* defined(_WIN32_WCE) */
976
977 /* Update state and call callback, if there was a change */
978 fghOnReshapeNotify(window, width, height, GL_FALSE);
979 }
980
981 /* according to docs, should return 0 */
982 lRet = 0;
983 break;
984
985 case WM_SIZING:
986 {
987 /* User resize-dragging the window, call reshape callback and
988 * force redisplay so display keeps running during dragging.
989 * Screen still wont update when not moving the cursor though...
990 */
991 RECT rect;
992 /* PRECT prect = (PRECT) lParam;
993 printf("WM_SIZING: nc-area: %i,%i\n",prect->right-prect->left,prect->bottom-prect->top); */
994 /* Get client area, the rect in lParam is including non-client area. */
995 fghGetClientArea(&rect,window,FALSE);
996
997 /* We'll get a WM_SIZE as well, but as state has
998 * already been updated here, the fghOnReshapeNotify
999 * in the handler for that message doesn't do anything.
1000 */
1001 fghOnReshapeNotify(window, rect.right-rect.left, rect.bottom-rect.top, GL_FALSE);
1002
1003 /* Now directly call the drawing function to update
1004 * window and window's childs.
1005 * This mimics the WM_PAINT messages that are received during
1006 * resizing. Note that we don't have a WM_MOVING handler
1007 * as move-dragging doesn't generate WM_MOVE or WM_PAINT
1008 * messages until the mouse is released.
1009 */
1010 fghRedrawWindowAndChildren(window);
1011 }
1012
1013 /* according to docs, should return TRUE */
1014 lRet = TRUE;
1015 break;
1016
1017 case WM_MOVE:
1018 {
1019 /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */
1020 if (!IsIconic(window->Window.Handle))
1021 {
1022 RECT windowRect;
1023
1024 /* lParam contains coordinates of top-left of client area.
1025 * Get top-left of non-client area of window, matching coordinates of
1026 * glutInitPosition and glutPositionWindow, but not those of
1027 * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
1028 * top-left of client area.
1029 */
1030 GetWindowRect( window->Window.Handle, &windowRect );
1031
1032 if (window->Parent)
1033 {
1034 /* For child window, we should return relative to upper-left
1035 * of parent's client area.
1036 */
1037 POINT topleft;
1038 topleft.x = windowRect.left;
1039 topleft.y = windowRect.top;
1040
1041 ScreenToClient(window->Parent->Window.Handle,&topleft);
1042 windowRect.left = topleft.x;
1043 windowRect.top = topleft.y;
1044 }
1045
1046 /* Update state and call callback, if there was a change */
1047 fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_FALSE);
1048 }
1049 }
1050
1051 /* according to docs, should return 0 */
1052 lRet = 0;
1053 break;
1054
1055 case WM_SETFOCUS:
1056 /*printf("WM_SETFOCUS: %p\n", window );*/
1057 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1058
1059 SetActiveWindow( window->Window.Handle );
1060 UpdateWindow ( hWnd );
1061
1062 break;
1063
1064 case WM_KILLFOCUS:
1065 /*printf("WM_KILLFOCUS: %p\n", window ); */
1066 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1067
1068 /* Check if there are any open menus that need to be closed */
1069 fgPlatformCheckMenuDeactivate((HWND)wParam);
1070 break;
1071
1072 case WM_MOUSEACTIVATE:
1073 /* Clicks should not activate the menu.
1074 * Especially important when clicking on a menu's submenu item which has no effect.
1075 */
1076 /*printf("WM_MOUSEACTIVATE\n");*/
1077 if (window->IsMenu)
1078 lRet = MA_NOACTIVATEANDEAT;
1079 else
1080 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1081 break;
1082
1083 case WM_NCLBUTTONDOWN:
1084 case WM_NCMBUTTONDOWN:
1085 case WM_NCRBUTTONDOWN:
1086 {
1087 SFG_Menu *menu;
1088 if (fgState.ActiveMenus && (menu = fgGetActiveMenu()))
1089 /* user clicked non-client area of window while a menu is open. Close menu */
1090 fgDeactivateMenu(menu->ParentWindow);
1091
1092 /* and always pass to DefWindowProc */
1093 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1094 }
1095 break;
1096
1097 #if 0
1098 case WM_ACTIVATE:
1099 /* printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam)); */
1100 if (LOWORD(wParam) != WA_INACTIVE)
1101 {
1102 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
1103 window->State.Cursor ); */
1104 fgSetCursor( window, window->State.Cursor );
1105 }
1106
1107 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1108 break;
1109 #endif
1110
1111 #if _MSC_VER > 1400
1112 case WM_SETCURSOR:
1113 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
1114 if( LOWORD( lParam ) == HTCLIENT )
1115 {
1116 if (!window->State.pWState.MouseTracking)
1117 {
1118 TRACKMOUSEEVENT tme;
1119
1120 /* Cursor just entered window, set cursor look */
1121 fgSetCursor ( window, window->State.Cursor ) ;
1122
1123 /* If an EntryFunc callback is specified by the user, also
1124 * invoke that callback and start mouse tracking so that
1125 * we get a WM_MOUSELEAVE message
1126 */
1127 if (FETCH_WCB( *window, Entry ))
1128 {
1129 SFG_Window* saved_window = fgStructure.CurrentWindow;
1130 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
1131 fgSetWindow(saved_window);
1132
1133 tme.cbSize = sizeof(TRACKMOUSEEVENT);
1134 tme.dwFlags = TME_LEAVE;
1135 tme.hwndTrack = window->Window.Handle;
1136 TrackMouseEvent(&tme);
1137
1138 window->State.pWState.MouseTracking = TRUE;
1139 }
1140 }
1141 }
1142 else
1143 /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
1144 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1145 break;
1146 #endif
1147
1148 case WM_MOUSELEAVE:
1149 {
1150 /* NB: This message is only received when a EntryFunc callback
1151 * is specified by the user, as that is the only condition under
1152 * which mouse tracking is setup in WM_SETCURSOR handler above
1153 */
1154 SFG_Window* saved_window = fgStructure.CurrentWindow;
1155 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
1156 fgSetWindow(saved_window);
1157
1158 window->State.pWState.MouseTracking = FALSE;
1159 lRet = 0; /* As per docs, must return zero */
1160 }
1161 break;
1162
1163 case WM_SHOWWINDOW:
1164 /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */
1165 if (wParam)
1166 {
1167 fghPlatformOnWindowStatusNotify(window, GL_TRUE, GL_FALSE);
1168 window->State.WorkMask |= GLUT_DISPLAY_WORK;
1169 }
1170 else
1171 {
1172 fghPlatformOnWindowStatusNotify(window, GL_FALSE, GL_FALSE);
1173 window->State.WorkMask &= ~GLUT_DISPLAY_WORK;
1174 }
1175 break;
1176
1177 case WM_PAINT:
1178 {
1179 RECT rect;
1180
1181 /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */
1182 if (GetUpdateRect(hWnd,&rect,FALSE))
1183 {
1184 /* Dummy begin/end paint to validate rect that needs
1185 * redrawing, then signal that a redisplay is needed.
1186 * This allows us full control about when we do any
1187 * redrawing, and is the same as what original GLUT
1188 * does.
1189 */
1190 PAINTSTRUCT ps;
1191 BeginPaint( hWnd, &ps );
1192 EndPaint( hWnd, &ps );
1193
1194 window->State.WorkMask |= GLUT_DISPLAY_WORK;
1195 }
1196 lRet = 0; /* As per docs, should return 0 */
1197 }
1198 break;
1199
1200 case WM_CLOSE:
1201 fgDestroyWindow ( window );
1202 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
1203 PostQuitMessage(0);
1204 break;
1205
1206 case WM_DESTROY:
1207 /*
1208 * The window already got destroyed, so don't bother with it.
1209 */
1210 return 0;
1211
1212 case WM_MOUSEMOVE:
1213 {
1214 /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
1215 #if defined(_WIN32_WCE)
1216 window->State.MouseX = 320-HIWORD( lParam ); /* XXX: Docs say x should be loword and y hiword? */
1217 window->State.MouseY = LOWORD( lParam );
1218 #else
1219 window->State.MouseX = GET_X_LPARAM( lParam );
1220 window->State.MouseY = GET_Y_LPARAM( lParam );
1221 #endif /* defined(_WIN32_WCE) */
1222 /* Restrict to [-32768, 32767] to match X11 behaviour */
1223 /* See comment in "freeglut_developer" mailing list 10/4/04 */
1224 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
1225 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
1226
1227 if ( window->ActiveMenu )
1228 {
1229 fgUpdateMenuHighlight( window->ActiveMenu );
1230 break;
1231 }
1232
1233 fgState.Modifiers = fgPlatformGetModifiers( );
1234
1235 if( ( wParam & MK_LBUTTON ) ||
1236 ( wParam & MK_MBUTTON ) ||
1237 ( wParam & MK_RBUTTON ) )
1238 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
1239 window->State.MouseY ) );
1240 else
1241 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
1242 window->State.MouseY ) );
1243
1244 fgState.Modifiers = INVALID_MODIFIERS;
1245 }
1246 break;
1247
1248 case WM_LBUTTONDOWN:
1249 case WM_MBUTTONDOWN:
1250 case WM_RBUTTONDOWN:
1251 case WM_LBUTTONUP:
1252 case WM_MBUTTONUP:
1253 case WM_RBUTTONUP:
1254 {
1255 GLboolean pressed = GL_TRUE;
1256 int button;
1257
1258 /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
1259 #if defined(_WIN32_WCE)
1260 window->State.MouseX = 320-HIWORD( lParam ); /* XXX: Docs say x should be loword and y hiword? */
1261 window->State.MouseY = LOWORD( lParam );
1262 #else
1263 window->State.MouseX = GET_X_LPARAM( lParam );
1264 window->State.MouseY = GET_Y_LPARAM( lParam );
1265 #endif /* defined(_WIN32_WCE) */
1266
1267 /* Restrict to [-32768, 32767] to match X11 behaviour */
1268 /* See comment in "freeglut_developer" mailing list 10/4/04 */
1269 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
1270 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
1271
1272 switch( uMsg )
1273 {
1274 case WM_LBUTTONDOWN:
1275 pressed = GL_TRUE;
1276 button = GLUT_LEFT_BUTTON;
1277 break;
1278 case WM_MBUTTONDOWN:
1279 pressed = GL_TRUE;
1280 button = GLUT_MIDDLE_BUTTON;
1281 break;
1282 case WM_RBUTTONDOWN:
1283 pressed = GL_TRUE;
1284 button = GLUT_RIGHT_BUTTON;
1285 break;
1286 case WM_LBUTTONUP:
1287 pressed = GL_FALSE;
1288 button = GLUT_LEFT_BUTTON;
1289 break;
1290 case WM_MBUTTONUP:
1291 pressed = GL_FALSE;
1292 button = GLUT_MIDDLE_BUTTON;
1293 break;
1294 case WM_RBUTTONUP:
1295 pressed = GL_FALSE;
1296 button = GLUT_RIGHT_BUTTON;
1297 break;
1298 default:
1299 pressed = GL_FALSE;
1300 button = -1;
1301 break;
1302 }
1303
1304 #if !defined(_WIN32_WCE)
1305 if( GetSystemMetrics( SM_SWAPBUTTON ) )
1306 {
1307 if( button == GLUT_LEFT_BUTTON )
1308 button = GLUT_RIGHT_BUTTON;
1309 else
1310 if( button == GLUT_RIGHT_BUTTON )
1311 button = GLUT_LEFT_BUTTON;
1312 }
1313 #endif /* !defined(_WIN32_WCE) */
1314
1315 if( button == -1 )
1316 return DefWindowProc( hWnd, uMsg, lParam, wParam );
1317
1318 /*
1319 * Do not execute the application's mouse callback if a menu
1320 * is hooked to this button. In that case an appropriate
1321 * private call should be generated.
1322 */
1323 if( fgCheckActiveMenu( window, button, pressed,
1324 window->State.MouseX, window->State.MouseY ) )
1325 break;
1326
1327 /* Set capture so that the window captures all the mouse messages
1328 *
1329 * The mouse is not released from the window until all buttons have
1330 * been released, even if the user presses a button in another window.
1331 * This is consistent with the behavior on X11.
1332 */
1333 if ( pressed == GL_TRUE )
1334 {
1335 if (!setCaptureActive)
1336 SetCapture ( window->Window.Handle ) ;
1337 setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
1338 }
1339 else if (!fgGetKeyState(VK_LBUTTON) && !fgGetKeyState(VK_MBUTTON) && !fgGetKeyState(VK_RBUTTON))
1340 /* Make sure all mouse buttons are released before releasing capture */
1341 ReleaseCapture () ;
1342
1343 if( ! FETCH_WCB( *window, Mouse ) )
1344 break;
1345
1346 fgSetWindow( window );
1347 fgState.Modifiers = fgPlatformGetModifiers( );
1348
1349 INVOKE_WCB(
1350 *window, Mouse,
1351 ( button,
1352 pressed ? GLUT_DOWN : GLUT_UP,
1353 window->State.MouseX,
1354 window->State.MouseY
1355 )
1356 );
1357
1358 fgState.Modifiers = INVALID_MODIFIERS;
1359
1360 /* As per docs, should return zero */
1361 lRet = 0;
1362 }
1363 break;
1364
1365 case WM_MOUSEWHEEL:
1366 {
1367 int wheel_number = 0; /* Only one scroll wheel on windows */
1368 #if defined(_WIN32_WCE)
1369 int modkeys = LOWORD(wParam);
1370 short ticks = (short)HIWORD(wParam);
1371 /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
1372 xPos = LOWORD(lParam); -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong)
1373 yPos = HIWORD(lParam);
1374 */
1375 #else
1376 /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
1377 short ticks = HIWORD( wParam );
1378 /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
1379 window->State.MouseX = GET_X_LPARAM( lParam );
1380 window->State.MouseY = GET_Y_LPARAM( lParam );
1381 */
1382 #endif /* defined(_WIN32_WCE) */
1383
1384 window = fghWindowUnderCursor(window);
1385
1386 fgState.MouseWheelTicks += ticks;
1387 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
1388 {
1389 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
1390
1391 if( ! FETCH_WCB( *window, MouseWheel ) &&
1392 ! FETCH_WCB( *window, Mouse ) )
1393 break;
1394
1395 fgSetWindow( window );
1396 fgState.Modifiers = fgPlatformGetModifiers( );
1397
1398 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
1399 {
1400 if( FETCH_WCB( *window, MouseWheel ) )
1401 INVOKE_WCB( *window, MouseWheel,
1402 ( wheel_number,
1403 direction,
1404 window->State.MouseX,
1405 window->State.MouseY
1406 )
1407 );
1408 else /* No mouse wheel, call the mouse button callback twice */
1409 {
1410 /*
1411 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
1412 * " " one +1 to 5, -1 to 6, ...
1413 *
1414 * XXX The below assumes that you have no more than 3 mouse
1415 * XXX buttons. Sorry.
1416 */
1417 int button = wheel_number * 2 + 3;
1418 if( direction < 0 )
1419 ++button;
1420 INVOKE_WCB( *window, Mouse,
1421 ( button, GLUT_DOWN,
1422 window->State.MouseX, window->State.MouseY )
1423 );
1424 INVOKE_WCB( *window, Mouse,
1425 ( button, GLUT_UP,
1426 window->State.MouseX, window->State.MouseY )
1427 );
1428 }
1429
1430 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
1431 }
1432
1433 fgState.Modifiers = INVALID_MODIFIERS;
1434 }
1435 /* Per docs, should return zero */
1436 lRet = 0;
1437 }
1438 break ;
1439
1440 case WM_SYSKEYDOWN:
1441 case WM_KEYDOWN:
1442 {
1443 window = fghWindowUnderCursor(window);
1444 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
1445 }
1446 break;
1447
1448 case WM_SYSKEYUP:
1449 case WM_KEYUP:
1450 {
1451 window = fghWindowUnderCursor(window);
1452 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
1453 }
1454 break;
1455
1456 case WM_SYSCHAR:
1457 case WM_CHAR:
1458 {
1459 window = fghWindowUnderCursor(window);
1460
1461 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
1462 break;
1463
1464 fgState.Modifiers = fgPlatformGetModifiers( );
1465 INVOKE_WCB( *window, KeyboardExt,
1466 ( (int)wParam, window->State.MouseX, window->State.MouseY )
1467 );
1468 if (wParam < 256)
1469 INVOKE_WCB( *window, Keyboard,
1470 ( (unsigned char)wParam, window->State.MouseX, window->State.MouseY )
1471 );
1472 fgState.Modifiers = INVALID_MODIFIERS;
1473 }
1474 break;
1475
1476 case WM_CAPTURECHANGED:
1477 if (!lParam || !fgWindowByHandle((HWND)lParam))
1478 /* Capture released or capture taken by non-FreeGLUT window */
1479 setCaptureActive = 0;
1480 /* Docs advise a redraw */
1481 InvalidateRect( hWnd, NULL, GL_FALSE );
1482 UpdateWindow(hWnd);
1483 lRet = 0; /* Per docs, should return zero */
1484 break;
1485
1486 #if !defined(_WIN32_WCE)
1487 case WM_SYNCPAINT: /* 0x0088 */
1488 /* Another window has moved, need to update this one */
1489 window->State.WorkMask |= GLUT_DISPLAY_WORK;
1490 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1491 /* Help screen says this message must be passed to "DefWindowProc" */
1492 break;
1493
1494 case WM_DISPLAYCHANGE: /* 0x007E */
1495 /* The system display resolution/depth has changed */
1496 fgDisplay.ScreenWidth = LOWORD(lParam);
1497 fgDisplay.ScreenHeight = HIWORD(lParam);
1498 break;
1499
1500 case WM_SYSCOMMAND : /* 0x0112 */
1501 {
1502 /*
1503 * We have received a system command message. Try to act on it.
1504 * The commands are passed in through the "wParam" parameter:
1505 * The least significant digit seems to be which edge of the window
1506 * is being used for a resize event:
1507 * 4 3 5
1508 * 1 2
1509 * 7 6 8
1510 * Congratulations and thanks to Richard Rauch for figuring this out..
1511 */
1512 switch ( wParam & 0xfff0 )
1513 {
1514 case SC_SIZE :
1515 break ;
1516
1517 case SC_MOVE :
1518 break ;
1519
1520 case SC_MINIMIZE :
1521 /* User has clicked on the "-" to minimize the window */
1522 /* Turning off the visibility is handled in WM_SIZE handler */
1523
1524 break ;
1525
1526 case SC_MAXIMIZE :
1527 break ;
1528
1529 case SC_NEXTWINDOW :
1530 break ;
1531
1532 case SC_PREVWINDOW :
1533 break ;
1534
1535 case SC_CLOSE :
1536 /* Followed very closely by a WM_CLOSE message */
1537 break ;
1538
1539 case SC_VSCROLL :
1540 break ;
1541
1542 case SC_HSCROLL :
1543 break ;
1544
1545 case SC_MOUSEMENU :
1546 break ;
1547
1548 case SC_KEYMENU :
1549 break ;
1550
1551 case SC_ARRANGE :
1552 break ;
1553
1554 case SC_RESTORE :
1555 break ;
1556
1557 case SC_TASKLIST :
1558 break ;
1559
1560 case SC_SCREENSAVE :
1561 break ;
1562
1563 case SC_HOTKEY :
1564 break ;
1565
1566 #if(WINVER >= 0x0400)
1567 case SC_DEFAULT :
1568 break ;
1569
1570 case SC_MONITORPOWER :
1571 break ;
1572
1573 case SC_CONTEXTHELP :
1574 break ;
1575 #endif /* WINVER >= 0x0400 */
1576
1577 default:
1578 #if _DEBUG
1579 fgWarning( "Unknown wParam type 0x%x", wParam );
1580 #endif
1581 break;
1582 }
1583 }
1584 #endif /* !defined(_WIN32_WCE) */
1585
1586 /* We need to pass the message on to the operating system as well */
1587 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1588 break;
1589
1590 #ifdef WM_TOUCH
1591 /* handle multi-touch messages */
1592 case WM_TOUCH:
1593 {
1594 unsigned int numInputs = (unsigned int)wParam;
1595 unsigned int i = 0;
1596 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1597
1598 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1599 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1600 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1601 }
1602
1603 if (!fghGetTouchInputInfo) {
1604 free( (void*)ti );
1605 break;
1606 }
1607
1608 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1609 /* Handle each contact point */
1610 for (i = 0; i < numInputs; ++i ) {
1611
1612 POINT tp;
1613 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1614 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1615 ScreenToClient( hWnd, &tp );
1616
1617 ti[i].dwID = ti[i].dwID * 2;
1618
1619 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1620 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1621 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1622 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1623 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1624 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1625 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1626 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1627 }
1628 }
1629 }
1630 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1631 free( (void*)ti );
1632 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1633 break;
1634 }
1635 #endif
1636 default:
1637 /* Handle unhandled messages */
1638 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1639 break;
1640 }
1641
1642 return lRet;
1643 }
1644
1645
1646 /* deal with work list items */
1647 void fgPlatformInitWork(SFG_Window* window)
1648 {
1649 RECT windowRect;
1650
1651 /* Notify windowStatus/visibility */
1652 fghPlatformOnWindowStatusNotify(window, window->State.Visible, GL_TRUE);
1653
1654 /* get and notify window's position */
1655 GetWindowRect(window->Window.Handle,&windowRect);
1656 fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_TRUE);
1657
1658 /* get and notify window's size */
1659 GetClientRect(window->Window.Handle,&windowRect);
1660 fghOnReshapeNotify(window, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, GL_TRUE);
1661 }
1662
1663 /* On windows we can position, resize and change z order at the same time */
1664 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
1665 {
1666 UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
1667 HWND insertAfter = HWND_TOP;
1668 RECT clientRect;
1669
1670 #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1671 if (workMask & GLUT_FULL_SCREEN_WORK)
1672 {
1673 /* This asks us to toggle fullscreen mode */
1674 flags |= SWP_FRAMECHANGED;
1675
1676 if (window->State.IsFullscreen)
1677 {
1678 /* If we are fullscreen, resize the current window back to its original size */
1679 /* printf("OldRect %i,%i to %i,%i\n",window->State.pWState.OldRect.left,window->State.pWState.OldRect.top,window->State.pWState.OldRect.right,window->State.pWState.OldRect.bottom); */
1680
1681 /* restore style of window before making it fullscreen */
1682 SetWindowLong(window->Window.Handle, GWL_STYLE, window->State.pWState.OldStyle);
1683 SetWindowLong(window->Window.Handle, GWL_EXSTYLE, window->State.pWState.OldStyleEx);
1684
1685 /* Then set up resize/reposition, unless user already queued up reshape/position work */
1686 if (!(workMask & GLUT_POSITION_WORK))
1687 {
1688 workMask |= GLUT_POSITION_WORK;
1689 window->State.DesiredXpos = window->State.pWState.OldRect.left;
1690 window->State.DesiredYpos = window->State.pWState.OldRect.top;
1691 }
1692 if (!(workMask & GLUT_SIZE_WORK))
1693 {
1694 workMask |= GLUT_SIZE_WORK;
1695 window->State.DesiredWidth = window->State.pWState.OldRect.right - window->State.pWState.OldRect.left;
1696 window->State.DesiredHeight = window->State.pWState.OldRect.bottom - window->State.pWState.OldRect.top;
1697 }
1698
1699 /* We'll finish off the fullscreen operation below after the other GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK */
1700 }
1701 else
1702 {
1703 /* we are currently not fullscreen, go to fullscreen:
1704 * remove window decoration and then maximize
1705 */
1706 RECT rect;
1707 HMONITOR hMonitor;
1708 MONITORINFO mi;
1709
1710 /* save current window rect, style, exstyle and maximized state */
1711 window->State.pWState.OldMaximized = !!IsZoomed(window->Window.Handle);
1712 if (window->State.pWState.OldMaximized)
1713 /* We force the window into restored mode before going
1714 * fullscreen because Windows doesn't seem to hide the
1715 * taskbar if the window is in the maximized state.
1716 */
1717 SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
1718
1719 fghGetClientArea( &window->State.pWState.OldRect, window, GL_TRUE );
1720 window->State.pWState.OldStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
1721 window->State.pWState.OldStyleEx = GetWindowLong(window->Window.Handle, GWL_EXSTYLE);
1722
1723 /* remove decorations from style */
1724 SetWindowLong(window->Window.Handle, GWL_STYLE,
1725 window->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME));
1726 SetWindowLong(window->Window.Handle, GWL_EXSTYLE,
1727 window->State.pWState.OldStyleEx & ~(WS_EX_DLGMODALFRAME |
1728 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
1729
1730 /* For fullscreen mode, find the monitor that is covered the most
1731 * by the window and get its rect as the resize target.
1732 */
1733 hMonitor= MonitorFromWindow(window->Window.Handle, MONITOR_DEFAULTTONEAREST);
1734 mi.cbSize = sizeof(mi);
1735 GetMonitorInfo(hMonitor, &mi);
1736 rect = mi.rcMonitor;
1737
1738 /* then setup window resize, overwriting other work queued on the window */
1739 window->State.WorkMask |= GLUT_POSITION_WORK | GLUT_SIZE_WORK;
1740 window->State.WorkMask &= ~GLUT_ZORDER_WORK;
1741 window->State.DesiredXpos = rect.left;
1742 window->State.DesiredYpos = rect.top;
1743 window->State.DesiredWidth = rect.right - rect.left;
1744 window->State.DesiredHeight = rect.bottom - rect.top;
1745 }
1746 }
1747 #endif /*!defined(_WIN32_WCE) */
1748
1749 /* Now deal with normal position, reshape and z order requests (some might have been set when handling GLUT_FULLSCREEN_WORK above */
1750 {
1751 /* get rect describing window's current position and size,
1752 * in screen coordinates and in FreeGLUT format
1753 * (size (right-left, bottom-top) is client area size, top and left
1754 * are outside of window including decorations).
1755 */
1756 fghGetClientArea( &clientRect, window, TRUE );
1757
1758 if (workMask & GLUT_POSITION_WORK)
1759 {
1760 flags &= ~SWP_NOMOVE;
1761
1762 /* Move rect so that top-left is at requested position */
1763 /* This also automatically makes sure that child window requested coordinates are relative
1764 * to top-left of parent's client area (needed input for SetWindowPos on child windows),
1765 * so no need to further correct rect for child windows below (childs don't have decorations either).
1766 */
1767 OffsetRect(&clientRect,window->State.DesiredXpos-clientRect.left,window->State.DesiredYpos-clientRect.top);
1768 }
1769 if (workMask & GLUT_SIZE_WORK)
1770 {
1771 flags &= ~SWP_NOSIZE;
1772
1773 /* Note on maximizing behavior of Windows: the resize borders are off
1774 * the screen such that the client area extends all the way from the
1775 * leftmost corner to the rightmost corner to maximize screen real
1776 * estate. A caption is still shown however to allow interaction with
1777 * the window controls. This is default behavior of Windows that
1778 * FreeGLUT sticks with. To alter, one would have to check if
1779 * WS_MAXIMIZE style is set when a resize event is triggered, and
1780 * then manually correct the windowRect to put the borders back on
1781 * screen.
1782 */
1783
1784 /* Set new size of window, WxH specify client area */
1785 clientRect.right = clientRect.left + window->State.DesiredWidth;
1786 clientRect.bottom = clientRect.top + window->State.DesiredHeight;
1787 }
1788 if (workMask & GLUT_ZORDER_WORK)
1789 {
1790 flags &= ~SWP_NOZORDER;
1791
1792 /* Could change this to push it down or up one window at a time with some
1793 * more code using GetWindow with GW_HWNDPREV and GW_HWNDNEXT.
1794 * What would be consistent with X11? Win32 GLUT does what we do here...
1795 */
1796 if (window->State.DesiredZOrder < 0)
1797 insertAfter = HWND_BOTTOM;
1798 }
1799 }
1800
1801 /* Adjust for window decorations
1802 * Child windows don't have decoration, so no need to correct
1803 */
1804 if (!window->Parent)
1805 /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
1806 fghComputeWindowRectFromClientArea_QueryWindow(&clientRect,window,TRUE);
1807
1808 /* Do the requested positioning, moving, and z order push/pop. */
1809 SetWindowPos( window->Window.Handle,
1810 insertAfter,
1811 clientRect.left, clientRect.top,
1812 clientRect.right - clientRect.left,
1813 clientRect.bottom- clientRect.top,
1814 flags
1815 );
1816
1817 /* Finish off the fullscreen operation we were doing, if any */
1818 if (workMask & GLUT_FULL_SCREEN_WORK)
1819 {
1820 if (window->State.IsFullscreen)
1821 {
1822 /* leaving fullscreen, restore maximized state, if any */
1823 if (window->State.pWState.OldMaximized)
1824 SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
1825
1826 window->State.IsFullscreen = GL_FALSE;
1827 }
1828 else
1829 window->State.IsFullscreen = GL_TRUE;
1830 }
1831 }
1832
1833
1834 void fgPlatformVisibilityWork(SFG_Window* window)
1835 {
1836 /* Visibility status of window gets updated in the WM_SHOWWINDOW and WM_SIZE handlers */
1837 int cmdShow = 0;
1838 SFG_Window *win = window;
1839 switch (window->State.DesiredVisibility)
1840 {
1841 case DesireHiddenState:
1842 cmdShow = SW_HIDE;
1843 break;
1844 case DesireIconicState:
1845 cmdShow = SW_MINIMIZE;
1846 /* Call on top-level window */
1847 while (win->Parent)
1848 win = win->Parent;
1849 break;
1850 case DesireNormalState:
1851 if (win->IsMenu && !fgStructure.GameModeWindow)
1852 cmdShow = SW_SHOWNA; /* Just show, don't activate window if its a menu. Only exception is when there is a gamemode window as the menu would pop under it when we do this... */
1853 else
1854 cmdShow = SW_SHOW;
1855 break;
1856 }
1857
1858 ShowWindow( win->Window.Handle, cmdShow );
1859 }