mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
Calculations of the visible rect can be a heavy operation as it depends of the superviews visible rect. They have to be transformed and intersected together to create the result. This calculation is a recursive operation that travels up the view hierarchy all the way to the top. Updating the tracking areas is also a recursive operation. But it travels down the view hierarchy instead. It will calculate the new tracking area using the visible rect for the current view. For each view it updates it will get the visible rect that has to travel all the way up the view hierarchy to calculate it by transform and intersect them together. This results in that the visible rect will be calculated for each view multible times. This makes it a very slow operation, specially for deeper view hierarchies. This fix will send along the visible rect for the superview when traveling down the view hierarchy. This means that the visible rect does not need to travel up the view hierarchy to be calculated. It will just need transform and intersect the provided rect for its superview with the one from itself.
174 lines
7.1 KiB
Plaintext
174 lines
7.1 KiB
Plaintext
/*
|
|
* CPTrackingArea.j
|
|
* AppKit
|
|
*
|
|
* Created by Didier Korthoudt.
|
|
* Copyright 2015, Cappuccino Project.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
@import <Foundation/Foundation.j>
|
|
|
|
@class CPView
|
|
|
|
/* @group CPTrackingAreaOptions */
|
|
@typedef CPTrackingAreaOptions
|
|
CPTrackingMouseEnteredAndExited = 1 << 1;
|
|
CPTrackingMouseMoved = 1 << 2;
|
|
CPTrackingCursorUpdate = 1 << 3;
|
|
CPTrackingActiveWhenFirstResponder = 1 << 4;
|
|
CPTrackingActiveInKeyWindow = 1 << 5;
|
|
CPTrackingActiveInActiveApp = 1 << 6;
|
|
CPTrackingActiveAlways = 1 << 7;
|
|
CPTrackingAssumeInside = 1 << 8;
|
|
CPTrackingInVisibleRect = 1 << 9;
|
|
CPTrackingEnabledDuringMouseDrag = 1 << 10;
|
|
|
|
var CPTrackingAreaViewRectKey = @"CPTrackinkAreaViewRectKey",
|
|
CPTrackingAreaOptionsKey = @"CPTrackingAreaOptionsKey",
|
|
CPTrackingAreaOwnerKey = @"CPTrackingAreaOwnerKey",
|
|
CPTrackingAreaUserInfoKey = @"CPTrackingAreaUserInfoKey",
|
|
CPTrackingAreaReferencingViewKey = @"CPTrackingAreaReferencingViewKey",
|
|
CPTrackingAreaWindowRect = @"CPTrackingAreaWindowRect";
|
|
|
|
CPTrackingOwnerImplementsMouseEntered = 1 << 1;
|
|
CPTrackingOwnerImplementsMouseExited = 1 << 2;
|
|
CPTrackingOwnerImplementsMouseMoved = 1 << 3;
|
|
CPTrackingOwnerImplementsCursorUpdate = 1 << 4;
|
|
|
|
/*!
|
|
@ingroup appkit
|
|
|
|
A CPTrackingArea defines a region of view that generates mouse-tracking and
|
|
cursor-update events when the mouse is over that region.
|
|
*/
|
|
@implementation CPTrackingArea : CPObject
|
|
{
|
|
CGRect _viewRect @accessors(getter=rect);
|
|
CPTrackingAreaOptions _options @accessors(getter=options);
|
|
id _owner @accessors(getter=owner);
|
|
CPDictionary _userInfo @accessors(getter=userInfo);
|
|
|
|
CPView _referencingView @accessors(property=view);
|
|
CGRect _windowRect @accessors(getter=windowRect);
|
|
|
|
unsigned _implementedOwnerMethods @accessors(getter=implementedOwnerMethods);
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Initialization
|
|
|
|
/*!
|
|
Initializes and returns an object defining a region of a view to receive mouse-tracking events, mouse-moved events, cursor-update events, or possibly
|
|
all these events.
|
|
*/
|
|
- (CPTrackingArea)initWithRect:(CGRect)aRect options:(CPTrackingAreaOptions)options owner:(id)owner userInfo:(CPDictionary)userInfo
|
|
{
|
|
if (owner === nil)
|
|
[CPException raise:CPInternalInconsistencyException reason:"No owner specified"];
|
|
|
|
if (options === 0)
|
|
[CPException raise:CPInternalInconsistencyException reason:"Invalid CPTrackingArea options"];
|
|
|
|
// Check options:
|
|
// - at least one of CPTrackingMouseEnteredAndExited, CPTrackingMouseMoved, CPTrackingCursorUpdate
|
|
// - exactly one of CPTrackingActiveWhenFirstResponder, CPTrackingActiveInKeyWindow, CPTrackingActiveInActiveApp, CPTrackingActiveAlways
|
|
// - no check on CPTrackingAssumeInside, CPTrackingInVisibleRect, CPTrackingEnableDuringMouseDrag
|
|
|
|
if (!((options & CPTrackingMouseEnteredAndExited) || (options & CPTrackingMouseMoved) || (options & CPTrackingCursorUpdate)))
|
|
[CPException raise:CPInternalInconsistencyException reason:"Invalid CPTrackingAreaOptions: must use at least one of [CPTrackingMouseEnteredAndExited | CPTrackingMouseMoved | CPTrackingCursorUpdate]"];
|
|
|
|
if ((((options & CPTrackingActiveWhenFirstResponder) > 0) + ((options & CPTrackingActiveInKeyWindow) > 0) + ((options & CPTrackingActiveInActiveApp) > 0) + ((options & CPTrackingActiveAlways) > 0)) !== 1)
|
|
[CPException raise:CPInternalInconsistencyException reason:"Tracking area options may only specify one of [CPTrackingActiveWhenFirstResponder | CPTrackingActiveInKeyWindow | CPTrackingActiveInActiveApp | CPTrackingActiveAlways]."];
|
|
|
|
if (self = [super init])
|
|
{
|
|
_viewRect = aRect;
|
|
_options = options;
|
|
_owner = owner;
|
|
_userInfo = userInfo;
|
|
|
|
// Cache owner implemented methods
|
|
|
|
if ([_owner respondsToSelector:@selector(mouseEntered:)])
|
|
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseEntered;
|
|
|
|
if ([_owner respondsToSelector:@selector(mouseExited:)])
|
|
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseExited;
|
|
|
|
if ([_owner respondsToSelector:@selector(mouseMoved:)])
|
|
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseMoved;
|
|
|
|
if ([_owner respondsToSelector:@selector(cursorUpdate:)])
|
|
_implementedOwnerMethods |= CPTrackingOwnerImplementsCursorUpdate;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Implementation
|
|
|
|
- (void)_updateWindowRect
|
|
{
|
|
[self _updateWindowRectWithReferencingSuperViewVisibleRect:nil];
|
|
}
|
|
|
|
/*!
|
|
To speed up things we allow the caller to pass the visible rect of the referencing view's superview.
|
|
This allows the visible rect calculations to be optimized when traveling down the view hierarchy.
|
|
*/
|
|
- (void)_updateWindowRectWithReferencingSuperViewVisibleRect:(CGRect)referencingSuperviewVisibleRect
|
|
{
|
|
_windowRect = [_referencingView convertRect:((_options & CPTrackingInVisibleRect) ? [_referencingView _visibleRectWithSuperviewVisibleRect:referencingSuperviewVisibleRect] : _viewRect) toView:[[_referencingView window] _windowView]];
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
#pragma mark CPCoding
|
|
|
|
@implementation CPTrackingArea (CPCoding)
|
|
|
|
- (id)initWithCoder:(CPCoder)aCoder
|
|
{
|
|
if (self = [super init])
|
|
{
|
|
_viewRect = [aCoder decodeObjectForKey:CPTrackingAreaViewRectKey];
|
|
_options = [aCoder decodeObjectForKey:CPTrackingAreaOptionsKey];
|
|
_owner = [aCoder decodeObjectForKey:CPTrackingAreaOwnerKey];
|
|
_userInfo = [aCoder decodeObjectForKey:CPTrackingAreaUserInfoKey];
|
|
_referencingView = [aCoder decodeObjectForKey:CPTrackingAreaReferencingViewKey];
|
|
_windowRect = [aCoder decodeObjectForKey:CPTrackingAreaWindowRect];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
{
|
|
[aCoder encodeObject:_viewRect forKey:CPTrackingAreaViewRectKey];
|
|
[aCoder encodeObject:_options forKey:CPTrackingAreaOptionsKey];
|
|
[aCoder encodeObject:_owner forKey:CPTrackingAreaOwnerKey];
|
|
[aCoder encodeObject:_userInfo forKey:CPTrackingAreaUserInfoKey];
|
|
[aCoder encodeObject:_referencingView forKey:CPTrackingAreaReferencingViewKey];
|
|
[aCoder encodeObject:_windowRect forKey:CPTrackingAreaWindowRect];
|
|
}
|
|
|
|
@end
|