fixed memory leaks in cocoa bindings (trac ticket #253). Thanks to N. Butko
authorVadim Pisarevsky <no@email>
Thu, 24 Jun 2010 12:28:23 +0000 (12:28 +0000)
committerVadim Pisarevsky <no@email>
Thu, 24 Jun 2010 12:28:23 +0000 (12:28 +0000)
modules/highgui/src/window_cocoa.mm

index ce9030d..508dd43 100644 (file)
 //
 //M*/
 
+#import <TargetConditionals.h>
+
+#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+/*** begin IPhone OS Stubs ***/
+// When highgui functions are referred to on iPhone OS, they will fail silently. 
+CV_IMPL int cvInitSystem( int argc, char** argv) { return 0;} 
+CV_IMPL int cvStartWindowThread(){ return 0; }
+CV_IMPL void cvDestroyWindow( const char* name) {}
+CV_IMPL void cvDestroyAllWindows( void ) {}
+CV_IMPL void cvShowImage( const char* name, const CvArr* arr) {}
+CV_IMPL void cvResizeWindow( const char* name, int width, int height) {}
+CV_IMPL void cvMoveWindow( const char* name, int x, int y){}
+CV_IMPL int cvCreateTrackbar (const char* trackbar_name,const char* window_name,
+                              int* val, int count, CvTrackbarCallback on_notify) {return  0;}
+CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,const char* window_name,
+                              int* val, int count, CvTrackbarCallback2 on_notify2, void* userdata) {return 0;}
+CV_IMPL void cvSetMouseCallback( const char* name, CvMouseCallback function, void* info) {}
+CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) {return 0;}
+CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos) {}
+CV_IMPL void* cvGetWindowHandle( const char* name ) {return NULL;} 
+CV_IMPL const char* cvGetWindowName( void* window_handle ) {return NULL;}
+CV_IMPL int cvNamedWindow( const char* name, int flags ) {return 0; }
+CV_IMPL int cvWaitKey (int maxWait) {return 0;}
+//*** end IphoneOS Stubs ***/
+#else
+
+
 #import <Cocoa/Cocoa.h>
 #include "precomp.hpp"
 
+#include <iostream>
+using namespace std; 
+
 const int TOP_BORDER  = 7;
 
 static NSApplication *application = nil;
@@ -54,7 +84,7 @@ static bool wasInitialized = false;
 @interface CVView : NSView {
        NSImage *image;
 }
-@property(assign) NSImage *image;
+@property(retain) NSImage *image;
 - (void)setImageData:(CvArr *)arr;
 @end
 
@@ -66,8 +96,8 @@ static bool wasInitialized = false;
        CvTrackbarCallback callback;
        CvTrackbarCallback2 callback2;
 }
-@property(assign) NSSlider *slider;
-@property(assign) NSTextField *name;
+@property(retain) NSSlider *slider;
+@property(retain) NSTextField *name;
 @property(assign) int *value;
 @property(assign) void *userData;
 @property(assign) CvTrackbarCallback callback;
@@ -79,11 +109,13 @@ static bool wasInitialized = false;
        CvMouseCallback mouseCallback;
        void *mouseParam;
        BOOL autosize;
+       BOOL firstContent; 
 }
 @property(assign) CvMouseCallback mouseCallback;
 @property(assign) void *mouseParam;
 @property(assign) BOOL autosize;
-@property(assign) NSMutableDictionary *sliders;
+@property(assign) BOOL firstContent; 
+@property(retain) NSMutableDictionary *sliders;
 - (CVView *)contentView;
 - (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags;
 - (void)cvMouseEvent:(NSEvent *)event;
@@ -92,9 +124,11 @@ static bool wasInitialized = false;
 
 static void icvCocoaCleanup(void)
 {
+       //cout << "icvCocoaCleanup" << endl; 
     if( application )
     {
-        [application terminate:nil];
+               cvDestroyAllWindows(); 
+        //[application terminate:nil];
         application = 0;
         [pool release];
     }
@@ -102,6 +136,7 @@ static void icvCocoaCleanup(void)
 
 CV_IMPL int cvInitSystem( int argc, char** argv) 
 {
+       //cout << "cvInitSystem" << endl; 
        wasInitialized = true;
        
        pool = [[NSAutoreleasePool alloc] init];
@@ -116,43 +151,61 @@ CV_IMPL int cvInitSystem( int argc, char** argv)
     if( floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5 )
         [application setActivationPolicy:0/*NSApplicationActivationPolicyRegular*/];
 #endif
-    [application finishLaunching];
-    atexit(icvCocoaCleanup);
+    //[application finishLaunching];
+    //atexit(icvCocoaCleanup);
        
     return 0;
 }
 
 CVWindow *cvGetWindow(const char *name) {
-       NSString *cvname = [NSString stringWithFormat:@"%s", name];
-       return (CVWindow *)[windows valueForKey:cvname];
+       //cout << "cvGetWindow" << endl; 
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+       NSString *cvname = [NSString stringWithFormat:@"%s", name]; 
+       CVWindow* retval = (CVWindow*) [windows valueForKey:cvname] ; 
+       //cout << "retain count: " << [retval retainCount] << endl; 
+       //retval = [retval retain]; 
+       //cout << "retain count: " << [retval retainCount] << endl; 
+       [localpool drain]; 
+       //cout << "retain count: " << [retval retainCount] << endl; 
+       return retval; 
 }
 
 CV_IMPL int cvStartWindowThread()
 {
+       //cout << "cvStartWindowThread" << endl; 
     return 0;
 }
 
 CV_IMPL void cvDestroyWindow( const char* name)
 {
+       
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+       //cout << "cvDestroyWindow" << endl; 
        CVWindow *window = cvGetWindow(name);
        if(window) {
                [window performClose:nil];
                [windows removeObjectForKey:[NSString stringWithFormat:@"%s", name]];
        }
+       [localpool drain]; 
 }
 
 
 CV_IMPL void cvDestroyAllWindows( void )
 {
+       //cout << "cvDestroyAllWindows" << endl; 
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
        for(NSString *key in windows) {
                [[windows valueForKey:key] performClose:nil];
        }
        [windows removeAllObjects];
+       [localpool drain]; 
 }
 
 
 CV_IMPL void cvShowImage( const char* name, const CvArr* arr)
 {
+       //cout << "cvShowImage" << endl; 
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
        CVWindow *window = cvGetWindow(name);
     if(!window)
     {
@@ -167,21 +220,28 @@ CV_IMPL void cvShowImage( const char* name, const CvArr* arr)
         NSRect vrectOld = [[window contentView] frame];
         
                [[window contentView] setImageData:(CvArr *)arr];
-               if(/*[window autosize] ||*/ empty)
+               if([window autosize] || [window firstContent] || empty)
         {
                        NSRect vrectNew = vrectOld;
             vrectNew.size = [[[window contentView] image] size];
             rect.size.width += vrectNew.size.width - vrectOld.size.width;
             rect.size.height += vrectNew.size.height - vrectOld.size.height;
+                       rect.origin.y -= vrectNew.size.height - vrectOld.size.height;
+                       
             [window setFrame:rect display:YES];
                }
         else
                        [window display];
+               [window setFirstContent:NO]; 
        }
+       [localpool drain]; 
 }
 
 CV_IMPL void cvResizeWindow( const char* name, int width, int height)
 {
+
+       //cout << "cvResizeWindow" << endl; 
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
        CVWindow *window = cvGetWindow(name);
        if(window) {
                NSRect frame = [window frame];
@@ -189,23 +249,27 @@ CV_IMPL void cvResizeWindow( const char* name, int width, int height)
                frame.size.height = height;
                [window setFrame:frame display:YES];
        }
+       [localpool drain]; 
 }
 
 CV_IMPL void cvMoveWindow( const char* name, int x, int y)
 {
+       
        CV_FUNCNAME("cvMoveWindow");
        __BEGIN__;
        
+       NSAutoreleasePool* localpool1 = [[NSAutoreleasePool alloc] init];
        CVWindow *window = nil;
        
        if(name == NULL)
                CV_ERROR( CV_StsNullPtr, "NULL window name" );
-       
+       //cout << "cvMoveWindow"<< endl; 
        window = cvGetWindow(name);
        if(window) {
                y = [[window screen] frame].size.height - y;
                [window setFrameTopLeftPoint:NSMakePoint(x, y)];
        }
+       [localpool1 drain]; 
        
        __END__;
 }
@@ -216,15 +280,20 @@ CV_IMPL int cvCreateTrackbar (const char* trackbar_name,
                               CvTrackbarCallback on_notify)
 {
        CV_FUNCNAME("cvCreateTrackbar");
+       
 
        int result = 0;
        CVWindow *window = nil;
+       NSAutoreleasePool* localpool2 = nil;
        
        __BEGIN__;
+       if (localpool2 != nil) [localpool2 drain]; 
+       localpool2 = [[NSAutoreleasePool alloc] init];
        
        if(window_name == NULL)
                CV_ERROR( CV_StsNullPtr, "NULL window name" );
                
+       //cout << "cvCreateTrackbar" << endl ; 
        window = cvGetWindow(window_name);
        if(window) {
                [window createSliderWithName:trackbar_name
@@ -233,7 +302,7 @@ CV_IMPL int cvCreateTrackbar (const char* trackbar_name,
                                                        callback:on_notify];
                result = 1;
        }
-       
+       [localpool2 drain]; 
        __END__;
        return result;
 }
@@ -245,12 +314,15 @@ CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,
                               CvTrackbarCallback2 on_notify2,
                               void* userdata)
 {
+       //cout <<"cvCreateTrackbar2" << endl; 
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
        int res = cvCreateTrackbar(trackbar_name, window_name, val, count, NULL);
        if(res) {
                CVSlider *slider = [[cvGetWindow(window_name) sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
                [slider setCallback2:on_notify2];
                [slider setUserData:userdata];
        }
+       [localpool drain]; 
        return res;
 }
 
@@ -261,8 +333,12 @@ cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
        CV_FUNCNAME("cvSetMouseCallback");
        
        CVWindow *window = nil;
-       
+       NSAutoreleasePool* localpool3 = nil; 
        __BEGIN__;
+       //cout << "cvSetMouseCallback" << endl; 
+       
+       if (localpool3 != nil) [localpool3 drain]; 
+       localpool3 = [[NSAutoreleasePool alloc] init];
        
        if(name == NULL)
                CV_ERROR( CV_StsNullPtr, "NULL window name" );
@@ -272,6 +348,7 @@ cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
                [window setMouseCallback:function];
                [window setMouseParam:info];
        }
+       [localpool3 drain]; 
        
        __END__;
 }
@@ -282,12 +359,16 @@ cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
        
        CVWindow *window = nil;
        int pos = -1;
-       
+       NSAutoreleasePool* localpool4 = nil; 
        __BEGIN__;
        
+       //cout << "cvGetTrackbarPos" << endl; 
        if(trackbar_name == NULL || window_name == NULL)
                CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
        
+       if (localpool4 != nil) [localpool4 drain]; 
+       localpool4 = [[NSAutoreleasePool alloc] init];
+       
        window = cvGetWindow(window_name);
        if(window) {
                CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
@@ -295,7 +376,7 @@ cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
                        pos = [[slider slider] intValue];
                }
        }
-       
+       [localpool4 drain]; 
        __END__;
        return pos;
 }
@@ -306,15 +387,19 @@ CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name
        
        CVWindow *window = nil;
        CVSlider *slider = nil;
+       NSAutoreleasePool* localpool5 = nil; 
        
        __BEGIN__;
-       
+       //cout << "cvSetTrackbarPos" << endl; 
        if(trackbar_name == NULL || window_name == NULL)
                CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
        
        if(pos <= 0)
         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
        
+       if (localpool5 != nil) [localpool5 drain]; 
+       localpool5 = [[NSAutoreleasePool alloc] init];
+       
        window = cvGetWindow(window_name);
        if(window) {
                slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
@@ -322,22 +407,29 @@ CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name
                        [[slider slider] setIntValue:pos];
                }
        }
+       [localpool5 drain]; 
        
        __END__;
 }
 
 CV_IMPL void* cvGetWindowHandle( const char* name )
 {
+       //cout << "cvGetWindowHandle" << endl; 
        return cvGetWindow(name);
 }
 
 
 CV_IMPL const char* cvGetWindowName( void* window_handle )
 {      
+       //cout << "cvGetWindowName" << endl; 
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
        for(NSString *key in windows) {
-               if([windows valueForKey:key] == window_handle)
+               if([windows valueForKey:key] == window_handle) {
+                       [localpool drain]; 
                        return [key UTF8String];
+               }
        }
+       [localpool drain]; 
        return 0;
 }
 
@@ -346,20 +438,38 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
     if( !wasInitialized )
         cvInitSystem(0, 0);
     
+       //cout << "cvNamedWindow" << endl; 
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
        CVWindow *window = cvGetWindow(name);
     if( window )
     {
         [window setAutosize:(flags == CV_WINDOW_AUTOSIZE)];
+               [localpool drain]; 
         return 0;
     }
-    
-    window = [[CVWindow alloc] initWithContentRect:NSMakeRect(0,0,200,200)
-        styleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|
-        (!(flags & CV_WND_PROP_AUTOSIZE) ? NSResizableWindowMask : 0)
-        backing:NSBackingStoreBuffered  
-           defer:NO];
+       
+       NSScreen* mainDisplay = [NSScreen mainScreen]; 
        
        NSString *windowName = [NSString stringWithFormat:@"%s", name];
+       NSUInteger showResize = (flags == CV_WINDOW_AUTOSIZE) ? 0: NSResizableWindowMask ;
+       NSUInteger styleMask = NSTitledWindowMask|NSMiniaturizableWindowMask|showResize; 
+       CGFloat windowWidth = [NSWindow minFrameWidthWithTitle:windowName styleMask:styleMask]; 
+       NSRect initContentRect = NSMakeRect(0, 0, windowWidth, 0); 
+       if (mainDisplay) {
+               NSRect dispFrame = [mainDisplay visibleFrame]; 
+               initContentRect.origin.y = dispFrame.size.height-20;            
+       }
+     
+       
+    window = [[CVWindow alloc] initWithContentRect:initContentRect
+                                                                                styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|showResize
+                                                                                  backing:NSBackingStoreBuffered  
+                                                                                        defer:YES
+                                                                                       screen:mainDisplay];
+       
+       [window setFrameTopLeftPoint:initContentRect.origin]; 
+       
+       [window setFirstContent:YES]; 
        
        [window setContentView:[[CVView alloc] init]];
        
@@ -372,23 +482,25 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
        [window setAutosize:(flags == CV_WINDOW_AUTOSIZE)];     
        
        [windows setValue:window forKey:windowName];
-       
+               
+       [localpool drain]; 
        return [windows count]-1;
 }
 
 CV_IMPL int cvWaitKey (int maxWait)
 {
+       //cout << "cvWaitKey" << endl; 
     int returnCode = -1;
        double start = [[NSDate date] timeIntervalSince1970];
-    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
 
        while(true) {
                if(([[NSDate date] timeIntervalSince1970] - start) * 1000 >= maxWait && maxWait>0)
                        break;
                
                //event = [application currentEvent];
-        [pool release];
-        pool = [[NSAutoreleasePool alloc] init];
+        [localpool drain];
+        localpool = [[NSAutoreleasePool alloc] init];
         
         NSEvent *event =
         [application
@@ -408,7 +520,7 @@ CV_IMPL int cvWaitKey (int maxWait)
         
                [NSThread sleepForTimeInterval:1/100.];
        }
-    [pool release];
+    [localpool drain];
 
        return returnCode;
 }
@@ -418,9 +530,11 @@ CV_IMPL int cvWaitKey (int maxWait)
 @synthesize mouseCallback;
 @synthesize mouseParam;
 @synthesize autosize;
+@synthesize firstContent; 
 @synthesize sliders;
 
 - (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags {
+       //cout << "cvSendMouseEvent" << endl; 
        NSPoint mp = [NSEvent mouseLocation];
        NSRect visible = [[self contentView] frame];
     mp = [self convertScreenToBase: mp];
@@ -444,6 +558,7 @@ CV_IMPL int cvWaitKey (int maxWait)
 }
 
 - (void)cvMouseEvent:(NSEvent *)event {
+       //cout << "cvMouseEvent" << endl; 
        if(!mouseCallback) 
                return;
                
@@ -464,16 +579,20 @@ CV_IMPL int cvWaitKey (int maxWait)
        if([event type] == NSOtherMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags | CV_EVENT_FLAG_MBUTTON];}
 }
 - (void)keyDown:(NSEvent *)theEvent {
+       //cout << "keyDown" << endl; 
        [super keyDown:theEvent];
 }
 - (void)rightMouseDragged:(NSEvent *)theEvent {
+       //cout << "rightMouseDragged" << endl ;
        [self cvMouseEvent:theEvent];
 }
 - (void)rightMouseUp:(NSEvent *)theEvent {
+       //cout << "rightMouseUp" << endl; 
        [self cvMouseEvent:theEvent];
 }
 - (void)rightMouseDown:(NSEvent *)theEvent {
        // Does not seem to work?
+       //cout << "rightMouseDown" << endl; 
        [self cvMouseEvent:theEvent];
 }
 - (void)mouseMoved:(NSEvent *)theEvent {
@@ -499,6 +618,7 @@ CV_IMPL int cvWaitKey (int maxWait)
 }
 
 - (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback {
+       //cout << "createSliderWithName" << endl; 
        if(sliders == nil)
                sliders = [[NSMutableDictionary alloc] init];
        
@@ -512,6 +632,9 @@ CV_IMPL int cvWaitKey (int maxWait)
        CVSlider *slider = [[CVSlider alloc] init];
        [[slider name] setStringValue:cvname];
        [[slider slider] setMaxValue:max];
+       [[slider slider] setMinValue:0]; 
+       [[slider slider] setNumberOfTickMarks:(max+1)]; 
+       [[slider slider] setAllowsTickMarkValuesOnly:YES]; 
        if(value)
     {
                [[slider slider] setIntValue:*value];
@@ -527,6 +650,13 @@ CV_IMPL int cvWaitKey (int maxWait)
        // Update slider sizes
        [[self contentView] setFrameSize:[[self contentView] frame].size];
        [[self contentView] setNeedsDisplay:YES];
+       
+       
+       int height = 0;
+       for(NSString *key in sliders) {
+               height += [[sliders valueForKey:key] frame].size.height;
+       }
+       [self setContentMinSize:NSMakeSize(0, height)]; 
 }
 
 - (CVView *)contentView {
@@ -540,12 +670,15 @@ CV_IMPL int cvWaitKey (int maxWait)
 @synthesize image;
 
 - (id)init {
+       //cout << "CVView init" << endl; 
        [super init];
-       image = nil;
+       image = [[NSImage alloc] init];
        return self;
 }
 
 - (void)setImageData:(CvArr *)arr {
+       //cout << "setImageData" << endl; 
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
        CvMat *arrMat, *cvimage, stub;
         
        arrMat = cvGetMat(arr, &stub);
@@ -567,41 +700,54 @@ CV_IMPL int cvWaitKey (int maxWait)
       
        CGImageRef imageRef = CGImageCreate(width, height, size , size*nbChannels , cvimage->step, colorspace,  kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault);
        
-       NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithCGImage:imageRef] autorelease];
+       NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:imageRef]; 
        if(image) {
                [image release];
        }
+       
        image = [[NSImage alloc] init];
        [image addRepresentation:bitmap];
+       [bitmap release]; 
        
+       CGColorSpaceRelease(colorspace); 
     CGDataProviderRelease(provider);
+       CGImageRelease(imageRef);
        cvReleaseMat(&cvimage);
+       [localpool drain]; 
        
        [self setNeedsDisplay:YES];
+        
 }
 
 - (void)setFrameSize:(NSSize)size {
+       //cout << "setFrameSize" << endl; 
        [super setFrameSize:size];
+       
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
        int height = size.height;
        
-       CVWindow *window = (CVWindow *)[self window];
-       for(NSString *key in [window sliders]) {
-               NSSlider *slider = [[window sliders] valueForKey:key];
+       CVWindow *cvwindow = (CVWindow *)[self window];
+       for(NSString *key in [cvwindow sliders]) {
+               NSSlider *slider = [[cvwindow sliders] valueForKey:key];
                NSRect r = [slider frame];
                r.origin.y = height - r.size.height;
                [slider setFrame:r];
                height -= r.size.height;
        }
+       [localpool drain]; 
 }
 
 - (void)drawRect:(NSRect)rect {
-       CVWindow *window = (CVWindow *)[self window];
+       //cout << "drawRect" << endl; 
+       [super drawRect:rect];
+       
+       NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+       CVWindow *cvwindow = (CVWindow *)[self window];
        int height = 0;
-       for(NSString *key in [window sliders]) {
-               height += [[[window sliders] valueForKey:key] frame].size.height;
+       for(NSString *key in [cvwindow sliders]) {
+               height += [[[cvwindow sliders] valueForKey:key] frame].size.height;
        }
        
-       [super drawRect:rect];
 
        NSRect imageRect = {{0,0}, {self.frame.size.width, self.frame.size.height-height-6}};
        
@@ -611,6 +757,7 @@ CV_IMPL int cvWaitKey (int maxWait)
                                     operation: NSCompositeSourceOver
                                      fraction: 1.0];
        }
+       [localpool release]; 
 
 }
 
@@ -671,4 +818,6 @@ CV_IMPL int cvWaitKey (int maxWait)
 
 @end
 
+#endif
+
 /* End of file. */