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