From 0ff151d78683824266581ba161cf361e7f43962c Mon Sep 17 00:00:00 2001 From: "jamescook@chromium.org" Date: Fri, 4 Apr 2014 21:38:17 +0000 Subject: * Add --new-app-window flag to app_shell. * Add ShellAppWindowCreateFunction to provide a separate implementation of chrome.app.window.create() and manually register it (it has no IDL/JSON representation). * Add ShellAppWindow, a fullscreen app window that has no ui/views dependencies. * Hook up the various extension function dispatch machinery. This helps eliminate //chrome dependencies from app_shell by eliminating dependencies on //apps. BUG=360130 TEST=manual, app_shell --new-app-window can load and display hello-world and calculator NOTRY=true (try servers have no coverage for app_shell yet - we're working on it) Review URL: https://codereview.chromium.org/224733006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@261883 0039d316-1c4b-4281-b951-d872f2087c98 --- apps/shell/app_shell.gyp | 4 ++ apps/shell/browser/shell_app_window.cc | 76 ++++++++++++++++++++ apps/shell/browser/shell_app_window.h | 76 ++++++++++++++++++++ apps/shell/browser/shell_app_window_api.cc | 83 ++++++++++++++++++++++ apps/shell/browser/shell_app_window_api.h | 31 ++++++++ apps/shell/browser/shell_browser_main_parts.cc | 1 + apps/shell/browser/shell_desktop_controller.cc | 74 ++++++++++++++++++- apps/shell/browser/shell_desktop_controller.h | 21 ++++++ .../browser/shell_extensions_browser_client.cc | 14 +++- 9 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 apps/shell/browser/shell_app_window.cc create mode 100644 apps/shell/browser/shell_app_window.h create mode 100644 apps/shell/browser/shell_app_window_api.cc create mode 100644 apps/shell/browser/shell_app_window_api.h (limited to 'apps') diff --git a/apps/shell/app_shell.gyp b/apps/shell/app_shell.gyp index a66c960e..9b5d7e2 100644 --- a/apps/shell/app_shell.gyp +++ b/apps/shell/app_shell.gyp @@ -93,6 +93,10 @@ 'app/shell_main_delegate.h', 'browser/shell_app_sorting.cc', 'browser/shell_app_sorting.h', + 'browser/shell_app_window.cc', + 'browser/shell_app_window.h', + 'browser/shell_app_window_api.cc', + 'browser/shell_app_window_api.h', 'browser/shell_app_window_delegate.cc', 'browser/shell_app_window_delegate.h', 'browser/shell_apps_client.cc', diff --git a/apps/shell/browser/shell_app_window.cc b/apps/shell/browser/shell_app_window.cc new file mode 100644 index 0000000..52b1f6a --- /dev/null +++ b/apps/shell/browser/shell_app_window.cc @@ -0,0 +1,76 @@ +// 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 "apps/shell/browser/shell_app_window.h" + +#include "apps/shell/browser/shell_extension_web_contents_observer.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_view.h" +#include "extensions/browser/view_type_utils.h" +#include "extensions/common/extension_messages.h" +#include "ipc/ipc_message_macros.h" + +using content::BrowserContext; +using content::WebContents; + +namespace apps { + +ShellAppWindow::ShellAppWindow() {} + +ShellAppWindow::~ShellAppWindow() {} + +void ShellAppWindow::Init(BrowserContext* context, gfx::Size initial_size) { + extension_function_dispatcher_.reset( + new extensions::ExtensionFunctionDispatcher(context, this)); + + // Create the web contents with an initial size to avoid a resize. + WebContents::CreateParams create_params(context); + create_params.initial_size = initial_size; + web_contents_.reset(WebContents::Create(create_params)); + + content::WebContentsObserver::Observe(web_contents_.get()); + + // Add support for extension startup. + extensions::ShellExtensionWebContentsObserver::CreateForWebContents( + web_contents_.get()); + + extensions::SetViewType(web_contents_.get(), + extensions::VIEW_TYPE_APP_WINDOW); +} + +void ShellAppWindow::LoadURL(const GURL& url) { + content::NavigationController::LoadURLParams params(url); + web_contents_->GetController().LoadURLWithParams(params); + web_contents_->GetView()->Focus(); +} + +aura::Window* ShellAppWindow::GetNativeWindow() { + return web_contents_->GetView()->GetNativeView(); +} + +int ShellAppWindow::GetRenderViewRoutingID() { + return web_contents_->GetRenderViewHost()->GetRoutingID(); +} + +bool ShellAppWindow::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ShellAppWindow, message) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +content::WebContents* ShellAppWindow::GetAssociatedWebContents() const { + return web_contents_.get(); +} + +void ShellAppWindow::OnRequest(const ExtensionHostMsg_Request_Params& params) { + extension_function_dispatcher_->Dispatch(params, + web_contents_->GetRenderViewHost()); +} + +} // namespace apps diff --git a/apps/shell/browser/shell_app_window.h b/apps/shell/browser/shell_app_window.h new file mode 100644 index 0000000..3df66ad --- /dev/null +++ b/apps/shell/browser/shell_app_window.h @@ -0,0 +1,76 @@ +// 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. + +#ifndef APPS_SHELL_BROWSER_SHELL_APP_WINDOW_H_ +#define APPS_SHELL_BROWSER_SHELL_APP_WINDOW_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/web_contents_observer.h" +#include "extensions/browser/extension_function_dispatcher.h" + +struct ExtensionHostMsg_Request_Params; +class GURL; + +namespace aura { +class Window; +} + +namespace content { +class BrowserContext; +class WebContents; +} + +namespace extensions { +class ExtensionFunctionDispatcher; +} + +namespace gfx { +class Size; +} + +namespace apps { + +// A simplified app window created by chrome.app.window.create(). Manages the +// primary web contents for the app. +class ShellAppWindow + : public content::WebContentsObserver, + public extensions::ExtensionFunctionDispatcher::Delegate { + public: + ShellAppWindow(); + virtual ~ShellAppWindow(); + + // Creates the web contents and attaches extension-specific helpers. + // Passing a valid |initial_size| to avoid a web contents resize. + void Init(content::BrowserContext* context, gfx::Size initial_size); + + // Starts loading |url| which must be an extension URL. + void LoadURL(const GURL& url); + + // Returns the window hosting the web contents. + aura::Window* GetNativeWindow(); + + // Returns the routing ID of the render view host of |web_contents_|. + int GetRenderViewRoutingID(); + + // content::WebContentsObserver implementation + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // extensions::ExtensionFunctionDispatcher::Delegate implementation + virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE; + + private: + // IPC handler. + void OnRequest(const ExtensionHostMsg_Request_Params& params); + + scoped_ptr web_contents_; + scoped_ptr + extension_function_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(ShellAppWindow); +}; + +} // namespace apps + +#endif // APPS_SHELL_BROWSER_SHELL_APP_WINDOW_H_ diff --git a/apps/shell/browser/shell_app_window_api.cc b/apps/shell/browser/shell_app_window_api.cc new file mode 100644 index 0000000..136a0ce --- /dev/null +++ b/apps/shell/browser/shell_app_window_api.cc @@ -0,0 +1,83 @@ +// 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 "apps/shell/browser/shell_app_window_api.h" + +#include "apps/shell/browser/shell_app_window.h" +#include "apps/shell/browser/shell_desktop_controller.h" +#include "base/values.h" + +using base::DictionaryValue; + +namespace extensions { +namespace { + +// Returns stub values for window bounds. +DictionaryValue* CreateStubBoundsProperties() { + DictionaryValue* properties = new DictionaryValue; + properties->SetInteger("left", 0); + properties->SetInteger("top", 0); + properties->SetInteger("width", 0); + properties->SetInteger("height", 0); + return properties; +} + +// Creates a function call result to send to the renderer. +DictionaryValue* CreateResult(apps::ShellAppWindow* app_window) { + int view_id = app_window->GetRenderViewRoutingID(); + + DictionaryValue* result = new DictionaryValue; + result->Set("viewId", new base::FundamentalValue(view_id)); + result->Set("injectTitlebar", new base::FundamentalValue(false)); + result->Set("id", new base::StringValue("app_shell")); + + // Add stub window property data. + result->SetBoolean("fullscreen", true); + result->SetBoolean("minimized", false); + result->SetBoolean("maximized", false); + result->SetBoolean("alwaysOnTop", false); + result->SetBoolean("hasFrameColor", false); + result->SetInteger("frameColor", 0); + result->Set("innerBounds", CreateStubBoundsProperties()); + result->Set("outerBounds", CreateStubBoundsProperties()); + + return result; +} + +} // namespace + +ShellAppWindowCreateFunction::ShellAppWindowCreateFunction() {} + +ShellAppWindowCreateFunction::~ShellAppWindowCreateFunction() {} + +bool ShellAppWindowCreateFunction::RunImpl() { + // Arguments must contain a URL and may contain options and a callback. + if (args_->GetSize() < 1 || args_->GetSize() > 3) + return false; + + // Extract the URL for the window contents, e.g. "main.html". + std::string url_string; + if (!args_->GetString(0, &url_string)) + return false; + + // Convert "main.html" to "chrome-extension://main.html". + GURL url = GetExtension()->GetResourceURL(url_string); + if (!url.is_valid()) + return false; + + // The desktop keeps ownership of the window. + apps::ShellAppWindow* app_window = + apps::ShellDesktopController::instance()->CreateAppWindow( + browser_context()); + app_window->LoadURL(url); + + // Create the reply to send to the renderer. + DictionaryValue* result = CreateResult(app_window); + SetResult(result); + + SendResponse(true /* success */); + return true; +} + +} // namespace extensions diff --git a/apps/shell/browser/shell_app_window_api.h b/apps/shell/browser/shell_app_window_api.h new file mode 100644 index 0000000..d805dff --- /dev/null +++ b/apps/shell/browser/shell_app_window_api.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef APPS_SHELL_BROWSER_SHELL_APP_WINDOW_API_H_ +#define APPS_SHELL_BROWSER_SHELL_APP_WINDOW_API_H_ + +#include "base/compiler_specific.h" +#include "extensions/browser/extension_function.h" + +namespace extensions { + +// A simplified implementation of the chrome.app.window.create() function for +// app_shell. Opens a fullscreen window and invokes the window callback. Most +// of the response is stub data, but the JS contentWindow is valid. +class ShellAppWindowCreateFunction : public UIThreadExtensionFunction { + public: + ShellAppWindowCreateFunction(); + + // Don't use the APP_WINDOW_CREATE histogram so we don't pollute the + // statistics for the real Chrome implementation. + DECLARE_EXTENSION_FUNCTION("app.window.create", UNKNOWN); + + private: + virtual ~ShellAppWindowCreateFunction(); + virtual bool RunImpl() OVERRIDE; +}; + +} // namespace extensions + +#endif // APPS_SHELL_BROWSER_SHELL_APP_WINDOW_API_H_ diff --git a/apps/shell/browser/shell_browser_main_parts.cc b/apps/shell/browser/shell_browser_main_parts.cc index 2700cb4..b375e6c 100644 --- a/apps/shell/browser/shell_browser_main_parts.cc +++ b/apps/shell/browser/shell_browser_main_parts.cc @@ -143,6 +143,7 @@ void ShellBrowserMainParts::PostMainMessageLoopRun() { void ShellBrowserMainParts::OnHostCloseRequested( const aura::WindowTreeHost* host) { + desktop_controller_->CloseAppWindow(); extension_system_->CloseApp(); base::MessageLoop::current()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); diff --git a/apps/shell/browser/shell_desktop_controller.cc b/apps/shell/browser/shell_desktop_controller.cc index 9725c51..373b881 100644 --- a/apps/shell/browser/shell_desktop_controller.cc +++ b/apps/shell/browser/shell_desktop_controller.cc @@ -4,9 +4,12 @@ #include "apps/shell/browser/shell_desktop_controller.h" +#include "apps/shell/browser/shell_app_window.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/aura/env.h" +#include "ui/aura/layout_manager.h" #include "ui/aura/test/test_screen.h" +#include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/base/ime/input_method_initializer.h" #include "ui/gfx/screen.h" @@ -25,6 +28,40 @@ namespace { const SkColor kBackgroundColor = SK_ColorBLACK; +// A simple layout manager that makes each new window fill its parent. +class FillLayout : public aura::LayoutManager { + public: + FillLayout() {} + virtual ~FillLayout() {} + + private: + // aura::LayoutManager: + virtual void OnWindowResized() OVERRIDE {} + + virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { + if (!child->parent()) + return; + + // Create a rect at 0,0 with the size of the parent. + gfx::Size parent_size = child->parent()->bounds().size(); + child->SetBounds(gfx::Rect(parent_size)); + } + + virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {} + + virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {} + + virtual void OnChildWindowVisibilityChanged(aura::Window* child, + bool visible) OVERRIDE {} + + virtual void SetChildBounds(aura::Window* child, + const gfx::Rect& requested_bounds) OVERRIDE { + SetChildBoundsDirect(child, requested_bounds); + } + + DISALLOW_COPY_AND_ASSIGN(FillLayout); +}; + // A ViewsDelegate to attach new unparented windows to app_shell's root window. class ShellViewsDelegate : public views::TestViewsDelegate { public: @@ -46,6 +83,8 @@ class ShellViewsDelegate : public views::TestViewsDelegate { DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegate); }; +ShellDesktopController* g_instance = NULL; + } // namespace ShellDesktopController::ShellDesktopController() { @@ -60,15 +99,42 @@ ShellDesktopController::ShellDesktopController() { DCHECK(!views::ViewsDelegate::views_delegate); views::ViewsDelegate::views_delegate = new ShellViewsDelegate(wm_test_helper_->host()->window()); + + g_instance = this; } ShellDesktopController::~ShellDesktopController() { + // The app window must be explicitly closed before desktop teardown. + DCHECK(!app_window_); + g_instance = NULL; delete views::ViewsDelegate::views_delegate; views::ViewsDelegate::views_delegate = NULL; DestroyRootWindow(); aura::Env::DeleteInstance(); } +// static +ShellDesktopController* ShellDesktopController::instance() { + return g_instance; +} + +ShellAppWindow* ShellDesktopController::CreateAppWindow( + content::BrowserContext* context) { + aura::Window* root_window = GetWindowTreeHost()->window(); + + app_window_.reset(new ShellAppWindow); + app_window_->Init(context, root_window->bounds().size()); + + // Attach the web contents view to our window hierarchy. + aura::Window* content = app_window_->GetNativeWindow(); + root_window->AddChild(content); + content->Show(); + + return app_window_.get(); +} + +void ShellDesktopController::CloseAppWindow() { app_window_.reset(); } + aura::WindowTreeHost* ShellDesktopController::GetWindowTreeHost() { return wm_test_helper_->host(); } @@ -94,10 +160,14 @@ void ShellDesktopController::CreateRootWindow() { if (size.IsEmpty()) size = gfx::Size(800, 600); wm_test_helper_.reset(new wm::WMTestHelper(size)); - wm_test_helper_->host()->compositor()->SetBackgroundColor(kBackgroundColor); + aura::WindowTreeHost* host = wm_test_helper_->host(); + host->compositor()->SetBackgroundColor(kBackgroundColor); + + // Ensure new windows fill the display. + host->window()->SetLayoutManager(new FillLayout); // Ensure the X window gets mapped. - wm_test_helper_->host()->Show(); + host->Show(); } void ShellDesktopController::DestroyRootWindow() { diff --git a/apps/shell/browser/shell_desktop_controller.h b/apps/shell/browser/shell_desktop_controller.h index 3420790..1dcf503 100644 --- a/apps/shell/browser/shell_desktop_controller.h +++ b/apps/shell/browser/shell_desktop_controller.h @@ -20,12 +20,18 @@ class TestScreen; class WindowTreeHost; } +namespace content { +class BrowserContext; +} + namespace wm { class WMTestHelper; } namespace apps { +class ShellAppWindow; + // Handles desktop-related tasks for app_shell. class ShellDesktopController #if defined(OS_CHROMEOS) @@ -36,6 +42,18 @@ class ShellDesktopController ShellDesktopController(); virtual ~ShellDesktopController(); + // Returns the single instance of the desktop. (Stateless functions like + // ShellAppWindowCreateFunction need to be able to access the desktop, so + // we need a singleton somewhere). + static ShellDesktopController* instance(); + + // Creates a new app window and adds it to the desktop. The desktop maintains + // ownership of the window. + ShellAppWindow* CreateAppWindow(content::BrowserContext* context); + + // Closes and destroys the app window. + void CloseAppWindow(); + // Returns the host for the Aura window tree. aura::WindowTreeHost* GetWindowTreeHost(); @@ -66,6 +84,9 @@ class ShellDesktopController scoped_ptr test_screen_; + // The desktop supports a single app window. + scoped_ptr app_window_; + DISALLOW_COPY_AND_ASSIGN(ShellDesktopController); }; diff --git a/apps/shell/browser/shell_extensions_browser_client.cc b/apps/shell/browser/shell_extensions_browser_client.cc index 9207f77..91a7e6c 100644 --- a/apps/shell/browser/shell_extensions_browser_client.cc +++ b/apps/shell/browser/shell_extensions_browser_client.cc @@ -6,8 +6,10 @@ #include "apps/common/api/generated_api.h" #include "apps/shell/browser/shell_app_sorting.h" +#include "apps/shell/browser/shell_app_window_api.h" #include "apps/shell/browser/shell_extension_system_factory.h" #include "apps/shell/browser/shell_extension_web_contents_observer.h" +#include "base/command_line.h" #include "base/prefs/pref_service.h" #include "base/prefs/pref_service_factory.h" #include "base/prefs/testing_pref_store.h" @@ -16,6 +18,7 @@ #include "components/user_prefs/user_prefs.h" #include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/app_sorting.h" +#include "extensions/browser/extension_function_registry.h" #include "extensions/browser/extension_host_delegate.h" #include "extensions/browser/extension_prefs.h" #include "extensions/common/api/generated_api.h" @@ -204,8 +207,17 @@ void ShellExtensionsBrowserClient::RegisterExtensionFunctions( apps::api::GeneratedFunctionRegistry::RegisterAll(registry); // TODO(rockot): Remove dependency on src/chrome once we have some core APIs - // moved out. See http://crbug.com/349042. + // moved out. Also clean up the comment below. See http://crbug.com/349042. extensions::api::GeneratedFunctionRegistry::RegisterAll(registry); + + // Register our simplified implementation for chrome.app.window.create(). + // By registering it after extensions::api::GeneratedFunctionRegistry above + // we override the Chrome version of this function. + // TODO(jamescook): Remove the switch when the simple window good enough to + // use by default. + const std::string kNewAppWindow = "new-app-window"; + if (base::CommandLine::ForCurrentProcess()->HasSwitch(kNewAppWindow)) + registry->RegisterFunction(); } } // namespace extensions -- cgit v1.1