/* NSView.m The view class which encapsulates all drawing functionality Copyright (C) 1996 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 Author: Ovidiu Predescu . Date: 1997 Author: Felipe A. Rodriguez Date: August 1998 Author: Richard Frith-Macdonald Date: January 1999 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct NSWindow_struct { @defs(NSWindow) }; @implementation NSView /* * Class variables */ static Class rectClass; static Class viewClass; static NSAffineTransform *flip = nil; static void (*appImp)(NSAffineTransform*, SEL, NSAffineTransform*) = 0; static SEL appSel = @selector(appendTransform:); static void (*invalidateImp)(NSView*, SEL) = 0; static SEL invalidateSel = @selector(_invalidateCoordinates); /* * Stuff to maintain a map table so we know what views are * registered for drag and drop - we don't store the info in * the view directly 'cot it would take up a pointer in each * view and the vast majority of views wouldn't use it. * Types are not registered/unregistered often enough for the * performance of this mechanism to be an issue. */ static NSMapTable *typesMap = 0; static NSLock *typesLock = nil; /* * This is the only external interface to the drag types info. */ NSArray* GSGetDragTypes(NSView *obj) { NSArray *t; [typesLock lock]; t = (NSArray*)NSMapGet(typesMap, (void*)(gsaddr)obj); [typesLock unlock]; return t; } static void GSRemoveDragTypes(NSView* obj) { [typesLock lock]; NSMapRemove(typesMap, (void*)(gsaddr)obj); [typesLock unlock]; } static NSArray* GSSetDragTypes(NSView* obj, NSArray *types) { unsigned count = [types count]; NSString *strings[count]; NSArray *t; unsigned i; /* * Make a new array with copies of the type strings so we don't get * them mutated by someone else. */ [types getObjects: strings]; for (i = 0; i < count; i++) { strings[i] = [strings[i] copy]; } t = [NSArray arrayWithObjects: strings count: count]; for (i = 0; i < count; i++) { RELEASE(strings[i]); } /* * Store it. */ [typesLock lock]; NSMapInsert(typesMap, (void*)(gsaddr)obj, (void*)(gsaddr)t); [typesLock unlock]; return t; } /* * Class methods */ + (void) initialize { if (self == [NSView class]) { Class matrixClass = [NSAffineTransform class]; NSAffineTransformStruct ats = { 1, 0, 0, -1, 0, 1 }; typesMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSObjectMapValueCallBacks, 0); typesLock = [NSLock new]; appImp = (void (*)(NSAffineTransform*, SEL, NSAffineTransform*)) [matrixClass instanceMethodForSelector: appSel]; invalidateImp = (void (*)(NSView*, SEL)) [self instanceMethodForSelector: invalidateSel]; flip = [matrixClass new]; [flip setTransformStruct: ats]; viewClass = [NSView class]; rectClass = [GSTrackingRect class]; NSDebugLLog(@"NSView", @"Initialize NSView class\n"); [self setVersion: 1]; } } /* * return the view at the top of graphics contexts stack * or nil if none is focused */ + (NSView*) focusView { return [GSCurrentContext() focusView]; } /* * Instance methods */ - (id) init { return [self initWithFrame: NSZeroRect]; } - (id) initWithFrame: (NSRect)frameRect { [super init]; if (frameRect.size.width < 0) { NSWarnMLog(@"given negative width", 0); frameRect.size.width = 0; } if (frameRect.size.height < 0) { NSWarnMLog(@"given negative height", 0); frameRect.size.height = 0; } _frame = frameRect; // Set frame rectangle _bounds.origin = NSZeroPoint; // Set bounds rectangle _bounds.size = _frame.size; _frameMatrix = [NSAffineTransform new]; // Map fromsuperview to frame _boundsMatrix = [NSAffineTransform new]; // Map fromsuperview to bounds _matrixToWindow = [NSAffineTransform new]; // Map to window coordinates _matrixFromWindow = [NSAffineTransform new]; // Map from window coordinates [_frameMatrix setFrameOrigin: _frame.origin]; _sub_views = [NSMutableArray new]; _tracking_rects = [NSMutableArray new]; _cursor_rects = [NSMutableArray new]; _super_view = nil; _window = nil; _is_rotated_from_base = NO; _is_rotated_or_scaled_from_base = NO; _rFlags.needs_display = YES; _post_frame_changes = NO; _autoresizes_subviews = YES; _autoresizingMask = NSViewNotSizable; _coordinates_valid = NO; _nextKeyView = nil; _previousKeyView = nil; _rFlags.flipped_view = [self isFlipped]; return self; } - (void) dealloc { if (_nextKeyView) [_nextKeyView setPreviousKeyView: nil]; if (_previousKeyView) [_previousKeyView setNextKeyView: nil]; RELEASE(_matrixToWindow); RELEASE(_matrixFromWindow); RELEASE(_frameMatrix); RELEASE(_boundsMatrix); TEST_RELEASE(_sub_views); TEST_RELEASE(_tracking_rects); TEST_RELEASE(_cursor_rects); [self unregisterDraggedTypes]; [self releaseGState]; [super dealloc]; } - (void) addSubview: (NSView*)aView { if ([self isDescendantOf: aView]) { NSLog(@"Operation addSubview: creates a loop in the views tree!\n"); return; } RETAIN(aView); [aView removeFromSuperview]; if (aView->_coordinates_valid) { (*invalidateImp)(aView, invalidateSel); } [aView viewWillMoveToWindow: _window]; [aView viewWillMoveToSuperview: self]; [aView setNextResponder: self]; [_sub_views addObject: aView]; _rFlags.has_subviews = 1; [aView resetCursorRects]; [aView setNeedsDisplay: YES]; RELEASE(aView); } - (void) addSubview: (NSView*)aView positioned: (NSWindowOrderingMode)place relativeTo: (NSView*)otherView { unsigned index; if ([self isDescendantOf: aView]) { NSLog(@"addSubview: positioned: relativeTo: will create a cycle " @"in the views tree!\n"); return; } if (aView == otherView) return; index = [_sub_views indexOfObjectIdenticalTo: otherView]; if (index == NSNotFound) { if (place == NSWindowBelow) index = 0; else index = [_sub_views count]; } RETAIN(aView); [aView removeFromSuperview]; if (aView->_coordinates_valid) { (*invalidateImp)(aView, invalidateSel); } [aView viewWillMoveToWindow: _window]; [aView viewWillMoveToSuperview: self]; [aView setNextResponder: self]; if (place == NSWindowBelow) [_sub_views insertObject: aView atIndex: index]; else [_sub_views insertObject: aView atIndex: index+1]; _rFlags.has_subviews = 1; [aView resetCursorRects]; [aView setNeedsDisplay: YES]; RELEASE(aView); } - (NSView*) ancestorSharedWithView: (NSView*)aView { if (self == aView) return self; if ([self isDescendantOf: aView]) return aView; if ([aView isDescendantOf: self]) return self; /* * If neither are descendants of each other and either does not have a * superview then they cannot have a common ancestor */ if (!_super_view) return nil; if (![aView superview]) return nil; /* Find the common ancestor of superviews */ return [_super_view ancestorSharedWithView: [aView superview]]; } - (BOOL) isDescendantOf: (NSView*)aView { if (aView == self) return YES; if (!_super_view) return NO; if (_super_view == aView) return YES; return [_super_view isDescendantOf: aView]; } - (NSView*) opaqueAncestor { NSView *next = _super_view; NSView *current = self; while (next != nil) { if ([current isOpaque] == YES) { break; } current = next; next = current->_super_view; } return current; } - (void) removeFromSuperviewWithoutNeedingDisplay { if (_super_view != nil) { [_super_view removeSubview: self]; } } - (void) removeFromSuperview { if (_super_view != nil) { [_super_view setNeedsDisplayInRect: _frame]; [_super_view removeSubview: self]; } } - (void) removeSubview: (NSView*)aSubview { /* * This must be first because it invokes -resignFirstResponder:, * which assumes the view is still in the view hierarchy */ if ([_window firstResponder] == aSubview) { [_window makeFirstResponder: _window]; } aSubview->_super_view = nil; [aSubview viewWillMoveToWindow: nil]; [_sub_views removeObjectIdenticalTo: aSubview]; if ([_sub_views count] == 0) { _rFlags.has_subviews = 0; } } - (void) replaceSubview: (NSView*)oldView with: (NSView*)newView { if (newView == oldView) { return; } /* * NB. we implement the replacement in full rather than calling addSubview: * since classes like NSBox override these methods but expect to be able to * call [super replaceSubview:with:] safely. */ if (oldView == nil) { /* * Strictly speaking, the docs say that if 'oldView' is not a subview * of the receiver then we do nothing - but here we add newView anyway. * So a replacement with no oldView is an addition. */ RETAIN(newView); [newView removeFromSuperview]; if (newView->_coordinates_valid) { (*invalidateImp)(newView, invalidateSel); } [newView viewWillMoveToWindow: _window]; [newView viewWillMoveToSuperview: self]; [newView setNextResponder: self]; [_sub_views addObject: newView]; _rFlags.has_subviews = 1; [newView resetCursorRects]; [newView setNeedsDisplay: YES]; RELEASE(newView); } else if ([_sub_views indexOfObjectIdenticalTo: oldView] != NSNotFound) { if (newView == nil) { /* * If there is no new view to add - we just remove the old one. * So a replacement with no newView is a removal. */ [oldView removeFromSuperview]; } else { unsigned index; /* * Ok - the standard case - we remove the newView from wherever it * was (which may have been in this view), locate the position of * the oldView (which may have changed due to the removal of the * newView), remove the oldView, and insert the newView in it's * place. */ RETAIN(newView); [newView removeFromSuperview]; if (newView->_coordinates_valid) { (*invalidateImp)(newView, invalidateSel); } index = [_sub_views indexOfObjectIdenticalTo: oldView]; [oldView removeFromSuperview]; [newView viewWillMoveToWindow: _window]; [newView viewWillMoveToSuperview: self]; [newView setNextResponder: self]; [_sub_views addObject: newView]; _rFlags.has_subviews = 1; [newView resetCursorRects]; [newView setNeedsDisplay: YES]; RELEASE(newView); } } } - (void) sortSubviewsUsingFunction: (int (*)(id ,id ,void*))compare context: (void*)context { [_sub_views sortUsingFunction: compare context: context]; } - (void) viewWillMoveToSuperview: (NSView*)newSuper { _super_view = newSuper; } /* * NOTE - this method is used when removing a view from a window * (in which case, newWindow is nil) to let all the subviews know * that they have also been removed from the window. */ - (void) viewWillMoveToWindow: (NSWindow*)newWindow { if (newWindow == _window) { return; } if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } if (_rFlags.has_currects != 0) { [self discardCursorRects]; } if (_rFlags.has_draginfo) { NSGraphicsContext *ctxt = GSCurrentContext(); NSArray *t = GSGetDragTypes(self); if (_window != nil) { [ctxt _removeDragTypes: t fromWindow: [_window windowNumber]]; } if (newWindow != nil) { [ctxt _addDragTypes: t toWindow: [newWindow windowNumber]]; } } _window = newWindow; if (_rFlags.has_subviews) { unsigned count = [_sub_views count]; if (count > 0) { unsigned i; NSView *array[count]; [_sub_views getObjects: array]; for (i = 0; i < count; ++i) { [array[i] viewWillMoveToWindow: newWindow]; } } } } - (void) rotateByAngle: (float)angle { if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } [_boundsMatrix rotateByAngle: angle]; _is_rotated_from_base = _is_rotated_or_scaled_from_base = YES; if (_post_bounds_changes) { [[NSNotificationCenter defaultCenter] postNotificationName: NSViewBoundsDidChangeNotification object: self]; } } - (void) _updateBoundsMatrix { float sx; float sy; if (_bounds.size.width == 0) { if (_frame.size.width == 0) sx = 1; else sx = FLT_MAX; } else { sx = _frame.size.width / _bounds.size.width; } if (_bounds.size.height == 0) { if (_frame.size.height == 0) sy = 1; else sy = FLT_MAX; } else { sy = _frame.size.height / _bounds.size.height; } [_boundsMatrix scaleTo: sx : sy]; if (sx != 1 || sy != 1) _is_rotated_or_scaled_from_base = YES; } - (void) setFrame: (NSRect)frameRect { BOOL changedOrigin = NO; BOOL changedSize = NO; NSSize old_size = _frame.size; if (frameRect.size.width < 0) { NSWarnMLog(@"given negative width", 0); frameRect.size.width = 0; } if (frameRect.size.height < 0) { NSWarnMLog(@"given negative height", 0); frameRect.size.height = 0; } if (NSMinX(_frame) != NSMinX(frameRect) || NSMinY(_frame) != NSMinY(frameRect)) changedOrigin = YES; if (NSWidth(_frame) != NSWidth(frameRect) || NSHeight(_frame) != NSHeight(frameRect)) changedSize = YES; _frame = frameRect; _bounds.size = _frame.size; if (changedOrigin) [_frameMatrix setFrameOrigin: _frame.origin]; if (changedSize && _is_rotated_or_scaled_from_base) { [self _updateBoundsMatrix]; } if (changedSize || changedOrigin) { if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } [self resizeSubviewsWithOldSize: old_size]; if (_post_frame_changes) [[NSNotificationCenter defaultCenter] postNotificationName: NSViewFrameDidChangeNotification object: self]; } } - (void) setFrameOrigin: (NSPoint)newOrigin { if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } _frame.origin = newOrigin; [_frameMatrix setFrameOrigin: _frame.origin]; if (_post_frame_changes) [[NSNotificationCenter defaultCenter] postNotificationName: NSViewFrameDidChangeNotification object: self]; } - (void) setFrameSize: (NSSize)newSize { NSSize old_size = _frame.size; if (newSize.width < 0) { NSWarnMLog(@"given negative width", 0); newSize.width = 0; } if (newSize.height < 0) { NSWarnMLog(@"given negative height", 0); newSize.height = 0; } if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } _frame.size = _bounds.size = newSize; [self resizeSubviewsWithOldSize: old_size]; if (_post_frame_changes) { [[NSNotificationCenter defaultCenter] postNotificationName: NSViewFrameDidChangeNotification object: self]; } } - (void) setFrameRotation: (float)angle { if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } [_frameMatrix setFrameRotation: angle]; _is_rotated_from_base = _is_rotated_or_scaled_from_base = YES; if (_post_frame_changes) [[NSNotificationCenter defaultCenter] postNotificationName: NSViewFrameDidChangeNotification object: self]; } - (BOOL) isRotatedFromBase { if (_is_rotated_from_base) return _is_rotated_from_base; else if (_super_view) return [_super_view isRotatedFromBase]; else return NO; } - (BOOL) isRotatedOrScaledFromBase { if (_is_rotated_or_scaled_from_base) return _is_rotated_or_scaled_from_base; else if (_super_view) return [_super_view isRotatedOrScaledFromBase]; else return NO; } - (void) scaleUnitSquareToSize: (NSSize)newSize { if (newSize.width < 0) { NSWarnMLog(@"given negative width", 0); newSize.width = 0; } if (newSize.height < 0) { NSWarnMLog(@"given negative height", 0); newSize.height = 0; } if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } _bounds.size.width = _frame.size.width / newSize.width; _bounds.size.height = _frame.size.height / newSize.height; _is_rotated_or_scaled_from_base = YES; [self _updateBoundsMatrix]; if (_post_bounds_changes) [[NSNotificationCenter defaultCenter] postNotificationName: NSViewBoundsDidChangeNotification object: self]; } - (void) setBounds: (NSRect)aRect { if (aRect.size.width < 0) { NSWarnMLog(@"given negative width", 0); aRect.size.width = 0; } if (aRect.size.height < 0) { NSWarnMLog(@"given negative height", 0); aRect.size.height = 0; } if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } _bounds = aRect; [_boundsMatrix setFrameOrigin: NSMakePoint(-_bounds.origin.x,-_bounds.origin.y)]; [self _updateBoundsMatrix]; if (_post_bounds_changes) [[NSNotificationCenter defaultCenter] postNotificationName: NSViewBoundsDidChangeNotification object: self]; } - (void) setBoundsOrigin: (NSPoint)newOrigin { _bounds.origin = newOrigin; if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } [_boundsMatrix setFrameOrigin: NSMakePoint(-newOrigin.x, -newOrigin.y)]; if (_post_bounds_changes) { [[NSNotificationCenter defaultCenter] postNotificationName: NSViewBoundsDidChangeNotification object: self]; } } - (void) setBoundsSize: (NSSize)newSize { if (newSize.width < 0) { NSWarnMLog(@"given negative width", 0); newSize.width = 0; } if (newSize.height < 0) { NSWarnMLog(@"given negative height", 0); newSize.height = 0; } if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } _bounds.size = newSize; [self _updateBoundsMatrix]; if (_post_bounds_changes) [[NSNotificationCenter defaultCenter] postNotificationName: NSViewBoundsDidChangeNotification object: self]; } - (void) setBoundsRotation: (float)angle { if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } [_boundsMatrix setFrameRotation: angle]; _is_rotated_from_base = _is_rotated_or_scaled_from_base = YES; if (_post_bounds_changes) { [[NSNotificationCenter defaultCenter] postNotificationName: NSViewBoundsDidChangeNotification object: self]; } } - (void) translateOriginToPoint: (NSPoint)point { if (_coordinates_valid) { (*invalidateImp)(self, invalidateSel); } [_boundsMatrix translateToPoint: point]; if (_post_bounds_changes) [[NSNotificationCenter defaultCenter] postNotificationName: NSViewBoundsDidChangeNotification object: self]; } - (NSRect) centerScanRect: (NSRect)aRect { NSAffineTransform *matrix; /* * Hmm - we assume that the windows coordinate system is centered on the * pixels of the screen - this may not be correct of course. * Plus - this is all pretty meaningless is we are not in a window! */ matrix = [self _matrixToWindow]; aRect.origin = [matrix pointInMatrixSpace: aRect.origin]; aRect.size = [matrix sizeInMatrixSpace: aRect.size]; aRect.origin.x = floor(aRect.origin.x); aRect.origin.y = floor(aRect.origin.y); aRect.size.width = floor(aRect.size.width); aRect.size.height = floor(aRect.size.height); matrix = [self _matrixFromWindow]; aRect.origin = [matrix pointInMatrixSpace: aRect.origin]; aRect.size = [matrix sizeInMatrixSpace: aRect.size]; return aRect; } - (NSPoint) convertPoint: (NSPoint)aPoint fromView: (NSView*)aView { NSPoint new; NSAffineTransform *matrix; if (!aView) aView = [[_window contentView] superview]; if (aView == self || aView == nil) return aPoint; NSAssert(_window == [aView window], NSInvalidArgumentException); matrix = [aView _matrixToWindow]; new = [matrix pointInMatrixSpace: aPoint]; if (_coordinates_valid) { matrix = _matrixFromWindow; } else { matrix = [self _matrixFromWindow]; } new = [matrix pointInMatrixSpace: new]; return new; } - (NSPoint) convertPoint: (NSPoint)aPoint toView: (NSView*)aView { NSPoint new; NSAffineTransform *matrix; if (aView == nil) { aView = [[_window contentView] superview]; } if (aView == self || aView == nil) { return aPoint; } NSAssert(_window == [aView window], NSInvalidArgumentException); if (_coordinates_valid) { matrix = _matrixToWindow; } else { matrix = [self _matrixToWindow]; } new = [matrix pointInMatrixSpace: aPoint]; matrix = [aView _matrixFromWindow]; new = [matrix pointInMatrixSpace: new]; return new; } - (NSRect) convertRect: (NSRect)aRect fromView: (NSView*)aView { NSAffineTransform *matrix; NSRect r; if (aView == nil) { aView = [[_window contentView] superview]; } if (aView == self || aView == nil) { return aRect; } NSAssert(_window == [aView window], NSInvalidArgumentException); matrix = [aView _matrixToWindow]; r.origin = [matrix pointInMatrixSpace: aRect.origin]; r.size = [matrix sizeInMatrixSpace: aRect.size]; if (_coordinates_valid) { matrix = _matrixFromWindow; } else { matrix = [self _matrixFromWindow]; } r.origin = [matrix pointInMatrixSpace: r.origin]; r.size = [matrix sizeInMatrixSpace: r.size]; if (aView->_rFlags.flipped_view != _rFlags.flipped_view) { r.origin.y -= r.size.height; } return r; } - (NSRect) convertRect: (NSRect)aRect toView: (NSView*)aView { NSAffineTransform *matrix; NSRect r; if (aView == nil) { aView = [[_window contentView] superview]; } if (aView == self || aView == nil) { return aRect; } NSAssert(_window == [aView window], NSInvalidArgumentException); if (_coordinates_valid) { matrix = _matrixToWindow; } else { matrix = [self _matrixToWindow]; } r.origin = [matrix pointInMatrixSpace: aRect.origin]; r.size = [matrix sizeInMatrixSpace: aRect.size]; matrix = [aView _matrixFromWindow]; r.origin = [matrix pointInMatrixSpace: r.origin]; r.size = [matrix sizeInMatrixSpace: r.size]; if (aView->_rFlags.flipped_view != _rFlags.flipped_view) { r.origin.y -= r.size.height; } return r; } - (NSSize) convertSize: (NSSize)aSize fromView: (NSView*)aView { NSSize new; NSAffineTransform *matrix; if (aView == nil) { aView = [[_window contentView] superview]; } if (aView == self || aView == nil) { return aSize; } NSAssert(_window == [aView window], NSInvalidArgumentException); matrix = [aView _matrixToWindow]; new = [matrix sizeInMatrixSpace: aSize]; if (_coordinates_valid) { matrix = _matrixFromWindow; } else { matrix = [self _matrixFromWindow]; } new = [matrix sizeInMatrixSpace: new]; return new; } - (NSSize) convertSize: (NSSize)aSize toView: (NSView*)aView { NSSize new; NSAffineTransform *matrix; if (aView == nil) { aView = [[_window contentView] superview]; } if (aView == self || aView == nil) { return aSize; } NSAssert(_window == [aView window], NSInvalidArgumentException); if (_coordinates_valid) { matrix = _matrixToWindow; } else { matrix = [self _matrixToWindow]; } new = [matrix sizeInMatrixSpace: aSize]; matrix = [aView _matrixFromWindow]; new = [matrix sizeInMatrixSpace: new]; return new; } - (void) setPostsFrameChangedNotifications: (BOOL)flag { _post_frame_changes = flag; } - (void) setPostsBoundsChangedNotifications: (BOOL)flag { _post_bounds_changes = flag; } /* * resize subviews only if we are supposed to and we have never been rotated */ - (void) resizeSubviewsWithOldSize: (NSSize)oldSize { if (_rFlags.has_subviews) { id e, o; if (_autoresizes_subviews == NO || _is_rotated_from_base == YES) return; e = [_sub_views objectEnumerator]; o = [e nextObject]; while (o) { [o resizeWithOldSuperviewSize: oldSize]; o = [e nextObject]; } } } - (void) resizeWithOldSuperviewSize: (NSSize)oldSize { float change; float changePerOption; int options = 0; NSRect newFrame, newBounds; NSSize superViewFrameSize = [_super_view frame].size; BOOL changedOrigin = NO; BOOL changedSize = NO; if (_autoresizingMask == NSViewNotSizable) return; newFrame = _frame; newBounds = _bounds; /* * determine if and how the X axis can be resized */ if (_autoresizingMask & NSViewWidthSizable) options++; if (_autoresizingMask & NSViewMinXMargin) options++; if (_autoresizingMask & NSViewMaxXMargin) options++; /* * adjust the X axis if any X options are set in the mask */ if (options >= 1) { change = superViewFrameSize.width - oldSize.width; changePerOption = change/options; if (_autoresizingMask & NSViewWidthSizable) { float oldFrameWidth = newFrame.size.width; newFrame.size.width += changePerOption; if (_is_rotated_or_scaled_from_base) newBounds.size.width *= newFrame.size.width/oldFrameWidth; else newBounds.size.width += changePerOption; changedSize = YES; } if (_autoresizingMask & NSViewMinXMargin) { newFrame.origin.x += changePerOption; changedOrigin = YES; } } /* * determine if and how the Y axis can be resized */ options = 0; if (_autoresizingMask & NSViewHeightSizable) options++; if (_autoresizingMask & NSViewMinYMargin) options++; if (_autoresizingMask & NSViewMaxYMargin) options++; /* * adjust the Y axis if any Y options are set in the mask */ if (options >= 1) { change = superViewFrameSize.height - oldSize.height; changePerOption = change/options; if (_autoresizingMask & NSViewHeightSizable) { float oldFrameHeight = newFrame.size.height; newFrame.size.height += changePerOption; if (_is_rotated_or_scaled_from_base) newBounds.size.height *= newFrame.size.height/oldFrameHeight; else newBounds.size.height += changePerOption; changedSize = YES; } if (_autoresizingMask & (NSViewMaxYMargin | NSViewMinYMargin)) { if (_super_view && _super_view->_rFlags.flipped_view == YES) { if (_autoresizingMask & NSViewMaxYMargin) { newFrame.origin.y += changePerOption; changedOrigin = YES; } } else { if (_autoresizingMask & NSViewMinYMargin) { newFrame.origin.y += changePerOption; changedOrigin = YES; } } } } [self setFrame: newFrame]; /* Since setFrame sets the bounds itself, reset it correctly */ _bounds = newBounds; if (changedSize && _is_rotated_or_scaled_from_base) [self _updateBoundsMatrix]; } - (void) allocateGState { _allocate_gstate = 1; _renew_gstate = 1; } - (void) releaseGState { if (_allocate_gstate && _gstate) PSundefineuserobject(_gstate); _gstate = 0; _allocate_gstate = 0; } - (int) gState { return _gstate; } - (void) renewGState { _renew_gstate = 1; } /* Overridden by subclasses to setup custom gstate */ - (void) setUpGState { } - (void) lockFocusInRect: (NSRect)rect { NSGraphicsContext *ctxt = GSCurrentContext(); struct NSWindow_struct *window_t; NSRect wrect; NSAssert(_window != nil, NSInternalInconsistencyException); [ctxt lockFocusView: self inRect: rect]; wrect = [self convertRect: rect toView: nil]; NSDebugLLog(@"NSView", @"Displaying rect \n\t%@\n\t window %p", NSStringFromRect(wrect), _window); window_t = (struct NSWindow_struct *)_window; [window_t->rectsBeingDrawn addObject: [NSValue valueWithRect: wrect]]; DPSgsave(ctxt); if (_gstate) { DPSsetgstate(ctxt, _gstate); if (_renew_gstate) [self setUpGState]; _renew_gstate = 0; DPSgsave(ctxt); } else { int window_gstate; NSAffineTransform *matrix; float x, y, w, h; window_gstate = [_window gState]; NSAssert(window_gstate, NSInternalInconsistencyException); DPSsetgstate(ctxt, window_gstate); DPSgsave(ctxt); matrix = [self _matrixToWindow]; [matrix concat]; /* * Clipping - set viewclip to the visible rectangle - which will never be * greater than the bounds of the view. * Set the standard clippath to an empty path. */ if ([matrix isRotated]) [matrix boundingRectFor: rect result: &rect]; x = NSMinX(rect); y = NSMinY(rect); w = NSWidth(rect); h = NSHeight(rect); DPSrectviewclip(ctxt, x, y, w, h); /* Add any scaling due to the bounds matrix */ //[_boundsMatrix concat]; /* Allow subclases to make other modifications */ [self setUpGState]; _renew_gstate = 0; if (_allocate_gstate) { DPSgstate(ctxt); _gstate = GSWDefineAsUserObj(ctxt); /* Balance the previous gsave and install our own gstate */ DPSgrestore(ctxt); DPSsetgstate(ctxt, _gstate); DPSgsave(ctxt); } } GSWViewIsFlipped(ctxt, _rFlags.flipped_view); } - (void) unlockFocusNeedsFlush: (BOOL)flush { NSRect rect; struct NSWindow_struct *window_t; NSGraphicsContext *ctxt = GSCurrentContext(); NSAssert(_window != nil, NSInternalInconsistencyException); /* Restore our original gstate */ DPSgrestore(ctxt); /* Restore gstate of nesting lockFocus (if any) */ DPSgrestore(ctxt); if (!_allocate_gstate) _gstate = 0; window_t = (struct NSWindow_struct *)_window; if (flush) { rect = [[window_t->rectsBeingDrawn lastObject] rectValue]; window_t->rectNeedingFlush = NSUnionRect(window_t->rectNeedingFlush, rect); window_t->_f.needs_flush = YES; } [window_t->rectsBeingDrawn removeLastObject]; [ctxt unlockFocusView: self needsFlush: YES ]; } - (void) lockFocus { [self lockFocusInRect: [self visibleRect]]; } - (void) unlockFocus { [self unlockFocusNeedsFlush: YES ]; } - (BOOL) canDraw { // not implemented per OS spec FIX ME if (_window) return YES; else return NO; } - (void) display { if (_window != nil) { [self displayRect: _visibleRect]; } } - (void) displayIfNeeded { if (_rFlags.needs_display == YES) { if ([self isOpaque] == YES) { [self displayIfNeededIgnoringOpacity]; } else { NSView *firstOpaque = [self opaqueAncestor]; NSRect rect; if (_coordinates_valid == NO) { [self _rebuildCoordinates]; } rect = NSIntersectionRect(_invalidRect, _visibleRect); rect = [firstOpaque convertRect: rect fromView: self]; if (NSIsEmptyRect(rect) == NO) { [firstOpaque displayIfNeededInRectIgnoringOpacity: rect]; } /* * If we still need display after displaying the invalid rectangle, * display any subviews that need display. */ if (_rFlags.needs_display == YES) { NSEnumerator *enumerator = [_sub_views objectEnumerator]; NSView *sub; while ((sub = [enumerator nextObject]) != nil) { if (sub->_rFlags.needs_display) { [sub displayIfNeededIgnoringOpacity]; } } _rFlags.needs_display = NO; } } } } - (void) displayIfNeededIgnoringOpacity { if (_rFlags.needs_display == YES) { NSRect rect; if (_coordinates_valid == NO) { [self _rebuildCoordinates]; } rect = NSIntersectionRect(_invalidRect, _visibleRect); if (NSIsEmptyRect(rect) == NO) { [self displayIfNeededInRectIgnoringOpacity: rect]; } /* * If we still need display after displaying the invalid rectangle, * display any subviews that need display. */ if (_rFlags.needs_display == YES) { NSEnumerator *enumerator = [_sub_views objectEnumerator]; NSView *sub; while ((sub = [enumerator nextObject]) != nil) { if (sub->_rFlags.needs_display) { [sub displayIfNeededIgnoringOpacity]; } } _rFlags.needs_display = NO; } } } - (void) displayIfNeededInRect: (NSRect)aRect { if (_rFlags.needs_display == NO) { if ([self isOpaque] == YES) { [self displayIfNeededInRectIgnoringOpacity: aRect]; } else { NSView *firstOpaque = [self opaqueAncestor]; NSRect rect; rect = [firstOpaque convertRect: aRect fromView: self]; [firstOpaque displayIfNeededInRectIgnoringOpacity: rect]; } } } - (void) displayIfNeededInRectIgnoringOpacity: (NSRect)aRect { if (_window == nil) { return; } if (_rFlags.needs_display == YES) { BOOL subviewNeedsDisplay = NO; NSRect neededRect; NSRect redrawRect; if (_coordinates_valid == NO) { [self _rebuildCoordinates]; } aRect = NSIntersectionRect(aRect, _visibleRect); redrawRect = NSIntersectionRect(aRect, _invalidRect); neededRect = NSIntersectionRect(_visibleRect, _invalidRect); if (NSIsEmptyRect(redrawRect) == NO) { [self lockFocusInRect: redrawRect]; [self drawRect: redrawRect]; [self unlockFocusNeedsFlush: YES]; } if (_rFlags.has_subviews == YES) { unsigned count = [_sub_views count]; if (count > 0) { NSView *array[count]; unsigned i; [_sub_views getObjects: array]; for (i = 0; i < count; i++) { NSRect isect; NSView *subview = array[i]; NSRect subviewFrame = subview->_frame; BOOL intersectCalculated = NO; if ([subview->_frameMatrix isRotated]) { [subview->_frameMatrix boundingRectFor: subviewFrame result: &subviewFrame]; } /* * Having drawn ourself into the rect, we must make sure that * subviews overlapping the area are redrawn. */ isect = NSIntersectionRect(redrawRect, subviewFrame); if (NSIsEmptyRect(isect) == NO) { isect = [subview convertRect: isect fromView: self]; intersectCalculated = YES; /* * hack the ivars of the subview directly for speed. */ subview->_rFlags.needs_display = YES; subview->_invalidRect = NSUnionRect(subview->_invalidRect, isect); } if (subview->_rFlags.needs_display == YES) { if (intersectCalculated == NO || NSEqualRects(aRect, redrawRect) == NO) { isect = NSIntersectionRect(aRect, subviewFrame); isect = [subview convertRect: isect fromView: self]; } [subview displayIfNeededInRectIgnoringOpacity: isect]; if (subview->_rFlags.needs_display == YES) { subviewNeedsDisplay = YES; } } } } } /* * If the rect we displayed contains the _invalidRect or _visibleRect * then we can empty _invalidRect. * If all subviews have been fully displayed, we can also turn off the * 'needs_display' flag. */ if (NSEqualRects(aRect, NSUnionRect(neededRect, aRect)) == YES) { _invalidRect = NSZeroRect; _rFlags.needs_display = subviewNeedsDisplay; } if (_rFlags.needs_display == YES && NSEqualRects(aRect, NSUnionRect(_visibleRect, aRect)) == YES) { _rFlags.needs_display = NO; } [_window flushWindow]; } } - (void) displayRect: (NSRect)rect { if ([self isOpaque] == YES) { [self displayRectIgnoringOpacity: rect]; } else { NSView *firstOpaque = [self opaqueAncestor]; rect = [firstOpaque convertRect: rect fromView: self]; [firstOpaque displayRectIgnoringOpacity: rect]; } } - (void) displayRectIgnoringOpacity: (NSRect)aRect { BOOL subviewNeedsDisplay = NO; NSRect neededRect; if (_window == nil) { return; } if (_coordinates_valid == NO) { [self _rebuildCoordinates]; } aRect = NSIntersectionRect(aRect, _visibleRect); neededRect = NSIntersectionRect(_invalidRect, _visibleRect); if (NSIsEmptyRect(aRect) == NO) { /* * Now we draw this view. */ [self lockFocusInRect: aRect]; [self drawRect: aRect]; [self unlockFocusNeedsFlush: YES]; } if (_rFlags.has_subviews == YES) { unsigned count = [_sub_views count]; if (count > 0) { NSView *array[count]; unsigned i; [_sub_views getObjects: array]; for (i = 0; i < count; ++i) { NSView *subview = array[i]; NSRect subviewFrame = subview->_frame; NSRect isect; BOOL intersectCalculated = NO; if ([subview->_frameMatrix isRotated] == YES) [subview->_frameMatrix boundingRectFor: subviewFrame result: &subviewFrame]; /* * Having drawn ourself into the rect, we must make sure that * subviews overlapping the area are redrawn. */ isect = NSIntersectionRect(aRect, subviewFrame); if (NSIsEmptyRect(isect) == NO) { isect = [subview convertRect: isect fromView: self]; intersectCalculated = YES; /* * hack the ivars of the subview directly for speed. */ subview->_rFlags.needs_display = YES; subview->_invalidRect = NSUnionRect(subview->_invalidRect, isect); } if (subview->_rFlags.needs_display == YES) { if (intersectCalculated == NO) { isect = [subview convertRect: isect fromView: self]; } [subview displayIfNeededInRectIgnoringOpacity: isect]; if (subview->_rFlags.needs_display == YES) { subviewNeedsDisplay = YES; } } } } } /* * If the rect we displayed contains the _invalidRect or _visibleRect * then we can empty _invalidRect. If all subviews have been * fully displayed, we can also turn off the 'needs_display' flag. */ if (NSEqualRects(aRect, NSUnionRect(neededRect, aRect)) == YES) { _invalidRect = NSZeroRect; _rFlags.needs_display = subviewNeedsDisplay; } if (_rFlags.needs_display == YES && NSEqualRects(aRect, NSUnionRect(_visibleRect, aRect)) == YES) { _rFlags.needs_display = NO; } [_window flushWindow]; } - (void) drawRect: (NSRect)rect {} - (NSRect) visibleRect { if (_coordinates_valid == NO) { [self _rebuildCoordinates]; } return _visibleRect; } - (void) setNeedsDisplay: (BOOL)flag { if (flag) { [self setNeedsDisplayInRect: _bounds]; } else { _rFlags.needs_display = NO; _invalidRect = NSZeroRect; } } - (void) setNeedsDisplayInRect: (NSRect)rect { NSView *currentView = _super_view; /* * Limit to bounds, combine with old _invalidRect, and then check to see * if the result is the same as the old _invalidRect - if it isn't then * set the new _invalidRect. */ rect = NSIntersectionRect(rect, _bounds); rect = NSUnionRect(_invalidRect, rect); if (NSEqualRects(rect, _invalidRect) == NO) { NSView *firstOpaque = [self opaqueAncestor]; _rFlags.needs_display = YES; _invalidRect = rect; if (firstOpaque == self) { [_window setViewsNeedDisplay: YES]; } else { rect = [firstOpaque convertRect: _invalidRect fromView: self]; [firstOpaque setNeedsDisplayInRect: rect]; } } /* * Must make sure that superviews know that we need display. * NB. we may have been marked as needing display and then moved to another * parent, so we can't assume that our parent is marked simply because we are. */ while (currentView) { currentView->_rFlags.needs_display = YES; currentView = currentView->_super_view; } } /* * Scrolling */ - (NSRect) adjustScroll: (NSRect)newVisible { return newVisible; } - (BOOL) autoscroll: (NSEvent*)theEvent { if (_super_view) return [_super_view autoscroll: theEvent]; return NO; } - (void) reflectScrolledClipView: (NSClipView*)aClipView {} - (void) scrollClipView: (NSClipView*)aClipView toPoint: (NSPoint)aPoint {} - (void) scrollPoint: (NSPoint)aPoint { NSClipView *s = (NSClipView*)_super_view; while (s != nil && [s isKindOfClass: [NSClipView class]] == NO) { s = (NSClipView*)[s superview]; } aPoint = [self convertPoint: aPoint toView: s]; if (NSEqualPoints(aPoint, [s bounds].origin) == NO) { [s scrollToPoint: aPoint]; } } - (void) scrollRect: (NSRect)aRect by: (NSSize)delta {} - (BOOL) scrollRectToVisible: (NSRect)aRect { NSClipView *s = (NSClipView*)_super_view; while (s != nil && [s isKindOfClass: [NSClipView class]] == NO) { s = (NSClipView*)[s superview]; } if (s != nil) { NSRect vRect = [self visibleRect]; NSPoint aPoint = vRect.origin; BOOL shouldScroll = NO; if (vRect.size.width == 0 && vRect.size.height == 0) return NO; if (!(NSMinX(vRect) <= NSMinX(aRect) && (NSMaxX(vRect) >= NSMaxX(aRect)))) { shouldScroll = YES; if (aRect.origin.x < vRect.origin.x) aPoint.x = aRect.origin.x; else { float visibleRange = vRect.origin.x + vRect.size.width; float aRectRange = aRect.origin.x + aRect.size.width; aPoint.x = vRect.origin.x + (aRectRange - visibleRange); } } if (!(NSMinY(vRect) <= NSMinY(aRect) && (NSMaxY(vRect) >= NSMaxY(aRect)))) { shouldScroll = YES; if (aRect.origin.y < vRect.origin.y) aPoint.y = aRect.origin.y; else { float visibleRange = vRect.origin.y + vRect.size.height; float aRectRange = aRect.origin.y + aRect.size.height; aPoint.y = vRect.origin.y + (aRectRange - visibleRange); } } if (shouldScroll) { aPoint = [self convertPoint: aPoint toView: s]; [s scrollToPoint: aPoint]; return YES; } } return NO; } - (NSScrollView*) enclosingScrollView { id aView = [self superview]; while (aView != nil) { if ([aView isKindOfClass: [NSScrollView class]]) { break; } aView = [aView superview]; } return aView; } /* * Managing the Cursor * * We use the tracking rectangle class to maintain the cursor rects */ - (void) addCursorRect: (NSRect)aRect cursor: (NSCursor*)anObject { if (_window != nil) { GSTrackingRect *m; aRect = [self convertRect: aRect toView: nil]; m = [rectClass allocWithZone: NSDefaultMallocZone()]; m = [m initWithRect: aRect tag: 0 owner: anObject userData: NULL inside: YES]; [_cursor_rects addObject: m]; RELEASE(m); _rFlags.has_currects = 1; _rFlags.valid_rects = 1; } } - (void) discardCursorRects { if (_rFlags.has_currects != 0) { if (_rFlags.valid_rects != 0) { [_cursor_rects makeObjectsPerformSelector: @selector(invalidate)]; _rFlags.valid_rects = 0; } [_cursor_rects removeAllObjects]; _rFlags.has_currects = 0; } } - (void) removeCursorRect: (NSRect)aRect cursor: (NSCursor*)anObject { id e = [_cursor_rects objectEnumerator]; GSTrackingRect *o; NSCursor *c; /* Base remove test upon cursor object */ o = [e nextObject]; while (o) { c = [o owner]; if (c == anObject) { [o invalidate]; [_cursor_rects removeObject: o]; if ([_cursor_rects count] == 0) { _rFlags.has_currects = 0; _rFlags.valid_rects = 0; } break; } else { o = [e nextObject]; } } } - (void) resetCursorRects { } static NSView* findByTag(NSView *view, int aTag, unsigned *level) { unsigned i, count; NSArray *sub = [view subviews]; count = [sub count]; if (count > 0) { NSView *array[count]; [sub getObjects: array]; for (i = 0; i < count; i++) { if ([array[i] tag] == aTag) return array[i]; } *level += 1; for (i = 0; i < count; i++) { NSView *v; v = findByTag(array[i], aTag, level); if (v != nil) return v; } *level -= 1; } return nil; } - (id) viewWithTag: (int)aTag { NSView *view = nil; /* * If we have the specified tag - return self. */ if ([self tag] == aTag) { view = self; } else if (_rFlags.has_subviews) { unsigned count = [_sub_views count]; if (count > 0) { NSView *array[count]; unsigned i; [_sub_views getObjects: array]; /* * Quick check to see if any of our direct descendents has the tag. */ for (i = 0; i < count; i++) { view = array[i]; if ([view tag] == aTag) break; } if (view == nil) { unsigned level = 0xffffffff; /* * Ok - do it the long way - search the while tree for each of * our descendents and see which has the closest view matching * the tag. */ for (i = 0; i < count; i++) { unsigned l = 0; NSView *v; v = findByTag(array[i], aTag, &l); if (v != nil && l < level) { view = v; level = l; } } } } } return view; } /* * Aiding Event Handling */ - (BOOL) acceptsFirstMouse: (NSEvent*)theEvent { return NO; } - (NSView*) hitTest: (NSPoint)aPoint { NSPoint p; unsigned count; NSView *v = nil, *w; /* If not within our frame then it can't be a hit */ if (![_super_view mouse: aPoint inRect: _frame]) return nil; p = [self convertPoint: aPoint fromView: _super_view]; if (_rFlags.has_subviews) { count = [_sub_views count]; if (count > 0) { NSView* array[count]; [_sub_views getObjects: array]; while (count > 0) { w = array[--count]; v = [w hitTest: p]; if (v) break; } } } /* * mouse is either in the subview or within self */ if (v) return v; else return self; } - (BOOL) mouse: (NSPoint)aPoint inRect: (NSRect)aRect { if (aPoint.x < aRect.origin.x) return NO; if (aPoint.y < aRect.origin.y) return NO; if (aPoint.x > (aRect.origin.x + aRect.size.width)) return NO; if (aPoint.y > (aRect.origin.y + aRect.size.height)) return NO; return YES; } - (BOOL) performKeyEquivalent: (NSEvent*)theEvent { unsigned i; for (i = 0; i < [_sub_views count]; i++) if ([[_sub_views objectAtIndex: i] performKeyEquivalent: theEvent] == YES) return YES; return NO; } - (void) removeTrackingRect: (NSTrackingRectTag)tag { unsigned i, j; GSTrackingRect *m; j = [_tracking_rects count]; for (i = 0;i < j; ++i) { m = (GSTrackingRect*)[_tracking_rects objectAtIndex: i]; if ([m tag] == tag) { [_tracking_rects removeObjectAtIndex: i]; if ([_tracking_rects count] == 0) _rFlags.has_trkrects = 0; return; } } } - (BOOL) shouldDelayWindowOrderingForEvent: (NSEvent*)anEvent { return NO; } - (NSTrackingRectTag) addTrackingRect: (NSRect)aRect owner: (id)anObject userData: (void*)data assumeInside: (BOOL)flag { NSTrackingRectTag t; unsigned i, j; GSTrackingRect *m; t = 0; j = [_tracking_rects count]; for (i = 0; i < j; ++i) { m = (GSTrackingRect*)[_tracking_rects objectAtIndex: i]; if ([m tag] > t) t = [m tag]; } ++t; aRect = [self convertRect: aRect toView: nil]; m = [[rectClass alloc] initWithRect: aRect tag: t owner: anObject userData: data inside: flag]; [_tracking_rects addObject: m]; RELEASE(m); _rFlags.has_trkrects = 1; return t; } - (void) setNextKeyView: (NSView *)aView { if (!aView) { _nextKeyView = nil; return; } if ([aView isKindOfClass: viewClass]) { // As an exception, we do not retain aView, to avoid retain loops // (the simplest being a view retaining and being retained // by another view), which prevents objects from being ever // deallocated. To understand how we manage without retaining // _nextKeyView, see [NSView -dealloc]. _nextKeyView = aView; if ([aView previousKeyView] != self) [aView setPreviousKeyView: self]; } } - (NSView *) nextKeyView { return _nextKeyView; } - (NSView *) nextValidKeyView { NSView *theView; theView = _nextKeyView; while (1) { if ([theView acceptsFirstResponder] || (theView == nil) || (theView == self)) return theView; theView = [theView nextKeyView]; } } - (void) setPreviousKeyView: (NSView *)aView { if (!aView) { _previousKeyView = nil; return; } if ([aView isKindOfClass: viewClass]) { _previousKeyView = aView; if ([aView nextKeyView] != self) [aView setNextKeyView: self]; } } - (NSView *) previousKeyView { return _previousKeyView; } - (NSView *) previousValidKeyView { NSView *theView; theView = _previousKeyView; while (1) { if ([theView acceptsFirstResponder] || (theView == nil) || (theView == self)) return theView; theView = [theView previousKeyView]; } } /* * Dragging */ - (BOOL) dragFile: (NSString*)filename fromRect: (NSRect)rect slideBack: (BOOL)slideFlag event: (NSEvent*)event { return NO; } - (void) dragImage: (NSImage*)anImage at: (NSPoint)viewLocation offset: (NSSize)initialOffset event: (NSEvent*)event pasteboard: (NSPasteboard*)pboard source: (id)sourceObject slideBack: (BOOL)slideFlag { NSView *dragView = (NSView*)[GSCurrentContext() _dragInfo]; [dragView dragImage: anImage at: viewLocation offset: initialOffset event: event pasteboard: pboard source: sourceObject slideBack: slideFlag]; } - (void) registerForDraggedTypes: (NSArray*)types { NSArray *o; NSArray *t; if (types == nil || [types count] == 0) [NSException raise: NSInvalidArgumentException format: @"Types information missing"]; /* * Get the old drag types for this view if we need to tell the context * to change the registered types for the window. */ if (_rFlags.has_draginfo == 1 && _window != nil) { o = GSGetDragTypes(self); TEST_RETAIN(o); } else { o = nil; } t = GSSetDragTypes(self, types); _rFlags.has_draginfo = 1; if (_window != nil) { NSGraphicsContext *ctxt = GSCurrentContext(); [ctxt _addDragTypes: t toWindow: [_window windowNumber]]; if (o != nil) { [ctxt _removeDragTypes: o fromWindow: [_window windowNumber]]; } } TEST_RELEASE(o); } - (void) unregisterDraggedTypes { if (_rFlags.has_draginfo) { if (_window != nil) { NSGraphicsContext *ctxt = GSCurrentContext(); NSArray *t = GSGetDragTypes(self); [ctxt _removeDragTypes: t fromWindow: [_window windowNumber]]; } GSRemoveDragTypes(self); _rFlags.has_draginfo = 0; } } /* * Printing */ - (NSData*) dataWithEPSInsideRect: (NSRect)aRect { return nil; } - (void) fax: (id)sender { } - (void) print: (id)sender { } - (void) writeEPSInsideRect: (NSRect)rect toPasteboard: (NSPasteboard*)pasteboard { } /* * Pagination */ - (void) adjustPageHeightNew: (float*)newBottom top: (float)oldTop bottom: (float)oldBottom limit: (float)bottomLimit { } - (void) adjustPageWidthNew: (float*)newRight left: (float)oldLeft right: (float)oldRight limit: (float)rightLimit { } - (float) heightAdjustLimit { return 0; } - (BOOL) knowsPagesFirst: (int*)firstPageNum last: (int*)lastPageNum { return NO; } - (NSPoint) locationOfPrintRect: (NSRect)aRect { return NSZeroPoint; } - (NSRect) rectForPage: (int)page { return NSZeroRect; } - (float) widthAdjustLimit { return 0; } /* * Writing Conforming PostScript */ - (void) beginPage: (int)ordinalNum label: (NSString*)aString bBox: (NSRect)pageRect fonts: (NSString*)fontNames { } - (void) beginPageSetupRect: (NSRect)aRect placement: (NSPoint)location { } - (void) beginPrologueBBox: (NSRect)boundingBox creationDate: (NSString*)dateCreated createdBy: (NSString*)anApplication fonts: (NSString*)fontNames forWhom: (NSString*)user pages: (int)numPages title: (NSString*)aTitle { } - (void) addToPageSetup { } - (void) beginSetup { } - (void) beginTrailer { } - (void) drawPageBorderWithSize: (NSSize)borderSize { } - (void) drawSheetBorderWithSize: (NSSize)borderSize { } - (void) endHeaderComments { } - (void) endPrologue { } - (void) endSetup { } - (void) endPageSetup { } - (void) endPage { } - (void) endTrailer { } /* * NSCoding protocol */ - (void) encodeWithCoder: (NSCoder*)aCoder { [super encodeWithCoder: aCoder]; NSDebugLLog(@"NSView", @"NSView: start encoding\n"); [aCoder encodeRect: _frame]; [aCoder encodeRect: _bounds]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_is_rotated_from_base]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_is_rotated_or_scaled_from_base]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_post_frame_changes]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_autoresizes_subviews]; [aCoder encodeValueOfObjCType: @encode(unsigned int) at: &_autoresizingMask]; [aCoder encodeConditionalObject: _nextKeyView]; [aCoder encodeConditionalObject: _previousKeyView]; [aCoder encodeObject: _sub_views]; NSDebugLLog(@"NSView", @"NSView: finish encoding\n"); } - (id) initWithCoder: (NSCoder*)aDecoder { NSRect rect; NSEnumerator *e; NSView *sub; NSArray *subs; self = [super initWithCoder: aDecoder]; NSDebugLLog(@"NSView", @"NSView: start decoding\n"); _frame = [aDecoder decodeRect]; _bounds.origin = NSZeroPoint; _bounds.size = _frame.size; _frameMatrix = [NSAffineTransform new]; // Map fromsuperview to frame _boundsMatrix = [NSAffineTransform new]; // Map fromsuperview to bounds _matrixToWindow = [NSAffineTransform new]; // Map to window coordinates _matrixFromWindow = [NSAffineTransform new]; // Map from window coordinates [_frameMatrix setFrameOrigin: _frame.origin]; rect = [aDecoder decodeRect]; [self setBounds: rect]; _sub_views = [NSMutableArray new]; _tracking_rects = [NSMutableArray new]; _cursor_rects = [NSMutableArray new]; _super_view = nil; _window = nil; _rFlags.needs_display = YES; _coordinates_valid = NO; _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]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_post_frame_changes]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_autoresizes_subviews]; [aDecoder decodeValueOfObjCType: @encode(unsigned int) at: &_autoresizingMask]; _nextKeyView = [aDecoder decodeObject]; _previousKeyView = [aDecoder decodeObject]; [aDecoder decodeValueOfObjCType: @encode(id) at: &subs]; e = [subs objectEnumerator]; while ((sub = [e nextObject]) != nil) { NSAssert(sub->_window == nil, NSInternalInconsistencyException); NSAssert(sub->_super_view == nil, NSInternalInconsistencyException); [sub viewWillMoveToWindow: _window]; [sub viewWillMoveToSuperview: self]; [sub setNextResponder: self]; [_sub_views addObject: sub]; _rFlags.has_subviews = 1; [sub resetCursorRects]; [sub setNeedsDisplay: YES]; } RELEASE(subs); NSDebugLLog(@"NSView", @"NSView: finish decoding\n"); return self; } /* * Accessor methods */ - (void) setAutoresizesSubviews: (BOOL)flag { _autoresizes_subviews = flag; } - (void) setAutoresizingMask: (unsigned int)mask { _autoresizingMask = mask; } - (NSWindow*) window { return _window; } - (BOOL) autoresizesSubviews { return _autoresizes_subviews; } - (unsigned int) autoresizingMask { return _autoresizingMask; } - (NSArray*) subviews { /* * Return a mutable copy 'cos we know that a mutable copy of an array or * a mutable array does a shallow copy - which is what we want to give * away - we don't want people to mess with our actual subviews array. */ return AUTORELEASE([_sub_views mutableCopyWithZone: NSDefaultMallocZone()]); } - (NSView*) superview { return _super_view; } - (BOOL) shouldDrawColor { return YES; } - (BOOL) isOpaque { return NO; } - (BOOL) needsDisplay { return _rFlags.needs_display; } - (int) tag { return -1; } - (BOOL) isFlipped { return NO; } - (NSRect) bounds { return _bounds; } - (NSRect) frame { return _frame; } - (float) boundsRotation { return [_boundsMatrix rotationAngle]; } - (float) frameRotation { return [_frameMatrix rotationAngle]; } - (BOOL) postsFrameChangedNotifications { return _post_frame_changes; } - (BOOL) postsBoundsChangedNotifications { return _post_bounds_changes; } /* * Private methods. */ /* * The [-_invalidateCoordinates] method marks the coordinate mapping * matrices (matrixFromWindof and _matrixToWindow) and the cached visible * rectangle as invalid. It recursively invalidates the coordinates for * all subviews as well. * This method must be called whenever the size, shape or position of * the view is changed in any way. */ - (void) _invalidateCoordinates { if (_coordinates_valid == YES) { unsigned count; _coordinates_valid = NO; if (_rFlags.valid_rects != 0) { [_window invalidateCursorRectsForView: self]; } if (_rFlags.has_subviews) { count = [_sub_views count]; if (count > 0) { NSView* array[count]; unsigned i; [_sub_views getObjects: array]; for (i = 0; i < count; i++) { NSView *sub = array[i]; if (sub->_coordinates_valid == YES) { (*invalidateImp)(sub, invalidateSel); } } } } } } /* * The [-_matrixFromWindow] method returns a matrix that can be used to * map coordinates in the windows coordinate system to coordinates in the * views coordinate system. It rebuilds the mapping matrices and * visible rectangle cache if necessary. * All coordinate transformations use this matrix. */ - (NSAffineTransform*) _matrixFromWindow { if (_coordinates_valid == NO) { [self _rebuildCoordinates]; } return _matrixFromWindow; } /* * The [-_matrixToWindow] method returns a matrix that can be used to * map coordinates in the views coordinate system to coordinates in the * windows coordinate system. It rebuilds the mapping matrices and * visible rectangle cache if necessary. * All coordinate transformations use this matrix. */ - (NSAffineTransform*) _matrixToWindow { if (_coordinates_valid == NO) { [self _rebuildCoordinates]; } return _matrixToWindow; } /* * The [-_rebuildCoordinates] method rebuilds the coordinate mapping * matrices (matrixFromWindof and _matrixToWindow) and the cached visible * rectangle if they have been invalidated. */ - (void) _rebuildCoordinates { if (_coordinates_valid == NO) { _coordinates_valid = YES; if (!_window) { _visibleRect = NSZeroRect; [_matrixToWindow makeIdentityMatrix]; [_matrixFromWindow makeIdentityMatrix]; } if (!_super_view) { _visibleRect = _bounds; [_matrixToWindow makeIdentityMatrix]; [_matrixFromWindow makeIdentityMatrix]; } else { NSRect superviewsVisibleRect; BOOL wasFlipped = _super_view->_rFlags.flipped_view; float vals[6]; NSAffineTransform *pMatrix = [_super_view _matrixToWindow]; [pMatrix getMatrix: vals]; [_matrixToWindow setMatrix: vals]; (*appImp)(_matrixToWindow, appSel, _frameMatrix); if (_rFlags.flipped_view != wasFlipped) { /* * The flipping process must result in a coordinate system that * exactly overlays the original. To do that, we must translate * the origin by the height of the view. */ flip->matrix.ty = _bounds.size.height; (*appImp)(_matrixToWindow, appSel, flip); } (*appImp)(_matrixToWindow, appSel, _boundsMatrix); [_matrixToWindow getMatrix: vals]; [_matrixFromWindow setMatrix: vals]; [_matrixFromWindow inverse]; superviewsVisibleRect = [self convertRect: [_super_view visibleRect] fromView: _super_view]; _visibleRect = NSIntersectionRect(superviewsVisibleRect, _bounds); } } } @end