15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file. 45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/ui/views/extensions/extension_action_view_controller.h" 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h" 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/extensions/api/commands/command_service.h" 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/extensions/extension_action.h" 115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/profiles/profile.h" 1203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/sessions/session_tab_helper.h" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/ui/browser.h" 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/ui/extensions/accelerator_priority.h" 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/ui/views/extensions/extension_action_view_delegate.h" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/common/extensions/api/extension_action/action_info.h" 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/common/extension.h" 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/views/controls/menu/menu_controller.h" 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/views/controls/menu/menu_runner.h" 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/views/view.h" 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/views/widget/widget.h" 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)using extensions::ActionInfo; 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)using extensions::CommandService; 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace { 276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// The ExtensionActionViewController which is currently showing its context 296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// menu, if any. 306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Since only one context menu can be shown (even across browser windows), it's 316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// safe to have this be a global singleton. 326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ExtensionActionViewController* context_menu_owner = NULL; 336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} // namespace 356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ExtensionActionViewController::ExtensionActionViewController( 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const extensions::Extension* extension, 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Browser* browser, 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ExtensionAction* extension_action, 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ExtensionActionViewDelegate* delegate) 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : extension_(extension), 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) browser_(browser), 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extension_action_(extension_action), 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delegate_(delegate), 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) icon_factory_(browser->profile(), extension, extension_action, this), 466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) popup_(NULL), 476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) weak_factory_(this) { 4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DCHECK(extension_action); 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(extension_action->action_type() == ActionInfo::TYPE_PAGE || 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extension_action->action_type() == ActionInfo::TYPE_BROWSER); 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(extension); 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ExtensionActionViewController::~ExtensionActionViewController() { 556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (context_menu_owner == this) 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) context_menu_owner = NULL; 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HidePopup(); 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) UnregisterCommand(false); 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::InspectPopup() { 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ExecuteAction(ExtensionPopup::SHOW_AND_INSPECT, true); 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::ExecuteActionByUser() { 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ExecuteAction(ExtensionPopup::SHOW, true); 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ExtensionActionViewController::ExecuteAction( 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ExtensionPopup::ShowAction show_action, bool grant_tab_permissions) { 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (extensions::ExtensionActionAPI::Get(browser_->profile())-> 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ExecuteExtensionAction(extension_, browser_, grant_tab_permissions) == 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ExtensionAction::ACTION_SHOW_POPUP) { 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GURL popup_url = extension_action_->GetPopupUrl(GetCurrentTabId()); 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return delegate_->GetPreferredPopupViewController()->ShowPopupWithUrl( 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci show_action, popup_url, grant_tab_permissions); 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::HidePopup() { 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (popup_) 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CleanupPopup(true); 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)gfx::Image ExtensionActionViewController::GetIcon(int tab_id) { 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return icon_factory_.GetIcon(tab_id); 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int ExtensionActionViewController::GetCurrentTabId() const { 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::WebContents* web_contents = delegate_->GetCurrentWebContents(); 9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return web_contents ? SessionTabHelper::IdForTab(web_contents) : -1; 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::RegisterCommand() { 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If we've already registered, do nothing. 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (action_keybinding_.get()) 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::Command extension_command; 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::FocusManager* focus_manager = 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delegate_->GetFocusManagerForAccelerator(); 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (focus_manager && GetExtensionCommand(&extension_command)) { 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) action_keybinding_.reset( 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new ui::Accelerator(extension_command.accelerator())); 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) focus_manager->RegisterAccelerator( 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *action_keybinding_, 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetAcceleratorPriority(extension_command.accelerator(), extension_), 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) this); 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::UnregisterCommand(bool only_if_removed) { 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::FocusManager* focus_manager = 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delegate_->GetFocusManagerForAccelerator(); 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!focus_manager || !action_keybinding_.get()) 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If |only_if_removed| is true, it means that we only need to unregister 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // ourselves as an accelerator if the command was removed. Otherwise, we need 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // to unregister ourselves no matter what (likely because we are shutting 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // down). 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::Command extension_command; 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!only_if_removed || !GetExtensionCommand(&extension_command)) { 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) focus_manager->UnregisterAccelerator(*action_keybinding_, this); 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) action_keybinding_.reset(); 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::OnIconUpdated() { 1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delegate_->OnIconUpdated(); 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ExtensionActionViewController::AcceleratorPressed( 1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ui::Accelerator& accelerator) { 1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // We shouldn't be handling any accelerators if the view is hidden, unless 1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // this is a browser action. 1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(extension_action_->action_type() == ActionInfo::TYPE_BROWSER || 1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delegate_->GetAsView()->visible()); 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Normal priority shortcuts must be handled via standard browser commands to 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // be processed at the proper time. 1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (GetAcceleratorPriority(accelerator, extension()) == 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ui::AcceleratorManager::kNormalPriority) 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ExecuteActionByUser(); 1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ExtensionActionViewController::CanHandleAccelerators() const { 1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Page actions can only handle accelerators when they are visible. 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Browser actions can handle accelerators even when not visible, since they 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // might be hidden in an overflow menu. 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return extension_action_->action_type() == ActionInfo::TYPE_PAGE ? 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delegate_->GetAsView()->visible() : true; 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::OnWidgetDestroying(views::Widget* widget) { 1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(popup_); 1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_EQ(popup_->GetWidget(), widget); 1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CleanupPopup(false); 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::ShowContextMenuForView( 1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::View* source, 1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const gfx::Point& point, 1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ui::MenuSourceType source_type) { 1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If there's another active menu that won't be dismissed by opening this one, 1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // then we can't show this one right away, since we can only show one nested 1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // menu at a time. 1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If the other menu is an extension action's context menu, then we'll run 1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // this one after that one closes. If it's a different type of menu, then we 1756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // close it and give up, for want of a better solution. (Luckily, this is 1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // rare). 1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // TODO(devlin): Update this when views code no longer runs menus in a nested 1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // loop. 1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (context_menu_owner) { 1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) context_menu_owner->followup_context_menu_task_ = 1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::Bind(&ExtensionActionViewController::DoShowContextMenu, 1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) weak_factory_.GetWeakPtr(), 1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) source_type); 1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (CloseActiveMenuIfNeeded()) 1866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return; 1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Otherwise, no other menu is showing, and we can proceed normally. 1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DoShowContextMenu(source_type); 1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void ExtensionActionViewController::DoShowContextMenu( 1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ui::MenuSourceType source_type) { 1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!extension_->ShowConfigureContextMenus()) 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DCHECK(!context_menu_owner); 1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) context_menu_owner = this; 1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // We shouldn't have both a popup and a context menu showing. 2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) delegate_->HideActivePopup(); 2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Reconstructs the menu every time because the menu's contents are dynamic. 2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_refptr<ExtensionContextMenuModel> context_menu_model( 2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new ExtensionContextMenuModel(extension_, browser_, this)); 2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) gfx::Point screen_loc; 2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::View::ConvertPointToScreen(delegate_->GetAsView(), &screen_loc); 2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int run_types = views::MenuRunner::HAS_MNEMONICS | 2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::MenuRunner::CONTEXT_MENU; 2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (delegate_->IsShownInMenu()) 2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) run_types |= views::MenuRunner::IS_NESTED; 2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::Widget* parent = delegate_->GetParentForContextMenu(); 2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) menu_runner_.reset( 2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new views::MenuRunner(context_menu_model.get(), run_types)); 2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (menu_runner_->RunMenuAt( 2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) parent, 2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci delegate_->GetContextMenuButton(), 2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) gfx::Rect(screen_loc, delegate_->GetAsView()->size()), 2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::MENU_ANCHOR_TOPLEFT, 2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) source_type) == views::MenuRunner::MENU_DELETED) { 2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) context_menu_owner = NULL; 2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) menu_runner_.reset(); 2316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If another extension action wants to show its context menu, allow it to. 2336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!followup_context_menu_task_.is_null()) { 2346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::Closure task = followup_context_menu_task_; 2356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) followup_context_menu_task_ = base::Closure(); 2366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) task.Run(); 2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ExtensionActionViewController::ShowPopupWithUrl( 2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ExtensionPopup::ShowAction show_action, 2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const GURL& popup_url, 2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool grant_tab_permissions) { 2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If we're already showing the popup for this browser action, just hide it 2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // and return. 2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool already_showing = popup_ != NULL; 2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Always hide the current popup, even if it's not the same. 2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Only one popup should be visible at a time. 2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delegate_->HideActivePopup(); 2516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Similarly, don't allow a context menu and a popup to be showing 2536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // simultaneously. 2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) CloseActiveMenuIfNeeded(); 2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (already_showing) 2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::BubbleBorder::Arrow arrow = base::i18n::IsRTL() ? 2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::BubbleBorder::TOP_LEFT : views::BubbleBorder::TOP_RIGHT; 2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) views::View* reference_view = delegate_->GetReferenceViewForPopup(); 2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) popup_ = ExtensionPopup::ShowPopup( 2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) popup_url, browser_, reference_view, arrow, show_action); 2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) popup_->GetWidget()->AddObserver(this); 2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci delegate_->OnPopupShown(grant_tab_permissions); 2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ExtensionActionViewController::GetExtensionCommand( 2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::Command* command) { 2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(command); 2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CommandService* command_service = CommandService::Get(browser_->profile()); 2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (extension_action_->action_type() == ActionInfo::TYPE_PAGE) { 2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return command_service->GetPageActionCommand( 2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extension_->id(), CommandService::ACTIVE_ONLY, command, NULL); 2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return command_service->GetBrowserActionCommand( 2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extension_->id(), CommandService::ACTIVE_ONLY, command, NULL); 2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool ExtensionActionViewController::CloseActiveMenuIfNeeded() { 2866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If this view is shown inside another menu, there's a possibility that there 2876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // is another context menu showing that we have to close before we can 2886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // activate a different menu. 2896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (delegate_->IsShownInMenu()) { 2906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) views::MenuController* menu_controller = 2916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) views::MenuController::GetActiveInstance(); 2926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If this is shown inside a menu, then there should always be an active 2936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // menu controller. 2946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DCHECK(menu_controller); 2956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (menu_controller->in_nested_run()) { 2966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // There is another menu showing. Close the outermost menu (since we are 2976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // shown in the same menu, we don't want to close the whole thing). 2986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) menu_controller->Cancel(views::MenuController::EXIT_OUTERMOST); 2996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 3006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 3016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 3026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 3046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 3056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionActionViewController::CleanupPopup(bool close_widget) { 3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(popup_); 3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delegate_->CleanupPopup(); 3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) popup_->GetWidget()->RemoveObserver(this); 3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (close_widget) 3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) popup_->GetWidget()->Close(); 3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) popup_ = NULL; 3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 314