chrome_native_app_window_views_win.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
1// Copyright 2014 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/ui/views/apps/chrome_native_app_window_views_win.h"
6
7#include "apps/app_window.h"
8#include "apps/app_window_registry.h"
9#include "ash/shell.h"
10#include "base/command_line.h"
11#include "base/path_service.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/threading/sequenced_worker_pool.h"
14#include "chrome/browser/apps/per_app_settings_service.h"
15#include "chrome/browser/apps/per_app_settings_service_factory.h"
16#include "chrome/browser/jumplist_updater_win.h"
17#include "chrome/browser/metro_utils/metro_chrome_win.h"
18#include "chrome/browser/profiles/profile.h"
19#include "chrome/browser/web_applications/web_app.h"
20#include "chrome/common/chrome_icon_resources_win.h"
21#include "chrome/common/chrome_switches.h"
22#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
23#include "content/public/browser/browser_thread.h"
24#include "extensions/common/extension.h"
25#include "grit/generated_resources.h"
26#include "ui/aura/remote_window_tree_host_win.h"
27#include "ui/base/l10n/l10n_util.h"
28#include "ui/base/win/shell.h"
29#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
30#include "ui/views/win/hwnd_util.h"
31
32ChromeNativeAppWindowViewsWin::ChromeNativeAppWindowViewsWin()
33    : weak_ptr_factory_(this) {}
34
35void ChromeNativeAppWindowViewsWin::ActivateParentDesktopIfNecessary() {
36  if (!ash::Shell::HasInstance())
37    return;
38
39  views::Widget* widget =
40      implicit_cast<views::WidgetDelegate*>(this)->GetWidget();
41  chrome::HostDesktopType host_desktop_type =
42      chrome::GetHostDesktopTypeForNativeWindow(widget->GetNativeWindow());
43  // Only switching into Ash from Native is supported. Tearing the user out of
44  // Metro mode can only be done by launching a process from Metro mode itself.
45  // This is done for launching apps, but not regular activations.
46  if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH &&
47      chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_NATIVE) {
48    chrome::ActivateMetroChrome();
49  }
50}
51
52HWND ChromeNativeAppWindowViewsWin::GetNativeAppWindowHWND() const {
53  return views::HWNDForWidget(widget()->GetTopLevelWidget());
54}
55
56void ChromeNativeAppWindowViewsWin::OnBeforeWidgetInit(
57    views::Widget::InitParams* init_params,
58    views::Widget* widget) {
59  content::BrowserContext* browser_context = app_window()->browser_context();
60  const extensions::Extension* extension = app_window()->extension();
61  // If an app has any existing windows, ensure new ones are created on the
62  // same desktop.
63  apps::AppWindow* any_existing_window =
64      apps::AppWindowRegistry::Get(browser_context)
65          ->GetCurrentAppWindowForApp(extension->id());
66  chrome::HostDesktopType desktop_type;
67  if (any_existing_window) {
68    desktop_type = chrome::GetHostDesktopTypeForNativeWindow(
69        any_existing_window->GetNativeWindow());
70  } else {
71    PerAppSettingsService* settings =
72        PerAppSettingsServiceFactory::GetForBrowserContext(browser_context);
73    if (settings->HasDesktopLastLaunchedFrom(extension->id())) {
74      desktop_type = settings->GetDesktopLastLaunchedFrom(extension->id());
75    } else {
76      // We don't know what desktop this app was last launched from, so take our
77      // best guess as to what desktop the user is on.
78      desktop_type = chrome::GetActiveDesktop();
79    }
80  }
81  if (desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
82    init_params->context = ash::Shell::GetPrimaryRootWindow();
83  else
84    init_params->native_widget = new views::DesktopNativeWidgetAura(widget);
85}
86
87void ChromeNativeAppWindowViewsWin::InitializeDefaultWindow(
88    const apps::AppWindow::CreateParams& create_params) {
89  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
90
91  ChromeNativeAppWindowViews::InitializeDefaultWindow(create_params);
92
93  SetAppDetailsForWindow();
94
95  UpdateShelfMenu();
96}
97
98void ChromeNativeAppWindowViewsWin::Show() {
99  ActivateParentDesktopIfNecessary();
100  ChromeNativeAppWindowViews::Show();
101}
102
103void ChromeNativeAppWindowViewsWin::Activate() {
104  ActivateParentDesktopIfNecessary();
105  ChromeNativeAppWindowViews::Activate();
106}
107
108void ChromeNativeAppWindowViewsWin::UpdateShelfMenu() {
109  if (!JumpListUpdater::IsEnabled())
110    return;
111
112  // Currently the only option is related to ephemeral apps, so avoid updating
113  // the app's jump list when the feature is not enabled.
114  if (!CommandLine::ForCurrentProcess()->HasSwitch(
115          switches::kEnableEphemeralApps)) {
116    return;
117  }
118
119  // For the icon resources.
120  base::FilePath chrome_path;
121  if (!PathService::Get(base::FILE_EXE, &chrome_path))
122    return;
123
124  JumpListUpdater jumplist_updater(app_model_id_);
125  if (!jumplist_updater.BeginUpdate())
126    return;
127
128  // Add item to install ephemeral apps.
129  const extensions::Extension* extension = app_window()->extension();
130  DCHECK(extension);
131  if (extension->is_ephemeral()) {
132    scoped_refptr<ShellLinkItem> link(new ShellLinkItem());
133    link->set_title(l10n_util::GetStringUTF16(IDS_APP_INSTALL_TITLE));
134    link->set_icon(chrome_path.value(),
135                   icon_resources::kInstallPackagedAppIndex);
136    ShellIntegration::AppendProfileArgs(
137        app_window()->browser_context()->GetPath(), link->GetCommandLine());
138    link->GetCommandLine()->AppendSwitchASCII(switches::kInstallFromWebstore,
139                                              extension->id());
140
141    ShellLinkItemList items;
142    items.push_back(link);
143    jumplist_updater.AddTasks(items);
144  }
145
146  jumplist_updater.CommitUpdate();
147}
148
149void ChromeNativeAppWindowViewsWin::SetAppDetailsForWindow() {
150  // Set the Application Model ID so that windows are grouped correctly.
151  const extensions::Extension* app = app_window()->extension();
152  std::string app_name =
153      web_app::GenerateApplicationNameFromExtensionId(app->id());
154  base::string16 app_name_wide = base::UTF8ToWide(app_name);
155  HWND hwnd = GetNativeAppWindowHWND();
156  Profile* profile =
157      Profile::FromBrowserContext(app_window()->browser_context());
158  app_model_id_ =
159      ShellIntegration::GetAppModelIdForProfile(app_name_wide,
160                                                profile->GetPath());
161
162  // Set the relaunch data so "Pin this program to taskbar" has the app's
163  // information.
164  base::FilePath chrome_exe;
165  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
166    NOTREACHED();
167    return;
168  }
169
170  GURL url = extensions::AppLaunchInfo::GetLaunchWebURL(app);
171  CommandLine command_line = ShellIntegration::CommandLineArgsForLauncher(
172      url, app->id(), profile->GetPath());
173  command_line.SetProgram(chrome_exe);
174
175  // Set window's icon to the one in the web app path. This was created when the
176  // app was installed. The icon cache would have been refreshed at that time.
177  base::string16 title = base::UTF8ToUTF16(app->name());
178  base::FilePath web_app_path = web_app::GetWebAppDataDirectory(
179      profile->GetPath(), app->id(), url);
180  base::FilePath icon_file = web_app_path
181      .Append(web_app::internals::GetSanitizedFileName(title))
182      .ReplaceExtension(FILE_PATH_LITERAL(".ico"));
183
184  ui::win::SetAppDetailsForWindow(
185      app_model_id_,
186      icon_file.value(),
187      command_line.GetCommandLineString(),
188      title,
189      hwnd);
190}
191