mirror of
https://github.com/glfw/glfw.git
synced 2024-11-15 23:04:41 +00:00
1276 lines
45 KiB
C
1276 lines
45 KiB
C
//========================================================================
|
|
// 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
|
|
SetWindowTitleWithCFString(_glfwWin.window, CFSTR("GLFW Window"));
|
|
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
|
|
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);
|
|
|
|
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)
|
|
CollapseWindow(_glfwWin.window, TRUE);
|
|
}
|
|
|
|
//========================================================================
|
|
// Window un-iconification
|
|
//========================================================================
|
|
|
|
void _glfwPlatformRestoreWindow(void)
|
|
{
|
|
if (!_glfwWin.fullscreen)
|
|
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..
|
|
CGLSetParameter(_glfwWin.cglContext,
|
|
kCGLCPSwapInterval,
|
|
(GLint*) &CGLparameter);
|
|
}
|
|
else
|
|
{
|
|
// ..or here
|
|
aglSetInteger(_glfwWin.aglContext,
|
|
AGL_SWAP_INTERVAL,
|
|
&AGLparameter);
|
|
}
|
|
}
|
|
|
|
//========================================================================
|
|
// Read back framebuffer parameters from the context
|
|
//========================================================================
|
|
|
|
#define _getAGLAttribute(aglAttributeName, variableName) \
|
|
{ \
|
|
GLint aglValue; \
|
|
aglDescribePixelFormat(_glfwWin.aglPixelFormat, aglAttributeName, &aglValue); \
|
|
variableName = aglValue; \
|
|
}
|
|
|
|
#define _getCGLAttribute(cglAttributeName, variableName) \
|
|
{ \
|
|
GLint cglValue; \
|
|
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
|
|
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));
|
|
}
|
|
}
|
|
|