Fix OS X memory leak prints when starting blender:
[blender-staging.git] / intern / ghost / intern / GHOST_WindowCocoa.mm
index 66c6d75b6d756e4bb5603fb937938f5b4e0e2b98..83f86840eb4b0b61f978ef69ac4e95478a9bc707 100644 (file)
@@ -14,7 +14,7 @@
  *
  * 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.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
@@ -72,6 +72,8 @@ extern "C" {
 - (void)windowDidResignKey:(NSNotification *)notification;
 - (void)windowDidExpose:(NSNotification *)notification;
 - (void)windowDidResize:(NSNotification *)notification;
+- (void)windowDidMove:(NSNotification *)notification;
+- (void)windowWillMove:(NSNotification *)notification;
 @end
 
 @implementation CocoaWindowDelegate : NSObject
@@ -101,6 +103,16 @@ extern "C" {
        systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow);
 }
 
+- (void)windowDidMove:(NSNotification *)notification
+{
+       systemCocoa->handleWindowEvent(GHOST_kEventWindowMove, associatedWindow);
+}
+
+- (void)windowWillMove:(NSNotification *)notification
+{
+       systemCocoa->handleWindowEvent(GHOST_kEventWindowMove, associatedWindow);
+}
+
 - (void)windowDidResize:(NSNotification *)notification
 {
 #ifdef MAC_OS_X_VERSION_10_6
@@ -155,7 +167,7 @@ extern "C" {
        else if ([[draggingPBoard types] containsObject:NSStringPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeString;
        else return NSDragOperationNone;
        
-       associatedWindow->setAcceptDragOperation(FALSE); //Drag operation needs to be accepted explicitly by the event manager
+       associatedWindow->setAcceptDragOperation(TRUE); //Drag operation is accepted by default
        systemCocoa->handleDraggingEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil);
        return NSDragOperationCopy;
 }
@@ -170,7 +182,7 @@ extern "C" {
        NSPoint mouseLocation = [sender draggingLocation];
        
        systemCocoa->handleDraggingEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil);
-       return NSDragOperationCopy;
+       return associatedWindow->canAcceptDragOperation()?NSDragOperationCopy:NSDragOperationNone;
 }
 
 - (void)draggingExited:(id < NSDraggingInfo >)sender
@@ -191,11 +203,16 @@ extern "C" {
 {
        NSPoint mouseLocation = [sender draggingLocation];
        NSPasteboard *draggingPBoard = [sender draggingPasteboard];
+       NSImage *droppedImg;
        id data;
        
        switch (m_draggedObjectType) {
                case GHOST_kDragnDropTypeBitmap:
-                       data = [draggingPBoard dataForType:NSTIFFPboardType];
+                       if([NSImage canInitWithPasteboard:draggingPBoard]) {
+                               droppedImg = [[NSImage alloc]initWithPasteboard:draggingPBoard];
+                               data = droppedImg; //[draggingPBoard dataForType:NSTIFFPboardType];
+                       }
+                       else return NO;
                        break;
                case GHOST_kDragnDropTypeFilenames:
                        data = [draggingPBoard propertyListForType:NSFilenamesPboardType];
@@ -324,12 +341,18 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
        // Pixel Format Attributes for the windowed NSOpenGLContext
        i=0;
        pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer;
+       
+       // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer
+       // needed for 'Draw Overlap' drawing method
+       pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; 
+       
        pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated;
        //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,;   // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
-       
+
        pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
        pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
        
+       
        if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo;
        
        if (numOfAASamples>0) {
@@ -354,6 +377,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
        if (pixelFormat == nil) {
                i=0;
                pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer;
+               
+               // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer
+               // needed for 'Draw Overlap' drawing method
+               pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore;
+               
                pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated;
                //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,;   // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
                
@@ -443,6 +471,10 @@ bool GHOST_WindowCocoa::getValid() const
        return (m_window != 0);
 }
 
+void* GHOST_WindowCocoa::getOSWindow() const
+{
+       return (void*)m_window;
+}
 
 void GHOST_WindowCocoa::setTitle(const STR_String& title)
 {
@@ -562,6 +594,7 @@ void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const
 GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width)
 {
        GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid")
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        GHOST_Rect cBnds, wBnds;
        getClientBounds(cBnds);
        if (((GHOST_TUns32)cBnds.getWidth()) != width) {
@@ -570,6 +603,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width)
                size.height=cBnds.getHeight();
                [m_window setContentSize:size];
        }
+       [pool drain];
        return GHOST_kSuccess;
 }
 
@@ -577,6 +611,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width)
 GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height)
 {
        GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid")
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        GHOST_Rect cBnds, wBnds;
        getClientBounds(cBnds);
        if (((GHOST_TUns32)cBnds.getHeight()) != height) {
@@ -585,6 +620,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height)
                size.height=height;
                [m_window setContentSize:size];
        }
+       [pool drain];
        return GHOST_kSuccess;
 }
 
@@ -592,6 +628,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height)
 GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
 {
        GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid")
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        GHOST_Rect cBnds, wBnds;
        getClientBounds(cBnds);
        if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
@@ -601,6 +638,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32
                size.height=height;
                [m_window setContentSize:size];
        }
+       [pool drain];
        return GHOST_kSuccess;
 }
 
@@ -695,7 +733,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
 #ifdef MAC_OS_X_VERSION_10_6
                                //10.6 provides Cocoa functions to autoshow menu bar, and to change a window style
                                //Hide menu & dock if needed
-                               if ([[m_window screen] isEqual:[NSScreen mainScreen]])
+                               if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]])
                                {
                                        [NSApp setPresentationOptions:(NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar)];
                                }
@@ -706,7 +744,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
 #else
                                //With 10.5, we need to create a new window to change its style to borderless
                                //Hide menu & dock if needed
-                               if ([[m_window screen] isEqual:[NSScreen mainScreen]])
+                               if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]])
                                {
                                        //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:NO];
                                        //One of the very few 64bit compatible Carbon function
@@ -745,9 +783,9 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
                        break;
                case GHOST_kWindowStateNormal:
         default:
+                       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
                        if (m_fullScreen)
                        {
-                               NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
                                m_fullScreen = false;
 
                                //Exit fullscreen
@@ -797,15 +835,15 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
                        
                                //Tell WM of view new size
                                m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
-                               
-                               [pool drain];
                        }
             else if ([m_window isMiniaturized])
                                [m_window deminiaturize:nil];
                        else if ([m_window isZoomed])
                                [m_window zoom:nil];
+                       [pool drain];
             break;
     }
+
     return GHOST_kSuccess;
 }
 
@@ -823,6 +861,8 @@ GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges)
 
 GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
 {
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+       
        GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid")
     if (order == GHOST_kWindowOrderTop) {
                [m_window makeKeyAndOrderFront:nil];
@@ -838,6 +878,8 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
                        [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
                }
     }
+       
+       [pool drain];
     return GHOST_kSuccess;
 }
 
@@ -979,14 +1021,72 @@ GHOST_TSuccess GHOST_WindowCocoa::invalidate()
        return GHOST_kSuccess;
 }
 
+#pragma mark Progress bar
+
+GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress)
+{
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+       
+       if ((progress >=0.0) && (progress <=1.0)) {
+               NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)];
+               
+               [dockIcon lockFocus];
+        NSRect progressBox = {{4, 4}, {120, 16}};
+
+        [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0];
+        
+        // Track & Outline
+        [[NSColor blackColor] setFill];
+        NSRectFill(progressBox);
+        
+        [[NSColor whiteColor] set];
+        NSFrameRect(progressBox);
+        
+        // Progress fill
+        progressBox = NSInsetRect(progressBox, 1, 1);
+        [[NSColor knobColor] setFill];
+        progressBox.size.width = progressBox.size.width * progress;
+               NSRectFill(progressBox);
+               
+               [dockIcon unlockFocus];
+               
+               [NSApp setApplicationIconImage:dockIcon];
+               [dockIcon release];
+               
+               m_progressBarVisible = true;
+       }
+       
+       [pool drain];
+       return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_WindowCocoa::endProgressBar()
+{
+       if (!m_progressBarVisible) return GHOST_kFailure;
+       m_progressBarVisible = false;
+       
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+       
+       NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)];
+       [dockIcon lockFocus];
+       [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0];
+       [dockIcon unlockFocus];
+       [NSApp setApplicationIconImage:dockIcon];
+       [dockIcon release];
+       
+       [pool drain];
+       return GHOST_kSuccess;
+}
+
+
+
 #pragma mark Cursor handling
 
 void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
 {
        static bool systemCursorVisible = true;
        
-       NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init];
-
        NSCursor *tmpCursor =nil;
        
        if (visible != systemCursorVisible) {
@@ -1042,6 +1142,7 @@ void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) c
                        case GHOST_kStandardCursorTopRightCorner:
                        case GHOST_kStandardCursorBottomRightCorner:
                        case GHOST_kStandardCursorBottomLeftCorner:
+                       case GHOST_kStandardCursorCopy:
                        case GHOST_kStandardCursorDefault:
                        default:
                                tmpCursor = [NSCursor arrowCursor];
@@ -1049,17 +1150,19 @@ void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) c
                };
        }
        [tmpCursor set];
-       [pool drain];
 }
 
 
 
 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
 {
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
+       
        if ([m_window isVisible]) {
                loadCursor(visible, getCursorShape());
        }
        
+       [pool drain];
        return GHOST_kSuccess;
 }
 
@@ -1073,6 +1176,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode
                //No need to perform grab without warp as it is always on in OS X
                if(mode != GHOST_kGrabNormal) {
                        GHOST_TInt32 x_old,y_old;
+                       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
                        m_systemCocoa->getCursorPosition(x_old,y_old);
                        screenToClient(x_old, y_old, m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
@@ -1083,8 +1187,13 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode
                                setWindowCursorVisibility(false);
                        }
                        
+                       //Make window key if it wasn't to get the mouse move events
+                       [m_window makeKeyWindow];
+                       
                        //Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor
                        err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
+                       
+                       [pool drain];
                }
        }
        else {
@@ -1104,6 +1213,8 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode
        
 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)
 {
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
        if (m_customCursor) {
                [m_customCursor release];
                m_customCursor = nil;
@@ -1113,6 +1224,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor sha
                loadCursor(getCursorVisibility(), shape);
        }
        
+       [pool drain];
        return GHOST_kSuccess;
 }