| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/views/browser_actions_container.h" | 5 #include "chrome/browser/views/browser_actions_container.h" |
| 6 | 6 |
| 7 #include "app/gfx/canvas.h" | 7 #include "app/gfx/canvas.h" |
| 8 #include "app/resource_bundle.h" | 8 #include "app/resource_bundle.h" |
| 9 #include "app/slide_animation.h" | 9 #include "app/slide_animation.h" |
| 10 #include "base/stl_util-inl.h" | 10 #include "base/stl_util-inl.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "chrome/browser/browser.h" | 12 #include "chrome/browser/browser.h" |
| 13 #include "chrome/browser/browser_theme_provider.h" | 13 #include "chrome/browser/browser_theme_provider.h" |
| 14 #include "chrome/browser/browser_window.h" | 14 #include "chrome/browser/browser_window.h" |
| 15 #include "chrome/browser/extensions/extension_browser_event_router.h" | 15 #include "chrome/browser/extensions/extension_browser_event_router.h" |
| 16 #include "chrome/browser/extensions/extension_host.h" |
| 16 #include "chrome/browser/extensions/extensions_service.h" | 17 #include "chrome/browser/extensions/extensions_service.h" |
| 17 #include "chrome/browser/extensions/extension_tabs_module.h" | 18 #include "chrome/browser/extensions/extension_tabs_module.h" |
| 18 #include "chrome/browser/renderer_host/render_widget_host_view.h" | 19 #include "chrome/browser/renderer_host/render_widget_host_view.h" |
| 19 #include "chrome/browser/renderer_host/render_view_host.h" | 20 #include "chrome/browser/renderer_host/render_view_host.h" |
| 20 #include "chrome/browser/profile.h" | 21 #include "chrome/browser/profile.h" |
| 21 #include "chrome/browser/tab_contents/tab_contents.h" | 22 #include "chrome/browser/tab_contents/tab_contents.h" |
| 22 #include "chrome/browser/view_ids.h" | 23 #include "chrome/browser/view_ids.h" |
| 23 #include "chrome/browser/views/detachable_toolbar_view.h" | 24 #include "chrome/browser/views/detachable_toolbar_view.h" |
| 24 #include "chrome/browser/views/extensions/browser_action_drag_data.h" | 25 #include "chrome/browser/views/extensions/browser_action_drag_data.h" |
| 25 #include "chrome/browser/views/extensions/extension_popup.h" | 26 #include "chrome/browser/views/extensions/extension_popup.h" |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 BrowserActionButton::~BrowserActionButton() { | 127 BrowserActionButton::~BrowserActionButton() { |
| 127 if (tracker_) | 128 if (tracker_) |
| 128 tracker_->StopTrackingImageLoad(); | 129 tracker_->StopTrackingImageLoad(); |
| 129 } | 130 } |
| 130 | 131 |
| 131 gfx::Insets BrowserActionButton::GetInsets() const { | 132 gfx::Insets BrowserActionButton::GetInsets() const { |
| 132 static gfx::Insets zero_inset; | 133 static gfx::Insets zero_inset; |
| 133 return zero_inset; | 134 return zero_inset; |
| 134 } | 135 } |
| 135 | 136 |
| 136 void BrowserActionButton::ButtonPressed( | 137 void BrowserActionButton::ButtonPressed(views::Button* sender, |
| 137 views::Button* sender, const views::Event& event) { | 138 const views::Event& event) { |
| 138 panel_->OnBrowserActionExecuted(this); | 139 panel_->OnBrowserActionExecuted(this, false); // inspect_with_devtools |
| 139 } | 140 } |
| 140 | 141 |
| 141 void BrowserActionButton::OnImageLoaded(SkBitmap* image, size_t index) { | 142 void BrowserActionButton::OnImageLoaded(SkBitmap* image, size_t index) { |
| 142 if (image) | 143 if (image) |
| 143 default_icon_ = *image; | 144 default_icon_ = *image; |
| 144 | 145 |
| 145 tracker_ = NULL; // The tracker object will delete itself when we return. | 146 tracker_ = NULL; // The tracker object will delete itself when we return. |
| 146 | 147 |
| 147 // Call back to UpdateState() because a more specific icon might have been set | 148 // Call back to UpdateState() because a more specific icon might have been set |
| 148 // while the load was outstanding. | 149 // while the load was outstanding. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 if (tab_id < 0) { | 192 if (tab_id < 0) { |
| 192 NOTREACHED() << "Button is not on a specific tab."; | 193 NOTREACHED() << "Button is not on a specific tab."; |
| 193 GURL empty_url; | 194 GURL empty_url; |
| 194 return empty_url; | 195 return empty_url; |
| 195 } | 196 } |
| 196 return browser_action_->GetPopupUrl(tab_id); | 197 return browser_action_->GetPopupUrl(tab_id); |
| 197 } | 198 } |
| 198 | 199 |
| 199 bool BrowserActionButton::Activate() { | 200 bool BrowserActionButton::Activate() { |
| 200 if (IsPopup()) { | 201 if (IsPopup()) { |
| 201 panel_->OnBrowserActionExecuted(this); | 202 panel_->OnBrowserActionExecuted(this, false); // inspect_with_devtools |
| 202 | 203 |
| 203 // TODO(erikkay): Run a nested modal loop while the mouse is down to | 204 // TODO(erikkay): Run a nested modal loop while the mouse is down to |
| 204 // enable menu-like drag-select behavior. | 205 // enable menu-like drag-select behavior. |
| 205 | 206 |
| 206 // The return value of this method is returned via OnMousePressed. | 207 // The return value of this method is returned via OnMousePressed. |
| 207 // We need to return false here since we're handing off focus to another | 208 // We need to return false here since we're handing off focus to another |
| 208 // widget/view, and true will grab it right back and try to send events | 209 // widget/view, and true will grab it right back and try to send events |
| 209 // to us. | 210 // to us. |
| 210 return false; | 211 return false; |
| 211 } | 212 } |
| 212 return true; | 213 return true; |
| 213 } | 214 } |
| 214 | 215 |
| 215 bool BrowserActionButton::OnMousePressed(const views::MouseEvent& e) { | 216 bool BrowserActionButton::OnMousePressed(const views::MouseEvent& e) { |
| 216 showing_context_menu_ = e.IsRightMouseButton(); | 217 showing_context_menu_ = e.IsRightMouseButton(); |
| 217 if (showing_context_menu_) { | 218 if (showing_context_menu_) { |
| 218 SetButtonPushed(); | 219 SetButtonPushed(); |
| 219 | 220 |
| 220 // Get the top left point of this button in screen coordinates. | 221 // Get the top left point of this button in screen coordinates. |
| 221 gfx::Point point = gfx::Point(0, 0); | 222 gfx::Point point = gfx::Point(0, 0); |
| 222 ConvertPointToScreen(this, &point); | 223 ConvertPointToScreen(this, &point); |
| 223 | 224 |
| 224 // Make the menu appear below the button. | 225 // Make the menu appear below the button. |
| 225 point.Offset(0, height()); | 226 point.Offset(0, height()); |
| 226 | 227 |
| 227 panel_->GetContextMenu()->Run(extension(), point); | 228 panel_->GetContextMenu()->Run(extension(), extension()->browser_action(), |
| 229 panel_, panel_->profile()->GetPrefs(), point); |
| 228 | 230 |
| 229 SetButtonNotPushed(); | 231 SetButtonNotPushed(); |
| 230 return false; | 232 return false; |
| 231 } else if (IsPopup()) { | 233 } else if (IsPopup()) { |
| 232 return MenuButton::OnMousePressed(e); | 234 return MenuButton::OnMousePressed(e); |
| 233 } | 235 } |
| 234 return TextButton::OnMousePressed(e); | 236 return TextButton::OnMousePressed(e); |
| 235 } | 237 } |
| 236 | 238 |
| 237 void BrowserActionButton::OnMouseReleased(const views::MouseEvent& e, | 239 void BrowserActionButton::OnMouseReleased(const views::MouseEvent& e, |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 animation_target_size_(0), | 335 animation_target_size_(0), |
| 334 drop_indicator_position_(-1), | 336 drop_indicator_position_(-1), |
| 335 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), | 337 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), |
| 336 ALLOW_THIS_IN_INITIALIZER_LIST(show_menu_task_factory_(this)) { | 338 ALLOW_THIS_IN_INITIALIZER_LIST(show_menu_task_factory_(this)) { |
| 337 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); | 339 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); |
| 338 | 340 |
| 339 ExtensionsService* extension_service = profile_->GetExtensionsService(); | 341 ExtensionsService* extension_service = profile_->GetExtensionsService(); |
| 340 if (!extension_service) // The |extension_service| can be NULL in Incognito. | 342 if (!extension_service) // The |extension_service| can be NULL in Incognito. |
| 341 return; | 343 return; |
| 342 | 344 |
| 343 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, | |
| 344 Source<Profile>(profile_)); | |
| 345 | |
| 346 model_ = extension_service->toolbar_model(); | 345 model_ = extension_service->toolbar_model(); |
| 347 model_->AddObserver(this); | 346 model_->AddObserver(this); |
| 348 | 347 |
| 349 resize_animation_.reset(new SlideAnimation(this)); | 348 resize_animation_.reset(new SlideAnimation(this)); |
| 350 resize_gripper_ = new views::ResizeGripper(this); | 349 resize_gripper_ = new views::ResizeGripper(this); |
| 351 resize_gripper_->SetVisible(false); | 350 resize_gripper_->SetVisible(false); |
| 352 AddChildView(resize_gripper_); | 351 AddChildView(resize_gripper_); |
| 353 | 352 |
| 354 // TODO(glen): Come up with a new bitmap for the chevron. | 353 // TODO(glen): Come up with a new bitmap for the chevron. |
| 355 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 354 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 } | 476 } |
| 478 | 477 |
| 479 void BrowserActionsContainer::OnBrowserActionVisibilityChanged() { | 478 void BrowserActionsContainer::OnBrowserActionVisibilityChanged() { |
| 480 resize_gripper_->SetVisible(browser_action_views_.size() > 0); | 479 resize_gripper_->SetVisible(browser_action_views_.size() > 0); |
| 481 | 480 |
| 482 owner_view_->Layout(); | 481 owner_view_->Layout(); |
| 483 owner_view_->SchedulePaint(); | 482 owner_view_->SchedulePaint(); |
| 484 } | 483 } |
| 485 | 484 |
| 486 void BrowserActionsContainer::HidePopup() { | 485 void BrowserActionsContainer::HidePopup() { |
| 487 if (popup_) { | 486 if (popup_) |
| 488 // This sometimes gets called via a timer (See BubbleLostFocus), so clear | 487 popup_->Close(); |
| 489 // the task factory in case one is pending. | |
| 490 task_factory_.RevokeAll(); | |
| 491 | |
| 492 // Save these variables in local temporaries since destroying the popup | |
| 493 // calls BubbleLostFocus to be called, which will try to call HidePopup() | |
| 494 // again if popup_ is non-null. | |
| 495 ExtensionPopup* closing_popup = popup_; | |
| 496 BrowserActionButton* closing_button = popup_button_; | |
| 497 popup_ = NULL; | |
| 498 popup_button_ = NULL; | |
| 499 | |
| 500 closing_popup->DetachFromBrowser(); | |
| 501 delete closing_popup; | |
| 502 closing_button->SetButtonNotPushed(); | |
| 503 return; | |
| 504 } | |
| 505 } | 488 } |
| 506 | 489 |
| 507 void BrowserActionsContainer::TestExecuteBrowserAction(int index) { | 490 void BrowserActionsContainer::TestExecuteBrowserAction(int index) { |
| 508 BrowserActionButton* button = browser_action_views_[index]->button(); | 491 BrowserActionButton* button = browser_action_views_[index]->button(); |
| 509 OnBrowserActionExecuted(button); | 492 OnBrowserActionExecuted(button, false); // inspect_with_devtools |
| 510 } | 493 } |
| 511 | 494 |
| 512 void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { | 495 void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { |
| 513 chevron_->SetVisible(icons < browser_action_views_.size()); | 496 chevron_->SetVisible(icons < browser_action_views_.size()); |
| 514 container_size_.set_width(IconCountToWidth(icons)); | 497 container_size_.set_width(IconCountToWidth(icons)); |
| 515 Layout(); | 498 Layout(); |
| 516 SchedulePaint(); | 499 SchedulePaint(); |
| 517 } | 500 } |
| 518 | 501 |
| 519 void BrowserActionsContainer::OnBrowserActionExecuted( | 502 void BrowserActionsContainer::OnBrowserActionExecuted( |
| 520 BrowserActionButton* button) { | 503 BrowserActionButton* button, bool inspect_with_devtools) { |
| 521 ExtensionAction* browser_action = button->browser_action(); | 504 ExtensionAction* browser_action = button->browser_action(); |
| 522 | 505 |
| 523 // Popups just display. No notification to the extension. | 506 // Popups just display. No notification to the extension. |
| 524 // TODO(erikkay): should there be? | 507 // TODO(erikkay): should there be? |
| 525 if (button->IsPopup()) { | 508 if (button->IsPopup()) { |
| 526 // If we're showing the same popup, just hide it and return. | 509 // If we're showing the same popup, just hide it and return. |
| 527 bool same_showing = popup_ && button == popup_button_; | 510 bool same_showing = popup_ && button == popup_button_; |
| 528 | 511 |
| 529 // Always hide the current popup, even if it's not the same. | 512 // Always hide the current popup, even if it's not the same. |
| 530 // Only one popup should be visible at a time. | 513 // Only one popup should be visible at a time. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 541 View::ConvertPointToScreen(reference_view, &origin); | 524 View::ConvertPointToScreen(reference_view, &origin); |
| 542 gfx::Rect rect = reference_view->bounds(); | 525 gfx::Rect rect = reference_view->bounds(); |
| 543 rect.set_x(origin.x()); | 526 rect.set_x(origin.x()); |
| 544 rect.set_y(origin.y()); | 527 rect.set_y(origin.y()); |
| 545 | 528 |
| 546 gfx::NativeWindow frame_window = | 529 gfx::NativeWindow frame_window = |
| 547 browser_->window()->GetNativeHandle(); | 530 browser_->window()->GetNativeHandle(); |
| 548 BubbleBorder::ArrowLocation arrow_location = UILayoutIsRightToLeft() ? | 531 BubbleBorder::ArrowLocation arrow_location = UILayoutIsRightToLeft() ? |
| 549 BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT; | 532 BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT; |
| 550 | 533 |
| 551 popup_ = ExtensionPopup::Show( | 534 popup_ = ExtensionPopup::Show(button->GetPopupUrl(), browser_, |
| 552 button->GetPopupUrl(), | 535 browser_->profile(), frame_window, rect, arrow_location, |
| 553 browser_, | |
| 554 browser_->profile(), | |
| 555 frame_window, | |
| 556 rect, | |
| 557 arrow_location, | |
| 558 true, // Activate the popup window. | 536 true, // Activate the popup window. |
| 559 ExtensionPopup::BUBBLE_CHROME); | 537 inspect_with_devtools, |
| 560 popup_->set_delegate(this); | 538 ExtensionPopup::BUBBLE_CHROME, |
| 539 this); // ExtensionPopupDelegate |
| 561 popup_button_ = button; | 540 popup_button_ = button; |
| 562 popup_button_->SetButtonPushed(); | 541 popup_button_->SetButtonPushed(); |
| 542 |
| 563 return; | 543 return; |
| 564 } | 544 } |
| 565 | 545 |
| 566 // Otherwise, we send the action to the extension. | 546 // Otherwise, we send the action to the extension. |
| 567 ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted( | 547 ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted( |
| 568 profile_, browser_action->extension_id(), browser_); | 548 profile_, browser_action->extension_id(), browser_); |
| 569 } | 549 } |
| 570 | 550 |
| 571 gfx::Size BrowserActionsContainer::GetPreferredSize() { | 551 gfx::Size BrowserActionsContainer::GetPreferredSize() { |
| 572 if (browser_action_views_.empty()) | 552 if (browser_action_views_.empty()) |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 802 } | 782 } |
| 803 | 783 |
| 804 void BrowserActionsContainer::MoveBrowserAction( | 784 void BrowserActionsContainer::MoveBrowserAction( |
| 805 const std::string& extension_id, size_t new_index) { | 785 const std::string& extension_id, size_t new_index) { |
| 806 ExtensionsService* service = profile_->GetExtensionsService(); | 786 ExtensionsService* service = profile_->GetExtensionsService(); |
| 807 Extension* extension = service->GetExtensionById(extension_id, false); | 787 Extension* extension = service->GetExtensionById(extension_id, false); |
| 808 model_->MoveBrowserAction(extension, new_index); | 788 model_->MoveBrowserAction(extension, new_index); |
| 809 SchedulePaint(); | 789 SchedulePaint(); |
| 810 } | 790 } |
| 811 | 791 |
| 812 void BrowserActionsContainer::Observe(NotificationType type, | |
| 813 const NotificationSource& source, | |
| 814 const NotificationDetails& details) { | |
| 815 switch (type.value) { | |
| 816 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: | |
| 817 // If we aren't the host of the popup, then disregard the notification. | |
| 818 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) | |
| 819 return; | |
| 820 | |
| 821 HidePopup(); | |
| 822 break; | |
| 823 | |
| 824 default: | |
| 825 NOTREACHED() << "Unexpected notification"; | |
| 826 } | |
| 827 } | |
| 828 | |
| 829 void BrowserActionsContainer::BubbleBrowserWindowMoved(BrowserBubble* bubble) { | |
| 830 } | |
| 831 | |
| 832 void BrowserActionsContainer::BubbleBrowserWindowClosing( | |
| 833 BrowserBubble* bubble) { | |
| 834 HidePopup(); | |
| 835 } | |
| 836 | |
| 837 void BrowserActionsContainer::BubbleGotFocus(BrowserBubble* bubble) { | |
| 838 if (!popup_) | |
| 839 return; | |
| 840 | |
| 841 // Forward the focus to the renderer. | |
| 842 popup_->host()->render_view_host()->view()->Focus(); | |
| 843 } | |
| 844 | |
| 845 void BrowserActionsContainer::BubbleLostFocus(BrowserBubble* bubble, | |
| 846 bool lost_focus_to_child) { | |
| 847 // Don't close when we are losing focus to a child window, this is the case | |
| 848 // for select popups and alert for example. | |
| 849 if (!popup_ || lost_focus_to_child) | |
| 850 return; | |
| 851 | |
| 852 // This is a bit annoying. If you click on the button that generated the | |
| 853 // current popup, then we first get this lost focus message, and then | |
| 854 // we get the click action. This results in the popup being immediately | |
| 855 // shown again. To workaround this, we put in a delay. | |
| 856 MessageLoop::current()->PostTask(FROM_HERE, | |
| 857 task_factory_.NewRunnableMethod(&BrowserActionsContainer::HidePopup)); | |
| 858 } | |
| 859 | |
| 860 void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { | 792 void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { |
| 861 if (source == chevron_) { | 793 if (source == chevron_) { |
| 862 overflow_menu_ = new BrowserActionOverflowMenuController( | 794 overflow_menu_ = new BrowserActionOverflowMenuController( |
| 863 this, chevron_, browser_action_views_, VisibleBrowserActions()); | 795 this, chevron_, browser_action_views_, VisibleBrowserActions()); |
| 864 overflow_menu_->set_observer(this); | 796 overflow_menu_->set_observer(this); |
| 865 overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), false); | 797 overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), false); |
| 866 } | 798 } |
| 867 } | 799 } |
| 868 | 800 |
| 869 void BrowserActionsContainer::WriteDragData(View* sender, | 801 void BrowserActionsContainer::WriteDragData(View* sender, |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1135 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, | 1067 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, |
| 1136 container_size_.width()); | 1068 container_size_.width()); |
| 1137 } | 1069 } |
| 1138 | 1070 |
| 1139 void BrowserActionsContainer::NotifyMenuDeleted( | 1071 void BrowserActionsContainer::NotifyMenuDeleted( |
| 1140 BrowserActionOverflowMenuController* controller) { | 1072 BrowserActionOverflowMenuController* controller) { |
| 1141 DCHECK(controller == overflow_menu_); | 1073 DCHECK(controller == overflow_menu_); |
| 1142 overflow_menu_ = NULL; | 1074 overflow_menu_ = NULL; |
| 1143 } | 1075 } |
| 1144 | 1076 |
| 1077 void BrowserActionsContainer::ShowPopupForDevToolsWindow(Extension* extension, |
| 1078 ExtensionAction* extension_action) { |
| 1079 OnBrowserActionExecuted(GetBrowserActionView(extension)->button(), |
| 1080 true); // inspect_with_devtools |
| 1081 } |
| 1082 |
| 1083 void BrowserActionsContainer::ExtensionPopupClosed(ExtensionPopup* popup) { |
| 1084 // ExtensionPopup is ref-counted, so we don't need to delete it. |
| 1085 DCHECK_EQ(popup_, popup); |
| 1086 popup_ = NULL; |
| 1087 popup_button_->SetButtonNotPushed(); |
| 1088 popup_button_ = NULL; |
| 1089 } |
| 1090 |
| 1145 bool BrowserActionsContainer::ShouldDisplayBrowserAction(Extension* extension) { | 1091 bool BrowserActionsContainer::ShouldDisplayBrowserAction(Extension* extension) { |
| 1146 // Only display incognito-enabled extensions while in incognito mode. | 1092 // Only display incognito-enabled extensions while in incognito mode. |
| 1147 return (!profile_->IsOffTheRecord() || | 1093 return (!profile_->IsOffTheRecord() || |
| 1148 profile_->GetExtensionsService()->IsIncognitoEnabled(extension)); | 1094 profile_->GetExtensionsService()->IsIncognitoEnabled(extension)); |
| 1149 } | 1095 } |
| OLD | NEW |