Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(276)

Side by Side Diff: chrome/browser/cocoa/tab_strip_controller.mm

Issue 174461: (Mac) Make mashing the close tab button work. (Closed)
Patch Set: Rebased to ToT. Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/cocoa/tab_strip_controller.h ('k') | chrome/browser/cocoa/tab_view.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/cocoa/tab_strip_controller.h" 5 #import "chrome/browser/cocoa/tab_strip_controller.h"
6 6
7 #include "app/l10n_util.h" 7 #include "app/l10n_util.h"
8 #include "base/mac_util.h" 8 #include "base/mac_util.h"
9 #include "base/sys_string_conversions.h" 9 #include "base/sys_string_conversions.h"
10 #include "chrome/app/chrome_dll_resource.h" 10 #include "chrome/app/chrome_dll_resource.h"
(...skipping 19 matching lines...) Expand all
30 #include "chrome/browser/tabs/tab_strip_model.h" 30 #include "chrome/browser/tabs/tab_strip_model.h"
31 #include "grit/generated_resources.h" 31 #include "grit/generated_resources.h"
32 #include "skia/ext/skia_utils_mac.h" 32 #include "skia/ext/skia_utils_mac.h"
33 33
34 NSString* const kTabStripNumberOfTabsChanged = @"kTabStripNumberOfTabsChanged"; 34 NSString* const kTabStripNumberOfTabsChanged = @"kTabStripNumberOfTabsChanged";
35 35
36 // A value to indicate tab layout should use the full available width of the 36 // A value to indicate tab layout should use the full available width of the
37 // view. 37 // view.
38 static const float kUseFullAvailableWidth = -1.0; 38 static const float kUseFullAvailableWidth = -1.0;
39 39
40 // A simple view class that prevents the windowserver from dragging the 40 // A simple view class that prevents the Window Server from dragging the area
41 // area behind tabs. Sometimes core animation confuses it. 41 // behind tabs. Sometimes core animation confuses it. Unfortunately, it can also
42 @interface TabStripControllerDragBlockingView : NSView 42 // falsely pick up clicks during rapid tab closure, so we have to account for
43 // that.
44 @interface TabStripControllerDragBlockingView : NSView {
45 TabStripController* controller_; // weak; owns us
46 }
47
48 - (id)initWithFrame:(NSRect)frameRect
49 controller:(TabStripController*)controller;
43 @end 50 @end
44 @implementation TabStripControllerDragBlockingView 51 @implementation TabStripControllerDragBlockingView
45 - (BOOL)mouseDownCanMoveWindow {return NO;} 52 - (BOOL)mouseDownCanMoveWindow {return NO;}
46 - (void)drawRect:(NSRect)rect {} 53 - (void)drawRect:(NSRect)rect {}
54
55 - (id)initWithFrame:(NSRect)frameRect
56 controller:(TabStripController*)controller {
57 if ((self = [super initWithFrame:frameRect]))
58 controller_ = controller;
59 return self;
60 }
61
62 // In "rapid tab closure" mode (i.e., the user is clicking close tab buttons in
63 // rapid succession), the animations confuse Cocoa's hit testing (which appears
64 // to use cached results, among other tricks), so this view can somehow end up
65 // getting a mouse down event. Thus we do an explicit hit test during rapid tab
66 // closure, and if we find that we got a mouse down we shouldn't have, we send
67 // it off to the appropriate view.
68 - (void)mouseDown:(NSEvent*)event {
69 if ([controller_ inRapidClosureMode]) {
70 NSView* superview = [self superview];
71 NSPoint hitLocation =
72 [[superview superview] convertPoint:[event locationInWindow]
73 fromView:nil];
74 NSView* hitView = [superview hitTest:hitLocation];
75 if (hitView != self) {
76 [hitView mouseDown:event];
77 return;
78 }
79 }
80 [super mouseDown:event];
81 }
47 @end 82 @end
48 83
49 @interface TabStripController(Private) 84 @interface TabStripController(Private)
50 - (BOOL)useFullWidthForLayout; 85 - (void)installTrackingArea;
51 - (void)addSubviewToPermanentList:(NSView*)aView; 86 - (void)addSubviewToPermanentList:(NSView*)aView;
52 - (void)regenerateSubviewList; 87 - (void)regenerateSubviewList;
53 - (NSInteger)indexForContentsView:(NSView*)view; 88 - (NSInteger)indexForContentsView:(NSView*)view;
54 - (void)updateFavIconForContents:(TabContents*)contents 89 - (void)updateFavIconForContents:(TabContents*)contents
55 atIndex:(NSInteger)index; 90 atIndex:(NSInteger)index;
56 @end 91 @end
57 92
58 @implementation TabStripController 93 @implementation TabStripController
59 94
60 - (id)initWithView:(TabStripView*)view 95 - (id)initWithView:(TabStripView*)view
(...skipping 14 matching lines...) Expand all
75 // some reason, if the view is present in the nib apriori, it draws 110 // some reason, if the view is present in the nib apriori, it draws
76 // correctly. If we create it in code and add it to the tab view, it draws 111 // correctly. If we create it in code and add it to the tab view, it draws
77 // with all sorts of crazy artifacts. 112 // with all sorts of crazy artifacts.
78 newTabButton_ = [[tabView_ subviews] objectAtIndex:0]; 113 newTabButton_ = [[tabView_ subviews] objectAtIndex:0];
79 DCHECK([newTabButton_ isKindOfClass:[NSButton class]]); 114 DCHECK([newTabButton_ isKindOfClass:[NSButton class]]);
80 [self addSubviewToPermanentList:newTabButton_]; 115 [self addSubviewToPermanentList:newTabButton_];
81 [newTabButton_ setTarget:nil]; 116 [newTabButton_ setTarget:nil];
82 [newTabButton_ setAction:@selector(commandDispatch:)]; 117 [newTabButton_ setAction:@selector(commandDispatch:)];
83 [newTabButton_ setTag:IDC_NEW_TAB]; 118 [newTabButton_ setTag:IDC_NEW_TAB];
84 targetFrames_.reset([[NSMutableDictionary alloc] init]); 119 targetFrames_.reset([[NSMutableDictionary alloc] init]);
85 dragBlockingView_.reset([[TabStripControllerDragBlockingView alloc] 120 dragBlockingView_.reset(
86 initWithFrame:NSZeroRect]); 121 [[TabStripControllerDragBlockingView alloc] initWithFrame:NSZeroRect
122 controller:self]);
87 [self addSubviewToPermanentList:dragBlockingView_]; 123 [self addSubviewToPermanentList:dragBlockingView_];
88 newTabTargetFrame_ = NSMakeRect(0, 0, 0, 0); 124 newTabTargetFrame_ = NSMakeRect(0, 0, 0, 0);
89 availableResizeWidth_ = kUseFullAvailableWidth; 125 availableResizeWidth_ = kUseFullAvailableWidth;
90 126
91 // Install the permanent subviews. 127 // Install the permanent subviews.
92 [self regenerateSubviewList]; 128 [self regenerateSubviewList];
93 129
94 // Watch for notifications that the tab strip view has changed size so 130 // Watch for notifications that the tab strip view has changed size so
95 // we can tell it to layout for the new size. 131 // we can tell it to layout for the new size.
96 [[NSNotificationCenter defaultCenter] 132 [[NSNotificationCenter defaultCenter]
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 [[NSAnimationContext currentContext] setDuration:0.2]; 350 [[NSAnimationContext currentContext] setDuration:0.2];
315 351
316 // Update the current subviews and their z-order if requested. 352 // Update the current subviews and their z-order if requested.
317 if (doUpdate) 353 if (doUpdate)
318 [self regenerateSubviewList]; 354 [self regenerateSubviewList];
319 355
320 // Compute the base width of tabs given how much room we're allowed. We 356 // Compute the base width of tabs given how much room we're allowed. We
321 // may not be able to use the entire width if the user is quickly closing 357 // may not be able to use the entire width if the user is quickly closing
322 // tabs. 358 // tabs.
323 float availableWidth = 0; 359 float availableWidth = 0;
324 if ([self useFullWidthForLayout]) { 360 if ([self inRapidClosureMode]) {
361 availableWidth = availableResizeWidth_;
362 } else {
325 availableWidth = NSWidth([tabView_ frame]); 363 availableWidth = NSWidth([tabView_ frame]);
326 availableWidth -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset; 364 availableWidth -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset;
327 } else {
328 availableWidth = availableResizeWidth_;
329 } 365 }
330 availableWidth -= kIndentLeavingSpaceForControls; 366 availableWidth -= kIndentLeavingSpaceForControls;
331 367
332 // Add back in the amount we "get back" from the tabs overlapping. 368 // Add back in the amount we "get back" from the tabs overlapping.
333 availableWidth += ([tabContentsArray_ count] - 1) * kTabOverlap; 369 availableWidth += ([tabContentsArray_ count] - 1) * kTabOverlap;
334 const float baseTabWidth = 370 const float baseTabWidth =
335 MAX(MIN(availableWidth / [tabContentsArray_ count], 371 MAX(MIN(availableWidth / [tabContentsArray_ count],
336 kMaxTabWidth), 372 kMaxTabWidth),
337 kMinTabWidth); 373 kMinTabWidth);
338 374
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 offset -= kTabOverlap; 447 offset -= kTabOverlap;
412 i++; 448 i++;
413 } 449 }
414 450
415 // Hide the new tab button if we're explicitly told to. It may already 451 // Hide the new tab button if we're explicitly told to. It may already
416 // be hidden, doing it again doesn't hurt. 452 // be hidden, doing it again doesn't hurt.
417 if (forceNewTabButtonHidden_) { 453 if (forceNewTabButtonHidden_) {
418 [newTabButton_ setHidden:YES]; 454 [newTabButton_ setHidden:YES];
419 } else { 455 } else {
420 NSRect newTabNewFrame = [newTabButton_ frame]; 456 NSRect newTabNewFrame = [newTabButton_ frame];
421 if ([self useFullWidthForLayout]) 457 if ([self inRapidClosureMode])
458 newTabNewFrame.origin = NSMakePoint(offset + kNewTabButtonOffset, 0);
459 else
422 newTabNewFrame.origin = 460 newTabNewFrame.origin =
423 NSMakePoint(MIN(availableWidth, offset + kNewTabButtonOffset), 0); 461 NSMakePoint(MIN(availableWidth, offset + kNewTabButtonOffset), 0);
424 else
425 newTabNewFrame.origin = NSMakePoint(offset + kNewTabButtonOffset, 0);
426 newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x, 462 newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x,
427 NSMaxX(placeholderFrame_)); 463 NSMaxX(placeholderFrame_));
428 if (i > 0 && [newTabButton_ isHidden]) { 464 if (i > 0 && [newTabButton_ isHidden]) {
429 id target = animate ? [newTabButton_ animator] : newTabButton_; 465 id target = animate ? [newTabButton_ animator] : newTabButton_;
430 [target setHidden:NO]; 466 [target setHidden:NO];
431 } 467 }
432 468
433 if (!NSEqualRects(newTabTargetFrame_, newTabNewFrame)) { 469 if (!NSEqualRects(newTabTargetFrame_, newTabNewFrame)) {
434 [newTabButton_ setFrame:newTabNewFrame]; 470 [newTabButton_ setFrame:newTabNewFrame];
435 newTabTargetFrame_ = newTabNewFrame; 471 newTabTargetFrame_ = newTabNewFrame;
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 805
770 // Called when the tab strip view changes size. As we only registered for 806 // Called when the tab strip view changes size. As we only registered for
771 // changes on our view, we know it's only for our view. Layout w/out 807 // changes on our view, we know it's only for our view. Layout w/out
772 // animations since they are blocked by the resize nested runloop. We need 808 // animations since they are blocked by the resize nested runloop. We need
773 // the views to adjust immediately. Neither the tabs nor their z-order are 809 // the views to adjust immediately. Neither the tabs nor their z-order are
774 // changed, so we don't need to update the subviews. 810 // changed, so we don't need to update the subviews.
775 - (void)tabViewFrameChanged:(NSNotification*)info { 811 - (void)tabViewFrameChanged:(NSNotification*)info {
776 [self layoutTabsWithAnimation:NO regenerateSubviews:NO]; 812 [self layoutTabsWithAnimation:NO regenerateSubviews:NO];
777 } 813 }
778 814
779 - (BOOL)useFullWidthForLayout { 815 - (BOOL)inRapidClosureMode {
780 return availableResizeWidth_ == kUseFullAvailableWidth; 816 return availableResizeWidth_ != kUseFullAvailableWidth;
781 } 817 }
782 818
783 - (void)mouseMoved:(NSEvent *)event { 819 - (void)mouseMoved:(NSEvent *)event {
784 // Use hit test to figure out what view we are hovering over. 820 // Use hit test to figure out what view we are hovering over.
785 TabView* targetView = (TabView*)[tabView_ hitTest:[event locationInWindow]]; 821 TabView* targetView = (TabView*)[tabView_ hitTest:[event locationInWindow]];
786 if (![targetView isKindOfClass:[TabView class]]) { 822 if (![targetView isKindOfClass:[TabView class]]) {
787 if ([[targetView superview] isKindOfClass:[TabView class]]) { 823 if ([[targetView superview] isKindOfClass:[TabView class]]) {
788 targetView = (TabView*)[targetView superview]; 824 targetView = (TabView*)[targetView superview];
789 } else { 825 } else {
790 targetView = nil; 826 targetView = nil;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 BrowserWindowController* controller = 945 BrowserWindowController* controller =
910 (BrowserWindowController*)[[switchView_ window] windowController]; 946 (BrowserWindowController*)[[switchView_ window] windowController];
911 DCHECK(index >= 0); 947 DCHECK(index >= 0);
912 if (index >= 0) { 948 if (index >= 0) {
913 [controller setTab:[self viewAtIndex:index] isDraggable:YES]; 949 [controller setTab:[self viewAtIndex:index] isDraggable:YES];
914 } 950 }
915 } 951 }
916 952
917 953
918 @end 954 @end
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/tab_strip_controller.h ('k') | chrome/browser/cocoa/tab_view.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698