You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
1309 lines
46 KiB
1309 lines
46 KiB
//======================================================================== |
|
// GLFW - An OpenGL framework |
|
// Platform: Carbon/AGL/CGL |
|
// API Version: 3.0 |
|
// WWW: http://www.glfw.org/ |
|
//------------------------------------------------------------------------ |
|
// Copyright (c) 2002-2006 Marcus Geelnard |
|
// Copyright (c) 2003 Keith Bauer |
|
// Copyright (c) 2003-2010 Camilla Berglund <elmindreda@elmindreda.org> |
|
// Copyright (c) 2006-2007 Robin Leffmann |
|
// |
|
// 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. |
|
// |
|
//======================================================================== |
|
|
|
#include "internal.h" |
|
|
|
#define _glfwTestModifier( modifierMask, glfwKey ) \ |
|
if ( changed & modifierMask ) \ |
|
{ \ |
|
_glfwInputKey( glfwKey, (modifiers & modifierMask ? GLFW_PRESS : GLFW_RELEASE) ); \ |
|
} |
|
|
|
//************************************************************************ |
|
//**** GLFW internal functions **** |
|
//************************************************************************ |
|
|
|
static void handleMacModifierChange( UInt32 modifiers ) |
|
{ |
|
UInt32 changed = modifiers ^ _glfwInput.Modifiers; |
|
|
|
// The right *key variants below never actually occur |
|
// There also isn't even a broken right command key constant |
|
_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 ); |
|
_glfwTestModifier( cmdKey, GLFW_KEY_LSUPER ); |
|
|
|
_glfwInput.Modifiers = modifiers; |
|
} |
|
|
|
static void handleMacKeyChange( 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; |
|
case MAC_KEY_NUMLOCK: _glfwInputKey( GLFW_KEY_KP_NUM_LOCK, 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; |
|
} |
|
} |
|
|
|
// The set of event class/kind combinations supported by keyEventHandler |
|
// This is used by installEventHandlers below |
|
static const EventTypeSpec GLFW_KEY_EVENT_TYPES[] = |
|
{ |
|
{ kEventClassKeyboard, kEventRawKeyDown }, |
|
{ kEventClassKeyboard, kEventRawKeyUp }, |
|
{ kEventClassKeyboard, kEventRawKeyRepeat }, |
|
{ kEventClassKeyboard, kEventRawKeyModifiersChanged } |
|
}; |
|
|
|
static OSStatus keyEventHandler( EventHandlerCallRef handlerCallRef, |
|
EventRef event, |
|
void *userData ) |
|
{ |
|
UInt32 keyCode; |
|
short int keyChar; |
|
UInt32 modifiers; |
|
|
|
switch( GetEventKind( event ) ) |
|
{ |
|
case kEventRawKeyRepeat: |
|
case kEventRawKeyDown: |
|
{ |
|
if( GetEventParameter( event, |
|
kEventParamKeyCode, |
|
typeUInt32, |
|
NULL, |
|
sizeof( UInt32 ), |
|
NULL, |
|
&keyCode ) == noErr ) |
|
{ |
|
handleMacKeyChange( 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 ) |
|
{ |
|
handleMacKeyChange( 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 ) |
|
{ |
|
handleMacModifierChange( modifiers ); |
|
return noErr; |
|
} |
|
} |
|
break; |
|
} |
|
|
|
return eventNotHandledErr; |
|
} |
|
|
|
// The set of event class/kind combinations supported by mouseEventHandler |
|
// This is used by installEventHandlers below |
|
static const EventTypeSpec GLFW_MOUSE_EVENT_TYPES[] = |
|
{ |
|
{ kEventClassMouse, kEventMouseDown }, |
|
{ kEventClassMouse, kEventMouseUp }, |
|
{ kEventClassMouse, kEventMouseMoved }, |
|
{ kEventClassMouse, kEventMouseDragged }, |
|
{ kEventClassMouse, kEventMouseWheelMoved }, |
|
}; |
|
|
|
static OSStatus mouseEventHandler( 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.window, |
|
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; |
|
} |
|
|
|
// The set of event class/kind combinations supported by commandHandler |
|
// This is used by installEventHandlers below |
|
static const EventTypeSpec GLFW_COMMAND_EVENT_TYPES[] = |
|
{ |
|
{ kEventClassCommand, kEventCommandProcess } |
|
}; |
|
|
|
static OSStatus commandHandler( EventHandlerCallRef handlerCallRef, |
|
EventRef event, |
|
void *userData ) |
|
{ |
|
if( _glfwWin.sysKeysDisabled ) |
|
{ |
|
// TODO: 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; |
|
} |
|
|
|
// The set of event class/kind combinations supported by windowEventHandler |
|
// This is used by installEventHandlers below |
|
static const EventTypeSpec GLFW_WINDOW_EVENT_TYPES[] = |
|
{ |
|
{ kEventClassWindow, kEventWindowBoundsChanged }, |
|
{ kEventClassWindow, kEventWindowClose }, |
|
{ kEventClassWindow, kEventWindowDrawContent }, |
|
{ kEventClassWindow, kEventWindowActivated }, |
|
{ kEventClassWindow, kEventWindowDeactivated }, |
|
}; |
|
|
|
static OSStatus windowEventHandler( 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 client wants us to close the window |
|
if( _glfwWin.windowCloseCallback ) |
|
{ |
|
if( _glfwWin.windowCloseCallback() ) |
|
{ |
|
glfwCloseWindow(); |
|
} |
|
} |
|
else |
|
{ |
|
glfwCloseWindow(); |
|
} |
|
return noErr; |
|
} |
|
|
|
case kEventWindowDrawContent: |
|
{ |
|
if( _glfwWin.windowRefreshCallback ) |
|
{ |
|
_glfwWin.windowRefreshCallback(); |
|
} |
|
break; |
|
} |
|
|
|
case kEventWindowActivated: |
|
{ |
|
_glfwWin.active = GL_TRUE; |
|
break; |
|
} |
|
|
|
case kEventWindowDeactivated: |
|
{ |
|
_glfwWin.active = GL_FALSE; |
|
_glfwInputDeactivation(); |
|
break; |
|
} |
|
} |
|
|
|
return eventNotHandledErr; |
|
} |
|
|
|
static int installEventHandlers( void ) |
|
{ |
|
OSStatus error; |
|
|
|
_glfwWin.mouseUPP = NewEventHandlerUPP( mouseEventHandler ); |
|
|
|
error = InstallEventHandler( GetApplicationEventTarget(), |
|
_glfwWin.mouseUPP, |
|
GetEventTypeCount( GLFW_MOUSE_EVENT_TYPES ), |
|
GLFW_MOUSE_EVENT_TYPES, |
|
NULL, |
|
NULL ); |
|
if( error != noErr ) |
|
{ |
|
fprintf( stderr, "Failed to install Carbon application mouse event handler\n" ); |
|
return GL_FALSE; |
|
} |
|
|
|
_glfwWin.commandUPP = NewEventHandlerUPP( commandHandler ); |
|
|
|
error = InstallEventHandler( GetApplicationEventTarget(), |
|
_glfwWin.commandUPP, |
|
GetEventTypeCount( GLFW_COMMAND_EVENT_TYPES ), |
|
GLFW_COMMAND_EVENT_TYPES, |
|
NULL, |
|
NULL ); |
|
if( error != noErr ) |
|
{ |
|
fprintf( stderr, "Failed to install Carbon application command event handler\n" ); |
|
return GL_FALSE; |
|
} |
|
|
|
_glfwWin.keyboardUPP = NewEventHandlerUPP( keyEventHandler ); |
|
|
|
error = InstallEventHandler( GetApplicationEventTarget(), |
|
_glfwWin.keyboardUPP, |
|
GetEventTypeCount( GLFW_KEY_EVENT_TYPES ), |
|
GLFW_KEY_EVENT_TYPES, |
|
NULL, |
|
NULL ); |
|
if( error != noErr ) |
|
{ |
|
fprintf( stderr, "Failed to install Carbon application key event handler\n" ); |
|
return GL_FALSE; |
|
} |
|
|
|
return GL_TRUE; |
|
} |
|
|
|
//************************************************************************ |
|
//**** Platform implementation functions **** |
|
//************************************************************************ |
|
|
|
#define _setAGLAttribute( aglAttributeName, AGLparameter ) \ |
|
if ( AGLparameter != 0 ) \ |
|
{ \ |
|
AGLpixelFormatAttributes[numAGLAttrs++] = aglAttributeName; \ |
|
AGLpixelFormatAttributes[numAGLAttrs++] = AGLparameter; \ |
|
} |
|
|
|
#define _setCGLAttribute( cglAttributeName, CGLparameter ) \ |
|
if ( CGLparameter != 0 ) \ |
|
{ \ |
|
CGLpixelFormatAttributes[ numCGLAttrs++ ] = cglAttributeName; \ |
|
CGLpixelFormatAttributes[ numCGLAttrs++ ] = CGLparameter; \ |
|
} |
|
|
|
//======================================================================== |
|
// Here is where the window is created, and |
|
// the OpenGL rendering context is created |
|
//======================================================================== |
|
|
|
int _glfwPlatformOpenWindow( int width, int height, |
|
const _GLFWwndconfig *wndconfig, |
|
const _GLFWfbconfig *fbconfig ) |
|
{ |
|
OSStatus error; |
|
unsigned int windowAttributes; |
|
ProcessSerialNumber psn; |
|
|
|
// TODO: Break up this function! |
|
|
|
_glfwWin.windowUPP = NULL; |
|
_glfwWin.mouseUPP = NULL; |
|
_glfwWin.keyboardUPP = NULL; |
|
_glfwWin.commandUPP = NULL; |
|
_glfwWin.window = NULL; |
|
_glfwWin.aglContext = NULL; |
|
_glfwWin.aglPixelFormat = NULL; |
|
_glfwWin.cglContext = NULL; |
|
_glfwWin.cglPixelFormat = NULL; |
|
|
|
_glfwWin.refreshRate = wndconfig->refreshRate; |
|
|
|
// Fail if OpenGL 3.0 or above was requested |
|
if( wndconfig->glMajor > 2 ) |
|
{ |
|
fprintf( stderr, "OpenGL 3.0+ is not yet supported on Mac OS X\n" ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
if( _glfwLibrary.Unbundled ) |
|
{ |
|
if( GetCurrentProcess( &psn ) != noErr ) |
|
{ |
|
fprintf( stderr, "Failed to get the process serial number\n" ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
if( TransformProcessType( &psn, kProcessTransformToForegroundApplication ) != noErr ) |
|
{ |
|
fprintf( stderr, "Failed to become a foreground application\n" ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
if( wndconfig->mode == GLFW_FULLSCREEN ) |
|
{ |
|
if( SetFrontProcess( &psn ) != noErr ) |
|
{ |
|
fprintf( stderr, "Failed to become the front process\n" ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
} |
|
} |
|
|
|
if( !installEventHandlers() ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to install Carbon application event handlers\n" ); |
|
|
|
_glfwPlatformTerminate(); |
|
return GL_FALSE; |
|
} |
|
|
|
// 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( wndconfig->mode == GLFW_WINDOW ) |
|
{ |
|
// create AGL pixel format attribute list |
|
GLint AGLpixelFormatAttributes[256]; |
|
int numAGLAttrs = 0; |
|
|
|
AGLpixelFormatAttributes[numAGLAttrs++] = AGL_RGBA; |
|
AGLpixelFormatAttributes[numAGLAttrs++] = AGL_DOUBLEBUFFER; |
|
AGLpixelFormatAttributes[numAGLAttrs++] = AGL_CLOSEST_POLICY; |
|
|
|
if( fbconfig->stereo ) |
|
{ |
|
AGLpixelFormatAttributes[numAGLAttrs++] = AGL_STEREO; |
|
} |
|
|
|
_setAGLAttribute( AGL_AUX_BUFFERS, fbconfig->auxBuffers); |
|
_setAGLAttribute( AGL_RED_SIZE, fbconfig->redBits ); |
|
_setAGLAttribute( AGL_GREEN_SIZE, fbconfig->greenBits ); |
|
_setAGLAttribute( AGL_BLUE_SIZE, fbconfig->blueBits ); |
|
_setAGLAttribute( AGL_ALPHA_SIZE, fbconfig->alphaBits ); |
|
_setAGLAttribute( AGL_DEPTH_SIZE, fbconfig->depthBits ); |
|
_setAGLAttribute( AGL_STENCIL_SIZE, fbconfig->stencilBits ); |
|
_setAGLAttribute( AGL_ACCUM_RED_SIZE, fbconfig->accumRedBits ); |
|
_setAGLAttribute( AGL_ACCUM_GREEN_SIZE, fbconfig->accumGreenBits ); |
|
_setAGLAttribute( AGL_ACCUM_BLUE_SIZE, fbconfig->accumBlueBits ); |
|
_setAGLAttribute( AGL_ACCUM_ALPHA_SIZE, fbconfig->accumAlphaBits ); |
|
|
|
if( fbconfig->samples > 1 ) |
|
{ |
|
_setAGLAttribute( AGL_SAMPLE_BUFFERS_ARB, 1 ); |
|
_setAGLAttribute( AGL_SAMPLES_ARB, fbconfig->samples ); |
|
AGLpixelFormatAttributes[numAGLAttrs++] = AGL_NO_RECOVERY; |
|
} |
|
|
|
AGLpixelFormatAttributes[numAGLAttrs++] = AGL_NONE; |
|
|
|
// create pixel format descriptor |
|
AGLDevice mainMonitor = GetMainDevice(); |
|
_glfwWin.aglPixelFormat = aglChoosePixelFormat( &mainMonitor, |
|
1, |
|
AGLpixelFormatAttributes ); |
|
if( _glfwWin.aglPixelFormat == NULL ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to choose AGL pixel format: %s\n", |
|
aglErrorString( aglGetError() ) ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
// create AGL context |
|
_glfwWin.aglContext = aglCreateContext( _glfwWin.aglPixelFormat, NULL ); |
|
|
|
if( _glfwWin.aglContext == NULL ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to create AGL context: %s\n", |
|
aglErrorString( aglGetError() ) ); |
|
|
|
_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( wndconfig->windowNoResize ) |
|
{ |
|
windowAttributes |= kWindowLiveResizeAttribute; |
|
} |
|
else |
|
{ |
|
windowAttributes |= ( kWindowFullZoomAttribute | |
|
kWindowResizableAttribute ); |
|
} |
|
|
|
error = CreateNewWindow( kDocumentWindowClass, |
|
windowAttributes, |
|
&windowContentBounds, |
|
&( _glfwWin.window ) ); |
|
if( ( error != noErr ) || ( _glfwWin.window == NULL ) ) |
|
{ |
|
fprintf( stderr, "Failed to create Carbon window\n" ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
_glfwWin.windowUPP = NewEventHandlerUPP( windowEventHandler ); |
|
|
|
error = InstallWindowEventHandler( _glfwWin.window, |
|
_glfwWin.windowUPP, |
|
GetEventTypeCount( GLFW_WINDOW_EVENT_TYPES ), |
|
GLFW_WINDOW_EVENT_TYPES, |
|
NULL, |
|
NULL ); |
|
if( error != noErr ) |
|
{ |
|
fprintf( stderr, "Failed to install Carbon window event handler\n" ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
// Don't care if we fail here |
|
(void)SetWindowTitleWithCFString( _glfwWin.window, CFSTR( "GLFW Window" ) ); |
|
(void)RepositionWindow( _glfwWin.window, |
|
NULL, |
|
kWindowCenterOnMainScreen ); |
|
|
|
if( !aglSetDrawable( _glfwWin.aglContext, |
|
GetWindowPort( _glfwWin.window ) ) ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to set the AGL context as the Carbon window drawable: %s\n", |
|
aglErrorString( aglGetError() ) ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
// Make OpenGL context current |
|
if( !aglSetCurrentContext( _glfwWin.aglContext ) ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to make AGL context current: %s\n", |
|
aglErrorString( aglGetError() ) ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
ShowWindow( _glfwWin.window ); |
|
} |
|
else |
|
{ |
|
CGDisplayErr cgErr; |
|
CGLError cglErr; |
|
|
|
CFDictionaryRef optimalMode; |
|
|
|
GLint numCGLvs = 0; |
|
|
|
CGLPixelFormatAttribute CGLpixelFormatAttributes[64]; |
|
int numCGLAttrs = 0; |
|
|
|
// variables for enumerating color depths |
|
GLint rgbColorDepth; |
|
|
|
// CGL pixel format attributes |
|
_setCGLAttribute( kCGLPFADisplayMask, |
|
CGDisplayIDToOpenGLDisplayMask( kCGDirectMainDisplay ) ); |
|
|
|
if( fbconfig->stereo ) |
|
{ |
|
CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAStereo; |
|
} |
|
|
|
if( fbconfig->samples > 1 ) |
|
{ |
|
_setCGLAttribute( kCGLPFASamples, (CGLPixelFormatAttribute)fbconfig->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)( fbconfig->accumRedBits \ |
|
+ fbconfig->accumGreenBits \ |
|
+ fbconfig->accumBlueBits \ |
|
+ fbconfig->accumAlphaBits ) ); |
|
|
|
_setCGLAttribute( kCGLPFAAlphaSize, (CGLPixelFormatAttribute)fbconfig->alphaBits ); |
|
_setCGLAttribute( kCGLPFADepthSize, (CGLPixelFormatAttribute)fbconfig->depthBits ); |
|
_setCGLAttribute( kCGLPFAStencilSize, (CGLPixelFormatAttribute)fbconfig->stencilBits ); |
|
_setCGLAttribute( kCGLPFAAuxBuffers, (CGLPixelFormatAttribute)fbconfig->auxBuffers ); |
|
|
|
CGLpixelFormatAttributes[ numCGLAttrs++ ] = (CGLPixelFormatAttribute)NULL; |
|
|
|
// create a suitable pixel format with above attributes.. |
|
cglErr = CGLChoosePixelFormat( CGLpixelFormatAttributes, |
|
&_glfwWin.cglPixelFormat, |
|
&numCGLvs ); |
|
if( cglErr != kCGLNoError ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to choose CGL pixel format: %s\n", |
|
CGLErrorString( cglErr ) ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
// ..and create a rendering context using that pixel format |
|
cglErr = CGLCreateContext( _glfwWin.cglPixelFormat, NULL, &_glfwWin.cglContext ); |
|
if( cglErr != kCGLNoError ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to create CGL context: %s\n", |
|
CGLErrorString( cglErr ) ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
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( _glfwWin.cglPixelFormat, |
|
0, |
|
kCGLPFAColorSize, |
|
&rgbColorDepth ); |
|
|
|
// capture the display for our application |
|
cgErr = CGCaptureAllDisplays(); |
|
if( cgErr != kCGErrorSuccess ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to capture Core Graphics displays\n"); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
// find closest matching NON-STRETCHED display mode.. |
|
optimalMode = CGDisplayBestModeForParametersAndRefreshRateWithProperty( |
|
kCGDirectMainDisplay, |
|
rgbColorDepth, |
|
width, |
|
height, |
|
wndconfig->refreshRate, |
|
NULL, |
|
NULL ); |
|
if( optimalMode == NULL ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to retrieve Core Graphics display mode\n"); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
// ..and switch to that mode |
|
cgErr = CGDisplaySwitchToMode( kCGDirectMainDisplay, optimalMode ); |
|
if( cgErr != kCGErrorSuccess ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to switch to Core Graphics display mode\n"); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
// switch to our OpenGL context, and bring it up fullscreen |
|
cglErr = CGLSetCurrentContext( _glfwWin.cglContext ); |
|
if( cglErr != kCGLNoError ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to make CGL context current: %s\n", |
|
CGLErrorString( cglErr ) ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
|
|
cglErr = CGLSetFullScreen( _glfwWin.cglContext ); |
|
if( cglErr != kCGLNoError ) |
|
{ |
|
fprintf( stderr, |
|
"Failed to set CGL fullscreen mode: %s\n", |
|
CGLErrorString( cglErr ) ); |
|
|
|
_glfwPlatformCloseWindow(); |
|
return GL_FALSE; |
|
} |
|
} |
|
|
|
return GL_TRUE; |
|
} |
|
|
|
//======================================================================== |
|
// Properly kill the window/video display |
|
//======================================================================== |
|
|
|
void _glfwPlatformCloseWindow( void ) |
|
{ |
|
if( _glfwWin.mouseUPP != NULL ) |
|
{ |
|
DisposeEventHandlerUPP( _glfwWin.mouseUPP ); |
|
_glfwWin.mouseUPP = NULL; |
|
} |
|
if( _glfwWin.commandUPP != NULL ) |
|
{ |
|
DisposeEventHandlerUPP( _glfwWin.commandUPP ); |
|
_glfwWin.commandUPP = NULL; |
|
} |
|
if( _glfwWin.keyboardUPP != NULL ) |
|
{ |
|
DisposeEventHandlerUPP( _glfwWin.keyboardUPP ); |
|
_glfwWin.keyboardUPP = NULL; |
|
} |
|
if( _glfwWin.windowUPP != NULL ) |
|
{ |
|
DisposeEventHandlerUPP( _glfwWin.windowUPP ); |
|
_glfwWin.windowUPP = NULL; |
|
} |
|
|
|
if( _glfwWin.fullscreen ) |
|
{ |
|
if( _glfwWin.cglContext != NULL ) |
|
{ |
|
CGLSetCurrentContext( NULL ); |
|
CGLClearDrawable( _glfwWin.cglContext ); |
|
CGLDestroyContext( _glfwWin.cglContext ); |
|
CGReleaseAllDisplays(); |
|
_glfwWin.cglContext = NULL; |
|
} |
|
|
|
if( _glfwWin.cglPixelFormat != NULL ) |
|
{ |
|
CGLDestroyPixelFormat( _glfwWin.cglPixelFormat ); |
|
_glfwWin.cglPixelFormat = NULL; |
|
} |
|
} |
|
else |
|
{ |
|
if( _glfwWin.aglContext != NULL ) |
|
{ |
|
aglSetCurrentContext( NULL ); |
|
aglSetDrawable( _glfwWin.aglContext, NULL ); |
|
aglDestroyContext( _glfwWin.aglContext ); |
|
_glfwWin.aglContext = NULL; |
|
} |
|
|
|
if( _glfwWin.aglPixelFormat != NULL ) |
|
{ |
|
aglDestroyPixelFormat( _glfwWin.aglPixelFormat ); |
|
_glfwWin.aglPixelFormat = NULL; |
|
} |
|
} |
|
|
|
if( _glfwWin.window != NULL ) |
|
{ |
|
ReleaseWindow( _glfwWin.window ); |
|
_glfwWin.window = NULL; |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Set the window title |
|
//======================================================================== |
|
|
|
void _glfwPlatformSetWindowTitle( const char *title ) |
|
{ |
|
CFStringRef windowTitle; |
|
|
|
if( !_glfwWin.fullscreen ) |
|
{ |
|
windowTitle = CFStringCreateWithCString( kCFAllocatorDefault, |
|
title, |
|
kCFStringEncodingISOLatin1 ); |
|
|
|
(void)SetWindowTitleWithCFString( _glfwWin.window, windowTitle ); |
|
|
|
CFRelease( windowTitle ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Set the window size |
|
//======================================================================== |
|
|
|
void _glfwPlatformSetWindowSize( int width, int height ) |
|
{ |
|
if( !_glfwWin.fullscreen ) |
|
{ |
|
SizeWindow( _glfwWin.window, width, height, TRUE ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Set the window position |
|
//======================================================================== |
|
|
|
void _glfwPlatformSetWindowPos( int x, int y ) |
|
{ |
|
if( !_glfwWin.fullscreen ) |
|
{ |
|
MoveWindow( _glfwWin.window, x, y, FALSE ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Window iconification |
|
//======================================================================== |
|
|
|
void _glfwPlatformIconifyWindow( void ) |
|
{ |
|
if( !_glfwWin.fullscreen ) |
|
{ |
|
(void)CollapseWindow( _glfwWin.window, TRUE ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Window un-iconification |
|
//======================================================================== |
|
|
|
void _glfwPlatformRestoreWindow( void ) |
|
{ |
|
if( !_glfwWin.fullscreen ) |
|
{ |
|
(void)CollapseWindow( _glfwWin.window, FALSE ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Swap buffers (double-buffering) and poll any new events |
|
//======================================================================== |
|
|
|
void _glfwPlatformSwapBuffers( void ) |
|
{ |
|
if( _glfwWin.fullscreen ) |
|
{ |
|
CGLFlushDrawable( _glfwWin.cglContext ); |
|
} |
|
else |
|
{ |
|
aglSwapBuffers( _glfwWin.aglContext ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Set double buffering swap interval |
|
//======================================================================== |
|
|
|
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 ? 1 : 0 ); |
|
|
|
if( _glfwWin.fullscreen ) |
|
{ |
|
// Don't care if we fail here.. |
|
(void)CGLSetParameter( _glfwWin.cglContext, |
|
kCGLCPSwapInterval, |
|
(GLint*) &CGLparameter ); |
|
} |
|
else |
|
{ |
|
// ..or here |
|
(void)aglSetInteger( _glfwWin.aglContext, |
|
AGL_SWAP_INTERVAL, |
|
&AGLparameter ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Read back framebuffer parameters from the context |
|
//======================================================================== |
|
|
|
#define _getAGLAttribute( aglAttributeName, variableName ) \ |
|
{ \ |
|
GLint aglValue; \ |
|
(void)aglDescribePixelFormat( _glfwWin.aglPixelFormat, aglAttributeName, &aglValue ); \ |
|
variableName = aglValue; \ |
|
} |
|
|
|
#define _getCGLAttribute( cglAttributeName, variableName ) \ |
|
{ \ |
|
GLint cglValue; \ |
|
(void)CGLDescribePixelFormat( _glfwWin.cglPixelFormat, 0, cglAttributeName, &cglValue ); \ |
|
variableName = cglValue; \ |
|
} |
|
|
|
void _glfwPlatformRefreshWindowParams( void ) |
|
{ |
|
GLint rgbColorDepth; |
|
GLint rgbaAccumDepth = 0; |
|
GLint rgbChannelDepth = 0; |
|
|
|
if( _glfwWin.fullscreen ) |
|
{ |
|
_getCGLAttribute( kCGLPFAAccelerated, _glfwWin.accelerated ); |
|
_getCGLAttribute( kCGLPFAAlphaSize, _glfwWin.alphaBits ); |
|
_getCGLAttribute( kCGLPFADepthSize, _glfwWin.depthBits ); |
|
_getCGLAttribute( kCGLPFAStencilSize, _glfwWin.stencilBits ); |
|
_getCGLAttribute( kCGLPFAAuxBuffers, _glfwWin.auxBuffers ); |
|
_getCGLAttribute( kCGLPFAStereo, _glfwWin.stereo ); |
|
_getCGLAttribute( kCGLPFASamples, _glfwWin.samples ); |
|
|
|
// Enumerate depth of RGB channels - unlike AGL, CGL works with |
|
// a single parameter reflecting the full depth of the frame buffer |
|
(void)CGLDescribePixelFormat( _glfwWin.cglPixelFormat, |
|
0, |
|
kCGLPFAColorSize, |
|
&rgbColorDepth ); |
|
|
|
if( rgbColorDepth == 24 || rgbColorDepth == 32 ) |
|
{ |
|
rgbChannelDepth = 8; |
|
} |
|
if( rgbColorDepth == 16 ) |
|
{ |
|
rgbChannelDepth = 5; |
|
} |
|
|
|
_glfwWin.redBits = rgbChannelDepth; |
|
_glfwWin.greenBits = rgbChannelDepth; |
|
_glfwWin.blueBits = rgbChannelDepth; |
|
|
|
// 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... |
|
_getCGLAttribute( kCGLPFAColorSize, rgbaAccumDepth ); |
|
if( rgbaAccumDepth == 32 ) |
|
{ |
|
rgbaAccumDepth = 8; |
|
} |
|
|
|
_glfwWin.accumRedBits = rgbaAccumDepth; |
|
_glfwWin.accumGreenBits = rgbaAccumDepth; |
|
_glfwWin.accumBlueBits = rgbaAccumDepth; |
|
_glfwWin.accumAlphaBits = rgbaAccumDepth; |
|
} |
|
else |
|
{ |
|
_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 ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Poll for new window and input events |
|
//======================================================================== |
|
|
|
void _glfwPlatformPollEvents( void ) |
|
{ |
|
EventRef event; |
|
EventTargetRef eventDispatcher = GetEventDispatcherTarget(); |
|
|
|
while ( ReceiveNextEvent( 0, NULL, 0.0, TRUE, &event ) == noErr ) |
|
{ |
|
SendEventToEventTarget( event, eventDispatcher ); |
|
ReleaseEvent( event ); |
|
} |
|
} |
|
|
|
//======================================================================== |
|
// Wait for new window and input events |
|
//======================================================================== |
|
|
|
void _glfwPlatformWaitEvents( void ) |
|
{ |
|
EventRef event; |
|
|
|
// Wait for new events |
|
ReceiveNextEvent( 0, NULL, kEventDurationForever, FALSE, &event ); |
|
|
|
// Process the new events |
|
_glfwPlatformPollEvents(); |
|
} |
|
|
|
//======================================================================== |
|
// Hide mouse cursor (lock it) |
|
//======================================================================== |
|
|
|
void _glfwPlatformHideMouseCursor( void ) |
|
{ |
|
CGDisplayHideCursor( kCGDirectMainDisplay ); |
|
CGAssociateMouseAndMouseCursorPosition( false ); |
|
} |
|
|
|
//======================================================================== |
|
// Show mouse cursor (unlock it) |
|
//======================================================================== |
|
|
|
void _glfwPlatformShowMouseCursor( void ) |
|
{ |
|
CGDisplayShowCursor( kCGDirectMainDisplay ); |
|
CGAssociateMouseAndMouseCursorPosition( true ); |
|
} |
|
|
|
//======================================================================== |
|
// Set physical mouse cursor position |
|
//======================================================================== |
|
|
|
void _glfwPlatformSetMouseCursorPos( int x, int y ) |
|
{ |
|
Rect content; |
|
|
|
if( _glfwWin.fullscreen ) |
|
{ |
|
CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, |
|
CGPointMake( x, y ) ); |
|
} |
|
else |
|
{ |
|
GetWindowBounds(_glfwWin.window, kWindowContentRgn, &content); |
|
|
|
_glfwInput.MousePosX = x + content.left; |
|
_glfwInput.MousePosY = y + content.top; |
|
|
|
CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, |
|
CGPointMake( _glfwInput.MousePosX, |
|
_glfwInput.MousePosY ) ); |
|
} |
|
} |
|
|
|
|