/*
- * freeglut_main_x11.c
+ * fg_main_x11.c
*
* The X11-specific windows message processing methods.
*
#include <GL/freeglut.h>
#include "../fg_internal.h"
-#ifdef HAVE_ERRNO_H
-# include <errno.h>
-#endif
+#include <errno.h>
#include <stdarg.h>
-#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
/*
# 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)...
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
}
}
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;
- INVOKE_WCB( *window, Reshape, ( 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;
if( event.xexpose.count == 0 )
{
GETWINDOW( xexpose );
- window->State.Redisplay = GL_TRUE;
+ window->State.WorkMask |= GLUT_DISPLAY_WORK;
}
break;
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,
*/
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, event.xbutton.y ) )
+ 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;
}
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 );
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? */
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;
}
{
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;
}
}
{
}
+
+/* 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;
+ }
+}
+