diff options
author | davidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-19 23:05:37 +0000 |
---|---|---|
committer | davidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-19 23:05:37 +0000 |
commit | e5f5d63c986365509b388146d6985cd968cb46d9 (patch) | |
tree | 7ca863b2fd41ee36de05f9291d03dcff4789ec77 /chrome | |
parent | ef044ebebc47d4ee9636f25c61ab079411630126 (diff) | |
download | chromium_src-e5f5d63c986365509b388146d6985cd968cb46d9.zip chromium_src-e5f5d63c986365509b388146d6985cd968cb46d9.tar.gz chromium_src-e5f5d63c986365509b388146d6985cd968cb46d9.tar.bz2 |
Respect Spaces when dragging tabs on OS X
For 10.6 and above, we can simply filter windows out with isOnActiveSpace. For
10.5, there is another API in CoreGraphics that gives us the same information.
It is slow and causes noticeable CPU usage during a drag, so cache it per-drag.
R=pinkerton
BUG=32796
TEST=open windows on separate spaces, drag a tab over where a window is on the other space
Review URL: http://codereview.chromium.org/2962018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52960 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/cocoa/tab_view.h | 9 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_view.mm | 67 |
2 files changed, 76 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/tab_view.h b/chrome/browser/cocoa/tab_view.h index 0e1149f..6d4898e 100644 --- a/chrome/browser/cocoa/tab_view.h +++ b/chrome/browser/cocoa/tab_view.h @@ -6,6 +6,9 @@ #define CHROME_BROWSER_COCOA_TAB_VIEW_H_ #import <Cocoa/Cocoa.h> +#include <ApplicationServices/ApplicationServices.h> + +#include <map> #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/background_gradient_view.h" @@ -81,6 +84,12 @@ enum AlertState { TabWindowController* draggedController_; // weak. Controller being dragged. NSWindow* dragWindow_; // weak. The window being dragged NSWindow* dragOverlay_; // weak. The overlay being dragged + // Cache workspace IDs per-drag because computing them on 10.5 with + // CGWindowListCreateDescriptionFromArray is expensive. + // resetDragControllers clears this cache. + // + // TODO(davidben): When 10.5 becomes unsupported, remove this. + std::map<CGWindowID, int> workspaceIDCache_; TabWindowController* targetController_; // weak. Controller being targeted NSCellStateValue state_; diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm index 7f34aa5..82217de 100644 --- a/chrome/browser/cocoa/tab_view.mm +++ b/chrome/browser/cocoa/tab_view.mm @@ -5,7 +5,9 @@ #import "chrome/browser/cocoa/tab_view.h" #include "base/logging.h" +#import "base/mac_util.h" #include "base/nsimage_cache_mac.h" +#include "base/scoped_cftyperef.h" #include "chrome/browser/browser_theme_provider.h" #import "chrome/browser/cocoa/tab_controller.h" #import "chrome/browser/cocoa/tab_window_controller.h" @@ -46,6 +48,8 @@ const CGFloat kRapidCloseDist = 2.5; - (void)resetLastGlowUpdateTime; - (NSTimeInterval)timeElapsedSinceLastGlowUpdate; - (void)adjustGlowValue; +// TODO(davidben): When we stop supporting 10.5, this can be removed. +- (int)getWorkspaceID:(NSWindow*)window useCache:(BOOL)useCache; @end // TabView(Private) @@ -161,6 +165,20 @@ const CGFloat kRapidCloseDist = 2.5; for (NSWindow* window in [NSApp orderedWindows]) { if (window == dragWindow) continue; if (![window isVisible]) continue; + // Skip windows on the wrong space. + if ([window respondsToSelector:@selector(isOnActiveSpace)]) { + if (![window performSelector:@selector(isOnActiveSpace)]) + continue; + } else { + // TODO(davidben): When we stop supporting 10.5, this can be + // removed. + // + // We don't cache the workspace of |dragWindow| because it may + // move around spaces. + if ([self getWorkspaceID:dragWindow useCache:NO] != + [self getWorkspaceID:window useCache:YES]) + continue; + } NSWindowController* controller = [window windowController]; if ([controller isKindOfClass:[TabWindowController class]]) { TabWindowController* realController = @@ -180,6 +198,7 @@ const CGFloat kRapidCloseDist = 2.5; sourceController_ = nil; sourceWindow_ = nil; targetController_ = nil; + workspaceIDCache_.clear(); } // Sets whether the window background should be visible or invisible when @@ -963,4 +982,52 @@ const CGFloat kRapidCloseDist = 2.5; [self setNeedsDisplay:YES]; } +// Returns the workspace id of |window|. If |useCache|, then lookup +// and remember the value in |workspaceIDCache_| until the end of the +// current drag. +- (int)getWorkspaceID:(NSWindow*)window useCache:(BOOL)useCache { + CGWindowID windowID = [window windowNumber]; + if (useCache) { + std::map<CGWindowID, int>::iterator iter = + workspaceIDCache_.find(windowID); + if (iter != workspaceIDCache_.end()) + return iter->second; + } + + int workspace = -1; + // It's possible to query in bulk, but probably not necessary. + scoped_cftyperef<CFArrayRef> windowIDs(CFArrayCreate( + NULL, reinterpret_cast<const void **>(&windowID), 1, NULL)); + scoped_cftyperef<CFArrayRef> descriptions( + CGWindowListCreateDescriptionFromArray(windowIDs)); + DCHECK(CFArrayGetCount(descriptions.get()) <= 1); + if (CFArrayGetCount(descriptions.get()) > 0) { + CFDictionaryRef dict = static_cast<CFDictionaryRef>( + CFArrayGetValueAtIndex(descriptions.get(), 0)); + DCHECK(CFGetTypeID(dict) == CFDictionaryGetTypeID()); + + // Sanity check the ID. + CFNumberRef otherIDRef = (CFNumberRef)mac_util::GetValueFromDictionary( + dict, kCGWindowNumber, CFNumberGetTypeID()); + CGWindowID otherID; + if (otherIDRef && + CFNumberGetValue(otherIDRef, kCGWindowIDCFNumberType, &otherID) && + otherID == windowID) { + // And then get the workspace. + CFNumberRef workspaceRef = (CFNumberRef)mac_util::GetValueFromDictionary( + dict, kCGWindowWorkspace, CFNumberGetTypeID()); + if (!workspaceRef || + !CFNumberGetValue(workspaceRef, kCFNumberIntType, &workspace)) { + workspace = -1; + } + } else { + NOTREACHED(); + } + } + if (useCache) { + workspaceIDCache_[windowID] = workspace; + } + return workspace; +} + @end // @implementation TabView(Private) |