X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fx11%2Ffg_main_x11.c;h=e3e2a2249d3862433f4d0492e4c2a70eaa1ddd49;hb=e1b231e938f0851ea4fb97c9ee2aae59110dd24a;hp=e72db37b562e1e3447ffb91d1b67837eb875e8ef;hpb=5b3d339481bac6dbaeb599bffc1325f716585bfe;p=freeglut diff --git a/src/x11/fg_main_x11.c b/src/x11/fg_main_x11.c index e72db37..e3e2a22 100644 --- a/src/x11/fg_main_x11.c +++ b/src/x11/fg_main_x11.c @@ -1,5 +1,5 @@ /* - * freeglut_main_x11.c + * fg_main_x11.c * * The X11-specific windows message processing methods. * @@ -28,17 +28,9 @@ #include #include "../fg_internal.h" -#ifdef HAVE_ERRNO_H -# include -#endif +#include #include -#ifdef HAVE_VFPRINTF -# define VFPRINTF(s,f,a) vfprintf((s),(f),(a)) -#elif defined(HAVE__DOPRNT) -# define VFPRINTF(s,f,a) _doprnt((f),(a),(s)) -#else -# define VFPRINTF(s,f,a) -#endif + /* * Try to get the maximum value allowed for ints, falling back to the minimum @@ -55,39 +47,31 @@ # define MIN(a,b) (((a)<(b)) ? (a) : (b)) #endif +extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify); +extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify); +extern void fgPlatformFullScreenToggle( SFG_Window *win ); +extern void fgPlatformPositionWindow( SFG_Window *window, int x, int y ); +extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height ); +extern void fgPlatformPushWindow( SFG_Window *window ); +extern void fgPlatformPopWindow( SFG_Window *window ); +extern void fgPlatformHideWindow( SFG_Window *window ); +extern void fgPlatformIconifyWindow( SFG_Window *window ); +extern void fgPlatformShowWindow( SFG_Window *window ); + +/* used in the event handling code to match and discard stale mouse motion events */ +static Bool match_motion(Display *dpy, XEvent *xev, XPointer arg); + /* * TODO BEFORE THE STABLE RELEASE: * * There are some issues concerning window redrawing under X11, and maybe - * some events are not handled. The Win32 version lacks some more features, - * but seems acceptable for not demanding purposes. + * some events are not handled. * * Need to investigate why the X11 version breaks out with an error when * closing a window (using the window manager, not glutDestroyWindow)... */ -/* - * Handle a window configuration change. When no reshape - * callback is hooked, the viewport size is updated to - * match the new window size. - */ -void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height ) -{ - XResizeWindow( fgDisplay.pDisplay.Display, window->Window.Handle, - width, height ); - XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */ -} - - -/* - * A static helper function to execute display callback for a window - */ -void fgPlatformDisplayWindow ( SFG_Window *window ) -{ - fghRedrawWindow ( window ) ; -} - fg_time_t fgPlatformSystemTime ( void ) { @@ -132,10 +116,8 @@ void fgPlatformSleepForEvents( fg_time_t msec ) wait.tv_usec = (msec % 1000) * 1000; err = select( socket+1, &fdset, NULL, NULL, &wait ); -#ifdef HAVE_ERRNO_H if( ( -1 == err ) && ( errno != EINTR ) ) fgWarning ( "freeglut select() error: %d", errno ); -#endif } } @@ -295,7 +277,7 @@ static const char* fghColormapStateToString( int state ) } } -static void fghPrintEvent( XEvent *event ) +__fg_unused static void fghPrintEvent( XEvent *event ) { switch( event->type ) { @@ -625,10 +607,11 @@ void fgPlatformProcessSingleEvent ( void ) switch( event.type ) { case ClientMessage: - if(fgIsSpaceballXEvent(&event)) { - fgSpaceballHandleXEvent(&event); - break; - } + if (fgStructure.CurrentWindow) + if(fgIsSpaceballXEvent(&event)) { + fgSpaceballHandleXEvent(&event); + break; + } /* Destroy the window when the WM_DELETE_WINDOW message arrives */ if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.pDisplay.DeleteWindow ) { @@ -660,35 +643,25 @@ void fgPlatformProcessSingleEvent ( void ) case CreateNotify: case ConfigureNotify: { - int width, height; + int width, height, x, y; if( event.type == CreateNotify ) { GETWINDOW( xcreatewindow ); width = event.xcreatewindow.width; height = event.xcreatewindow.height; + x = event.xcreatewindow.x; + y = event.xcreatewindow.y; } else { GETWINDOW( xconfigure ); width = event.xconfigure.width; height = event.xconfigure.height; + x = event.xconfigure.x; + y = event.xconfigure.y; } - if( ( width != window->State.pWState.OldWidth ) || - ( height != window->State.pWState.OldHeight ) ) - { - SFG_Window *current_window = fgStructure.CurrentWindow; - - window->State.pWState.OldWidth = width; - window->State.pWState.OldHeight = height; - if( FETCH_WCB( *window, Reshape ) ) - INVOKE_WCB( *window, Reshape, ( width, height ) ); - else - { - fgSetWindow( window ); - glViewport( 0, 0, width, height ); - } - glutPostRedisplay( ); - if( window->IsMenu ) - fgSetWindow( current_window ); - } + /* Update state and call callback, if there was a change */ + fghOnPositionNotify(window, x, y, GL_FALSE); + /* Update state and call callback, if there was a change */ + fghOnReshapeNotify(window, width, height, GL_FALSE); } break; @@ -714,7 +687,7 @@ void fgPlatformProcessSingleEvent ( void ) if( event.xexpose.count == 0 ) { GETWINDOW( xexpose ); - window->State.Redisplay = GL_TRUE; + window->State.WorkMask |= GLUT_DISPLAY_WORK; } break; @@ -788,6 +761,13 @@ void fgPlatformProcessSingleEvent ( void ) case MotionNotify: { + /* if GLUT_SKIP_STALE_MOTION_EVENTS is true, then discard all but + * the last motion event from the queue + */ + if(fgState.SkipStaleMotion) { + while(XCheckIfEvent(fgDisplay.pDisplay.Display, &event, match_motion, 0)); + } + GETWINDOW( xmotion ); GETMOUSE( xmotion ); @@ -827,11 +807,8 @@ void fgPlatformProcessSingleEvent ( void ) case ButtonRelease: case ButtonPress: { - GLboolean pressed = GL_TRUE; - int button; - - if( event.type == ButtonRelease ) - pressed = GL_FALSE ; + GLboolean pressed; + int button, x, y; /* * A mouse button has been pressed or released. Traditionally, @@ -849,59 +826,46 @@ void fgPlatformProcessSingleEvent ( void ) */ button = event.xbutton.button - 1; + pressed = event.type == ButtonPress ? GL_TRUE : GL_FALSE; + x = event.xbutton.x; + y = event.xbutton.y; + /* * Do not execute the application's mouse callback if a menu * is hooked to this button. In that case an appropriate * private call should be generated. */ - if( fgCheckActiveMenu( window, button, pressed, - event.xbutton.x_root, event.xbutton.y_root ) ) + if(fgCheckActiveMenu( window, button, pressed, x, y)) break; /* * Check if there is a mouse or mouse wheel callback hooked to the * window */ - if( ! FETCH_WCB( *window, Mouse ) && - ! FETCH_WCB( *window, MouseWheel ) ) + if(!FETCH_WCB(*window, Mouse) && !FETCH_WCB(*window, MouseWheel)) break; - fgState.Modifiers = fgPlatformGetModifiers( event.xbutton.state ); + fgState.Modifiers = fgPlatformGetModifiers(event.xbutton.state); - /* Finally execute the mouse or mouse wheel callback */ - if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) - INVOKE_WCB( *window, Mouse, ( button, - pressed ? GLUT_DOWN : GLUT_UP, - event.xbutton.x, - event.xbutton.y ) - ); - else - { - /* - * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1 - * " 6 and 7 " " one; ... - * - * XXX This *should* be behind some variables/macros, - * XXX since the order and numbering isn't certain - * XXX See XFree86 configuration docs (even back in the - * XXX 3.x days, and especially with 4.x). - * - * XXX Note that {button} has already been decremented - * XXX in mapping from X button numbering to GLUT. - * - * XXX Should add support for partial wheel turns as Windows does -- 5/27/11 - */ - int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2; - int direction = -1; - if( button % 2 ) - direction = 1; - - if( pressed ) - INVOKE_WCB( *window, MouseWheel, ( wheel_number, - direction, - event.xbutton.x, - event.xbutton.y ) - ); + /* Finally execute the mouse or mouse wheel callback. + * The mouse wheel is reported as buttons 4 (down) and 5 (up) by + * the X server. "button" has been converted to 0-based above, so + * that's 3 and 4 for us. + * If a wheel callback hasn't been registered, we simply treat them + * as button presses and pass them to the mouse handler. This is + * important for compatibility with the original GLUT. + */ + if(button < 3 || button > 4 || !FETCH_WCB(*window, MouseWheel)) { + INVOKE_WCB(*window, Mouse, (button, pressed ? GLUT_DOWN : GLUT_UP, x, y)); + } else { + if(pressed) { + int dir = button & 1 ? 1 : -1; + /* there's no way to know if X buttons after 5 are more + * wheels/wheel axes, or regular buttons. So we'll only + * ever invoke the wheel CB for wheel 0. + */ + INVOKE_WCB(*window, MouseWheel, (0, dir, x, y)); + } } fgState.Modifiers = INVALID_MODIFIERS; } @@ -910,8 +874,10 @@ void fgPlatformProcessSingleEvent ( void ) case KeyRelease: case KeyPress: { - FGCBKeyboard keyboard_cb; - FGCBSpecial special_cb; + FGCBKeyboardUC keyboard_cb; + FGCBSpecialUC special_cb; + FGCBUserData keyboard_ud; + FGCBUserData special_ud; GETWINDOW( xkey ); GETMOUSE( xkey ); @@ -933,32 +899,36 @@ void fgPlatformProcessSingleEvent ( void ) if ( event.xkey.keycode<256 ) /* XQueryKeymap is limited to 256 keycodes */ { if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) ) - window->State.KeyRepeating = GL_TRUE; + window->State.pWState.KeyRepeating = GL_TRUE; else - window->State.KeyRepeating = GL_FALSE; + window->State.pWState.KeyRepeating = GL_FALSE; } } } else - window->State.KeyRepeating = GL_FALSE; + window->State.pWState.KeyRepeating = GL_FALSE; /* Cease processing this event if it is auto repeated */ - if (window->State.KeyRepeating) + if (window->State.pWState.KeyRepeating) { - if (event.type == KeyPress) window->State.KeyRepeating = GL_FALSE; + if (event.type == KeyPress) window->State.pWState.KeyRepeating = GL_FALSE; break; } if( event.type == KeyPress ) { - keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard )); - special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special )); + keyboard_cb = (FGCBKeyboardUC)( FETCH_WCB( *window, Keyboard )); + special_cb = (FGCBSpecialUC) ( FETCH_WCB( *window, Special )); + keyboard_ud = FETCH_USER_DATA_WCB( *window, Keyboard ); + special_ud = FETCH_USER_DATA_WCB( *window, Special ); } else { - keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); - special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp )); + keyboard_cb = (FGCBKeyboardUC)( FETCH_WCB( *window, KeyboardUp )); + special_cb = (FGCBSpecialUC) ( FETCH_WCB( *window, SpecialUp )); + keyboard_ud = FETCH_USER_DATA_WCB( *window, KeyboardUp ); + special_ud = FETCH_USER_DATA_WCB( *window, SpecialUp ); } /* Is there a keyboard/special callback hooked for this window? */ @@ -983,7 +953,8 @@ void fgPlatformProcessSingleEvent ( void ) fgSetWindow( window ); fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state ); keyboard_cb( asciiCode[ 0 ], - event.xkey.x, event.xkey.y + event.xkey.x, event.xkey.y, + keyboard_ud ); fgState.Modifiers = INVALID_MODIFIERS; } @@ -1051,7 +1022,7 @@ void fgPlatformProcessSingleEvent ( void ) { fgSetWindow( window ); fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state ); - special_cb( special, event.xkey.x, event.xkey.y ); + special_cb( special, event.xkey.x, event.xkey.y, special_ud ); fgState.Modifiers = INVALID_MODIFIERS; } } @@ -1077,7 +1048,64 @@ void fgPlatformProcessSingleEvent ( void ) } +static Bool match_motion(Display *dpy, XEvent *xev, XPointer arg) +{ + return xev->type == MotionNotify; +} + void fgPlatformMainLoopPreliminaryWork ( void ) { } + +/* deal with work list items */ +void fgPlatformInitWork(SFG_Window* window) +{ + /* Notify windowStatus/visibility, position and size get notified on window creation with message handlers above + * XXX CHECK: do the messages happen too early like on windows, so client code cannot have registered + * a callback yet and the message is thus never received by client? + * -> this is a no-op + */ + return; +} + +void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask) +{ + if (workMask & GLUT_FULL_SCREEN_WORK) + fgPlatformFullScreenToggle( window ); + if (workMask & GLUT_POSITION_WORK) + fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos ); + if (workMask & GLUT_SIZE_WORK) + fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight ); + if (workMask & GLUT_ZORDER_WORK) + { + if (window->State.DesiredZOrder < 0) + fgPlatformPushWindow( window ); + else + fgPlatformPopWindow( window ); + } +} + +void fgPlatformVisibilityWork(SFG_Window* window) +{ + /* Visibility status of window gets updated in the window message handlers above + * XXX: is this really the case? check + */ + SFG_Window *win = window; + switch (window->State.DesiredVisibility) + { + case DesireHiddenState: + fgPlatformHideWindow( window ); + break; + case DesireIconicState: + /* Call on top-level window */ + while (win->Parent) + win = win->Parent; + fgPlatformIconifyWindow( win ); + break; + case DesireNormalState: + fgPlatformShowWindow( window ); + break; + } +} +