GLFW 0.5.1.0 → 0.5.2.0
raw patch · 16 files changed
+969/−202 lines, 16 filessetup-changed
Files
- Changelog.txt +9/−0
- GLFW.cabal +7/−3
- README.txt +7/−7
- Setup.hs +9/−10
- glfw/include/GL/glfw.h +1/−1
- glfw/lib/cocoa/cocoa_init.m +8/−1
- glfw/lib/cocoa/cocoa_joystick.m +587/−6
- glfw/lib/cocoa/cocoa_window.m +39/−23
- glfw/lib/cocoa/platform.h +3/−0
- glfw/lib/enable.c +20/−18
- glfw/lib/win32/platform.h +2/−3
- glfw/lib/win32/win32_init.c +1/−1
- glfw/lib/win32/win32_window.c +125/−96
- glfw/lib/x11/platform.h +23/−2
- glfw/lib/x11/x11_init.c +5/−3
- glfw/lib/x11/x11_window.c +123/−28
Changelog.txt view
@@ -1,3 +1,12 @@+Thu Oct 3 23:59:17 PDT 2013 paul@thev.net+ * Bump version to 0.5.2.0++Thu Oct 3 23:26:34 PDT 2013 paul@thev.net+ * Upgrade to glfw C version 2.7.9++Thu Oct 3 23:25:39 PDT 2013 paul@thev.net+ * Compatibility fix to work with Cabal 1.18+ Sat Nov 3 21:41:09 PDT 2012 paul@thev.net * Bump version to 0.5.1.0 for release
GLFW.cabal view
@@ -1,15 +1,19 @@ name: GLFW-version: 0.5.1.0+version: 0.5.2.0 homepage: http://haskell.org/haskellwiki/GLFW maintainer: Paul H. Liu <paul@thev.net>, Marc Sunet <jeannekamikaze@gmail.com>-cabal-version: >= 1.10+cabal-version: >= 1.12 build-type: Custom category: Graphics synopsis: A Haskell binding for GLFW description: A Haskell binding for GLFW, a window system independent toolkit for writing OpenGL programs. For more information about the C library on which this binding is based, please see- <http://www.glfw.org>.+ <http://www.glfw.org>. Note that this binding comes with an + older GLFW C version 2.7.9 due to incompatible API changes + GLFW since 3.0 (for example, the removal of texture functions).+ If you want to use newer GLFW C versions, install Haskell package+ GLFW-b instead. license: BSD3 license-file: LICENSE
README.txt view
@@ -19,7 +19,7 @@ ============ The package comes together with a (partial) source distribution -of GLFW v2.7.2, which is compiled and installed together with +of GLFW v2.7.9, which is compiled and installed together with the Haskell package. If you already have the Haskell package cabal-install, you can @@ -62,7 +62,7 @@ ==== For Windows users, you may have to include GHC's gcc-lib directory -in your PATH environment, e.g., c:\ghc\ghc-6.8.3\gcc-lib, before +in your PATH environment, e.g., c:\ghc\ghc-7.6.3\gcc-lib, before configuring the GLFW module, otherwise it'll complain about missing program for ld. @@ -72,15 +72,15 @@ command. For Mac users, unfortunately interactively running GLFW programs -from GHCi would result in a crash. The only sensible way is to -compile and run the program. On the other hand, it no longer -requires the enableGUI trick. +from GHCi would result in a crash if you use GHC 7.6.3 or older. +The only sensible way is to compile and run the program, or use +GHC 7.8 or newer. ============= Package Usage ============= -The package is tested with GHC 6.10.2 and GHC 7.0.2 on all +The package is tested with GHC 7.4.2 and GHC 7.6.3 on all three platforms (Linux, Win32/MinGW, and Mac OS X). Though it may work with older versions of GHC or even Hugs, they are not tested. @@ -127,4 +127,4 @@ http://projects.haskell.org/cgi-bin/mailman/listinfo/glfw -- -Last Updated: Fri Jan 20 PST 2012 +Last Updated: Thu Oct 3 PST 2013
Setup.hs view
@@ -7,6 +7,7 @@ import Distribution.Simple.Utils (rawSystemStdInOut, withTempFile) import Distribution.Simple.LocalBuildInfo import Distribution.Simple.Program+import Distribution.Simple.Program.Types import Distribution.Verbosity import Distribution.PackageDescription import Distribution.System@@ -14,9 +15,9 @@ import System.FilePath import System.Directory import System.IO (hClose, hPutStr)-import System.Cmd (rawSystem)+import System.IO.Error (catchIOError) import Data.Maybe (fromJust)-import Foreign (bitSize)+import Foreign (sizeOf) import Control.Monad (when) --import Control.Monad.State --import Control.Monad.Trans.Class (lift)@@ -51,14 +52,12 @@ Just cpp_name -> do let cpp_name = fromJust (lookup "x-cc-name" custom_bi) c_srcs = cSources lib_bi- mbits = bitSize (undefined :: Int)+ mbits = 8 * sizeOf (undefined :: Int) cc_opts = ("-m" ++ show mbits) : "-S" : ccOptions lib_bi inc_dirs = includeDirs lib_bi lib_dirs = extraLibDirs lib_bi bld_dir = buildDir local_bld_info- prog = ConfiguredProgram { programId = cpp_name, programVersion = Nothing,- programDefaultArgs = [], programOverrideArgs = [],- programLocation = FoundOnSystem { locationPath = cpp_name } }+ prog = simpleConfiguredProgram cpp_name (FoundOnSystem { locationPath = cpp_name }) -- Compile C/C++ sources putStrLn $ "invoking my compile phase " ++ cpp_name objs <- mapM (compileCxx prog cc_opts inc_dirs bld_dir) c_srcs@@ -164,8 +163,9 @@ hClose outHandle hPutStr inHandle contents hClose inHandle- (out, err, exitCode) <- rawSystemStdInOut verbosity "cc" (["-c", path, "-o", objPath] ++ flags) Nothing False- return (exitCode == ExitSuccess) + let cc = simpleProgramInvocation "cc" (["-c", path, "-o", objPath] ++ flags)+ -- (out, err, exitCode) <- rawSystemStdInOut verbosity "cc" Nothing Nothing Nothing False+ catchIOError (getProgramInvocationOutput verbosity cc >> return True) (\_ -> return False) progXrandr = unlines ["#include <X11/Xlib.h>"@@ -250,6 +250,5 @@ a <- m return (a, s) instance (Monad m) => MonadState s (StateT s m) where- get = StateT $ \s -> return (s, s) + get = StateT $ \s -> return (s, s) put s = StateT $ \_ -> return ((), s)-
glfw/include/GL/glfw.h view
@@ -187,7 +187,7 @@ #define GLFW_VERSION_MAJOR 2 #define GLFW_VERSION_MINOR 7-#define GLFW_VERSION_REVISION 5+#define GLFW_VERSION_REVISION 9 /*************************************************************************
glfw/lib/cocoa/cocoa_init.m view
@@ -146,6 +146,8 @@ _glfwInitTimer(); + _glfwInitJoysticks();+ _glfwLibrary.eventSource = CGEventSourceCreate( kCGEventSourceStateHIDSystemState ); if( !_glfwLibrary.eventSource ) {@@ -167,7 +169,10 @@ int _glfwPlatformTerminate( void ) {- // TODO: Fail unless this is the main thread+ if( pthread_self() != _glfwThrd.First.PosixID )+ {+ return GL_FALSE;+ } glfwCloseWindow(); @@ -179,6 +184,8 @@ CFRelease( _glfwLibrary.eventSource ); _glfwLibrary.eventSource = NULL; }++ _glfwTerminateJoysticks(); [_glfwLibrary.autoreleasePool release]; _glfwLibrary.autoreleasePool = nil;
glfw/lib/cocoa/cocoa_joystick.m view
@@ -29,7 +29,481 @@ #include "internal.h" +#include <unistd.h>+#include <ctype.h>++#include <mach/mach.h>+#include <mach/mach_error.h>++#include <CoreFoundation/CoreFoundation.h>+#include <IOKit/IOKitLib.h>+#include <IOKit/IOCFPlugIn.h>+#include <IOKit/hid/IOHIDLib.h>+#include <IOKit/hid/IOHIDKeys.h>+#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>+++//------------------------------------------------------------------------+// Joystick state+//------------------------------------------------------------------------++typedef struct+{+ int present;+ char product[256];++ IOHIDDeviceInterface** interface;++ int numAxes;+ int numButtons;+ int numHats;++ CFMutableArrayRef axes;+ CFMutableArrayRef buttons;+ CFMutableArrayRef hats;++} _glfwJoystick;++static _glfwJoystick _glfwJoysticks[GLFW_JOYSTICK_LAST + 1];+++typedef struct+{+ IOHIDElementCookie cookie;++ long value;++ long min;+ long max;++ long minReport;+ long maxReport;++} _glfwJoystickElement;+++void GetElementsCFArrayHandler( const void* value, void* parameter );+++//========================================================================+// Adds an element to the specified joystick+//========================================================================++static void addJoystickElement( _glfwJoystick* joystick, CFTypeRef refElement )+{+ long elementType, usagePage, usage;+ CFTypeRef refElementType, refUsagePage, refUsage;++ refElementType = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementTypeKey ) );+ refUsagePage = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementUsagePageKey ) );+ refUsage = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementUsageKey ) );++ CFMutableArrayRef elementsArray = NULL;++ CFNumberGetValue( refElementType, kCFNumberLongType, &elementType );+ CFNumberGetValue( refUsagePage, kCFNumberLongType, &usagePage );+ CFNumberGetValue( refUsage, kCFNumberLongType, &usage );++ if( elementType == kIOHIDElementTypeInput_Axis ||+ elementType == kIOHIDElementTypeInput_Button ||+ elementType == kIOHIDElementTypeInput_Misc )+ {+ switch( usagePage ) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */+ {+ case kHIDPage_GenericDesktop:+ {+ switch( usage )+ {+ case kHIDUsage_GD_X:+ case kHIDUsage_GD_Y:+ case kHIDUsage_GD_Z:+ case kHIDUsage_GD_Rx:+ case kHIDUsage_GD_Ry:+ case kHIDUsage_GD_Rz:+ case kHIDUsage_GD_Slider:+ case kHIDUsage_GD_Dial:+ case kHIDUsage_GD_Wheel:+ joystick->numAxes++;+ elementsArray = joystick->axes;+ break;+ case kHIDUsage_GD_Hatswitch:+ joystick->numHats++;+ elementsArray = joystick->hats;+ break;+ }++ break;+ }++ case kHIDPage_Button:+ joystick->numButtons++;+ elementsArray = joystick->buttons;+ break;+ default:+ break;+ }++ if( elementsArray )+ {+ long number;+ CFTypeRef refType;++ _glfwJoystickElement* element = (_glfwJoystickElement*) malloc( sizeof( _glfwJoystickElement ) );++ CFArrayAppendValue( elementsArray, element );++ refType = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementCookieKey ) );+ if( refType && CFNumberGetValue( refType, kCFNumberLongType, &number ) )+ {+ element->cookie = (IOHIDElementCookie) number;+ }++ refType = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementMinKey ) );+ if( refType && CFNumberGetValue( refType, kCFNumberLongType, &number ) )+ {+ element->minReport = element->min = number;+ }++ refType = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementMaxKey ) );+ if( refType && CFNumberGetValue( refType, kCFNumberLongType, &number ) )+ {+ element->maxReport = element->max = number;+ }+ }+ }+ else+ {+ CFTypeRef refElementTop = CFDictionaryGetValue( refElement, CFSTR( kIOHIDElementKey ) );+ if( refElementTop )+ {+ CFTypeID type = CFGetTypeID( refElementTop );+ if( type == CFArrayGetTypeID() ) /* if element is an array */+ {+ CFRange range = { 0, CFArrayGetCount( refElementTop ) };+ CFArrayApplyFunction( refElementTop, range, GetElementsCFArrayHandler, joystick );+ }+ }+ }+}+++//========================================================================+// Adds an element to the specified joystick+//========================================================================++void GetElementsCFArrayHandler( const void* value, void* parameter )+{+ if( CFGetTypeID( value ) == CFDictionaryGetTypeID() )+ {+ addJoystickElement( (_glfwJoystick*) parameter, (CFTypeRef) value );+ }+}+++//========================================================================+// Returns the value of the specified element of the specified joystick+//========================================================================++static long getElementValue( _glfwJoystick* joystick, _glfwJoystickElement* element )+{+ IOReturn result = kIOReturnSuccess;+ IOHIDEventStruct hidEvent;+ hidEvent.value = 0;++ if( joystick && element && joystick->interface )+ {+ result = (*(joystick->interface))->getElementValue( joystick->interface,+ element->cookie,+ &hidEvent );+ if( kIOReturnSuccess == result )+ {+ /* record min and max for auto calibration */+ if( hidEvent.value < element->minReport )+ {+ element->minReport = hidEvent.value;+ }+ if( hidEvent.value > element->maxReport )+ {+ element->maxReport = hidEvent.value;+ }+ }+ }++ /* auto user scale */+ return (long) hidEvent.value;+}+++//========================================================================+// Removes the specified joystick+//========================================================================++static void removeJoystick( _glfwJoystick* joystick )+{+ int i;++ if( joystick->present )+ {+ joystick->present = GL_FALSE;++ for( i = 0; i < joystick->numAxes; i++ )+ {+ _glfwJoystickElement* axes =+ (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->axes, i );+ free( axes );+ }+ CFArrayRemoveAllValues( joystick->axes );+ joystick->numAxes = 0;++ for( i = 0; i < joystick->numButtons; i++ )+ {+ _glfwJoystickElement* button =+ (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->buttons, i );+ free( button );+ }+ CFArrayRemoveAllValues( joystick->buttons );+ joystick->numButtons = 0;++ for( i = 0; i < joystick->numHats; i++ )+ {+ _glfwJoystickElement* hat =+ (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->hats, i );+ free( hat );+ }+ CFArrayRemoveAllValues( joystick->hats );+ joystick->hats = 0;++ (*(joystick->interface))->close( joystick->interface );+ (*(joystick->interface))->Release( joystick->interface );++ joystick->interface = NULL;+ }+}+++//========================================================================+// Callback for user-initiated joystick removal+//========================================================================++static void removalCallback( void* target, IOReturn result, void* refcon, void* sender )+{+ removeJoystick( (_glfwJoystick*) refcon );+}+++//========================================================================+// Polls for joystick events and updates GFLW state+//========================================================================++static void pollJoystickEvents( void )+{+ int i;+ CFIndex j;++ for( i = 0; i < GLFW_JOYSTICK_LAST + 1; i++ )+ {+ _glfwJoystick* joystick = &_glfwJoysticks[i];++ if( joystick->present )+ {+ for( j = 0; j < joystick->numButtons; j++ )+ {+ _glfwJoystickElement* button =+ (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->buttons, j );+ button->value = getElementValue( joystick, button );+ }++ for( j = 0; j < joystick->numAxes; j++ )+ {+ _glfwJoystickElement* axes =+ (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->axes, j );+ axes->value = getElementValue( joystick, axes );+ }++ for( j = 0; j < joystick->numHats; j++ )+ {+ _glfwJoystickElement* hat =+ (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick->hats, j );+ hat->value = getElementValue( joystick, hat );+ }+ }+ }+}++ //************************************************************************+//**** GLFW internal functions ****+//************************************************************************++//========================================================================+// Initialize joystick interface+//========================================================================++void _glfwInitJoysticks( void )+{+ int deviceCounter = 0;+ IOReturn result = kIOReturnSuccess;+ mach_port_t masterPort = 0;+ io_iterator_t objectIterator = 0;+ CFMutableDictionaryRef hidMatchDictionary = NULL;+ io_object_t ioHIDDeviceObject = 0;++ result = IOMasterPort( bootstrap_port, &masterPort );+ hidMatchDictionary = IOServiceMatching( kIOHIDDeviceKey );+ if( kIOReturnSuccess != result || !hidMatchDictionary )+ {+ if( hidMatchDictionary )+ {+ CFRelease( hidMatchDictionary );+ }++ return;+ }++ result = IOServiceGetMatchingServices( masterPort,+ hidMatchDictionary,+ &objectIterator );+ if( result != kIOReturnSuccess )+ {+ return;+ }++ if( !objectIterator ) /* there are no joysticks */+ {+ return;+ }++ while( ( ioHIDDeviceObject = IOIteratorNext( objectIterator ) ) )+ {+ CFMutableDictionaryRef hidProperties = 0;+ kern_return_t result;+ CFTypeRef refCF = 0;++ IOCFPlugInInterface** ppPlugInInterface = NULL;+ HRESULT plugInResult = S_OK;+ SInt32 score = 0;++ long usagePage, usage;++ result = IORegistryEntryCreateCFProperties( ioHIDDeviceObject,+ &hidProperties,+ kCFAllocatorDefault,+ kNilOptions );++ if( result != kIOReturnSuccess )+ {+ continue;+ }++ /* Check device type */+ refCF = CFDictionaryGetValue( hidProperties, CFSTR( kIOHIDPrimaryUsagePageKey ) );+ if( refCF )+ {+ CFNumberGetValue( refCF, kCFNumberLongType, &usagePage );+ if( usagePage != kHIDPage_GenericDesktop )+ {+ /* We are not interested in this device */+ continue;+ }+ }++ refCF = CFDictionaryGetValue( hidProperties, CFSTR( kIOHIDPrimaryUsageKey ) );+ if( refCF )+ {+ CFNumberGetValue( refCF, kCFNumberLongType, &usage );++ if( usage != kHIDUsage_GD_Joystick &&+ usage != kHIDUsage_GD_GamePad &&+ usage != kHIDUsage_GD_MultiAxisController )+ {+ /* We are not interested in this device */+ continue;+ }+ }++ _glfwJoystick* joystick = &_glfwJoysticks[deviceCounter];++ joystick->present = GL_TRUE;++ result = IOCreatePlugInInterfaceForService( ioHIDDeviceObject,+ kIOHIDDeviceUserClientTypeID,+ kIOCFPlugInInterfaceID,+ &ppPlugInInterface,+ &score );++ if( kIOReturnSuccess != result )+ {+ return;+ }++ plugInResult = (*ppPlugInInterface)->QueryInterface( ppPlugInInterface,+ CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ),+ (void *) &(joystick->interface) );++ if( plugInResult != S_OK )+ {+ return;+ }++ (*ppPlugInInterface)->Release( ppPlugInInterface );++ (*(joystick->interface))->open( joystick->interface, 0 );+ (*(joystick->interface))->setRemovalCallback( joystick->interface,+ removalCallback,+ joystick,+ joystick );++ /* Get product string */+ refCF = CFDictionaryGetValue( hidProperties, CFSTR( kIOHIDProductKey ) );+ if( refCF )+ {+ CFStringGetCString( refCF,+ (char*) &(joystick->product),+ 256,+ CFStringGetSystemEncoding() );+ }++ joystick->numAxes = 0;+ joystick->numButtons = 0;+ joystick->numHats = 0;+ joystick->axes = CFArrayCreateMutable( NULL, 0, NULL );+ joystick->buttons = CFArrayCreateMutable( NULL, 0, NULL );+ joystick->hats = CFArrayCreateMutable( NULL, 0, NULL );++ CFTypeRef refTopElement = CFDictionaryGetValue( hidProperties,+ CFSTR( kIOHIDElementKey ) );+ CFTypeID type = CFGetTypeID( refTopElement );+ if( type == CFArrayGetTypeID() )+ {+ CFRange range = { 0, CFArrayGetCount( refTopElement ) };+ CFArrayApplyFunction( refTopElement,+ range,+ GetElementsCFArrayHandler,+ (void*) joystick);+ }++ deviceCounter++;+ }+}+++//========================================================================+// Close all opened joystick handles+//========================================================================++void _glfwTerminateJoysticks( void )+{+ int i;++ for( i = 0; i < GLFW_JOYSTICK_LAST + 1; i++ )+ {+ _glfwJoystick* joystick = &_glfwJoysticks[i];+ removeJoystick( joystick );+ }+}+++//************************************************************************ //**** Platform implementation functions **** //************************************************************************ @@ -39,8 +513,29 @@ int _glfwPlatformGetJoystickParam( int joy, int param ) {- // TODO: Implement this.- return 0;+ if( !_glfwJoysticks[joy].present )+ {+ // TODO: Figure out if this is an error+ return GL_FALSE;+ }++ switch( param )+ {+ case GLFW_PRESENT:+ return GL_TRUE;++ case GLFW_AXES:+ return (int) CFArrayGetCount( _glfwJoysticks[joy].axes );++ case GLFW_BUTTONS:+ return (int) CFArrayGetCount( _glfwJoysticks[joy].buttons ) ++ ((int) CFArrayGetCount( _glfwJoysticks[joy].hats )) * 4;++ default:+ break;+ }++ return GL_FALSE; } @@ -50,8 +545,51 @@ int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) {- // TODO: Implement this.- return 0;+ int i;++ if( joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST )+ {+ return 0;+ }++ _glfwJoystick joystick = _glfwJoysticks[joy];++ if( !joystick.present )+ {+ // TODO: Figure out if this is an error+ return 0;+ }++ numaxes = numaxes < joystick.numAxes ? numaxes : joystick.numAxes;++ // Update joystick state+ pollJoystickEvents();++ for( i = 0; i < numaxes; i++ )+ {+ _glfwJoystickElement* axes =+ (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick.axes, i );++ long readScale = axes->maxReport - axes->minReport;++ if( readScale == 0 )+ {+ pos[i] = axes->value;+ }+ else+ {+ pos[i] = (2.0f * (axes->value - axes->minReport) / readScale) - 1.0f;+ }++ //printf("%ld, %ld, %ld\n", axes->value, axes->minReport, axes->maxReport);++ if( i & 1 )+ {+ pos[i] = -pos[i];+ }+ }++ return numaxes; } @@ -61,7 +599,50 @@ int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ) {- // TODO: Implement this.- return 0;+ int i, j, button;++ if( joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST )+ {+ return 0;+ }++ _glfwJoystick joystick = _glfwJoysticks[joy];++ if( !joystick.present )+ {+ // TODO: Figure out if this is an error+ return 0;+ }++ // Update joystick state+ pollJoystickEvents();++ for( button = 0; button < numbuttons && button < joystick.numButtons; button++ )+ {+ _glfwJoystickElement* element = (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick.buttons, button );+ buttons[button] = element->value ? GLFW_PRESS : GLFW_RELEASE;+ }++ // Virtual buttons - Inject data from hats+ // Each hat is exposed as 4 buttons which exposes 8 directions with concurrent button presses++ const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; // Bit fields of button presses for each direction, including nil++ for( i = 0; i < joystick.numHats; i++ )+ {+ _glfwJoystickElement* hat = (_glfwJoystickElement*) CFArrayGetValueAtIndex( joystick.hats, i );+ int value = hat->value;+ if( value < 0 || value > 8 )+ {+ value = 8;+ }++ for( j = 0; j < 4 && button < numbuttons; j++ )+ {+ buttons[button++] = directions[value] & (1 << j) ? GLFW_PRESS : GLFW_RELEASE;+ }+ }++ return button; }
glfw/lib/cocoa/cocoa_window.m view
@@ -253,6 +253,18 @@ } } +- (void)windowDidMove:(NSNotification *)notification+{+ NSPoint point = [_glfwWin.window mouseLocationOutsideOfEventStream];+ _glfwInput.MousePosX = lround(floor(point.x));+ _glfwInput.MousePosY = _glfwWin.height - lround(ceil(point.y));++ if( _glfwWin.mousePosCallback )+ {+ _glfwWin.mousePosCallback( _glfwInput.MousePosX, _glfwInput.MousePosY );+ }+}+ - (void)windowDidMiniaturize:(NSNotification *)notification { _glfwWin.iconified = GL_TRUE;@@ -494,7 +506,7 @@ // Cocoa coordinate system has origin at lower left _glfwInput.MousePosX = p.x;- _glfwInput.MousePosY = [[_glfwWin.window contentView] bounds].size.height - p.y;+ _glfwInput.MousePosY = _glfwWin.height - p.y; } if( _glfwWin.mousePosCallback )@@ -733,6 +745,11 @@ [_glfwWin.window setAcceptsMouseMovedEvents:YES]; [_glfwWin.window center]; + if( [_glfwWin.window respondsToSelector:@selector(setRestorable:)] )+ {+ [_glfwWin.window setRestorable:NO];+ }+ if( wndconfig->mode == GLFW_FULLSCREEN ) { _glfwLibrary.originalMode = (NSDictionary*)@@ -752,7 +769,10 @@ if( wndconfig->mode == GLFW_FULLSCREEN ) {+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070 ADD_ATTR( NSOpenGLPFAFullScreen );+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/+ ADD_ATTR( NSOpenGLPFANoRecovery ); ADD_ATTR2( NSOpenGLPFAScreenMask, CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() ) );@@ -833,9 +853,9 @@ [_glfwWin.context makeCurrentContext]; - NSPoint point = [[NSCursor currentCursor] hotSpot];+ NSPoint point = [_glfwWin.window mouseLocationOutsideOfEventStream]; _glfwInput.MousePosX = point.x;- _glfwInput.MousePosY = point.y;+ _glfwInput.MousePosY = _glfwWin.height - point.y; return GL_TRUE; }@@ -1022,8 +1042,6 @@ forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; _glfwWin.samples = value;-- _glfwWin.glDebug = GL_FALSE; } @@ -1101,23 +1119,21 @@ void _glfwPlatformSetMouseCursorPos( int x, int y ) {- // The library seems to assume that after calling this the mouse won't move,- // but obviously it will, and escape the app's window, and activate other apps,- // and other badness in pain. I think the API's just silly, but maybe I'm- // misunderstanding it...-- // Also, (x, y) are window coords...-- // Also, it doesn't seem possible to write this robustly without- // calculating the maximum y coordinate of all screens, since Cocoa's- // "global coordinates" are upside down from CG's...-- NSPoint localPoint = NSMakePoint( x, y );- NSPoint globalPoint = [_glfwWin.window convertBaseToScreen:localPoint];- CGPoint mainScreenOrigin = CGDisplayBounds( CGMainDisplayID() ).origin;- double mainScreenHeight = CGDisplayBounds( CGMainDisplayID() ).size.height;- CGPoint targetPoint = CGPointMake( globalPoint.x - mainScreenOrigin.x,- mainScreenHeight - globalPoint.y - mainScreenOrigin.y );- CGDisplayMoveCursorToPoint( CGMainDisplayID(), targetPoint );+ if( _glfwWin.fullscreen )+ {+ CGPoint globalPoint = CGPointMake( x, y );+ CGDisplayMoveCursorToPoint( CGMainDisplayID(), globalPoint );+ }+ else+ {+ NSPoint localPoint = NSMakePoint( x, _glfwWin.height - y - 1 );+ NSPoint globalPoint = [_glfwWin.window convertBaseToScreen:localPoint];+ CGPoint mainScreenOrigin = CGDisplayBounds( CGMainDisplayID() ).origin;+ double mainScreenHeight = CGDisplayBounds( CGMainDisplayID() ).size.height;+ CGPoint targetPoint = CGPointMake( globalPoint.x - mainScreenOrigin.x,+ mainScreenHeight - globalPoint.y -+ mainScreenOrigin.y );+ CGDisplayMoveCursorToPoint( CGMainDisplayID(), targetPoint );+ } }
glfw/lib/cocoa/platform.h view
@@ -261,5 +261,8 @@ // Time void _glfwInitTimer( void ); +// Joystick+void _glfwInitJoysticks( void );+void _glfwTerminateJoysticks( void ); #endif // _platform_h_
glfw/lib/enable.c view
@@ -48,23 +48,26 @@ return; } - // Show mouse cursor- _glfwPlatformShowMouseCursor();-- centerPosX = _glfwWin.width / 2;- centerPosY = _glfwWin.height / 2;-- if( centerPosX != _glfwInput.MousePosX || centerPosY != _glfwInput.MousePosY )+ if( _glfwWin.active ) {- _glfwPlatformSetMouseCursorPos( centerPosX, centerPosY );+ // Show mouse cursor+ _glfwPlatformShowMouseCursor(); - _glfwInput.MousePosX = centerPosX;- _glfwInput.MousePosY = centerPosY;+ centerPosX = _glfwWin.width / 2;+ centerPosY = _glfwWin.height / 2; - if( _glfwWin.mousePosCallback )+ if( centerPosX != _glfwInput.MousePosX || centerPosY != _glfwInput.MousePosY ) {- _glfwWin.mousePosCallback( _glfwInput.MousePosX,- _glfwInput.MousePosY );+ _glfwPlatformSetMouseCursorPos( centerPosX, centerPosY );++ _glfwInput.MousePosX = centerPosX;+ _glfwInput.MousePosY = centerPosY;++ if( _glfwWin.mousePosCallback )+ {+ _glfwWin.mousePosCallback( _glfwInput.MousePosX,+ _glfwInput.MousePosY );+ } } } @@ -84,11 +87,10 @@ } // Hide mouse cursor- _glfwPlatformHideMouseCursor();-- // Move cursor to the middle of the window- _glfwPlatformSetMouseCursorPos( _glfwWin.width >> 1,- _glfwWin.height >> 1 );+ if( _glfwWin.active )+ {+ _glfwPlatformHideMouseCursor();+ } // From now on the mouse is locked _glfwWin.mouseLock = GL_TRUE;
glfw/lib/win32/platform.h view
@@ -369,9 +369,8 @@ GLboolean has_WGL_ARB_create_context_profile; // Various platform specific internal variables- int oldMouseLock; // Old mouse-lock flag (used for remembering- // mouse-lock state when iconifying)- int oldMouseLockValid;+ int mouseLockActive; // Whether the mouse cursor enable is applied+ // to the actual system cursor int desiredRefreshRate; // Desired vertical monitor refresh rate };
glfw/lib/win32/win32_init.c view
@@ -350,7 +350,7 @@ // Restore FOREGROUNDLOCKTIMEOUT system setting SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0,- (LPVOID) _glfwLibrary.Sys.foregroundLockTimeout,+ (LPVOID) (INT_PTR) _glfwLibrary.Sys.foregroundLockTimeout, SPIF_SENDCHANGE ); return GL_TRUE;
glfw/lib/win32/win32_window.c view
@@ -42,6 +42,20 @@ //========================================================================+// Updates the cursor clip rect+//========================================================================++static void updateClipRect( void )+{+ RECT clipRect;+ GetClientRect( _glfwWin.window, &clipRect );+ ClientToScreen( _glfwWin.window, (POINT*) &clipRect.left );+ ClientToScreen( _glfwWin.window, (POINT*) &clipRect.right );+ ClipCursor( &clipRect );+}+++//======================================================================== // Enable/disable minimize/restore animations //======================================================================== @@ -154,7 +168,7 @@ static _GLFWfbconfig *getFBConfigs( unsigned int *found ) {- _GLFWfbconfig *result;+ _GLFWfbconfig *fbconfigs; PIXELFORMATDESCRIPTOR pfd; int i, count; @@ -175,8 +189,8 @@ return NULL; } - result = (_GLFWfbconfig*) malloc( sizeof( _GLFWfbconfig ) * count );- if( !result )+ fbconfigs = (_GLFWfbconfig*) malloc( sizeof( _GLFWfbconfig ) * count );+ if( !fbconfigs ) { fprintf(stderr, "Out of memory"); return NULL;@@ -184,6 +198,8 @@ for( i = 1; i <= count; i++ ) {+ _GLFWfbconfig *fbconfig = fbconfigs + *found;+ if( _glfwWin.has_WGL_ARB_pixel_format ) { // Get pixel format attributes through WGL_ARB_pixel_format@@ -209,29 +225,29 @@ continue; } - result[*found].redBits = getPixelFormatAttrib( i, WGL_RED_BITS_ARB );- result[*found].greenBits = getPixelFormatAttrib( i, WGL_GREEN_BITS_ARB );- result[*found].blueBits = getPixelFormatAttrib( i, WGL_BLUE_BITS_ARB );- result[*found].alphaBits = getPixelFormatAttrib( i, WGL_ALPHA_BITS_ARB );+ fbconfig->redBits = getPixelFormatAttrib( i, WGL_RED_BITS_ARB );+ fbconfig->greenBits = getPixelFormatAttrib( i, WGL_GREEN_BITS_ARB );+ fbconfig->blueBits = getPixelFormatAttrib( i, WGL_BLUE_BITS_ARB );+ fbconfig->alphaBits = getPixelFormatAttrib( i, WGL_ALPHA_BITS_ARB ); - result[*found].depthBits = getPixelFormatAttrib( i, WGL_DEPTH_BITS_ARB );- result[*found].stencilBits = getPixelFormatAttrib( i, WGL_STENCIL_BITS_ARB );+ fbconfig->depthBits = getPixelFormatAttrib( i, WGL_DEPTH_BITS_ARB );+ fbconfig->stencilBits = getPixelFormatAttrib( i, WGL_STENCIL_BITS_ARB ); - result[*found].accumRedBits = getPixelFormatAttrib( i, WGL_ACCUM_RED_BITS_ARB );- result[*found].accumGreenBits = getPixelFormatAttrib( i, WGL_ACCUM_GREEN_BITS_ARB );- result[*found].accumBlueBits = getPixelFormatAttrib( i, WGL_ACCUM_BLUE_BITS_ARB );- result[*found].accumAlphaBits = getPixelFormatAttrib( i, WGL_ACCUM_ALPHA_BITS_ARB );+ fbconfig->accumRedBits = getPixelFormatAttrib( i, WGL_ACCUM_RED_BITS_ARB );+ fbconfig->accumGreenBits = getPixelFormatAttrib( i, WGL_ACCUM_GREEN_BITS_ARB );+ fbconfig->accumBlueBits = getPixelFormatAttrib( i, WGL_ACCUM_BLUE_BITS_ARB );+ fbconfig->accumAlphaBits = getPixelFormatAttrib( i, WGL_ACCUM_ALPHA_BITS_ARB ); - result[*found].auxBuffers = getPixelFormatAttrib( i, WGL_AUX_BUFFERS_ARB );- result[*found].stereo = getPixelFormatAttrib( i, WGL_STEREO_ARB );+ fbconfig->auxBuffers = getPixelFormatAttrib( i, WGL_AUX_BUFFERS_ARB );+ fbconfig->stereo = getPixelFormatAttrib( i, WGL_STEREO_ARB ); if( _glfwWin.has_WGL_ARB_multisample ) {- result[*found].samples = getPixelFormatAttrib( i, WGL_SAMPLES_ARB );+ fbconfig->samples = getPixelFormatAttrib( i, WGL_SAMPLES_ARB ); } else {- result[*found].samples = 0;+ fbconfig->samples = 0; } } else@@ -254,6 +270,8 @@ if( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) && ( pfd.dwFlags & PFD_GENERIC_FORMAT ) ) {+ // If this is true, this pixel format is only supported by the+ // generic software implementation continue; } @@ -263,32 +281,38 @@ continue; } - result[*found].redBits = pfd.cRedBits;- result[*found].greenBits = pfd.cGreenBits;- result[*found].blueBits = pfd.cBlueBits;- result[*found].alphaBits = pfd.cAlphaBits;+ fbconfig->redBits = pfd.cRedBits;+ fbconfig->greenBits = pfd.cGreenBits;+ fbconfig->blueBits = pfd.cBlueBits;+ fbconfig->alphaBits = pfd.cAlphaBits; - result[*found].depthBits = pfd.cDepthBits;- result[*found].stencilBits = pfd.cStencilBits;+ fbconfig->depthBits = pfd.cDepthBits;+ fbconfig->stencilBits = pfd.cStencilBits; - result[*found].accumRedBits = pfd.cAccumRedBits;- result[*found].accumGreenBits = pfd.cAccumGreenBits;- result[*found].accumBlueBits = pfd.cAccumBlueBits;- result[*found].accumAlphaBits = pfd.cAccumAlphaBits;+ fbconfig->accumRedBits = pfd.cAccumRedBits;+ fbconfig->accumGreenBits = pfd.cAccumGreenBits;+ fbconfig->accumBlueBits = pfd.cAccumBlueBits;+ fbconfig->accumAlphaBits = pfd.cAccumAlphaBits; - result[*found].auxBuffers = pfd.cAuxBuffers;- result[*found].stereo = ( pfd.dwFlags & PFD_STEREO ) ? GL_TRUE : GL_FALSE;+ fbconfig->auxBuffers = pfd.cAuxBuffers;+ fbconfig->stereo = ( pfd.dwFlags & PFD_STEREO ) ? GL_TRUE : GL_FALSE; // PFD pixel formats do not support FSAA- result[*found].samples = 0;+ fbconfig->samples = 0; } - result[*found].platformID = i;+ fbconfig->platformID = i; (*found)++; } - return result;+ if( *found == 0 )+ {+ free( fbconfigs );+ return NULL;+ }++ return fbconfigs; } @@ -370,6 +394,11 @@ { return GL_FALSE; }++ // Copy the debug context hint as there's no way of verifying it+ // This is the only code path capable of creating a debug context,+ // so leave it as false (from the earlier memset) otherwise+ _glfwWin.glDebug = wndconfig->glDebug; } else {@@ -659,19 +688,26 @@ static LRESULT CALLBACK windowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {- int wheelDelta, iconified;+ int wheelDelta; switch( uMsg ) { // Window activate message? (iconification?) case WM_ACTIVATE: {- _glfwWin.active = LOWORD(wParam) != WA_INACTIVE ? GL_TRUE : GL_FALSE;+ int activated = (LOWORD(wParam) != WA_INACTIVE) ? GL_TRUE : GL_FALSE;+ int iconified = HIWORD(wParam) ? GL_TRUE : GL_FALSE; - iconified = HIWORD(wParam) ? GL_TRUE : GL_FALSE;+ if( activated && iconified )+ {+ // This is a workaround for window iconification using the+ // taskbar leading to windows being told they're focused and+ // iconified and then never told they're defocused+ activated = GL_FALSE;+ } // Were we deactivated/iconified?- if( (!_glfwWin.active || iconified) && !_glfwWin.iconified )+ if( !activated && _glfwWin.active ) { _glfwInputDeactivation(); @@ -691,14 +727,12 @@ } // Unlock mouse if locked- if( !_glfwWin.oldMouseLockValid )+ if( _glfwWin.mouseLock ) {- _glfwWin.oldMouseLock = _glfwWin.mouseLock;- _glfwWin.oldMouseLockValid = GL_TRUE;- glfwEnable( GLFW_MOUSE_CURSOR );+ _glfwPlatformShowMouseCursor(); } }- else if( _glfwWin.active || !iconified )+ else if( activated && !_glfwWin.active ) { // If we are in fullscreen mode we need to maximize if( _glfwWin.opened && _glfwWin.fullscreen && _glfwWin.iconified )@@ -721,13 +755,13 @@ } // Lock mouse, if necessary- if( _glfwWin.oldMouseLockValid && _glfwWin.oldMouseLock )+ if( _glfwWin.mouseLock ) {- glfwDisable( GLFW_MOUSE_CURSOR );+ _glfwPlatformHideMouseCursor(); }- _glfwWin.oldMouseLockValid = GL_FALSE; } + _glfwWin.active = activated; _glfwWin.iconified = iconified; return 0; }@@ -865,8 +899,15 @@ if( NewMouseX != _glfwInput.OldMouseX || NewMouseY != _glfwInput.OldMouseY ) {+ _glfwInput.MouseMoved = GL_TRUE;+ if( _glfwWin.mouseLock ) {+ if( !_glfwWin.active )+ {+ return 0;+ }+ _glfwInput.MousePosX += NewMouseX - _glfwInput.OldMouseX; _glfwInput.MousePosY += NewMouseY -@@ -879,7 +920,6 @@ } _glfwInput.OldMouseX = NewMouseX; _glfwInput.OldMouseY = NewMouseY;- _glfwInput.MouseMoved = GL_TRUE; if( _glfwWin.mousePosCallback ) {@@ -914,11 +954,7 @@ // If the mouse is locked, update the clipping rect if( _glfwWin.mouseLock ) {- RECT ClipWindowRect;- if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) )- {- ClipCursor( &ClipWindowRect );- }+ updateClipRect(); } if( _glfwWin.windowSizeCallback )@@ -933,11 +969,7 @@ // If the mouse is locked, update the clipping rect if( _glfwWin.mouseLock ) {- RECT ClipWindowRect;- if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) )- {- ClipCursor( &ClipWindowRect );- }+ updateClipRect(); } return 0; }@@ -991,23 +1023,20 @@ //======================================================================== // Initialize WGL-specific extensions-// This function is called once before initial context creation, i.e. before-// any WGL extensions could be present. This is done in order to have both-// extension variable clearing and loading in the same place, hopefully-// decreasing the possibility of forgetting to add one without the other. //======================================================================== static void initWGLExtensions( void ) {- // This needs to include every function pointer loaded below+ // This needs to include every function pointer loaded below, because+ // context re-creation means we cannot assume the struct has been cleared _glfwWin.SwapIntervalEXT = NULL; _glfwWin.GetPixelFormatAttribivARB = NULL; _glfwWin.GetExtensionsStringARB = NULL; _glfwWin.GetExtensionsStringEXT = NULL; _glfwWin.CreateContextAttribsARB = NULL; - // This needs to include every extension used below except for- // WGL_ARB_extensions_string and WGL_EXT_extensions_string+ // This needs to include every extension boolean used below, because context+ // re-creation means we cannot assume the struct has been cleared _glfwWin.has_WGL_EXT_swap_control = GL_FALSE; _glfwWin.has_WGL_ARB_pixel_format = GL_FALSE; _glfwWin.has_WGL_ARB_multisample = GL_FALSE;@@ -1143,7 +1172,7 @@ _glfwWin.window = NULL; // Set common window styles- dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;+ dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; dwExStyle = WS_EX_APPWINDOW; // Set window style, depending on fullscreen mode@@ -1316,8 +1345,6 @@ wndconfig->refreshRate ); } - initWGLExtensions();- if( !createWindow( wndconfig, fbconfig ) ) { fprintf( stderr, "Failed to create GLFW window\n" );@@ -1338,6 +1365,17 @@ } } + if( wndconfig->glDebug )+ {+ // Debug contexts are not a hard constraint, so we don't fail here if+ // the extension isn't available++ if( _glfwWin.has_WGL_ARB_create_context )+ {+ recreateContext = GL_TRUE;+ }+ }+ if( wndconfig->glMajor > 2 ) { if ( wndconfig->glMajor != _glfwWin.glMajor ||@@ -1410,6 +1448,7 @@ SWP_NOMOVE | SWP_NOSIZE ); } + ShowWindow( _glfwWin.window, SW_SHOWNORMAL ); setForegroundWindow( _glfwWin.window ); SetFocus( _glfwWin.window ); @@ -1553,14 +1592,6 @@ // Change display settings to the desktop resolution ChangeDisplaySettings( NULL, CDS_FULLSCREEN ); }-- // Unlock mouse- if( !_glfwWin.oldMouseLockValid )- {- _glfwWin.oldMouseLock = _glfwWin.mouseLock;- _glfwWin.oldMouseLockValid = GL_TRUE;- glfwEnable( GLFW_MOUSE_CURSOR );- } } @@ -1587,13 +1618,6 @@ // Window is no longer iconified _glfwWin.iconified = GL_FALSE;-- // Lock mouse, if necessary- if( _glfwWin.oldMouseLockValid && _glfwWin.oldMouseLock )- {- glfwDisable( GLFW_MOUSE_CURSOR );- }- _glfwWin.oldMouseLockValid = GL_FALSE; } @@ -1730,16 +1754,6 @@ // Flag: mouse was not moved (will be changed by _glfwGetNextEvent if // there was a mouse move event) _glfwInput.MouseMoved = GL_FALSE;- if( _glfwWin.mouseLock )- {- _glfwInput.OldMouseX = _glfwWin.width/2;- _glfwInput.OldMouseY = _glfwWin.height/2;- }- else- {- _glfwInput.OldMouseX = _glfwInput.MousePosX;- _glfwInput.OldMouseY = _glfwInput.MousePosY;- } // Check for new window messages while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )@@ -1783,7 +1797,7 @@ } // Did we have mouse movement in locked cursor mode?- if( _glfwInput.MouseMoved && _glfwWin.mouseLock )+ if( _glfwInput.MouseMoved && _glfwWin.active && _glfwWin.mouseLock ) { _glfwPlatformSetMouseCursorPos( _glfwWin.width / 2, _glfwWin.height / 2 );@@ -1820,18 +1834,23 @@ void _glfwPlatformHideMouseCursor( void ) {- RECT ClipWindowRect;+ if( _glfwWin.mouseLockActive )+ {+ return;+ } + // Move cursor to the middle of the window+ _glfwPlatformSetMouseCursorPos( _glfwWin.width / 2, _glfwWin.height / 2 );+ ShowCursor( FALSE ); // Clip cursor to the window- if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) )- {- ClipCursor( &ClipWindowRect );- }+ updateClipRect(); // Capture cursor to user window SetCapture( _glfwWin.window );++ _glfwWin.mouseLockActive = GL_TRUE; } @@ -1841,6 +1860,11 @@ void _glfwPlatformShowMouseCursor( void ) {+ if( !_glfwWin.mouseLockActive )+ {+ return;+ }+ // Un-capture cursor ReleaseCapture(); @@ -1848,6 +1872,8 @@ ClipCursor( NULL ); ShowCursor( TRUE );++ _glfwWin.mouseLockActive = GL_FALSE; } @@ -1863,6 +1889,9 @@ pos.x = x; pos.y = y; ClientToScreen( _glfwWin.window, &pos );++ _glfwInput.OldMouseX = x;+ _glfwInput.OldMouseY = y; SetCursorPos( pos.x, pos.y ); }
glfw/lib/x11/platform.h view
@@ -129,6 +129,20 @@ typedef intptr_t GLFWintptr; +#ifndef GLX_EXT_swap_control++typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);++#endif /*GLX_MESA_swap_control*/+++#ifndef GLX_MESA_swap_control++typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);++#endif /*GLX_MESA_swap_control*/++ #ifndef GLX_SGI_swap_control // Function signature for GLX_SGI_swap_control@@ -282,6 +296,8 @@ Cursor cursor; // Invisible cursor for hidden cursor // GLX extensions+ PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;+ PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; PFNGLXGETFBCONFIGATTRIBSGIXPROC GetFBConfigAttribSGIX; PFNGLXCHOOSEFBCONFIGSGIXPROC ChooseFBConfigSGIX;@@ -289,6 +305,8 @@ PFNGLXGETVISUALFROMFBCONFIGSGIXPROC GetVisualFromFBConfigSGIX; PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; GLboolean has_GLX_SGIX_fbconfig;+ GLboolean has_GLX_EXT_swap_control;+ GLboolean has_GLX_MESA_swap_control; GLboolean has_GLX_SGI_swap_control; GLboolean has_GLX_ARB_multisample; GLboolean has_GLX_ARB_create_context;@@ -375,8 +393,11 @@ Display *display; - // Server-side GLX version- int glxMajor, glxMinor;+ struct {+ int versionMajor, versionMinor;+ int eventBase;+ int errorBase;+ } GLX; struct { int available;
glfw/lib/x11/x11_init.c view
@@ -177,7 +177,9 @@ // Fullscreen & screen saver settings // Check if GLX is supported on this display- if( !glXQueryExtension( _glfwLibrary.display, NULL, NULL ) )+ if( !glXQueryExtension( _glfwLibrary.display,+ &_glfwLibrary.GLX.errorBase,+ &_glfwLibrary.GLX.eventBase)) { fprintf(stderr, "GLX not supported\n"); return GL_FALSE;@@ -185,8 +187,8 @@ // Retrieve GLX version if( !glXQueryVersion( _glfwLibrary.display,- &_glfwLibrary.glxMajor,- &_glfwLibrary.glxMinor ) )+ &_glfwLibrary.GLX.versionMajor,+ &_glfwLibrary.GLX.versionMinor ) ) { fprintf(stderr, "Unable to query GLX version\n"); return GL_FALSE;
glfw/lib/x11/x11_window.c view
@@ -46,7 +46,18 @@ #define _NET_WM_STATE_ADD 1 #define _NET_WM_STATE_TOGGLE 2 +#ifndef GLXBadProfileARB+ #define GLXBadProfileARB 13+#endif ++//========================================================================+// The X error code as provided to the X error handler+//========================================================================++static unsigned long _glfwErrorCode = Success;++ //************************************************************************ //**** GLFW internal functions **** //************************************************************************@@ -58,6 +69,7 @@ static int errorHandler( Display *display, XErrorEvent *event ) {+ _glfwErrorCode = event->error_code; return 0; } @@ -428,10 +440,11 @@ GLXFBConfig *fbconfigs; _GLFWfbconfig *result; int i, count = 0;+ GLboolean trustWindowBit = GL_TRUE; *found = 0; - if( _glfwLibrary.glxMajor == 1 && _glfwLibrary.glxMinor < 3 )+ if( _glfwLibrary.GLX.versionMajor == 1 && _glfwLibrary.GLX.versionMinor < 3 ) { if( !_glfwWin.has_GLX_SGIX_fbconfig ) {@@ -440,6 +453,14 @@ } } + if( strcmp( glXGetClientString( _glfwLibrary.display, GLX_VENDOR ),+ "Chromium" ) == 0 )+ {+ // This is a (hopefully temporary) workaround for Chromium (VirtualBox+ // GL) not setting the window bit on any GLXFBConfigs+ trustWindowBit = GL_FALSE;+ }+ if( _glfwWin.has_GLX_SGIX_fbconfig ) { fbconfigs = _glfwWin.ChooseFBConfigSGIX( _glfwLibrary.display,@@ -486,8 +507,11 @@ if( !( getFBConfigAttrib( fbconfigs[i], GLX_DRAWABLE_TYPE ) & GLX_WINDOW_BIT ) ) {- // Only consider window GLXFBConfigs- continue;+ if( trustWindowBit )+ {+ // Only consider window GLXFBConfigs+ continue;+ } } result[*found].redBits = getFBConfigAttrib( fbconfigs[i], GLX_RED_SIZE );@@ -527,6 +551,31 @@ //========================================================================+// Create the OpenGL context using the legacy interface+//========================================================================++static GLXContext createLegacyContext( GLXFBConfig fbconfig )+{+ if( _glfwWin.has_GLX_SGIX_fbconfig )+ {+ return _glfwWin.CreateContextWithConfigSGIX( _glfwLibrary.display,+ fbconfig,+ GLX_RGBA_TYPE,+ NULL,+ True );+ }+ else+ {+ return glXCreateNewContext( _glfwLibrary.display,+ fbconfig,+ GLX_RGBA_TYPE,+ NULL,+ True );+ }+}+++//======================================================================== // Create the OpenGL context //======================================================================== @@ -654,25 +703,28 @@ // We are done, so unset the error handler again (see above) XSetErrorHandler( NULL );++ if( _glfwWin.context == NULL )+ {+ // HACK: This is a fallback for the broken Mesa implementation of+ // GLX_ARB_create_context_profile, which fails default 1.0 context+ // creation with a GLXBadProfileARB error in violation of the spec+ if( _glfwErrorCode == _glfwLibrary.GLX.errorBase + GLXBadProfileARB &&+ wndconfig->glProfile == 0 &&+ wndconfig->glForward == GL_FALSE )+ {+ _glfwWin.context = createLegacyContext( *fbconfig );+ }+ }++ // Copy the debug context hint as there's no way of verifying it+ // This is the only code path capable of creating a debug context,+ // so leave it as false (from the earlier memset) otherwise+ _glfwWin.glDebug = wndconfig->glDebug; } else {- if( _glfwWin.has_GLX_SGIX_fbconfig )- {- _glfwWin.context = _glfwWin.CreateContextWithConfigSGIX( _glfwLibrary.display,- *fbconfig,- GLX_RGBA_TYPE,- NULL,- True );- }- else- {- _glfwWin.context = glXCreateNewContext( _glfwLibrary.display,- *fbconfig,- GLX_RGBA_TYPE,- NULL,- True );- }+ _glfwWin.context = createLegacyContext( *fbconfig ); } XFree( fbconfig );@@ -698,6 +750,8 @@ static void initGLXExtensions( void ) { // This needs to include every function pointer loaded below+ _glfwWin.SwapIntervalEXT = NULL;+ _glfwWin.SwapIntervalMESA = NULL; _glfwWin.SwapIntervalSGI = NULL; _glfwWin.GetFBConfigAttribSGIX = NULL; _glfwWin.ChooseFBConfigSGIX = NULL;@@ -707,11 +761,35 @@ // This needs to include every extension used below _glfwWin.has_GLX_SGIX_fbconfig = GL_FALSE;+ _glfwWin.has_GLX_EXT_swap_control = GL_FALSE;+ _glfwWin.has_GLX_MESA_swap_control = GL_FALSE; _glfwWin.has_GLX_SGI_swap_control = GL_FALSE; _glfwWin.has_GLX_ARB_multisample = GL_FALSE; _glfwWin.has_GLX_ARB_create_context = GL_FALSE; _glfwWin.has_GLX_ARB_create_context_profile = GL_FALSE; + if( _glfwPlatformExtensionSupported( "GLX_EXT_swap_control" ) )+ {+ _glfwWin.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)+ _glfwPlatformGetProcAddress( "glXSwapIntervalEXT" );++ if( _glfwWin.SwapIntervalEXT )+ {+ _glfwWin.has_GLX_EXT_swap_control = GL_TRUE;+ }+ }++ if( _glfwPlatformExtensionSupported( "GLX_MESA_swap_control" ) )+ {+ _glfwWin.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)+ _glfwPlatformGetProcAddress( "glXSwapIntervalMESA" );++ if( _glfwWin.SwapIntervalMESA )+ {+ _glfwWin.has_GLX_MESA_swap_control = GL_TRUE;+ }+ }+ if( _glfwPlatformExtensionSupported( "GLX_SGI_swap_control" ) ) { _glfwWin.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)@@ -1521,6 +1599,8 @@ XFreeCursor( _glfwLibrary.display, _glfwWin.cursor ); _glfwWin.cursor = (Cursor) 0; }++ XFlush( _glfwLibrary.display ); } @@ -1543,7 +1623,6 @@ void _glfwPlatformSetWindowSize( int width, int height ) { int mode = 0, rate, sizeChanged = GL_FALSE;- XSizeHints *sizehints; rate = _glfwWin.refreshRate; @@ -1557,14 +1636,14 @@ { // Update window size restrictions to match new window size - sizehints = XAllocSizeHints();- sizehints->flags = 0;+ XSizeHints *hints = XAllocSizeHints(); - sizehints->min_width = sizehints->max_width = width;- sizehints->min_height = sizehints->max_height = height;+ hints->flags |= (PMinSize | PMaxSize);+ hints->min_width = hints->max_width = width;+ hints->min_height = hints->max_height = height; - XSetWMNormalHints( _glfwLibrary.display, _glfwWin.window, sizehints );- XFree( sizehints );+ XSetWMNormalHints( _glfwLibrary.display, _glfwWin.window, hints );+ XFree( hints ); } // Change window size before changing fullscreen mode?@@ -1649,10 +1728,23 @@ void _glfwPlatformSwapInterval( int interval ) {- if( _glfwWin.has_GLX_SGI_swap_control )+ if( _glfwWin.has_GLX_EXT_swap_control ) {- _glfwWin.SwapIntervalSGI( interval );+ _glfwWin.SwapIntervalEXT( _glfwLibrary.display,+ _glfwWin.window,+ interval ); }+ else if( _glfwWin.has_GLX_MESA_swap_control )+ {+ _glfwWin.SwapIntervalMESA( interval );+ }+ else if( _glfwWin.has_GLX_SGI_swap_control )+ {+ if( interval > 0 )+ {+ _glfwWin.SwapIntervalSGI( interval );+ }+ } } @@ -1838,6 +1930,9 @@ _glfwWin.pointerGrabbed = GL_TRUE; } }++ // Move cursor to the middle of the window+ _glfwPlatformSetMouseCursorPos( _glfwWin.width / 2, _glfwWin.height / 2 ); }