Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/ghost')
-rw-r--r--intern/ghost/CMakeLists.txt17
-rw-r--r--intern/ghost/GHOST_C-api.h10
-rw-r--r--intern/ghost/GHOST_IWindow.h13
-rw-r--r--intern/ghost/GHOST_Types.h6
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp7
-rw-r--r--intern/ghost/intern/GHOST_DisplayManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerCocoa.h106
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerCocoa.mm168
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp12
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h274
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm1414
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp16
-rw-r--r--intern/ghost/intern/GHOST_Window.h16
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h315
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm751
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp19
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.h10
17 files changed, 3141 insertions, 15 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/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index c0b7077fb53..9460fb504a9 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -598,6 +598,16 @@ extern GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle);
extern GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle,
GHOST_TWindowState state);
+
+/**
+ * Sets the window "modified" status, indicating unsaved changes
+ * @param windowhandle The handle to the window
+ * @param isUnsavedChanges Unsaved changes or not
+ * @return Indication of success.
+ */
+extern GHOST_TSuccess GHOST_SetWindowModifiedState(GHOST_WindowHandle windowhandle,
+ GHOST_TUns8 isUnsavedChanges);
+
/**
* Sets the order of the window (bottom, top).
* @param windowhandle The handle to the window
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index d91995e35ec..ff1484909b0 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -162,6 +162,19 @@ public:
virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0;
/**
+ * Sets the window "modified" status, indicating unsaved changes
+ * @param isUnsavedChanges Unsaved changes or not
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges) = 0;
+
+ /**
+ * Gets the window "modified" status, indicating unsaved changes
+ * @return True if there are unsaved changes
+ */
+ virtual bool getModifiedState() = 0;
+
+ /**
* Sets the order of the window (bottom, top).
* @param order The order of the window.
* @return Indication of success.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 31819f341a0..14e3c4bb5f7 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -116,6 +116,12 @@ typedef enum {
} GHOST_TWindowState;
+/** Constants for the answer to the blender exit request */
+typedef enum {
+ GHOST_kExitCancel = 0,
+ GHOST_kExitNow
+} GHOST_TExitRequestResponse;
+
typedef enum {
GHOST_kWindowOrderTop = 0,
GHOST_kWindowOrderBottom
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 5c23b6c42a3..d14945d1bf8 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -629,6 +629,13 @@ GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle,
}
+GHOST_TSuccess GHOST_SetWindowModifiedState(GHOST_WindowHandle windowhandle, GHOST_TUns8 isUnsavedChanges)
+{
+ GHOST_IWindow* window = (GHOST_IWindow*) windowhandle;
+
+ return window->setModifiedState(isUnsavedChanges);
+}
+
GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle,
GHOST_TWindowOrder order)
diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp
index a06692797c7..712ded7ea20 100644
--- a/intern/ghost/intern/GHOST_DisplayManager.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManager.cpp
@@ -27,8 +27,6 @@
*/
/**
-
- * $Id$
* Copyright (C) 2001 NaN Technologies B.V.
* @author Maarten Gribnau
* @date September 21, 2001
diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.h b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h
new file mode 100644
index 00000000000..153ee401011
--- /dev/null
+++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h
@@ -0,0 +1,106 @@
+/**
+ * $Id$
+ * ***** 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:
+ //Do not cache values as OS X supports screen hot plug
+ /** 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..f105928c9a3
--- /dev/null
+++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm
@@ -0,0 +1,168 @@
+/**
+ * $Id$
+ * ***** 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 09/2001
+ Damien Plisson 10/2009
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <Cocoa/Cocoa.h>
+
+#include "GHOST_DisplayManagerCocoa.h"
+#include "GHOST_Debug.h"
+
+// We do not support multiple monitors at the moment
+
+
+GHOST_DisplayManagerCocoa::GHOST_DisplayManagerCocoa(void)
+{
+}
+
+
+GHOST_TSuccess GHOST_DisplayManagerCocoa::getNumDisplays(GHOST_TUns8& numDisplays) const
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ numDisplays = (GHOST_TUns8) [[NSScreen screens] count];
+
+ [pool drain];
+ 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");
+
+ numSettings = (GHOST_TInt32)3; //Width, Height, BitsPerPixel
+
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_DisplayManagerCocoa::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const
+{
+ //Note that only current display setting is available
+ NSScreen *askedDisplay;
+
+ GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getDisplaySetting(): only main display is supported");
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (display == kMainDisplay) //Screen #0 may not be the main one
+ askedDisplay = [NSScreen mainScreen];
+ else
+ askedDisplay = [[NSScreen screens] objectAtIndex:display];
+
+ if(askedDisplay == nil) {
+ [pool drain];
+ return GHOST_kFailure;
+ }
+
+ NSRect frame = [askedDisplay visibleFrame];
+ setting.xPixels = frame.size.width;
+ setting.yPixels = frame.size.height;
+
+ setting.bpp = NSBitsPerPixelFromDepth([askedDisplay depth]);
+
+ setting.frequency = 0; //No more CRT display...
+
+#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
+
+ [pool drain];
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const
+{
+ NSScreen *askedDisplay;
+
+ GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(): only main display is supported");
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (display == kMainDisplay) //Screen #0 may not be the main one
+ askedDisplay = [NSScreen mainScreen];
+ else
+ askedDisplay = [[NSScreen screens] objectAtIndex:display];
+
+ if(askedDisplay == nil) {
+ [pool drain];
+ return GHOST_kFailure;
+ }
+
+ NSRect frame = [askedDisplay visibleFrame];
+ setting.xPixels = frame.size.width;
+ setting.yPixels = frame.size.height;
+
+ setting.bpp = NSBitsPerPixelFromDepth([askedDisplay depth]);
+
+ setting.frequency = 0; //No more CRT display...
+
+#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
+
+ [pool drain];
+ 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
+
+ //Display configuration is no more available in 10.6
+
+/* 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;
+}
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..3e499f3d136
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -0,0 +1,274 @@
+/**
+ * $Id$
+ * ***** 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);
+
+ /**
+ * Handle User request to quit, from Menu bar Quit, and Cmd+Q
+ * Display alert panel if changes performed since last save
+ */
+ GHOST_TUns8 handleQuitRequest();
+
+ /***************************************************************************************
+ ** 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();
+
+ /**
+ * 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.
+ */
+ GHOST_TSuccess 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.
+ */
+ GHOST_TSuccess 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.
+ */
+ GHOST_TSuccess 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.
+ */
+ GHOST_TSuccess 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* m_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..06ce2882beb
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -0,0 +1,1414 @@
+/**
+ * $Id$
+ * ***** 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"
+
+#pragma mark KeyMap, mouse converters
+
+//TODO: remove (kept as reminder to implement window events)
+/*
+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;
+ }
+}
+
+/**
+ * Converts Mac rawkey codes (same for Cocoa & Carbon)
+ * into GHOST key codes
+ * @param rawCode The raw physical key code
+ * @param recvChar the character ignoring modifiers (except for shift)
+ * @return Ghost key code
+ */
+static GHOST_TKey convertKey(int rawCode, unichar recvChar)
+{
+
+ //printf("\nrecvchar %c 0x%x",recvChar,recvChar);
+ switch (rawCode) {
+ /*Physical keycodes not used due to map changes in int'l keyboards
+ case kVK_ANSI_A: return GHOST_kKeyA;
+ case kVK_ANSI_B: return GHOST_kKeyB;
+ case kVK_ANSI_C: return GHOST_kKeyC;
+ case kVK_ANSI_D: return GHOST_kKeyD;
+ case kVK_ANSI_E: return GHOST_kKeyE;
+ case kVK_ANSI_F: return GHOST_kKeyF;
+ case kVK_ANSI_G: return GHOST_kKeyG;
+ case kVK_ANSI_H: return GHOST_kKeyH;
+ case kVK_ANSI_I: return GHOST_kKeyI;
+ case kVK_ANSI_J: return GHOST_kKeyJ;
+ case kVK_ANSI_K: return GHOST_kKeyK;
+ case kVK_ANSI_L: return GHOST_kKeyL;
+ case kVK_ANSI_M: return GHOST_kKeyM;
+ case kVK_ANSI_N: return GHOST_kKeyN;
+ case kVK_ANSI_O: return GHOST_kKeyO;
+ case kVK_ANSI_P: return GHOST_kKeyP;
+ case kVK_ANSI_Q: return GHOST_kKeyQ;
+ case kVK_ANSI_R: return GHOST_kKeyR;
+ case kVK_ANSI_S: return GHOST_kKeyS;
+ case kVK_ANSI_T: return GHOST_kKeyT;
+ case kVK_ANSI_U: return GHOST_kKeyU;
+ case kVK_ANSI_V: return GHOST_kKeyV;
+ case kVK_ANSI_W: return GHOST_kKeyW;
+ case kVK_ANSI_X: return GHOST_kKeyX;
+ case kVK_ANSI_Y: return GHOST_kKeyY;
+ case kVK_ANSI_Z: return GHOST_kKeyZ;*/
+
+ /* Numbers keys mapped to handle some int'l keyboard (e.g. French)*/
+ case kVK_ISO_Section: return GHOST_kKeyUnknown;
+ case kVK_ANSI_1: return GHOST_kKey1;
+ case kVK_ANSI_2: return GHOST_kKey2;
+ case kVK_ANSI_3: return GHOST_kKey3;
+ case kVK_ANSI_4: return GHOST_kKey4;
+ case kVK_ANSI_5: return GHOST_kKey5;
+ case kVK_ANSI_6: return GHOST_kKey6;
+ case kVK_ANSI_7: return GHOST_kKey7;
+ case kVK_ANSI_8: return GHOST_kKey8;
+ case kVK_ANSI_9: return GHOST_kKey9;
+ case kVK_ANSI_0: return GHOST_kKey0;
+
+ case kVK_ANSI_Keypad0: return GHOST_kKeyNumpad0;
+ case kVK_ANSI_Keypad1: return GHOST_kKeyNumpad1;
+ case kVK_ANSI_Keypad2: return GHOST_kKeyNumpad2;
+ case kVK_ANSI_Keypad3: return GHOST_kKeyNumpad3;
+ case kVK_ANSI_Keypad4: return GHOST_kKeyNumpad4;
+ case kVK_ANSI_Keypad5: return GHOST_kKeyNumpad5;
+ case kVK_ANSI_Keypad6: return GHOST_kKeyNumpad6;
+ case kVK_ANSI_Keypad7: return GHOST_kKeyNumpad7;
+ case kVK_ANSI_Keypad8: return GHOST_kKeyNumpad8;
+ case kVK_ANSI_Keypad9: return GHOST_kKeyNumpad9;
+ case kVK_ANSI_KeypadDecimal: return GHOST_kKeyNumpadPeriod;
+ case kVK_ANSI_KeypadEnter: return GHOST_kKeyNumpadEnter;
+ case kVK_ANSI_KeypadPlus: return GHOST_kKeyNumpadPlus;
+ case kVK_ANSI_KeypadMinus: return GHOST_kKeyNumpadMinus;
+ case kVK_ANSI_KeypadMultiply: return GHOST_kKeyNumpadAsterisk;
+ case kVK_ANSI_KeypadDivide: return GHOST_kKeyNumpadSlash;
+ case kVK_ANSI_KeypadClear: return GHOST_kKeyUnknown;
+
+ case kVK_F1: return GHOST_kKeyF1;
+ case kVK_F2: return GHOST_kKeyF2;
+ case kVK_F3: return GHOST_kKeyF3;
+ case kVK_F4: return GHOST_kKeyF4;
+ case kVK_F5: return GHOST_kKeyF5;
+ case kVK_F6: return GHOST_kKeyF6;
+ case kVK_F7: return GHOST_kKeyF7;
+ case kVK_F8: return GHOST_kKeyF8;
+ case kVK_F9: return GHOST_kKeyF9;
+ case kVK_F10: return GHOST_kKeyF10;
+ case kVK_F11: return GHOST_kKeyF11;
+ case kVK_F12: return GHOST_kKeyF12;
+ case kVK_F13: return GHOST_kKeyF13;
+ case kVK_F14: return GHOST_kKeyF14;
+ case kVK_F15: return GHOST_kKeyF15;
+ case kVK_F16: return GHOST_kKeyF16;
+ case kVK_F17: return GHOST_kKeyF17;
+ case kVK_F18: return GHOST_kKeyF18;
+ case kVK_F19: return GHOST_kKeyF19;
+ case kVK_F20: return GHOST_kKeyF20;
+
+ case kVK_UpArrow: return GHOST_kKeyUpArrow;
+ case kVK_DownArrow: return GHOST_kKeyDownArrow;
+ case kVK_LeftArrow: return GHOST_kKeyLeftArrow;
+ case kVK_RightArrow: return GHOST_kKeyRightArrow;
+
+ case kVK_Return: return GHOST_kKeyEnter;
+ case kVK_Delete: return GHOST_kKeyBackSpace;
+ case kVK_ForwardDelete: return GHOST_kKeyDelete;
+ case kVK_Escape: return GHOST_kKeyEsc;
+ case kVK_Tab: return GHOST_kKeyTab;
+ case kVK_Space: return GHOST_kKeySpace;
+
+ case kVK_Home: return GHOST_kKeyHome;
+ case kVK_End: return GHOST_kKeyEnd;
+ case kVK_PageUp: return GHOST_kKeyUpPage;
+ case kVK_PageDown: return GHOST_kKeyDownPage;
+
+ /*case kVK_ANSI_Minus: return GHOST_kKeyMinus;
+ case kVK_ANSI_Equal: return GHOST_kKeyEqual;
+ case kVK_ANSI_Comma: return GHOST_kKeyComma;
+ case kVK_ANSI_Period: return GHOST_kKeyPeriod;
+ case kVK_ANSI_Slash: return GHOST_kKeySlash;
+ case kVK_ANSI_Semicolon: return GHOST_kKeySemicolon;
+ case kVK_ANSI_Quote: return GHOST_kKeyQuote;
+ case kVK_ANSI_Backslash: return GHOST_kKeyBackslash;
+ case kVK_ANSI_LeftBracket: return GHOST_kKeyLeftBracket;
+ case kVK_ANSI_RightBracket: return GHOST_kKeyRightBracket;
+ case kVK_ANSI_Grave: return GHOST_kKeyAccentGrave;*/
+
+ case kVK_VolumeUp:
+ case kVK_VolumeDown:
+ case kVK_Mute:
+ return GHOST_kKeyUnknown;
+
+ default:
+ /*Then detect on character value for "remappable" keys in int'l keyboards*/
+ if ((recvChar >= 'A') && (recvChar <= 'Z')) {
+ return (GHOST_TKey) (recvChar - 'A' + GHOST_kKeyA);
+ } else if ((recvChar >= 'a') && (recvChar <= 'z')) {
+ return (GHOST_TKey) (recvChar - 'a' + GHOST_kKeyA);
+ } else
+ switch (recvChar) {
+ 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;
+ default:
+ return GHOST_kKeyUnknown;
+ }
+ }
+ 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];
+
+//TODO:Need to investigate this. Function called too early in creator.c to have g_hasFirstFile == true
+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 {
+ GHOST_SystemCocoa *systemCocoa;
+}
+-(void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa;
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+- (void)applicationWillTerminate:(NSNotification *)aNotification;
+@end
+
+@implementation CocoaAppDelegate : NSObject
+-(void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa
+{
+ systemCocoa = sysCocoa;
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
+{
+ //TODO: implement graceful termination through Cocoa mechanism to avoid session log off to be cancelled
+ //Note that Cmd+Q is already handled by keyhandler
+ if (systemCocoa->handleQuitRequest() == GHOST_kExitNow)
+ return NSTerminateCancel;//NSTerminateNow;
+ else
+ return NSTerminateCancel;
+}
+
+// To avoid cancelling a log off process, we must use Cocoa termination process
+// And this function is the only chance to perform clean up
+// So WM_exit needs to be called directly, as the event loop will never run before termination
+- (void)applicationWillTerminate:(NSNotification *)aNotification
+{
+ /*G.afbreek = 0; //Let Cocoa perform the termination at the end
+ WM_exit(C);*/
+}
+@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()
+{
+ NSAutoreleasePool* pool = (NSAutoreleasePool *)m_autoReleasePool;
+ [pool drain];
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::init()
+{
+
+ GHOST_TSuccess success = GHOST_System::init();
+ if (success) {
+ //ProcessSerialNumber psn;
+
+ //Carbon stuff to move window & menu to foreground
+ /*if (!GetCurrentProcess(&psn)) {
+ TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+ SetFrontProcess(&psn);
+ }*/
+
+ m_autoReleasePool = [[NSAutoreleasePool alloc] init];
+ if (NSApp == nil) {
+ [NSApplication sharedApplication];
+
+ if ([NSApp mainMenu] == nil) {
+ NSMenu *mainMenubar = [[NSMenu alloc] init];
+ NSMenuItem *menuItem;
+
+ //Create the application menu
+ NSMenu *appMenu = [[NSMenu alloc] initWithTitle:@"Blender"];
+
+ [appMenu addItemWithTitle:@"About Blender" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+ [appMenu addItem:[NSMenuItem separatorItem]];
+
+ menuItem = [appMenu addItemWithTitle:@"Hide Blender" action:@selector(hide:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ menuItem = [appMenu addItemWithTitle:@"Hide others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
+
+ [appMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ menuItem = [appMenu addItemWithTitle:@"Quit Blender" action:@selector(terminate:) keyEquivalent:@"q"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ menuItem = [[NSMenuItem alloc] init];
+ [menuItem setSubmenu:appMenu];
+
+ [mainMenubar addItem:menuItem];
+ [menuItem release];
+ [appMenu release];
+
+ //Create the window menu
+ NSMenu *windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ menuItem = [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
+
+ menuItem = [[NSMenuItem alloc] init];
+ [menuItem setSubmenu:windowMenu];
+
+ [mainMenubar addItem:menuItem];
+ [menuItem release];
+
+ [NSApp setMainMenu:mainMenubar];
+ [NSApp setWindowsMenu:windowMenu];
+ [windowMenu release];
+ }
+ [NSApp finishLaunching];
+ }
+ if ([NSApp delegate] == nil) {
+ CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init];
+ [appDelegate setSystemCocoa:this];
+ [NSApp setDelegate:appDelegate];
+ }
+
+
+ /*
+ * 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;
+}
+
+
+#pragma mark window management
+
+GHOST_TUns64 GHOST_SystemCocoa::getMilliSeconds() const
+{
+ //Cocoa equivalent exists in 10.6 ([[NSProcessInfo processInfo] systemUptime])
+ 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
+{
+ //Get visible frame, that is frame excluding dock and top menu bar
+ NSRect frame = [[NSScreen mainScreen] visibleFrame];
+
+ //Returns max window contents (excluding title bar...)
+ NSRect contentRect = [NSWindow contentRectForFrameRect:frame
+ styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
+
+ width = contentRect.size.width;
+ height = contentRect.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;
+
+ //Get the available rect for including window contents
+ NSRect frame = [[NSScreen mainScreen] visibleFrame];
+ NSRect contentRect = [NSWindow contentRectForFrameRect:frame
+ styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
+
+ //Ensures window top left is inside this available rect
+ left = left > contentRect.origin.x ? left : contentRect.origin.x;
+ top = top > contentRect.origin.y ? top : contentRect.origin.y;
+
+ 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;
+
+ CGAssociateMouseAndMouseCursorPosition(false);
+ CGWarpMouseCursorPosition(CGPointMake(xf, yf));
+ CGAssociateMouseAndMouseCursorPosition(true);
+
+ 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)
+{
+ NSAutoreleasePool* pool = (NSAutoreleasePool*)m_autoReleasePool;
+ //bool anyProcessed = false;
+ NSEvent *event;
+
+ //Reinit the AutoReleasePool
+ //This is not done the typical Cocoa way (init at beginning of loop, and drain at the end)
+ //to allow pool to work with other function calls outside this loop (but in same thread)
+ [pool drain];
+ m_autoReleasePool = [[NSAutoreleasePool alloc] init];
+
+ // 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é, ...) =>included in always NSApp sendEvent */
+ /* 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); Needed only for timer implementation
+
+
+ return true; //anyProcessed;
+}
+
+//TODO: To be called from NSWindow delegate
+GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(void *eventPtr)
+{
+ /*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 GHOST_kSuccess;
+}
+
+GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest()
+{
+ //Check open windows if some changes are not saved
+ if (m_windowManager->getAnyModifiedState())
+ {
+ int shouldQuit = NSRunAlertPanel(@"Exit Blender", @"Some changes have not been saved. Do you really want to quit ?",
+ @"Cancel", @"Quit anyway", nil);
+ if (shouldQuit == NSAlertAlternateReturn)
+ {
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL) );
+ return GHOST_kExitNow;
+ }
+ }
+ else {
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL) );
+ return GHOST_kExitNow;
+ }
+
+ return GHOST_kExitCancel;
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
+{
+ NSEvent *event = (NSEvent *)eventPtr;
+ GHOST_IWindow* window = m_windowManager->getActiveWindow();
+ GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
+ NSUInteger tabletEvent;
+
+ ct.Pressure = 0;
+ ct.Xtilt = 0;
+ ct.Ytilt = 0;
+
+ //Handle tablet events combined with mouse events
+ switch ([event subtype]) {
+ case NX_SUBTYPE_TABLET_POINT:
+ tabletEvent = NSTabletPoint;
+ break;
+ case NX_SUBTYPE_TABLET_PROXIMITY:
+ tabletEvent = NSTabletProximity;
+ break;
+
+ default:
+ tabletEvent = [event type];
+ break;
+ }
+
+ switch (tabletEvent) {
+ 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");
+ return GHOST_kFailure;
+ break;
+ }
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
+{
+ NSEvent *event = (NSEvent *)eventPtr;
+ GHOST_IWindow* window = m_windowManager->getActiveWindow();
+
+ switch ([event type])
+ {
+ case NSLeftMouseDown:
+ case NSRightMouseDown:
+ case NSOtherMouseDown:
+ if (m_windowManager->getActiveWindow()) {
+ pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonDown, window, convertButton([event buttonNumber])));
+ }
+ handleTabletEvent(eventPtr);
+ break;
+
+ case NSLeftMouseUp:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
+ if (m_windowManager->getActiveWindow()) {
+ pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonUp, window, convertButton([event buttonNumber])));
+ }
+ handleTabletEvent(eventPtr);
+ break;
+
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSOtherMouseDragged:
+ handleTabletEvent(eventPtr);
+ case NSMouseMoved:
+ {
+ 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;
+
+ default:
+ return GHOST_kFailure;
+ break;
+ }
+
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
+{
+ NSEvent *event = (NSEvent *)eventPtr;
+ GHOST_IWindow* window = m_windowManager->getActiveWindow();
+ NSUInteger modifiers;
+ NSString *characters;
+ GHOST_TKey keyCode;
+ 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) {
+ return GHOST_kFailure;
+ }
+
+ switch ([event type]) {
+ case NSKeyDown:
+ case NSKeyUp:
+ characters = [event characters];
+ if ([characters length]) { //Check for dead keys
+ keyCode = convertKey([event keyCode],
+ [[event charactersIgnoringModifiers] characterAtIndex:0]);
+ ascii= convertRomanToLatin((char)[characters characterAtIndex:0]);
+ } else {
+ keyCode = convertKey([event keyCode],0);
+ ascii= 0;
+ }
+
+
+ if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask))
+ break; //Cmd-Q is directly handled by Cocoa
+
+ if ([event type] == NSKeyDown) {
+ pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyDown, window, keyCode, ascii) );
+ //printf("\nKey pressed keyCode=%u ascii=%i %c",keyCode,ascii,ascii);
+ } else {
+ pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyUp, window, keyCode, 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:
+ return GHOST_kFailure;
+ break;
+ }
+
+ return GHOST_kSuccess;
+}
+
+
+/* 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;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
+
+ if (pasteBoard == nil) {
+ [pool drain];
+ return NULL;
+ }
+
+ NSArray *supportedTypes =
+ [NSArray arrayWithObjects: @"public.utf8-plain-text", nil];
+
+ NSString *bestType = [[NSPasteboard generalPasteboard]
+ availableTypeFromArray:supportedTypes];
+
+ if (bestType == nil) {
+ [pool drain];
+ return NULL;
+ }
+
+ NSString * textPasted = [pasteBoard stringForType:@"public.utf8-plain-text"];
+
+ if (textPasted == nil) {
+ [pool drain];
+ return NULL;
+ }
+
+ pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+ temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1);
+
+ if (temp_buff == NULL) {
+ [pool drain];
+ return NULL;
+ }
+
+ strncpy((char*)temp_buff, [textPasted UTF8String], pastedTextSize);
+
+ temp_buff[pastedTextSize] = '\0';
+
+ [pool drain];
+
+ 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
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
+
+ if (pasteBoard == nil) {
+ [pool drain];
+ return;
+ }
+
+ NSArray *supportedTypes = [NSArray arrayWithObject:@"public.utf8-plain-text"];
+
+ [pasteBoard declareTypes:supportedTypes owner:nil];
+
+ textToCopy = [NSString stringWithUTF8String:buffer];
+
+ [pasteBoard setString:textToCopy forType:@"public.utf8-plain-text"];
+
+ [pool drain];
+}
+
+#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;
+}
+#endif \ No newline at end of file
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index dee890830a1..34e9f519a07 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -27,8 +27,6 @@
*/
/**
-
- * $Id$
* Copyright (C) 2001 NaN Technologies B.V.
* @author Maarten Gribnau
* @date May 10, 2001
@@ -54,6 +52,8 @@ GHOST_Window::GHOST_Window(
m_cursorShape(GHOST_kStandardCursorDefault),
m_stereoVisual(stereoVisual)
{
+ m_isUnsavedChanges = false;
+
m_fullScreen = state == GHOST_kWindowStateFullScreen;
if (m_fullScreen) {
m_fullScreenWidth = width;
@@ -139,3 +139,15 @@ GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUn
}
}
+
+GHOST_TSuccess GHOST_Window::setModifiedState(bool isUnsavedChanges)
+{
+ m_isUnsavedChanges = isUnsavedChanges;
+
+ return GHOST_kSuccess;
+}
+
+bool GHOST_Window::getModifiedState()
+{
+ return m_isUnsavedChanges;
+} \ No newline at end of file
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 88178bae5b3..a2d1675f6ab 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -174,6 +174,19 @@ public:
virtual GHOST_TSuccess setCursorGrab(bool grab);
/**
+ * Sets the window "modified" status, indicating unsaved changes
+ * @param isUnsavedChanges Unsaved changes or not
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges);
+
+ /**
+ * Gets the window "modified" status, indicating unsaved changes
+ * @return True if there are unsaved changes
+ */
+ virtual bool getModifiedState();
+
+ /**
* Returns the type of drawing context used in this window.
* @return The current type of drawing context.
*/
@@ -262,6 +275,9 @@ protected:
/** The current shape of the cursor */
GHOST_TStandardCursor m_cursorShape;
+ /** Modified state : are there unsaved changes */
+ bool m_isUnsavedChanges;
+
/** Stores wether this is a full screen window. */
bool m_fullScreen;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
new file mode 100644
index 00000000000..f383e3a7a81
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -0,0 +1,315 @@
+/**
+ * $Id$
+ * ***** 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;
+
+ /**
+ * Sets the window "modified" status, indicating unsaved changes
+ * @param isUnsavedChanges Unsaved changes or not
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges);
+
+ /**
+ * 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..092443814b0
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -0,0 +1,751 @@
+/**
+ * $Id$
+ * ***** 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 *****
+ */
+
+/**
+ * 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_kWindowStateMaximized:
+ case GHOST_kWindowStateNormal:
+ default:
+ ::ShowWindow(m_windowRef);
+ break;
+ }
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges)
+{
+ if (isUnsavedChanges) {
+ SetWindowModified(m_windowRef, 1);
+ } else {
+ SetWindowModified(m_windowRef, 0);
+ }
+
+ return GHOST_Window::setModifiedState(isUnsavedChanges);
+}
+
+
+
+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;
+}
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index af96653db13..15ee41e3dce 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -187,10 +187,21 @@ void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow* window)
}
- std::vector<GHOST_IWindow *> &
-GHOST_WindowManager::
-getWindows(
-){
+std::vector<GHOST_IWindow *> &GHOST_WindowManager::getWindows()
+{
return m_windows;
}
+
+bool GHOST_WindowManager::getAnyModifiedState()
+{
+ bool isAnyModified = false;
+ std::vector<GHOST_IWindow*>::iterator iter;
+
+ for (iter = m_windows.begin(); iter != m_windows.end(); iter++) {
+ if ((*iter)->getModifiedState())
+ isAnyModified = true;
+ }
+
+ return isAnyModified;
+} \ No newline at end of file
diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h
index 46e80d2c603..3690ad41e2c 100644
--- a/intern/ghost/intern/GHOST_WindowManager.h
+++ b/intern/ghost/intern/GHOST_WindowManager.h
@@ -133,11 +133,13 @@ public:
* this vector. Please do not destroy or add windows use the
* interface above for this,
*/
+ std::vector<GHOST_IWindow *> & getWindows();
- std::vector<GHOST_IWindow *> &
- getWindows(
- );
-
+ /**
+ * Return true if any windows has a modified status
+ * @return True if any window has unsaved changes
+ */
+ bool getAnyModifiedState();
protected:
/** The list of windows managed */