Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 #include "chrome/browser/ui/views/toolbar/browser_action_view.h" | 5 #include "chrome/browser/ui/views/toolbar/browser_action_view.h" |
| 6 | 6 |
| 7 #include <string> | |
| 8 | |
| 7 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
| 8 #include "chrome/browser/chrome_notification_types.h" | 10 #include "chrome/browser/chrome_notification_types.h" |
| 9 #include "chrome/browser/extensions/api/commands/command_service.h" | 11 #include "chrome/browser/extensions/api/commands/command_service.h" |
| 10 #include "chrome/browser/extensions/extension_action.h" | 12 #include "chrome/browser/extensions/extension_action.h" |
| 11 #include "chrome/browser/extensions/extension_action_manager.h" | 13 #include "chrome/browser/extensions/extension_action_manager.h" |
| 12 #include "chrome/browser/extensions/extension_context_menu_model.h" | 14 #include "chrome/browser/extensions/extension_context_menu_model.h" |
| 13 #include "chrome/browser/extensions/extension_service.h" | |
| 14 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/themes/theme_service.h" | 16 #include "chrome/browser/themes/theme_service.h" |
| 16 #include "chrome/browser/themes/theme_service_factory.h" | 17 #include "chrome/browser/themes/theme_service_factory.h" |
| 17 #include "chrome/browser/ui/browser.h" | 18 #include "chrome/browser/ui/browser.h" |
| 18 #include "chrome/browser/ui/extensions/accelerator_priority.h" | 19 #include "chrome/browser/ui/extensions/accelerator_priority.h" |
| 19 #include "chrome/browser/ui/view_ids.h" | 20 #include "chrome/browser/ui/view_ids.h" |
| 20 #include "chrome/browser/ui/views/frame/browser_view.h" | 21 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 21 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" | 22 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" |
| 22 #include "chrome/browser/ui/views/toolbar/toolbar_view.h" | 23 #include "chrome/browser/ui/views/toolbar/toolbar_view.h" |
| 23 #include "extensions/common/extension.h" | 24 #include "extensions/common/extension.h" |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 // to GTK requires that we regrab our browser action images. | 132 // to GTK requires that we regrab our browser action images. |
| 132 registrar_.Add( | 133 registrar_.Add( |
| 133 this, | 134 this, |
| 134 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, | 135 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, |
| 135 content::Source<ThemeService>( | 136 content::Source<ThemeService>( |
| 136 ThemeServiceFactory::GetForProfile(browser->profile()))); | 137 ThemeServiceFactory::GetForProfile(browser->profile()))); |
| 137 } | 138 } |
| 138 | 139 |
| 139 void BrowserActionButton::Destroy() { | 140 void BrowserActionButton::Destroy() { |
| 140 MaybeUnregisterExtensionCommand(false); | 141 MaybeUnregisterExtensionCommand(false); |
| 141 | 142 HidePopup(); |
| 142 if (menu_runner_) { | 143 if (menu_runner_) { |
| 143 menu_runner_->Cancel(); | 144 menu_runner_->Cancel(); |
| 144 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 145 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 145 } else { | 146 } else { |
| 146 delete this; | 147 delete this; |
| 147 } | 148 } |
| 148 } | 149 } |
| 149 | 150 |
| 150 void BrowserActionButton::ViewHierarchyChanged( | 151 void BrowserActionButton::ViewHierarchyChanged( |
| 151 const ViewHierarchyChangedDetails& details) { | 152 const ViewHierarchyChangedDetails& details) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 169 return true; | 170 return true; |
| 170 } | 171 } |
| 171 | 172 |
| 172 void BrowserActionButton::GetAccessibleState(ui::AXViewState* state) { | 173 void BrowserActionButton::GetAccessibleState(ui::AXViewState* state) { |
| 173 views::MenuButton::GetAccessibleState(state); | 174 views::MenuButton::GetAccessibleState(state); |
| 174 state->role = ui::AX_ROLE_BUTTON; | 175 state->role = ui::AX_ROLE_BUTTON; |
| 175 } | 176 } |
| 176 | 177 |
| 177 void BrowserActionButton::ButtonPressed(views::Button* sender, | 178 void BrowserActionButton::ButtonPressed(views::Button* sender, |
| 178 const ui::Event& event) { | 179 const ui::Event& event) { |
| 179 delegate_->OnBrowserActionExecuted(this); | 180 ExecuteBrowserAction(); |
| 180 } | 181 } |
| 181 | 182 |
| 182 void BrowserActionButton::ShowContextMenuForView( | 183 void BrowserActionButton::ShowContextMenuForView( |
| 183 View* source, | 184 View* source, |
| 184 const gfx::Point& point, | 185 const gfx::Point& point, |
| 185 ui::MenuSourceType source_type) { | 186 ui::MenuSourceType source_type) { |
| 186 if (!extension()->ShowConfigureContextMenus()) | 187 if (!extension()->ShowConfigureContextMenus()) |
| 187 return; | 188 return; |
| 188 | 189 |
| 189 SetButtonPushed(); | 190 SetButtonPushed(); |
| 190 | 191 |
| 191 // Reconstructs the menu every time because the menu's contents are dynamic. | 192 // Reconstructs the menu every time because the menu's contents are dynamic. |
| 192 scoped_refptr<ExtensionContextMenuModel> context_menu_contents( | 193 scoped_refptr<ExtensionContextMenuModel> context_menu_contents( |
| 193 new ExtensionContextMenuModel(extension(), browser_, delegate_)); | 194 new ExtensionContextMenuModel(extension(), browser_, this)); |
| 194 gfx::Point screen_loc; | 195 gfx::Point screen_loc; |
| 195 views::View::ConvertPointToScreen(this, &screen_loc); | 196 views::View::ConvertPointToScreen(this, &screen_loc); |
| 196 | 197 |
| 197 views::Widget* parent = NULL; | 198 views::Widget* parent = NULL; |
| 198 int run_types = views::MenuRunner::HAS_MNEMONICS | | 199 int run_types = views::MenuRunner::HAS_MNEMONICS | |
| 199 views::MenuRunner::CONTEXT_MENU; | 200 views::MenuRunner::CONTEXT_MENU; |
| 200 if (delegate_->ShownInsideMenu()) { | 201 if (delegate_->ShownInsideMenu()) { |
| 201 run_types |= views::MenuRunner::IS_NESTED; | 202 run_types |= views::MenuRunner::IS_NESTED; |
| 202 // RunMenuAt expects a nested menu to be parented by the same widget as the | 203 // RunMenuAt expects a nested menu to be parented by the same widget as the |
| 203 // already visible menu, in this case the Chrome menu. | 204 // already visible menu, in this case the Chrome menu. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 264 bool BrowserActionButton::IsPopup() { | 265 bool BrowserActionButton::IsPopup() { |
| 265 int tab_id = delegate_->GetCurrentTabId(); | 266 int tab_id = delegate_->GetCurrentTabId(); |
| 266 return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id); | 267 return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id); |
| 267 } | 268 } |
| 268 | 269 |
| 269 GURL BrowserActionButton::GetPopupUrl() { | 270 GURL BrowserActionButton::GetPopupUrl() { |
| 270 int tab_id = delegate_->GetCurrentTabId(); | 271 int tab_id = delegate_->GetCurrentTabId(); |
| 271 return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id); | 272 return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id); |
| 272 } | 273 } |
| 273 | 274 |
| 275 bool BrowserActionButton::ShowPopup( | |
| 276 ExtensionPopup::ShowAction show_action, | |
| 277 bool grant_tab_permissions) { | |
| 278 GURL popup_url; | |
| 279 if (delegate_->GetModel()->ExecuteBrowserAction( | |
| 280 extension_, browser_, &popup_url, grant_tab_permissions) == | |
| 281 extensions::ExtensionToolbarModel::ACTION_NONE) { | |
| 282 return false; | |
| 283 } | |
| 284 | |
| 285 // If we're showing the same popup, just hide it and return. | |
|
Peter Kasting
2014/07/26 02:33:20
Nit: The word "same" in this sentence is slightly
Devlin
2014/07/29 19:07:14
Yeah - same means "the popup for this browser acti
| |
| 286 bool already_showing = popup_ != NULL; | |
| 287 | |
| 288 // Always hide the current popup, even if it's not the same. | |
| 289 // Only one popup should be visible at a time. | |
| 290 delegate_->HideActivePopup(); | |
| 291 if (already_showing) | |
| 292 return false; | |
| 293 | |
| 294 // Browser actions in the overflow menu can still show popups, so we may need | |
| 295 // a reference view other than this view. If so, use the overflow view. | |
| 296 views::View* reference_view = | |
| 297 parent()->visible() ? this : delegate_->GetOverflowReferenceView(); | |
| 298 | |
| 299 popup_ = ExtensionPopup::ShowPopup(popup_url, | |
| 300 browser_, | |
| 301 reference_view, | |
| 302 views::BubbleBorder::TOP_RIGHT, | |
| 303 show_action); | |
| 304 popup_->GetWidget()->AddObserver(this); | |
| 305 delegate_->SetPopupOwner(this); | |
| 306 | |
| 307 // Only set button as pushed if it was triggered by a user click. | |
| 308 if (grant_tab_permissions) | |
| 309 SetButtonPushed(); | |
| 310 return true; | |
| 311 } | |
| 312 | |
| 313 void BrowserActionButton::HidePopup() { | |
| 314 if (popup_) { | |
| 315 popup_->GetWidget()->RemoveObserver(this); | |
| 316 popup_->GetWidget()->Close(); | |
| 317 popup_ = NULL; | |
| 318 SetButtonNotPushed(); | |
| 319 delegate_->SetPopupOwner(NULL); | |
| 320 } | |
| 321 } | |
| 322 | |
| 323 void BrowserActionButton::ExecuteBrowserAction() { | |
| 324 ShowPopup(ExtensionPopup::SHOW, true); | |
| 325 } | |
| 326 | |
| 274 void BrowserActionButton::Observe(int type, | 327 void BrowserActionButton::Observe(int type, |
| 275 const content::NotificationSource& source, | 328 const content::NotificationSource& source, |
| 276 const content::NotificationDetails& details) { | 329 const content::NotificationDetails& details) { |
| 277 switch (type) { | 330 switch (type) { |
| 278 case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED: | 331 case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED: |
| 279 UpdateState(); | 332 UpdateState(); |
| 280 // The browser action may have become visible/hidden so we need to make | 333 // The browser action may have become visible/hidden so we need to make |
| 281 // sure the state gets updated. | 334 // sure the state gets updated. |
| 282 delegate_->OnBrowserActionVisibilityChanged(); | 335 delegate_->OnBrowserActionVisibilityChanged(); |
| 283 break; | 336 break; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 308 void BrowserActionButton::OnIconUpdated() { | 361 void BrowserActionButton::OnIconUpdated() { |
| 309 UpdateState(); | 362 UpdateState(); |
| 310 if (icon_observer_) | 363 if (icon_observer_) |
| 311 icon_observer_->OnIconUpdated(GetIconWithBadge()); | 364 icon_observer_->OnIconUpdated(GetIconWithBadge()); |
| 312 } | 365 } |
| 313 | 366 |
| 314 bool BrowserActionButton::Activate() { | 367 bool BrowserActionButton::Activate() { |
| 315 if (!IsPopup()) | 368 if (!IsPopup()) |
| 316 return true; | 369 return true; |
| 317 | 370 |
| 318 delegate_->OnBrowserActionExecuted(this); | 371 ExecuteBrowserAction(); |
| 319 | 372 |
| 320 // TODO(erikkay): Run a nested modal loop while the mouse is down to | 373 // TODO(erikkay): Run a nested modal loop while the mouse is down to |
| 321 // enable menu-like drag-select behavior. | 374 // enable menu-like drag-select behavior. |
| 322 | 375 |
| 323 // The return value of this method is returned via OnMousePressed. | 376 // The return value of this method is returned via OnMousePressed. |
| 324 // We need to return false here since we're handing off focus to another | 377 // We need to return false here since we're handing off focus to another |
| 325 // widget/view, and true will grab it right back and try to send events | 378 // widget/view, and true will grab it right back and try to send events |
| 326 // to us. | 379 // to us. |
| 327 return false; | 380 return false; |
| 328 } | 381 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 379 } | 432 } |
| 380 | 433 |
| 381 bool BrowserActionButton::AcceleratorPressed( | 434 bool BrowserActionButton::AcceleratorPressed( |
| 382 const ui::Accelerator& accelerator) { | 435 const ui::Accelerator& accelerator) { |
| 383 // Normal priority shortcuts must be handled via standard browser commands to | 436 // Normal priority shortcuts must be handled via standard browser commands to |
| 384 // be processed at the proper time. | 437 // be processed at the proper time. |
| 385 if (GetAcceleratorPriority(accelerator, extension_) == | 438 if (GetAcceleratorPriority(accelerator, extension_) == |
| 386 ui::AcceleratorManager::kNormalPriority) | 439 ui::AcceleratorManager::kNormalPriority) |
| 387 return false; | 440 return false; |
| 388 | 441 |
| 389 delegate_->OnBrowserActionExecuted(this); | 442 ExecuteBrowserAction(); |
| 390 return true; | 443 return true; |
| 391 } | 444 } |
| 392 | 445 |
| 393 void BrowserActionButton::SetButtonPushed() { | 446 void BrowserActionButton::SetButtonPushed() { |
| 394 SetState(views::CustomButton::STATE_PRESSED); | 447 SetState(views::CustomButton::STATE_PRESSED); |
| 395 menu_visible_ = true; | 448 menu_visible_ = true; |
| 396 } | 449 } |
| 397 | 450 |
| 398 void BrowserActionButton::SetButtonNotPushed() { | 451 void BrowserActionButton::SetButtonNotPushed() { |
| 399 SetState(views::CustomButton::STATE_NORMAL); | 452 SetState(views::CustomButton::STATE_NORMAL); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 413 return browser_action_->GetIconWithBadge(icon, tab_id, spacing); | 466 return browser_action_->GetIconWithBadge(icon, tab_id, spacing); |
| 414 } | 467 } |
| 415 | 468 |
| 416 gfx::ImageSkia BrowserActionButton::GetIconForTest() { | 469 gfx::ImageSkia BrowserActionButton::GetIconForTest() { |
| 417 return GetImage(views::Button::STATE_NORMAL); | 470 return GetImage(views::Button::STATE_NORMAL); |
| 418 } | 471 } |
| 419 | 472 |
| 420 BrowserActionButton::~BrowserActionButton() { | 473 BrowserActionButton::~BrowserActionButton() { |
| 421 } | 474 } |
| 422 | 475 |
| 476 void BrowserActionButton::InspectPopup(ExtensionAction* action) { | |
| 477 DCHECK_EQ(browser_action_, action); | |
| 478 ShowPopup(ExtensionPopup::SHOW_AND_INSPECT, true); // grant active tab | |
| 479 } | |
| 480 | |
| 481 void BrowserActionButton::OnWidgetDestroying(views::Widget* widget) { | |
|
Peter Kasting
2014/07/26 02:33:20
This code sure looks a lot like HidePopup(). Can
Devlin
2014/07/29 19:07:14
I'm not 100% sure. The problem being the call to
Peter Kasting
2014/07/29 19:18:01
Widget::Close()'s definition checks whether the wi
Devlin
2014/07/29 19:51:46
That may still be problematic. In particular, wid
Peter Kasting
2014/07/29 19:56:05
There isn't from the user's perspective, but there
Devlin
2014/07/29 19:59:48
In theory, if we have a popup showing, and then we
Peter Kasting
2014/07/29 20:03:02
The async close should happen with the next messag
Devlin
2014/07/29 21:25:43
- PatchSet 2 (just calling HidePopup() from OnWidg
Devlin
2014/07/29 21:45:04
Done!
| |
| 482 DCHECK(popup_); | |
| 483 DCHECK_EQ(popup_->GetWidget(), widget); | |
| 484 popup_->GetWidget()->RemoveObserver(this); | |
| 485 popup_ = NULL; | |
| 486 SetButtonNotPushed(); | |
| 487 delegate_->SetPopupOwner(NULL); | |
| 488 } | |
| 489 | |
| 423 void BrowserActionButton::MaybeRegisterExtensionCommand() { | 490 void BrowserActionButton::MaybeRegisterExtensionCommand() { |
| 424 extensions::CommandService* command_service = | 491 extensions::CommandService* command_service = |
| 425 extensions::CommandService::Get(browser_->profile()); | 492 extensions::CommandService::Get(browser_->profile()); |
| 426 extensions::Command browser_action_command; | 493 extensions::Command browser_action_command; |
| 427 if (command_service->GetBrowserActionCommand( | 494 if (command_service->GetBrowserActionCommand( |
| 428 extension_->id(), | 495 extension_->id(), |
| 429 extensions::CommandService::ACTIVE_ONLY, | 496 extensions::CommandService::ACTIVE_ONLY, |
| 430 &browser_action_command, | 497 &browser_action_command, |
| 431 NULL)) { | 498 NULL)) { |
| 432 keybinding_.reset(new ui::Accelerator( | 499 keybinding_.reset(new ui::Accelerator( |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 449 extensions::Command browser_action_command; | 516 extensions::Command browser_action_command; |
| 450 if (!only_if_active || !command_service->GetBrowserActionCommand( | 517 if (!only_if_active || !command_service->GetBrowserActionCommand( |
| 451 extension_->id(), | 518 extension_->id(), |
| 452 extensions::CommandService::ACTIVE_ONLY, | 519 extensions::CommandService::ACTIVE_ONLY, |
| 453 &browser_action_command, | 520 &browser_action_command, |
| 454 NULL)) { | 521 NULL)) { |
| 455 GetFocusManager()->UnregisterAccelerator(*keybinding_.get(), this); | 522 GetFocusManager()->UnregisterAccelerator(*keybinding_.get(), this); |
| 456 keybinding_.reset(NULL); | 523 keybinding_.reset(NULL); |
| 457 } | 524 } |
| 458 } | 525 } |
| OLD | NEW |