added a function to translate WM_ messages to text, for debugging
[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 #if 0
987     case WM_ACTIVATE:
988         /* printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam)); */
989         if (LOWORD(wParam) != WA_INACTIVE)
990         {
991 /*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
992                    window->State.Cursor ); */
993             fgSetCursor( window, window->State.Cursor );
994         }
995
996         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
997         break;
998 #endif
999
1000     case WM_SETCURSOR:
1001 /*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
1002         if( LOWORD( lParam ) == HTCLIENT )
1003         {
1004             if (!window->State.pWState.MouseTracking)
1005             {
1006                 TRACKMOUSEEVENT tme;
1007
1008                 /* Cursor just entered window, set cursor look */ 
1009                 fgSetCursor ( window, window->State.Cursor ) ;
1010
1011                 /* If an EntryFunc callback is specified by the user, also
1012                  * invoke that callback and start mouse tracking so that
1013                  * we get a WM_MOUSELEAVE message
1014                  */
1015                 if (FETCH_WCB( *window, Entry ))
1016                 {
1017                     SFG_Window* saved_window = fgStructure.CurrentWindow;
1018                     INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
1019                     fgSetWindow(saved_window);
1020
1021                     tme.cbSize = sizeof(TRACKMOUSEEVENT);
1022                     tme.dwFlags = TME_LEAVE;
1023                     tme.hwndTrack = window->Window.Handle;
1024                     TrackMouseEvent(&tme);
1025
1026                     window->State.pWState.MouseTracking = TRUE;
1027                 }
1028             }
1029         }
1030         else
1031             /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
1032             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1033         break;
1034
1035     case WM_MOUSELEAVE:
1036         {
1037             /* NB: This message is only received when a EntryFunc callback
1038              * is specified by the user, as that is the only condition under
1039              * which mouse tracking is setup in WM_SETCURSOR handler above
1040              */
1041             SFG_Window* saved_window = fgStructure.CurrentWindow;
1042             INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
1043             fgSetWindow(saved_window);
1044
1045             window->State.pWState.MouseTracking = FALSE;
1046             lRet = 0;   /* As per docs, must return zero */
1047         }
1048         break;
1049
1050     case WM_SHOWWINDOW:
1051         /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */
1052         if (wParam)
1053         {
1054             fghPlatformOnWindowStatusNotify(window, GL_TRUE, GL_FALSE);
1055             window->State.Redisplay = GL_TRUE;
1056         }
1057         else
1058         {
1059             fghPlatformOnWindowStatusNotify(window, GL_FALSE, GL_FALSE);
1060             window->State.Redisplay = GL_FALSE;
1061         }
1062         break;
1063
1064     case WM_PAINT:
1065     {
1066         RECT rect;
1067         
1068         /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */
1069         if (GetUpdateRect(hWnd,&rect,FALSE))
1070         {
1071             /* Dummy begin/end paint to validate rect that needs
1072              * redrawing, then signal that a redisplay is needed.
1073              * This allows us full control about when we do any
1074              * redrawing, and is the same as what original GLUT
1075              * does.
1076              */
1077             PAINTSTRUCT ps;
1078             BeginPaint( hWnd, &ps );
1079             EndPaint( hWnd, &ps );
1080
1081             window->State.Redisplay = GL_TRUE;
1082         }
1083         lRet = 0;   /* As per docs, should return 0 */
1084     }
1085     break;
1086
1087     case WM_CLOSE:
1088         fgDestroyWindow ( window );
1089         if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
1090             PostQuitMessage(0);
1091         break;
1092
1093     case WM_DESTROY:
1094         /*
1095          * The window already got destroyed, so don't bother with it.
1096          */
1097         return 0;
1098
1099     case WM_MOUSEMOVE:
1100     {
1101         /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
1102 #if defined(_WIN32_WCE)
1103         window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
1104         window->State.MouseY = LOWORD( lParam );
1105 #else
1106         window->State.MouseX = GET_X_LPARAM( lParam );
1107         window->State.MouseY = GET_Y_LPARAM( lParam );
1108 #endif /* defined(_WIN32_WCE) */
1109         /* Restrict to [-32768, 32767] to match X11 behaviour       */
1110         /* See comment in "freeglut_developer" mailing list 10/4/04 */
1111         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
1112         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
1113
1114         if ( window->ActiveMenu )
1115         {
1116             fgUpdateMenuHighlight( window->ActiveMenu );
1117             break;
1118         }
1119
1120         fgState.Modifiers = fgPlatformGetModifiers( );
1121
1122         if( ( wParam & MK_LBUTTON ) ||
1123             ( wParam & MK_MBUTTON ) ||
1124             ( wParam & MK_RBUTTON ) )
1125             INVOKE_WCB( *window, Motion, ( window->State.MouseX,
1126                                            window->State.MouseY ) );
1127         else
1128             INVOKE_WCB( *window, Passive, ( window->State.MouseX,
1129                                             window->State.MouseY ) );
1130
1131         fgState.Modifiers = INVALID_MODIFIERS;
1132     }
1133     break;
1134
1135     case WM_LBUTTONDOWN:
1136     case WM_MBUTTONDOWN:
1137     case WM_RBUTTONDOWN:
1138     case WM_LBUTTONUP:
1139     case WM_MBUTTONUP:
1140     case WM_RBUTTONUP:
1141     {
1142         GLboolean pressed = GL_TRUE;
1143         int button;
1144
1145         /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
1146 #if defined(_WIN32_WCE)
1147         window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
1148         window->State.MouseY = LOWORD( lParam );
1149 #else
1150         window->State.MouseX = GET_X_LPARAM( lParam );
1151         window->State.MouseY = GET_Y_LPARAM( lParam );
1152 #endif /* defined(_WIN32_WCE) */
1153
1154         /* Restrict to [-32768, 32767] to match X11 behaviour       */
1155         /* See comment in "freeglut_developer" mailing list 10/4/04 */
1156         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
1157         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
1158
1159         switch( uMsg )
1160         {
1161         case WM_LBUTTONDOWN:
1162             pressed = GL_TRUE;
1163             button = GLUT_LEFT_BUTTON;
1164             break;
1165         case WM_MBUTTONDOWN:
1166             pressed = GL_TRUE;
1167             button = GLUT_MIDDLE_BUTTON;
1168             break;
1169         case WM_RBUTTONDOWN:
1170             pressed = GL_TRUE;
1171             button = GLUT_RIGHT_BUTTON;
1172             break;
1173         case WM_LBUTTONUP:
1174             pressed = GL_FALSE;
1175             button = GLUT_LEFT_BUTTON;
1176             break;
1177         case WM_MBUTTONUP:
1178             pressed = GL_FALSE;
1179             button = GLUT_MIDDLE_BUTTON;
1180             break;
1181         case WM_RBUTTONUP:
1182             pressed = GL_FALSE;
1183             button = GLUT_RIGHT_BUTTON;
1184             break;
1185         default:
1186             pressed = GL_FALSE;
1187             button = -1;
1188             break;
1189         }
1190
1191 #if !defined(_WIN32_WCE)
1192         if( GetSystemMetrics( SM_SWAPBUTTON ) )
1193         {
1194             if( button == GLUT_LEFT_BUTTON )
1195                 button = GLUT_RIGHT_BUTTON;
1196             else
1197                 if( button == GLUT_RIGHT_BUTTON )
1198                     button = GLUT_LEFT_BUTTON;
1199         }
1200 #endif /* !defined(_WIN32_WCE) */
1201
1202         if( button == -1 )
1203             return DefWindowProc( hWnd, uMsg, lParam, wParam );
1204
1205         /*
1206          * Do not execute the application's mouse callback if a menu
1207          * is hooked to this button.  In that case an appropriate
1208          * private call should be generated.
1209          */
1210         if( fgCheckActiveMenu( window, button, pressed,
1211                                window->State.MouseX, window->State.MouseY ) )
1212             break;
1213
1214         /* Set capture so that the window captures all the mouse messages
1215          *
1216          * The mouse is not released from the window until all buttons have
1217          * been released, even if the user presses a button in another window.
1218          * This is consistent with the behavior on X11.
1219          */
1220         if ( pressed == GL_TRUE )
1221         {
1222             if (!setCaptureActive)
1223                 SetCapture ( window->Window.Handle ) ;
1224             setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
1225         }
1226         else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
1227           /* Make sure all mouse buttons are released before releasing capture */
1228           ReleaseCapture () ;
1229
1230         if( ! FETCH_WCB( *window, Mouse ) )
1231             break;
1232
1233         fgSetWindow( window );
1234         fgState.Modifiers = fgPlatformGetModifiers( );
1235
1236         INVOKE_WCB(
1237             *window, Mouse,
1238             ( button,
1239               pressed ? GLUT_DOWN : GLUT_UP,
1240               window->State.MouseX,
1241               window->State.MouseY
1242             )
1243         );
1244
1245         fgState.Modifiers = INVALID_MODIFIERS;
1246
1247         /* As per docs, should return zero */
1248         lRet = 0;
1249     }
1250     break;
1251
1252     case WM_MOUSEWHEEL:
1253     {
1254         int wheel_number = 0;   /* Only one scroll wheel on windows */
1255 #if defined(_WIN32_WCE)
1256         int modkeys = LOWORD(wParam); 
1257         short ticks = (short)HIWORD(wParam);
1258         /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
1259         xPos = LOWORD(lParam);  -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong)
1260         yPos = HIWORD(lParam);
1261         */
1262 #else
1263         /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
1264         short ticks = GET_WHEEL_DELTA_WPARAM( wParam );
1265         /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
1266         window->State.MouseX = GET_X_LPARAM( lParam );
1267         window->State.MouseY = GET_Y_LPARAM( lParam );
1268         */
1269 #endif /* defined(_WIN32_WCE) */
1270
1271         window = fghWindowUnderCursor(window);
1272
1273                 fgState.MouseWheelTicks += ticks;
1274         if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
1275                 {
1276                         int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
1277
1278             if( ! FETCH_WCB( *window, MouseWheel ) &&
1279                 ! FETCH_WCB( *window, Mouse ) )
1280                 break;
1281
1282             fgSetWindow( window );
1283             fgState.Modifiers = fgPlatformGetModifiers( );
1284
1285             while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
1286                         {
1287                 if( FETCH_WCB( *window, MouseWheel ) )
1288                     INVOKE_WCB( *window, MouseWheel,
1289                                 ( wheel_number,
1290                                   direction,
1291                                   window->State.MouseX,
1292                                   window->State.MouseY
1293                                 )
1294                     );
1295                 else  /* No mouse wheel, call the mouse button callback twice */
1296                                 {
1297                     /*
1298                      * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
1299                      *  "    "   one                     +1 to 5, -1 to 6, ...
1300                      *
1301                      * XXX The below assumes that you have no more than 3 mouse
1302                      * XXX buttons.  Sorry.
1303                      */
1304                     int button = wheel_number * 2 + 3;
1305                     if( direction < 0 )
1306                         ++button;
1307                     INVOKE_WCB( *window, Mouse,
1308                                 ( button, GLUT_DOWN,
1309                                   window->State.MouseX, window->State.MouseY )
1310                     );
1311                     INVOKE_WCB( *window, Mouse,
1312                                 ( button, GLUT_UP,
1313                                   window->State.MouseX, window->State.MouseY )
1314                     );
1315                                 }
1316
1317                                 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
1318                         }
1319
1320             fgState.Modifiers = INVALID_MODIFIERS;
1321                 }
1322         /* Per docs, should return zero */
1323         lRet = 0;
1324     }
1325     break ;
1326
1327     case WM_SYSKEYDOWN:
1328     case WM_KEYDOWN:
1329     {
1330         window = fghWindowUnderCursor(window);
1331         lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
1332     }
1333     break;
1334
1335     case WM_SYSKEYUP:
1336     case WM_KEYUP:
1337     {
1338         window = fghWindowUnderCursor(window);
1339         lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
1340     }
1341     break;
1342
1343     case WM_SYSCHAR:
1344     case WM_CHAR:
1345     {
1346       window = fghWindowUnderCursor(window);
1347
1348       if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
1349             break;
1350
1351         fgState.Modifiers = fgPlatformGetModifiers( );
1352         INVOKE_WCB( *window, Keyboard,
1353                     ( (char)wParam,
1354                       window->State.MouseX, window->State.MouseY )
1355         );
1356         fgState.Modifiers = INVALID_MODIFIERS;
1357     }
1358     break;
1359
1360     case WM_CAPTURECHANGED:
1361         if (!lParam || !fgWindowByHandle((HWND)lParam))
1362             /* Capture released or capture taken by non-FreeGLUT window */
1363             setCaptureActive = 0;
1364         /* Docs advise a redraw */
1365         InvalidateRect( hWnd, NULL, GL_FALSE );
1366         UpdateWindow(hWnd);
1367         lRet = 0;   /* Per docs, should return zero */
1368         break;
1369
1370 #if !defined(_WIN32_WCE)
1371     case WM_SYNCPAINT:  /* 0x0088 */
1372         /* Another window has moved, need to update this one */
1373         window->State.Redisplay = GL_TRUE;
1374         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1375         /* Help screen says this message must be passed to "DefWindowProc" */
1376         break;
1377
1378     case WM_DISPLAYCHANGE: /* 0x007E */
1379         /* The system display resolution/depth has changed */
1380         fgDisplay.ScreenWidth = LOWORD(lParam);
1381         fgDisplay.ScreenHeight = HIWORD(lParam);
1382         break;
1383
1384     case WM_SYSCOMMAND :  /* 0x0112 */
1385         {
1386           /*
1387            * We have received a system command message.  Try to act on it.
1388            * The commands are passed in through the "wParam" parameter:
1389            * The least significant digit seems to be which edge of the window
1390            * is being used for a resize event:
1391            *     4  3  5
1392            *     1     2
1393            *     7  6  8
1394            * Congratulations and thanks to Richard Rauch for figuring this out..
1395            */
1396             switch ( wParam & 0xfff0 )
1397             {
1398             case SC_SIZE       :
1399                 break ;
1400
1401             case SC_MOVE       :
1402                 break ;
1403
1404             case SC_MINIMIZE   :
1405                 /* User has clicked on the "-" to minimize the window */
1406                 /* Turning off the visibility is handled in WM_SIZE handler */
1407
1408                 break ;
1409
1410             case SC_MAXIMIZE   :
1411                 break ;
1412
1413             case SC_NEXTWINDOW :
1414                 break ;
1415
1416             case SC_PREVWINDOW :
1417                 break ;
1418
1419             case SC_CLOSE      :
1420                 /* Followed very closely by a WM_CLOSE message */
1421                 break ;
1422
1423             case SC_VSCROLL    :
1424                 break ;
1425
1426             case SC_HSCROLL    :
1427                 break ;
1428
1429             case SC_MOUSEMENU  :
1430                 break ;
1431
1432             case SC_KEYMENU    :
1433                 break ;
1434
1435             case SC_ARRANGE    :
1436                 break ;
1437
1438             case SC_RESTORE    :
1439                 break ;
1440
1441             case SC_TASKLIST   :
1442                 break ;
1443
1444             case SC_SCREENSAVE :
1445                 break ;
1446
1447             case SC_HOTKEY     :
1448                 break ;
1449
1450 #if(WINVER >= 0x0400)
1451             case SC_DEFAULT    :
1452                 break ;
1453
1454             case SC_MONITORPOWER    :
1455                 break ;
1456
1457             case SC_CONTEXTHELP    :
1458                 break ;
1459 #endif /* WINVER >= 0x0400 */
1460
1461             default:
1462 #if _DEBUG
1463                 fgWarning( "Unknown wParam type 0x%x", wParam );
1464 #endif
1465                 break;
1466             }
1467         }
1468 #endif /* !defined(_WIN32_WCE) */
1469
1470         /* We need to pass the message on to the operating system as well */
1471         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1472         break;
1473
1474 #ifdef WM_TOUCH
1475         /* handle multi-touch messages */
1476         case WM_TOUCH:
1477         {
1478                 unsigned int numInputs = (unsigned int)wParam;
1479                 unsigned int i = 0;
1480                 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1481
1482                 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1483                     fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1484                     fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1485                 }
1486
1487                 if (!fghGetTouchInputInfo) { 
1488                         free( (void*)ti );
1489                         break;
1490                 }
1491
1492                 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1493                         /* Handle each contact point */
1494                         for (i = 0; i < numInputs; ++i ) {
1495
1496                                 POINT tp;
1497                                 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1498                                 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1499                                 ScreenToClient( hWnd, &tp );
1500
1501                                 ti[i].dwID = ti[i].dwID * 2;
1502
1503                                 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1504                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_ENTERED ) );
1505                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1506                                 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1507                                         INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1508                                 } else if (ti[i].dwFlags & TOUCHEVENTF_UP)   { 
1509                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1510                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_LEFT ) );
1511                                 }
1512                         }
1513                 }
1514                 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1515                 free( (void*)ti );
1516                 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1517                 break;
1518         }
1519 #endif
1520     default:
1521         /* Handle unhandled messages */
1522         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1523         break;
1524     }
1525
1526     return lRet;
1527 }
1528
1529
1530 /* Step through the work list */
1531 void fgPlatformProcessWork(SFG_Window *window)
1532 {
1533     unsigned int workMask = window->State.WorkMask;
1534     /* Now clear it so that any callback generated by the actions below can set work again */
1535     window->State.WorkMask = 0;
1536
1537     /* This is before the first display callback: call a few callbacks to inform user of window size, position, etc
1538      * we know this is before the first display callback of a window as for all windows GLUT_INIT_WORK is set when
1539      * they are opened, and work is done before displaying in the mainloop.
1540      */
1541     if (workMask & GLUT_INIT_WORK)
1542     {
1543         RECT windowRect;
1544
1545         /* Notify windowStatus/visibility */
1546         fghPlatformOnWindowStatusNotify(window, window->State.Visible, GL_TRUE);
1547
1548         /* get and notify window's position */
1549         GetWindowRect(window->Window.Handle,&windowRect);
1550         fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_TRUE);
1551
1552         /* get and notify window's size */
1553         GetClientRect(window->Window.Handle,&windowRect);
1554         fghOnReshapeNotify(window, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, GL_TRUE);
1555
1556         /* Call init context callback */
1557         INVOKE_WCB( *window, InitContext, ());
1558
1559         /* Lastly, check if we have a display callback, error out if not
1560          * This is the right place to do it, as the redisplay will be
1561          * next right after we exit this function, so there is no more
1562          * opportunity for the user to register a callback for this window.
1563          */
1564         if (!FETCH_WCB(*window, Display))
1565             fgError ( "ERROR:  No display callback registered for window %d\n", window->ID );
1566     }
1567
1568     /* On windows we can position, resize and change z order at the same time */
1569     if (workMask & (GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK|GLUT_FULL_SCREEN_WORK))
1570     {
1571         UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
1572         HWND insertAfter = HWND_TOP;
1573         RECT clientRect;
1574
1575 #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1576         if (workMask & GLUT_FULL_SCREEN_WORK)
1577         {
1578             /* This asks us to toggle fullscreen mode */
1579             flags |= SWP_FRAMECHANGED;
1580
1581             if (window->State.IsFullscreen)
1582             {
1583                 /* If we are fullscreen, resize the current window back to its original size */
1584                 /* 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); */
1585
1586                 /* restore style of window before making it fullscreen */
1587                 SetWindowLong(window->Window.Handle, GWL_STYLE, window->State.pWState.OldStyle);
1588                 SetWindowLong(window->Window.Handle, GWL_EXSTYLE, window->State.pWState.OldStyleEx);
1589
1590                 /* Then set up resize/reposition, unless user already queued up reshape/position work */
1591                 if (!(workMask & GLUT_POSITION_WORK))
1592                 {
1593                     workMask |= GLUT_POSITION_WORK;
1594                     window->State.DesiredXpos   = window->State.pWState.OldRect.left;
1595                     window->State.DesiredYpos   = window->State.pWState.OldRect.top;
1596                 }
1597                 if (!(workMask & GLUT_SIZE_WORK))
1598                 {
1599                     workMask |= GLUT_SIZE_WORK;
1600                     window->State.DesiredWidth  = window->State.pWState.OldRect.right  - window->State.pWState.OldRect.left;
1601                     window->State.DesiredHeight = window->State.pWState.OldRect.bottom - window->State.pWState.OldRect.top;
1602                 }
1603                 
1604                 /* We'll finish off the fullscreen operation below after the other GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK */
1605             }
1606             else
1607             {
1608                 /* we are currently not fullscreen, go to fullscreen:
1609                  * remove window decoration and then maximize
1610                  */
1611                 RECT rect;
1612                 HMONITOR hMonitor;
1613                 MONITORINFO mi;
1614         
1615                 /* save current window rect, style, exstyle and maximized state */
1616                 window->State.pWState.OldMaximized = !!IsZoomed(window->Window.Handle);
1617                 if (window->State.pWState.OldMaximized)
1618                     /* We force the window into restored mode before going
1619                      * fullscreen because Windows doesn't seem to hide the
1620                      * taskbar if the window is in the maximized state.
1621                      */
1622                     SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
1623
1624                 fghGetClientArea( &window->State.pWState.OldRect, window, GL_TRUE );
1625                 window->State.pWState.OldStyle   = GetWindowLong(window->Window.Handle, GWL_STYLE);
1626                 window->State.pWState.OldStyleEx = GetWindowLong(window->Window.Handle, GWL_EXSTYLE);
1627
1628                 /* remove decorations from style */
1629                 SetWindowLong(window->Window.Handle, GWL_STYLE,
1630                               window->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME));
1631                 SetWindowLong(window->Window.Handle, GWL_EXSTYLE,
1632                               window->State.pWState.OldStyleEx & ~(WS_EX_DLGMODALFRAME |
1633                               WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
1634
1635                 /* For fullscreen mode, find the monitor that is covered the most
1636                  * by the window and get its rect as the resize target.
1637                      */
1638                 GetWindowRect(window->Window.Handle, &rect);
1639                 hMonitor= MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
1640                 mi.cbSize = sizeof(mi);
1641                 GetMonitorInfo(hMonitor, &mi);
1642                 rect = mi.rcMonitor;
1643
1644                 /* then setup window resize, overwriting other work queued on the window */
1645                 window->State.WorkMask |= GLUT_POSITION_WORK | GLUT_SIZE_WORK;
1646                 window->State.WorkMask &= ~GLUT_ZORDER_WORK;
1647                 window->State.DesiredXpos   = rect.left;
1648                 window->State.DesiredYpos   = rect.top;
1649                 window->State.DesiredWidth  = rect.right  - rect.left;
1650                 window->State.DesiredHeight = rect.bottom - rect.top;
1651             }
1652         }
1653 #endif /*!defined(_WIN32_WCE) */
1654
1655         /* Now deal with normal position, reshape and z order requests (some might have been set when handling GLUT_FULLSCREEN_WORK above */
1656         {
1657             /* get rect describing window's current position and size, 
1658              * in screen coordinates and in FreeGLUT format
1659              * (size (right-left, bottom-top) is client area size, top and left
1660              * are outside of window including decorations).
1661              */
1662             fghGetClientArea( &clientRect, window, TRUE );
1663
1664             if (workMask & GLUT_POSITION_WORK)
1665             {
1666                 flags &= ~SWP_NOMOVE;
1667                 
1668                 /* Move rect so that top-left is at requested position */
1669                 /* This also automatically makes sure that child window requested coordinates are relative
1670                  * to top-left of parent's client area (needed input for SetWindowPos on child windows),
1671                  * so no need to further correct rect for child windows below (childs don't have decorations either).
1672                  */
1673                 OffsetRect(&clientRect,window->State.DesiredXpos-clientRect.left,window->State.DesiredYpos-clientRect.top);
1674             }
1675             if (workMask & GLUT_SIZE_WORK)
1676             {
1677                 flags &= ~SWP_NOSIZE;
1678                 
1679                 /* Note on maximizing behavior of Windows: the resize borders are off
1680                  * the screen such that the client area extends all the way from the
1681                  * leftmost corner to the rightmost corner to maximize screen real
1682                  * estate. A caption is still shown however to allow interaction with
1683                  * the window controls. This is default behavior of Windows that
1684                  * FreeGLUT sticks with. To alter, one would have to check if
1685                  * WS_MAXIMIZE style is set when a resize event is triggered, and
1686                  * then manually correct the windowRect to put the borders back on
1687                  * screen.
1688                  */
1689
1690                 /* Set new size of window, WxH specify client area */
1691                 clientRect.right    = clientRect.left + window->State.DesiredWidth;
1692                 clientRect.bottom   = clientRect.top  + window->State.DesiredHeight;
1693             }
1694             if (workMask & GLUT_ZORDER_WORK)
1695             {
1696                 flags &= ~SWP_NOZORDER;
1697
1698                 /* Could change this to push it down or up one window at a time with some
1699                  * more code using GetWindow with GW_HWNDPREV and GW_HWNDNEXT.
1700                  * What would be consistent with X11? Win32 GLUT does what we do here...
1701                  */
1702                 if (window->State.DesiredZOrder < 0)
1703                     insertAfter = HWND_BOTTOM;
1704             }
1705         }
1706
1707         /* Adjust for window decorations
1708          * Child windows don't have decoration, so no need to correct
1709          */
1710         if (!window->Parent)
1711             /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
1712             fghComputeWindowRectFromClientArea_QueryWindow(&clientRect,window,TRUE);
1713     
1714         /* Do the requested positioning, moving, and z order push/pop. */
1715         SetWindowPos( window->Window.Handle,
1716                       insertAfter,
1717                       clientRect.left, clientRect.top,
1718                       clientRect.right - clientRect.left,
1719                       clientRect.bottom- clientRect.top,
1720                       flags
1721         );
1722
1723         /* Finish off the fullscreen operation we were doing, if any */
1724         if (workMask & GLUT_FULL_SCREEN_WORK)
1725         {
1726             if (window->State.IsFullscreen)
1727             {
1728                 /* leaving fullscreen, restore maximized state, if any */
1729                 if (window->State.pWState.OldMaximized)
1730                     SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
1731
1732                 window->State.IsFullscreen = GL_FALSE;
1733             }
1734             else
1735                 window->State.IsFullscreen = GL_TRUE;
1736         }
1737     }
1738
1739     if (workMask & GLUT_VISIBILITY_WORK)
1740     {
1741         /* Visibility status of window gets updated in the WM_SHOWWINDOW and WM_SIZE handlers */
1742         int cmdShow = 0;
1743         SFG_Window *win = window;
1744         switch (window->State.DesiredVisibility)
1745         {
1746         case DesireHiddenState:
1747             cmdShow = SW_HIDE;
1748             break;
1749         case DesireIconicState:
1750             cmdShow = SW_MINIMIZE;
1751             /* Call on top-level window */
1752             while (win->Parent)
1753                 win = win->Parent;
1754             break;
1755         case DesireNormalState:
1756             if (win->IsMenu)
1757                 cmdShow = SW_SHOWNOACTIVATE;    /* Just show, don't activate if its a menu */
1758             else
1759                 cmdShow = SW_SHOW;
1760             break;
1761         }
1762
1763         ShowWindow( win->Window.Handle, cmdShow );
1764     }
1765 }