cleanup a debug statement
[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();
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 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
582 {
583     static unsigned char lControl = 0, lShift = 0, lAlt = 0,
584                          rControl = 0, rShift = 0, rAlt = 0;
585
586     int keypress = -1;
587     
588     /* if keydown, check for repeat */
589     /* If repeat is globally switched off, it cannot be switched back on per window.
590      * But if it is globally switched on, it can be switched off per window. This matches
591      * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
592      * global state switch.
593      */
594     if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
595         return 1;
596     
597     /* Remember the current modifiers state so user can query it from their callback */
598     fgState.Modifiers = fgPlatformGetModifiers( );
599
600     /* Convert the Win32 keystroke codes to GLUTtish way */
601 #   define KEY(a,b) case a: keypress = b; break;
602
603     switch( wParam )
604     {
605         KEY( VK_F1,     GLUT_KEY_F1        );
606         KEY( VK_F2,     GLUT_KEY_F2        );
607         KEY( VK_F3,     GLUT_KEY_F3        );
608         KEY( VK_F4,     GLUT_KEY_F4        );
609         KEY( VK_F5,     GLUT_KEY_F5        );
610         KEY( VK_F6,     GLUT_KEY_F6        );
611         KEY( VK_F7,     GLUT_KEY_F7        );
612         KEY( VK_F8,     GLUT_KEY_F8        );
613         KEY( VK_F9,     GLUT_KEY_F9        );
614         KEY( VK_F10,    GLUT_KEY_F10       );
615         KEY( VK_F11,    GLUT_KEY_F11       );
616         KEY( VK_F12,    GLUT_KEY_F12       );
617         KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
618         KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
619         KEY( VK_HOME,   GLUT_KEY_HOME      );
620         KEY( VK_END,    GLUT_KEY_END       );
621         KEY( VK_LEFT,   GLUT_KEY_LEFT      );
622         KEY( VK_UP,     GLUT_KEY_UP        );
623         KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
624         KEY( VK_DOWN,   GLUT_KEY_DOWN      );
625         KEY( VK_INSERT, GLUT_KEY_INSERT    );
626
627     /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
628      * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
629      * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
630      */
631 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
632     if (!keyStateVar && GetAsyncKeyState ( winKey ))\
633     {\
634         keypress   = glutKey;\
635         keyStateVar = 1;\
636     }\
637     else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
638     {\
639         keypress   = glutKey;\
640         keyStateVar = 0;\
641     }
642     case VK_CONTROL:
643         ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
644         ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
645         break;
646     case VK_SHIFT:
647         ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
648         ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
649         break;
650     case VK_MENU:
651         ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
652         ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
653         break;
654 #undef ASYNC_KEY_EVENT
655
656     case VK_DELETE:
657         /* The delete key should be treated as an ASCII keypress: */
658         if (keydown)
659             INVOKE_WCB( *window, Keyboard,
660                         ( 127, window->State.MouseX, window->State.MouseY )
661             );
662         else
663             INVOKE_WCB( *window, KeyboardUp,
664                         ( 127, window->State.MouseX, window->State.MouseY )
665             );
666         break;
667
668 #if !defined(_WIN32_WCE)
669     default:
670         /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
671         if (!keydown)
672         {
673             BYTE state[ 256 ];
674             WORD code[ 2 ];
675
676             GetKeyboardState( state );
677
678             if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
679                 wParam=code[ 0 ];
680
681             INVOKE_WCB( *window, KeyboardUp,
682                    ( (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 */
683                         window->State.MouseX, window->State.MouseY )
684             );
685         }
686 #endif
687     }
688
689 #if defined(_WIN32_WCE)
690     if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
691     {
692         if(wParam==(unsigned)gxKeyList.vkRight)
693             keypress = GLUT_KEY_RIGHT;
694         else if(wParam==(unsigned)gxKeyList.vkLeft)
695             keypress = GLUT_KEY_LEFT;
696         else if(wParam==(unsigned)gxKeyList.vkUp)
697             keypress = GLUT_KEY_UP;
698         else if(wParam==(unsigned)gxKeyList.vkDown)
699             keypress = GLUT_KEY_DOWN;
700         else if(wParam==(unsigned)gxKeyList.vkA)
701             keypress = GLUT_KEY_F1;
702         else if(wParam==(unsigned)gxKeyList.vkB)
703             keypress = GLUT_KEY_F2;
704         else if(wParam==(unsigned)gxKeyList.vkC)
705             keypress = GLUT_KEY_F3;
706         else if(wParam==(unsigned)gxKeyList.vkStart)
707             keypress = GLUT_KEY_F4;
708     }
709 #endif
710     
711     if( keypress != -1 )
712         if (keydown)
713             INVOKE_WCB( *window, Special,
714                         ( keypress,
715                             window->State.MouseX, window->State.MouseY )
716             );
717         else
718             INVOKE_WCB( *window, SpecialUp,
719                         ( keypress,
720                             window->State.MouseX, window->State.MouseY )
721             );
722
723     fgState.Modifiers = INVALID_MODIFIERS;
724
725     /* SYSKEY events should be sent to default window proc for system to handle them */
726     if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
727         return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
728     else
729         return 1;
730 }
731
732 SFG_Window* fghWindowUnderCursor(SFG_Window *window)
733 {
734     /* Check if the current window that the mouse is over is a child window
735      * of the window the message was sent to. Some events only sent to main window,
736      * and when handling some messages, we need to make sure that we process
737      * callbacks on the child window instead. This mirrors how GLUT does things.
738      * returns either the original window or the found child.
739      */
740     if (window && window->Children.First)   /* This window has childs */
741     {
742         HWND hwnd;
743         SFG_Window* child_window;
744
745         /* Get mouse position at time of message */
746         DWORD mouse_pos_dw = GetMessagePos();
747         POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)};
748         ScreenToClient( window->Window.Handle, &mouse_pos );
749         
750         hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
751         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 */
752         {
753             child_window = fgWindowByHandle(hwnd);
754             if (child_window)    /* Verify we got a FreeGLUT window */
755             {
756                 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
757                 window = fghWindowUnderCursor(child_window);
758             }
759         }
760     }
761
762     return window;
763 }
764
765 /*
766  * The window procedure for handling Win32 events
767  */
768 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
769 {
770     SFG_Window *window;
771     LRESULT lRet = 1;
772     static int setCaptureActive = 0;
773
774     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
775
776     window = fgWindowByHandle( hWnd );
777
778     if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
779       return DefWindowProc( hWnd, uMsg, wParam, lParam );
780
781     /* printf ( "Window %3d message %s (<%04x>) %12d %12d\n", window?window->ID:0,
782              WMMsg2Str(uMsg), uMsg, wParam, lParam ); */
783
784     switch( uMsg )
785     {
786     case WM_CREATE:
787         /* The window structure is passed as the creation structure parameter... */
788         window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
789         FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
790                                        "fgPlatformWindowProc" );
791
792         window->Window.Handle = hWnd;
793         window->Window.pContext.Device = GetDC( hWnd );
794         if( window->IsMenu )
795         {
796             unsigned int current_DisplayMode = fgState.DisplayMode;
797             fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
798 #if !defined(_WIN32_WCE)
799             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
800 #endif
801             fgState.DisplayMode = current_DisplayMode;
802
803             if( fgStructure.MenuContext )
804                 wglMakeCurrent( window->Window.pContext.Device,
805                                 fgStructure.MenuContext->MContext
806                 );
807             else
808             {
809                 fgStructure.MenuContext =
810                     (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
811                 fgStructure.MenuContext->MContext =
812                     wglCreateContext( window->Window.pContext.Device );
813             }
814
815             /* window->Window.Context = wglGetCurrentContext ();   */
816             window->Window.Context = wglCreateContext( window->Window.pContext.Device );
817         }
818         else
819         {
820 #if !defined(_WIN32_WCE)
821             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
822 #endif
823
824             if( ! fgState.UseCurrentContext )
825                 window->Window.Context =
826                     wglCreateContext( window->Window.pContext.Device );
827             else
828             {
829                 window->Window.Context = wglGetCurrentContext( );
830                 if( ! window->Window.Context )
831                     window->Window.Context =
832                         wglCreateContext( window->Window.pContext.Device );
833             }
834
835 #if !defined(_WIN32_WCE)
836             fgNewWGLCreateContext( window );
837 #endif
838         }
839
840         ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
841
842 #if defined(_WIN32_WCE)
843         /* Take over button handling */
844         {
845             HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
846             if (dxDllLib)
847             {
848                 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
849                 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
850             }
851
852             if(GXOpenInput_)
853                 (*GXOpenInput_)();
854             if(GXGetDefaultKeys_)
855                 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
856         }
857
858 #endif /* defined(_WIN32_WCE) */
859         break;
860
861     case WM_SIZE:
862         /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */
863
864         /* Update visibility state of the window */
865         if (wParam==SIZE_MINIMIZED)
866             fghPlatformOnWindowStatusNotify(window,GL_FALSE,GL_FALSE);
867         else if (wParam==SIZE_RESTORED && !window->State.Visible)
868             fghPlatformOnWindowStatusNotify(window,GL_TRUE,GL_FALSE);
869
870         /* Check window visible, we don't want do anything when we get a WM_SIZE because the user or glutIconifyWindow minimized the window */
871         if( window->State.Visible )
872         {
873             int width, height;
874 #if defined(_WIN32_WCE)
875             width  = HIWORD(lParam);
876             height = LOWORD(lParam);
877 #else
878             width  = LOWORD(lParam);
879             height = HIWORD(lParam);
880 #endif /* defined(_WIN32_WCE) */
881             
882             /* Update state and call callback, if there was a change */
883             fghOnReshapeNotify(window, width, height, GL_FALSE);
884         }
885
886         /* according to docs, should return 0 */
887         lRet = 0;
888         break;
889
890     case WM_SIZING:
891         {
892             /* User resize-dragging the window, call reshape callback and
893              * force redisplay so display keeps running during dragging.
894              * Screen still wont update when not moving the cursor though...
895              */
896             /* PRECT prect = (PRECT) lParam; */
897             RECT rect;
898             /* printf("WM_SIZING: nc-area: %i,%i\n",prect->right-prect->left,prect->bottom-prect->top); */
899             /* Get client area, the rect in lParam is including non-client area. */
900             fghGetClientArea(&rect,window,FALSE);
901
902             /* We'll get a WM_SIZE as well, but as state has
903              * already been updated here, the fghOnReshapeNotify
904              * in the handler for that message doesn't do anything.
905              */
906             fghOnReshapeNotify(window, rect.right-rect.left, rect.bottom-rect.top, GL_FALSE);
907
908             /* Now directly call the drawing function to update
909              * window and window's childs.
910              * This mimics the WM_PAINT messages that are received during
911              * resizing. Note that we don't have a WM_MOVING handler
912              * as move-dragging doesn't generate WM_MOVE or WM_PAINT
913              * messages until the mouse is released.
914              */
915             fghRedrawWindowAndChildren(window);
916         }
917
918         /* according to docs, should return TRUE */
919         lRet = TRUE;
920         break;
921
922     case WM_MOVE:
923         {
924             /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */
925             if (!IsIconic(window->Window.Handle))
926             {
927                 RECT windowRect;
928                 
929                 /* lParam contains coordinates of top-left of client area.
930                  * Get top-left of non-client area of window, matching coordinates of
931                  * glutInitPosition and glutPositionWindow, but not those of 
932                  * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
933                  * top-left of client area.
934                  */
935                 GetWindowRect( window->Window.Handle, &windowRect );
936             
937                 if (window->Parent)
938                 {
939                     /* For child window, we should return relative to upper-left
940                      * of parent's client area.
941                      */
942                     POINT topleft = {windowRect.left,windowRect.top};
943
944                     ScreenToClient(window->Parent->Window.Handle,&topleft);
945                     windowRect.left = topleft.x;
946                     windowRect.top  = topleft.y;
947                 }
948
949                 /* Update state and call callback, if there was a change */
950                 fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_FALSE);
951             }
952         }
953
954         /* according to docs, should return 0 */
955         lRet = 0;
956         break;
957
958     case WM_SETFOCUS:
959         /*printf("WM_SETFOCUS: %p\n", window );*/
960         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
961
962         SetActiveWindow( window->Window.Handle );
963         UpdateWindow ( hWnd );
964
965         break;
966
967     case WM_KILLFOCUS:
968         /*printf("WM_KILLFOCUS: %p\n", window ); */
969         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
970
971         /* Check if there are any open menus that need to be closed */
972         fgPlatformCheckMenuDeactivate();
973         break;
974
975     case WM_MOUSEACTIVATE:
976         /* Clicks should not activate the menu.
977          * Especially important when clicking on a menu's submenu item which has no effect.
978          */
979         printf("WM_MOUSEACTIVATE\n");
980         if (window->IsMenu)
981             lRet = MA_NOACTIVATEANDEAT;
982         else
983             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
984         break;
985
986     case WM_NCLBUTTONDOWN:
987     case WM_NCMBUTTONDOWN:
988     case WM_NCRBUTTONDOWN:
989         {
990             SFG_Menu *menu;
991             if (fgStructure.Menus.First && (menu = fgGetActiveMenu()))
992                 /* user clicked non-client area of window while a menu is open. Close menu */
993                 fgDeactivateMenu(menu->ParentWindow);
994
995             /* and always pass to DefWindowProc */
996             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
997         }
998         break;
999
1000 #if 0
1001     case WM_ACTIVATE:
1002         /* printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam)); */
1003         if (LOWORD(wParam) != WA_INACTIVE)
1004         {
1005 /*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
1006                    window->State.Cursor ); */
1007             fgSetCursor( window, window->State.Cursor );
1008         }
1009
1010         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1011         break;
1012 #endif
1013
1014     case WM_SETCURSOR:
1015 /*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
1016         if( LOWORD( lParam ) == HTCLIENT )
1017         {
1018             if (!window->State.pWState.MouseTracking)
1019             {
1020                 TRACKMOUSEEVENT tme;
1021
1022                 /* Cursor just entered window, set cursor look */ 
1023                 fgSetCursor ( window, window->State.Cursor ) ;
1024
1025                 /* If an EntryFunc callback is specified by the user, also
1026                  * invoke that callback and start mouse tracking so that
1027                  * we get a WM_MOUSELEAVE message
1028                  */
1029                 if (FETCH_WCB( *window, Entry ))
1030                 {
1031                     SFG_Window* saved_window = fgStructure.CurrentWindow;
1032                     INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
1033                     fgSetWindow(saved_window);
1034
1035                     tme.cbSize = sizeof(TRACKMOUSEEVENT);
1036                     tme.dwFlags = TME_LEAVE;
1037                     tme.hwndTrack = window->Window.Handle;
1038                     TrackMouseEvent(&tme);
1039
1040                     window->State.pWState.MouseTracking = TRUE;
1041                 }
1042             }
1043         }
1044         else
1045             /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
1046             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1047         break;
1048
1049     case WM_MOUSELEAVE:
1050         {
1051             /* NB: This message is only received when a EntryFunc callback
1052              * is specified by the user, as that is the only condition under
1053              * which mouse tracking is setup in WM_SETCURSOR handler above
1054              */
1055             SFG_Window* saved_window = fgStructure.CurrentWindow;
1056             INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
1057             fgSetWindow(saved_window);
1058
1059             window->State.pWState.MouseTracking = FALSE;
1060             lRet = 0;   /* As per docs, must return zero */
1061         }
1062         break;
1063
1064     case WM_SHOWWINDOW:
1065         /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */
1066         if (wParam)
1067         {
1068             fghPlatformOnWindowStatusNotify(window, GL_TRUE, GL_FALSE);
1069             window->State.Redisplay = GL_TRUE;
1070         }
1071         else
1072         {
1073             fghPlatformOnWindowStatusNotify(window, GL_FALSE, GL_FALSE);
1074             window->State.Redisplay = GL_FALSE;
1075         }
1076         break;
1077
1078     case WM_PAINT:
1079     {
1080         RECT rect;
1081         
1082         /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */
1083         if (GetUpdateRect(hWnd,&rect,FALSE))
1084         {
1085             /* Dummy begin/end paint to validate rect that needs
1086              * redrawing, then signal that a redisplay is needed.
1087              * This allows us full control about when we do any
1088              * redrawing, and is the same as what original GLUT
1089              * does.
1090              */
1091             PAINTSTRUCT ps;
1092             BeginPaint( hWnd, &ps );
1093             EndPaint( hWnd, &ps );
1094
1095             window->State.Redisplay = GL_TRUE;
1096         }
1097         lRet = 0;   /* As per docs, should return 0 */
1098     }
1099     break;
1100
1101     case WM_CLOSE:
1102         fgDestroyWindow ( window );
1103         if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
1104             PostQuitMessage(0);
1105         break;
1106
1107     case WM_DESTROY:
1108         /*
1109          * The window already got destroyed, so don't bother with it.
1110          */
1111         return 0;
1112
1113     case WM_MOUSEMOVE:
1114     {
1115         /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
1116 #if defined(_WIN32_WCE)
1117         window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
1118         window->State.MouseY = LOWORD( lParam );
1119 #else
1120         window->State.MouseX = GET_X_LPARAM( lParam );
1121         window->State.MouseY = GET_Y_LPARAM( lParam );
1122 #endif /* defined(_WIN32_WCE) */
1123         /* Restrict to [-32768, 32767] to match X11 behaviour       */
1124         /* See comment in "freeglut_developer" mailing list 10/4/04 */
1125         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
1126         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
1127
1128         if ( window->ActiveMenu )
1129         {
1130             fgUpdateMenuHighlight( window->ActiveMenu );
1131             break;
1132         }
1133
1134         fgState.Modifiers = fgPlatformGetModifiers( );
1135
1136         if( ( wParam & MK_LBUTTON ) ||
1137             ( wParam & MK_MBUTTON ) ||
1138             ( wParam & MK_RBUTTON ) )
1139             INVOKE_WCB( *window, Motion, ( window->State.MouseX,
1140                                            window->State.MouseY ) );
1141         else
1142             INVOKE_WCB( *window, Passive, ( window->State.MouseX,
1143                                             window->State.MouseY ) );
1144
1145         fgState.Modifiers = INVALID_MODIFIERS;
1146     }
1147     break;
1148
1149     case WM_LBUTTONDOWN:
1150     case WM_MBUTTONDOWN:
1151     case WM_RBUTTONDOWN:
1152     case WM_LBUTTONUP:
1153     case WM_MBUTTONUP:
1154     case WM_RBUTTONUP:
1155     {
1156         GLboolean pressed = GL_TRUE;
1157         int button;
1158
1159         /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
1160 #if defined(_WIN32_WCE)
1161         window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
1162         window->State.MouseY = LOWORD( lParam );
1163 #else
1164         window->State.MouseX = GET_X_LPARAM( lParam );
1165         window->State.MouseY = GET_Y_LPARAM( lParam );
1166 #endif /* defined(_WIN32_WCE) */
1167
1168         /* Restrict to [-32768, 32767] to match X11 behaviour       */
1169         /* See comment in "freeglut_developer" mailing list 10/4/04 */
1170         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
1171         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
1172
1173         switch( uMsg )
1174         {
1175         case WM_LBUTTONDOWN:
1176             pressed = GL_TRUE;
1177             button = GLUT_LEFT_BUTTON;
1178             break;
1179         case WM_MBUTTONDOWN:
1180             pressed = GL_TRUE;
1181             button = GLUT_MIDDLE_BUTTON;
1182             break;
1183         case WM_RBUTTONDOWN:
1184             pressed = GL_TRUE;
1185             button = GLUT_RIGHT_BUTTON;
1186             break;
1187         case WM_LBUTTONUP:
1188             pressed = GL_FALSE;
1189             button = GLUT_LEFT_BUTTON;
1190             break;
1191         case WM_MBUTTONUP:
1192             pressed = GL_FALSE;
1193             button = GLUT_MIDDLE_BUTTON;
1194             break;
1195         case WM_RBUTTONUP:
1196             pressed = GL_FALSE;
1197             button = GLUT_RIGHT_BUTTON;
1198             break;
1199         default:
1200             pressed = GL_FALSE;
1201             button = -1;
1202             break;
1203         }
1204
1205 #if !defined(_WIN32_WCE)
1206         if( GetSystemMetrics( SM_SWAPBUTTON ) )
1207         {
1208             if( button == GLUT_LEFT_BUTTON )
1209                 button = GLUT_RIGHT_BUTTON;
1210             else
1211                 if( button == GLUT_RIGHT_BUTTON )
1212                     button = GLUT_LEFT_BUTTON;
1213         }
1214 #endif /* !defined(_WIN32_WCE) */
1215
1216         if( button == -1 )
1217             return DefWindowProc( hWnd, uMsg, lParam, wParam );
1218
1219         /*
1220          * Do not execute the application's mouse callback if a menu
1221          * is hooked to this button.  In that case an appropriate
1222          * private call should be generated.
1223          */
1224         if( fgCheckActiveMenu( window, button, pressed,
1225                                window->State.MouseX, window->State.MouseY ) )
1226             break;
1227
1228         /* Set capture so that the window captures all the mouse messages
1229          *
1230          * The mouse is not released from the window until all buttons have
1231          * been released, even if the user presses a button in another window.
1232          * This is consistent with the behavior on X11.
1233          */
1234         if ( pressed == GL_TRUE )
1235         {
1236             if (!setCaptureActive)
1237                 SetCapture ( window->Window.Handle ) ;
1238             setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
1239         }
1240         else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
1241           /* Make sure all mouse buttons are released before releasing capture */
1242           ReleaseCapture () ;
1243
1244         if( ! FETCH_WCB( *window, Mouse ) )
1245             break;
1246
1247         fgSetWindow( window );
1248         fgState.Modifiers = fgPlatformGetModifiers( );
1249
1250         INVOKE_WCB(
1251             *window, Mouse,
1252             ( button,
1253               pressed ? GLUT_DOWN : GLUT_UP,
1254               window->State.MouseX,
1255               window->State.MouseY
1256             )
1257         );
1258
1259         fgState.Modifiers = INVALID_MODIFIERS;
1260
1261         /* As per docs, should return zero */
1262         lRet = 0;
1263     }
1264     break;
1265
1266     case WM_MOUSEWHEEL:
1267     {
1268         int wheel_number = 0;   /* Only one scroll wheel on windows */
1269 #if defined(_WIN32_WCE)
1270         int modkeys = LOWORD(wParam); 
1271         short ticks = (short)HIWORD(wParam);
1272         /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
1273         xPos = LOWORD(lParam);  -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong)
1274         yPos = HIWORD(lParam);
1275         */
1276 #else
1277         /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
1278         short ticks = GET_WHEEL_DELTA_WPARAM( wParam );
1279         /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
1280         window->State.MouseX = GET_X_LPARAM( lParam );
1281         window->State.MouseY = GET_Y_LPARAM( lParam );
1282         */
1283 #endif /* defined(_WIN32_WCE) */
1284
1285         window = fghWindowUnderCursor(window);
1286
1287                 fgState.MouseWheelTicks += ticks;
1288         if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
1289                 {
1290                         int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
1291
1292             if( ! FETCH_WCB( *window, MouseWheel ) &&
1293                 ! FETCH_WCB( *window, Mouse ) )
1294                 break;
1295
1296             fgSetWindow( window );
1297             fgState.Modifiers = fgPlatformGetModifiers( );
1298
1299             while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
1300                         {
1301                 if( FETCH_WCB( *window, MouseWheel ) )
1302                     INVOKE_WCB( *window, MouseWheel,
1303                                 ( wheel_number,
1304                                   direction,
1305                                   window->State.MouseX,
1306                                   window->State.MouseY
1307                                 )
1308                     );
1309                 else  /* No mouse wheel, call the mouse button callback twice */
1310                                 {
1311                     /*
1312                      * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
1313                      *  "    "   one                     +1 to 5, -1 to 6, ...
1314                      *
1315                      * XXX The below assumes that you have no more than 3 mouse
1316                      * XXX buttons.  Sorry.
1317                      */
1318                     int button = wheel_number * 2 + 3;
1319                     if( direction < 0 )
1320                         ++button;
1321                     INVOKE_WCB( *window, Mouse,
1322                                 ( button, GLUT_DOWN,
1323                                   window->State.MouseX, window->State.MouseY )
1324                     );
1325                     INVOKE_WCB( *window, Mouse,
1326                                 ( button, GLUT_UP,
1327                                   window->State.MouseX, window->State.MouseY )
1328                     );
1329                                 }
1330
1331                                 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
1332                         }
1333
1334             fgState.Modifiers = INVALID_MODIFIERS;
1335                 }
1336         /* Per docs, should return zero */
1337         lRet = 0;
1338     }
1339     break ;
1340
1341     case WM_SYSKEYDOWN:
1342     case WM_KEYDOWN:
1343     {
1344         window = fghWindowUnderCursor(window);
1345         lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
1346     }
1347     break;
1348
1349     case WM_SYSKEYUP:
1350     case WM_KEYUP:
1351     {
1352         window = fghWindowUnderCursor(window);
1353         lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
1354     }
1355     break;
1356
1357     case WM_SYSCHAR:
1358     case WM_CHAR:
1359     {
1360       window = fghWindowUnderCursor(window);
1361
1362       if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
1363             break;
1364
1365         fgState.Modifiers = fgPlatformGetModifiers( );
1366         INVOKE_WCB( *window, Keyboard,
1367                     ( (char)wParam,
1368                       window->State.MouseX, window->State.MouseY )
1369         );
1370         fgState.Modifiers = INVALID_MODIFIERS;
1371     }
1372     break;
1373
1374     case WM_CAPTURECHANGED:
1375         if (!lParam || !fgWindowByHandle((HWND)lParam))
1376             /* Capture released or capture taken by non-FreeGLUT window */
1377             setCaptureActive = 0;
1378         /* Docs advise a redraw */
1379         InvalidateRect( hWnd, NULL, GL_FALSE );
1380         UpdateWindow(hWnd);
1381         lRet = 0;   /* Per docs, should return zero */
1382         break;
1383
1384 #if !defined(_WIN32_WCE)
1385     case WM_SYNCPAINT:  /* 0x0088 */
1386         /* Another window has moved, need to update this one */
1387         window->State.Redisplay = GL_TRUE;
1388         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1389         /* Help screen says this message must be passed to "DefWindowProc" */
1390         break;
1391
1392     case WM_DISPLAYCHANGE: /* 0x007E */
1393         /* The system display resolution/depth has changed */
1394         fgDisplay.ScreenWidth = LOWORD(lParam);
1395         fgDisplay.ScreenHeight = HIWORD(lParam);
1396         break;
1397
1398     case WM_SYSCOMMAND :  /* 0x0112 */
1399         {
1400           /*
1401            * We have received a system command message.  Try to act on it.
1402            * The commands are passed in through the "wParam" parameter:
1403            * The least significant digit seems to be which edge of the window
1404            * is being used for a resize event:
1405            *     4  3  5
1406            *     1     2
1407            *     7  6  8
1408            * Congratulations and thanks to Richard Rauch for figuring this out..
1409            */
1410             switch ( wParam & 0xfff0 )
1411             {
1412             case SC_SIZE       :
1413                 break ;
1414
1415             case SC_MOVE       :
1416                 break ;
1417
1418             case SC_MINIMIZE   :
1419                 /* User has clicked on the "-" to minimize the window */
1420                 /* Turning off the visibility is handled in WM_SIZE handler */
1421
1422                 break ;
1423
1424             case SC_MAXIMIZE   :
1425                 break ;
1426
1427             case SC_NEXTWINDOW :
1428                 break ;
1429
1430             case SC_PREVWINDOW :
1431                 break ;
1432
1433             case SC_CLOSE      :
1434                 /* Followed very closely by a WM_CLOSE message */
1435                 break ;
1436
1437             case SC_VSCROLL    :
1438                 break ;
1439
1440             case SC_HSCROLL    :
1441                 break ;
1442
1443             case SC_MOUSEMENU  :
1444                 break ;
1445
1446             case SC_KEYMENU    :
1447                 break ;
1448
1449             case SC_ARRANGE    :
1450                 break ;
1451
1452             case SC_RESTORE    :
1453                 break ;
1454
1455             case SC_TASKLIST   :
1456                 break ;
1457
1458             case SC_SCREENSAVE :
1459                 break ;
1460
1461             case SC_HOTKEY     :
1462                 break ;
1463
1464 #if(WINVER >= 0x0400)
1465             case SC_DEFAULT    :
1466                 break ;
1467
1468             case SC_MONITORPOWER    :
1469                 break ;
1470
1471             case SC_CONTEXTHELP    :
1472                 break ;
1473 #endif /* WINVER >= 0x0400 */
1474
1475             default:
1476 #if _DEBUG
1477                 fgWarning( "Unknown wParam type 0x%x", wParam );
1478 #endif
1479                 break;
1480             }
1481         }
1482 #endif /* !defined(_WIN32_WCE) */
1483
1484         /* We need to pass the message on to the operating system as well */
1485         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1486         break;
1487
1488 #ifdef WM_TOUCH
1489         /* handle multi-touch messages */
1490         case WM_TOUCH:
1491         {
1492                 unsigned int numInputs = (unsigned int)wParam;
1493                 unsigned int i = 0;
1494                 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1495
1496                 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1497                     fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1498                     fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1499                 }
1500
1501                 if (!fghGetTouchInputInfo) { 
1502                         free( (void*)ti );
1503                         break;
1504                 }
1505
1506                 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1507                         /* Handle each contact point */
1508                         for (i = 0; i < numInputs; ++i ) {
1509
1510                                 POINT tp;
1511                                 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1512                                 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1513                                 ScreenToClient( hWnd, &tp );
1514
1515                                 ti[i].dwID = ti[i].dwID * 2;
1516
1517                                 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1518                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_ENTERED ) );
1519                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1520                                 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1521                                         INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1522                                 } else if (ti[i].dwFlags & TOUCHEVENTF_UP)   { 
1523                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1524                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_LEFT ) );
1525                                 }
1526                         }
1527                 }
1528                 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1529                 free( (void*)ti );
1530                 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1531                 break;
1532         }
1533 #endif
1534     default:
1535         /* Handle unhandled messages */
1536         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1537         break;
1538     }
1539
1540     return lRet;
1541 }
1542
1543
1544 /* Step through the work list */
1545 void fgPlatformProcessWork(SFG_Window *window)
1546 {
1547     unsigned int workMask = window->State.WorkMask;
1548     /* Now clear it so that any callback generated by the actions below can set work again */
1549     window->State.WorkMask = 0;
1550
1551     /* This is before the first display callback: call a few callbacks to inform user of window size, position, etc
1552      * we know this is before the first display callback of a window as for all windows GLUT_INIT_WORK is set when
1553      * they are opened, and work is done before displaying in the mainloop.
1554      */
1555     if (workMask & GLUT_INIT_WORK)
1556     {
1557         RECT windowRect;
1558
1559         /* Notify windowStatus/visibility */
1560         fghPlatformOnWindowStatusNotify(window, window->State.Visible, GL_TRUE);
1561
1562         /* get and notify window's position */
1563         GetWindowRect(window->Window.Handle,&windowRect);
1564         fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_TRUE);
1565
1566         /* get and notify window's size */
1567         GetClientRect(window->Window.Handle,&windowRect);
1568         fghOnReshapeNotify(window, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, GL_TRUE);
1569
1570         /* Call init context callback */
1571         INVOKE_WCB( *window, InitContext, ());
1572
1573         /* Lastly, check if we have a display callback, error out if not
1574          * This is the right place to do it, as the redisplay will be
1575          * next right after we exit this function, so there is no more
1576          * opportunity for the user to register a callback for this window.
1577          */
1578         if (!FETCH_WCB(*window, Display))
1579             fgError ( "ERROR:  No display callback registered for window %d\n", window->ID );
1580     }
1581
1582     /* On windows we can position, resize and change z order at the same time */
1583     if (workMask & (GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK|GLUT_FULL_SCREEN_WORK))
1584     {
1585         UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
1586         HWND insertAfter = HWND_TOP;
1587         RECT clientRect;
1588
1589 #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1590         if (workMask & GLUT_FULL_SCREEN_WORK)
1591         {
1592             /* This asks us to toggle fullscreen mode */
1593             flags |= SWP_FRAMECHANGED;
1594
1595             if (window->State.IsFullscreen)
1596             {
1597                 /* If we are fullscreen, resize the current window back to its original size */
1598                 /* 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); */
1599
1600                 /* restore style of window before making it fullscreen */
1601                 SetWindowLong(window->Window.Handle, GWL_STYLE, window->State.pWState.OldStyle);
1602                 SetWindowLong(window->Window.Handle, GWL_EXSTYLE, window->State.pWState.OldStyleEx);
1603
1604                 /* Then set up resize/reposition, unless user already queued up reshape/position work */
1605                 if (!(workMask & GLUT_POSITION_WORK))
1606                 {
1607                     workMask |= GLUT_POSITION_WORK;
1608                     window->State.DesiredXpos   = window->State.pWState.OldRect.left;
1609                     window->State.DesiredYpos   = window->State.pWState.OldRect.top;
1610                 }
1611                 if (!(workMask & GLUT_SIZE_WORK))
1612                 {
1613                     workMask |= GLUT_SIZE_WORK;
1614                     window->State.DesiredWidth  = window->State.pWState.OldRect.right  - window->State.pWState.OldRect.left;
1615                     window->State.DesiredHeight = window->State.pWState.OldRect.bottom - window->State.pWState.OldRect.top;
1616                 }
1617                 
1618                 /* We'll finish off the fullscreen operation below after the other GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK */
1619             }
1620             else
1621             {
1622                 /* we are currently not fullscreen, go to fullscreen:
1623                  * remove window decoration and then maximize
1624                  */
1625                 RECT rect;
1626                 HMONITOR hMonitor;
1627                 MONITORINFO mi;
1628         
1629                 /* save current window rect, style, exstyle and maximized state */
1630                 window->State.pWState.OldMaximized = !!IsZoomed(window->Window.Handle);
1631                 if (window->State.pWState.OldMaximized)
1632                     /* We force the window into restored mode before going
1633                      * fullscreen because Windows doesn't seem to hide the
1634                      * taskbar if the window is in the maximized state.
1635                      */
1636                     SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
1637
1638                 fghGetClientArea( &window->State.pWState.OldRect, window, GL_TRUE );
1639                 window->State.pWState.OldStyle   = GetWindowLong(window->Window.Handle, GWL_STYLE);
1640                 window->State.pWState.OldStyleEx = GetWindowLong(window->Window.Handle, GWL_EXSTYLE);
1641
1642                 /* remove decorations from style */
1643                 SetWindowLong(window->Window.Handle, GWL_STYLE,
1644                               window->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME));
1645                 SetWindowLong(window->Window.Handle, GWL_EXSTYLE,
1646                               window->State.pWState.OldStyleEx & ~(WS_EX_DLGMODALFRAME |
1647                               WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
1648
1649                 /* For fullscreen mode, find the monitor that is covered the most
1650                  * by the window and get its rect as the resize target.
1651                      */
1652                 GetWindowRect(window->Window.Handle, &rect);
1653                 hMonitor= MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
1654                 mi.cbSize = sizeof(mi);
1655                 GetMonitorInfo(hMonitor, &mi);
1656                 rect = mi.rcMonitor;
1657
1658                 /* then setup window resize, overwriting other work queued on the window */
1659                 window->State.WorkMask |= GLUT_POSITION_WORK | GLUT_SIZE_WORK;
1660                 window->State.WorkMask &= ~GLUT_ZORDER_WORK;
1661                 window->State.DesiredXpos   = rect.left;
1662                 window->State.DesiredYpos   = rect.top;
1663                 window->State.DesiredWidth  = rect.right  - rect.left;
1664                 window->State.DesiredHeight = rect.bottom - rect.top;
1665             }
1666         }
1667 #endif /*!defined(_WIN32_WCE) */
1668
1669         /* Now deal with normal position, reshape and z order requests (some might have been set when handling GLUT_FULLSCREEN_WORK above */
1670         {
1671             /* get rect describing window's current position and size, 
1672              * in screen coordinates and in FreeGLUT format
1673              * (size (right-left, bottom-top) is client area size, top and left
1674              * are outside of window including decorations).
1675              */
1676             fghGetClientArea( &clientRect, window, TRUE );
1677
1678             if (workMask & GLUT_POSITION_WORK)
1679             {
1680                 flags &= ~SWP_NOMOVE;
1681                 
1682                 /* Move rect so that top-left is at requested position */
1683                 /* This also automatically makes sure that child window requested coordinates are relative
1684                  * to top-left of parent's client area (needed input for SetWindowPos on child windows),
1685                  * so no need to further correct rect for child windows below (childs don't have decorations either).
1686                  */
1687                 OffsetRect(&clientRect,window->State.DesiredXpos-clientRect.left,window->State.DesiredYpos-clientRect.top);
1688             }
1689             if (workMask & GLUT_SIZE_WORK)
1690             {
1691                 flags &= ~SWP_NOSIZE;
1692                 
1693                 /* Note on maximizing behavior of Windows: the resize borders are off
1694                  * the screen such that the client area extends all the way from the
1695                  * leftmost corner to the rightmost corner to maximize screen real
1696                  * estate. A caption is still shown however to allow interaction with
1697                  * the window controls. This is default behavior of Windows that
1698                  * FreeGLUT sticks with. To alter, one would have to check if
1699                  * WS_MAXIMIZE style is set when a resize event is triggered, and
1700                  * then manually correct the windowRect to put the borders back on
1701                  * screen.
1702                  */
1703
1704                 /* Set new size of window, WxH specify client area */
1705                 clientRect.right    = clientRect.left + window->State.DesiredWidth;
1706                 clientRect.bottom   = clientRect.top  + window->State.DesiredHeight;
1707             }
1708             if (workMask & GLUT_ZORDER_WORK)
1709             {
1710                 flags &= ~SWP_NOZORDER;
1711
1712                 /* Could change this to push it down or up one window at a time with some
1713                  * more code using GetWindow with GW_HWNDPREV and GW_HWNDNEXT.
1714                  * What would be consistent with X11? Win32 GLUT does what we do here...
1715                  */
1716                 if (window->State.DesiredZOrder < 0)
1717                     insertAfter = HWND_BOTTOM;
1718             }
1719         }
1720
1721         /* Adjust for window decorations
1722          * Child windows don't have decoration, so no need to correct
1723          */
1724         if (!window->Parent)
1725             /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
1726             fghComputeWindowRectFromClientArea_QueryWindow(&clientRect,window,TRUE);
1727     
1728         /* Do the requested positioning, moving, and z order push/pop. */
1729         SetWindowPos( window->Window.Handle,
1730                       insertAfter,
1731                       clientRect.left, clientRect.top,
1732                       clientRect.right - clientRect.left,
1733                       clientRect.bottom- clientRect.top,
1734                       flags
1735         );
1736
1737         /* Finish off the fullscreen operation we were doing, if any */
1738         if (workMask & GLUT_FULL_SCREEN_WORK)
1739         {
1740             if (window->State.IsFullscreen)
1741             {
1742                 /* leaving fullscreen, restore maximized state, if any */
1743                 if (window->State.pWState.OldMaximized)
1744                     SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
1745
1746                 window->State.IsFullscreen = GL_FALSE;
1747             }
1748             else
1749                 window->State.IsFullscreen = GL_TRUE;
1750         }
1751     }
1752
1753     if (workMask & GLUT_VISIBILITY_WORK)
1754     {
1755         /* Visibility status of window gets updated in the WM_SHOWWINDOW and WM_SIZE handlers */
1756         int cmdShow = 0;
1757         SFG_Window *win = window;
1758         switch (window->State.DesiredVisibility)
1759         {
1760         case DesireHiddenState:
1761             cmdShow = SW_HIDE;
1762             break;
1763         case DesireIconicState:
1764             cmdShow = SW_MINIMIZE;
1765             /* Call on top-level window */
1766             while (win->Parent)
1767                 win = win->Parent;
1768             break;
1769         case DesireNormalState:
1770             if (win->IsMenu)
1771                 cmdShow = SW_SHOWNA;    /* Just show, don't activate if its a menu */
1772             else
1773                 cmdShow = SW_SHOW;
1774             break;
1775         }
1776
1777         ShowWindow( win->Window.Handle, cmdShow );
1778     }
1779 }