//======================================================================== // GLFW - An OpenGL framework // File: macosx_window.c // Platform: Mac OS X // API Version: 2.6 // WWW: http://glfw.sourceforge.net //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Camilla Berglund // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //------------------------------------------------------------------------ // $Id: macosx_window.c,v 1.21 2007/03/23 22:58:14 elmindreda Exp $ //======================================================================== #include "internal.h" static _GLFWmacwindowfunctions _glfwMacFSWindowFunctions = { _glfwMacFSOpenWindow, _glfwMacFSCloseWindow, _glfwMacFSSetWindowTitle, _glfwMacFSSetWindowSize, _glfwMacFSSetWindowPos, _glfwMacFSIconifyWindow, _glfwMacFSRestoreWindow, _glfwMacFSRefreshWindowParams, _glfwMacFSSetMouseCursorPos }; static _GLFWmacwindowfunctions _glfwMacDWWindowFunctions = { _glfwMacDWOpenWindow, _glfwMacDWCloseWindow, _glfwMacDWSetWindowTitle, _glfwMacDWSetWindowSize, _glfwMacDWSetWindowPos, _glfwMacDWIconifyWindow, _glfwMacDWRestoreWindow, _glfwMacDWRefreshWindowParams, _glfwMacDWSetMouseCursorPos }; #define _glfwTestModifier( modifierMask, glfwKey ) \ if ( changed & modifierMask ) \ { \ _glfwInputKey( glfwKey, (modifiers & modifierMask ? GLFW_PRESS : GLFW_RELEASE) ); \ } void _glfwHandleMacModifierChange( UInt32 modifiers ) { UInt32 changed = modifiers ^ _glfwInput.Modifiers; _glfwTestModifier( shiftKey, GLFW_KEY_LSHIFT ); _glfwTestModifier( rightShiftKey, GLFW_KEY_RSHIFT ); _glfwTestModifier( controlKey, GLFW_KEY_LCTRL ); _glfwTestModifier( rightControlKey, GLFW_KEY_RCTRL ); _glfwTestModifier( optionKey, GLFW_KEY_LALT ); _glfwTestModifier( rightOptionKey, GLFW_KEY_RALT ); _glfwInput.Modifiers = modifiers; } void _glfwHandleMacKeyChange( UInt32 keyCode, int action ) { switch ( keyCode ) { case MAC_KEY_ENTER: _glfwInputKey( GLFW_KEY_ENTER, action); break; case MAC_KEY_RETURN: _glfwInputKey( GLFW_KEY_KP_ENTER, action); break; case MAC_KEY_ESC: _glfwInputKey( GLFW_KEY_ESC, action); break; case MAC_KEY_F1: _glfwInputKey( GLFW_KEY_F1, action); break; case MAC_KEY_F2: _glfwInputKey( GLFW_KEY_F2, action); break; case MAC_KEY_F3: _glfwInputKey( GLFW_KEY_F3, action); break; case MAC_KEY_F4: _glfwInputKey( GLFW_KEY_F4, action); break; case MAC_KEY_F5: _glfwInputKey( GLFW_KEY_F5, action); break; case MAC_KEY_F6: _glfwInputKey( GLFW_KEY_F6, action); break; case MAC_KEY_F7: _glfwInputKey( GLFW_KEY_F7, action); break; case MAC_KEY_F8: _glfwInputKey( GLFW_KEY_F8, action); break; case MAC_KEY_F9: _glfwInputKey( GLFW_KEY_F9, action); break; case MAC_KEY_F10: _glfwInputKey( GLFW_KEY_F10, action); break; case MAC_KEY_F11: _glfwInputKey( GLFW_KEY_F11, action); break; case MAC_KEY_F12: _glfwInputKey( GLFW_KEY_F12, action); break; case MAC_KEY_F13: _glfwInputKey( GLFW_KEY_F13, action); break; case MAC_KEY_F14: _glfwInputKey( GLFW_KEY_F14, action); break; case MAC_KEY_F15: _glfwInputKey( GLFW_KEY_F15, action); break; case MAC_KEY_UP: _glfwInputKey( GLFW_KEY_UP, action); break; case MAC_KEY_DOWN: _glfwInputKey( GLFW_KEY_DOWN, action); break; case MAC_KEY_LEFT: _glfwInputKey( GLFW_KEY_LEFT, action); break; case MAC_KEY_RIGHT: _glfwInputKey( GLFW_KEY_RIGHT, action); break; case MAC_KEY_TAB: _glfwInputKey( GLFW_KEY_TAB, action); break; case MAC_KEY_BACKSPACE: _glfwInputKey( GLFW_KEY_BACKSPACE, action); break; case MAC_KEY_HELP: _glfwInputKey( GLFW_KEY_INSERT, action); break; case MAC_KEY_DEL: _glfwInputKey( GLFW_KEY_DEL, action); break; case MAC_KEY_PAGEUP: _glfwInputKey( GLFW_KEY_PAGEUP, action); break; case MAC_KEY_PAGEDOWN: _glfwInputKey( GLFW_KEY_PAGEDOWN, action); break; case MAC_KEY_HOME: _glfwInputKey( GLFW_KEY_HOME, action); break; case MAC_KEY_END: _glfwInputKey( GLFW_KEY_END, action); break; case MAC_KEY_KP_0: _glfwInputKey( GLFW_KEY_KP_0, action); break; case MAC_KEY_KP_1: _glfwInputKey( GLFW_KEY_KP_1, action); break; case MAC_KEY_KP_2: _glfwInputKey( GLFW_KEY_KP_2, action); break; case MAC_KEY_KP_3: _glfwInputKey( GLFW_KEY_KP_3, action); break; case MAC_KEY_KP_4: _glfwInputKey( GLFW_KEY_KP_4, action); break; case MAC_KEY_KP_5: _glfwInputKey( GLFW_KEY_KP_5, action); break; case MAC_KEY_KP_6: _glfwInputKey( GLFW_KEY_KP_6, action); break; case MAC_KEY_KP_7: _glfwInputKey( GLFW_KEY_KP_7, action); break; case MAC_KEY_KP_8: _glfwInputKey( GLFW_KEY_KP_8, action); break; case MAC_KEY_KP_9: _glfwInputKey( GLFW_KEY_KP_9, action); break; case MAC_KEY_KP_DIVIDE: _glfwInputKey( GLFW_KEY_KP_DIVIDE, action); break; case MAC_KEY_KP_MULTIPLY: _glfwInputKey( GLFW_KEY_KP_MULTIPLY, action); break; case MAC_KEY_KP_SUBTRACT: _glfwInputKey( GLFW_KEY_KP_SUBTRACT, action); break; case MAC_KEY_KP_ADD: _glfwInputKey( GLFW_KEY_KP_ADD, action); break; case MAC_KEY_KP_DECIMAL: _glfwInputKey( GLFW_KEY_KP_DECIMAL, action); break; case MAC_KEY_KP_EQUAL: _glfwInputKey( GLFW_KEY_KP_EQUAL, action); break; case MAC_KEY_KP_ENTER: _glfwInputKey( GLFW_KEY_KP_ENTER, action); break; default: { extern void *KCHRPtr; UInt32 state = 0; char charCode = (char)KeyTranslate( KCHRPtr, keyCode, &state ); UppercaseText( &charCode, 1, smSystemScript ); _glfwInputKey( (unsigned char)charCode, action ); } break; } } EventTypeSpec GLFW_KEY_EVENT_TYPES[] = { { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyUp }, { kEventClassKeyboard, kEventRawKeyModifiersChanged } }; OSStatus _glfwKeyEventHandler( EventHandlerCallRef handlerCallRef, EventRef event, void *userData ) { UInt32 keyCode; short int keyChar; UInt32 modifiers; switch( GetEventKind( event ) ) { case kEventRawKeyDown: { if( GetEventParameter( event, kEventParamKeyCode, typeUInt32, NULL, sizeof( UInt32 ), NULL, &keyCode ) == noErr ) { _glfwHandleMacKeyChange( keyCode, GLFW_PRESS ); } if( GetEventParameter( event, kEventParamKeyUnicodes, typeUnicodeText, NULL, sizeof(keyChar), NULL, &keyChar) == noErr ) { _glfwInputChar( keyChar, GLFW_PRESS ); } return noErr; } case kEventRawKeyUp: { if( GetEventParameter( event, kEventParamKeyCode, typeUInt32, NULL, sizeof( UInt32 ), NULL, &keyCode ) == noErr ) { _glfwHandleMacKeyChange( keyCode, GLFW_RELEASE ); } if( GetEventParameter( event, kEventParamKeyUnicodes, typeUnicodeText, NULL, sizeof(keyChar), NULL, &keyChar) == noErr ) { _glfwInputChar( keyChar, GLFW_RELEASE ); } return noErr; } case kEventRawKeyModifiersChanged: { if( GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof( UInt32 ), NULL, &modifiers ) == noErr ) { _glfwHandleMacModifierChange( modifiers ); return noErr; } } break; } return eventNotHandledErr; } EventTypeSpec GLFW_MOUSE_EVENT_TYPES[] = { { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseDragged }, { kEventClassMouse, kEventMouseWheelMoved }, }; OSStatus _glfwMouseEventHandler( EventHandlerCallRef handlerCallRef, EventRef event, void *userData ) { switch( GetEventKind( event ) ) { case kEventMouseDown: { WindowRef window; EventRecord oldStyleMacEvent; ConvertEventRefToEventRecord( event, &oldStyleMacEvent ); if( FindWindow ( oldStyleMacEvent.where, &window ) == inMenuBar ) { MenuSelect( oldStyleMacEvent.where ); HiliteMenu(0); return noErr; } else { EventMouseButton button; if( GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, sizeof( EventMouseButton ), NULL, &button ) == noErr ) { button -= kEventMouseButtonPrimary; if( button <= GLFW_MOUSE_BUTTON_LAST ) { _glfwInputMouseClick( button + GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS ); } return noErr; } } break; } case kEventMouseUp: { EventMouseButton button; if( GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, sizeof( EventMouseButton ), NULL, &button ) == noErr ) { button -= kEventMouseButtonPrimary; if( button <= GLFW_MOUSE_BUTTON_LAST ) { _glfwInputMouseClick( button + GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE ); } return noErr; } break; } case kEventMouseMoved: case kEventMouseDragged: { HIPoint mouseLocation; if( _glfwWin.MouseLock ) { if( GetEventParameter( event, kEventParamMouseDelta, typeHIPoint, NULL, sizeof( HIPoint ), NULL, &mouseLocation ) != noErr ) { break; } _glfwInput.MousePosX += mouseLocation.x; _glfwInput.MousePosY += mouseLocation.y; } else { if( GetEventParameter( event, kEventParamMouseLocation, typeHIPoint, NULL, sizeof( HIPoint ), NULL, &mouseLocation ) != noErr ) { break; } _glfwInput.MousePosX = mouseLocation.x; _glfwInput.MousePosY = mouseLocation.y; if( !_glfwWin.Fullscreen ) { Rect content; GetWindowBounds( _glfwWin.MacWindow, kWindowContentRgn, &content ); _glfwInput.MousePosX -= content.left; _glfwInput.MousePosY -= content.top; } } if( _glfwWin.MousePosCallback ) { _glfwWin.MousePosCallback( _glfwInput.MousePosX, _glfwInput.MousePosY ); } break; } case kEventMouseWheelMoved: { EventMouseWheelAxis axis; if( GetEventParameter( event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof( EventMouseWheelAxis ), NULL, &axis) == noErr ) { long wheelDelta; if( axis == kEventMouseWheelAxisY && GetEventParameter( event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof( long ), NULL, &wheelDelta ) == noErr ) { _glfwInput.WheelPos += wheelDelta; if( _glfwWin.MouseWheelCallback ) { _glfwWin.MouseWheelCallback( _glfwInput.WheelPos ); } return noErr; } } break; } } return eventNotHandledErr; } EventTypeSpec GLFW_COMMAND_EVENT_TYPES[] = { { kEventClassCommand, kEventCommandProcess } }; OSStatus _glfwCommandHandler( EventHandlerCallRef handlerCallRef, EventRef event, void *userData ) { if( _glfwWin.SysKeysDisabled ) { // TO DO: give adequate UI feedback that this is the case return eventNotHandledErr; } HICommand command; if( GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof( HICommand ), NULL, &command ) == noErr ) { switch( command.commandID ) { case kHICommandClose: case kHICommandQuit: { // Check if the program wants us to close the window if( _glfwWin.WindowCloseCallback ) { if( _glfwWin.WindowCloseCallback() ) { glfwCloseWindow(); } } else { glfwCloseWindow(); } return noErr; } } } return eventNotHandledErr; } EventTypeSpec GLFW_WINDOW_EVENT_TYPES[] = { { kEventClassWindow, kEventWindowBoundsChanged }, { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowActivated }, { kEventClassWindow, kEventWindowDeactivated }, }; OSStatus _glfwWindowEventHandler( EventHandlerCallRef handlerCallRef, EventRef event, void *userData ) { switch( GetEventKind(event) ) { case kEventWindowBoundsChanged: { WindowRef window; GetEventParameter( event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window ); Rect rect; GetWindowPortBounds( window, &rect ); if( _glfwWin.Width != rect.right || _glfwWin.Height != rect.bottom ) { aglUpdateContext(_glfwWin.AGLContext); _glfwWin.Width = rect.right; _glfwWin.Height = rect.bottom; if( _glfwWin.WindowSizeCallback ) { _glfwWin.WindowSizeCallback( _glfwWin.Width, _glfwWin.Height ); } // Emulate (force) content invalidation if( _glfwWin.WindowRefreshCallback ) { _glfwWin.WindowRefreshCallback(); } } break; } case kEventWindowClose: { // Check if the program wants us to close the window if( _glfwWin.WindowCloseCallback ) { if( _glfwWin.WindowCloseCallback() ) { glfwCloseWindow(); } } else { glfwCloseWindow(); } return noErr; } case kEventWindowDrawContent: { // Call user callback function if( _glfwWin.WindowRefreshCallback ) { _glfwWin.WindowRefreshCallback(); } break; } case kEventWindowActivated: { _glfwWin.Active = GL_TRUE; break; } case kEventWindowDeactivated: { _glfwWin.Active = GL_FALSE; _glfwInputDeactivation(); break; } } return eventNotHandledErr; } int _glfwInstallEventHandlers( void ) { OSStatus error; _glfwWin.MouseUPP = NewEventHandlerUPP( _glfwMouseEventHandler ); error = InstallEventHandler( GetApplicationEventTarget(), _glfwWin.MouseUPP, GetEventTypeCount( GLFW_MOUSE_EVENT_TYPES ), GLFW_MOUSE_EVENT_TYPES, NULL, NULL ); if( error != noErr ) { return GL_FALSE; } _glfwWin.CommandUPP = NewEventHandlerUPP( _glfwCommandHandler ); error = InstallEventHandler( GetApplicationEventTarget(), _glfwWin.CommandUPP, GetEventTypeCount( GLFW_COMMAND_EVENT_TYPES ), GLFW_COMMAND_EVENT_TYPES, NULL, NULL ); if( error != noErr ) { return GL_FALSE; } _glfwWin.KeyboardUPP = NewEventHandlerUPP( _glfwKeyEventHandler ); error = InstallEventHandler( GetApplicationEventTarget(), _glfwWin.KeyboardUPP, GetEventTypeCount( GLFW_KEY_EVENT_TYPES ), GLFW_KEY_EVENT_TYPES, NULL, NULL ); if( error != noErr ) { return GL_FALSE; } return GL_TRUE; } #define _setAGLAttribute( aglAttributeName, AGLparameter ) \ if ( AGLparameter != 0 ) \ { \ AGLpixelFormatAttributes[numAGLAttrs++] = aglAttributeName; \ AGLpixelFormatAttributes[numAGLAttrs++] = AGLparameter; \ } #define _getAGLAttribute( aglAttributeName, variableName ) \ { \ GLint aglValue; \ (void)aglDescribePixelFormat( pixelFormat, aglAttributeName, &aglValue ); \ variableName = aglValue; \ } #define _setCGLAttribute( cglAttributeName, CGLparameter ) \ if ( CGLparameter != 0 ) \ { \ CGLpixelFormatAttributes[ numCGLAttrs++ ] = cglAttributeName; \ CGLpixelFormatAttributes[ numCGLAttrs++ ] = CGLparameter; \ } #define _getCGLAttribute( cglAttributeName, variableName ) \ { \ long cglValue; \ (void)CGLDescribePixelFormat( CGLpfObj, 0, cglAttributeName, &cglValue ); \ variableName = cglValue; \ } int _glfwPlatformOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode, _GLFWhints* hints ) { OSStatus error; unsigned int windowAttributes; // TO DO: Refactor this function! _glfwWin.WindowFunctions = ( _glfwWin.Fullscreen ? &_glfwMacFSWindowFunctions : &_glfwMacDWWindowFunctions ); // Windowed or fullscreen; AGL or CGL? Quite the mess... // AGL appears to be the only choice for attaching OpenGL contexts to // Carbon windows, but it leaves the user no control over fullscreen // mode stretching. Solution: AGL for windowed, CGL for fullscreen. if( !_glfwWin.Fullscreen ) { // create AGL pixel format attribute list GLint AGLpixelFormatAttributes[256]; int numAGLAttrs = 0; AGLpixelFormatAttributes[numAGLAttrs++] = AGL_RGBA; AGLpixelFormatAttributes[numAGLAttrs++] = AGL_DOUBLEBUFFER; if( hints->Stereo ) { AGLpixelFormatAttributes[numAGLAttrs++] = AGL_STEREO; } _setAGLAttribute( AGL_AUX_BUFFERS, hints->AuxBuffers); _setAGLAttribute( AGL_RED_SIZE, redbits ); _setAGLAttribute( AGL_GREEN_SIZE, greenbits ); _setAGLAttribute( AGL_BLUE_SIZE, bluebits ); _setAGLAttribute( AGL_ALPHA_SIZE, alphabits ); _setAGLAttribute( AGL_DEPTH_SIZE, depthbits ); _setAGLAttribute( AGL_STENCIL_SIZE, stencilbits ); _setAGLAttribute( AGL_ACCUM_RED_SIZE, hints->AccumRedBits ); _setAGLAttribute( AGL_ACCUM_GREEN_SIZE, hints->AccumGreenBits ); _setAGLAttribute( AGL_ACCUM_BLUE_SIZE, hints->AccumBlueBits ); _setAGLAttribute( AGL_ACCUM_ALPHA_SIZE, hints->AccumAlphaBits ); if( hints->Samples > 1 ) { _setAGLAttribute( AGL_SAMPLE_BUFFERS_ARB, 1 ); _setAGLAttribute( AGL_SAMPLES_ARB, hints->Samples ); AGLpixelFormatAttributes[numAGLAttrs++] = AGL_NO_RECOVERY; } AGLpixelFormatAttributes[numAGLAttrs++] = AGL_NONE; // create pixel format descriptor AGLDevice mainMonitor = GetMainDevice(); AGLPixelFormat pixelFormat = aglChoosePixelFormat( &mainMonitor, 1, AGLpixelFormatAttributes ); if( pixelFormat == NULL ) { return GL_FALSE; } // store pixel format's values for _glfwPlatformGetWindowParam's use _getAGLAttribute( AGL_ACCELERATED, _glfwWin.Accelerated ); _getAGLAttribute( AGL_RED_SIZE, _glfwWin.RedBits ); _getAGLAttribute( AGL_GREEN_SIZE, _glfwWin.GreenBits ); _getAGLAttribute( AGL_BLUE_SIZE, _glfwWin.BlueBits ); _getAGLAttribute( AGL_ALPHA_SIZE, _glfwWin.AlphaBits ); _getAGLAttribute( AGL_DEPTH_SIZE, _glfwWin.DepthBits ); _getAGLAttribute( AGL_STENCIL_SIZE, _glfwWin.StencilBits ); _getAGLAttribute( AGL_ACCUM_RED_SIZE, _glfwWin.AccumRedBits ); _getAGLAttribute( AGL_ACCUM_GREEN_SIZE, _glfwWin.AccumGreenBits ); _getAGLAttribute( AGL_ACCUM_BLUE_SIZE, _glfwWin.AccumBlueBits ); _getAGLAttribute( AGL_ACCUM_ALPHA_SIZE, _glfwWin.AccumAlphaBits ); _getAGLAttribute( AGL_AUX_BUFFERS, _glfwWin.AuxBuffers ); _getAGLAttribute( AGL_STEREO, _glfwWin.Stereo ); _getAGLAttribute( AGL_SAMPLES_ARB, _glfwWin.Samples ); _glfwWin.RefreshRate = hints->RefreshRate; // create AGL context _glfwWin.AGLContext = aglCreateContext( pixelFormat, NULL ); aglDestroyPixelFormat( pixelFormat ); if( _glfwWin.AGLContext == NULL ) { _glfwPlatformCloseWindow(); return GL_FALSE; } // create window Rect windowContentBounds; windowContentBounds.left = 0; windowContentBounds.top = 0; windowContentBounds.right = width; windowContentBounds.bottom = height; windowAttributes = ( kWindowCloseBoxAttribute \ | kWindowCollapseBoxAttribute \ | kWindowStandardHandlerAttribute ); if( hints->WindowNoResize ) { windowAttributes |= kWindowLiveResizeAttribute; } else { windowAttributes |= ( kWindowFullZoomAttribute | kWindowResizableAttribute ); } error = CreateNewWindow( kDocumentWindowClass, windowAttributes, &windowContentBounds, &( _glfwWin.MacWindow ) ); if( ( error != noErr ) || ( _glfwWin.MacWindow == NULL ) ) { _glfwPlatformCloseWindow(); return GL_FALSE; } _glfwWin.WindowUPP = NewEventHandlerUPP( _glfwWindowEventHandler ); error = InstallWindowEventHandler( _glfwWin.MacWindow, _glfwWin.WindowUPP, GetEventTypeCount( GLFW_WINDOW_EVENT_TYPES ), GLFW_WINDOW_EVENT_TYPES, NULL, NULL ); if( error != noErr ) { _glfwPlatformCloseWindow(); return GL_FALSE; } // Don't care if we fail here (void)SetWindowTitleWithCFString( _glfwWin.MacWindow, CFSTR( "GLFW Window" ) ); (void)RepositionWindow( _glfwWin.MacWindow, NULL, kWindowCenterOnMainScreen ); if( !aglSetDrawable( _glfwWin.AGLContext, GetWindowPort( _glfwWin.MacWindow ) ) ) { _glfwPlatformCloseWindow(); return GL_FALSE; } // Make OpenGL context current if( !aglSetCurrentContext( _glfwWin.AGLContext ) ) { _glfwPlatformCloseWindow(); return GL_FALSE; } // show window ShowWindow( _glfwWin.MacWindow ); return GL_TRUE; } else { CGDisplayErr cgErr; CGLError cglErr; CFDictionaryRef optimalMode; CGLPixelFormatObj CGLpfObj; long numCGLvs = 0; CGLPixelFormatAttribute CGLpixelFormatAttributes[64]; int numCGLAttrs = 0; // variables for enumerating color depths long rgbColorDepth; long rgbaAccumDepth = 0; int rgbChannelDepth = 0; // CGL pixel format attributes _setCGLAttribute( kCGLPFADisplayMask, CGDisplayIDToOpenGLDisplayMask( kCGDirectMainDisplay ) ); if( hints->Stereo ) { CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAStereo; } if( hints->Samples > 1 ) { _setCGLAttribute( kCGLPFASamples, (CGLPixelFormatAttribute)hints->Samples ); _setCGLAttribute( kCGLPFASampleBuffers, (CGLPixelFormatAttribute)1 ); CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFANoRecovery; } CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAFullScreen; CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFADoubleBuffer; CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAAccelerated; CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFANoRecovery; CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAMinimumPolicy; _setCGLAttribute( kCGLPFAAccumSize, (CGLPixelFormatAttribute)( hints->AccumRedBits \ + hints->AccumGreenBits \ + hints->AccumBlueBits \ + hints->AccumAlphaBits ) ); _setCGLAttribute( kCGLPFAAlphaSize, (CGLPixelFormatAttribute)alphabits ); _setCGLAttribute( kCGLPFADepthSize, (CGLPixelFormatAttribute)depthbits ); _setCGLAttribute( kCGLPFAStencilSize, (CGLPixelFormatAttribute)stencilbits ); _setCGLAttribute( kCGLPFAAuxBuffers, (CGLPixelFormatAttribute)hints->AuxBuffers ); CGLpixelFormatAttributes[ numCGLAttrs++ ] = (CGLPixelFormatAttribute)NULL; // create a suitable pixel format with above attributes.. cglErr = CGLChoosePixelFormat( CGLpixelFormatAttributes, &CGLpfObj, &numCGLvs ); if( cglErr != kCGLNoError ) { return GL_FALSE; } // ..and create a rendering context using that pixel format cglErr = CGLCreateContext( CGLpfObj, NULL, &_glfwWin.CGLContext ); if( cglErr != kCGLNoError ) { return GL_FALSE; } // enumerate depth of RGB channels - unlike AGL, CGL works with // a single parameter reflecting the full depth of the frame buffer (void)CGLDescribePixelFormat( CGLpfObj, 0, kCGLPFAColorSize, &rgbColorDepth ); if( rgbColorDepth == 24 || rgbColorDepth == 32 ) { rgbChannelDepth = 8; } if( rgbColorDepth == 16 ) { rgbChannelDepth = 5; } // get pixel depth of accumulator - I haven't got the slightest idea // how this number conforms to any other channel depth than 8 bits, // so this might end up giving completely knackered results... (void)CGLDescribePixelFormat( CGLpfObj, 0, kCGLPFAAccumSize, &rgbaAccumDepth ); if( rgbaAccumDepth == 32 ) { rgbaAccumDepth = 8; } // store values of pixel format for _glfwPlatformGetWindowParam's use _getCGLAttribute( kCGLPFAAccelerated, _glfwWin.Accelerated ); _getCGLAttribute( rgbChannelDepth, _glfwWin.RedBits ); _getCGLAttribute( rgbChannelDepth, _glfwWin.GreenBits ); _getCGLAttribute( rgbChannelDepth, _glfwWin.BlueBits ); _getCGLAttribute( kCGLPFAAlphaSize, _glfwWin.AlphaBits ); _getCGLAttribute( kCGLPFADepthSize, _glfwWin.DepthBits ); _getCGLAttribute( kCGLPFAStencilSize, _glfwWin.StencilBits ); _getCGLAttribute( rgbaAccumDepth, _glfwWin.AccumRedBits ); _getCGLAttribute( rgbaAccumDepth, _glfwWin.AccumGreenBits ); _getCGLAttribute( rgbaAccumDepth, _glfwWin.AccumBlueBits ); _getCGLAttribute( rgbaAccumDepth, _glfwWin.AccumAlphaBits ); _getCGLAttribute( kCGLPFAAuxBuffers, _glfwWin.AuxBuffers ); _getCGLAttribute( kCGLPFAStereo, _glfwWin.Stereo ); _glfwWin.RefreshRate = hints->RefreshRate; // destroy our pixel format (void)CGLDestroyPixelFormat( CGLpfObj ); // capture the display for our application cgErr = CGDisplayCapture( kCGDirectMainDisplay ); if( cgErr != kCGErrorSuccess ) { return GL_FALSE; } // find closest matching NON-STRETCHED display mode.. optimalMode = CGDisplayBestModeForParametersAndRefreshRateWithProperty( kCGDirectMainDisplay, rgbColorDepth, width, /* Check further to the right -> */ height, hints->RefreshRate, NULL, NULL ); if( optimalMode == NULL ) { return GL_FALSE; } // ..and switch to that mode cgErr = CGDisplaySwitchToMode( kCGDirectMainDisplay, optimalMode ); if( cgErr != kCGErrorSuccess ) { return GL_FALSE; } // switch to our OpenGL context, and bring it up fullscreen cglErr = CGLSetCurrentContext( _glfwWin.CGLContext ); if( cglErr != kCGLNoError ) { return GL_FALSE; } cglErr = CGLSetFullScreen( _glfwWin.CGLContext ); if( cglErr != kCGLNoError ) { return GL_FALSE; } return GL_TRUE; } } void _glfwPlatformCloseWindow( void ) { if( _glfwWin.WindowFunctions != NULL ) { if( _glfwWin.WindowUPP != NULL ) { DisposeEventHandlerUPP( _glfwWin.WindowUPP ); _glfwWin.WindowUPP = NULL; } _glfwWin.WindowFunctions->CloseWindow(); if( !_glfwWin.Fullscreen && _glfwWin.AGLContext != NULL ) { aglSetCurrentContext( NULL ); aglSetDrawable( _glfwWin.AGLContext, NULL ); aglDestroyContext( _glfwWin.AGLContext ); _glfwWin.AGLContext = NULL; } if( _glfwWin.Fullscreen && _glfwWin.CGLContext != NULL ) { CGLSetCurrentContext( NULL ); CGLClearDrawable( _glfwWin.CGLContext ); CGLDestroyContext( _glfwWin.CGLContext ); CGReleaseAllDisplays(); _glfwWin.CGLContext = NULL; } if( _glfwWin.MacWindow != NULL ) { ReleaseWindow( _glfwWin.MacWindow ); _glfwWin.MacWindow = NULL; } _glfwWin.WindowFunctions = NULL; } } void _glfwPlatformSetWindowTitle( const char *title ) { _glfwWin.WindowFunctions->SetWindowTitle( title ); } void _glfwPlatformSetWindowSize( int width, int height ) { _glfwWin.WindowFunctions->SetWindowSize( width, height ); } void _glfwPlatformSetWindowPos( int x, int y ) { _glfwWin.WindowFunctions->SetWindowPos( x, y ); } void _glfwPlatformIconifyWindow( void ) { _glfwWin.WindowFunctions->IconifyWindow(); } void _glfwPlatformRestoreWindow( void ) { _glfwWin.WindowFunctions->RestoreWindow(); } void _glfwPlatformSwapBuffers( void ) { if( !_glfwWin.Fullscreen ) { aglSwapBuffers( _glfwWin.AGLContext ); } else { CGLFlushDrawable( _glfwWin.CGLContext ); } } void _glfwPlatformSwapInterval( int interval ) { GLint AGLparameter = interval; // CGL doesn't seem to like intervals other than 0 (vsync off) or 1 (vsync on) long CGLparameter = ( interval == 0 ? 0 : 1 ); if( !_glfwWin.Fullscreen ) { // Don't care if we fail here.. (void)aglSetInteger( _glfwWin.AGLContext, AGL_SWAP_INTERVAL, &AGLparameter ); } else { // ..or here (void)CGLSetParameter( _glfwWin.CGLContext, kCGLCPSwapInterval, &CGLparameter ); } } void _glfwPlatformRefreshWindowParams( void ) { _glfwWin.WindowFunctions->RefreshWindowParams(); } int _glfwPlatformGetWindowParam( int param ) { switch ( param ) { case GLFW_ACCELERATED: return _glfwWin.Accelerated; break; case GLFW_RED_BITS: return _glfwWin.RedBits; break; case GLFW_GREEN_BITS: return _glfwWin.GreenBits; break; case GLFW_BLUE_BITS: return _glfwWin.BlueBits; break; case GLFW_ALPHA_BITS: return _glfwWin.AlphaBits; break; case GLFW_DEPTH_BITS: return _glfwWin.DepthBits; break; case GLFW_STENCIL_BITS: return _glfwWin.StencilBits; break; case GLFW_ACCUM_RED_BITS: return _glfwWin.AccumRedBits; break; case GLFW_ACCUM_GREEN_BITS: return _glfwWin.AccumGreenBits; break; case GLFW_ACCUM_BLUE_BITS: return _glfwWin.AccumBlueBits; break; case GLFW_ACCUM_ALPHA_BITS: return _glfwWin.AccumAlphaBits; break; case GLFW_AUX_BUFFERS: return _glfwWin.AuxBuffers; break; case GLFW_STEREO: return _glfwWin.Stereo; break; case GLFW_REFRESH_RATE: return _glfwWin.RefreshRate; break; default: return GL_FALSE; } } void _glfwPlatformPollEvents( void ) { EventRef event; EventTargetRef eventDispatcher = GetEventDispatcherTarget(); while ( ReceiveNextEvent( 0, NULL, 0.0, TRUE, &event ) == noErr ) { SendEventToEventTarget( event, eventDispatcher ); ReleaseEvent( event ); } } void _glfwPlatformWaitEvents( void ) { EventRef event; // Wait for new events ReceiveNextEvent( 0, NULL, kEventDurationForever, FALSE, &event ); // Poll new events _glfwPlatformPollEvents(); } void _glfwPlatformHideMouseCursor( void ) { // TO DO: What if we fail here? CGDisplayHideCursor( kCGDirectMainDisplay ); CGAssociateMouseAndMouseCursorPosition( false ); } void _glfwPlatformShowMouseCursor( void ) { // TO DO: What if we fail here? CGDisplayShowCursor( kCGDirectMainDisplay ); CGAssociateMouseAndMouseCursorPosition( true ); } void _glfwPlatformSetMouseCursorPos( int x, int y ) { _glfwWin.WindowFunctions->SetMouseCursorPos( x, y ); } int _glfwMacFSOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int accumredbits, int accumgreenbits, int accumbluebits, int accumalphabits, int auxbuffers, int stereo, int refreshrate ) { return GL_FALSE; } void _glfwMacFSCloseWindow( void ) { // TO DO: un-capture displays, &c. } void _glfwMacFSSetWindowTitle( const char *title ) { // no-op really, change "fake" mini-window title _glfwMacDWSetWindowTitle( title ); } void _glfwMacFSSetWindowSize( int width, int height ) { // TO DO: something funky for full-screen _glfwMacDWSetWindowSize( width, height ); } void _glfwMacFSSetWindowPos( int x, int y ) { // no-op really, change "fake" mini-window position _glfwMacDWSetWindowPos( x, y ); } void _glfwMacFSIconifyWindow( void ) { // TO DO: Something funky for full-screen _glfwMacDWIconifyWindow(); } void _glfwMacFSRestoreWindow( void ) { _glfwMacDWRestoreWindow(); // TO DO: Something funky for full-screen } void _glfwMacFSRefreshWindowParams( void ) { // TO DO: implement this! } void _glfwMacFSSetMouseCursorPos( int x, int y ) { // TO DO: what if we fail here? CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, CGPointMake( x, y ) ); } int _glfwMacDWOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int accumredbits, int accumgreenbits, int accumbluebits, int accumalphabits, int auxbuffers, int stereo, int refreshrate ) { return GL_FALSE; } void _glfwMacDWCloseWindow( void ) { } void _glfwMacDWSetWindowTitle( const char *title ) { CFStringRef windowTitle = CFStringCreateWithCString( kCFAllocatorDefault, title, kCFStringEncodingISOLatin1 ); // Don't care if we fail (void)SetWindowTitleWithCFString( _glfwWin.MacWindow, windowTitle ); CFRelease( windowTitle ); } void _glfwMacDWSetWindowSize( int width, int height ) { SizeWindow( _glfwWin.MacWindow, width, height, TRUE ); } void _glfwMacDWSetWindowPos( int x, int y ) { // TO DO: take main monitor bounds into account MoveWindow( _glfwWin.MacWindow, x, y, FALSE ); } void _glfwMacDWIconifyWindow( void ) { // TO DO: What if we fail here? (void)CollapseWindow( _glfwWin.MacWindow, TRUE ); } void _glfwMacDWRestoreWindow( void ) { // TO DO: What if we fail here? (void)CollapseWindow( _glfwWin.MacWindow, FALSE ); } void _glfwMacDWRefreshWindowParams( void ) { // TO DO: implement this! } void _glfwMacDWSetMouseCursorPos( int x, int y ) { Rect content; GetWindowBounds(_glfwWin.MacWindow, kWindowContentRgn, &content); _glfwInput.MousePosX = x + content.left; _glfwInput.MousePosY = y + content.top; CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, CGPointMake( _glfwInput.MousePosX, _glfwInput.MousePosY ) ); }