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

Side by Side Diff: chrome/browser/ui/cocoa/tabs/tab_controller.mm

Issue 688523002: [Cocoa] Tab audio mute control, behind a switch (off by default). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 1 month 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/ui/cocoa/tabs/tab_controller.h" 5 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 9
10 #include "base/i18n/rtl.h" 10 #include "base/i18n/rtl.h"
11 #include "base/mac/bundle_locations.h" 11 #include "base/mac/bundle_locations.h"
12 #include "base/mac/mac_util.h" 12 #include "base/mac/mac_util.h"
13 #import "chrome/browser/themes/theme_properties.h" 13 #import "chrome/browser/themes/theme_properties.h"
14 #import "chrome/browser/themes/theme_service.h" 14 #import "chrome/browser/themes/theme_service.h"
15 #import "chrome/browser/ui/cocoa/sprite_view.h" 15 #import "chrome/browser/ui/cocoa/sprite_view.h"
16 #import "chrome/browser/ui/cocoa/tabs/media_indicator_view.h" 16 #import "chrome/browser/ui/cocoa/tabs/media_indicator_button.h"
17 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h" 17 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
18 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" 18 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
19 #import "chrome/browser/ui/cocoa/themed_window.h" 19 #import "chrome/browser/ui/cocoa/themed_window.h"
20 #include "content/public/browser/user_metrics.h"
20 #import "extensions/common/extension.h" 21 #import "extensions/common/extension.h"
21 #import "ui/base/cocoa/menu_controller.h" 22 #import "ui/base/cocoa/menu_controller.h"
22 23
23 @implementation TabController 24 @implementation TabController
24 25
25 @synthesize action = action_; 26 @synthesize action = action_;
26 @synthesize app = app_; 27 @synthesize app = app_;
27 @synthesize loadingState = loadingState_; 28 @synthesize loadingState = loadingState_;
28 @synthesize mini = mini_; 29 @synthesize mini = mini_;
29 @synthesize pinned = pinned_; 30 @synthesize pinned = pinned_;
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 selector:@selector(themeChangedNotification:) 121 selector:@selector(themeChangedNotification:)
121 name:kBrowserThemeDidChangeNotification 122 name:kBrowserThemeDidChangeNotification
122 object:nil]; 123 object:nil];
123 124
124 [self internalSetSelected:selected_]; 125 [self internalSetSelected:selected_];
125 } 126 }
126 return self; 127 return self;
127 } 128 }
128 129
129 - (void)dealloc { 130 - (void)dealloc {
130 [mediaIndicatorView_ setAnimationDoneCallbackObject:nil withSelector:nil];
131 [[NSNotificationCenter defaultCenter] removeObserver:self]; 131 [[NSNotificationCenter defaultCenter] removeObserver:self];
132 [[self tabView] setController:nil]; 132 [[self tabView] setController:nil];
133 [super dealloc]; 133 [super dealloc];
134 } 134 }
135 135
136 // The internals of |-setSelected:| and |-setActive:| but doesn't set the 136 // The internals of |-setSelected:| and |-setActive:| but doesn't set the
137 // backing variables. This updates the drawing state and marks self as needing 137 // backing variables. This updates the drawing state and marks self as needing
138 // a re-draw. 138 // a re-draw.
139 - (void)internalSetSelected:(BOOL)selected { 139 - (void)internalSetSelected:(BOOL)selected {
140 TabView* tabView = [self tabView]; 140 TabView* tabView = [self tabView];
(...skipping 15 matching lines...) Expand all
156 new TabControllerInternal::MenuDelegate(target_, self)); 156 new TabControllerInternal::MenuDelegate(target_, self));
157 contextMenuModel_.reset( 157 contextMenuModel_.reset(
158 [target_ contextMenuModelForController:self 158 [target_ contextMenuModelForController:self
159 menuDelegate:contextMenuDelegate_.get()]); 159 menuDelegate:contextMenuDelegate_.get()]);
160 contextMenuController_.reset( 160 contextMenuController_.reset(
161 [[MenuController alloc] initWithModel:contextMenuModel_.get() 161 [[MenuController alloc] initWithModel:contextMenuModel_.get()
162 useWithPopUpButtonCell:NO]); 162 useWithPopUpButtonCell:NO]);
163 return [contextMenuController_ menu]; 163 return [contextMenuController_ menu];
164 } 164 }
165 165
166 - (void)toggleMute:(id)sender {
167 if ([[self target] respondsToSelector:@selector(toggleMute:)]) {
168 [[self target] performSelector:@selector(toggleMute:)
169 withObject:[self view]];
170 }
171 }
172
166 - (void)closeTab:(id)sender { 173 - (void)closeTab:(id)sender {
174 using base::UserMetricsAction;
175
176 if (mediaIndicatorButton_ && ![mediaIndicatorButton_ isHidden]) {
177 if ([mediaIndicatorButton_ isEnabled]) {
178 content::RecordAction(UserMetricsAction("CloseTab_MuteToggleAvailable"));
179 } else if ([mediaIndicatorButton_ showingMediaState] ==
180 TAB_MEDIA_STATE_AUDIO_PLAYING) {
181 content::RecordAction(UserMetricsAction("CloseTab_AudioIndicator"));
182 } else {
183 content::RecordAction(UserMetricsAction("CloseTab_RecordingIndicator"));
184 }
185 } else {
186 content::RecordAction(UserMetricsAction("CloseTab_NoMediaIndicator"));
187 }
188
167 if ([[self target] respondsToSelector:@selector(closeTab:)]) { 189 if ([[self target] respondsToSelector:@selector(closeTab:)]) {
168 [[self target] performSelector:@selector(closeTab:) 190 [[self target] performSelector:@selector(closeTab:)
169 withObject:[self view]]; 191 withObject:[self view]];
170 } 192 }
171 } 193 }
172 194
173 - (void)selectTab:(id)sender { 195 - (void)selectTab:(id)sender {
174 if ([[self tabView] isClosing]) 196 if ([[self tabView] isClosing])
175 return; 197 return;
176 if ([[self target] respondsToSelector:[self action]]) { 198 if ([[self target] respondsToSelector:[self action]]) {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 } 245 }
224 246
225 - (void)setIconView:(SpriteView*)iconView { 247 - (void)setIconView:(SpriteView*)iconView {
226 [iconView_ removeFromSuperview]; 248 [iconView_ removeFromSuperview];
227 iconView_.reset([iconView retain]); 249 iconView_.reset([iconView retain]);
228 250
229 if (iconView_) 251 if (iconView_)
230 [[self view] addSubview:iconView_]; 252 [[self view] addSubview:iconView_];
231 } 253 }
232 254
233 - (MediaIndicatorView*)mediaIndicatorView { 255 - (MediaIndicatorButton*)mediaIndicatorButton {
234 return mediaIndicatorView_; 256 if (!mediaIndicatorButton_) {
235 } 257 mediaIndicatorButton_.reset([[MediaIndicatorButton alloc] init]);
236 258 [self updateVisibility]; // Do layout and visibility before adding subview.
237 - (void)setMediaIndicatorView:(MediaIndicatorView*)mediaIndicatorView { 259 [[self view] addSubview:mediaIndicatorButton_];
238 [mediaIndicatorView_ removeFromSuperview]; 260 [mediaIndicatorButton_ setAnimationDoneTarget:self
239 mediaIndicatorView_.reset([mediaIndicatorView retain]); 261 withAction:@selector(updateVisibility)];
240 [self updateVisibility]; 262 [mediaIndicatorButton_ setClickTarget:self
241 if (mediaIndicatorView_) { 263 withAction:@selector(toggleMute:)];
242 [[self view] addSubview:mediaIndicatorView_];
243 [mediaIndicatorView_
244 setAnimationDoneCallbackObject:self
245 withSelector:@selector(updateVisibility)];
246
247 } 264 }
265 return mediaIndicatorButton_;
248 } 266 }
249 267
250 - (HoverCloseButton*)closeButton { 268 - (HoverCloseButton*)closeButton {
251 return closeButton_; 269 return closeButton_;
252 } 270 }
253 271
254 - (NSString*)toolTip { 272 - (NSString*)toolTip {
255 return [[self tabView] toolTipText]; 273 return [[self tabView] toolTipText];
256 } 274 }
257 275
258 // Return a rough approximation of the number of icons we could fit in the 276 // Return a rough approximation of the number of icons we could fit in the
259 // tab. We never actually do this, but it's a helpful guide for determining 277 // tab. We never actually do this, but it's a helpful guide for determining
260 // how much space we have available. 278 // how much space we have available.
261 - (int)iconCapacity { 279 - (int)iconCapacity {
262 const CGFloat availableWidth = std::max<CGFloat>( 280 const CGFloat availableWidth = std::max<CGFloat>(
263 0, NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_)); 281 0, NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_));
264 const CGFloat widthPerIcon = NSWidth(originalIconFrame_); 282 const CGFloat widthPerIcon = NSWidth(originalIconFrame_);
265 const int kPaddingBetweenIcons = 2; 283 const int kPaddingBetweenIcons = 2;
266 if (availableWidth >= widthPerIcon && 284 if (availableWidth >= widthPerIcon &&
267 availableWidth < (widthPerIcon + kPaddingBetweenIcons)) { 285 availableWidth < (widthPerIcon + kPaddingBetweenIcons)) {
268 return 1; 286 return 1;
269 } 287 }
270 return availableWidth / (widthPerIcon + kPaddingBetweenIcons); 288 return availableWidth / (widthPerIcon + kPaddingBetweenIcons);
271 } 289 }
272 290
273 - (BOOL)shouldShowIcon { 291 - (BOOL)shouldShowIcon {
274 return chrome::ShouldTabShowFavicon( 292 return chrome::ShouldTabShowFavicon(
275 [self iconCapacity], [self mini], [self active], iconView_ != nil, 293 [self iconCapacity], [self mini], [self active], iconView_ != nil,
276 !mediaIndicatorView_ ? TAB_MEDIA_STATE_NONE : 294 !mediaIndicatorButton_ ? TAB_MEDIA_STATE_NONE :
277 [mediaIndicatorView_ animatingMediaState]); 295 [mediaIndicatorButton_ showingMediaState]);
278 } 296 }
279 297
280 - (BOOL)shouldShowMediaIndicator { 298 - (BOOL)shouldShowMediaIndicator {
281 if (!mediaIndicatorView_)
282 return NO;
283 return chrome::ShouldTabShowMediaIndicator( 299 return chrome::ShouldTabShowMediaIndicator(
284 [self iconCapacity], [self mini], [self active], iconView_ != nil, 300 [self iconCapacity], [self mini], [self active], iconView_ != nil,
285 [mediaIndicatorView_ animatingMediaState]); 301 !mediaIndicatorButton_ ? TAB_MEDIA_STATE_NONE :
302 [mediaIndicatorButton_ showingMediaState]);
286 } 303 }
287 304
288 - (BOOL)shouldShowCloseButton { 305 - (BOOL)shouldShowCloseButton {
289 return chrome::ShouldTabShowCloseButton( 306 return chrome::ShouldTabShowCloseButton(
290 [self iconCapacity], [self mini], [self active]); 307 [self iconCapacity], [self mini], [self active]);
291 } 308 }
292 309
293 - (void)setIconImage:(NSImage*)image { 310 - (void)setIconImage:(NSImage*)image {
294 [self setIconImage:image withToastAnimation:NO]; 311 [self setIconImage:image withToastAnimation:NO];
295 } 312 }
(...skipping 18 matching lines...) Expand all
314 : [TabController miniTabWidth]; 331 : [TabController miniTabWidth];
315 332
316 // Center the icon. 333 // Center the icon.
317 appIconFrame.origin.x = 334 appIconFrame.origin.x =
318 std::floor((tabWidth - NSWidth(appIconFrame)) / 2.0); 335 std::floor((tabWidth - NSWidth(appIconFrame)) / 2.0);
319 [iconView_ setFrame:appIconFrame]; 336 [iconView_ setFrame:appIconFrame];
320 } else { 337 } else {
321 [iconView_ setFrame:originalIconFrame_]; 338 [iconView_ setFrame:originalIconFrame_];
322 } 339 }
323 } 340 }
324 // Ensure that the icon is suppressed if no icon is set or if the tab is too
325 // narrow to display one.
326 [self updateVisibility];
327 } 341 }
328 342
329 - (void)updateVisibility { 343 - (void)updateVisibility {
330 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden] 344 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden]
331 // won't work. Instead, the state of the icon is tracked separately in 345 // won't work. Instead, the state of the icon is tracked separately in
332 // isIconShowing_. 346 // isIconShowing_.
333 BOOL newShowIcon = [self shouldShowIcon]; 347 BOOL newShowIcon = [self shouldShowIcon];
334 348
335 [iconView_ setHidden:!newShowIcon]; 349 [iconView_ setHidden:!newShowIcon];
336 isIconShowing_ = newShowIcon; 350 isIconShowing_ = newShowIcon;
337 351
338 // If the tab is a mini-tab, hide the title. 352 // If the tab is a mini-tab, hide the title.
339 TabView* tabView = [self tabView]; 353 TabView* tabView = [self tabView];
340 [tabView setTitleHidden:[self mini]]; 354 [tabView setTitleHidden:[self mini]];
341 355
342 BOOL newShowCloseButton = [self shouldShowCloseButton]; 356 BOOL newShowCloseButton = [self shouldShowCloseButton];
343 357
344 [closeButton_ setHidden:!newShowCloseButton]; 358 [closeButton_ setHidden:!newShowCloseButton];
345 359
346 BOOL newShowMediaIndicator = [self shouldShowMediaIndicator]; 360 BOOL newShowMediaIndicator = [self shouldShowMediaIndicator];
347 361
348 [mediaIndicatorView_ setHidden:!newShowMediaIndicator]; 362 [mediaIndicatorButton_ setHidden:!newShowMediaIndicator];
349 363
350 if (newShowMediaIndicator) { 364 if (newShowMediaIndicator) {
351 NSRect newFrame = [mediaIndicatorView_ frame]; 365 NSRect newFrame = [mediaIndicatorButton_ frame];
366 newFrame.size = [[mediaIndicatorButton_ image] size];
352 if ([self app] || [self mini]) { 367 if ([self app] || [self mini]) {
353 // Tab is pinned: Position the media indicator in the center. 368 // Tab is pinned: Position the media indicator in the center.
354 const CGFloat tabWidth = [self app] ? 369 const CGFloat tabWidth = [self app] ?
355 [TabController appTabWidth] : [TabController miniTabWidth]; 370 [TabController appTabWidth] : [TabController miniTabWidth];
356 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2); 371 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2);
357 newFrame.origin.y = NSMinY(originalIconFrame_) - 372 newFrame.origin.y = NSMinY(originalIconFrame_) -
358 std::floor((NSHeight(newFrame) - NSHeight(originalIconFrame_)) / 2); 373 std::floor((NSHeight(newFrame) - NSHeight(originalIconFrame_)) / 2);
359 } else { 374 } else {
360 // The Frame for the mediaIndicatorView_ depends on whether iconView_ 375 // The Frame for the mediaIndicatorButton_ depends on whether iconView_
361 // and/or closeButton_ are visible, and where they have been positioned. 376 // and/or closeButton_ are visible, and where they have been positioned.
362 const NSRect closeButtonFrame = [closeButton_ frame]; 377 const NSRect closeButtonFrame = [closeButton_ frame];
363 newFrame.origin.x = NSMinX(closeButtonFrame); 378 newFrame.origin.x = NSMinX(closeButtonFrame);
364 // Position to the left of the close button when it is showing. 379 // Position to the left of the close button when it is showing.
365 if (newShowCloseButton) 380 if (newShowCloseButton)
366 newFrame.origin.x -= NSWidth(newFrame); 381 newFrame.origin.x -= NSWidth(newFrame);
367 // Media indicator is centered vertically, with respect to closeButton_. 382 // Media indicator is centered vertically, with respect to closeButton_.
368 newFrame.origin.y = NSMinY(closeButtonFrame) - 383 newFrame.origin.y = NSMinY(closeButtonFrame) -
369 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2); 384 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2);
370 } 385 }
371 [mediaIndicatorView_ setFrame:newFrame]; 386 [mediaIndicatorButton_ setFrame:newFrame];
372 } 387 }
373 388
374 // Adjust the title view based on changes to the icon's and close button's 389 // Adjust the title view based on changes to the icon's and close button's
375 // visibility. 390 // visibility.
376 NSRect oldTitleFrame = [tabView titleFrame]; 391 NSRect oldTitleFrame = [tabView titleFrame];
377 NSRect newTitleFrame; 392 NSRect newTitleFrame;
378 newTitleFrame.size.height = oldTitleFrame.size.height; 393 newTitleFrame.size.height = oldTitleFrame.size.height;
379 newTitleFrame.origin.y = oldTitleFrame.origin.y; 394 newTitleFrame.origin.y = oldTitleFrame.origin.y;
380 395
381 if (newShowIcon) { 396 if (newShowIcon) {
382 newTitleFrame.origin.x = NSMaxX([iconView_ frame]); 397 newTitleFrame.origin.x = NSMaxX([iconView_ frame]);
383 } else { 398 } else {
384 newTitleFrame.origin.x = originalIconFrame_.origin.x; 399 newTitleFrame.origin.x = originalIconFrame_.origin.x;
385 } 400 }
386 401
387 if (newShowMediaIndicator) { 402 if (newShowMediaIndicator) {
388 newTitleFrame.size.width = NSMinX([mediaIndicatorView_ frame]) - 403 newTitleFrame.size.width = NSMinX([mediaIndicatorButton_ frame]) -
389 newTitleFrame.origin.x; 404 newTitleFrame.origin.x;
390 } else if (newShowCloseButton) { 405 } else if (newShowCloseButton) {
391 newTitleFrame.size.width = NSMinX([closeButton_ frame]) - 406 newTitleFrame.size.width = NSMinX([closeButton_ frame]) -
392 newTitleFrame.origin.x; 407 newTitleFrame.origin.x;
393 } else { 408 } else {
394 newTitleFrame.size.width = NSMaxX([closeButton_ frame]) - 409 newTitleFrame.size.width = NSMaxX([closeButton_ frame]) -
395 newTitleFrame.origin.x; 410 newTitleFrame.origin.x;
396 } 411 }
397 412
398 [tabView setTitleFrame:newTitleFrame]; 413 [tabView setTitleFrame:newTitleFrame];
(...skipping 27 matching lines...) Expand all
426 // TabStripDragController. 441 // TabStripDragController.
427 - (BOOL)tabCanBeDragged:(TabController*)controller { 442 - (BOOL)tabCanBeDragged:(TabController*)controller {
428 return [[target_ dragController] tabCanBeDragged:controller]; 443 return [[target_ dragController] tabCanBeDragged:controller];
429 } 444 }
430 445
431 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab { 446 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab {
432 [[target_ dragController] maybeStartDrag:event forTab:tab]; 447 [[target_ dragController] maybeStartDrag:event forTab:tab];
433 } 448 }
434 449
435 @end 450 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698