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.
1275 lines
45 KiB
1275 lines
45 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 |
|
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)); |
|
} |
|
} |
|
|
|
|