Cocoa port start:

GHOST*Cocoa.mm & .h files creation
First Cocoa version of GHOST_SystemCocoa.mm
CMake files update to allow optional (WITH_COCOA option) Cocoa version build - disabled by default
SCons files are not updated to allow Cocoa build (the ghost .mm files)
This commit is contained in:
Damien Plisson
2009-09-30 08:47:39 +00:00
parent 2a21c1acbe
commit 570c187ba1
9 changed files with 2940 additions and 4 deletions

View File

@@ -81,6 +81,10 @@ OPTION(WITH_CXX_GUARDEDALLOC "Enable GuardedAlloc for C++ memory allocation" OFF
OPTION(WITH_BUILDINFO "Include extra build details" ON)
OPTION(WITH_INSTALL "Install accompanying scripts and language files needed to run blender" ON)
IF (APPLE)
OPTION(WITH_COCOA "Use Cocoa framework instead of deprecated Carbon" OFF)
ENDIF (APPLE)
IF(NOT WITH_GAMEENGINE AND WITH_PLAYER)
MESSAGE("WARNING: WITH_PLAYER needs WITH_GAMEENGINE")
ENDIF(NOT WITH_GAMEENGINE AND WITH_PLAYER)
@@ -402,6 +406,7 @@ IF(APPLE)
FIND_PACKAGE(OpenAL)
IF(OPENAL_FOUND)
SET(WITH_OPENAL ON)
SET(OPENAL_INCLUDE_DIR "${OPENAL_INCLUDE_DIR};${LIBDIR}/openal/include")
ELSE(OPENAL_FOUND)
SET(WITH_OPENAL OFF)
ENDIF(OPENAL_FOUND)
@@ -485,9 +490,13 @@ IF(APPLE)
SET(LLIBS stdc++ SystemStubs)
IF (WITH_COCOA)
SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -DGHOST_COCOA")
SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime")
ELSE (WITH_COCOA)
SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime")
ENDIF (WITH_COCOA)
IF(WITH_OPENMP)
SET(LLIBS "${LLIBS} -lgomp ")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp ")

View File

@@ -26,9 +26,18 @@
SET(INC . ../string)
FILE(GLOB SRC intern/*.cpp)
FILE(GLOB SRC intern/*.cpp intern/*.mm)
IF(APPLE)
IF(WITH_COCOA)
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCarbon.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCarbon.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCarbon.cpp")
ELSE(WITH_COCOA)
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCocoa.mm")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCocoa.mm")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCocoa.mm")
ENDIF(WITH_COCOA)
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerWin32.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemWin32.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowWin32.cpp")
@@ -41,6 +50,9 @@ ELSE(APPLE)
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCarbon.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCarbon.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCarbon.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCocoa.mm")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCocoa.mm")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCocoa.mm")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerX11.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemX11.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowX11.cpp")
@@ -52,6 +64,9 @@ ELSE(APPLE)
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCarbon.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCarbon.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCarbon.cpp")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCocoa.mm")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCocoa.mm")
LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCocoa.mm")
ENDIF(WIN32)
ENDIF(APPLE)

View File

@@ -0,0 +1,113 @@
/**
* $Id: GHOST_DisplayManagerCocoa.h 13161 2008-01-07 19:13:47Z hos $
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/**
* @file GHOST_DisplayManagerCocoa.h
* Declaration of GHOST_DisplayManagerCocoa class.
*/
#ifndef _GHOST_DISPLAY_MANAGER_COCOA_H_
#define _GHOST_DISPLAY_MANAGER_COCOA_H_
#ifndef __APPLE__
#error Apple only!
#endif // __APPLE__
#include "GHOST_DisplayManager.h"
/**
* Manages system displays (Mac OSX/Cocoa implementation).
* @see GHOST_DisplayManager
* @author Maarten Gribnau
* @date September 21, 2001
*/
class GHOST_DisplayManagerCocoa : public GHOST_DisplayManager
{
public:
/**
* Constructor.
*/
GHOST_DisplayManagerCocoa(void);
/**
* Returns the number of display devices on this system.
* @param numDisplays The number of displays on this system.
* @return Indication of success.
*/
virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const;
/**
* Returns the number of display settings for this display device.
* @param display The index of the display to query with 0 <= display < getNumDisplays().
* @param setting The number of settings of the display device with this index.
* @return Indication of success.
*/
virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const;
/**
* Returns the current setting for this display device.
* @param display The index of the display to query with 0 <= display < getNumDisplays().
* @param index The setting index to be returned.
* @param setting The setting of the display device with this index.
* @return Indication of success.
*/
virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const;
/**
* Returns the current setting for this display device.
* @param display The index of the display to query with 0 <= display < getNumDisplays().
* @param setting The current setting of the display device with this index.
* @return Indication of success.
*/
virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const;
/**
* Changes the current setting for this display device.
* @param display The index of the display to query with 0 <= display < getNumDisplays().
* @param setting The current setting of the display device with this index.
* @return Indication of success.
*/
virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting);
protected:
/**
* Returns a value from a dictionary.
* @param values Dictionary to return value from.
* @param key Key to return value for.
* @return The value for this key.
*/
long getValue(CFDictionaryRef values, CFStringRef key) const;
/** Cached number of displays. */
CGDisplayCount m_numDisplays;
/** Cached display id's for each display. */
CGDirectDisplayID* m_displayIDs;
};
#endif // _GHOST_DISPLAY_MANAGER_COCOA_H_

View File

@@ -0,0 +1,180 @@
/**
* $Id: GHOST_DisplayManagerCocoa.mm 13161 2008-01-07 19:13:47Z hos $
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/**
* $Id: GHOST_DisplayManagerCocoa.mm 13161 2008-01-07 19:13:47Z hos $
* Copyright (C) 2001 NaN Technologies B.V.
* @author Maarten Gribnau
* @date September 21, 2001
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Carbon/Carbon.h>
#include "GHOST_DisplayManagerCocoa.h"
#include "GHOST_Debug.h"
// We do not support multiple monitors at the moment
GHOST_DisplayManagerCocoa::GHOST_DisplayManagerCocoa(void)
{
if (::CGGetActiveDisplayList(0, NULL, &m_numDisplays) != CGDisplayNoErr)
{
m_numDisplays = 0;
m_displayIDs = NULL;
}
if (m_numDisplays > 0)
{
m_displayIDs = new CGDirectDisplayID [m_numDisplays];
GHOST_ASSERT((m_displayIDs!=NULL), "GHOST_DisplayManagerCocoa::GHOST_DisplayManagerCocoa(): memory allocation failed");
::CGGetActiveDisplayList(m_numDisplays, m_displayIDs, &m_numDisplays);
}
}
GHOST_TSuccess GHOST_DisplayManagerCocoa::getNumDisplays(GHOST_TUns8& numDisplays) const
{
numDisplays = (GHOST_TUns8) m_numDisplays;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_DisplayManagerCocoa::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const
{
GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getNumDisplaySettings(): only main display is supported");
CFArrayRef displayModes;
displayModes = ::CGDisplayAvailableModes(m_displayIDs[display]);
CFIndex numModes = ::CFArrayGetCount(displayModes);
numSettings = (GHOST_TInt32)numModes;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_DisplayManagerCocoa::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const
{
GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getDisplaySetting(): only main display is supported");
CFArrayRef displayModes;
CGDirectDisplayID d = m_displayIDs[display];
displayModes = ::CGDisplayAvailableModes(d);
//CFIndex numModes = ::CFArrayGetCount(displayModes);/*unused*/
//GHOST_TInt32 numSettings = (GHOST_TInt32)numModes; /*unused*/
CFDictionaryRef displayModeValues = (CFDictionaryRef)::CFArrayGetValueAtIndex(displayModes, index);
setting.xPixels = getValue(displayModeValues, kCGDisplayWidth);
setting.yPixels = getValue(displayModeValues, kCGDisplayHeight);
setting.bpp = getValue(displayModeValues, kCGDisplayBitsPerPixel);
setting.frequency = getValue(displayModeValues, kCGDisplayRefreshRate);
#ifdef GHOST_DEBUG
printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency);
#endif // GHOST_DEBUG
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const
{
GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(): only main display is supported");
CFDictionaryRef displayModeValues = ::CGDisplayCurrentMode(m_displayIDs[display]);
setting.xPixels = getValue(displayModeValues, kCGDisplayWidth);
setting.yPixels = getValue(displayModeValues, kCGDisplayHeight);
setting.bpp = getValue(displayModeValues, kCGDisplayBitsPerPixel);
setting.frequency = getValue(displayModeValues, kCGDisplayRefreshRate);
#ifdef GHOST_DEBUG
printf("current display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency);
#endif // GHOST_DEBUG
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting)
{
GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): only main display is supported");
#ifdef GHOST_DEBUG
printf("GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): requested settings:\n");
printf(" setting.xPixels=%d\n", setting.xPixels);
printf(" setting.yPixels=%d\n", setting.yPixels);
printf(" setting.bpp=%d\n", setting.bpp);
printf(" setting.frequency=%d\n", setting.frequency);
#endif // GHOST_DEBUG
CFDictionaryRef displayModeValues = ::CGDisplayBestModeForParametersAndRefreshRate(
m_displayIDs[display],
(size_t)setting.bpp,
(size_t)setting.xPixels,
(size_t)setting.yPixels,
(CGRefreshRate)setting.frequency,
NULL);
#ifdef GHOST_DEBUG
printf("GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): switching to:\n");
printf(" setting.xPixels=%d\n", getValue(displayModeValues, kCGDisplayWidth));
printf(" setting.yPixels=%d\n", getValue(displayModeValues, kCGDisplayHeight));
printf(" setting.bpp=%d\n", getValue(displayModeValues, kCGDisplayBitsPerPixel));
printf(" setting.frequency=%d\n", getValue(displayModeValues, kCGDisplayRefreshRate));
#endif // GHOST_DEBUG
CGDisplayErr err = ::CGDisplaySwitchToMode(m_displayIDs[display], displayModeValues);
return err == CGDisplayNoErr ? GHOST_kSuccess : GHOST_kFailure;
}
long GHOST_DisplayManagerCocoa::getValue(CFDictionaryRef values, CFStringRef key) const
{
CFNumberRef numberValue = (CFNumberRef) CFDictionaryGetValue(values, key);
if (!numberValue)
{
return -1;
}
long intValue;
if (!CFNumberGetValue(numberValue, kCFNumberLongType, &intValue))
{
return -1;
}
return intValue;
}

View File

@@ -44,7 +44,11 @@
# include "GHOST_SystemWin32.h"
#else
# ifdef __APPLE__
# include "GHOST_SystemCarbon.h"
# ifdef GHOST_COCOA
# include "GHOST_SystemCocoa.h"
# else
# include "GHOST_SystemCarbon.h"
# endif
# else
# include "GHOST_SystemX11.h"
# endif
@@ -62,7 +66,11 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
m_system = new GHOST_SystemWin32 ();
#else
# ifdef __APPLE__
m_system = new GHOST_SystemCarbon ();
# ifdef GHOST_COCOA
m_system = new GHOST_SystemCocoa ();
# else
m_system = new GHOST_SystemCarbon ();
# endif
# else
m_system = new GHOST_SystemX11 ();
# endif

View File

@@ -0,0 +1,274 @@
/**
* $Id: GHOST_SystemCocoa.h 20741 2009-06-08 20:08:19Z blendix $
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Maarten Gribnau 05/2001
* Damien Plisson 09/2009
*
* ***** END GPL LICENSE BLOCK *****
*/
/**
* @file GHOST_SystemCocoa.h
* Declaration of GHOST_SystemCocoa class.
*/
#ifndef _GHOST_SYSTEM_COCOA_H_
#define _GHOST_SYSTEM_COCOA_H_
#ifndef __APPLE__
#error Apple OSX only!
#endif // __APPLE__
//#define __CARBONSOUND__
#include "GHOST_System.h"
class GHOST_EventCursor;
class GHOST_EventKey;
class GHOST_EventWindow;
class GHOST_SystemCocoa : public GHOST_System {
public:
/**
* Constructor.
*/
GHOST_SystemCocoa();
/**
* Destructor.
*/
~GHOST_SystemCocoa();
/***************************************************************************************
** Time(r) functionality
***************************************************************************************/
/**
* Returns the system time.
* Returns the number of milliseconds since the start of the system process.
* Based on ANSI clock() routine.
* @return The number of milliseconds.
*/
virtual GHOST_TUns64 getMilliSeconds() const;
/***************************************************************************************
** Display/window management functionality
***************************************************************************************/
/**
* Returns the number of displays on this system.
* @return The number of displays.
*/
virtual GHOST_TUns8 getNumDisplays() const;
/**
* Returns the dimensions of the main display on this system.
* @return The dimension of the main display.
*/
virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const;
/**
* Create a new window.
* The new window is added to the list of windows managed.
* Never explicitly delete the window, use disposeWindow() instead.
* @param title The name of the window (displayed in the title bar of the window if the OS supports it).
* @param left The coordinate of the left edge of the window.
* @param top The coordinate of the top edge of the window.
* @param width The width the window.
* @param height The height the window.
* @param state The state of the window when opened.
* @param type The type of drawing context installed in this window.
* @param parentWindow Parent (embedder) window
* @return The new window (or 0 if creation failed).
*/
virtual GHOST_IWindow* createWindow(
const STR_String& title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
const bool stereoVisual,
const GHOST_TEmbedderWindowID parentWindow = 0
);
virtual GHOST_TSuccess beginFullScreen(
const GHOST_DisplaySetting& setting,
GHOST_IWindow** window,
const bool stereoVisual
);
virtual GHOST_TSuccess endFullScreen( void );
/***************************************************************************************
** Event management functionality
***************************************************************************************/
/**
* Gets events from the system and stores them in the queue.
* @param waitForEvent Flag to wait for an event (or return immediately).
* @return Indication of the presence of events.
*/
virtual bool processEvents(bool waitForEvent);
/***************************************************************************************
** Cursor management functionality
***************************************************************************************/
/**
* Returns the current location of the cursor (location in screen coordinates)
* @param x The x-coordinate of the cursor.
* @param y The y-coordinate of the cursor.
* @return Indication of success.
*/
virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const;
/**
* Updates the location of the cursor (location in screen coordinates).
* @param x The x-coordinate of the cursor.
* @param y The y-coordinate of the cursor.
* @return Indication of success.
*/
virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const;
/***************************************************************************************
** Access to mouse button and keyboard states.
***************************************************************************************/
/**
* Returns the state of all modifier keys.
* @param keys The state of all modifier keys (true == pressed).
* @return Indication of success.
*/
virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const;
/**
* Returns the state of the mouse buttons (ouside the message queue).
* @param buttons The state of the buttons.
* @return Indication of success.
*/
virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const;
/**
* Returns Clipboard data
* @param selection Indicate which buffer to return
* @return Returns the selected buffer
*/
virtual GHOST_TUns8* getClipboard(bool selection) const;
/**
* Puts buffer to system clipboard
* @param buffer The buffer to be copied
* @param selection Indicates which buffer to copy too, only used on X11
*/
virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const;
protected:
/**
* Initializes the system.
* For now, it justs registers the window class (WNDCLASS).
* @return A success value.
*/
virtual GHOST_TSuccess init();
/**
* Closes the system down.
* @return A success value.
*/
virtual GHOST_TSuccess exit();
/**
* Handles a tablet event.
* @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
* @return Indication whether the event was handled.
*/
int handleTabletEvent(void *eventPtr);
/**
* Handles a mouse event.
* @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
* @return Indication whether the event was handled.
*/
int handleMouseEvent(void *eventPtr);
/**
* Handles a key event.
* @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
* @return Indication whether the event was handled.
*/
int handleKeyEvent(void *eventPtr);
/**
* Handles a window event.
* @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
* @return Indication whether the event was handled.
*/
int handleWindowEvent(void *eventPtr);
/**
* Handles all basic Mac application stuff for a mouse down event.
* @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
* @return Indication whether the event was handled.
*/
// bool handleMouseDown(void *eventPtr);
/**
* Handles a Mac menu command.
* @param menuResult A Mac menu/item identifier.
* @return Indication whether the event was handled.
*/
// bool handleMenuCommand(GHOST_TInt32 menuResult);
/* callback for blender generated events */
// static OSStatus blendEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData);
/**
* Callback for Mac Timer tasks that expire.
* @param tmTask Pointer to the timer task that expired.
*/
//static void s_timerCallback(TMTaskPtr tmTask);
/** Cocoa autoReleasePool (void*) used for enablign standard C++ compilation */
void* autoReleasePool;
/** Event handler reference. */
//EventHandlerRef m_handler;
/** Start time at initialization. */
GHOST_TUns64 m_start_time;
/** Mouse buttons state */
GHOST_TUns32 m_pressedMouseButtons;
/** State of the modifiers. */
GHOST_TUns32 m_modifierMask;
/** Ignores window size messages (when window is dragged). */
bool m_ignoreWindowSizedMessages;
};
#endif // _GHOST_SYSTEM_COCOA_H_

View File

@@ -0,0 +1,1282 @@
/**
* $Id: GHOST_SystemCocoa.cpp 23296 2009-09-16 22:27:27Z broken $
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Maarten Gribnau 05/2001
* Damien Plisson 09/2009
*
* ***** END GPL LICENSE BLOCK *****
*/
#import <Cocoa/Cocoa.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include "GHOST_SystemCocoa.h"
#include "GHOST_DisplayManagerCocoa.h"
#include "GHOST_EventKey.h"
#include "GHOST_EventButton.h"
#include "GHOST_EventCursor.h"
#include "GHOST_EventWheel.h"
#include "GHOST_EventNDOF.h"
#include "GHOST_TimerManager.h"
#include "GHOST_TimerTask.h"
#include "GHOST_WindowManager.h"
#include "GHOST_WindowCocoa.h"
#include "GHOST_NDOFManager.h"
#include "AssertMacros.h"
#define GHOST_KEY_SWITCH(mac, ghost) { case (mac): ghostKey = (ghost); break; }
/* blender class and types events */
enum {
kEventClassBlender = 'blnd'
};
enum {
kEventBlenderNdofAxis = 1,
kEventBlenderNdofButtons = 2
};
#pragma mark KeyMap, mouse converters
const EventTypeSpec kEvents[] =
{
{ kEventClassAppleEvent, kEventAppleEvent },
/*
{ kEventClassApplication, kEventAppActivated },
{ kEventClassApplication, kEventAppDeactivated },
*/
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyRepeat },
{ kEventClassKeyboard, kEventRawKeyUp },
{ kEventClassKeyboard, kEventRawKeyModifiersChanged },
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseDragged },
{ kEventClassMouse, kEventMouseWheelMoved },
{ kEventClassWindow, kEventWindowClickZoomRgn } , /* for new zoom behaviour */
{ kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */
{ kEventClassWindow, kEventWindowExpand } , /* for new zoom behaviour */
{ kEventClassWindow, kEventWindowExpandAll }, /* for new zoom behaviour */
{ kEventClassWindow, kEventWindowClose },
{ kEventClassWindow, kEventWindowActivated },
{ kEventClassWindow, kEventWindowDeactivated },
{ kEventClassWindow, kEventWindowUpdate },
{ kEventClassWindow, kEventWindowBoundsChanged },
{ kEventClassBlender, kEventBlenderNdofAxis },
{ kEventClassBlender, kEventBlenderNdofButtons }
};
static GHOST_TButtonMask convertButton(EventMouseButton button)
{
switch (button) {
case 0:
return GHOST_kButtonMaskLeft;
case 1:
return GHOST_kButtonMaskRight;
case 2:
return GHOST_kButtonMaskMiddle;
case 3:
return GHOST_kButtonMaskButton4;
case 4:
return GHOST_kButtonMaskButton5;
default:
return GHOST_kButtonMaskLeft;
}
}
static GHOST_TKey convertKey(int rawCode, unsigned char asciiCharacter)
{
/* This bit of magic converts the rawCode into a virtual
* Mac key based on the current keyboard mapping, but
* without regard to the modifiers (so we don't get 'a'
* and 'A' for example.
*/
/* Map numpad based on rawcodes first, otherwise they
* look like non-numpad events.
* Added too: mapping the number keys, for french keyboards etc (ton)
*/
// printf("GHOST: vk: %d %c raw: %d\n", asciiCharacter, asciiCharacter, rawCode);
//FIXME : check rawcodes
switch (rawCode) {
case 18: return GHOST_kKey1;
case 19: return GHOST_kKey2;
case 20: return GHOST_kKey3;
case 21: return GHOST_kKey4;
case 23: return GHOST_kKey5;
case 22: return GHOST_kKey6;
case 26: return GHOST_kKey7;
case 28: return GHOST_kKey8;
case 25: return GHOST_kKey9;
case 29: return GHOST_kKey0;
case 82: return GHOST_kKeyNumpad0;
case 83: return GHOST_kKeyNumpad1;
case 84: return GHOST_kKeyNumpad2;
case 85: return GHOST_kKeyNumpad3;
case 86: return GHOST_kKeyNumpad4;
case 87: return GHOST_kKeyNumpad5;
case 88: return GHOST_kKeyNumpad6;
case 89: return GHOST_kKeyNumpad7;
case 91: return GHOST_kKeyNumpad8;
case 92: return GHOST_kKeyNumpad9;
case 65: return GHOST_kKeyNumpadPeriod;
case 76: return GHOST_kKeyNumpadEnter;
case 69: return GHOST_kKeyNumpadPlus;
case 78: return GHOST_kKeyNumpadMinus;
case 67: return GHOST_kKeyNumpadAsterisk;
case 75: return GHOST_kKeyNumpadSlash;
}
if ((asciiCharacter >= 'a') && (asciiCharacter <= 'z')) {
return (GHOST_TKey) (asciiCharacter - 'a' + GHOST_kKeyA);
} else if ((asciiCharacter >= '0') && (asciiCharacter <= '9')) {
return (GHOST_TKey) (asciiCharacter - '0' + GHOST_kKey0);
} else if (asciiCharacter==16) {
switch (rawCode) {
case 122: return GHOST_kKeyF1;
case 120: return GHOST_kKeyF2;
case 99: return GHOST_kKeyF3;
case 118: return GHOST_kKeyF4;
case 96: return GHOST_kKeyF5;
case 97: return GHOST_kKeyF6;
case 98: return GHOST_kKeyF7;
case 100: return GHOST_kKeyF8;
case 101: return GHOST_kKeyF9;
case 109: return GHOST_kKeyF10;
case 103: return GHOST_kKeyF11;
case 111: return GHOST_kKeyF12; // FIXME : Never get, is used for ejecting the CD!
}
} else {
switch (asciiCharacter) {
case kUpArrowCharCode: return GHOST_kKeyUpArrow;
case kDownArrowCharCode: return GHOST_kKeyDownArrow;
case kLeftArrowCharCode: return GHOST_kKeyLeftArrow;
case kRightArrowCharCode: return GHOST_kKeyRightArrow;
case kReturnCharCode: return GHOST_kKeyEnter;
case kBackspaceCharCode: return GHOST_kKeyBackSpace;
case kDeleteCharCode: return GHOST_kKeyDelete;
case kEscapeCharCode: return GHOST_kKeyEsc;
case kTabCharCode: return GHOST_kKeyTab;
case kSpaceCharCode: return GHOST_kKeySpace;
case kHomeCharCode: return GHOST_kKeyHome;
case kEndCharCode: return GHOST_kKeyEnd;
case kPageUpCharCode: return GHOST_kKeyUpPage;
case kPageDownCharCode: return GHOST_kKeyDownPage;
case '-': return GHOST_kKeyMinus;
case '=': return GHOST_kKeyEqual;
case ',': return GHOST_kKeyComma;
case '.': return GHOST_kKeyPeriod;
case '/': return GHOST_kKeySlash;
case ';': return GHOST_kKeySemicolon;
case '\'': return GHOST_kKeyQuote;
case '\\': return GHOST_kKeyBackslash;
case '[': return GHOST_kKeyLeftBracket;
case ']': return GHOST_kKeyRightBracket;
case '`': return GHOST_kKeyAccentGrave;
}
}
// printf("GHOST: unknown key: %d %d\n", vk, rawCode);
return GHOST_kKeyUnknown;
}
/* MacOSX returns a Roman charset with kEventParamKeyMacCharCodes
* as defined here: http://developer.apple.com/documentation/mac/Text/Text-516.html
* I am not sure how international this works...
* For cross-platform convention, we'll use the Latin ascii set instead.
* As defined at: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html
*
*/
static unsigned char convertRomanToLatin(unsigned char ascii)
{
if(ascii<128) return ascii;
switch(ascii) {
case 128: return 142;
case 129: return 143;
case 130: return 128;
case 131: return 201;
case 132: return 209;
case 133: return 214;
case 134: return 220;
case 135: return 225;
case 136: return 224;
case 137: return 226;
case 138: return 228;
case 139: return 227;
case 140: return 229;
case 141: return 231;
case 142: return 233;
case 143: return 232;
case 144: return 234;
case 145: return 235;
case 146: return 237;
case 147: return 236;
case 148: return 238;
case 149: return 239;
case 150: return 241;
case 151: return 243;
case 152: return 242;
case 153: return 244;
case 154: return 246;
case 155: return 245;
case 156: return 250;
case 157: return 249;
case 158: return 251;
case 159: return 252;
case 160: return 0;
case 161: return 176;
case 162: return 162;
case 163: return 163;
case 164: return 167;
case 165: return 183;
case 166: return 182;
case 167: return 223;
case 168: return 174;
case 169: return 169;
case 170: return 174;
case 171: return 180;
case 172: return 168;
case 173: return 0;
case 174: return 198;
case 175: return 216;
case 176: return 0;
case 177: return 177;
case 178: return 0;
case 179: return 0;
case 180: return 165;
case 181: return 181;
case 182: return 0;
case 183: return 0;
case 184: return 215;
case 185: return 0;
case 186: return 0;
case 187: return 170;
case 188: return 186;
case 189: return 0;
case 190: return 230;
case 191: return 248;
case 192: return 191;
case 193: return 161;
case 194: return 172;
case 195: return 0;
case 196: return 0;
case 197: return 0;
case 198: return 0;
case 199: return 171;
case 200: return 187;
case 201: return 201;
case 202: return 0;
case 203: return 192;
case 204: return 195;
case 205: return 213;
case 206: return 0;
case 207: return 0;
case 208: return 0;
case 209: return 0;
case 210: return 0;
case 214: return 247;
case 229: return 194;
case 230: return 202;
case 231: return 193;
case 232: return 203;
case 233: return 200;
case 234: return 205;
case 235: return 206;
case 236: return 207;
case 237: return 204;
case 238: return 211;
case 239: return 212;
case 240: return 0;
case 241: return 210;
case 242: return 218;
case 243: return 219;
case 244: return 217;
case 245: return 0;
case 246: return 0;
case 247: return 0;
case 248: return 0;
case 249: return 0;
case 250: return 0;
default: return 0;
}
}
#define FIRSTFILEBUFLG 512
static bool g_hasFirstFile = false;
static char g_firstFileBuf[512];
extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) {
if (g_hasFirstFile) {
strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1);
buf[FIRSTFILEBUFLG - 1] = '\0';
return 1;
} else {
return 0;
}
}
#pragma mark Cocoa objects
/**
* CocoaAppDelegate
* ObjC object to capture applicationShouldTerminate, and send quit event
**/
@interface CocoaAppDelegate : NSObject
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
@end
@implementation CocoaAppDelegate : NSObject
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
//Note that Cmd+Q is already handled by keyhandler
//FIXME: Cocoa_SendQuit();
return NSTerminateCancel;
}
@end
#pragma mark initialization/finalization
/***/
GHOST_SystemCocoa::GHOST_SystemCocoa()
{
m_modifierMask =0;
m_pressedMouseButtons =0;
m_displayManager = new GHOST_DisplayManagerCocoa ();
GHOST_ASSERT(m_displayManager, "GHOST_SystemCocoa::GHOST_SystemCocoa(): m_displayManager==0\n");
m_displayManager->initialize();
//NSEvent timeStamp is given in system uptime, state start date is boot time
//FIXME : replace by Cocoa equivalent
int mib[2];
struct timeval boottime;
size_t len;
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
len = sizeof(struct timeval);
sysctl(mib, 2, &boottime, &len, NULL, 0);
m_start_time = ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
m_ignoreWindowSizedMessages = false;
}
GHOST_SystemCocoa::~GHOST_SystemCocoa()
{
}
GHOST_TSuccess GHOST_SystemCocoa::init()
{
GHOST_TSuccess success = GHOST_System::init();
if (success) {
//ProcessSerialNumber psn;
//FIXME: Carbon stuff to move window & menu to foreground
/*if (!GetCurrentProcess(&psn)) {
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
}*/
autoReleasePool = [[NSAutoreleasePool alloc] init];
if (NSApp == nil) {
[NSApplication sharedApplication];
if ([NSApp mainMenu] == nil) {
//FIXME: CreateApplicationMenus();
printf("Creating main menu");
}
[NSApp finishLaunching];
}
if ([NSApp delegate] == nil) {
[NSApp setDelegate:[[CocoaAppDelegate alloc] init]];
}
/*
* Initialize the cursor to the standard arrow shape (so that we can change it later on).
* This initializes the cursor's visibility counter to 0.
*/
/*::InitCursor();
MenuRef windMenu;
::CreateStandardWindowMenu(0, &windMenu);
::InsertMenu(windMenu, 0);
::DrawMenuBar();
::InstallApplicationEventHandler(sEventHandlerProc, GetEventTypeCount(kEvents), kEvents, this, &m_handler);
::AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, sAEHandlerLaunch, (SInt32) this, false);
::AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, sAEHandlerOpenDocs, (SInt32) this, false);
::AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, sAEHandlerPrintDocs, (SInt32) this, false);
::AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, sAEHandlerQuit, (SInt32) this, false);
*/
}
return success;
}
GHOST_TSuccess GHOST_SystemCocoa::exit()
{
NSAutoreleasePool* pool = (NSAutoreleasePool *)autoReleasePool;
[pool release];
return GHOST_System::exit();
}
#pragma mark window management
GHOST_TUns64 GHOST_SystemCocoa::getMilliSeconds() const
{
//FIXME : replace by Cocoa equivalent
int mib[2];
struct timeval boottime;
size_t len;
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
len = sizeof(struct timeval);
sysctl(mib, 2, &boottime, &len, NULL, 0);
return ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
}
GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const
{
//Note that OS X supports monitor hot plug
// We do not support multiple monitors at the moment
return [[NSScreen screens] count];
}
void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
{
//TODO: Provide visible frame or total frame, check for consistency with rest of code
NSRect frame = [[NSScreen mainScreen] visibleFrame];
width = frame.size.width;
height = frame.size.height;
}
GHOST_IWindow* GHOST_SystemCocoa::createWindow(
const STR_String& title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
bool stereoVisual,
const GHOST_TEmbedderWindowID parentWindow
)
{
GHOST_IWindow* window = 0;
window = new GHOST_WindowCocoa (title, left, top, width, height, state, type);
if (window) {
if (window->getValid()) {
// Store the pointer to the window
GHOST_ASSERT(m_windowManager, "m_windowManager not initialized");
m_windowManager->addWindow(window);
m_windowManager->setActiveWindow(window);
pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
}
else {
GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
delete window;
window = 0;
}
}
else {
GHOST_PRINT("GHOST_SystemCocoa::createWindow(): could not create window\n");
}
return window;
}
GHOST_TSuccess GHOST_SystemCocoa::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual)
{
GHOST_TSuccess success = GHOST_kFailure;
//TODO: update this method
// need yo make this Carbon all on 10.5 for fullscreen to work correctly
CGCaptureAllDisplays();
success = GHOST_System::beginFullScreen( setting, window, stereoVisual);
if( success != GHOST_kSuccess ) {
// fullscreen failed for other reasons, release
CGReleaseAllDisplays();
}
return success;
}
GHOST_TSuccess GHOST_SystemCocoa::endFullScreen(void)
{
//TODO: update this method
CGReleaseAllDisplays();
return GHOST_System::endFullScreen();
}
GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
{
NSPoint mouseLoc = [NSEvent mouseLocation];
// Convert the coordinates to screen coordinates
x = (GHOST_TInt32)mouseLoc.x;
y = (GHOST_TInt32)mouseLoc.y;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
{
float xf=(float)x, yf=(float)y;
//TODO:cocoatize this
CGAssociateMouseAndMouseCursorPosition(false);
CGSetLocalEventsSuppressionInterval(0);
CGWarpMouseCursorPosition(CGPointMake(xf, yf));
CGAssociateMouseAndMouseCursorPosition(true);
//this doesn't work properly, see game engine mouse-look scripts
// CGWarpMouseCursorPosition(CGPointMake(xf, yf));
// this call below sends event, but empties other events (like shift)
// CGPostMouseEvent(CGPointMake(xf, yf), TRUE, 1, FALSE, 0);
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) const
{
NSUInteger modifiers = [[NSApp currentEvent] modifierFlags];
//Direct query to modifierFlags can be used in 10.6
keys.set(GHOST_kModifierKeyCommand, (modifiers & NSCommandKeyMask) ? true : false);
keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & NSAlternateKeyMask) ? true : false);
keys.set(GHOST_kModifierKeyLeftShift, (modifiers & NSShiftKeyMask) ? true : false);
keys.set(GHOST_kModifierKeyLeftControl, (modifiers & NSControlKeyMask) ? true : false);
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemCocoa::getButtons(GHOST_Buttons& buttons) const
{
buttons.clear();
buttons.set(GHOST_kButtonMaskLeft, m_pressedMouseButtons & GHOST_kButtonMaskLeft);
buttons.set(GHOST_kButtonMaskRight, m_pressedMouseButtons & GHOST_kButtonMaskRight);
buttons.set(GHOST_kButtonMaskMiddle, m_pressedMouseButtons & GHOST_kButtonMaskMiddle);
buttons.set(GHOST_kButtonMaskButton4, m_pressedMouseButtons & GHOST_kButtonMaskButton4);
buttons.set(GHOST_kButtonMaskButton5, m_pressedMouseButtons & GHOST_kButtonMaskButton5);
return GHOST_kSuccess;
}
#pragma mark Event handlers
/**
* The event queue polling function
*/
bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
{
bool anyProcessed = false;
NSEvent *event;
// SetMouseCoalescingEnabled(false, NULL);
//TODO : implement timer ??
do {
//GHOST_TimerManager* timerMgr = getTimerManager();
/*
if (waitForEvent) {
GHOST_TUns64 next = timerMgr->nextFireTime();
double timeOut;
if (next == GHOST_kFireTimeNever) {
timeOut = kEventDurationForever;
} else {
timeOut = (double)(next - getMilliSeconds())/1000.0;
if (timeOut < 0.0)
timeOut = 0.0;
}
::ReceiveNextEvent(0, NULL, timeOut, false, &event);
}
if (timerMgr->fireTimers(getMilliSeconds())) {
anyProcessed = true;
}
//TODO: check fullscreen redrawing issues
if (getFullScreen()) {
// Check if the full-screen window is dirty
GHOST_IWindow* window = m_windowManager->getFullScreenWindow();
if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) {
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
anyProcessed = true;
}
}*/
do {
event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (event==nil)
break;
anyProcessed = true;
switch ([event type]) {
case NSKeyDown:
case NSKeyUp:
case NSFlagsChanged:
handleKeyEvent(event);
/* Support system-wide keyboard shortcuts, like Exposé, ...) */
/* if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged) {
[NSApp sendEvent:event];
}*/
break;
case NSLeftMouseDown:
case NSLeftMouseUp:
case NSRightMouseDown:
case NSRightMouseUp:
case NSMouseMoved:
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSScrollWheel:
case NSOtherMouseDown:
case NSOtherMouseUp:
case NSOtherMouseDragged:
handleMouseEvent(event);
break;
case NSTabletPoint:
case NSTabletProximity:
handleTabletEvent(event);
break;
/* Trackpad features, will need OS X 10.6 for implementation
case NSEventTypeGesture:
case NSEventTypeMagnify:
case NSEventTypeSwipe:
case NSEventTypeRotate:
case NSEventTypeBeginGesture:
case NSEventTypeEndGesture:
break; */
/*Unused events
NSMouseEntered = 8,
NSMouseExited = 9,
NSAppKitDefined = 13,
NSSystemDefined = 14,
NSApplicationDefined = 15,
NSPeriodic = 16,
NSCursorUpdate = 17,*/
default:
break;
}
//Resend event to NSApp to ensure Mac wide events are handled
[NSApp sendEvent:event];
} while (event!= nil);
} while (waitForEvent && !anyProcessed);
return anyProcessed;
}
//TODO: To be called from NSWindow delegate
int GHOST_SystemCocoa::handleWindowEvent(void *eventPtr)
{
int err = eventNotHandledErr;
/*WindowRef windowRef;
GHOST_WindowCocoa *window;
// Check if the event was send to a GHOST window
::GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &windowRef);
window = (GHOST_WindowCarbon*) ::GetWRefCon(windowRef);
if (!validWindow(window)) {
return err;
}
//if (!getFullScreen()) {
err = noErr;
switch([event ])
{
case kEventWindowClose:
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) );
break;
case kEventWindowActivated:
m_windowManager->setActiveWindow(window);
window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) );
break;
case kEventWindowDeactivated:
m_windowManager->setWindowInactive(window);
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) );
break;
case kEventWindowUpdate:
//if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n");
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
break;
case kEventWindowBoundsChanged:
if (!m_ignoreWindowSizedMessages)
{
window->updateDrawingContext();
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
}
break;
default:
err = eventNotHandledErr;
break;
}
// }
//else {
//window = (GHOST_WindowCarbon*) m_windowManager->getFullScreenWindow();
//GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n");
//::RemoveEventFromQueue(::GetMainEventQueue(), event);
//}
*/
return err;
}
int GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
{
NSEvent *event = (NSEvent *)eventPtr;
GHOST_IWindow* window = m_windowManager->getActiveWindow();
GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
ct.Pressure = 0;
ct.Xtilt = 0;
ct.Ytilt = 0;
switch ([event type]) {
case NSTabletPoint:
ct.Pressure = [event tangentialPressure];
ct.Xtilt = [event tilt].x;
ct.Ytilt = [event tilt].y;
break;
case NSTabletProximity:
if ([event isEnteringProximity])
{
//pointer is entering tablet area proximity
switch ([event pointingDeviceType]) {
case NSPenPointingDevice:
ct.Active = GHOST_kTabletModeStylus;
break;
case NSEraserPointingDevice:
ct.Active = GHOST_kTabletModeEraser;
break;
case NSCursorPointingDevice:
case NSUnknownPointingDevice:
default:
ct.Active = GHOST_kTabletModeNone;
break;
}
} else {
// pointer is leaving - return to mouse
ct.Active = GHOST_kTabletModeNone;
}
break;
default:
GHOST_ASSERT(FALSE,"GHOST_SystemCocoa::handleTabletEvent : unknown event received");
break;
}
return noErr;
}
int GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
{
NSEvent *event = (NSEvent *)eventPtr;
GHOST_IWindow* window = m_windowManager->getActiveWindow();
switch ([event type])
{
//TODO: check for tablet subtype events
case NSLeftMouseDown:
case NSRightMouseDown:
case NSOtherMouseDown:
if (m_windowManager->getActiveWindow()) {
pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonDown, window, convertButton([event buttonNumber])));
}
break;
case NSLeftMouseUp:
case NSRightMouseUp:
case NSOtherMouseUp:
if (m_windowManager->getActiveWindow()) {
pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonUp, window, convertButton([event buttonNumber])));
}
break;
case NSMouseMoved:
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged:
{
NSPoint mousePos = [event locationInWindow];
pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y));
break;
}
case NSScrollWheel:
{
GHOST_TInt32 delta;
delta = [event deltaY] > 0 ? 1 : -1;
pushEvent(new GHOST_EventWheel(getMilliSeconds(), window, delta));
}
break;
}
return noErr;
}
int GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
{
NSEvent *event = (NSEvent *)eventPtr;
OSStatus err = eventNotHandledErr;
GHOST_IWindow* window = m_windowManager->getActiveWindow();
NSUInteger modifiers;
unsigned short rawCode;
GHOST_TKey key;
unsigned char ascii;
/* Can happen, very rarely - seems to only be when command-H makes
* the window go away and we still get an HKey up.
*/
if (!window) {
//::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode);
//key = convertKey(rawCode);
return err;
}
err = noErr;
switch ([event type]) {
case NSKeyDown:
case NSKeyUp:
rawCode = [event keyCode];
ascii = [[event characters] characterAtIndex:0];
key = convertKey(rawCode,ascii);
ascii= convertRomanToLatin(ascii);
if ([event type] == NSKeyDown) {
pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyDown, window, key, ascii) );
} else {
pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyUp, window, key, ascii) );
}
break;
case NSFlagsChanged:
modifiers = [event modifierFlags];
if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) );
}
if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) {
pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSControlKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) );
}
if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) {
pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) );
}
if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) );
}
m_modifierMask = modifiers;
break;
default:
err = eventNotHandledErr;
break;
}
return err;
}
/* System wide mouse clicks are handled directly through systematic event forwarding to Cocoa
bool GHOST_SystemCarbon::handleMouseDown(void *eventPtr)
{
NSEvent *event = (NSEvent *)eventPtr;
WindowPtr window;
short part;
BitMap screenBits;
bool handled = true;
GHOST_WindowCarbon* ghostWindow;
Point mousePos = {0 , 0};
::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos);
part = ::FindWindow(mousePos, &window);
ghostWindow = (GHOST_WindowCarbon*) ::GetWRefCon(window);
switch (part) {
case inMenuBar:
handleMenuCommand(::MenuSelect(mousePos));
break;
case inDrag:
// *
// * The DragWindow() routine creates a lot of kEventWindowBoundsChanged
// * events. By setting m_ignoreWindowSizedMessages these are suppressed.
// * @see GHOST_SystemCarbon::handleWindowEvent(EventRef event)
// *
// even worse: scale window also generates a load of events, and nothing
// is handled (read: client's event proc called) until you release mouse (ton)
GHOST_ASSERT(validWindow(ghostWindow), "GHOST_SystemCarbon::handleMouseDown: invalid window");
m_ignoreWindowSizedMessages = true;
::DragWindow(window, mousePos, &GetQDGlobalsScreenBits(&screenBits)->bounds);
m_ignoreWindowSizedMessages = false;
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, ghostWindow) );
break;
case inContent:
if (window != ::FrontWindow()) {
::SelectWindow(window);
//
// * We add a mouse down event on the newly actived window
// *
//GHOST_PRINT("GHOST_SystemCarbon::handleMouseDown(): adding mouse down event, " << ghostWindow << "\n");
EventMouseButton button;
::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonDown, ghostWindow, convertButton(button)));
} else {
handled = false;
}
break;
case inGoAway:
GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
if (::TrackGoAway(window, mousePos))
{
// todo: add option-close, because itÿs in the HIG
// if (event.modifiers & optionKey) {
// Close the clean documents, others will be confirmed one by one.
//}
// else {
pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, ghostWindow));
//}
}
break;
case inGrow:
GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
::ResizeWindow(window, mousePos, NULL, NULL);
break;
case inZoomIn:
case inZoomOut:
GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
if (::TrackBox(window, mousePos, part)) {
int macState;
macState = ghostWindow->getMac_windowState();
if ( macState== 0)
::ZoomWindow(window, part, true);
else
if (macState == 2) { // always ok
::ZoomWindow(window, part, true);
ghostWindow->setMac_windowState(1);
} else { // need to force size again
// GHOST_TUns32 scr_x,scr_y; //unused
Rect outAvailableRect;
ghostWindow->setMac_windowState(2);
::GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect);
//this->getMainDisplayDimensions(scr_x,scr_y);
::SizeWindow (window, outAvailableRect.right-outAvailableRect.left,outAvailableRect.bottom-outAvailableRect.top-1,false);
::MoveWindow (window, outAvailableRect.left, outAvailableRect.top,true);
}
}
break;
default:
handled = false;
break;
}
return handled;
}
bool GHOST_SystemCarbon::handleMenuCommand(GHOST_TInt32 menuResult)
{
short menuID;
short menuItem;
UInt32 command;
bool handled;
OSErr err;
menuID = HiWord(menuResult);
menuItem = LoWord(menuResult);
err = ::GetMenuItemCommandID(::GetMenuHandle(menuID), menuItem, &command);
handled = false;
if (err || command == 0) {
}
else {
switch(command) {
}
}
::HiliteMenu(0);
return handled;
}*/
#pragma mark Clipboard get/set
GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const
{
GHOST_TUns8 * temp_buff;
size_t pastedTextSize;
NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
if (pasteBoard = nil) {
return NULL;
}
NSArray *supportedTypes =
[NSArray arrayWithObjects: @"public.utf8-plain-text", nil];
NSString *bestType = [[NSPasteboard generalPasteboard]
availableTypeFromArray:supportedTypes];
if (bestType == nil) { return NULL; }
NSString * textPasted = [pasteBoard stringForType:@"public.utf8-plain-text"];
pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1);
if (temp_buff == NULL) return NULL;
strncpy((char*)temp_buff, [textPasted UTF8String], pastedTextSize);
temp_buff[pastedTextSize] = '\0';
if(temp_buff) {
return temp_buff;
} else {
return NULL;
}
}
void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
{
NSString *textToCopy;
if(selection) {return;} // for copying the selection, used on X11
NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
if (pasteBoard = nil) {
return;
}
NSArray *supportedTypes = [NSArray arrayWithObjects: @"public.utf8-plain-text",nil];
[pasteBoard declareTypes:supportedTypes owner:nil];
textToCopy = [NSString stringWithUTF8String:buffer];
[pasteBoard setString:textToCopy forType:@"public.utf8-plain-text"];
}
#pragma mark Carbon stuff to remove
#ifdef WITH_CARBON
OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
{
//GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
return noErr;
}
OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
{
//GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
AEDescList docs;
SInt32 ndocs;
OSErr err;
err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs);
if (err != noErr) return err;
err = AECountItems(&docs, &ndocs);
if (err==noErr) {
int i;
for (i=0; i<ndocs; i++) {
FSSpec fss;
AEKeyword kwd;
DescType actType;
Size actSize;
err = AEGetNthPtr(&docs, i+1, typeFSS, &kwd, &actType, &fss, sizeof(fss), &actSize);
if (err!=noErr)
break;
if (i==0) {
FSRef fsref;
if (FSpMakeFSRef(&fss, &fsref)!=noErr)
break;
if (FSRefMakePath(&fsref, (UInt8*) g_firstFileBuf, sizeof(g_firstFileBuf))!=noErr)
break;
g_hasFirstFile = true;
}
}
}
AEDisposeDesc(&docs);
return err;
}
OSErr GHOST_SystemCarbon::sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
{
//GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
return noErr;
}
OSErr GHOST_SystemCarbon::sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
{
GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
sys->pushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) );
return noErr;
}
OSStatus GHOST_SystemCarbon::sEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData)
{
GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) userData;
OSStatus err = eventNotHandledErr;
GHOST_IWindow* window;
GHOST_TEventNDOFData data;
UInt32 kind;
switch (::GetEventClass(event))
{
case kEventClassAppleEvent:
EventRecord eventrec;
if (ConvertEventRefToEventRecord(event, &eventrec)) {
err = AEProcessAppleEvent(&eventrec);
}
break;
case kEventClassMouse:
err = sys->handleMouseEvent(event);
break;
case kEventClassWindow:
err = sys->handleWindowEvent(event);
break;
case kEventClassKeyboard:
err = sys->handleKeyEvent(event);
break;
case kEventClassBlender :
window = sys->m_windowManager->getActiveWindow();
sys->m_ndofManager->GHOST_NDOFGetDatas(data);
kind = ::GetEventKind(event);
switch (kind)
{
case 1:
sys->m_eventManager->pushEvent(new GHOST_EventNDOF(sys->getMilliSeconds(), GHOST_kEventNDOFMotion, window, data));
// printf("motion\n");
break;
case 2:
sys->m_eventManager->pushEvent(new GHOST_EventNDOF(sys->getMilliSeconds(), GHOST_kEventNDOFButton, window, data));
// printf("button\n");
break;
}
err = noErr;
break;
default :
;
break;
}
return err;
}
#endif

View File

@@ -0,0 +1,308 @@
/**
* $Id: GHOST_WindowCocoa.h 13161 2008-01-07 19:13:47Z hos $
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/**
* @file GHOST_WindowCocoa.h
* Declaration of GHOST_WindowCocoa class.
*/
#ifndef _GHOST_WINDOW_COCOA_H_
#define _GHOST_WINDOW_COCOA_H_
#ifndef __APPLE__
#error Apple OSX only!
#endif // __APPLE__
#include "GHOST_Window.h"
#include "STR_String.h"
#include <AGL/agl.h>
/**
* Window on Mac OSX/Cocoa.
* Carbon windows have a size widget in the lower right corner of the window.
* To force it to be visible, the height of the client rectangle is reduced so
* that applications do not draw in that area. GHOST will manage that area
* which is called the gutter.
* When OpenGL contexts are active, GHOST will use AGL_BUFFER_RECT to prevent
* OpenGL drawing outside the reduced client rectangle.
* @author Maarten Gribnau
* @date May 23, 2001
*/
class GHOST_WindowCocoa : public GHOST_Window {
public:
/**
* Constructor.
* Creates a new window and opens it.
* To check if the window was created properly, use the getValid() method.
* @param title The text shown in the title bar of the window.
* @param left The coordinate of the left edge of the window.
* @param top The coordinate of the top edge of the window.
* @param width The width the window.
* @param height The height the window.
* @param state The state the window is initially opened with.
* @param type The type of drawing context installed in this window.
* @param stereoVisual Stereo visual for quad buffered stereo.
*/
GHOST_WindowCocoa(
const STR_String& title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
const bool stereoVisual = false
);
/**
* Destructor.
* Closes the window and disposes resources allocated.
*/
virtual ~GHOST_WindowCocoa();
/**
* Returns indication as to whether the window is valid.
* @return The validity of the window.
*/
virtual bool getValid() const;
/**
* Sets the title displayed in the title bar.
* @param title The title to display in the title bar.
*/
virtual void setTitle(const STR_String& title);
/**
* Returns the title displayed in the title bar.
* @param title The title displayed in the title bar.
*/
virtual void getTitle(STR_String& title) const;
/**
* Returns the window rectangle dimensions.
* The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
* @param bounds The bounding rectangle of the window.
*/
virtual void getWindowBounds(GHOST_Rect& bounds) const;
/**
* Returns the client rectangle dimensions.
* The left and top members of the rectangle are always zero.
* @param bounds The bounding rectangle of the cleient area of the window.
*/
virtual void getClientBounds(GHOST_Rect& bounds) const;
/**
* Resizes client rectangle width.
* @param width The new width of the client area of the window.
*/
virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width);
/**
* Resizes client rectangle height.
* @param height The new height of the client area of the window.
*/
virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height);
/**
* Resizes client rectangle.
* @param width The new width of the client area of the window.
* @param height The new height of the client area of the window.
*/
virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height);
/**
* Returns the state of the window (normal, minimized, maximized).
* @return The state of the window.
*/
virtual GHOST_TWindowState getState() const;
/**
* Converts a point in screen coordinates to client rectangle coordinates
* @param inX The x-coordinate on the screen.
* @param inY The y-coordinate on the screen.
* @param outX The x-coordinate in the client rectangle.
* @param outY The y-coordinate in the client rectangle.
*/
virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const;
/**
* Converts a point in screen coordinates to client rectangle coordinates
* @param inX The x-coordinate in the client rectangle.
* @param inY The y-coordinate in the client rectangle.
* @param outX The x-coordinate on the screen.
* @param outY The y-coordinate on the screen.
*/
virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const;
/**
* Sets the state of the window (normal, minimized, maximized).
* @param state The state of the window.
* @return Indication of success.
*/
virtual GHOST_TSuccess setState(GHOST_TWindowState state);
/**
* Sets the order of the window (bottom, top).
* @param order The order of the window.
* @return Indication of success.
*/
virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order);
/**
* Swaps front and back buffers of a window.
* @return A boolean success indicator.
*/
virtual GHOST_TSuccess swapBuffers();
/**
* Updates the drawing context of this window. Needed
* whenever the window is changed.
* @return Indication of success.
*/
GHOST_TSuccess updateDrawingContext();
/**
* Activates the drawing context of this window.
* @return A boolean success indicator.
*/
virtual GHOST_TSuccess activateDrawingContext();
virtual void loadCursor(bool visible, GHOST_TStandardCursor cursor) const;
/**
* Returns the dirty state of the window when in full-screen mode.
* @return Whether it is dirty.
*/
virtual bool getFullScreenDirty();
/* accessor for fullscreen window */
virtual void setMac_windowState(short value);
virtual short getMac_windowState();
const GHOST_TabletData* GetTabletData()
{ return &m_tablet; }
GHOST_TabletData& GetCocoaTabletData()
{ return m_tablet; }
protected:
/**
* Tries to install a rendering context in this window.
* @param type The type of rendering context installed.
* @return Indication as to whether installation has succeeded.
*/
virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type);
/**
* Removes the current drawing context.
* @return Indication as to whether removal has succeeded.
*/
virtual GHOST_TSuccess removeDrawingContext();
/**
* Invalidates the contents of this window.
* @return Indication of success.
*/
virtual GHOST_TSuccess invalidate();
/**
* Sets the cursor visibility on the window using
* native window system calls.
*/
virtual GHOST_TSuccess setWindowCursorVisibility(bool visible);
/**
* Sets the cursor shape on the window using
* native window system calls.
*/
virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
/**
* Sets the cursor shape on the window using
* native window system calls.
*/
virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color);
virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY);
/**
* Converts a string object to a Mac Pascal string.
* @param in The string object to be converted.
* @param out The converted string.
*/
virtual void gen2mac(const STR_String& in, Str255 out) const;
/**
* Converts a Mac Pascal string to a string object.
* @param in The string to be converted.
* @param out The converted string object.
*/
virtual void mac2gen(const Str255 in, STR_String& out) const;
WindowRef m_windowRef;
CGrafPtr m_grafPtr;
AGLContext m_aglCtx;
/** The first created OpenGL context (for sharing display lists) */
static AGLContext s_firstaglCtx;
Cursor* m_customCursor;
GHOST_TabletData m_tablet;
/** When running in full-screen this tells whether to refresh the window. */
bool m_fullScreenDirty;
/** specific MacOs X full screen window setting as we use partially system mechanism
values : 0 not maximizable default
1 normal state
2 maximized state
this will be reworked when rebuilding GHOST carbon to use new OS X apis
in order to be unified with GHOST fullscreen/maximised settings
(lukep)
**/
short mac_windowState;
/**
* The width/height of the size rectangle in the lower right corner of a
* Mac/Carbon window. This is also the height of the gutter area.
*/
#ifdef GHOST_DRAW_CARBON_GUTTER
static const GHOST_TInt32 s_sizeRectSize;
#endif // GHOST_DRAW_CARBON_GUTTER
};
#endif // _GHOST_WINDOW_COCOA_H_

View File

@@ -0,0 +1,747 @@
/**
* $Id: GHOST_WindowCocoa.mm 23275 2009-09-16 15:55:00Z campbellbarton $
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/**
* $Id: GHOST_WindowCocoa.mm 23275 2009-09-16 15:55:00Z campbellbarton $
* Copyright (C) 2001 NaN Technologies B.V.
* @author Maarten Gribnau
* @date May 10, 2001
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Carbon/Carbon.h>
#include "GHOST_WindowCocoa.h"
#include "GHOST_Debug.h"
AGLContext GHOST_WindowCocoa::s_firstaglCtx = NULL;
#ifdef GHOST_DRAW_CARBON_GUTTER
const GHOST_TInt32 GHOST_WindowCocoa::s_sizeRectSize = 16;
#endif //GHOST_DRAW_CARBON_GUTTER
static const GLint sPreferredFormatWindow[8] = {
AGL_RGBA,
AGL_DOUBLEBUFFER,
AGL_ACCELERATED,
AGL_DEPTH_SIZE, 32,
AGL_NONE,
};
static const GLint sPreferredFormatFullScreen[9] = {
AGL_RGBA,
AGL_DOUBLEBUFFER,
AGL_ACCELERATED,
AGL_FULLSCREEN,
AGL_DEPTH_SIZE, 32,
AGL_NONE,
};
WindowRef ugly_hack=NULL;
const EventTypeSpec kWEvents[] = {
{ kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */
};
static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) {
WindowRef mywindow;
GHOST_WindowCocoa *ghost_window;
OSStatus err;
int theState;
if (::GetEventKind(event) == kEventWindowZoom) {
err = ::GetEventParameter (event,kEventParamDirectObject,typeWindowRef,NULL,sizeof(mywindow),NULL, &mywindow);
ghost_window = (GHOST_WindowCocoa *) GetWRefCon(mywindow);
theState = ghost_window->getMac_windowState();
if (theState == 1)
ghost_window->setMac_windowState(2);
else if (theState == 2)
ghost_window->setMac_windowState(1);
}
return eventNotHandledErr;
}
GHOST_WindowCocoa::GHOST_WindowCocoa(
const STR_String& title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
const bool stereoVisual
) :
GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone),
m_windowRef(0),
m_grafPtr(0),
m_aglCtx(0),
m_customCursor(0),
m_fullScreenDirty(false)
{
Str255 title255;
OSStatus err;
//fprintf(stderr," main screen top %i left %i height %i width %i\n", top, left, height, width);
if (state >= GHOST_kWindowState8Normal ) {
if(state == GHOST_kWindowState8Normal) state= GHOST_kWindowStateNormal;
else if(state == GHOST_kWindowState8Maximized) state= GHOST_kWindowStateMaximized;
else if(state == GHOST_kWindowState8Minimized) state= GHOST_kWindowStateMinimized;
else if(state == GHOST_kWindowState8FullScreen) state= GHOST_kWindowStateFullScreen;
// state = state - 8; this was the simple version of above code, doesnt work in gcc 4.0
setMac_windowState(1);
} else
setMac_windowState(0);
if (state != GHOST_kWindowStateFullScreen) {
Rect bnds = { top, left, top+height, left+width };
// Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/
gen2mac(title, title255);
err = ::CreateNewWindow( kDocumentWindowClass,
kWindowStandardDocumentAttributes+kWindowLiveResizeAttribute,
&bnds,
&m_windowRef);
if ( err != noErr) {
fprintf(stderr," error creating window %i \n",err);
} else {
::SetWRefCon(m_windowRef,(SInt32)this);
setTitle(title);
err = InstallWindowEventHandler (m_windowRef, myWEventHandlerProc, GetEventTypeCount(kWEvents), kWEvents,NULL,NULL);
if ( err != noErr) {
fprintf(stderr," error creating handler %i \n",err);
} else {
// ::TransitionWindow (m_windowRef,kWindowZoomTransitionEffect,kWindowShowTransitionAction,NULL);
::ShowWindow(m_windowRef);
::MoveWindow (m_windowRef, left, top,true);
}
}
if (m_windowRef) {
m_grafPtr = ::GetWindowPort(m_windowRef);
setDrawingContextType(type);
updateDrawingContext();
activateDrawingContext();
}
if(ugly_hack==NULL) {
ugly_hack= m_windowRef;
// when started from commandline, window remains in the back... also for play anim
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
SetFrontProcess(&psn);
}
}
else {
/*
Rect bnds = { top, left, top+height, left+width };
gen2mac("", title255);
m_windowRef = ::NewCWindow(
nil, // Storage
&bnds, // Bounding rectangle of the window
title255, // Title of the window
0, // Window initially visible
plainDBox, // procID
(WindowRef)-1L, // Put window before all other windows
0, // Window has minimize box
(SInt32)this); // Store a pointer to the class in the refCon
*/
//GHOST_PRINT("GHOST_WindowCocoa::GHOST_WindowCocoa(): creating full-screen OpenGL context\n");
setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);;installDrawingContext(GHOST_kDrawingContextTypeOpenGL);
updateDrawingContext();
activateDrawingContext();
m_tablet.Active = GHOST_kTabletModeNone;
}
}
GHOST_WindowCocoa::~GHOST_WindowCocoa()
{
if (m_customCursor) delete m_customCursor;
if(ugly_hack==m_windowRef) ugly_hack= NULL;
// printf("GHOST_WindowCocoa::~GHOST_WindowCocoa(): removing drawing context\n");
if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone);
if (m_windowRef) {
::DisposeWindow(m_windowRef);
m_windowRef = 0;
}
}
bool GHOST_WindowCocoa::getValid() const
{
bool valid;
if (!m_fullScreen) {
valid = (m_windowRef != 0) && (m_grafPtr != 0) && ::IsValidWindowPtr(m_windowRef);
}
else {
valid = true;
}
return valid;
}
void GHOST_WindowCocoa::setTitle(const STR_String& title)
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid")
Str255 title255;
gen2mac(title, title255);
::SetWTitle(m_windowRef, title255);
}
void GHOST_WindowCocoa::getTitle(STR_String& title) const
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid")
Str255 title255;
::GetWTitle(m_windowRef, title255);
mac2gen(title255, title);
}
void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const
{
OSStatus success;
Rect rect;
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid")
success = ::GetWindowBounds(m_windowRef, kWindowStructureRgn, &rect);
bounds.m_b = rect.bottom;
bounds.m_l = rect.left;
bounds.m_r = rect.right;
bounds.m_t = rect.top;
}
void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const
{
Rect rect;
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid")
//::GetPortBounds(m_grafPtr, &rect);
::GetWindowBounds(m_windowRef, kWindowContentRgn, &rect);
bounds.m_b = rect.bottom;
bounds.m_l = rect.left;
bounds.m_r = rect.right;
bounds.m_t = rect.top;
// Subtract gutter height from bottom
#ifdef GHOST_DRAW_CARBON_GUTTER
if ((bounds.m_b - bounds.m_t) > s_sizeRectSize)
{
bounds.m_b -= s_sizeRectSize;
}
else
{
bounds.m_t = bounds.m_b;
}
#endif //GHOST_DRAW_CARBON_GUTTER
}
GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width)
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid")
GHOST_Rect cBnds, wBnds;
getClientBounds(cBnds);
if (((GHOST_TUns32)cBnds.getWidth()) != width) {
::SizeWindow(m_windowRef, width, cBnds.getHeight(), true);
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height)
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid")
GHOST_Rect cBnds, wBnds;
getClientBounds(cBnds);
#ifdef GHOST_DRAW_CARBON_GUTTER
if (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize) {
::SizeWindow(m_windowRef, cBnds.getWidth(), height+s_sizeRectSize, true);
}
#else //GHOST_DRAW_CARBON_GUTTER
if (((GHOST_TUns32)cBnds.getHeight()) != height) {
::SizeWindow(m_windowRef, cBnds.getWidth(), height, true);
}
#endif //GHOST_DRAW_CARBON_GUTTER
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid")
GHOST_Rect cBnds, wBnds;
getClientBounds(cBnds);
#ifdef GHOST_DRAW_CARBON_GUTTER
if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
(((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize)) {
::SizeWindow(m_windowRef, width, height+s_sizeRectSize, true);
}
#else //GHOST_DRAW_CARBON_GUTTER
if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
(((GHOST_TUns32)cBnds.getHeight()) != height)) {
::SizeWindow(m_windowRef, width, height, true);
}
#endif //GHOST_DRAW_CARBON_GUTTER
return GHOST_kSuccess;
}
GHOST_TWindowState GHOST_WindowCocoa::getState() const
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid")
GHOST_TWindowState state;
if (::IsWindowVisible(m_windowRef) == false) {
state = GHOST_kWindowStateMinimized;
}
else if (::IsWindowInStandardState(m_windowRef, nil, nil)) {
state = GHOST_kWindowStateMaximized;
}
else {
state = GHOST_kWindowStateNormal;
}
return state;
}
void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid")
Point point;
point.h = inX;
point.v = inY;
GrafPtr oldPort;
::GetPort(&oldPort);
::SetPort(m_grafPtr);
::GlobalToLocal(&point);
::SetPort(oldPort);
outX = point.h;
outY = point.v;
}
void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid")
Point point;
point.h = inX;
point.v = inY;
GrafPtr oldPort;
::GetPort(&oldPort);
::SetPort(m_grafPtr);
::LocalToGlobal(&point);
::SetPort(oldPort);
outX = point.h;
outY = point.v;
}
GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid")
switch (state) {
case GHOST_kWindowStateMinimized:
::HideWindow(m_windowRef);
break;
case GHOST_kWindowStateModified:
SetWindowModified(m_windowRef, 1);
break;
case GHOST_kWindowStateUnModified:
SetWindowModified(m_windowRef, 0);
break;
case GHOST_kWindowStateMaximized:
case GHOST_kWindowStateNormal:
default:
::ShowWindow(m_windowRef);
break;
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid")
if (order == GHOST_kWindowOrderTop) {
//::BringToFront(m_windowRef); is wrong, front window should be active for input too
::SelectWindow(m_windowRef);
}
else {
/* doesnt work if you do this with a mouseclick */
::SendBehind(m_windowRef, nil);
}
return GHOST_kSuccess;
}
/*#define WAIT_FOR_VSYNC 1*/
#ifdef WAIT_FOR_VSYNC
#include <OpenGL/OpenGL.h>
#endif
GHOST_TSuccess GHOST_WindowCocoa::swapBuffers()
{
#ifdef WAIT_FOR_VSYNC
/* wait for vsync, to avoid tearing artifacts */
long VBL = 1;
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL);
#endif
GHOST_TSuccess succeeded = GHOST_kSuccess;
if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
if (m_aglCtx) {
::aglSwapBuffers(m_aglCtx);
}
else {
succeeded = GHOST_kFailure;
}
}
return succeeded;
}
GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext()
{
GHOST_TSuccess succeeded = GHOST_kSuccess;
if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
if (m_aglCtx) {
::aglUpdateContext(m_aglCtx);
}
else {
succeeded = GHOST_kFailure;
}
}
return succeeded;
}
GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext()
{
GHOST_TSuccess succeeded = GHOST_kSuccess;
if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
if (m_aglCtx) {
::aglSetCurrentContext(m_aglCtx);
#ifdef GHOST_DRAW_CARBON_GUTTER
// Restrict drawing to non-gutter area
::aglEnable(m_aglCtx, AGL_BUFFER_RECT);
GHOST_Rect bnds;
getClientBounds(bnds);
GLint b[4] =
{
bnds.m_l,
bnds.m_t+s_sizeRectSize,
bnds.m_r-bnds.m_l,
bnds.m_b-bnds.m_t
};
GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b);
#endif //GHOST_DRAW_CARBON_GUTTER
}
else {
succeeded = GHOST_kFailure;
}
}
return succeeded;
}
GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type)
{
GHOST_TSuccess success = GHOST_kFailure;
switch (type) {
case GHOST_kDrawingContextTypeOpenGL:
{
if (!getValid()) break;
AGLPixelFormat pixelFormat;
if (!m_fullScreen) {
pixelFormat = ::aglChoosePixelFormat(0, 0, sPreferredFormatWindow);
m_aglCtx = ::aglCreateContext(pixelFormat, s_firstaglCtx);
if (!m_aglCtx) break;
if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx;
success = ::aglSetDrawable(m_aglCtx, m_grafPtr) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure;
}
else {
//GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL\n");
GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,sPreferredFormatFullScreen);
m_aglCtx = ::aglCreateContext(pixelFormat, 0);
if (!m_aglCtx) break;
if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx;
//GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): created OpenGL context\n");
//::CGGetActiveDisplayList(0, NULL, &m_numDisplays)
success = ::aglSetFullScreen(m_aglCtx, m_fullScreenWidth, m_fullScreenHeight, 75, 0) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure;
/*
if (success == GHOST_kSuccess) {
GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL succeeded\n");
}
else {
GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL failed\n");
}
*/
}
::aglDestroyPixelFormat(pixelFormat);
}
break;
case GHOST_kDrawingContextTypeNone:
success = GHOST_kSuccess;
break;
default:
break;
}
return success;
}
GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext()
{
GHOST_TSuccess success = GHOST_kFailure;
switch (m_drawingContextType) {
case GHOST_kDrawingContextTypeOpenGL:
if (m_aglCtx) {
aglSetCurrentContext(NULL);
aglSetDrawable(m_aglCtx, NULL);
//aglDestroyContext(m_aglCtx);
if (s_firstaglCtx == m_aglCtx) s_firstaglCtx = NULL;
success = ::aglDestroyContext(m_aglCtx) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure;
m_aglCtx = 0;
}
break;
case GHOST_kDrawingContextTypeNone:
success = GHOST_kSuccess;
break;
default:
break;
}
return success;
}
GHOST_TSuccess GHOST_WindowCocoa::invalidate()
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid")
if (!m_fullScreen) {
Rect rect;
::GetPortBounds(m_grafPtr, &rect);
::InvalWindowRect(m_windowRef, &rect);
}
else {
//EventRef event;
//OSStatus status = ::CreateEvent(NULL, kEventClassWindow, kEventWindowUpdate, 0, 0, &event);
//GHOST_PRINT("GHOST_WindowCocoa::invalidate(): created event " << status << " \n");
//status = ::SetEventParameter(event, kEventParamDirectObject, typeWindowRef, sizeof(WindowRef), this);
//GHOST_PRINT("GHOST_WindowCocoa::invalidate(): set event parameter " << status << " \n");
//status = ::PostEventToQueue(::GetMainEventQueue(), event, kEventPriorityStandard);
//status = ::SendEventToEventTarget(event, ::GetApplicationEventTarget());
//GHOST_PRINT("GHOST_WindowCocoa::invalidate(): added event to queue " << status << " \n");
m_fullScreenDirty = true;
}
return GHOST_kSuccess;
}
void GHOST_WindowCocoa::gen2mac(const STR_String& in, Str255 out) const
{
STR_String tempStr = in;
int num = tempStr.Length();
if (num > 255) num = 255;
::memcpy(out+1, tempStr.Ptr(), num);
out[0] = num;
}
void GHOST_WindowCocoa::mac2gen(const Str255 in, STR_String& out) const
{
char tmp[256];
::memcpy(tmp, in+1, in[0]);
tmp[in[0]] = '\0';
out = tmp;
}
void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
{
static bool systemCursorVisible = true;
if (visible != systemCursorVisible) {
if (visible) {
::ShowCursor();
systemCursorVisible = true;
}
else {
::HideCursor();
systemCursorVisible = false;
}
}
if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
::SetCursor( m_customCursor );
} else {
int carbon_cursor;
#define GCMAP(ghostCursor, carbonCursor) case ghostCursor: carbon_cursor = carbonCursor; break
switch (cursor) {
default:
GCMAP( GHOST_kStandardCursorDefault, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorRightArrow, kThemeAliasArrowCursor);
GCMAP( GHOST_kStandardCursorLeftArrow, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorInfo, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorDestroy, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorHelp, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorCycle, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorSpray, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorWait, kThemeWatchCursor);
GCMAP( GHOST_kStandardCursorText, kThemeIBeamCursor);
GCMAP( GHOST_kStandardCursorCrosshair, kThemeCrossCursor);
GCMAP( GHOST_kStandardCursorUpDown, kThemeClosedHandCursor);
GCMAP( GHOST_kStandardCursorLeftRight, kThemeClosedHandCursor);
GCMAP( GHOST_kStandardCursorTopSide, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorBottomSide, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorLeftSide, kThemeResizeLeftCursor);
GCMAP( GHOST_kStandardCursorRightSide, kThemeResizeRightCursor);
GCMAP( GHOST_kStandardCursorTopLeftCorner, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorTopRightCorner, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorBottomRightCorner, kThemeArrowCursor);
GCMAP( GHOST_kStandardCursorBottomLeftCorner, kThemeArrowCursor);
};
#undef GCMAP
::SetThemeCursor(carbon_cursor);
}
}
bool GHOST_WindowCocoa::getFullScreenDirty()
{
return m_fullScreen && m_fullScreenDirty;
}
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
{
if (::FrontWindow() == m_windowRef) {
loadCursor(visible, getCursorShape());
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)
{
if (m_customCursor) {
delete m_customCursor;
m_customCursor = 0;
}
if (::FrontWindow() == m_windowRef) {
loadCursor(getCursorVisibility(), shape);
}
return GHOST_kSuccess;
}
#if 0
/** Reverse the bits in a GHOST_TUns8 */
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
{
ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
return ch;
}
#endif
/** Reverse the bits in a GHOST_TUns16 */
static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
{
shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
return shrt;
}
GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color)
{
int y;
if (m_customCursor) {
delete m_customCursor;
m_customCursor = 0;
}
m_customCursor = new Cursor;
if (!m_customCursor) return GHOST_kFailure;
for (y=0; y<16; y++) {
#if !defined(__LITTLE_ENDIAN__)
m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8));
m_customCursor->mask[y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8));
#else
m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8));
m_customCursor->mask[y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8));
#endif
}
m_customCursor->hotSpot.h = hotX;
m_customCursor->hotSpot.v = hotY;
if (::FrontWindow() == m_windowRef) {
loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2],
GHOST_TUns8 mask[16][2], int hotX, int hotY)
{
return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1);
}
void GHOST_WindowCocoa::setMac_windowState(short value)
{
mac_windowState = value;
}
short GHOST_WindowCocoa::getMac_windowState()
{
return mac_windowState;
}