diff options
author | Damien Plisson <damien.plisson@yahoo.fr> | 2009-09-30 12:47:39 +0400 |
---|---|---|
committer | Damien Plisson <damien.plisson@yahoo.fr> | 2009-09-30 12:47:39 +0400 |
commit | 570c187ba1289c2515ee9db499ecf8c18f0d0b72 (patch) | |
tree | 601338952b62b32e3cfe7f42d31ce59070aeaf8c /intern | |
parent | 2a21c1acbef1920a7bf177974119800c23a993c7 (diff) |
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)
Diffstat (limited to 'intern')
-rw-r--r-- | intern/ghost/CMakeLists.txt | 17 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_DisplayManagerCocoa.h | 113 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_DisplayManagerCocoa.mm | 180 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_ISystem.cpp | 12 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemCocoa.h | 274 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemCocoa.mm | 1282 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowCocoa.h | 308 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowCocoa.mm | 747 |
8 files changed, 2930 insertions, 3 deletions
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 9128e923e19..33af61baa07 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -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) diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.h b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h new file mode 100644 index 00000000000..1483f62c577 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h @@ -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_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm b/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm new file mode 100644 index 00000000000..298baa5780f --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm @@ -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; +} + diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 9329e68132b..fc338c182a9 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -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 diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h new file mode 100644 index 00000000000..3093118abbe --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -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_ + diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm new file mode 100644 index 00000000000..749528472d3 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -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
\ No newline at end of file diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h new file mode 100644 index 00000000000..1a0038575cc --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -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_ + diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm new file mode 100644 index 00000000000..8318fd5c8da --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -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; +} |