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::EnsureCaptionStyleSet() {
120 // Windows seems to have issues maximizing windows without WS_CAPTION.
121 // The default views / Aura implementation will remove this if we are using
122 // frameless or colored windows, so we put it back here.
123 HWND hwnd
= GetNativeAppWindowHWND();
124 int current_style
= ::GetWindowLong(hwnd
, GWL_STYLE
);
125 ::SetWindowLong(hwnd
, GWL_STYLE
, current_style
| WS_CAPTION
);
128 void ChromeNativeAppWindowViewsWin::OnBeforeWidgetInit(
129 views::Widget::InitParams
* init_params
,
130 views::Widget
* widget
) {
131 content::BrowserContext
* browser_context
= app_window()->browser_context();
132 std::string extension_id
= app_window()->extension_id();
133 // If an app has any existing windows, ensure new ones are created on the
135 apps::AppWindow
* any_existing_window
=
136 apps::AppWindowRegistry::Get(browser_context
)
137 ->GetCurrentAppWindowForApp(extension_id
);
138 chrome::HostDesktopType desktop_type
;
139 if (any_existing_window
) {
140 desktop_type
= chrome::GetHostDesktopTypeForNativeWindow(
141 any_existing_window
->GetNativeWindow());
143 PerAppSettingsService
* settings
=
144 PerAppSettingsServiceFactory::GetForBrowserContext(browser_context
);
145 if (settings
->HasDesktopLastLaunchedFrom(extension_id
)) {
146 desktop_type
= settings
->GetDesktopLastLaunchedFrom(extension_id
);
148 // We don't know what desktop this app was last launched from, so take our
149 // best guess as to what desktop the user is on.
150 desktop_type
= chrome::GetActiveDesktop();
153 if (desktop_type
== chrome::HOST_DESKTOP_TYPE_ASH
)
154 init_params
->context
= ash::Shell::GetPrimaryRootWindow();
156 init_params
->native_widget
= new AppWindowDesktopNativeWidgetAuraWin(this);
159 void ChromeNativeAppWindowViewsWin::InitializeDefaultWindow(
160 const apps::AppWindow::CreateParams
& create_params
) {
161 ChromeNativeAppWindowViews::InitializeDefaultWindow(create_params
);
163 const extensions::Extension
* extension
= app_window()->GetExtension();
167 std::string app_name
=
168 web_app::GenerateApplicationNameFromExtensionId(extension
->id());
169 base::string16 app_name_wide
= base::UTF8ToWide(app_name
);
170 HWND hwnd
= GetNativeAppWindowHWND();
172 Profile::FromBrowserContext(app_window()->browser_context());
174 ShellIntegration::GetAppModelIdForProfile(app_name_wide
,
176 ui::win::SetAppIdForWindow(app_model_id_
, hwnd
);
178 web_app::UpdateShortcutInfoAndIconForApp(
181 base::Bind(&ChromeNativeAppWindowViewsWin::OnShortcutInfoLoaded
,
182 weak_ptr_factory_
.GetWeakPtr()));
184 EnsureCaptionStyleSet();
188 views::NonClientFrameView
*
189 ChromeNativeAppWindowViewsWin::CreateStandardDesktopAppFrame() {
190 glass_frame_view_
= NULL
;
191 if (ui::win::IsAeroGlassEnabled()) {
192 glass_frame_view_
= new GlassAppWindowFrameViewWin(this, widget());
193 return glass_frame_view_
;
195 return ChromeNativeAppWindowViews::CreateStandardDesktopAppFrame();
198 void ChromeNativeAppWindowViewsWin::Show() {
199 ActivateParentDesktopIfNecessary();
200 ChromeNativeAppWindowViews::Show();
203 void ChromeNativeAppWindowViewsWin::Activate() {
204 ActivateParentDesktopIfNecessary();
205 ChromeNativeAppWindowViews::Activate();
208 void ChromeNativeAppWindowViewsWin::UpdateShelfMenu() {
209 if (!JumpListUpdater::IsEnabled())
212 // Currently the only option is related to ephemeral apps, so avoid updating
213 // the app's jump list when the feature is not enabled.
214 if (!CommandLine::ForCurrentProcess()->HasSwitch(
215 switches::kEnableEphemeralApps
)) {
219 const extensions::Extension
* extension
= app_window()->GetExtension();
223 // For the icon resources.
224 base::FilePath chrome_path
;
225 if (!PathService::Get(base::FILE_EXE
, &chrome_path
))
228 JumpListUpdater
jumplist_updater(app_model_id_
);
229 if (!jumplist_updater
.BeginUpdate())
232 // Add item to install ephemeral apps.
233 if (extension
->is_ephemeral()) {
234 scoped_refptr
<ShellLinkItem
> link(new ShellLinkItem());
235 link
->set_title(l10n_util::GetStringUTF16(IDS_APP_INSTALL_TITLE
));
236 link
->set_icon(chrome_path
.value(),
237 icon_resources::kInstallPackagedAppIndex
);
238 ShellIntegration::AppendProfileArgs(
239 app_window()->browser_context()->GetPath(), link
->GetCommandLine());
240 link
->GetCommandLine()->AppendSwitchASCII(switches::kInstallFromWebstore
,
243 ShellLinkItemList items
;
244 items
.push_back(link
);
245 jumplist_updater
.AddTasks(items
);
248 jumplist_updater
.CommitUpdate();