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.
5 #include "chrome/browser/ui/views/apps/chrome_native_app_window_views_win.h"
7 #include "apps/app_window.h"
8 #include "apps/app_window_registry.h"
9 #include "apps/ui/views/app_window_frame_view.h"
10 #include "ash/shell.h"
11 #include "base/command_line.h"
12 #include "base/file_util.h"
13 #include "base/path_service.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "chrome/browser/apps/per_app_settings_service.h"
17 #include "chrome/browser/apps/per_app_settings_service_factory.h"
18 #include "chrome/browser/jumplist_updater_win.h"
19 #include "chrome/browser/metro_utils/metro_chrome_win.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/shell_integration.h"
22 #include "chrome/browser/ui/views/apps/app_window_desktop_native_widget_aura_win.h"
23 #include "chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h"
24 #include "chrome/browser/web_applications/web_app.h"
25 #include "chrome/browser/web_applications/web_app_win.h"
26 #include "chrome/common/chrome_icon_resources_win.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "extensions/common/extension.h"
30 #include "grit/generated_resources.h"
31 #include "ui/aura/remote_window_tree_host_win.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/base/win/shell.h"
34 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
35 #include "ui/views/win/hwnd_util.h"
39 void CreateIconAndSetRelaunchDetails(
40 const base::FilePath
& web_app_path
,
41 const base::FilePath
& icon_file
,
42 const web_app::ShortcutInfo
& shortcut_info
,
44 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
46 // Set the relaunch data so "Pin this program to taskbar" has the app's
48 CommandLine command_line
= ShellIntegration::CommandLineArgsForLauncher(
50 shortcut_info
.extension_id
,
51 shortcut_info
.profile_path
);
53 base::FilePath chrome_exe
;
54 if (!PathService::Get(base::FILE_EXE
, &chrome_exe
)) {
58 command_line
.SetProgram(chrome_exe
);
59 ui::win::SetRelaunchDetailsForWindow(command_line
.GetCommandLineString(),
60 shortcut_info
.title
, hwnd
);
62 if (!base::PathExists(web_app_path
) &&
63 !base::CreateDirectory(web_app_path
)) {
67 ui::win::SetAppIconForWindow(icon_file
.value(), hwnd
);
68 web_app::internals::CheckAndSaveIcon(icon_file
, shortcut_info
.favicon
);
73 ChromeNativeAppWindowViewsWin::ChromeNativeAppWindowViewsWin()
74 : weak_ptr_factory_(this), glass_frame_view_(NULL
) {
77 void ChromeNativeAppWindowViewsWin::ActivateParentDesktopIfNecessary() {
78 if (!ash::Shell::HasInstance())
81 views::Widget
* widget
=
82 implicit_cast
<views::WidgetDelegate
*>(this)->GetWidget();
83 chrome::HostDesktopType host_desktop_type
=
84 chrome::GetHostDesktopTypeForNativeWindow(widget
->GetNativeWindow());
85 // Only switching into Ash from Native is supported. Tearing the user out of
86 // Metro mode can only be done by launching a process from Metro mode itself.
87 // This is done for launching apps, but not regular activations.
88 if (host_desktop_type
== chrome::HOST_DESKTOP_TYPE_ASH
&&
89 chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_NATIVE
) {
90 chrome::ActivateMetroChrome();
94 void ChromeNativeAppWindowViewsWin::OnShortcutInfoLoaded(
95 const web_app::ShortcutInfo
& shortcut_info
) {
96 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
98 HWND hwnd
= GetNativeAppWindowHWND();
100 // Set window's icon to the one we're about to create/update in the web app
101 // path. The icon cache will refresh on icon creation.
102 base::FilePath web_app_path
= web_app::GetWebAppDataDirectory(
103 shortcut_info
.profile_path
, shortcut_info
.extension_id
,
105 base::FilePath icon_file
= web_app_path
106 .Append(web_app::internals::GetSanitizedFileName(shortcut_info
.title
))
107 .ReplaceExtension(FILE_PATH_LITERAL(".ico"));
109 content::BrowserThread::PostBlockingPoolTask(
111 base::Bind(&CreateIconAndSetRelaunchDetails
,
112 web_app_path
, icon_file
, shortcut_info
, hwnd
));
115 HWND
ChromeNativeAppWindowViewsWin::GetNativeAppWindowHWND() const {
116 return views::HWNDForWidget(widget()->GetTopLevelWidget());
119 void ChromeNativeAppWindowViewsWin::OnBeforeWidgetInit(
120 views::Widget::InitParams
* init_params
,
121 views::Widget
* widget
) {
122 content::BrowserContext
* browser_context
= app_window()->browser_context();
123 std::string extension_id
= app_window()->extension_id();
124 // If an app has any existing windows, ensure new ones are created on the
126 apps::AppWindow
* any_existing_window
=
127 apps::AppWindowRegistry::Get(browser_context
)
128 ->GetCurrentAppWindowForApp(extension_id
);
129 chrome::HostDesktopType desktop_type
;
130 if (any_existing_window
) {
131 desktop_type
= chrome::GetHostDesktopTypeForNativeWindow(
132 any_existing_window
->GetNativeWindow());
134 PerAppSettingsService
* settings
=
135 PerAppSettingsServiceFactory::GetForBrowserContext(browser_context
);
136 if (settings
->HasDesktopLastLaunchedFrom(extension_id
)) {
137 desktop_type
= settings
->GetDesktopLastLaunchedFrom(extension_id
);
139 // We don't know what desktop this app was last launched from, so take our
140 // best guess as to what desktop the user is on.
141 desktop_type
= chrome::GetActiveDesktop();
144 if (desktop_type
== chrome::HOST_DESKTOP_TYPE_ASH
)
145 init_params
->context
= ash::Shell::GetPrimaryRootWindow();
147 init_params
->native_widget
= new AppWindowDesktopNativeWidgetAuraWin(this);
150 void ChromeNativeAppWindowViewsWin::InitializeDefaultWindow(
151 const apps::AppWindow::CreateParams
& create_params
) {
152 ChromeNativeAppWindowViews::InitializeDefaultWindow(create_params
);
154 const extensions::Extension
* extension
= app_window()->GetExtension();
158 std::string app_name
=
159 web_app::GenerateApplicationNameFromExtensionId(extension
->id());
160 base::string16 app_name_wide
= base::UTF8ToWide(app_name
);
161 HWND hwnd
= GetNativeAppWindowHWND();
163 Profile::FromBrowserContext(app_window()->browser_context());
165 ShellIntegration::GetAppModelIdForProfile(app_name_wide
,
167 ui::win::SetAppIdForWindow(app_model_id_
, hwnd
);
169 web_app::UpdateShortcutInfoAndIconForApp(
172 base::Bind(&ChromeNativeAppWindowViewsWin::OnShortcutInfoLoaded
,
173 weak_ptr_factory_
.GetWeakPtr()));
178 views::NonClientFrameView
*
179 ChromeNativeAppWindowViewsWin::CreateStandardDesktopAppFrame() {
180 glass_frame_view_
= NULL
;
181 if (ui::win::IsAeroGlassEnabled()) {
182 glass_frame_view_
= new GlassAppWindowFrameViewWin(this, widget());
183 return glass_frame_view_
;
185 return ChromeNativeAppWindowViews::CreateStandardDesktopAppFrame();
188 void ChromeNativeAppWindowViewsWin::Show() {
189 ActivateParentDesktopIfNecessary();
190 ChromeNativeAppWindowViews::Show();
193 void ChromeNativeAppWindowViewsWin::Activate() {
194 ActivateParentDesktopIfNecessary();
195 ChromeNativeAppWindowViews::Activate();
198 void ChromeNativeAppWindowViewsWin::UpdateShelfMenu() {
199 if (!JumpListUpdater::IsEnabled())
202 // Currently the only option is related to ephemeral apps, so avoid updating
203 // the app's jump list when the feature is not enabled.
204 if (!CommandLine::ForCurrentProcess()->HasSwitch(
205 switches::kEnableEphemeralApps
)) {
209 const extensions::Extension
* extension
= app_window()->GetExtension();
213 // For the icon resources.
214 base::FilePath chrome_path
;
215 if (!PathService::Get(base::FILE_EXE
, &chrome_path
))
218 JumpListUpdater
jumplist_updater(app_model_id_
);
219 if (!jumplist_updater
.BeginUpdate())
222 // Add item to install ephemeral apps.
223 if (extension
->is_ephemeral()) {
224 scoped_refptr
<ShellLinkItem
> link(new ShellLinkItem());
225 link
->set_title(l10n_util::GetStringUTF16(IDS_APP_INSTALL_TITLE
));
226 link
->set_icon(chrome_path
.value(),
227 icon_resources::kInstallPackagedAppIndex
);
228 ShellIntegration::AppendProfileArgs(
229 app_window()->browser_context()->GetPath(), link
->GetCommandLine());
230 link
->GetCommandLine()->AppendSwitchASCII(switches::kInstallFromWebstore
,
233 ShellLinkItemList items
;
234 items
.push_back(link
);
235 jumplist_updater
.AddTasks(items
);
238 jumplist_updater
.CommitUpdate();