Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / app_window / app_window_api.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/app_window/app_window_api.h"
6
7 #include "apps/app_window.h"
8 #include "apps/app_window_contents.h"
9 #include "apps/app_window_registry.h"
10 #include "apps/ui/native_app_window.h"
11 #include "base/command_line.h"
12 #include "base/time/time.h"
13 #include "base/values.h"
14 #include "chrome/browser/app_mode/app_mode_utils.h"
15 #include "chrome/browser/devtools/devtools_window.h"
16 #include "chrome/browser/extensions/window_controller.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/apps/chrome_shell_window_delegate.h"
19 #include "chrome/common/extensions/api/app_window.h"
20 #include "chrome/common/extensions/features/feature_channel.h"
21 #include "content/public/browser/notification_registrar.h"
22 #include "content/public/browser/notification_types.h"
23 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/common/url_constants.h"
27 #include "extensions/browser/extensions_browser_client.h"
28 #include "extensions/common/switches.h"
29 #include "ui/base/ui_base_types.h"
30 #include "ui/gfx/rect.h"
31 #include "url/gurl.h"
32
33 #if defined(USE_ASH)
34 #include "ash/shell.h"
35 #include "ui/aura/root_window.h"
36 #include "ui/aura/window.h"
37 #endif
38
39 using apps::AppWindow;
40
41 namespace app_window = extensions::api::app_window;
42 namespace Create = app_window::Create;
43
44 namespace extensions {
45
46 namespace app_window_constants {
47 const char kInvalidWindowId[] =
48     "The window id can not be more than 256 characters long.";
49 }
50
51 const char kNoneFrameOption[] = "none";
52 const char kHtmlFrameOption[] = "experimental-html";
53
54 namespace {
55
56 // Opens an inspector window and delays the response to the
57 // AppWindowCreateFunction until the DevToolsWindow has finished loading, and is
58 // ready to stop on breakpoints in the callback.
59 class DevToolsRestorer : public base::RefCounted<DevToolsRestorer> {
60  public:
61   DevToolsRestorer(AppWindowCreateFunction* delayed_create_function,
62                    content::RenderViewHost* created_view)
63       : delayed_create_function_(delayed_create_function) {
64     AddRef();  // Balanced in LoadCompleted.
65     DevToolsWindow* devtools_window =
66         DevToolsWindow::OpenDevToolsWindow(
67             created_view,
68             DevToolsToggleAction::ShowConsole());
69     devtools_window->SetLoadCompletedCallback(
70         base::Bind(&DevToolsRestorer::LoadCompleted, this));
71   }
72
73  private:
74   friend class base::RefCounted<DevToolsRestorer>;
75   ~DevToolsRestorer() {}
76
77   void LoadCompleted() {
78     delayed_create_function_->SendDelayedResponse();
79     Release();
80   }
81
82   scoped_refptr<AppWindowCreateFunction> delayed_create_function_;
83 };
84
85 }  // namespace
86
87 void AppWindowCreateFunction::SendDelayedResponse() {
88   SendResponse(true);
89 }
90
91 bool AppWindowCreateFunction::RunImpl() {
92   // Don't create app window if the system is shutting down.
93   if (extensions::ExtensionsBrowserClient::Get()->IsShuttingDown())
94     return false;
95
96   scoped_ptr<Create::Params> params(Create::Params::Create(*args_));
97   EXTENSION_FUNCTION_VALIDATE(params.get());
98
99   GURL url = GetExtension()->GetResourceURL(params->url);
100   // Allow absolute URLs for component apps, otherwise prepend the extension
101   // path.
102   if (GetExtension()->location() == extensions::Manifest::COMPONENT) {
103     GURL absolute = GURL(params->url);
104     if (absolute.has_scheme())
105       url = absolute;
106   }
107
108   bool inject_html_titlebar = false;
109
110   // TODO(jeremya): figure out a way to pass the opening WebContents through to
111   // AppWindow::Create so we can set the opener at create time rather than
112   // with a hack in AppWindowCustomBindings::GetView().
113   AppWindow::CreateParams create_params;
114   app_window::CreateWindowOptions* options = params->options.get();
115   if (options) {
116     if (options->id.get()) {
117       // TODO(mek): use URL if no id specified?
118       // Limit length of id to 256 characters.
119       if (options->id->length() > 256) {
120         error_ = app_window_constants::kInvalidWindowId;
121         return false;
122       }
123
124       create_params.window_key = *options->id;
125
126       if (options->singleton && *options->singleton == false) {
127         WriteToConsole(
128           content::CONSOLE_MESSAGE_LEVEL_WARNING,
129           "The 'singleton' option in chrome.apps.window.create() is deprecated!"
130           " Change your code to no longer rely on this.");
131       }
132
133       if (!options->singleton || *options->singleton) {
134         AppWindow* window = apps::AppWindowRegistry::Get(GetProfile())
135                                 ->GetAppWindowForAppAndKey(
136                                       extension_id(), create_params.window_key);
137         if (window) {
138           content::RenderViewHost* created_view =
139               window->web_contents()->GetRenderViewHost();
140           int view_id = MSG_ROUTING_NONE;
141           if (render_view_host_->GetProcess()->GetID() ==
142               created_view->GetProcess()->GetID()) {
143             view_id = created_view->GetRoutingID();
144           }
145
146           if (options->focused.get() && !*options->focused.get())
147             window->Show(AppWindow::SHOW_INACTIVE);
148           else
149             window->Show(AppWindow::SHOW_ACTIVE);
150
151           base::DictionaryValue* result = new base::DictionaryValue;
152           result->Set("viewId", new base::FundamentalValue(view_id));
153           window->GetSerializedState(result);
154           result->SetBoolean("existingWindow", true);
155           result->SetBoolean("injectTitlebar", false);
156           SetResult(result);
157           SendResponse(true);
158           return true;
159         }
160       }
161     }
162
163     // TODO(jeremya): remove these, since they do the same thing as
164     // left/top/width/height.
165     if (options->default_width.get())
166       create_params.bounds.set_width(*options->default_width.get());
167     if (options->default_height.get())
168       create_params.bounds.set_height(*options->default_height.get());
169     if (options->default_left.get())
170       create_params.bounds.set_x(*options->default_left.get());
171     if (options->default_top.get())
172       create_params.bounds.set_y(*options->default_top.get());
173
174     if (options->width.get())
175       create_params.bounds.set_width(*options->width.get());
176     if (options->height.get())
177       create_params.bounds.set_height(*options->height.get());
178     if (options->left.get())
179       create_params.bounds.set_x(*options->left.get());
180     if (options->top.get())
181       create_params.bounds.set_y(*options->top.get());
182
183     if (options->bounds.get()) {
184       app_window::Bounds* bounds = options->bounds.get();
185       if (bounds->width.get())
186         create_params.bounds.set_width(*bounds->width.get());
187       if (bounds->height.get())
188         create_params.bounds.set_height(*bounds->height.get());
189       if (bounds->left.get())
190         create_params.bounds.set_x(*bounds->left.get());
191       if (bounds->top.get())
192         create_params.bounds.set_y(*bounds->top.get());
193     }
194
195     if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV ||
196         GetExtension()->location() == extensions::Manifest::COMPONENT) {
197       if (options->type == extensions::api::app_window::WINDOW_TYPE_PANEL) {
198         create_params.window_type = AppWindow::WINDOW_TYPE_PANEL;
199       }
200     }
201
202     if (options->frame.get()) {
203       if (*options->frame == kHtmlFrameOption &&
204           (GetExtension()->HasAPIPermission(APIPermission::kExperimental) ||
205            CommandLine::ForCurrentProcess()->HasSwitch(
206                switches::kEnableExperimentalExtensionApis))) {
207         create_params.frame = AppWindow::FRAME_NONE;
208         inject_html_titlebar = true;
209       } else if (*options->frame == kNoneFrameOption) {
210         create_params.frame = AppWindow::FRAME_NONE;
211       } else {
212         create_params.frame = AppWindow::FRAME_CHROME;
213       }
214     }
215
216     if (options->transparent_background.get() &&
217         (GetExtension()->HasAPIPermission(APIPermission::kExperimental) ||
218          CommandLine::ForCurrentProcess()->HasSwitch(
219              switches::kEnableExperimentalExtensionApis))) {
220       create_params.transparent_background = *options->transparent_background;
221     }
222
223     gfx::Size& minimum_size = create_params.minimum_size;
224     if (options->min_width.get())
225       minimum_size.set_width(*options->min_width);
226     if (options->min_height.get())
227       minimum_size.set_height(*options->min_height);
228     gfx::Size& maximum_size = create_params.maximum_size;
229     if (options->max_width.get())
230       maximum_size.set_width(*options->max_width);
231     if (options->max_height.get())
232       maximum_size.set_height(*options->max_height);
233
234     if (options->hidden.get())
235       create_params.hidden = *options->hidden.get();
236
237     if (options->resizable.get())
238       create_params.resizable = *options->resizable.get();
239
240     if (options->always_on_top.get() &&
241         GetExtension()->HasAPIPermission(APIPermission::kAlwaysOnTopWindows))
242       create_params.always_on_top = *options->always_on_top.get();
243
244     if (options->focused.get())
245       create_params.focused = *options->focused.get();
246
247     if (options->type != extensions::api::app_window::WINDOW_TYPE_PANEL) {
248       switch (options->state) {
249         case extensions::api::app_window::STATE_NONE:
250         case extensions::api::app_window::STATE_NORMAL:
251           break;
252         case extensions::api::app_window::STATE_FULLSCREEN:
253           create_params.state = ui::SHOW_STATE_FULLSCREEN;
254           break;
255         case extensions::api::app_window::STATE_MAXIMIZED:
256           create_params.state = ui::SHOW_STATE_MAXIMIZED;
257           break;
258         case extensions::api::app_window::STATE_MINIMIZED:
259           create_params.state = ui::SHOW_STATE_MINIMIZED;
260           break;
261       }
262     }
263   }
264
265   create_params.creator_process_id =
266       render_view_host_->GetProcess()->GetID();
267
268   AppWindow* app_window = new AppWindow(
269       GetProfile(), new ChromeShellWindowDelegate(), GetExtension());
270   app_window->Init(
271       url, new apps::AppWindowContentsImpl(app_window), create_params);
272
273   if (chrome::IsRunningInForcedAppMode())
274     app_window->ForcedFullscreen();
275
276   content::RenderViewHost* created_view =
277       app_window->web_contents()->GetRenderViewHost();
278   int view_id = MSG_ROUTING_NONE;
279   if (create_params.creator_process_id == created_view->GetProcess()->GetID())
280     view_id = created_view->GetRoutingID();
281
282   base::DictionaryValue* result = new base::DictionaryValue;
283   result->Set("viewId", new base::FundamentalValue(view_id));
284   result->Set("injectTitlebar",
285       new base::FundamentalValue(inject_html_titlebar));
286   result->Set("id", new base::StringValue(app_window->window_key()));
287   app_window->GetSerializedState(result);
288   SetResult(result);
289
290   if (apps::AppWindowRegistry::Get(GetProfile())
291           ->HadDevToolsAttached(created_view)) {
292     new DevToolsRestorer(this, created_view);
293     return true;
294   }
295
296   SendResponse(true);
297   return true;
298 }
299
300 }  // namespace extensions