Cocoa port :
authorDamien Plisson <damien.plisson@yahoo.fr>
Mon, 5 Oct 2009 12:55:16 +0000 (12:55 +0000)
committerDamien Plisson <damien.plisson@yahoo.fr>
Mon, 5 Oct 2009 12:55:16 +0000 (12:55 +0000)
- Window creation at preferred size
  Implement in Ghost the use of Cocoa functions to get the maximum visible rect (size and position) for the window contents (all screen excluding dock, top menu, and window title bar)
  Thus Apple specific code in window creation (wm_window.c & wm_apple.c) is no more needed => removed in case of Cocoa build

- Alert on exiting despite unsaved changes
  Add to GHOST method to maintain an all platforms (not apple specific anymore) status on unsaved changes
  Update GHOST_SystemCocoa to use this for asking or not user to confirm exit without saving changes

14 files changed:
intern/ghost/GHOST_C-api.h
intern/ghost/GHOST_IWindow.h
intern/ghost/GHOST_Types.h
intern/ghost/intern/GHOST_C-api.cpp
intern/ghost/intern/GHOST_SystemCocoa.h
intern/ghost/intern/GHOST_SystemCocoa.mm
intern/ghost/intern/GHOST_Window.cpp
intern/ghost/intern/GHOST_Window.h
intern/ghost/intern/GHOST_WindowCocoa.h
intern/ghost/intern/GHOST_WindowCocoa.mm
intern/ghost/intern/GHOST_WindowManager.cpp
intern/ghost/intern/GHOST_WindowManager.h
source/blender/windowmanager/CMakeLists.txt
source/blender/windowmanager/intern/wm_window.c

index c0b7077fb538c771b1666cd864471fe355c88b83..9460fb504a9b3dca4d3519333b572e7c4f983f6a 100644 (file)
@@ -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
index d91995e35ecb2a0e9f75c554eaa4fb534226018e..ff1484909b081e9720c87880dc1fe04ff55e6996 100644 (file)
@@ -161,6 +161,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.
index 31819f341a0b66ea3ca1ea0a5e829312dfda572d..14e3c4bb5f7bb0fcda55842fa402b9aae783a8b0 100644 (file)
@@ -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
index 5c23b6c42a379f421b6b421e461ae9cfb4f72691..d14945d1bf8ca0910132faeb8f8c5cd8d306b68f 100644 (file)
@@ -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)
index cd2cf12daa1bb78cd7982361ce143ed61ac2934c..3e499f3d136dc7151acd2d8e9f2f73473d75f697 100644 (file)
@@ -133,6 +133,12 @@ public:
         */
        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
         ***************************************************************************************/
@@ -193,39 +199,33 @@ protected:
         */
        virtual GHOST_TSuccess init();
 
-       /**
-        * Closes the system down.
-        * @return A success value.
-        */
-       virtual GHOST_TSuccess exit();
-
-       
     /**
      * Handles a tablet event.
      * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
      * @return Indication whether the event was handled. 
      */
-    int handleTabletEvent(void *eventPtr);
-    /**
+    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. 
      */
-    int handleMouseEvent(void *eventPtr);
+    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. 
      */
-    int handleKeyEvent(void *eventPtr);
+    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. 
      */
-    int handleWindowEvent(void *eventPtr);
+    GHOST_TSuccess handleWindowEvent(void *eventPtr);
 
     /**
      * Handles all basic Mac application stuff for a mouse down event.
index d0c382e1469756c23a0cce00633a15f84219bb38..c66153ab6705ee708c86c2083076e4cec1f06638 100644 (file)
@@ -414,6 +414,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) {
 }
 -(void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa;
 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+- (void)applicationWillTerminate:(NSNotification *)aNotification;
 @end
 
 @implementation CocoaAppDelegate : NSObject
@@ -424,15 +425,21 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) {
 
 - (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
-    //FIXME: Need an event "QuitRequest"
-       int shouldQuit = NSRunAlertPanel(@"Exit Blender", @"Some changes may not have been saved. Do you really want to quit ?",
-                                                                        @"No", @"Yes", nil);
-       
-       if (shouldQuit == NSAlertAlternateReturn)
-               systemCocoa->pushEvent( new GHOST_Event(systemCocoa->getMilliSeconds(), GHOST_kEventQuit, NULL) );
-    
-       return NSTerminateCancel;
+    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
 
@@ -440,7 +447,6 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) {
 
 #pragma mark initialization/finalization
 
-/***/
 
 GHOST_SystemCocoa::GHOST_SystemCocoa()
 {
@@ -468,6 +474,8 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
 
 GHOST_SystemCocoa::~GHOST_SystemCocoa()
 {
+       NSAutoreleasePool* pool = (NSAutoreleasePool *)m_autoReleasePool;
+       [pool drain];
 }
 
 
@@ -478,7 +486,7 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
     if (success) {
                //ProcessSerialNumber psn;
                
-               //FIXME: Carbon stuff to move window & menu to foreground
+               //Carbon stuff to move window & menu to foreground
                /*if (!GetCurrentProcess(&psn)) {
                        TransformProcessType(&psn, kProcessTransformToForegroundApplication);
                        SetFrontProcess(&psn);
@@ -566,13 +574,6 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
 }
 
 
-GHOST_TSuccess GHOST_SystemCocoa::exit()
-{
-       NSAutoreleasePool* pool = (NSAutoreleasePool *)m_autoReleasePool;
-       [pool drain];
-    return GHOST_System::exit();
-}
-
 #pragma mark window management
 
 GHOST_TUns64 GHOST_SystemCocoa::getMilliSeconds() const
@@ -602,11 +603,15 @@ GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const
 
 void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
 {
-       //TODO: Provide visible frame or total frame, check for consistency with rest of code
+       //Get visible frame, that is frame excluding dock and top menu bar
        NSRect frame = [[NSScreen mainScreen] visibleFrame];
        
-       width = frame.size.width;
-       height = frame.size.height;
+       //Returns max window contents (excluding title bar...)
+       NSRect contentRect = [NSWindow contentRectForFrameRect:frame
+                                                                                                styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
+       
+       width = contentRect.size.width;
+       height = contentRect.size.height;
 }
 
 
@@ -623,7 +628,16 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
 )
 {
     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) {
@@ -847,7 +861,7 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
 }
 
 //TODO: To be called from NSWindow delegate
-int GHOST_SystemCocoa::handleWindowEvent(void *eventPtr)
+GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(void *eventPtr)
 {
        /*WindowRef windowRef;
        GHOST_WindowCocoa *window;
@@ -900,7 +914,29 @@ int GHOST_SystemCocoa::handleWindowEvent(void *eventPtr)
        return GHOST_kSuccess;
 }
 
-int GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
+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();
@@ -964,7 +1000,7 @@ int GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
 }
 
 
-int GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
+GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 {
        NSEvent *event = (NSEvent *)eventPtr;
     GHOST_IWindow* window = m_windowManager->getActiveWindow();
@@ -1018,11 +1054,12 @@ int GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 }
 
 
-int GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
+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;
 
@@ -1036,9 +1073,16 @@ int GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
        switch ([event type]) {
                case NSKeyDown:
                case NSKeyUp:
-                       keyCode = convertKey([event keyCode],
-                                                        [[event charactersIgnoringModifiers] characterAtIndex:0]);
-                       ascii= convertRomanToLatin((char)[[event characters] characterAtIndex:0]);
+                       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
@@ -1223,9 +1267,12 @@ 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;
        }
        
@@ -1235,7 +1282,10 @@ GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const
        NSString *bestType = [[NSPasteboard generalPasteboard]
                                                  availableTypeFromArray:supportedTypes];
        
-       if (bestType == nil) { return NULL; }
+       if (bestType == nil) {
+               [pool drain];
+               return NULL;
+       }
        
        NSString * textPasted = [pasteBoard stringForType:@"public.utf8-plain-text"];
 
@@ -1249,6 +1299,8 @@ GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const
        
        temp_buff[pastedTextSize] = '\0';
        
+       [pool drain];
+
        if(temp_buff) {
                return temp_buff;
        } else {
@@ -1262,10 +1314,12 @@ void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
        
        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;
        }
        
@@ -1277,8 +1331,7 @@ void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
        
        [pasteBoard setString:textToCopy forType:@"public.utf8-plain-text"];
        
-       printf("\nCopy");
-       
+       [pool drain];
 }
 
 #pragma mark Carbon stuff to remove
index 951c3bc381d3c88845ca3359ad88cfb035df2d75..34e9f519a07085945344fd8a4479febc53ce0a02 100644 (file)
@@ -52,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;
@@ -137,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
index 88178bae5b317d1d88f0d2b5cba140ea08c86f2b..a2d1675f6abcf8861d56b0e0c73a8707763e95b1 100644 (file)
@@ -173,6 +173,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;
 
index 146d0ff47de9a2b610a84c63cfc32784679d617e..f383e3a7a811d33582d557397ad083d9bd378143 100644 (file)
@@ -143,6 +143,13 @@ public:
         */
        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.
index 53d7fa9b24501d0f25ed3b87e18f22371e4815f7..092443814b0f08f7d211b7c224c563e8abbd1e5a 100644 (file)
@@ -378,12 +378,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
        case GHOST_kWindowStateMinimized:
             ::HideWindow(m_windowRef);
             break;
-       case GHOST_kWindowStateModified:
-               SetWindowModified(m_windowRef, 1);
-               break;
-       case GHOST_kWindowStateUnModified:
-               SetWindowModified(m_windowRef, 0);
-               break;
        case GHOST_kWindowStateMaximized:
        case GHOST_kWindowStateNormal:
         default:
@@ -393,6 +387,18 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
     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)
 {
index af96653db1313f8d8afd6bc4ca05e1e4d55fa0e9..15ee41e3dce6221d8d57b0084d3fda9611339647 100644 (file)
@@ -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
index 46e80d2c60372df25b63485c847c7a4c5a3c4e49..3690ad41e2cd791880ab84895bc834c015002b63 100644 (file)
@@ -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 */
index cb2fc92a1b67e1a0f8bb4a1d530cdfeebed24ed2..7deac8a4aa0fb89b65ae683d04699238e2bc1cb4 100644 (file)
@@ -70,6 +70,10 @@ IF(WIN32)
        SET(INC ${INC} ${PTHREADS_INC})
 ENDIF(WIN32)
 
+IF(WITH_COCOA)
+       LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/wm_apple.c")
+ENDIF(WITH_COCOA)
+
 # TODO buildinfo
 IF(BF_BUILDINFO)
        ADD_DEFINITIONS(-DNAN_BUILDINFO)
index c853afe450712bf1becf0c6fbf8e3ebf16bff15d..466e5868723e8efee82c2db34c39358bfae7e043 100644 (file)
@@ -71,7 +71,8 @@ static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0;
 
 /* ******** win open & close ************ */
 
-/* XXX this one should correctly check for apple top header... */
+/* XXX this one should correctly check for apple top header...
+ done for Cocoa : returns window contents (and not frame) max size*/
 static void wm_get_screensize(int *width_r, int *height_r) 
 {
        unsigned int uiwidth;
@@ -90,7 +91,7 @@ static void wm_window_check_position(rcti *rect)
        
        wm_get_screensize(&width, &height);
        
-#ifdef __APPLE__
+#if defined(__APPLE__) && !defined(GHOST_COCOA)
        height -= 70;
 #endif
        
@@ -269,7 +270,12 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
                else
                        GHOST_SetTitle(win->ghostwin, "Blender");
 
-#ifdef __APPLE__
+               /* Informs GHOST of unsaved changes, to set window modified visual indicator (MAC OS X)
+                and to give hint of unsaved changes for a user warning mechanism
+                in case of OS application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end) */
+               GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8)!wm->file_saved);
+               
+#if defined(__APPLE__) && !defined(GHOST_COCOA)
                if(wm->file_saved)
                        GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateUnModified);
                else
@@ -292,7 +298,7 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, char *title, wmWindow
        //              inital_state = GHOST_kWindowStateMaximized;
        inital_state = GHOST_kWindowStateNormal;
        
-#ifdef __APPLE__
+#if defined(__APPLE__) && !defined(GHOST_COCOA)
        {
                extern int macPrefState; /* creator.c */
                inital_state += macPrefState;
@@ -339,7 +345,8 @@ void wm_window_add_ghostwindows(wmWindowManager *wm)
        if (!prefsizx) {
                wm_get_screensize(&prefsizx, &prefsizy);
                
-#ifdef __APPLE__
+#if defined(__APPLE__) && !defined(GHOST_COCOA)
+//Cocoa provides functions to get correct max window size
                {
                        extern void wm_set_apple_prefsize(int, int);    /* wm_apple.c */