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