Added subwindows to CallbackMaker demo, for testing and demonstration. Also figured...
[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
32 extern void fghRedrawWindow ( SFG_Window *window );
33
34 extern void fgNewWGLCreateContext( SFG_Window* window );
35 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
36                                      unsigned char layer_type );
37
38 extern void fgPlatformCheckMenuDeactivate();
39
40 #ifdef WM_TOUCH
41 typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
42 typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
43 static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
44 static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
45 #endif
46
47 #ifdef _WIN32_WCE
48 typedef struct GXDisplayProperties GXDisplayProperties;
49 typedef struct GXKeyList GXKeyList;
50 #include <gx.h>
51
52 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
53 typedef int (*GXOPENINPUT)();
54
55 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
56 GXOPENINPUT GXOpenInput_ = NULL;
57
58 struct GXKeyList gxKeyList;
59 #endif /* _WIN32_WCE */
60
61
62 /* Get system time, taking special precautions against 32bit timer wrap.
63    We use timeGetTime and not GetTickCount because of its better stability,
64    and because we can increase its granularity (to 1 ms in
65    fgPlatformInitialize). For that reason we can't use GetTickCount64 which
66    wouldn't have the wrap issue.
67    Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html)
68    */
69 static fg_time_t lastTime32 = 0;
70 static fg_time_t timeEpoch = 0;
71 void fgPlatformInitSystemTime()
72 {
73 #if defined(_WIN32_WCE)
74     lastTime32 = GetTickCount();
75 #else
76     lastTime32 = timeGetTime();
77 #endif
78 }
79 fg_time_t fgPlatformSystemTime ( void )
80 {
81     fg_time_t currTime32;
82 #if defined(_WIN32_WCE)
83     currTime32 = GetTickCount();
84 #else
85     currTime32 = timeGetTime();
86 #endif
87     /* Check if we just wrapped */
88     if (currTime32 < lastTime32)
89         timeEpoch++;
90     
91     lastTime32 = currTime32;
92
93     return currTime32 | timeEpoch << 32;
94 }
95
96
97 void fgPlatformSleepForEvents( fg_time_t msec )
98 {
99     MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
100 }
101
102
103 void fgPlatformProcessSingleEvent ( void )
104 {
105     MSG stMsg;
106
107     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
108
109     while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
110     {
111         if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
112         {
113             if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
114             {
115                 fgDeinitialize( );
116                 exit( 0 );
117             }
118             else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
119                 fgState.ExecState = GLUT_EXEC_STATE_STOP;
120
121             return;
122         }
123
124         TranslateMessage( &stMsg );
125         DispatchMessage( &stMsg );
126     }
127 }
128
129
130
131 void fgPlatformMainLoopPreliminaryWork ( void )
132 {
133     SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
134
135     /*
136      * Processing before the main loop:  If there is a window which is open and
137      * which has a visibility callback, call it.  I know this is an ugly hack,
138      * but I'm not sure what else to do about it.  Ideally we should leave
139      * something uninitialized in the create window code and initialize it in
140      * the main loop, and have that initialization create a "WM_ACTIVATE"
141      * message.  Then we would put the visibility callback code in the
142      * "case WM_ACTIVATE" block below.         - John Fay -- 10/24/02
143      */
144     while( window )
145     {
146         if ( FETCH_WCB( *window, Visibility ) )
147         {
148             SFG_Window *current_window = fgStructure.CurrentWindow ;
149
150             INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
151             fgSetWindow( current_window );
152         }
153
154         window = (SFG_Window *)window->Node.Next ;
155     }
156 }
157
158
159 /*
160  * Determine a GLUT modifier mask based on MS-WINDOWS system info.
161  */
162 static int fgPlatformGetModifiers (void)
163 {
164     return
165         ( ( ( GetKeyState( VK_LSHIFT   ) < 0 ) ||
166             ( GetKeyState( VK_RSHIFT   ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
167         ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
168             ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL  : 0 ) |
169         ( ( ( GetKeyState( VK_LMENU    ) < 0 ) ||
170             ( GetKeyState( VK_RMENU    ) < 0 )) ? GLUT_ACTIVE_ALT   : 0 );
171 }
172
173 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
174 {
175     static unsigned char lControl = 0, lShift = 0, lAlt = 0,
176                          rControl = 0, rShift = 0, rAlt = 0;
177
178     int keypress = -1;
179     POINT mouse_pos ;
180     
181     /* if keydown, check for repeat */
182     /* If repeat is globally switched off, it cannot be switched back on per window.
183      * But if it is globally switched on, it can be switched off per window. This matches
184      * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
185      * global state switch.
186      */
187     if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
188         return 1;
189     
190     /* Remember the current modifiers state so user can query it from their callback */
191     fgState.Modifiers = fgPlatformGetModifiers( );
192
193     /* Get mouse position roughly at time of keypress */
194     GetCursorPos( &mouse_pos );
195     ScreenToClient( window->Window.Handle, &mouse_pos );
196     window->State.MouseX = mouse_pos.x;
197     window->State.MouseY = mouse_pos.y;
198
199     /* Convert the Win32 keystroke codes to GLUTtish way */
200 #   define KEY(a,b) case a: keypress = b; break;
201
202     switch( wParam )
203     {
204         KEY( VK_F1,     GLUT_KEY_F1        );
205         KEY( VK_F2,     GLUT_KEY_F2        );
206         KEY( VK_F3,     GLUT_KEY_F3        );
207         KEY( VK_F4,     GLUT_KEY_F4        );
208         KEY( VK_F5,     GLUT_KEY_F5        );
209         KEY( VK_F6,     GLUT_KEY_F6        );
210         KEY( VK_F7,     GLUT_KEY_F7        );
211         KEY( VK_F8,     GLUT_KEY_F8        );
212         KEY( VK_F9,     GLUT_KEY_F9        );
213         KEY( VK_F10,    GLUT_KEY_F10       );
214         KEY( VK_F11,    GLUT_KEY_F11       );
215         KEY( VK_F12,    GLUT_KEY_F12       );
216         KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
217         KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
218         KEY( VK_HOME,   GLUT_KEY_HOME      );
219         KEY( VK_END,    GLUT_KEY_END       );
220         KEY( VK_LEFT,   GLUT_KEY_LEFT      );
221         KEY( VK_UP,     GLUT_KEY_UP        );
222         KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
223         KEY( VK_DOWN,   GLUT_KEY_DOWN      );
224         KEY( VK_INSERT, GLUT_KEY_INSERT    );
225
226     /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
227      * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
228      * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
229      */
230 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
231     if (!keyStateVar && GetAsyncKeyState ( winKey ))\
232     {\
233         keypress   = glutKey;\
234         keyStateVar = 1;\
235     }\
236     else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
237     {\
238         keypress   = glutKey;\
239         keyStateVar = 0;\
240     }
241     case VK_CONTROL:
242         ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
243         ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
244         break;
245     case VK_SHIFT:
246         ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
247         ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
248         break;
249     case VK_MENU:
250         ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
251         ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
252         break;
253 #undef ASYNC_KEY_EVENT
254
255     case VK_DELETE:
256         /* The delete key should be treated as an ASCII keypress: */
257         if (keydown)
258             INVOKE_WCB( *window, Keyboard,
259                         ( 127, window->State.MouseX, window->State.MouseY )
260             );
261         else
262             INVOKE_WCB( *window, KeyboardUp,
263                         ( 127, window->State.MouseX, window->State.MouseY )
264             );
265         break;
266
267 #if !defined(_WIN32_WCE)
268     default:
269         /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
270         if (!keydown)
271         {
272             BYTE state[ 256 ];
273             WORD code[ 2 ];
274
275             GetKeyboardState( state );
276
277             if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
278                 wParam=code[ 0 ];
279
280             INVOKE_WCB( *window, KeyboardUp,
281                    ( (char)wParam,
282                         window->State.MouseX, window->State.MouseY )
283             );
284         }
285 #endif
286     }
287
288 #if defined(_WIN32_WCE)
289     if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
290     {
291         if(wParam==(unsigned)gxKeyList.vkRight)
292             keypress = GLUT_KEY_RIGHT;
293         else if(wParam==(unsigned)gxKeyList.vkLeft)
294             keypress = GLUT_KEY_LEFT;
295         else if(wParam==(unsigned)gxKeyList.vkUp)
296             keypress = GLUT_KEY_UP;
297         else if(wParam==(unsigned)gxKeyList.vkDown)
298             keypress = GLUT_KEY_DOWN;
299         else if(wParam==(unsigned)gxKeyList.vkA)
300             keypress = GLUT_KEY_F1;
301         else if(wParam==(unsigned)gxKeyList.vkB)
302             keypress = GLUT_KEY_F2;
303         else if(wParam==(unsigned)gxKeyList.vkC)
304             keypress = GLUT_KEY_F3;
305         else if(wParam==(unsigned)gxKeyList.vkStart)
306             keypress = GLUT_KEY_F4;
307     }
308 #endif
309     
310     if( keypress != -1 )
311         if (keydown)
312             INVOKE_WCB( *window, Special,
313                         ( keypress,
314                             window->State.MouseX, window->State.MouseY )
315             );
316         else
317             INVOKE_WCB( *window, SpecialUp,
318                         ( keypress,
319                             window->State.MouseX, window->State.MouseY )
320             );
321
322     fgState.Modifiers = INVALID_MODIFIERS;
323
324     /* SYSKEY events should be sent to default window proc for system to handle them */
325     if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
326         return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
327     else
328         return 1;
329 }
330
331 void fghWindowUnderCursor(SFG_Window *window, SFG_Window **child_window)
332 {
333     /* Check if the current window that the mouse is over is a child window
334      * of the window the message was sent to.
335      */
336     if (window && window->Children.First)
337     {
338         POINT mouse_pos;
339         SFG_WindowHandleType hwnd;
340         SFG_Window* temp_window;
341
342         GetCursorPos( &mouse_pos );
343         ScreenToClient( window->Window.Handle, &mouse_pos );
344         hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
345         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 */
346         {
347             temp_window = fgWindowByHandle(hwnd);
348             if (temp_window)    /* Verify we got a FreeGLUT window */
349             {
350                 *child_window = temp_window;
351                 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
352                 fghWindowUnderCursor(temp_window,child_window);
353             }
354         }
355     }
356 }
357
358 /*
359  * The window procedure for handling Win32 events
360  */
361 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
362 {
363     SFG_Window *window, *child_window = NULL;
364     PAINTSTRUCT ps;
365     LRESULT lRet = 1;
366
367     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
368
369     window = fgWindowByHandle( hWnd );
370
371     if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
372       return DefWindowProc( hWnd, uMsg, wParam, lParam );
373
374     /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
375              uMsg, wParam, lParam ); */
376
377     /* Some events only sent to main window. Check if the current window that
378      * the mouse is over is a child window. Below when handling some messages,
379      * we make sure that we process callbacks on the child window instead.
380      * This mirrors how GLUT does things.
381      */
382     fghWindowUnderCursor(window, &child_window);
383     
384     switch( uMsg )
385     {
386     case WM_CREATE:
387         /* The window structure is passed as the creation structure parameter... */
388         window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
389         FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
390                                        "fgPlatformWindowProc" );
391
392         window->Window.Handle = hWnd;
393         window->Window.pContext.Device = GetDC( hWnd );
394         if( window->IsMenu )
395         {
396             unsigned int current_DisplayMode = fgState.DisplayMode;
397             fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
398 #if !defined(_WIN32_WCE)
399             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
400 #endif
401             fgState.DisplayMode = current_DisplayMode;
402
403             if( fgStructure.MenuContext )
404                 wglMakeCurrent( window->Window.pContext.Device,
405                                 fgStructure.MenuContext->MContext
406                 );
407             else
408             {
409                 fgStructure.MenuContext =
410                     (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
411                 fgStructure.MenuContext->MContext =
412                     wglCreateContext( window->Window.pContext.Device );
413             }
414
415             /* window->Window.Context = wglGetCurrentContext ();   */
416             window->Window.Context = wglCreateContext( window->Window.pContext.Device );
417         }
418         else
419         {
420 #if !defined(_WIN32_WCE)
421             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
422 #endif
423
424             if( ! fgState.UseCurrentContext )
425                 window->Window.Context =
426                     wglCreateContext( window->Window.pContext.Device );
427             else
428             {
429                 window->Window.Context = wglGetCurrentContext( );
430                 if( ! window->Window.Context )
431                     window->Window.Context =
432                         wglCreateContext( window->Window.pContext.Device );
433             }
434
435 #if !defined(_WIN32_WCE)
436             fgNewWGLCreateContext( window );
437 #endif
438         }
439
440         window->State.NeedToResize = GL_TRUE;
441         /* if we used CW_USEDEFAULT (thats a negative value) for the size
442          * of the window, query the window now for the size at which it
443          * was created.
444          */
445         if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
446         {
447             SFG_Window *current_window = fgStructure.CurrentWindow;
448
449             fgSetWindow( window );
450             window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
451             window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
452             fgSetWindow( current_window );
453         }
454
455         ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
456
457 #if defined(_WIN32_WCE)
458         /* Take over button handling */
459         {
460             HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
461             if (dxDllLib)
462             {
463                 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
464                 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
465             }
466
467             if(GXOpenInput_)
468                 (*GXOpenInput_)();
469             if(GXGetDefaultKeys_)
470                 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
471         }
472
473 #endif /* defined(_WIN32_WCE) */
474         break;
475
476     case WM_SIZE:
477         /*
478          * If the window is visible, then it is the user manually resizing it.
479          * If it is not, then it is the system sending us a dummy resize with
480          * zero dimensions on a "glutIconifyWindow" call.
481          */
482         if( window->State.Visible )
483         {
484             /* get old values first to compare to below */
485             int width = window->State.Width, height=window->State.Height;
486 #if defined(_WIN32_WCE)
487             window->State.Width  = HIWORD(lParam);
488             window->State.Height = LOWORD(lParam);
489 #else
490             window->State.Width  = LOWORD(lParam);
491             window->State.Height = HIWORD(lParam);
492 #endif /* defined(_WIN32_WCE) */
493             
494             if (width!=window->State.Width || height!=window->State.Height)
495                 /* Something changed, need to resize */
496                 window->State.NeedToResize = GL_TRUE;
497         }
498
499         break;
500
501     case WM_MOVE:
502         {
503             SFG_Window* saved_window = fgStructure.CurrentWindow;
504             RECT windowRect;
505             GetWindowRect( window->Window.Handle, &windowRect );
506             
507             if (window->Parent)
508             {
509                 /* For child window, we should return relative to upper-left
510                 * of parent's client area.
511                 */
512                 POINT topleft = {windowRect.left,windowRect.top};
513
514                 ScreenToClient(window->Parent->Window.Handle,&topleft);
515                 windowRect.left = topleft.x;
516                 windowRect.top  = topleft.y;
517             }
518
519             INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
520             fgSetWindow(saved_window);
521         }
522         break;
523
524     case WM_SETFOCUS:
525 /*        printf("WM_SETFOCUS: %p\n", window ); */
526
527         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
528
529         if (child_window)
530         {
531             /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
532             SetFocus(child_window->Window.Handle);
533             SetActiveWindow( child_window->Window.Handle );
534             INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
535             UpdateWindow ( child_window->Window.Handle );
536         }
537         else
538         {
539             SetActiveWindow( window->Window.Handle );
540             INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
541         }
542         /* Always request update on main window to be safe */
543         UpdateWindow ( hWnd );
544
545         break;
546
547     case WM_KILLFOCUS:
548         {
549             SFG_Window* saved_window = fgStructure.CurrentWindow;
550 /*            printf("WM_KILLFOCUS: %p\n", window ); */
551             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
552             INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
553             fgSetWindow(saved_window);
554
555             /* Check if there are any open menus that need to be closed */
556             fgPlatformCheckMenuDeactivate();
557         }
558         break;
559
560 #if 0
561     case WM_ACTIVATE:
562         if (LOWORD(wParam) != WA_INACTIVE)
563         {
564 /*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
565                    window->State.Cursor ); */
566             fgSetCursor( window, window->State.Cursor );
567         }
568
569         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
570         break;
571 #endif
572
573     case WM_SETCURSOR:
574 /*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
575         if( LOWORD( lParam ) == HTCLIENT )
576             fgSetCursor ( window, window->State.Cursor ) ;
577         else
578             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
579         break;
580
581     case WM_SHOWWINDOW:
582         window->State.Visible = GL_TRUE;
583         window->State.Redisplay = GL_TRUE;
584         break;
585
586     case WM_PAINT:
587         /* Turn on the visibility in case it was turned off somehow */
588         window->State.Visible = GL_TRUE;
589         InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
590         BeginPaint( hWnd, &ps );
591         fghRedrawWindow( window );
592         EndPaint( hWnd, &ps );
593         break;
594
595     case WM_CLOSE:
596         fgDestroyWindow ( window );
597         if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
598             PostQuitMessage(0);
599         break;
600
601     case WM_DESTROY:
602         /*
603          * The window already got destroyed, so don't bother with it.
604          */
605         return 0;
606
607     case WM_MOUSEMOVE:
608     {
609 #if defined(_WIN32_WCE)
610         window->State.MouseX = 320-HIWORD( lParam );
611         window->State.MouseY = LOWORD( lParam );
612 #else
613         window->State.MouseX = LOWORD( lParam );
614         window->State.MouseY = HIWORD( lParam );
615 #endif /* defined(_WIN32_WCE) */
616         /* Restrict to [-32768, 32767] to match X11 behaviour       */
617         /* See comment in "freeglut_developer" mailing list 10/4/04 */
618         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
619         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
620
621         if ( window->ActiveMenu )
622         {
623             fgUpdateMenuHighlight( window->ActiveMenu );
624             break;
625         }
626
627         fgState.Modifiers = fgPlatformGetModifiers( );
628
629         if( ( wParam & MK_LBUTTON ) ||
630             ( wParam & MK_MBUTTON ) ||
631             ( wParam & MK_RBUTTON ) )
632             INVOKE_WCB( *window, Motion, ( window->State.MouseX,
633                                            window->State.MouseY ) );
634         else
635             INVOKE_WCB( *window, Passive, ( window->State.MouseX,
636                                             window->State.MouseY ) );
637
638         fgState.Modifiers = INVALID_MODIFIERS;
639     }
640     break;
641
642     case WM_LBUTTONDOWN:
643     case WM_MBUTTONDOWN:
644     case WM_RBUTTONDOWN:
645     case WM_LBUTTONUP:
646     case WM_MBUTTONUP:
647     case WM_RBUTTONUP:
648     {
649         GLboolean pressed = GL_TRUE;
650         int button;
651
652 #if defined(_WIN32_WCE)
653         window->State.MouseX = 320-HIWORD( lParam );
654         window->State.MouseY = LOWORD( lParam );
655 #else
656         window->State.MouseX = LOWORD( lParam );
657         window->State.MouseY = HIWORD( lParam );
658 #endif /* defined(_WIN32_WCE) */
659
660         /* Restrict to [-32768, 32767] to match X11 behaviour       */
661         /* See comment in "freeglut_developer" mailing list 10/4/04 */
662         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
663         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
664
665         switch( uMsg )
666         {
667         case WM_LBUTTONDOWN:
668             pressed = GL_TRUE;
669             button = GLUT_LEFT_BUTTON;
670             break;
671         case WM_MBUTTONDOWN:
672             pressed = GL_TRUE;
673             button = GLUT_MIDDLE_BUTTON;
674             break;
675         case WM_RBUTTONDOWN:
676             pressed = GL_TRUE;
677             button = GLUT_RIGHT_BUTTON;
678             break;
679         case WM_LBUTTONUP:
680             pressed = GL_FALSE;
681             button = GLUT_LEFT_BUTTON;
682             break;
683         case WM_MBUTTONUP:
684             pressed = GL_FALSE;
685             button = GLUT_MIDDLE_BUTTON;
686             break;
687         case WM_RBUTTONUP:
688             pressed = GL_FALSE;
689             button = GLUT_RIGHT_BUTTON;
690             break;
691         default:
692             pressed = GL_FALSE;
693             button = -1;
694             break;
695         }
696
697 #if !defined(_WIN32_WCE)
698         if( GetSystemMetrics( SM_SWAPBUTTON ) )
699         {
700             if( button == GLUT_LEFT_BUTTON )
701                 button = GLUT_RIGHT_BUTTON;
702             else
703                 if( button == GLUT_RIGHT_BUTTON )
704                     button = GLUT_LEFT_BUTTON;
705         }
706 #endif /* !defined(_WIN32_WCE) */
707
708         if( button == -1 )
709             return DefWindowProc( hWnd, uMsg, lParam, wParam );
710
711         /*
712          * Do not execute the application's mouse callback if a menu
713          * is hooked to this button.  In that case an appropriate
714          * private call should be generated.
715          */
716         if( fgCheckActiveMenu( window, button, pressed,
717                                window->State.MouseX, window->State.MouseY ) )
718             break;
719
720         /* Set capture so that the window captures all the mouse messages */
721         /*
722          * XXX - Multiple button support:  Under X11, the mouse is not released
723          * XXX - from the window until all buttons have been released, even if the
724          * XXX - user presses a button in another window.  This will take more
725          * XXX - code changes than I am up to at the moment (10/5/04).  The present
726          * XXX - is a 90 percent solution.
727          */
728         if ( pressed == GL_TRUE )
729           SetCapture ( window->Window.Handle ) ;
730         else
731           ReleaseCapture () ;
732
733         if( ! FETCH_WCB( *window, Mouse ) )
734             break;
735
736         fgSetWindow( window );
737         fgState.Modifiers = fgPlatformGetModifiers( );
738
739         INVOKE_WCB(
740             *window, Mouse,
741             ( button,
742               pressed ? GLUT_DOWN : GLUT_UP,
743               window->State.MouseX,
744               window->State.MouseY
745             )
746         );
747
748         fgState.Modifiers = INVALID_MODIFIERS;
749     }
750     break;
751
752     case WM_MOUSEWHEEL:
753     {
754         int wheel_number = LOWORD( wParam );
755         short ticks = ( short )HIWORD( wParam );
756                 fgState.MouseWheelTicks += ticks;
757
758         if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
759                 {
760                         int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
761
762             if( ! FETCH_WCB( *window, MouseWheel ) &&
763                 ! FETCH_WCB( *window, Mouse ) )
764                 break;
765
766             fgSetWindow( window );
767             fgState.Modifiers = fgPlatformGetModifiers( );
768
769             while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
770                         {
771                 if( FETCH_WCB( *window, MouseWheel ) )
772                     INVOKE_WCB( *window, MouseWheel,
773                                 ( wheel_number,
774                                   direction,
775                                   window->State.MouseX,
776                                   window->State.MouseY
777                                 )
778                     );
779                 else  /* No mouse wheel, call the mouse button callback twice */
780                                 {
781                     /*
782                      * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
783                      *  "    "   one                     +1 to 5, -1 to 6, ...
784                      *
785                      * XXX The below assumes that you have no more than 3 mouse
786                      * XXX buttons.  Sorry.
787                      */
788                     int button = wheel_number * 2 + 3;
789                     if( direction < 0 )
790                         ++button;
791                     INVOKE_WCB( *window, Mouse,
792                                 ( button, GLUT_DOWN,
793                                   window->State.MouseX, window->State.MouseY )
794                     );
795                     INVOKE_WCB( *window, Mouse,
796                                 ( button, GLUT_UP,
797                                   window->State.MouseX, window->State.MouseY )
798                     );
799                                 }
800
801                                 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
802                         }
803
804             fgState.Modifiers = INVALID_MODIFIERS;
805                 }
806     }
807     break ;
808
809     case WM_SYSKEYDOWN:
810     case WM_KEYDOWN:
811         if (child_window)
812             window = child_window;
813         lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
814     break;
815
816     case WM_SYSKEYUP:
817     case WM_KEYUP:
818         if (child_window)
819             window = child_window;
820         lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
821     break;
822
823     case WM_SYSCHAR:
824     case WM_CHAR:
825     {
826       if (child_window)
827         window = child_window;
828
829       if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
830             break;
831
832         fgState.Modifiers = fgPlatformGetModifiers( );
833         INVOKE_WCB( *window, Keyboard,
834                     ( (char)wParam,
835                       window->State.MouseX, window->State.MouseY )
836         );
837         fgState.Modifiers = INVALID_MODIFIERS;
838     }
839     break;
840
841     case WM_CAPTURECHANGED:
842         /* User has finished resizing the window, force a redraw */
843         INVOKE_WCB( *window, Display, ( ) );
844
845         /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
846         break;
847
848         /* Other messages that I have seen and which are not handled already */
849     case WM_SETTEXT:  /* 0x000c */
850         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
851         /* Pass it on to "DefWindowProc" to set the window text */
852         break;
853
854     case WM_GETTEXT:  /* 0x000d */
855         /* Ideally we would copy the title of the window into "lParam" */
856         /* strncpy ( (char *)lParam, "Window Title", wParam );
857            lRet = ( wParam > 12 ) ? 12 : wParam;  */
858         /* the number of characters copied */
859         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
860         break;
861
862     case WM_GETTEXTLENGTH:  /* 0x000e */
863         /* Ideally we would get the length of the title of the window */
864         lRet = 12;
865         /* the number of characters in "Window Title\0" (see above) */
866         break;
867
868     case WM_ERASEBKGND:  /* 0x0014 */
869         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
870         break;
871
872 #if !defined(_WIN32_WCE)
873     case WM_SYNCPAINT:  /* 0x0088 */
874         /* Another window has moved, need to update this one */
875         window->State.Redisplay = GL_TRUE;
876         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
877         /* Help screen says this message must be passed to "DefWindowProc" */
878         break;
879
880     case WM_NCPAINT:  /* 0x0085 */
881       /* Need to update the border of this window */
882         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
883         /* Pass it on to "DefWindowProc" to repaint a standard border */
884         break;
885
886     case WM_SYSCOMMAND :  /* 0x0112 */
887         {
888           /*
889            * We have received a system command message.  Try to act on it.
890            * The commands are passed in through the "wParam" parameter:
891            * The least significant digit seems to be which edge of the window
892            * is being used for a resize event:
893            *     4  3  5
894            *     1     2
895            *     7  6  8
896            * Congratulations and thanks to Richard Rauch for figuring this out..
897            */
898             switch ( wParam & 0xfff0 )
899             {
900             case SC_SIZE       :
901                 break ;
902
903             case SC_MOVE       :
904                 break ;
905
906             case SC_MINIMIZE   :
907                 /* User has clicked on the "-" to minimize the window */
908                 /* Turn off the visibility */
909                 window->State.Visible = GL_FALSE ;
910
911                 break ;
912
913             case SC_MAXIMIZE   :
914                 break ;
915
916             case SC_NEXTWINDOW :
917                 break ;
918
919             case SC_PREVWINDOW :
920                 break ;
921
922             case SC_CLOSE      :
923                 /* Followed very closely by a WM_CLOSE message */
924                 break ;
925
926             case SC_VSCROLL    :
927                 break ;
928
929             case SC_HSCROLL    :
930                 break ;
931
932             case SC_MOUSEMENU  :
933                 break ;
934
935             case SC_KEYMENU    :
936                 break ;
937
938             case SC_ARRANGE    :
939                 break ;
940
941             case SC_RESTORE    :
942                 break ;
943
944             case SC_TASKLIST   :
945                 break ;
946
947             case SC_SCREENSAVE :
948                 break ;
949
950             case SC_HOTKEY     :
951                 break ;
952
953 #if(WINVER >= 0x0400)
954             case SC_DEFAULT    :
955                 break ;
956
957             case SC_MONITORPOWER    :
958                 break ;
959
960             case SC_CONTEXTHELP    :
961                 break ;
962 #endif /* WINVER >= 0x0400 */
963
964             default:
965 #if _DEBUG
966                 fgWarning( "Unknown wParam type 0x%x", wParam );
967 #endif
968                 break;
969             }
970         }
971 #endif /* !defined(_WIN32_WCE) */
972
973         /* We need to pass the message on to the operating system as well */
974         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
975         break;
976
977 #ifdef WM_TOUCH
978         /* handle multi-touch messages */
979         case WM_TOUCH:
980         {
981                 unsigned int numInputs = (unsigned int)wParam;
982                 unsigned int i = 0;
983                 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
984
985                 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
986                     fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
987                     fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
988                 }
989
990                 if (!fghGetTouchInputInfo) { 
991                         free( (void*)ti );
992                         break;
993                 }
994
995                 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
996                         /* Handle each contact point */
997                         for (i = 0; i < numInputs; ++i ) {
998
999                                 POINT tp;
1000                                 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1001                                 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1002                                 ScreenToClient( hWnd, &tp );
1003
1004                                 ti[i].dwID = ti[i].dwID * 2;
1005
1006                                 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1007                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_ENTERED ) );
1008                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1009                                 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1010                                         INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1011                                 } else if (ti[i].dwFlags & TOUCHEVENTF_UP)   { 
1012                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1013                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_LEFT ) );
1014                                 }
1015                         }
1016                 }
1017                 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1018                 free( (void*)ti );
1019                 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1020                 break;
1021         }
1022 #endif
1023     default:
1024         /* Handle unhandled messages */
1025         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1026         break;
1027     }
1028
1029     return lRet;
1030 }