Index: src/freeglut_window.c =================================================================== --- src/freeglut_window.c (Revision 832) +++ src/freeglut_window.c (Arbeitskopie) @@ -934,6 +934,9 @@ window->Window.Context ); + /* register extension events _before_ window is mapped */ + fgRegisterDevices( fgDisplay.Display, &(window->Window.Handle) ); + XMapWindow( fgDisplay.Display, window->Window.Handle ); XFree(visualInfo); Index: src/freeglut_callbacks.c =================================================================== --- src/freeglut_callbacks.c (Revision 832) +++ src/freeglut_callbacks.c (Arbeitskopie) @@ -358,4 +358,40 @@ SET_CALLBACK( TabletButton ); } +/* + * Sets the multi-pointer entry callback for the current window + */ +void FGAPIENTRY glutXExtensionEntryFunc( void (* callback)(int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutXExtensionEntryFunc" ); + SET_CALLBACK( XExtensionEntry ); +} + +/* + * Sets the multi-pointer button callback for the current window + */ +void FGAPIENTRY glutXExtensionButtonFunc( void (* callback)(int, int, int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutXExtensionButtonFunc" ); + SET_CALLBACK( XExtensionButton ); +} + +/* + * Sets the multi-pointer motion callback for the current window + */ +void FGAPIENTRY glutXExtensionMotionFunc( void (* callback)(int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutXExtensionMotionFunc" ); + SET_CALLBACK( XExtensionMotion ); +} + +/* + * Sets the multi-pointer passive motion callback for the current window + */ +void FGAPIENTRY glutXExtensionPassiveFunc( void (* callback)(int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutXExtensionPassiveFunc" ); + SET_CALLBACK( XExtensionPassive ); +} + /*** END OF FILE ***/ Index: src/freeglut_internal.h =================================================================== --- src/freeglut_internal.h (Revision 832) +++ src/freeglut_internal.h (Arbeitskopie) @@ -227,6 +227,11 @@ typedef void (* FGCBTabletButton )( int, int, int, int ); typedef void (* FGCBDestroy )( void ); +typedef void (* FGCBXExtensionEntry )( int, int ); +typedef void (* FGCBXExtensionButton )( int, int, int, int, int ); +typedef void (* FGCBXExtensionMotion )( int, int, int ); +typedef void (* FGCBXExtensionPassive )( int, int, int ); + /* The global callbacks type definitions */ typedef void (* FGCBIdle )( void ); typedef void (* FGCBTimer )( int ); @@ -561,6 +566,12 @@ CB_Joystick, CB_Destroy, + /* MPX-related */ + CB_XExtensionEntry, + CB_XExtensionButton, + CB_XExtensionMotion, + CB_XExtensionPassive, + /* Presently ignored */ CB_Select, CB_OverlayDisplay, @@ -925,11 +936,17 @@ void fgError( const char *fmt, ... ); void fgWarning( const char *fmt, ... ); +#if TARGET_HOST_POSIX_X11 + /* * Check if "hint" is present in "property" for "window". See freeglut_init.c */ -#if TARGET_HOST_POSIX_X11 int fgHintPresent(Window window, Atom property, Atom hint); + +/* Handler for X extension Events */ +void fgHandleExtensionEvents( XEvent * ev ); +void fgRegisterDevices( Display* dpy, Window* win ); + #endif SFG_Proc fghGetProcAddress( const char *procName ); Index: src/freeglut_main.c =================================================================== --- src/freeglut_main.c (Revision 832) +++ src/freeglut_main.c (Arbeitskopie) @@ -483,7 +483,7 @@ /* * Returns GLUT modifier mask for the state field of an X11 event. */ -static int fghGetXModifiers( int state ) +int fghGetXModifiers( int state ) { int ret = 0; @@ -1405,7 +1405,8 @@ break; default: - fgWarning ("Unknown X event type: %d\n", event.type); + /* enter handling of Extension Events here */ + fgHandleExtensionEvents( &event ); break; } } Index: src/freeglut_xinput.c =================================================================== --- src/freeglut_xinput.c (Revision 0) +++ src/freeglut_xinput.c (Revision 0) @@ -0,0 +1,225 @@ +/* Written for XI1 by Nikolas Doerfler (c) 2008 * + * Rewritten for XI2 by Florian Echtler (c) 2009 */ + +#include + +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 && HAVE_X11_EXTENSIONS_XINPUT2_H + +#include +#include + +#include +#include + +/* import function from freeglut_main.c */ +int fghGetXModifiers( int state ); + +/* extension opcode for XInput */ +int xi_opcode = -1; + +/** + * \brief Sets window up for XI2 events. + */ +void fgRegisterDevices( Display* dpy, Window* win ) { + + XIEventMask mask; + unsigned char flags[2] = { 0, 0 }; + int event, error; + + /*Display* dpy = fgDisplay.Display; + Window* win = glutGetXWindow();*/ + + /* get XInput extension opcode */ + if (!XQueryExtension( dpy, "XInputExtension", &xi_opcode, &event, &error )) { xi_opcode = -1; } + + /* Select for motion events */ + mask.deviceid = XIAllMasterDevices; + mask.mask_len = 2; + mask.mask = flags; + + XISetMask(mask.mask, XI_Enter); + XISetMask(mask.mask, XI_Motion); + XISetMask(mask.mask, XI_ButtonPress); + XISetMask(mask.mask, XI_ButtonRelease); + XISetMask(mask.mask, XI_Leave); + /*XISetMask(mask.mask, XI_KeyPress); + XISetMask(mask.mask, XI_KeyRelease); + XISetMask(mask.mask, XI_DeviceChanged); + XISetMask(mask.mask, XI_RawEvent); + XISetMask(mask.mask, XI_FocusIn); + XISetMask(mask.mask, XI_FocusOut); + XISetMask(mask.mask, XI_HierarchyChanged);*/ + + XISelectEvents( dpy, *win, &mask, 1 ); +} + + +void fgPrintXILeaveEvent(XILeaveEvent* event) +{ + char* mode = ""; + char* detail = ""; + int i; + + printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n", + event->root, event->event, event->child); + switch(event->mode) + { + case NotifyNormal: mode = "NotifyNormal"; break; + case NotifyGrab: mode = "NotifyGrab"; break; + case NotifyUngrab: mode = "NotifyUngrab"; break; + case NotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break; + } + switch (event->detail) + { + case NotifyAncestor: detail = "NotifyAncestor"; break; + case NotifyVirtual: detail = "NotifyVirtual"; break; + case NotifyInferior: detail = "NotifyInferior"; break; + case NotifyNonlinear: detail = "NotifyNonlinear"; break; + case NotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break; + case NotifyPointer: detail = "NotifyPointer"; break; + case NotifyPointerRoot: detail = "NotifyPointerRoot"; break; + case NotifyDetailNone: detail = "NotifyDetailNone"; break; + } + printf(" mode: %s (detail %s)\n", mode, detail); + printf(" flags: %s %s\n", event->focus ? "[focus]" : "", + event->same_screen ? "[same screen]" : ""); + printf(" buttons:"); + for (i = 0; i < event->buttons.mask_len * 8; i++) + if (XIMaskIsSet(event->buttons.mask, i)) + printf(" %d", i); + printf("\n"); + + printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n", + event->mods.locked, event->mods.latched, + event->mods.base); + printf(" group: locked 0x%x latched 0x%x base 0x%x\n", + event->group.locked, event->group.latched, + event->group.base); + + printf(" root x/y: %.2f / %.2f\n", event->root_x, event->root_y); + printf(" event x/y: %.2f / %.2f\n", event->event_x, event->event_y); + +} + + +void fgPrintXIDeviceEvent(XIDeviceEvent* event) +{ + double *val; + int i; + + printf(" device: %d (%d)\n", event->deviceid, event->sourceid); + printf(" detail: %d\n", event->detail); + printf(" buttons:"); + for (i = 0; i < event->buttons.mask_len * 8; i++) + if (XIMaskIsSet(event->buttons.mask, i)) + printf(" %d", i); + printf("\n"); + + printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n", + event->mods.locked, event->mods.latched, + event->mods.base); + printf(" group: locked 0x%x latched 0x%x base 0x%x\n", + event->group.locked, event->group.latched, + event->group.base); + printf(" valuators:"); + + val = event->valuators.values; + for (i = 0; i < event->valuators.mask_len * 8; i++) + if (XIMaskIsSet(event->valuators.mask, i)) + printf(" %d: %.2f", i, *val++); + printf("\n"); + + printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n", + event->root, event->event, event->child); + printf(" root x/y: %.2f / %.2f\n", event->root_x, event->root_y); + printf(" event x/y: %.2f / %.2f\n", event->event_x, event->event_y); + +} + + +/** + * \brief This function is called when an Extension Event is received + * and calls the corresponding callback functions for these events. + */ +void fgHandleExtensionEvents( XEvent* base_ev ) { + + int i, button = 0; + XGenericEventCookie* cookie = (XGenericEventCookie*)&(base_ev->xcookie); + + if ( XGetEventData( fgDisplay.Display, cookie ) && (cookie->type == GenericEvent) && (cookie->extension == xi_opcode) ) { + + XIDeviceEvent* event = (XIDeviceEvent*)(cookie->data); + /*printf("XI2 event type: %d - %d\n", cookie->evtype, event->type );*/ + + SFG_Window* window = fgWindowByHandle( event->event ); + if (!window) return; + + switch (cookie->evtype) { + + case XI_Enter: + case XI_Leave: + fgState.Modifiers = fghGetXModifiers( ((XIEnterEvent*)event)->mods.base ); + INVOKE_WCB( *window, XExtensionEntry, ( + event->deviceid, + (event->evtype == XI_Enter ? GLUT_ENTERED : GLUT_LEFT) + )); + #if _DEBUG + fgPrintXILeaveEvent((XILeaveEvent*)event); + #endif + break; + + case XI_ButtonPress: + case XI_ButtonRelease: + fgState.Modifiers = fghGetXModifiers( event->mods.base ); + INVOKE_WCB( *window, XExtensionButton, ( + event->deviceid, + event->event_x, + event->event_y, + (event->detail)-1, + (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP) + )); + INVOKE_WCB( *window, Mouse, ( + (event->detail)-1, + (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP), + event->event_x, + event->event_y + )); + break; + + case XI_Motion: + fgState.Modifiers = fghGetXModifiers( event->mods.base ); + for (i = 0; i < event->buttons.mask_len; i++) if (event->buttons.mask[i]) button = 1; + if (button) { + INVOKE_WCB( *window, XExtensionMotion, ( event->deviceid, event->event_x, event->event_y ) ); + INVOKE_WCB( *window, Motion, ( event->event_x, event->event_y ) ); + } else { + INVOKE_WCB( *window, XExtensionPassive, ( event->deviceid, event->event_x, event->event_y ) ); + INVOKE_WCB( *window, Passive, ( event->event_x, event->event_y ) ); + } + #if _DEBUG + fgPrintXIDeviceEvent(event); + #endif + break; + + default: + #if _DEBUG + fgWarning( "Unknown XI2 device event:" ); + fgPrintXIDeviceEvent( event ); + #endif + break; + } + fgState.Modifiers = INVALID_MODIFIERS; + } + XFreeEventData( fgDisplay.Display, cookie ); +} + +#else + +/* empty stubs for non-MPX platforms */ +void fgRegisterDevices( Display* dpy, Window* win ) { } +void fgHandleExtensionEvents( XEvent* ev ) { } + +#endif + Index: src/Makefile.am =================================================================== --- src/Makefile.am (Revision 832) +++ src/Makefile.am (Arbeitskopie) @@ -37,7 +37,8 @@ freeglut_structure.c \ freeglut_teapot.c \ freeglut_videoresize.c \ - freeglut_window.c + freeglut_window.c \ + freeglut_xinput.c # # Additional linker flags Index: src/freeglut_ext.c =================================================================== --- src/freeglut_ext.c (Revision 832) +++ src/freeglut_ext.c (Arbeitskopie) @@ -85,6 +85,10 @@ CHECK_NAME(glutReshapeFunc); CHECK_NAME(glutKeyboardFunc); CHECK_NAME(glutMouseFunc); + CHECK_NAME(glutXExtensionEntryFunc); + CHECK_NAME(glutXExtensionMotionFunc); + CHECK_NAME(glutXExtensionButtonFunc); + CHECK_NAME(glutXExtensionPassiveFunc); CHECK_NAME(glutMotionFunc); CHECK_NAME(glutPassiveMotionFunc); CHECK_NAME(glutEntryFunc); Index: configure.ac =================================================================== --- configure.ac (Revision 832) +++ configure.ac (Arbeitskopie) @@ -50,6 +50,7 @@ AC_HEADER_TIME AC_CHECK_HEADERS([X11/extensions/xf86vmode.h], [], [], [#include ]) AC_CHECK_HEADERS([X11/extensions/XI.h X11/extensions/XInput.h]) +AC_CHECK_HEADERS([X11/extensions/XInput2.h]) CPPFLAGS="$save_CPPFLAGS" # Checks for library functions. Index: include/GL/freeglut_ext.h =================================================================== --- include/GL/freeglut_ext.h (Revision 832) +++ include/GL/freeglut_ext.h (Arbeitskopie) @@ -167,6 +167,17 @@ FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName ); /* + * MPX extensions, see freeglut_xinput.c + */ + +#define GLUT_HAS_MPX 1 + +FGAPI void FGAPIENTRY glutXExtensionEntryFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutXExtensionButtonFunc( void (* callback)( int, int, int, int, int ) ); +FGAPI void FGAPIENTRY glutXExtensionMotionFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutXExtensionPassiveFunc( void (* callback)( int, int, int ) ); + +/* * Joystick functions, see freeglut_joystick.c */ /* USE OF THESE FUNCTIONS IS DEPRECATED !!!!! */