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