freeglut_main.c
上传用户:gb3593
上传日期:2022-01-07
资源大小:3028k
文件大小:74k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /*
  2.  * freeglut_main.c
  3.  *
  4.  * The windows message processing methods.
  5.  *
  6.  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
  7.  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
  8.  * Creation date: Fri Dec 3 1999
  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. #include <GL/freeglut.h>
  28. #include "freeglut_internal.h"
  29. #if HAVE_ERRNO
  30. #    include <errno.h>
  31. #endif
  32. #include <stdarg.h>
  33. #if  HAVE_VPRINTF
  34. #    define VFPRINTF(s,f,a) vfprintf((s),(f),(a))
  35. #elif HAVE_DOPRNT
  36. #    define VFPRINTF(s,f,a) _doprnt((f),(a),(s))
  37. #else
  38. #    define VFPRINTF(s,f,a)
  39. #endif
  40. #ifdef _WIN32_WCE
  41. typedef struct GXDisplayProperties GXDisplayProperties;
  42. typedef struct GXKeyList GXKeyList;
  43. #include <gx.h>
  44. typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
  45. typedef int (*GXOPENINPUT)();
  46. GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
  47. GXOPENINPUT GXOpenInput_ = NULL;
  48. struct GXKeyList gxKeyList;
  49. #endif /* _WIN32_WCE */
  50. /*
  51.  * Try to get the maximum value allowed for ints, falling back to the minimum
  52.  * guaranteed by ISO C99 if there is no suitable header.
  53.  */
  54. #if HAVE_LIMITS_H
  55. #    include <limits.h>
  56. #endif
  57. #ifndef INT_MAX
  58. #    define INT_MAX 32767
  59. #endif
  60. #ifndef MIN
  61. #    define MIN(a,b) (((a)<(b)) ? (a) : (b))
  62. #endif
  63. /*
  64.  * TODO BEFORE THE STABLE RELEASE:
  65.  *
  66.  * There are some issues concerning window redrawing under X11, and maybe
  67.  * some events are not handled. The Win32 version lacks some more features,
  68.  * but seems acceptable for not demanding purposes.
  69.  *
  70.  * Need to investigate why the X11 version breaks out with an error when
  71.  * closing a window (using the window manager, not glutDestroyWindow)...
  72.  */
  73. /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
  74. /*
  75.  * Handle a window configuration change. When no reshape
  76.  * callback is hooked, the viewport size is updated to
  77.  * match the new window size.
  78.  */
  79. static void fghReshapeWindow ( SFG_Window *window, int width, int height )
  80. {
  81.     SFG_Window *current_window = fgStructure.CurrentWindow;
  82.     freeglut_return_if_fail( window != NULL );
  83. #if TARGET_HOST_POSIX_X11
  84.     XResizeWindow( fgDisplay.Display, window->Window.Handle,
  85.                    width, height );
  86.     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
  87. #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
  88.     {
  89.         RECT winRect;
  90.         int x, y, w, h;
  91.         /*
  92.          * For windowed mode, get the current position of the
  93.          * window and resize taking the size of the frame
  94.          * decorations into account.
  95.          */
  96.         /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
  97.         GetWindowRect( window->Window.Handle, &winRect );
  98.         x = winRect.left;
  99.         y = winRect.top;
  100.         w = width;
  101.         h = height;
  102.         if ( window->Parent == NULL )
  103.         {
  104.             if ( ! window->IsMenu && (window != fgStructure.GameModeWindow) )
  105.             {
  106.                 w += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
  107.                 h += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 +
  108.                      GetSystemMetrics( SM_CYCAPTION );
  109.             }
  110.         }
  111.         else
  112.         {
  113.             RECT parentRect;
  114.             GetWindowRect( window->Parent->Window.Handle, &parentRect );
  115.             x -= parentRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
  116.             y -= parentRect.top  + GetSystemMetrics( SM_CYSIZEFRAME ) * 2 +
  117.                                    GetSystemMetrics( SM_CYCAPTION );
  118.         }
  119.         /*
  120.          * SWP_NOACTIVATE      Do not activate the window
  121.          * SWP_NOOWNERZORDER   Do not change position in z-order
  122.          * SWP_NOSENDCHANGING  Supress WM_WINDOWPOSCHANGING message
  123.          * SWP_NOZORDER        Retains the current Z order (ignore 2nd param)
  124.          */
  125.         SetWindowPos( window->Window.Handle,
  126.                       HWND_TOP,
  127.                       x, y, w, h,
  128.                       SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
  129.                       SWP_NOZORDER
  130.         );
  131.     }
  132. #endif
  133.     /*
  134.      * XXX Should update {window->State.OldWidth, window->State.OldHeight}
  135.      * XXX to keep in lockstep with POSIX_X11 code.
  136.      */
  137.     if( FETCH_WCB( *window, Reshape ) )
  138.         INVOKE_WCB( *window, Reshape, ( width, height ) );
  139.     else
  140.     {
  141.         fgSetWindow( window );
  142.         glViewport( 0, 0, width, height );
  143.     }
  144.     /*
  145.      * Force a window redraw.  In Windows at least this is only a partial
  146.      * solution:  if the window is increasing in size in either dimension,
  147.      * the already-drawn part does not get drawn again and things look funny.
  148.      * But without this we get this bad behaviour whenever we resize the
  149.      * window.
  150.      */
  151.     window->State.Redisplay = GL_TRUE;
  152.     if( window->IsMenu )
  153.         fgSetWindow( current_window );
  154. }
  155. /*
  156.  * Calls a window's redraw method. This is used when
  157.  * a redraw is forced by the incoming window messages.
  158.  */
  159. static void fghRedrawWindow ( SFG_Window *window )
  160. {
  161.     SFG_Window *current_window = fgStructure.CurrentWindow;
  162.     freeglut_return_if_fail( window );
  163.     freeglut_return_if_fail( FETCH_WCB ( *window, Display ) );
  164.     window->State.Redisplay = GL_FALSE;
  165.     freeglut_return_if_fail( window->State.Visible );
  166.     fgSetWindow( window );
  167.     if( window->State.NeedToResize )
  168.     {
  169.         fghReshapeWindow(
  170.             window,
  171.             window->State.Width,
  172.             window->State.Height
  173.         );
  174.         window->State.NeedToResize = GL_FALSE;
  175.     }
  176.     INVOKE_WCB( *window, Display, ( ) );
  177.     fgSetWindow( current_window );
  178. }
  179. /*
  180.  * A static helper function to execute display callback for a window
  181.  */
  182. static void fghcbDisplayWindow( SFG_Window *window,
  183.                                 SFG_Enumerator *enumerator )
  184. {
  185.     if( window->State.Redisplay &&
  186.         window->State.Visible )
  187.     {
  188.         window->State.Redisplay = GL_FALSE;
  189. #if TARGET_HOST_POSIX_X11
  190.         fghRedrawWindow ( window ) ;
  191. #elif TARGET_HOST_MS_WINDOWS
  192.         RedrawWindow(
  193.             window->Window.Handle, NULL, NULL,
  194.             RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
  195.         );
  196. #endif
  197.     }
  198.     fgEnumSubWindows( window, fghcbDisplayWindow, enumerator );
  199. }
  200. /*
  201.  * Make all windows perform a display call
  202.  */
  203. static void fghDisplayAll( void )
  204. {
  205.     SFG_Enumerator enumerator;
  206.     enumerator.found = GL_FALSE;
  207.     enumerator.data  =  NULL;
  208.     fgEnumWindows( fghcbDisplayWindow, &enumerator );
  209. }
  210. /*
  211.  * Window enumerator callback to check for the joystick polling code
  212.  */
  213. static void fghcbCheckJoystickPolls( SFG_Window *window,
  214.                                      SFG_Enumerator *enumerator )
  215. {
  216.     long int checkTime = fgElapsedTime( );
  217.     if( window->State.JoystickLastPoll + window->State.JoystickPollRate <=
  218.         checkTime )
  219.     {
  220. #if !defined(_WIN32_WCE)
  221.         fgJoystickPollWindow( window );
  222. #endif /* !defined(_WIN32_WCE) */
  223.         window->State.JoystickLastPoll = checkTime;
  224.     }
  225.     fgEnumSubWindows( window, fghcbCheckJoystickPolls, enumerator );
  226. }
  227. /*
  228.  * Check all windows for joystick polling
  229.  */
  230. static void fghCheckJoystickPolls( void )
  231. {
  232.     SFG_Enumerator enumerator;
  233.     enumerator.found = GL_FALSE;
  234.     enumerator.data  =  NULL;
  235.     fgEnumWindows( fghcbCheckJoystickPolls, &enumerator );
  236. }
  237. /*
  238.  * Check the global timers
  239.  */
  240. static void fghCheckTimers( void )
  241. {
  242.     long checkTime = fgElapsedTime( );
  243.     while( fgState.Timers.First )
  244.     {
  245.         SFG_Timer *timer = fgState.Timers.First;
  246.         if( timer->TriggerTime > checkTime )
  247.             break;
  248.         fgListRemove( &fgState.Timers, &timer->Node );
  249.         fgListAppend( &fgState.FreeTimers, &timer->Node );
  250.         timer->Callback( timer->ID );
  251.     }
  252. }
  253.  
  254. /* Platform-dependent time in milliseconds, as an unsigned 32-bit integer.
  255.  * This value wraps every 49.7 days, but integer overflows cancel
  256.  * when subtracting an initial start time, unless the total time exceeds
  257.  * 32-bit, where the GLUT API return value is also overflowed.
  258.  */  
  259. unsigned long fgSystemTime(void) {
  260. #if TARGET_HOST_SOLARIS || HAVE_GETTIMEOFDAY
  261.     struct timeval now;
  262.     gettimeofday( &now, NULL );
  263.     return now.tv_usec/1000 + now.tv_sec*1000;
  264. #elif TARGET_HOST_MS_WINDOWS
  265. #    if defined(_WIN32_WCE)
  266.     return GetTickCount();
  267. #    else
  268.     return timeGetTime();
  269. #    endif
  270. #endif
  271. }
  272.   
  273. /*
  274.  * Elapsed Time
  275.  */
  276. long fgElapsedTime( void )
  277. {
  278.     return (long) (fgSystemTime() - fgState.Time);
  279. }
  280. /*
  281.  * Error Messages.
  282.  */
  283. void fgError( const char *fmt, ... )
  284. {
  285.     va_list ap;
  286.     va_start( ap, fmt );
  287.     fprintf( stderr, "freeglut ");
  288.     if( fgState.ProgramName )
  289.         fprintf( stderr, "(%s): ", fgState.ProgramName );
  290.     VFPRINTF( stderr, fmt, ap );
  291.     fprintf( stderr, "n" );
  292.     va_end( ap );
  293.     if ( fgState.Initialised )
  294.         fgDeinitialize ();
  295.     exit( 1 );
  296. }
  297. void fgWarning( const char *fmt, ... )
  298. {
  299.     va_list ap;
  300.     va_start( ap, fmt );
  301.     fprintf( stderr, "freeglut ");
  302.     if( fgState.ProgramName )
  303.         fprintf( stderr, "(%s): ", fgState.ProgramName );
  304.     VFPRINTF( stderr, fmt, ap );
  305.     fprintf( stderr, "n" );
  306.     va_end( ap );
  307. }
  308. /*
  309.  * Indicates whether Joystick events are being used by ANY window.
  310.  *
  311.  * The current mechanism is to walk all of the windows and ask if
  312.  * there is a joystick callback.  We have a short-circuit early
  313.  * return if we find any joystick handler registered.
  314.  *
  315.  * The real way to do this is to make use of the glutTimer() API
  316.  * to more cleanly re-implement the joystick API.  Then, this code
  317.  * and all other "joystick timer" code can be yanked.
  318.  *
  319.  */
  320. static void fghCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e)
  321. {
  322.     if( FETCH_WCB( *w, Joystick ) )
  323.     {
  324.         e->found = GL_TRUE;
  325.         e->data = w;
  326.     }
  327.     fgEnumSubWindows( w, fghCheckJoystickCallback, e );
  328. }
  329. static int fghHaveJoystick( void )
  330. {
  331.     SFG_Enumerator enumerator;
  332.     enumerator.found = GL_FALSE;
  333.     enumerator.data = NULL;
  334.     fgEnumWindows( fghCheckJoystickCallback, &enumerator );
  335.     return !!enumerator.data;
  336. }
  337. static void fghHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e)
  338. {
  339.     if( w->State.Redisplay && w->State.Visible )
  340.     {
  341.         e->found = GL_TRUE;
  342.         e->data = w;
  343.     }
  344.     fgEnumSubWindows( w, fghHavePendingRedisplaysCallback, e );
  345. }
  346. static int fghHavePendingRedisplays (void)
  347. {
  348.     SFG_Enumerator enumerator;
  349.     enumerator.found = GL_FALSE;
  350.     enumerator.data = NULL;
  351.     fgEnumWindows( fghHavePendingRedisplaysCallback, &enumerator );
  352.     return !!enumerator.data;
  353. }
  354. /*
  355.  * Returns the number of GLUT ticks (milliseconds) till the next timer event.
  356.  */
  357. static long fghNextTimer( void )
  358. {
  359.     long ret = INT_MAX;
  360.     SFG_Timer *timer = fgState.Timers.First;
  361.     if( timer )
  362.         ret = timer->TriggerTime - fgElapsedTime();
  363.     if( ret < 0 )
  364.         ret = 0;
  365.     return ret;
  366. }
  367. /*
  368.  * Does the magic required to relinquish the CPU until something interesting
  369.  * happens.
  370.  */
  371. static void fghSleepForEvents( void )
  372. {
  373.     long msec;
  374.     if( fgState.IdleCallback || fghHavePendingRedisplays( ) )
  375.         return;
  376.     msec = fghNextTimer( );
  377.     /* XXX Use GLUT timers for joysticks... */
  378.     /* XXX Dumb; forces granularity to .01sec */
  379.     if( fghHaveJoystick( ) && ( msec > 10 ) )     
  380.         msec = 10;
  381. #if TARGET_HOST_POSIX_X11
  382.     /*
  383.      * Possibly due to aggressive use of XFlush() and friends,
  384.      * it is possible to have our socket drained but still have
  385.      * unprocessed events.  (Or, this may just be normal with
  386.      * X, anyway?)  We do non-trivial processing of X events
  387.      * after the event-reading loop, in any case, so we
  388.      * need to allow that we may have an empty socket but non-
  389.      * empty event queue.
  390.      */
  391.     if( ! XPending( fgDisplay.Display ) )
  392.     {
  393.         fd_set fdset;
  394.         int err;
  395.         int socket;
  396.         struct timeval wait;
  397.         socket = ConnectionNumber( fgDisplay.Display );
  398.         FD_ZERO( &fdset );
  399.         FD_SET( socket, &fdset );
  400.         wait.tv_sec = msec / 1000;
  401.         wait.tv_usec = (msec % 1000) * 1000;
  402.         err = select( socket+1, &fdset, NULL, NULL, &wait );
  403. #if HAVE_ERRNO
  404.         if( ( -1 == err ) && ( errno != EINTR ) )
  405.             fgWarning ( "freeglut select() error: %d", errno );
  406. #endif
  407.     }
  408. #elif TARGET_HOST_MS_WINDOWS
  409.     MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLINPUT );
  410. #endif
  411. }
  412. #if TARGET_HOST_POSIX_X11
  413. /*
  414.  * Returns GLUT modifier mask for the state field of an X11 event.
  415.  */
  416. static int fghGetXModifiers( int state )
  417. {
  418.     int ret = 0;
  419.     if( state & ( ShiftMask | LockMask ) )
  420.         ret |= GLUT_ACTIVE_SHIFT;
  421.     if( state & ControlMask )
  422.         ret |= GLUT_ACTIVE_CTRL;
  423.     if( state & Mod1Mask )
  424.         ret |= GLUT_ACTIVE_ALT;
  425.     return ret;
  426. }
  427. #endif
  428. #if TARGET_HOST_POSIX_X11 && _DEBUG
  429. static const char* fghTypeToString( int type )
  430. {
  431.     switch( type ) {
  432.     case KeyPress: return "KeyPress";
  433.     case KeyRelease: return "KeyRelease";
  434.     case ButtonPress: return "ButtonPress";
  435.     case ButtonRelease: return "ButtonRelease";
  436.     case MotionNotify: return "MotionNotify";
  437.     case EnterNotify: return "EnterNotify";
  438.     case LeaveNotify: return "LeaveNotify";
  439.     case FocusIn: return "FocusIn";
  440.     case FocusOut: return "FocusOut";
  441.     case KeymapNotify: return "KeymapNotify";
  442.     case Expose: return "Expose";
  443.     case GraphicsExpose: return "GraphicsExpose";
  444.     case NoExpose: return "NoExpose";
  445.     case VisibilityNotify: return "VisibilityNotify";
  446.     case CreateNotify: return "CreateNotify";
  447.     case DestroyNotify: return "DestroyNotify";
  448.     case UnmapNotify: return "UnmapNotify";
  449.     case MapNotify: return "MapNotify";
  450.     case MapRequest: return "MapRequest";
  451.     case ReparentNotify: return "ReparentNotify";
  452.     case ConfigureNotify: return "ConfigureNotify";
  453.     case ConfigureRequest: return "ConfigureRequest";
  454.     case GravityNotify: return "GravityNotify";
  455.     case ResizeRequest: return "ResizeRequest";
  456.     case CirculateNotify: return "CirculateNotify";
  457.     case CirculateRequest: return "CirculateRequest";
  458.     case PropertyNotify: return "PropertyNotify";
  459.     case SelectionClear: return "SelectionClear";
  460.     case SelectionRequest: return "SelectionRequest";
  461.     case SelectionNotify: return "SelectionNotify";
  462.     case ColormapNotify: return "ColormapNotify";
  463.     case ClientMessage: return "ClientMessage";
  464.     case MappingNotify: return "MappingNotify";
  465.     default: return "UNKNOWN";
  466.     }
  467. }
  468. static const char* fghBoolToString( Bool b )
  469. {
  470.     return b == False ? "False" : "True";
  471. }
  472. static const char* fghNotifyHintToString( char is_hint )
  473. {
  474.     switch( is_hint ) {
  475.     case NotifyNormal: return "NotifyNormal";
  476.     case NotifyHint: return "NotifyHint";
  477.     default: return "UNKNOWN";
  478.     }
  479. }
  480. static const char* fghNotifyModeToString( int mode )
  481. {
  482.     switch( mode ) {
  483.     case NotifyNormal: return "NotifyNormal";
  484.     case NotifyGrab: return "NotifyGrab";
  485.     case NotifyUngrab: return "NotifyUngrab";
  486.     case NotifyWhileGrabbed: return "NotifyWhileGrabbed";
  487.     default: return "UNKNOWN";
  488.     }
  489. }
  490. static const char* fghNotifyDetailToString( int detail )
  491. {
  492.     switch( detail ) {
  493.     case NotifyAncestor: return "NotifyAncestor";
  494.     case NotifyVirtual: return "NotifyVirtual";
  495.     case NotifyInferior: return "NotifyInferior";
  496.     case NotifyNonlinear: return "NotifyNonlinear";
  497.     case NotifyNonlinearVirtual: return "NotifyNonlinearVirtual";
  498.     case NotifyPointer: return "NotifyPointer";
  499.     case NotifyPointerRoot: return "NotifyPointerRoot";
  500.     case NotifyDetailNone: return "NotifyDetailNone";
  501.     default: return "UNKNOWN";
  502.     }
  503. }
  504. static const char* fghVisibilityToString( int state ) {
  505.     switch( state ) {
  506.     case VisibilityUnobscured: return "VisibilityUnobscured";
  507.     case VisibilityPartiallyObscured: return "VisibilityPartiallyObscured";
  508.     case VisibilityFullyObscured: return "VisibilityFullyObscured";
  509.     default: return "UNKNOWN";
  510.     }
  511. }
  512. static const char* fghConfigureDetailToString( int detail )
  513. {
  514.     switch( detail ) {
  515.     case Above: return "Above";
  516.     case Below: return "Below";
  517.     case TopIf: return "TopIf";
  518.     case BottomIf: return "BottomIf";
  519.     case Opposite: return "Opposite";
  520.     default: return "UNKNOWN";
  521.     }
  522. }
  523. static const char* fghPlaceToString( int place )
  524. {
  525.     switch( place ) {
  526.     case PlaceOnTop: return "PlaceOnTop";
  527.     case PlaceOnBottom: return "PlaceOnBottom";
  528.     default: return "UNKNOWN";
  529.     }
  530. }
  531. static const char* fghMappingRequestToString( int request )
  532. {
  533.     switch( request ) {
  534.     case MappingModifier: return "MappingModifier";
  535.     case MappingKeyboard: return "MappingKeyboard";
  536.     case MappingPointer: return "MappingPointer";
  537.     default: return "UNKNOWN";
  538.     }
  539. }
  540. static const char* fghPropertyStateToString( int state )
  541. {
  542.     switch( state ) {
  543.     case PropertyNewValue: return "PropertyNewValue";
  544.     case PropertyDelete: return "PropertyDelete";
  545.     default: return "UNKNOWN";
  546.     }
  547. }
  548. static const char* fghColormapStateToString( int state )
  549. {
  550.     switch( state ) {
  551.     case ColormapUninstalled: return "ColormapUninstalled";
  552.     case ColormapInstalled: return "ColormapInstalled";
  553.     default: return "UNKNOWN";
  554.     }
  555. }
  556. static void fghPrintEvent( XEvent *event )
  557. {
  558.     switch( event->type ) {
  559.     case KeyPress:
  560.     case KeyRelease: {
  561.         XKeyEvent *e = &event->xkey;
  562.         fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, "
  563.                    "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, "
  564.                    "keycode=%u, same_screen=%s", fghTypeToString( e->type ),
  565.                    e->window, e->root, e->subwindow, (unsigned long)e->time,
  566.                    e->x, e->y, e->x_root, e->y_root, e->state, e->keycode,
  567.                    fghBoolToString( e->same_screen ) );
  568.         break;
  569.     }
  570.     case ButtonPress:
  571.     case ButtonRelease: {
  572.         XButtonEvent *e = &event->xbutton;
  573.         fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, "
  574.                    "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, "
  575.                    "button=%u, same_screen=%d", fghTypeToString( e->type ),
  576.                    e->window, e->root, e->subwindow, (unsigned long)e->time,
  577.                    e->x, e->y, e->x_root, e->y_root, e->state, e->button,
  578.                    fghBoolToString( e->same_screen ) );
  579.         break;
  580.     }
  581.     case MotionNotify: {
  582.         XMotionEvent *e = &event->xmotion;
  583.         fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, "
  584.                    "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, "
  585.                    "is_hint=%s, same_screen=%d", fghTypeToString( e->type ),
  586.                    e->window, e->root, e->subwindow, (unsigned long)e->time,
  587.                    e->x, e->y, e->x_root, e->y_root, e->state,
  588.                    fghNotifyHintToString( e->is_hint ),
  589.                    fghBoolToString( e->same_screen ) );
  590.         break;
  591.     }
  592.     case EnterNotify:
  593.     case LeaveNotify: {
  594.         XCrossingEvent *e = &event->xcrossing;
  595.         fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, "
  596.                    "(x,y)=(%d,%d), mode=%s, detail=%s, same_screen=%d, "
  597.                    "focus=%d, state=0x%x", fghTypeToString( e->type ),
  598.                    e->window, e->root, e->subwindow, (unsigned long)e->time,
  599.                    e->x, e->y, fghNotifyModeToString( e->mode ),
  600.                    fghNotifyDetailToString( e->detail ), (int)e->same_screen,
  601.                    (int)e->focus, e->state );
  602.         break;
  603.     }
  604.     case FocusIn:
  605.     case FocusOut: {
  606.         XFocusChangeEvent *e = &event->xfocus;
  607.         fgWarning( "%s: window=0x%x, mode=%s, detail=%s",
  608.                    fghTypeToString( e->type ), e->window,
  609.                    fghNotifyModeToString( e->mode ),
  610.                    fghNotifyDetailToString( e->detail ) );
  611.         break;
  612.     }
  613.     case KeymapNotify: {
  614.         XKeymapEvent *e = &event->xkeymap;
  615.         char buf[32 * 2 + 1];
  616.         int i;
  617.         for ( i = 0; i < 32; i++ ) {
  618.             snprintf( &buf[ i * 2 ], sizeof( buf ) - i * 2,
  619.                       "%02x", e->key_vector[ i ] );
  620.         }
  621.         buf[ i ] = '';
  622.         fgWarning( "%s: window=0x%x, %s", fghTypeToString( e->type ), e->window,
  623.                    buf );
  624.         break;
  625.     }
  626.     case Expose: {
  627.         XExposeEvent *e = &event->xexpose;
  628.         fgWarning( "%s: window=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), "
  629.                    "count=%d", fghTypeToString( e->type ), e->window, e->x,
  630.                    e->y, e->width, e->height, e->count );
  631.         break;
  632.     }
  633.     case GraphicsExpose: {
  634.         XGraphicsExposeEvent *e = &event->xgraphicsexpose;
  635.         fgWarning( "%s: drawable=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), "
  636.                    "count=%d, (major_code,minor_code)=(%d,%d)",
  637.                    fghTypeToString( e->type ), e->drawable, e->x, e->y,
  638.                    e->width, e->height, e->count, e->major_code,
  639.                    e->minor_code );
  640.         break;
  641.     }
  642.     case NoExpose: {
  643.         XNoExposeEvent *e = &event->xnoexpose;
  644.         fgWarning( "%s: drawable=0x%x, (major_code,minor_code)=(%d,%d)",
  645.                    fghTypeToString( e->type ), e->drawable, e->major_code,
  646.                    e->minor_code );
  647.         break;
  648.     }
  649.     case VisibilityNotify: {
  650.         XVisibilityEvent *e = &event->xvisibility;
  651.         fgWarning( "%s: window=0x%x, state=%s", fghTypeToString( e->type ),
  652.                    e->window, fghVisibilityToString( e->state) );
  653.         break;
  654.     }
  655.     case CreateNotify: {
  656.         XCreateWindowEvent *e = &event->xcreatewindow;
  657.         fgWarning( "%s: (x,y)=(%d,%d), (width,height)=(%d,%d), border_width=%d, "
  658.                    "window=0x%x, override_redirect=%s",
  659.                    fghTypeToString( e->type ), e->x, e->y, e->width, e->height,
  660.                    e->border_width, e->window,
  661.                    fghBoolToString( e->override_redirect ) );
  662.         break;
  663.     }
  664.     case DestroyNotify: {
  665.         XDestroyWindowEvent *e = &event->xdestroywindow;
  666.         fgWarning( "%s: event=0x%x, window=0x%x",
  667.                    fghTypeToString( e->type ), e->event, e->window );
  668.         break;
  669.     }
  670.     case UnmapNotify: {
  671.         XUnmapEvent *e = &event->xunmap;
  672.         fgWarning( "%s: event=0x%x, window=0x%x, from_configure=%s",
  673.                    fghTypeToString( e->type ), e->event, e->window,
  674.                    fghBoolToString( e->from_configure ) );
  675.         break;
  676.     }
  677.     case MapNotify: {
  678.         XMapEvent *e = &event->xmap;
  679.         fgWarning( "%s: event=0x%x, window=0x%x, override_redirect=%s",
  680.                    fghTypeToString( e->type ), e->event, e->window,
  681.                    fghBoolToString( e->override_redirect ) );
  682.         break;
  683.     }
  684.     case MapRequest: {
  685.         XMapRequestEvent *e = &event->xmaprequest;
  686.         fgWarning( "%s: parent=0x%x, window=0x%x",
  687.                    fghTypeToString( event->type ), e->parent, e->window );
  688.         break;
  689.     }
  690.     case ReparentNotify: {
  691.         XReparentEvent *e = &event->xreparent;
  692.         fgWarning( "%s: event=0x%x, window=0x%x, parent=0x%x, (x,y)=(%d,%d), "
  693.                    "override_redirect=%s", fghTypeToString( e->type ),
  694.                    e->event, e->window, e->parent, e->x, e->y,
  695.                    fghBoolToString( e->override_redirect ) );
  696.         break;
  697.     }
  698.     case ConfigureNotify: {
  699.         XConfigureEvent *e = &event->xconfigure;
  700.         fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d), "
  701.                    "(width,height)=(%d,%d), border_width=%d, above=0x%x, "
  702.                    "override_redirect=%s", fghTypeToString( e->type ), e->event,
  703.                    e->window, e->x, e->y, e->width, e->height, e->border_width,
  704.                    e->above, fghBoolToString( e->override_redirect ) );
  705.         break;
  706.     }
  707.     case ConfigureRequest: {
  708.         XConfigureRequestEvent *e = &event->xconfigurerequest;
  709.         fgWarning( "%s: parent=0x%x, window=0x%x, (x,y)=(%d,%d), "
  710.                    "(width,height)=(%d,%d), border_width=%d, above=0x%x, "
  711.                    "detail=%s, value_mask=%lx", fghTypeToString( e->type ),
  712.                    e->parent, e->window, e->x, e->y, e->width, e->height,
  713.                    e->border_width, e->above,
  714.                    fghConfigureDetailToString( e->detail ), e->value_mask );
  715.         break;
  716.     }
  717.     case GravityNotify: {
  718.         XGravityEvent *e = &event->xgravity;
  719.         fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d)",
  720.                    fghTypeToString( e->type ), e->event, e->window, e->x, e->y );
  721.         break;
  722.     }
  723.     case ResizeRequest: {
  724.         XResizeRequestEvent *e = &event->xresizerequest;
  725.         fgWarning( "%s: window=0x%x, (width,height)=(%d,%d)",
  726.                    fghTypeToString( e->type ), e->window, e->width, e->height );
  727.         break;
  728.     }
  729.     case CirculateNotify: {
  730.         XCirculateEvent *e = &event->xcirculate;
  731.         fgWarning( "%s: event=0x%x, window=0x%x, place=%s",
  732.                    fghTypeToString( e->type ), e->event, e->window,
  733.                    fghPlaceToString( e->place ) );
  734.         break;
  735.     }
  736.     case CirculateRequest: {
  737.         XCirculateRequestEvent *e = &event->xcirculaterequest;
  738.         fgWarning( "%s: parent=0x%x, window=0x%x, place=%s",
  739.                    fghTypeToString( e->type ), e->parent, e->window,
  740.                    fghPlaceToString( e->place ) );
  741.         break;
  742.     }
  743.     case PropertyNotify: {
  744.         XPropertyEvent *e = &event->xproperty;
  745.         fgWarning( "%s: window=0x%x, atom=%lu, time=%lu, state=%s",
  746.                    fghTypeToString( e->type ), e->window,
  747.                    (unsigned long)e->atom, (unsigned long)e->time,
  748.                    fghPropertyStateToString( e->state ) );
  749.         break;
  750.     }
  751.     case SelectionClear: {
  752.         XSelectionClearEvent *e = &event->xselectionclear;
  753.         fgWarning( "%s: window=0x%x, selection=%lu, time=%lu",
  754.                    fghTypeToString( e->type ), e->window,
  755.                    (unsigned long)e->selection, (unsigned long)e->time );
  756.         break;
  757.     }
  758.     case SelectionRequest: {
  759.         XSelectionRequestEvent *e = &event->xselectionrequest;
  760.         fgWarning( "%s: owner=0x%x, requestor=0x%x, selection=0x%x, "
  761.                    "target=0x%x, property=%lu, time=%lu",
  762.                    fghTypeToString( e->type ), e->owner, e->requestor,
  763.                    (unsigned long)e->selection, (unsigned long)e->target,
  764.                    (unsigned long)e->property, (unsigned long)e->time );
  765.         break;
  766.     }
  767.     case SelectionNotify: {
  768.         XSelectionEvent *e = &event->xselection;
  769.         fgWarning( "%s: requestor=0x%x, selection=0x%x, target=0x%x, "
  770.                    "property=%lu, time=%lu", fghTypeToString( e->type ),
  771.                    e->requestor, (unsigned long)e->selection,
  772.                    (unsigned long)e->target, (unsigned long)e->property,
  773.                    (unsigned long)e->time );
  774.         break;
  775.     }
  776.     case ColormapNotify: {
  777.         XColormapEvent *e = &event->xcolormap;
  778.         fgWarning( "%s: window=0x%x, colormap=%lu, new=%s, state=%s",
  779.                    fghTypeToString( e->type ), e->window,
  780.                    (unsigned long)e->colormap, fghBoolToString( e->new ),
  781.                    fghColormapStateToString( e->state ) );
  782.         break;
  783.     }
  784.     case ClientMessage: {
  785.         XClientMessageEvent *e = &event->xclient;
  786.         char buf[ 61 ];
  787.         char* p = buf;
  788.         char* end = buf + sizeof( buf );
  789.         int i;
  790.         switch( e->format ) {
  791.         case 8:
  792.           for ( i = 0; i < 20; i++, p += 3 ) {
  793.                 snprintf( p, end - p, " %02x", e->data.b[ i ] );
  794.             }
  795.             break;
  796.         case 16:
  797.             for ( i = 0; i < 10; i++, p += 5 ) {
  798.                 snprintf( p, end - p, " %04x", e->data.s[ i ] );
  799.             }
  800.             break;
  801.         case 32:
  802.             for ( i = 0; i < 5; i++, p += 9 ) {
  803.                 snprintf( p, end - p, " %08lx", e->data.l[ i ] );
  804.             }
  805.             break;
  806.         }
  807.         *p = '';
  808.         fgWarning( "%s: window=0x%x, message_type=%lu, format=%d, data=(%s )",
  809.                    fghTypeToString( e->type ), e->window,
  810.                    (unsigned long)e->message_type, e->format, buf );
  811.         break;
  812.     }
  813.     case MappingNotify: {
  814.         XMappingEvent *e = &event->xmapping;
  815.         fgWarning( "%s: window=0x%x, request=%s, first_keycode=%d, count=%d",
  816.                    fghTypeToString( e->type ), e->window,
  817.                    fghMappingRequestToString( e->request ), e->first_keycode,
  818.                    e->count );
  819.         break;
  820.     }
  821.     default: {
  822.         fgWarning( "%s", fghTypeToString( event->type ) );
  823.         break;
  824.     }
  825.     }
  826. }
  827. #endif
  828. /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
  829. /*
  830.  * Executes a single iteration in the freeglut processing loop.
  831.  */
  832. void FGAPIENTRY glutMainLoopEvent( void )
  833. {
  834. #if TARGET_HOST_POSIX_X11
  835.     SFG_Window* window;
  836.     XEvent event;
  837.     /* This code was repeated constantly, so here it goes into a definition: */
  838. #define GETWINDOW(a)                             
  839.     window = fgWindowByHandle( event.a.window ); 
  840.     if( window == NULL )                         
  841.         break;
  842. #define GETMOUSE(a)                              
  843.     window->State.MouseX = event.a.x;            
  844.     window->State.MouseY = event.a.y;
  845.     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
  846.     while( XPending( fgDisplay.Display ) )
  847.     {
  848.         XNextEvent( fgDisplay.Display, &event );
  849. #if _DEBUG
  850.         fghPrintEvent( &event );
  851. #endif
  852.         switch( event.type )
  853.         {
  854.         case ClientMessage:
  855.             if(fgIsSpaceballXEvent(&event)) {
  856.                 fgSpaceballHandleXEvent(&event);
  857.                 break;
  858.             }
  859.             /* Destroy the window when the WM_DELETE_WINDOW message arrives */
  860.             if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow )
  861.             {
  862.                 GETWINDOW( xclient );
  863.                 fgDestroyWindow ( window );
  864.                 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
  865.                 {
  866.                     fgDeinitialize( );
  867.                     exit( 0 );
  868.                 }
  869.                 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
  870.                     fgState.ExecState = GLUT_EXEC_STATE_STOP;
  871.                 return;
  872.             }
  873.             break;
  874.             /*
  875.              * CreateNotify causes a configure-event so that sub-windows are
  876.              * handled compatibly with GLUT.  Otherwise, your sub-windows
  877.              * (in freeglut only) will not get an initial reshape event,
  878.              * which can break things.
  879.              *
  880.              * GLUT presumably does this because it generally tries to treat
  881.              * sub-windows the same as windows.
  882.              */
  883.         case CreateNotify:
  884.         case ConfigureNotify:
  885.             {
  886.                 int width, height;
  887.                 if( event.type == CreateNotify ) {
  888.                     GETWINDOW( xcreatewindow );
  889.                     width = event.xcreatewindow.width;
  890.                     height = event.xcreatewindow.height;
  891.                 } else {
  892.                     GETWINDOW( xconfigure );
  893.                     width = event.xconfigure.width;
  894.                     height = event.xconfigure.height;
  895.                 }
  896.                 if( ( width != window->State.OldWidth ) ||
  897.                     ( height != window->State.OldHeight ) )
  898.                 {
  899.                     SFG_Window *current_window = fgStructure.CurrentWindow;
  900.                     window->State.OldWidth = width;
  901.                     window->State.OldHeight = height;
  902.                     if( FETCH_WCB( *window, Reshape ) )
  903.                         INVOKE_WCB( *window, Reshape, ( width, height ) );
  904.                     else
  905.                     {
  906.                         fgSetWindow( window );
  907.                         glViewport( 0, 0, width, height );
  908.                     }
  909.                     glutPostRedisplay( );
  910.                     if( window->IsMenu )
  911.                         fgSetWindow( current_window );
  912.                 }
  913.             }
  914.             break;
  915.         case DestroyNotify:
  916.             /*
  917.              * This is sent to confirm the XDestroyWindow call.
  918.              *
  919.              * XXX WHY is this commented out?  Should we re-enable it?
  920.              */
  921.             /* fgAddToWindowDestroyList ( window ); */
  922.             break;
  923.         case Expose:
  924.             /*
  925.              * We are too dumb to process partial exposes...
  926.              *
  927.              * XXX Well, we could do it.  However, it seems to only
  928.              * XXX be potentially useful for single-buffered (since
  929.              * XXX double-buffered does not respect viewport when we
  930.              * XXX do a buffer-swap).
  931.              *
  932.              */
  933.             if( event.xexpose.count == 0 )
  934.             {
  935.                 GETWINDOW( xexpose );
  936.                 window->State.Redisplay = GL_TRUE;
  937.             }
  938.             break;
  939.         case MapNotify:
  940.             break;
  941.         case UnmapNotify:
  942.             /* We get this when iconifying a window. */ 
  943.             GETWINDOW( xunmap );
  944.             INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) );
  945.             window->State.Visible = GL_FALSE;
  946.             break;
  947.         case MappingNotify:
  948.             /*
  949.              * Have the client's keyboard knowledge updated (xlib.ps,
  950.              * page 206, says that's a good thing to do)
  951.              */
  952.             XRefreshKeyboardMapping( (XMappingEvent *) &event );
  953.             break;
  954.         case VisibilityNotify:
  955.         {
  956.             /*
  957.              * Sending this event, the X server can notify us that the window
  958.              * has just acquired one of the three possible visibility states:
  959.              * VisibilityUnobscured, VisibilityPartiallyObscured or
  960.              * VisibilityFullyObscured. Note that we DO NOT receive a
  961.              * VisibilityNotify event when iconifying a window, we only get an
  962.              * UnmapNotify then.
  963.              */
  964.             GETWINDOW( xvisibility );
  965.             switch( event.xvisibility.state )
  966.             {
  967.             case VisibilityUnobscured:
  968.                 INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) );
  969.                 window->State.Visible = GL_TRUE;
  970.                 break;
  971.             case VisibilityPartiallyObscured:
  972.                 INVOKE_WCB( *window, WindowStatus,
  973.                             ( GLUT_PARTIALLY_RETAINED ) );
  974.                 window->State.Visible = GL_TRUE;
  975.                 break;
  976.             case VisibilityFullyObscured:
  977.                 INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) );
  978.                 window->State.Visible = GL_FALSE;
  979.                 break;
  980.             default:
  981.                 fgWarning( "Unknown X visibility state: %d",
  982.                            event.xvisibility.state );
  983.                 break;
  984.             }
  985.         }
  986.         break;
  987.         case EnterNotify:
  988.         case LeaveNotify:
  989.             GETWINDOW( xcrossing );
  990.             GETMOUSE( xcrossing );
  991.             if( ( event.type == LeaveNotify ) && window->IsMenu &&
  992.                 window->ActiveMenu && window->ActiveMenu->IsActive )
  993.                 fgUpdateMenuHighlight( window->ActiveMenu );
  994.             INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ?
  995.                                           GLUT_ENTERED :
  996.                                           GLUT_LEFT ) );
  997.             break;
  998.         case MotionNotify:
  999.         {
  1000.             GETWINDOW( xmotion );
  1001.             GETMOUSE( xmotion );
  1002.             if( window->ActiveMenu )
  1003.             {
  1004.                 if( window == window->ActiveMenu->ParentWindow )
  1005.                 {
  1006.                     window->ActiveMenu->Window->State.MouseX =
  1007.                         event.xmotion.x_root - window->ActiveMenu->X;
  1008.                     window->ActiveMenu->Window->State.MouseY =
  1009.                         event.xmotion.y_root - window->ActiveMenu->Y;
  1010.                 }
  1011.                 fgUpdateMenuHighlight( window->ActiveMenu );
  1012.                 break;
  1013.             }
  1014.             /*
  1015.              * XXX For more than 5 buttons, just check {event.xmotion.state},
  1016.              * XXX rather than a host of bit-masks?  Or maybe we need to
  1017.              * XXX track ButtonPress/ButtonRelease events in our own
  1018.              * XXX bit-mask?
  1019.              */
  1020.             fgState.Modifiers = fghGetXModifiers( event.xmotion.state );
  1021.             if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) {
  1022.                 INVOKE_WCB( *window, Motion, ( event.xmotion.x,
  1023.                                                event.xmotion.y ) );
  1024.             } else {
  1025.                 INVOKE_WCB( *window, Passive, ( event.xmotion.x,
  1026.                                                 event.xmotion.y ) );
  1027.             }
  1028.             fgState.Modifiers = INVALID_MODIFIERS;
  1029.         }
  1030.         break;
  1031.         case ButtonRelease:
  1032.         case ButtonPress:
  1033.         {
  1034.             GLboolean pressed = GL_TRUE;
  1035.             int button;
  1036.             if( event.type == ButtonRelease )
  1037.                 pressed = GL_FALSE ;
  1038.             /*
  1039.              * A mouse button has been pressed or released. Traditionally,
  1040.              * break if the window was found within the freeglut structures.
  1041.              */
  1042.             GETWINDOW( xbutton );
  1043.             GETMOUSE( xbutton );
  1044.             /*
  1045.              * An X button (at least in XFree86) is numbered from 1.
  1046.              * A GLUT button is numbered from 0.
  1047.              * Old GLUT passed through buttons other than just the first
  1048.              * three, though it only gave symbolic names and official
  1049.              * support to the first three.
  1050.              */
  1051.             button = event.xbutton.button - 1;
  1052.             /*
  1053.              * Do not execute the application's mouse callback if a menu
  1054.              * is hooked to this button.  In that case an appropriate
  1055.              * private call should be generated.
  1056.              */
  1057.             if( fgCheckActiveMenu( window, button, pressed,
  1058.                                    event.xbutton.x_root, event.xbutton.y_root ) )
  1059.                 break;
  1060.             /*
  1061.              * Check if there is a mouse or mouse wheel callback hooked to the
  1062.              * window
  1063.              */
  1064.             if( ! FETCH_WCB( *window, Mouse ) &&
  1065.                 ! FETCH_WCB( *window, MouseWheel ) )
  1066.                 break;
  1067.             fgState.Modifiers = fghGetXModifiers( event.xbutton.state );
  1068.             /* Finally execute the mouse or mouse wheel callback */
  1069.             if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) )
  1070.                 INVOKE_WCB( *window, Mouse, ( button,
  1071.                                               pressed ? GLUT_DOWN : GLUT_UP,
  1072.                                               event.xbutton.x,
  1073.                                               event.xbutton.y )
  1074.                 );
  1075.             else
  1076.             {
  1077.                 /*
  1078.                  * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1
  1079.                  *  "  6 and 7 "    "   one; ...
  1080.                  *
  1081.                  * XXX This *should* be behind some variables/macros,
  1082.                  * XXX since the order and numbering isn't certain
  1083.                  * XXX See XFree86 configuration docs (even back in the
  1084.                  * XXX 3.x days, and especially with 4.x).
  1085.                  *
  1086.                  * XXX Note that {button} has already been decremeted
  1087.                  * XXX in mapping from X button numbering to GLUT.
  1088.                  */
  1089.                 int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2;
  1090.                 int direction = -1;
  1091.                 if( button % 2 )
  1092.                     direction = 1;
  1093.                 if( pressed )
  1094.                     INVOKE_WCB( *window, MouseWheel, ( wheel_number,
  1095.                                                        direction,
  1096.                                                        event.xbutton.x,
  1097.                                                        event.xbutton.y )
  1098.                     );
  1099.             }
  1100.             fgState.Modifiers = INVALID_MODIFIERS;
  1101.         }
  1102.         break;
  1103.         case KeyRelease:
  1104.         case KeyPress:
  1105.         {
  1106.             FGCBKeyboard keyboard_cb;
  1107.             FGCBSpecial special_cb;
  1108.             GETWINDOW( xkey );
  1109.             GETMOUSE( xkey );
  1110.             /* Detect auto repeated keys, if configured globally or per-window */
  1111.             if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE )
  1112.             {
  1113.                 if (event.type==KeyRelease)
  1114.                 {
  1115.                     /*
  1116.                      * Look at X11 keystate to detect repeat mode.
  1117.                      * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs.
  1118.                      */
  1119.                     char keys[32];
  1120.                     XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */
  1121.                     if ( event.xkey.keycode<256 )            /* XQueryKeymap is limited to 256 keycodes    */
  1122.                     {
  1123.                         if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) )
  1124.                             window->State.KeyRepeating = GL_TRUE;
  1125.                         else
  1126.                             window->State.KeyRepeating = GL_FALSE;
  1127.                     }
  1128.                 }
  1129.             }
  1130.             else
  1131.                 window->State.KeyRepeating = GL_FALSE;
  1132.             /* Cease processing this event if it is auto repeated */
  1133.             if (window->State.KeyRepeating)
  1134.             {
  1135.                 if (event.type == KeyPress) window->State.KeyRepeating = GL_FALSE;
  1136.                 break;
  1137.             }
  1138.             if( event.type == KeyPress )
  1139.             {
  1140.                 keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
  1141.                 special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, Special  ));
  1142.             }
  1143.             else
  1144.             {
  1145.                 keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
  1146.                 special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp  ));
  1147.             }
  1148.             /* Is there a keyboard/special callback hooked for this window? */
  1149.             if( keyboard_cb || special_cb )
  1150.             {
  1151.                 XComposeStatus composeStatus;
  1152.                 char asciiCode[ 32 ];
  1153.                 KeySym keySym;
  1154.                 int len;
  1155.                 /* Check for the ASCII/KeySym codes associated with the event: */
  1156.                 len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode),
  1157.                                      &keySym, &composeStatus
  1158.                 );
  1159.                 /* GLUT API tells us to have two separate callbacks... */
  1160.                 if( len > 0 )
  1161.                 {
  1162.                     /* ...one for the ASCII translateable keypresses... */
  1163.                     if( keyboard_cb )
  1164.                     {
  1165.                         fgSetWindow( window );
  1166.                         fgState.Modifiers = fghGetXModifiers( event.xkey.state );
  1167.                         keyboard_cb( asciiCode[ 0 ],
  1168.                                      event.xkey.x, event.xkey.y
  1169.                         );
  1170.                         fgState.Modifiers = INVALID_MODIFIERS;
  1171.                     }
  1172.                 }
  1173.                 else
  1174.                 {
  1175.                     int special = -1;
  1176.                     /*
  1177.                      * ...and one for all the others, which need to be
  1178.                      * translated to GLUT_KEY_Xs...
  1179.                      */
  1180.                     switch( keySym )
  1181.                     {
  1182.                     case XK_F1:     special = GLUT_KEY_F1;     break;
  1183.                     case XK_F2:     special = GLUT_KEY_F2;     break;
  1184.                     case XK_F3:     special = GLUT_KEY_F3;     break;
  1185.                     case XK_F4:     special = GLUT_KEY_F4;     break;
  1186.                     case XK_F5:     special = GLUT_KEY_F5;     break;
  1187.                     case XK_F6:     special = GLUT_KEY_F6;     break;
  1188.                     case XK_F7:     special = GLUT_KEY_F7;     break;
  1189.                     case XK_F8:     special = GLUT_KEY_F8;     break;
  1190.                     case XK_F9:     special = GLUT_KEY_F9;     break;
  1191.                     case XK_F10:    special = GLUT_KEY_F10;    break;
  1192.                     case XK_F11:    special = GLUT_KEY_F11;    break;
  1193.                     case XK_F12:    special = GLUT_KEY_F12;    break;
  1194.                     case XK_KP_Left:
  1195.                     case XK_Left:   special = GLUT_KEY_LEFT;   break;
  1196.                     case XK_KP_Right:
  1197.                     case XK_Right:  special = GLUT_KEY_RIGHT;  break;
  1198.                     case XK_KP_Up:
  1199.                     case XK_Up:     special = GLUT_KEY_UP;     break;
  1200.                     case XK_KP_Down:
  1201.                     case XK_Down:   special = GLUT_KEY_DOWN;   break;
  1202.                     case XK_KP_Prior:
  1203.                     case XK_Prior:  special = GLUT_KEY_PAGE_UP; break;
  1204.                     case XK_KP_Next:
  1205.                     case XK_Next:   special = GLUT_KEY_PAGE_DOWN; break;
  1206.                     case XK_KP_Home:
  1207.                     case XK_Home:   special = GLUT_KEY_HOME;   break;
  1208.                     case XK_KP_End:
  1209.                     case XK_End:    special = GLUT_KEY_END;    break;
  1210.                     case XK_KP_Insert:
  1211.                     case XK_Insert: special = GLUT_KEY_INSERT; break;
  1212.                     case XK_Num_Lock :  special = GLUT_KEY_NUM_LOCK;  break;
  1213.                     case XK_KP_Begin :  special = GLUT_KEY_BEGIN;     break;
  1214.                     case XK_KP_Delete:  special = GLUT_KEY_DELETE;    break;
  1215.                     }
  1216.                     /*
  1217.                      * Execute the callback (if one has been specified),
  1218.                      * given that the special code seems to be valid...
  1219.                      */
  1220.                     if( special_cb && (special != -1) )
  1221.                     {
  1222.                         fgSetWindow( window );
  1223.                         fgState.Modifiers = fghGetXModifiers( event.xkey.state );
  1224.                         special_cb( special, event.xkey.x, event.xkey.y );
  1225.                         fgState.Modifiers = INVALID_MODIFIERS;
  1226.                     }
  1227.                 }
  1228.             }
  1229.         }
  1230.         break;
  1231.         case ReparentNotify:
  1232.             break; /* XXX Should disable this event */
  1233.         /* Not handled */
  1234.         case GravityNotify:
  1235.             break;
  1236.         default:
  1237.             fgWarning ("Unknown X event type: %dn", event.type);
  1238.             break;
  1239.         }
  1240.     }
  1241. #elif TARGET_HOST_MS_WINDOWS
  1242.     MSG stMsg;
  1243.     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
  1244.     while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
  1245.     {
  1246.         if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
  1247.         {
  1248.             if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
  1249.             {
  1250.                 fgDeinitialize( );
  1251.                 exit( 0 );
  1252.             }
  1253.             else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
  1254.                 fgState.ExecState = GLUT_EXEC_STATE_STOP;
  1255.             return;
  1256.         }
  1257.         TranslateMessage( &stMsg );
  1258.         DispatchMessage( &stMsg );
  1259.     }
  1260. #endif
  1261.     if( fgState.Timers.First )
  1262.         fghCheckTimers( );
  1263.     fghCheckJoystickPolls( );
  1264.     fghDisplayAll( );
  1265.     fgCloseWindows( );
  1266. }
  1267. /*
  1268.  * Enters the freeglut processing loop.
  1269.  * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP".
  1270.  */
  1271. void FGAPIENTRY glutMainLoop( void )
  1272. {
  1273.     int action;
  1274. #if TARGET_HOST_MS_WINDOWS
  1275.     SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
  1276. #endif
  1277.     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" );
  1278. #if TARGET_HOST_MS_WINDOWS
  1279.     /*
  1280.      * Processing before the main loop:  If there is a window which is open and
  1281.      * which has a visibility callback, call it.  I know this is an ugly hack,
  1282.      * but I'm not sure what else to do about it.  Ideally we should leave
  1283.      * something uninitialized in the create window code and initialize it in
  1284.      * the main loop, and have that initialization create a "WM_ACTIVATE"
  1285.      * message.  Then we would put the visibility callback code in the
  1286.      * "case WM_ACTIVATE" block below.         - John Fay -- 10/24/02
  1287.      */
  1288.     while( window )
  1289.     {
  1290.         if ( FETCH_WCB( *window, Visibility ) )
  1291.         {
  1292.             SFG_Window *current_window = fgStructure.CurrentWindow ;
  1293.             INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
  1294.             fgSetWindow( current_window );
  1295.         }
  1296.         window = (SFG_Window *)window->Node.Next ;
  1297.     }
  1298. #endif
  1299.     fgState.ExecState = GLUT_EXEC_STATE_RUNNING ;
  1300.     while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING )
  1301.     {
  1302.         SFG_Window *window;
  1303.         glutMainLoopEvent( );
  1304.         /*
  1305.          * Step through the list of windows, seeing if there are any
  1306.          * that are not menus
  1307.          */
  1308.         for( window = ( SFG_Window * )fgStructure.Windows.First;
  1309.              window;
  1310.              window = ( SFG_Window * )window->Node.Next )
  1311.             if ( ! ( window->IsMenu ) )
  1312.                 break;
  1313.         if( ! window )
  1314.             fgState.ExecState = GLUT_EXEC_STATE_STOP;
  1315.         else
  1316.         {
  1317.             if( fgState.IdleCallback )
  1318.             {
  1319.                 if( fgStructure.CurrentWindow &&
  1320.                     fgStructure.CurrentWindow->IsMenu )
  1321.                     /* fail safe */
  1322.                     fgSetWindow( window );
  1323.                 fgState.IdleCallback( );
  1324.             }
  1325.             fghSleepForEvents( );
  1326.         }
  1327.     }
  1328.     /*
  1329.      * When this loop terminates, destroy the display, state and structure
  1330.      * of a freeglut session, so that another glutInit() call can happen
  1331.      *
  1332.      * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it.
  1333.      */
  1334.     action = fgState.ActionOnWindowClose;
  1335.     fgDeinitialize( );
  1336.     if( action == GLUT_ACTION_EXIT )
  1337.         exit( 0 );
  1338. }
  1339. /*
  1340.  * Leaves the freeglut processing loop.
  1341.  */
  1342. void FGAPIENTRY glutLeaveMainLoop( void )
  1343. {
  1344.     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveMainLoop" );
  1345.     fgState.ExecState = GLUT_EXEC_STATE_STOP ;
  1346. }
  1347. #if TARGET_HOST_MS_WINDOWS
  1348. /*
  1349.  * Determine a GLUT modifer mask based on MS-WINDOWS system info.
  1350.  */
  1351. static int fghGetWin32Modifiers (void)
  1352. {
  1353.     return
  1354.         ( ( ( GetKeyState( VK_LSHIFT   ) < 0 ) ||
  1355.             ( GetKeyState( VK_RSHIFT   ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
  1356.         ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
  1357.             ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL  : 0 ) |
  1358.         ( ( ( GetKeyState( VK_LMENU    ) < 0 ) ||
  1359.             ( GetKeyState( VK_RMENU    ) < 0 )) ? GLUT_ACTIVE_ALT   : 0 );
  1360. }
  1361. /*
  1362.  * The window procedure for handling Win32 events
  1363.  */
  1364. LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  1365.                                LPARAM lParam )
  1366. {
  1367.     SFG_Window* window;
  1368.     PAINTSTRUCT ps;
  1369.     LRESULT lRet = 1;
  1370.     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
  1371.     window = fgWindowByHandle( hWnd );
  1372.     if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
  1373.       return DefWindowProc( hWnd, uMsg, wParam, lParam );
  1374.     /* printf ( "Window %3d message <%04x> %12d %12dn", window?window->ID:0,
  1375.              uMsg, wParam, lParam ); */
  1376.     switch( uMsg )
  1377.     {
  1378.     case WM_CREATE:
  1379.         /* The window structure is passed as the creation structure paramter... */
  1380.         window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
  1381.         FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
  1382.                                        "fgWindowProc" );
  1383.         window->Window.Handle = hWnd;
  1384.         window->Window.Device = GetDC( hWnd );
  1385.         if( window->IsMenu )
  1386.         {
  1387.             unsigned int current_DisplayMode = fgState.DisplayMode;
  1388.             fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
  1389. #if !defined(_WIN32_WCE)
  1390.             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
  1391. #endif
  1392.             fgState.DisplayMode = current_DisplayMode;
  1393.             if( fgStructure.MenuContext )
  1394.                 wglMakeCurrent( window->Window.Device,
  1395.                                 fgStructure.MenuContext->MContext
  1396.                 );
  1397.             else
  1398.             {
  1399.                 fgStructure.MenuContext =
  1400.                     (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
  1401.                 fgStructure.MenuContext->MContext =
  1402.                     wglCreateContext( window->Window.Device );
  1403.             }
  1404.             /* window->Window.Context = wglGetCurrentContext ();   */
  1405.             window->Window.Context = wglCreateContext( window->Window.Device );
  1406.         }
  1407.         else
  1408.         {
  1409. #if !defined(_WIN32_WCE)
  1410.             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
  1411. #endif
  1412.             if( ! fgState.UseCurrentContext )
  1413.                 window->Window.Context =
  1414.                     wglCreateContext( window->Window.Device );
  1415.             else
  1416.             {
  1417.                 window->Window.Context = wglGetCurrentContext( );
  1418.                 if( ! window->Window.Context )
  1419.                     window->Window.Context =
  1420.                         wglCreateContext( window->Window.Device );
  1421.             }
  1422. #if !defined(_WIN32_WCE)
  1423.             fgNewWGLCreateContext( window );
  1424. #endif
  1425.         }
  1426.         window->State.NeedToResize = GL_TRUE;
  1427.         if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
  1428.         {
  1429.             SFG_Window *current_window = fgStructure.CurrentWindow;
  1430.             fgSetWindow( window );
  1431.             window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
  1432.             window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
  1433.             fgSetWindow( current_window );
  1434.         }
  1435.         ReleaseDC( window->Window.Handle, window->Window.Device );
  1436. #if defined(_WIN32_WCE)
  1437.         /* Take over button handling */
  1438.         {
  1439.             HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
  1440.             if (dxDllLib)
  1441.             {
  1442.                 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
  1443.                 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
  1444.             }
  1445.             if(GXOpenInput_)
  1446.                 (*GXOpenInput_)();
  1447.             if(GXGetDefaultKeys_)
  1448.                 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
  1449.         }
  1450. #endif /* defined(_WIN32_WCE) */
  1451.         break;
  1452.     case WM_SIZE:
  1453.         /*
  1454.          * If the window is visible, then it is the user manually resizing it.
  1455.          * If it is not, then it is the system sending us a dummy resize with
  1456.          * zero dimensions on a "glutIconifyWindow" call.
  1457.          */
  1458.         if( window->State.Visible )
  1459.         {
  1460.             window->State.NeedToResize = GL_TRUE;
  1461. #if defined(_WIN32_WCE)
  1462.             window->State.Width  = HIWORD(lParam);
  1463.             window->State.Height = LOWORD(lParam);
  1464. #else
  1465.             window->State.Width  = LOWORD(lParam);
  1466.             window->State.Height = HIWORD(lParam);
  1467. #endif /* defined(_WIN32_WCE) */
  1468.         }
  1469.         break;
  1470.     case WM_SETFOCUS:
  1471. /*        printf("WM_SETFOCUS: %pn", window ); */
  1472.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1473.         INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
  1474.         break;
  1475.     case WM_KILLFOCUS:
  1476. /*        printf("WM_KILLFOCUS: %pn", window ); */
  1477.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1478.         INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
  1479.         if( window->IsMenu &&
  1480.             window->ActiveMenu && window->ActiveMenu->IsActive )
  1481.             fgUpdateMenuHighlight( window->ActiveMenu );
  1482.         break;
  1483. #if 0
  1484.     case WM_ACTIVATE:
  1485.         if (LOWORD(wParam) != WA_INACTIVE)
  1486.         {
  1487. /*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)n", window,
  1488.                    window->State.Cursor ); */
  1489.             fgSetCursor( window, window->State.Cursor );
  1490.         }
  1491.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1492.         break;
  1493. #endif
  1494.     case WM_SETCURSOR:
  1495. /*      printf ( "Cursor event %x %x %x %xn", window, window->State.Cursor, lParam, wParam ) ; */
  1496.         if( LOWORD( lParam ) == HTCLIENT )
  1497.             fgSetCursor ( window, window->State.Cursor ) ;
  1498.         else
  1499.             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1500.         break;
  1501.     case WM_SHOWWINDOW:
  1502.         window->State.Visible = GL_TRUE;
  1503.         window->State.Redisplay = GL_TRUE;
  1504.         break;
  1505.     case WM_PAINT:
  1506.         /* Turn on the visibility in case it was turned off somehow */
  1507.         window->State.Visible = GL_TRUE;
  1508.         BeginPaint( hWnd, &ps );
  1509.         fghRedrawWindow( window );
  1510.         EndPaint( hWnd, &ps );
  1511.         break;
  1512.     case WM_CLOSE:
  1513.         fgDestroyWindow ( window );
  1514.         if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
  1515.             PostQuitMessage(0);
  1516.         break;
  1517.     case WM_DESTROY:
  1518.         /*
  1519.          * The window already got destroyed, so don't bother with it.
  1520.          */
  1521.         return 0;
  1522.     case WM_MOUSEMOVE:
  1523.     {
  1524. #if defined(_WIN32_WCE)
  1525.         window->State.MouseX = 320-HIWORD( lParam );
  1526.         window->State.MouseY = LOWORD( lParam );
  1527. #else
  1528.         window->State.MouseX = LOWORD( lParam );
  1529.         window->State.MouseY = HIWORD( lParam );
  1530. #endif /* defined(_WIN32_WCE) */
  1531.         /* Restrict to [-32768, 32767] to match X11 behaviour       */
  1532.         /* See comment in "freeglut_developer" mailing list 10/4/04 */
  1533.         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
  1534.         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
  1535.         if ( window->ActiveMenu )
  1536.         {
  1537.             fgUpdateMenuHighlight( window->ActiveMenu );
  1538.             break;
  1539.         }
  1540.         fgState.Modifiers = fghGetWin32Modifiers( );
  1541.         if( ( wParam & MK_LBUTTON ) ||
  1542.             ( wParam & MK_MBUTTON ) ||
  1543.             ( wParam & MK_RBUTTON ) )
  1544.             INVOKE_WCB( *window, Motion, ( window->State.MouseX,
  1545.                                            window->State.MouseY ) );
  1546.         else
  1547.             INVOKE_WCB( *window, Passive, ( window->State.MouseX,
  1548.                                             window->State.MouseY ) );
  1549.         fgState.Modifiers = INVALID_MODIFIERS;
  1550.     }
  1551.     break;
  1552.     case WM_LBUTTONDOWN:
  1553.     case WM_MBUTTONDOWN:
  1554.     case WM_RBUTTONDOWN:
  1555.     case WM_LBUTTONUP:
  1556.     case WM_MBUTTONUP:
  1557.     case WM_RBUTTONUP:
  1558.     {
  1559.         GLboolean pressed = GL_TRUE;
  1560.         int button;
  1561. #if defined(_WIN32_WCE)
  1562.         window->State.MouseX = 320-HIWORD( lParam );
  1563.         window->State.MouseY = LOWORD( lParam );
  1564. #else
  1565.         window->State.MouseX = LOWORD( lParam );
  1566.         window->State.MouseY = HIWORD( lParam );
  1567. #endif /* defined(_WIN32_WCE) */
  1568.         /* Restrict to [-32768, 32767] to match X11 behaviour       */
  1569.         /* See comment in "freeglut_developer" mailing list 10/4/04 */
  1570.         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
  1571.         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
  1572.         switch( uMsg )
  1573.         {
  1574.         case WM_LBUTTONDOWN:
  1575.             pressed = GL_TRUE;
  1576.             button = GLUT_LEFT_BUTTON;
  1577.             break;
  1578.         case WM_MBUTTONDOWN:
  1579.             pressed = GL_TRUE;
  1580.             button = GLUT_MIDDLE_BUTTON;
  1581.             break;
  1582.         case WM_RBUTTONDOWN:
  1583.             pressed = GL_TRUE;
  1584.             button = GLUT_RIGHT_BUTTON;
  1585.             break;
  1586.         case WM_LBUTTONUP:
  1587.             pressed = GL_FALSE;
  1588.             button = GLUT_LEFT_BUTTON;
  1589.             break;
  1590.         case WM_MBUTTONUP:
  1591.             pressed = GL_FALSE;
  1592.             button = GLUT_MIDDLE_BUTTON;
  1593.             break;
  1594.         case WM_RBUTTONUP:
  1595.             pressed = GL_FALSE;
  1596.             button = GLUT_RIGHT_BUTTON;
  1597.             break;
  1598.         default:
  1599.             pressed = GL_FALSE;
  1600.             button = -1;
  1601.             break;
  1602.         }
  1603. #if !defined(_WIN32_WCE)
  1604.         if( GetSystemMetrics( SM_SWAPBUTTON ) )
  1605.         {
  1606.             if( button == GLUT_LEFT_BUTTON )
  1607.                 button = GLUT_RIGHT_BUTTON;
  1608.             else
  1609.                 if( button == GLUT_RIGHT_BUTTON )
  1610.                     button = GLUT_LEFT_BUTTON;
  1611.         }
  1612. #endif /* !defined(_WIN32_WCE) */
  1613.         if( button == -1 )
  1614.             return DefWindowProc( hWnd, uMsg, lParam, wParam );
  1615.         /*
  1616.          * Do not execute the application's mouse callback if a menu
  1617.          * is hooked to this button.  In that case an appropriate
  1618.          * private call should be generated.
  1619.          */
  1620.         if( fgCheckActiveMenu( window, button, pressed,
  1621.                                window->State.MouseX, window->State.MouseY ) )
  1622.             break;
  1623.         /* Set capture so that the window captures all the mouse messages */
  1624.         /*
  1625.          * XXX - Multiple button support:  Under X11, the mouse is not released
  1626.          * XXX - from the window until all buttons have been released, even if the
  1627.          * XXX - user presses a button in another window.  This will take more
  1628.          * XXX - code changes than I am up to at the moment (10/5/04).  The present
  1629.          * XXX - is a 90 percent solution.
  1630.          */
  1631.         if ( pressed == GL_TRUE )
  1632.           SetCapture ( window->Window.Handle ) ;
  1633.         else
  1634.           ReleaseCapture () ;
  1635.         if( ! FETCH_WCB( *window, Mouse ) )
  1636.             break;
  1637.         fgSetWindow( window );
  1638.         fgState.Modifiers = fghGetWin32Modifiers( );
  1639.         INVOKE_WCB(
  1640.             *window, Mouse,
  1641.             ( button,
  1642.               pressed ? GLUT_DOWN : GLUT_UP,
  1643.               window->State.MouseX,
  1644.               window->State.MouseY
  1645.             )
  1646.         );
  1647.         fgState.Modifiers = INVALID_MODIFIERS;
  1648.     }
  1649.     break;
  1650.     case 0x020a:
  1651.         /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */
  1652.     {
  1653.         /*
  1654.          * XXX THIS IS SPECULATIVE -- John Fay, 10/2/03
  1655.          * XXX Should use WHEEL_DELTA instead of 120
  1656.          */
  1657.         int wheel_number = LOWORD( wParam );
  1658.         short ticks = ( short )HIWORD( wParam ) / 120;
  1659.         int direction = 1;
  1660.         if( ticks < 0 )
  1661.         {
  1662.             direction = -1;
  1663.             ticks = -ticks;
  1664.         }
  1665.         /*
  1666.          * The mouse cursor has moved. Remember the new mouse cursor's position
  1667.          */
  1668.         /*        window->State.MouseX = LOWORD( lParam ); */
  1669.         /* Need to adjust by window position, */
  1670.         /*        window->State.MouseY = HIWORD( lParam ); */
  1671.         /* change "lParam" to other parameter */
  1672.         if( ! FETCH_WCB( *window, MouseWheel ) &&
  1673.             ! FETCH_WCB( *window, Mouse ) )
  1674.             break;
  1675.         fgSetWindow( window );
  1676.         fgState.Modifiers = fghGetWin32Modifiers( );
  1677.         while( ticks-- )
  1678.             if( FETCH_WCB( *window, MouseWheel ) )
  1679.                 INVOKE_WCB( *window, MouseWheel,
  1680.                             ( wheel_number,
  1681.                               direction,
  1682.                               window->State.MouseX,
  1683.                               window->State.MouseY
  1684.                             )
  1685.                 );
  1686.             else  /* No mouse wheel, call the mouse button callback twice */
  1687.             {
  1688.                 /*
  1689.                  * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
  1690.                  *  "    "   one                     +1 to 5, -1 to 6, ...
  1691.                  *
  1692.                  * XXX The below assumes that you have no more than 3 mouse
  1693.                  * XXX buttons.  Sorry.
  1694.                  */
  1695.                 int button = wheel_number * 2 + 3;
  1696.                 if( direction < 0 )
  1697.                     ++button;
  1698.                 INVOKE_WCB( *window, Mouse,
  1699.                             ( button, GLUT_DOWN,
  1700.                               window->State.MouseX, window->State.MouseY )
  1701.                 );
  1702.                 INVOKE_WCB( *window, Mouse,
  1703.                             ( button, GLUT_UP,
  1704.                               window->State.MouseX, window->State.MouseY )
  1705.                 );
  1706.             }
  1707.         fgState.Modifiers = INVALID_MODIFIERS;
  1708.     }
  1709.     break ;
  1710.     case WM_SYSKEYDOWN:
  1711.     case WM_KEYDOWN:
  1712.     {
  1713.         int keypress = -1;
  1714.         POINT mouse_pos ;
  1715.         if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
  1716.             break;
  1717.         /*
  1718.          * Remember the current modifiers state. This is done here in order
  1719.          * to make sure the VK_DELETE keyboard callback is executed properly.
  1720.          */
  1721.         fgState.Modifiers = fghGetWin32Modifiers( );
  1722.         GetCursorPos( &mouse_pos );
  1723.         ScreenToClient( window->Window.Handle, &mouse_pos );
  1724.         window->State.MouseX = mouse_pos.x;
  1725.         window->State.MouseY = mouse_pos.y;
  1726.         /* Convert the Win32 keystroke codes to GLUTtish way */
  1727. #       define KEY(a,b) case a: keypress = b; break;
  1728.         switch( wParam )
  1729.         {
  1730.             KEY( VK_F1,     GLUT_KEY_F1        );
  1731.             KEY( VK_F2,     GLUT_KEY_F2        );
  1732.             KEY( VK_F3,     GLUT_KEY_F3        );
  1733.             KEY( VK_F4,     GLUT_KEY_F4        );
  1734.             KEY( VK_F5,     GLUT_KEY_F5        );
  1735.             KEY( VK_F6,     GLUT_KEY_F6        );
  1736.             KEY( VK_F7,     GLUT_KEY_F7        );
  1737.             KEY( VK_F8,     GLUT_KEY_F8        );
  1738.             KEY( VK_F9,     GLUT_KEY_F9        );
  1739.             KEY( VK_F10,    GLUT_KEY_F10       );
  1740.             KEY( VK_F11,    GLUT_KEY_F11       );
  1741.             KEY( VK_F12,    GLUT_KEY_F12       );
  1742.             KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
  1743.             KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
  1744.             KEY( VK_HOME,   GLUT_KEY_HOME      );
  1745.             KEY( VK_END,    GLUT_KEY_END       );
  1746.             KEY( VK_LEFT,   GLUT_KEY_LEFT      );
  1747.             KEY( VK_UP,     GLUT_KEY_UP        );
  1748.             KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
  1749.             KEY( VK_DOWN,   GLUT_KEY_DOWN      );
  1750.             KEY( VK_INSERT, GLUT_KEY_INSERT    );
  1751.         case VK_DELETE:
  1752.             /* The delete key should be treated as an ASCII keypress: */
  1753.             INVOKE_WCB( *window, Keyboard,
  1754.                         ( 127, window->State.MouseX, window->State.MouseY )
  1755.             );
  1756.         }
  1757. #if defined(_WIN32_WCE)
  1758.         if(!(lParam & 0x40000000)) /* Prevent auto-repeat */
  1759.         {
  1760.             if(wParam==(unsigned)gxKeyList.vkRight)
  1761.                 keypress = GLUT_KEY_RIGHT;
  1762.             else if(wParam==(unsigned)gxKeyList.vkLeft)
  1763.                 keypress = GLUT_KEY_LEFT;
  1764.             else if(wParam==(unsigned)gxKeyList.vkUp)
  1765.                 keypress = GLUT_KEY_UP;
  1766.             else if(wParam==(unsigned)gxKeyList.vkDown)
  1767.                 keypress = GLUT_KEY_DOWN;
  1768.             else if(wParam==(unsigned)gxKeyList.vkA)
  1769.                 keypress = GLUT_KEY_F1;
  1770.             else if(wParam==(unsigned)gxKeyList.vkB)
  1771.                 keypress = GLUT_KEY_F2;
  1772.             else if(wParam==(unsigned)gxKeyList.vkC)
  1773.                 keypress = GLUT_KEY_F3;
  1774.             else if(wParam==(unsigned)gxKeyList.vkStart)
  1775.                 keypress = GLUT_KEY_F4;
  1776.         }
  1777. #endif
  1778.         if( keypress != -1 )
  1779.             INVOKE_WCB( *window, Special,
  1780.                         ( keypress,
  1781.                           window->State.MouseX, window->State.MouseY )
  1782.             );
  1783.         fgState.Modifiers = INVALID_MODIFIERS;
  1784.     }
  1785.     break;
  1786.     case WM_SYSKEYUP:
  1787.     case WM_KEYUP:
  1788.     {
  1789.         int keypress = -1;
  1790.         POINT mouse_pos;
  1791.         /*
  1792.          * Remember the current modifiers state. This is done here in order
  1793.          * to make sure the VK_DELETE keyboard callback is executed properly.
  1794.          */
  1795.         fgState.Modifiers = fghGetWin32Modifiers( );
  1796.         GetCursorPos( &mouse_pos );
  1797.         ScreenToClient( window->Window.Handle, &mouse_pos );
  1798.         window->State.MouseX = mouse_pos.x;
  1799.         window->State.MouseY = mouse_pos.y;
  1800.         /*
  1801.          * Convert the Win32 keystroke codes to GLUTtish way.
  1802.          * "KEY(a,b)" was defined under "WM_KEYDOWN"
  1803.          */
  1804.         switch( wParam )
  1805.         {
  1806.             KEY( VK_F1,     GLUT_KEY_F1        );
  1807.             KEY( VK_F2,     GLUT_KEY_F2        );
  1808.             KEY( VK_F3,     GLUT_KEY_F3        );
  1809.             KEY( VK_F4,     GLUT_KEY_F4        );
  1810.             KEY( VK_F5,     GLUT_KEY_F5        );
  1811.             KEY( VK_F6,     GLUT_KEY_F6        );
  1812.             KEY( VK_F7,     GLUT_KEY_F7        );
  1813.             KEY( VK_F8,     GLUT_KEY_F8        );
  1814.             KEY( VK_F9,     GLUT_KEY_F9        );
  1815.             KEY( VK_F10,    GLUT_KEY_F10       );
  1816.             KEY( VK_F11,    GLUT_KEY_F11       );
  1817.             KEY( VK_F12,    GLUT_KEY_F12       );
  1818.             KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
  1819.             KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
  1820.             KEY( VK_HOME,   GLUT_KEY_HOME      );
  1821.             KEY( VK_END,    GLUT_KEY_END       );
  1822.             KEY( VK_LEFT,   GLUT_KEY_LEFT      );
  1823.             KEY( VK_UP,     GLUT_KEY_UP        );
  1824.             KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
  1825.             KEY( VK_DOWN,   GLUT_KEY_DOWN      );
  1826.             KEY( VK_INSERT, GLUT_KEY_INSERT    );
  1827.           case VK_DELETE:
  1828.               /* The delete key should be treated as an ASCII keypress: */
  1829.               INVOKE_WCB( *window, KeyboardUp,
  1830.                           ( 127, window->State.MouseX, window->State.MouseY )
  1831.               );
  1832.               break;
  1833.         default:
  1834.         {
  1835. #if !defined(_WIN32_WCE)
  1836.             BYTE state[ 256 ];
  1837.             WORD code[ 2 ];
  1838.             GetKeyboardState( state );
  1839.             if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
  1840.                 wParam=code[ 0 ];
  1841.             INVOKE_WCB( *window, KeyboardUp,
  1842.                         ( (char)wParam,
  1843.                           window->State.MouseX, window->State.MouseY )
  1844.             );
  1845. #endif /* !defined(_WIN32_WCE) */
  1846.         }
  1847.         }
  1848.         if( keypress != -1 )
  1849.             INVOKE_WCB( *window, SpecialUp,
  1850.                         ( keypress,
  1851.                           window->State.MouseX, window->State.MouseY )
  1852.             );
  1853.         fgState.Modifiers = INVALID_MODIFIERS;
  1854.     }
  1855.     break;
  1856.     case WM_SYSCHAR:
  1857.     case WM_CHAR:
  1858.     {
  1859.       if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
  1860.             break;
  1861.         fgState.Modifiers = fghGetWin32Modifiers( );
  1862.         INVOKE_WCB( *window, Keyboard,
  1863.                     ( (char)wParam,
  1864.                       window->State.MouseX, window->State.MouseY )
  1865.         );
  1866.         fgState.Modifiers = INVALID_MODIFIERS;
  1867.     }
  1868.     break;
  1869.     case WM_CAPTURECHANGED:
  1870.         /* User has finished resizing the window, force a redraw */
  1871.         INVOKE_WCB( *window, Display, ( ) );
  1872.         /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
  1873.         break;
  1874.         /* Other messages that I have seen and which are not handled already */
  1875.     case WM_SETTEXT:  /* 0x000c */
  1876.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1877.         /* Pass it on to "DefWindowProc" to set the window text */
  1878.         break;
  1879.     case WM_GETTEXT:  /* 0x000d */
  1880.         /* Ideally we would copy the title of the window into "lParam" */
  1881.         /* strncpy ( (char *)lParam, "Window Title", wParam );
  1882.            lRet = ( wParam > 12 ) ? 12 : wParam;  */
  1883.         /* the number of characters copied */
  1884.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1885.         break;
  1886.     case WM_GETTEXTLENGTH:  /* 0x000e */
  1887.         /* Ideally we would get the length of the title of the window */
  1888.         lRet = 12;
  1889.         /* the number of characters in "Window Title" (see above) */
  1890.         break;
  1891.     case WM_ERASEBKGND:  /* 0x0014 */
  1892.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1893.         break;
  1894. #if !defined(_WIN32_WCE)
  1895.     case WM_SYNCPAINT:  /* 0x0088 */
  1896.         /* Another window has moved, need to update this one */
  1897.         window->State.Redisplay = GL_TRUE;
  1898.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1899.         /* Help screen says this message must be passed to "DefWindowProc" */
  1900.         break;
  1901.     case WM_NCPAINT:  /* 0x0085 */
  1902.       /* Need to update the border of this window */
  1903.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1904.         /* Pass it on to "DefWindowProc" to repaint a standard border */
  1905.         break;
  1906.     case WM_SYSCOMMAND :  /* 0x0112 */
  1907.         {
  1908.           /*
  1909.            * We have received a system command message.  Try to act on it.
  1910.            * The commands are passed in through the "wParam" parameter:
  1911.            * The least significant digit seems to be which edge of the window
  1912.            * is being used for a resize event:
  1913.            *     4  3  5
  1914.            *     1     2
  1915.            *     7  6  8
  1916.            * Congratulations and thanks to Richard Rauch for figuring this out..
  1917.            */
  1918.             switch ( wParam & 0xfff0 )
  1919.             {
  1920.             case SC_SIZE       :
  1921.                 break ;
  1922.             case SC_MOVE       :
  1923.                 break ;
  1924.             case SC_MINIMIZE   :
  1925.                 /* User has clicked on the "-" to minimize the window */
  1926.                 /* Turn off the visibility */
  1927.                 window->State.Visible = GL_FALSE ;
  1928.                 break ;
  1929.             case SC_MAXIMIZE   :
  1930.                 break ;
  1931.             case SC_NEXTWINDOW :
  1932.                 break ;
  1933.             case SC_PREVWINDOW :
  1934.                 break ;
  1935.             case SC_CLOSE      :
  1936.                 /* Followed very closely by a WM_CLOSE message */
  1937.                 break ;
  1938.             case SC_VSCROLL    :
  1939.                 break ;
  1940.             case SC_HSCROLL    :
  1941.                 break ;
  1942.             case SC_MOUSEMENU  :
  1943.                 break ;
  1944.             case SC_KEYMENU    :
  1945.                 break ;
  1946.             case SC_ARRANGE    :
  1947.                 break ;
  1948.             case SC_RESTORE    :
  1949.                 break ;
  1950.             case SC_TASKLIST   :
  1951.                 break ;
  1952.             case SC_SCREENSAVE :
  1953.                 break ;
  1954.             case SC_HOTKEY     :
  1955.                 break ;
  1956. #if(WINVER >= 0x0400)
  1957.             case SC_DEFAULT    :
  1958.                 break ;
  1959.             case SC_MONITORPOWER    :
  1960.                 break ;
  1961.             case SC_CONTEXTHELP    :
  1962.                 break ;
  1963. #endif /* WINVER >= 0x0400 */
  1964.             default:
  1965. #if _DEBUG
  1966.                 fgWarning( "Unknown wParam type 0x%x", wParam );
  1967. #endif
  1968.                 break;
  1969.             }
  1970.         }
  1971. #endif /* !defined(_WIN32_WCE) */
  1972.         /* We need to pass the message on to the operating system as well */
  1973.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1974.         break;
  1975.     default:
  1976.         /* Handle unhandled messages */
  1977.         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
  1978.         break;
  1979.     }
  1980.     return lRet;
  1981. }
  1982. #endif
  1983. /*** END OF FILE ***/