| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/extensions/chrome_extension_function_details.h" |
| |
| #include "chrome/browser/extensions/extension_tab_util.h" |
| #include "chrome/browser/extensions/window_controller.h" |
| #include "chrome/browser/extensions/window_controller_list.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "components/web_modal/web_contents_modal_dialog_manager.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "extensions/browser/app_window/app_window.h" |
| #include "extensions/browser/app_window/app_window_registry.h" |
| #include "extensions/browser/extension_function.h" |
| #include "extensions/browser/extension_function_dispatcher.h" |
| |
| using content::WebContents; |
| using content::RenderViewHost; |
| using extensions::WindowController; |
| |
| ChromeExtensionFunctionDetails::ChromeExtensionFunctionDetails( |
| UIThreadExtensionFunction* function) |
| : function_(function) { |
| } |
| |
| ChromeExtensionFunctionDetails::~ChromeExtensionFunctionDetails() { |
| } |
| |
| Profile* ChromeExtensionFunctionDetails::GetProfile() const { |
| return Profile::FromBrowserContext(function_->browser_context()); |
| } |
| |
| // TODO(stevenjb): Replace this with GetExtensionWindowController(). |
| Browser* ChromeExtensionFunctionDetails::GetCurrentBrowser() const { |
| // If the delegate has an associated browser, return it. |
| if (function_->dispatcher()) { |
| extensions::WindowController* window_controller = |
| function_->dispatcher()->GetExtensionWindowController(); |
| if (window_controller) { |
| Browser* browser = window_controller->GetBrowser(); |
| if (browser) |
| return browser; |
| } |
| } |
| |
| // Otherwise, try to default to a reasonable browser. If |include_incognito_| |
| // is true, we will also search browsers in the incognito version of this |
| // profile. Note that the profile may already be incognito, in which case |
| // we will search the incognito version only, regardless of the value of |
| // |include_incognito|. Look only for browsers on the active desktop as it is |
| // preferable to pretend no browser is open then to return a browser on |
| // another desktop. |
| if (function_->render_frame_host()) { |
| Profile* profile = Profile::FromBrowserContext( |
| function_->render_frame_host()->GetProcess()->GetBrowserContext()); |
| Browser* browser = chrome::FindAnyBrowser( |
| profile, function_->include_incognito(), chrome::GetActiveDesktop()); |
| if (browser) |
| return browser; |
| } |
| |
| // NOTE(rafaelw): This can return NULL in some circumstances. In particular, |
| // a background_page onload chrome.tabs api call can make it into here |
| // before the browser is sufficiently initialized to return here, or |
| // all of this profile's browser windows may have been closed. |
| // A similar situation may arise during shutdown. |
| // TODO(rafaelw): Delay creation of background_page until the browser |
| // is available. http://code.google.com/p/chromium/issues/detail?id=13284 |
| return NULL; |
| } |
| |
| extensions::WindowController* |
| ChromeExtensionFunctionDetails::GetExtensionWindowController() const { |
| // If the delegate has an associated window controller, return it. |
| if (function_->dispatcher()) { |
| extensions::WindowController* window_controller = |
| function_->dispatcher()->GetExtensionWindowController(); |
| if (window_controller) |
| return window_controller; |
| } |
| |
| return extensions::WindowControllerList::GetInstance() |
| ->CurrentWindowForFunction(function_); |
| } |
| |
| content::WebContents* |
| ChromeExtensionFunctionDetails::GetAssociatedWebContents() { |
| content::WebContents* web_contents = function_->GetAssociatedWebContents(); |
| if (web_contents) |
| return web_contents; |
| |
| Browser* browser = GetCurrentBrowser(); |
| if (!browser) |
| return NULL; |
| return browser->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| content::WebContents* ChromeExtensionFunctionDetails::GetOriginWebContents() { |
| WebContents* contents = function_->GetSenderWebContents(); |
| if (!contents) |
| return nullptr; |
| |
| // Hack: use the existence of a WebContentsModalDialogManager to decide |
| // whether the sender web contents is visible. |
| web_modal::WebContentsModalDialogManager* web_contents_modal_dialog_manager = |
| web_modal::WebContentsModalDialogManager::FromWebContents(contents); |
| if (web_contents_modal_dialog_manager) |
| return contents; |
| |
| // If there is no WebContentsModalDialogManager, then this contents is |
| // probably the background page for an extension or app. |
| contents = nullptr; |
| |
| int source_tab_id = function_->source_tab_id(); |
| if (source_tab_id != TabStripModel::kNoTab) { |
| // When the request originated from a background page, but there is no |
| // app window open, check to see if it originated from a tab and display |
| // the dialog in that tab. |
| if (extensions::ExtensionTabUtil::GetTabById( |
| source_tab_id, GetProfile(), true /* include_incognito */, nullptr, |
| nullptr, &contents, nullptr)) |
| return contents; |
| } |
| |
| // Try to find an app window and get its web contents. |
| const extensions::Extension* extension = function_->extension(); |
| if (extension) { |
| extensions::AppWindow* window = |
| extensions::AppWindowRegistry::Get(GetProfile()) |
| ->GetCurrentAppWindowForApp(extension->id()); |
| if (window) |
| return window->web_contents(); |
| } |
| return contents; |
| } |
| |
| gfx::NativeWindow ChromeExtensionFunctionDetails::GetNativeWindowForUI() { |
| // Try to use WindowControllerList first because WebContents's |
| // GetTopLevelNativeWindow() can't return the top level window when the tab |
| // is not focused. |
| WindowController* controller = |
| extensions::WindowControllerList::GetInstance()->CurrentWindowForFunction( |
| function_); |
| if (controller) |
| return controller->window()->GetNativeWindow(); |
| |
| // CurrentWindowForFunction() can't find app's window. |
| WebContents* contents = GetOriginWebContents(); |
| if (contents) |
| return contents->GetTopLevelNativeWindow(); |
| |
| Browser* browser = |
| chrome::FindBrowserWithProfile(GetProfile(), chrome::GetActiveDesktop()); |
| return browser->window()->GetNativeWindow(); |
| } |