diff --git a/ChangeLog b/ChangeLog index fc0053bb1..7416a8dfb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2006-10-01 Richard Frith-Macdonald + + * Source/GSTrackingRect.m: + * Source/NSView.m: + * Headers/AppKit/NSView.h: + Fix tracking rect bug ... the owner of the rectangle should not + be retained by a tracking rect (but should be retained by a cursor + rect). Updated documentation to clearly state what mis retained. + 2006-10-01 Richard Frith-Macdonald * Source/GSTheme.m: Add rudimentary inspector. diff --git a/Headers/AppKit/NSView.h b/Headers/AppKit/NSView.h index 295c4b149..f8515c72e 100644 --- a/Headers/AppKit/NSView.h +++ b/Headers/AppKit/NSView.h @@ -328,14 +328,41 @@ typedef enum _NSFocusRingType { event: (NSEvent *)theEvent; #endif -/* - * Managing the Cursor +/** + * Adds a cursor rectangle. This provides for automatic update of the + * cursor to be anObject while the mouse is in aRect.
+ * The cursor (anObject) is retained until the cursor rectangle is + * removed or discarded.
+ * Generally your subviews should call this in their implementation of + * the -resetCursorRects method.
+ * It is your responsibility to ensure that aRect lies within your veiw's + * visible rectangle. */ - (void) addCursorRect: (NSRect)aRect cursor: (NSCursor*)anObject; + +/** + * Removes all the cursor rectancles which have been set up for the + * receiver. This is equivalent to calling -removeCursorRect:cursor: + * for all cursor rectangles which have been set up.
+ * This is called automatically before the system calls -resetCursorRects + * so you never need to call it. + */ - (void) discardCursorRects; + +/** + * Removes the cursor rectangle which was set up for the specified + * rectangle and cursor. + */ - (void) removeCursorRect: (NSRect)aRect cursor: (NSCursor*)anObject; + +/** + * This is called to establish a new set of cursor rectangles whenever + * the receiver needs to do so (eg the view has been resized). The default + * implementation does nothing, but subclasses should use it to make + * calls to -addCursorRect:cursor: to establish their new cursor rectangles. + */ - (void) resetCursorRects; #ifndef STRICT_OPENSTEP @@ -351,10 +378,26 @@ typedef enum _NSFocusRingType { - (NSString *) toolTip; #endif -/* - * Tracking rectangles +/** + * Removes a tracking rectangle which was previously established using the + * -addTrackingRect:owner:userData:assumeInside: method.
+ * The value of tag must be the value returned by the method used to add + * the rectangle. */ - (void) removeTrackingRect: (NSTrackingRectTag)tag; + +/** + * Adds a tracking rectangle to monitor mouse movement and generate + * mouse-entered and mouse-exited events.
+ * The event messages are sent to anObject, which is not + * retained and must therefore be sure to remove any tracking rectangles + * using it before it is deallocated.
+ * The value of data is supplied as the user data in the event objects + * generated.
+ * If flag is YES then the mouse is assumed to be inside the tracking + * rectangle and the first event generated will therefore be a mouse exit, + * if it is NO then the first event generated will be a mouse entry. + */ - (NSTrackingRectTag) addTrackingRect: (NSRect)aRect owner: (id)anObject userData: (void*)data diff --git a/Source/GSTrackingRect.m b/Source/GSTrackingRect.m index 6a65d45e2..2ee8b6ac0 100644 --- a/Source/GSTrackingRect.m +++ b/Source/GSTrackingRect.m @@ -51,10 +51,6 @@ rectangle = aRect; tag = aTag; owner = anObject; - if (owner != nil) - { - RETAIN(owner); - } user_data = theData; flags.inside = flag; flags.isValid = YES; @@ -63,7 +59,6 @@ - (void) dealloc { - TEST_RELEASE(owner); [super dealloc]; } @@ -103,10 +98,6 @@ { flags.isValid = NO; flags.checked = NO; - if (owner != nil) - { - DESTROY(owner); - } } } @@ -134,7 +125,7 @@ rectangle = [aDecoder decodeRect]; [aDecoder decodeValueOfObjCType: @encode(NSTrackingRectTag) at: &tag]; - [aDecoder decodeValueOfObjCType: @encode(id) at: &owner]; + owner = [aDecoder decodeObject]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &inside]; flags.inside = inside; } diff --git a/Source/NSView.m b/Source/NSView.m index 11a57196f..93b27e598 100644 --- a/Source/NSView.m +++ b/Source/NSView.m @@ -557,6 +557,10 @@ GSSetDragTypes(NSView* obj, NSArray *types) RELEASE(_boundsMatrix); TEST_RELEASE(_sub_views); TEST_RELEASE(_tracking_rects); + if (_rFlags.has_currects != 0) + { + [self discardCursorRects]; // Handle release of cursors + } TEST_RELEASE(_cursor_rects); [self unregisterDraggedTypes]; [self releaseGState]; @@ -2610,7 +2614,7 @@ Returns YES iff any scrolling was done. m = [rectClass allocWithZone: NSDefaultMallocZone()]; m = [m initWithRect: aRect tag: 0 - owner: anObject + owner: RETAIN(anObject) userData: NULL inside: YES]; [_cursor_rects addObject: m]; @@ -2624,17 +2628,18 @@ Returns YES iff any scrolling was done. { if (_rFlags.has_currects != 0) { - if (_rFlags.valid_rects != 0) - { - unsigned count = [_cursor_rects count]; - if (count > 0) + unsigned count = [_cursor_rects count]; + + if (count > 0) + { + GSTrackingRect *rects[count]; + + [_cursor_rects getObjects: rects]; + if (_rFlags.valid_rects != 0) { - GSTrackingRect *rects[count]; NSPoint loc = ((struct NSWindow_struct *)_window)->_lastPoint; unsigned i; - [_cursor_rects getObjects: rects]; - for (i = 0; i < count; ++i) { GSTrackingRect *r = rects[i]; @@ -2644,10 +2649,14 @@ Returns YES iff any scrolling was done. } [r invalidate]; } + _rFlags.valid_rects = 0; } - _rFlags.valid_rects = 0; + while (count-- > 0) + { + RELEASE([rects[count] owner]); + } + [_cursor_rects removeAllObjects]; } - [_cursor_rects removeAllObjects]; _rFlags.has_currects = 0; } } @@ -2677,6 +2686,7 @@ Returns YES iff any scrolling was done. _rFlags.has_currects = 0; _rFlags.valid_rects = 0; } + RELEASE(c); break; } else @@ -4091,13 +4101,15 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level) _rFlags.flipped_view = [self isFlipped]; - [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_is_rotated_from_base]; [aDecoder decodeValueOfObjCType: @encode(BOOL) - at: &_is_rotated_or_scaled_from_base]; + at: &_is_rotated_from_base]; + [aDecoder decodeValueOfObjCType: @encode(BOOL) + at: &_is_rotated_or_scaled_from_base]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_post_frame_changes]; - [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_autoresizes_subviews]; + [aDecoder decodeValueOfObjCType: @encode(BOOL) + at: &_autoresizes_subviews]; [aDecoder decodeValueOfObjCType: @encode(unsigned int) - at: &_autoresizingMask]; + at: &_autoresizingMask]; [self setNextKeyView: [aDecoder decodeObject]]; [[aDecoder decodeObject] setNextKeyView: self]; @@ -4109,9 +4121,9 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level) while ((sub = [e nextObject]) != nil) { NSAssert([sub window] == nil, - NSInternalInconsistencyException); + NSInternalInconsistencyException); NSAssert([sub superview] == nil, - NSInternalInconsistencyException); + NSInternalInconsistencyException); [sub viewWillMoveToWindow: _window]; [sub viewWillMoveToSuperview: self]; [sub setNextResponder: self];