| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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/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/file_util.h" | |
| 12 #include "base/path_service.h" | |
| 13 #include "base/strings/utf_string_conversions.h" | |
| 14 #include "base/threading/sequenced_worker_pool.h" | |
| 15 #include "chrome/browser/apps/per_app_settings_service.h" | |
| 16 #include "chrome/browser/apps/per_app_settings_service_factory.h" | |
| 17 #include "chrome/browser/jumplist_updater_win.h" | |
| 18 #include "chrome/browser/metro_utils/metro_chrome_win.h" | |
| 19 #include "chrome/browser/profiles/profile.h" | |
| 20 #include "chrome/browser/shell_integration.h" | |
| 21 #include "chrome/browser/ui/web_applications/web_app_ui.h" | |
| 22 #include "chrome/browser/web_applications/web_app.h" | |
| 23 #include "chrome/browser/web_applications/web_app_win.h" | |
| 24 #include "chrome/common/chrome_icon_resources_win.h" | |
| 25 #include "chrome/common/chrome_switches.h" | |
| 26 #include "content/public/browser/browser_thread.h" | |
| 27 #include "extensions/common/extension.h" | |
| 28 #include "grit/generated_resources.h" | |
| 29 #include "ui/aura/remote_window_tree_host_win.h" | |
| 30 #include "ui/base/l10n/l10n_util.h" | |
| 31 #include "ui/base/win/shell.h" | |
| 32 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" | |
| 33 #include "ui/views/win/hwnd_util.h" | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 void CreateIconAndSetRelaunchDetails( | |
| 38 const base::FilePath& web_app_path, | |
| 39 const base::FilePath& icon_file, | |
| 40 const ShellIntegration::ShortcutInfo& shortcut_info, | |
| 41 const HWND hwnd) { | |
| 42 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
| 43 | |
| 44 // Set the relaunch data so "Pin this program to taskbar" has the app's | |
| 45 // information. | |
| 46 CommandLine command_line = ShellIntegration::CommandLineArgsForLauncher( | |
| 47 shortcut_info.url, | |
| 48 shortcut_info.extension_id, | |
| 49 shortcut_info.profile_path); | |
| 50 | |
| 51 base::FilePath chrome_exe; | |
| 52 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | |
| 53 NOTREACHED(); | |
| 54 return; | |
| 55 } | |
| 56 command_line.SetProgram(chrome_exe); | |
| 57 ui::win::SetRelaunchDetailsForWindow(command_line.GetCommandLineString(), | |
| 58 shortcut_info.title, hwnd); | |
| 59 | |
| 60 if (!base::PathExists(web_app_path) && | |
| 61 !base::CreateDirectory(web_app_path)) { | |
| 62 return; | |
| 63 } | |
| 64 | |
| 65 ui::win::SetAppIconForWindow(icon_file.value(), hwnd); | |
| 66 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon); | |
| 67 } | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 71 NativeAppWindowViewsWin::NativeAppWindowViewsWin() | |
| 72 : weak_ptr_factory_(this) { | |
| 73 } | |
| 74 | |
| 75 void NativeAppWindowViewsWin::ActivateParentDesktopIfNecessary() { | |
| 76 if (!ash::Shell::HasInstance()) | |
| 77 return; | |
| 78 | |
| 79 views::Widget* widget = | |
| 80 implicit_cast<views::WidgetDelegate*>(this)->GetWidget(); | |
| 81 chrome::HostDesktopType host_desktop_type = | |
| 82 chrome::GetHostDesktopTypeForNativeWindow(widget->GetNativeWindow()); | |
| 83 // Only switching into Ash from Native is supported. Tearing the user out of | |
| 84 // Metro mode can only be done by launching a process from Metro mode itself. | |
| 85 // This is done for launching apps, but not regular activations. | |
| 86 if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH && | |
| 87 chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_NATIVE) { | |
| 88 chrome::ActivateMetroChrome(); | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 void NativeAppWindowViewsWin::OnShortcutInfoLoaded( | |
| 93 const ShellIntegration::ShortcutInfo& shortcut_info) { | |
| 94 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 95 | |
| 96 HWND hwnd = GetNativeAppWindowHWND(); | |
| 97 | |
| 98 // Set window's icon to the one we're about to create/update in the web app | |
| 99 // path. The icon cache will refresh on icon creation. | |
| 100 base::FilePath web_app_path = web_app::GetWebAppDataDirectory( | |
| 101 shortcut_info.profile_path, shortcut_info.extension_id, | |
| 102 shortcut_info.url); | |
| 103 base::FilePath icon_file = web_app_path | |
| 104 .Append(web_app::internals::GetSanitizedFileName(shortcut_info.title)) | |
| 105 .ReplaceExtension(FILE_PATH_LITERAL(".ico")); | |
| 106 | |
| 107 content::BrowserThread::PostBlockingPoolTask( | |
| 108 FROM_HERE, | |
| 109 base::Bind(&CreateIconAndSetRelaunchDetails, | |
| 110 web_app_path, icon_file, shortcut_info, hwnd)); | |
| 111 } | |
| 112 | |
| 113 HWND NativeAppWindowViewsWin::GetNativeAppWindowHWND() const { | |
| 114 return views::HWNDForWidget(window()->GetTopLevelWidget()); | |
| 115 } | |
| 116 | |
| 117 void NativeAppWindowViewsWin::OnBeforeWidgetInit( | |
| 118 views::Widget::InitParams* init_params, views::Widget* widget) { | |
| 119 content::BrowserContext* browser_context = app_window()->browser_context(); | |
| 120 const extensions::Extension* extension = app_window()->extension(); | |
| 121 // If an app has any existing windows, ensure new ones are created on the | |
| 122 // same desktop. | |
| 123 apps::AppWindow* any_existing_window = | |
| 124 apps::AppWindowRegistry::Get(browser_context) | |
| 125 ->GetCurrentAppWindowForApp(extension->id()); | |
| 126 chrome::HostDesktopType desktop_type; | |
| 127 if (any_existing_window) { | |
| 128 desktop_type = chrome::GetHostDesktopTypeForNativeWindow( | |
| 129 any_existing_window->GetNativeWindow()); | |
| 130 } else { | |
| 131 PerAppSettingsService* settings = | |
| 132 PerAppSettingsServiceFactory::GetForBrowserContext(browser_context); | |
| 133 if (settings->HasDesktopLastLaunchedFrom(extension->id())) { | |
| 134 desktop_type = settings->GetDesktopLastLaunchedFrom(extension->id()); | |
| 135 } else { | |
| 136 // We don't know what desktop this app was last launched from, so take our | |
| 137 // best guess as to what desktop the user is on. | |
| 138 desktop_type = chrome::GetActiveDesktop(); | |
| 139 } | |
| 140 } | |
| 141 if (desktop_type == chrome::HOST_DESKTOP_TYPE_ASH) | |
| 142 init_params->context = ash::Shell::GetPrimaryRootWindow(); | |
| 143 else | |
| 144 init_params->native_widget = new views::DesktopNativeWidgetAura(widget); | |
| 145 } | |
| 146 | |
| 147 void NativeAppWindowViewsWin::InitializeDefaultWindow( | |
| 148 const apps::AppWindow::CreateParams& create_params) { | |
| 149 NativeAppWindowViews::InitializeDefaultWindow(create_params); | |
| 150 | |
| 151 const extensions::Extension* extension = app_window()->extension(); | |
| 152 std::string app_name = | |
| 153 web_app::GenerateApplicationNameFromExtensionId(extension->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 ui::win::SetAppIdForWindow(app_model_id_, hwnd); | |
| 162 | |
| 163 web_app::UpdateShortcutInfoAndIconForApp( | |
| 164 *extension, | |
| 165 profile, | |
| 166 base::Bind(&NativeAppWindowViewsWin::OnShortcutInfoLoaded, | |
| 167 weak_ptr_factory_.GetWeakPtr())); | |
| 168 | |
| 169 UpdateShelfMenu(); | |
| 170 } | |
| 171 | |
| 172 void NativeAppWindowViewsWin::Show() { | |
| 173 ActivateParentDesktopIfNecessary(); | |
| 174 NativeAppWindowViews::Show(); | |
| 175 } | |
| 176 | |
| 177 void NativeAppWindowViewsWin::Activate() { | |
| 178 ActivateParentDesktopIfNecessary(); | |
| 179 NativeAppWindowViews::Activate(); | |
| 180 } | |
| 181 | |
| 182 void NativeAppWindowViewsWin::UpdateShelfMenu() { | |
| 183 if (!JumpListUpdater::IsEnabled()) | |
| 184 return; | |
| 185 | |
| 186 // Currently the only option is related to ephemeral apps, so avoid updating | |
| 187 // the app's jump list when the feature is not enabled. | |
| 188 if (!CommandLine::ForCurrentProcess()->HasSwitch( | |
| 189 switches::kEnableEphemeralApps)) { | |
| 190 return; | |
| 191 } | |
| 192 | |
| 193 // For the icon resources. | |
| 194 base::FilePath chrome_path; | |
| 195 if (!PathService::Get(base::FILE_EXE, &chrome_path)) | |
| 196 return; | |
| 197 | |
| 198 JumpListUpdater jumplist_updater(app_model_id_); | |
| 199 if (!jumplist_updater.BeginUpdate()) | |
| 200 return; | |
| 201 | |
| 202 // Add item to install ephemeral apps. | |
| 203 const extensions::Extension* extension = app_window()->extension(); | |
| 204 DCHECK(extension); | |
| 205 if (extension->is_ephemeral()) { | |
| 206 scoped_refptr<ShellLinkItem> link(new ShellLinkItem()); | |
| 207 link->set_title(l10n_util::GetStringUTF16(IDS_APP_INSTALL_TITLE)); | |
| 208 link->set_icon(chrome_path.value(), | |
| 209 icon_resources::kInstallPackagedAppIndex); | |
| 210 ShellIntegration::AppendProfileArgs( | |
| 211 app_window()->browser_context()->GetPath(), link->GetCommandLine()); | |
| 212 link->GetCommandLine()->AppendSwitchASCII(switches::kInstallFromWebstore, | |
| 213 extension->id()); | |
| 214 | |
| 215 ShellLinkItemList items; | |
| 216 items.push_back(link); | |
| 217 jumplist_updater.AddTasks(items); | |
| 218 } | |
| 219 | |
| 220 jumplist_updater.CommitUpdate(); | |
| 221 } | |
| OLD | NEW |