Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/web_applications/web_app.h" | 5 #include "chrome/browser/web_applications/web_app.h" |
| 6 | 6 |
| 7 #include <shlobj.h> | 7 #include <shlobj.h> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 base::StringPrintf(" (%d)", i)); | 122 base::StringPrintf(" (%d)", i)); |
| 123 } | 123 } |
| 124 if (file_util::PathExists(shortcut_file) && | 124 if (file_util::PathExists(shortcut_file) && |
| 125 ShortcutIsForProfile(shortcut_file, profile_path)) { | 125 ShortcutIsForProfile(shortcut_file, profile_path)) { |
| 126 shortcut_paths.push_back(shortcut_file); | 126 shortcut_paths.push_back(shortcut_file); |
| 127 } | 127 } |
| 128 } | 128 } |
| 129 return shortcut_paths; | 129 return shortcut_paths; |
| 130 } | 130 } |
| 131 | 131 |
| 132 } // namespace | 132 // Creates application shortcuts in a given set of paths. |
| 133 | 133 // |shortcut_paths| is a list of directories in which shortcuts should be |
| 134 namespace web_app { | 134 // created. |
| 135 | 135 // Returns true on success, false on failure. |
| 136 namespace internals { | 136 // Must be called on the FILE thread. |
| 137 | 137 bool CreateShortcutsInPaths( |
| 138 // Saves |image| to |icon_file| if the file is outdated and refresh shell's | |
| 139 // icon cache to ensure correct icon is displayed. Returns true if icon_file | |
| 140 // is up to date or successfully updated. | |
| 141 bool CheckAndSaveIcon(const base::FilePath& icon_file, | |
| 142 const gfx::ImageFamily& image) { | |
| 143 if (ShouldUpdateIcon(icon_file, image)) { | |
| 144 if (SaveIconWithCheckSum(icon_file, image)) { | |
| 145 // Refresh shell's icon cache. This call is quite disruptive as user would | |
| 146 // see explorer rebuilding the icon cache. It would be great that we find | |
| 147 // a better way to achieve this. | |
| 148 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, | |
| 149 NULL, NULL); | |
| 150 } else { | |
| 151 return false; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 return true; | |
| 156 } | |
| 157 | |
| 158 bool CreatePlatformShortcuts( | |
| 159 const base::FilePath& web_app_path, | 138 const base::FilePath& web_app_path, |
| 160 const ShellIntegration::ShortcutInfo& shortcut_info, | 139 const ShellIntegration::ShortcutInfo& shortcut_info, |
| 161 const ShellIntegration::ShortcutLocations& creation_locations) { | 140 const std::vector<base::FilePath>& shortcut_paths) { |
| 162 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 163 | |
| 164 // Shortcut paths under which to create shortcuts. | |
| 165 std::vector<base::FilePath> shortcut_paths = | |
| 166 GetShortcutPaths(creation_locations); | |
| 167 | |
| 168 bool pin_to_taskbar = creation_locations.in_quick_launch_bar && | |
| 169 (base::win::GetVersion() >= base::win::VERSION_WIN7); | |
| 170 | |
| 171 // Create/update the shortcut in the web app path for the "Pin To Taskbar" | |
| 172 // option in Win7. We use the web app path shortcut because we will overwrite | |
| 173 // it rather than appending unique numbers if the shortcut already exists. | |
| 174 // This prevents pinned apps from having unique numbers in their names. | |
| 175 if (pin_to_taskbar) | |
| 176 shortcut_paths.push_back(web_app_path); | |
| 177 | |
| 178 if (shortcut_paths.empty()) | |
| 179 return false; | |
| 180 | |
| 181 // Ensure web_app_path exists. | 141 // Ensure web_app_path exists. |
| 182 if (!file_util::PathExists(web_app_path) && | 142 if (!file_util::PathExists(web_app_path) && |
| 183 !file_util::CreateDirectory(web_app_path)) { | 143 !file_util::CreateDirectory(web_app_path)) { |
| 184 return false; | 144 return false; |
| 185 } | 145 } |
| 186 | 146 |
| 187 // Generates file name to use with persisted ico and shortcut file. | 147 // Generates file name to use with persisted ico and shortcut file. |
| 188 base::FilePath file_name = | 148 base::FilePath file_name = |
| 189 web_app::internals::GetSanitizedFileName(shortcut_info.title); | 149 web_app::internals::GetSanitizedFileName(shortcut_info.title); |
| 190 | 150 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 250 if (!file_util::PathExists(shortcut_file.DirName()) && | 210 if (!file_util::PathExists(shortcut_file.DirName()) && |
| 251 !file_util::CreateDirectory(shortcut_file.DirName())) { | 211 !file_util::CreateDirectory(shortcut_file.DirName())) { |
| 252 NOTREACHED(); | 212 NOTREACHED(); |
| 253 return false; | 213 return false; |
| 254 } | 214 } |
| 255 success = base::win::CreateOrUpdateShortcutLink( | 215 success = base::win::CreateOrUpdateShortcutLink( |
| 256 shortcut_file, shortcut_properties, | 216 shortcut_file, shortcut_properties, |
| 257 base::win::SHORTCUT_CREATE_ALWAYS) && success; | 217 base::win::SHORTCUT_CREATE_ALWAYS) && success; |
| 258 } | 218 } |
| 259 | 219 |
| 260 if (success && pin_to_taskbar) { | |
| 261 // Use the web app path shortcut for pinning to avoid having unique numbers | |
| 262 // in the application name. | |
| 263 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). | |
| 264 AddExtension(installer::kLnkExt); | |
| 265 success = base::win::TaskbarPinShortcutLink( | |
| 266 shortcut_to_pin.value().c_str()) && success; | |
| 267 } | |
| 268 | |
| 269 return success; | 220 return success; |
| 270 } | 221 } |
| 271 | 222 |
| 223 // Gets the directories with shortcuts for an app, and deletes the shortcuts. | |
| 224 // This will search the standard locations for shortcuts named |title| that open | |
| 225 // in the profile with |profile_path|. | |
| 226 // |was_pinned_to_taskbar| will be set to true if there was previously a | |
| 227 // shortcut pinned to the taskbar for this app; false otherwise. | |
| 228 // |shortcut_paths| will be populated with a list of directories where shortcuts | |
| 229 // for this app were found (and deleted). Both of these may be NULL. | |
| 230 void GetShortcutLocationsAndDeleteShortcuts( | |
|
Matt Giuca
2013/05/28 01:09:14
This was renamed at Sam's request: the new name is
benwells
2013/05/28 02:14:07
Could you add a comment somewhere that duplicates
Matt Giuca
2013/05/28 03:10:07
Done.
| |
| 231 const base::FilePath& web_app_path, | |
| 232 const base::FilePath& profile_path, | |
| 233 const string16& title, | |
| 234 bool* was_pinned_to_taskbar, | |
| 235 std::vector<base::FilePath>* shortcut_paths) { | |
| 236 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 237 | |
| 238 // Get all possible locations for shortcuts. | |
| 239 ShellIntegration::ShortcutLocations all_shortcut_locations; | |
| 240 all_shortcut_locations.in_applications_menu = true; | |
| 241 all_shortcut_locations.in_quick_launch_bar = true; | |
| 242 all_shortcut_locations.on_desktop = true; | |
| 243 // Delete shortcuts from the Chrome Apps subdirectory. | |
| 244 // This matches the subdir name set by CreateApplicationShortcutView::Accept | |
| 245 // for Chrome apps (not URL apps, but this function does not apply for them). | |
| 246 all_shortcut_locations.applications_menu_subdir = | |
| 247 web_app::GetAppShortcutsSubdirName(); | |
| 248 std::vector<base::FilePath> all_paths = web_app::internals::GetShortcutPaths( | |
| 249 all_shortcut_locations); | |
| 250 if (base::win::GetVersion() >= base::win::VERSION_WIN7) | |
| 251 all_paths.push_back(web_app_path); | |
| 252 | |
| 253 if (was_pinned_to_taskbar) { | |
| 254 // Determine if there is a link to this app in the TaskBar pin directory. | |
| 255 base::FilePath taskbar_pin_path; | |
| 256 if (PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pin_path)) { | |
| 257 std::vector<base::FilePath> taskbar_pin_files = | |
| 258 MatchingShortcutsForProfileAndExtension(taskbar_pin_path, | |
| 259 profile_path, title); | |
| 260 *was_pinned_to_taskbar = !taskbar_pin_files.empty(); | |
| 261 } else { | |
| 262 *was_pinned_to_taskbar = false; | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 for (std::vector<base::FilePath>::const_iterator i = all_paths.begin(); | |
| 267 i != all_paths.end(); ++i) { | |
| 268 std::vector<base::FilePath> shortcut_files = | |
| 269 MatchingShortcutsForProfileAndExtension(*i, profile_path, title); | |
| 270 if (shortcut_paths && !shortcut_files.empty()) { | |
| 271 shortcut_paths->push_back(*i); | |
| 272 } | |
| 273 for (std::vector<base::FilePath>::const_iterator j = shortcut_files.begin(); | |
| 274 j != shortcut_files.end(); ++j) { | |
| 275 // Any shortcut could have been pinned, either by chrome or the user, so | |
| 276 // they are all unpinned. | |
| 277 base::win::TaskbarUnpinShortcutLink(j->value().c_str()); | |
| 278 file_util::Delete(*j, false); | |
| 279 } | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 } // namespace | |
| 284 | |
| 285 namespace web_app { | |
| 286 | |
| 287 namespace internals { | |
| 288 | |
| 289 // Saves |image| to |icon_file| if the file is outdated and refresh shell's | |
| 290 // icon cache to ensure correct icon is displayed. Returns true if icon_file | |
| 291 // is up to date or successfully updated. | |
| 292 bool CheckAndSaveIcon(const base::FilePath& icon_file, | |
| 293 const gfx::ImageFamily& image) { | |
| 294 if (ShouldUpdateIcon(icon_file, image)) { | |
| 295 if (SaveIconWithCheckSum(icon_file, image)) { | |
| 296 // Refresh shell's icon cache. This call is quite disruptive as user would | |
| 297 // see explorer rebuilding the icon cache. It would be great that we find | |
| 298 // a better way to achieve this. | |
| 299 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, | |
| 300 NULL, NULL); | |
| 301 } else { | |
| 302 return false; | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 return true; | |
| 307 } | |
| 308 | |
| 309 bool CreatePlatformShortcuts( | |
| 310 const base::FilePath& web_app_path, | |
| 311 const ShellIntegration::ShortcutInfo& shortcut_info, | |
| 312 const ShellIntegration::ShortcutLocations& creation_locations) { | |
| 313 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 314 | |
| 315 // Shortcut paths under which to create shortcuts. | |
| 316 std::vector<base::FilePath> shortcut_paths = | |
| 317 GetShortcutPaths(creation_locations); | |
| 318 | |
| 319 bool pin_to_taskbar = creation_locations.in_quick_launch_bar && | |
| 320 (base::win::GetVersion() >= base::win::VERSION_WIN7); | |
| 321 | |
| 322 // Create/update the shortcut in the web app path for the "Pin To Taskbar" | |
| 323 // option in Win7. We use the web app path shortcut because we will overwrite | |
| 324 // it rather than appending unique numbers if the shortcut already exists. | |
| 325 // This prevents pinned apps from having unique numbers in their names. | |
| 326 if (pin_to_taskbar) | |
| 327 shortcut_paths.push_back(web_app_path); | |
| 328 | |
| 329 if (shortcut_paths.empty()) | |
| 330 return false; | |
| 331 | |
| 332 if (!CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths)) | |
| 333 return false; | |
| 334 | |
| 335 if (pin_to_taskbar) { | |
| 336 base::FilePath file_name = | |
| 337 web_app::internals::GetSanitizedFileName(shortcut_info.title); | |
| 338 // Use the web app path shortcut for pinning to avoid having unique numbers | |
| 339 // in the application name. | |
| 340 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). | |
| 341 AddExtension(installer::kLnkExt); | |
| 342 if (!base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str())) | |
| 343 return false; | |
| 344 } | |
| 345 | |
| 346 return true; | |
| 347 } | |
| 348 | |
| 272 void UpdatePlatformShortcuts( | 349 void UpdatePlatformShortcuts( |
| 273 const base::FilePath& web_app_path, | 350 const base::FilePath& web_app_path, |
| 351 const string16& old_app_title, | |
| 274 const ShellIntegration::ShortcutInfo& shortcut_info) { | 352 const ShellIntegration::ShortcutInfo& shortcut_info) { |
| 275 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 353 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 276 | 354 |
| 277 // Generates file name to use with persisted ico and shortcut file. | 355 // Generates file name to use with persisted ico and shortcut file. |
| 278 base::FilePath file_name = | 356 base::FilePath file_name = |
| 279 web_app::internals::GetSanitizedFileName(shortcut_info.title); | 357 web_app::internals::GetSanitizedFileName(shortcut_info.title); |
| 280 | 358 |
| 359 if (old_app_title != shortcut_info.title) { | |
| 360 // The app's title has changed. Delete all existing app shortcuts and | |
| 361 // recreate them in any locations they already existed (but do not add them | |
| 362 // to locations where they do not currently exist). | |
| 363 bool was_pinned_to_taskbar; | |
| 364 std::vector<base::FilePath> shortcut_paths; | |
| 365 GetShortcutLocationsAndDeleteShortcuts( | |
| 366 web_app_path, shortcut_info.profile_path, old_app_title, | |
| 367 &was_pinned_to_taskbar, &shortcut_paths); | |
| 368 CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths); | |
| 369 // If the shortcut was pinned to the taskbar, | |
| 370 // GetShortcutLocationsAndDeleteShortcuts will have deleted it. In that | |
| 371 // case, re-pin it. | |
| 372 if (was_pinned_to_taskbar) { | |
| 373 base::FilePath file_name = | |
| 374 web_app::internals::GetSanitizedFileName(shortcut_info.title); | |
| 375 // Use the web app path shortcut for pinning to avoid having unique | |
| 376 // numbers in the application name. | |
| 377 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). | |
| 378 AddExtension(installer::kLnkExt); | |
| 379 base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str()); | |
| 380 } | |
| 381 } | |
| 382 | |
| 281 // If an icon file exists, and is out of date, replace it with the new icon | 383 // If an icon file exists, and is out of date, replace it with the new icon |
| 282 // and let the shell know the icon has been modified. | 384 // and let the shell know the icon has been modified. |
| 283 base::FilePath icon_file = web_app_path.Append(file_name).AddExtension( | 385 base::FilePath icon_file = web_app_path.Append(file_name).AddExtension( |
| 284 FILE_PATH_LITERAL(".ico")); | 386 FILE_PATH_LITERAL(".ico")); |
| 285 if (file_util::PathExists(icon_file)) { | 387 if (file_util::PathExists(icon_file)) { |
| 286 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon); | 388 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon); |
| 287 } | 389 } |
| 288 } | 390 } |
| 289 | 391 |
| 290 void DeletePlatformShortcuts( | 392 void DeletePlatformShortcuts( |
| 291 const base::FilePath& web_app_path, | 393 const base::FilePath& web_app_path, |
| 292 const ShellIntegration::ShortcutInfo& shortcut_info) { | 394 const ShellIntegration::ShortcutInfo& shortcut_info) { |
| 293 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 395 GetShortcutLocationsAndDeleteShortcuts( |
| 294 | 396 web_app_path, shortcut_info.profile_path, shortcut_info.title, NULL, |
| 295 // Get all possible locations for shortcuts. | 397 NULL); |
| 296 ShellIntegration::ShortcutLocations all_shortcut_locations; | |
| 297 all_shortcut_locations.in_applications_menu = true; | |
| 298 all_shortcut_locations.in_quick_launch_bar = true; | |
| 299 all_shortcut_locations.on_desktop = true; | |
| 300 // Delete shortcuts from the Chrome Apps subdirectory. | |
| 301 // This matches the subdir name set by CreateApplicationShortcutView::Accept | |
| 302 // for Chrome apps (not URL apps, but this function does not apply for them). | |
| 303 string16 start_menu_subdir = GetAppShortcutsSubdirName(); | |
| 304 all_shortcut_locations.applications_menu_subdir = start_menu_subdir; | |
| 305 std::vector<base::FilePath> shortcut_paths = GetShortcutPaths( | |
| 306 all_shortcut_locations); | |
| 307 if (base::win::GetVersion() >= base::win::VERSION_WIN7) | |
| 308 shortcut_paths.push_back(web_app_path); | |
| 309 | |
| 310 for (std::vector<base::FilePath>::const_iterator i = shortcut_paths.begin(); | |
| 311 i != shortcut_paths.end(); ++i) { | |
| 312 std::vector<base::FilePath> shortcut_files = | |
| 313 MatchingShortcutsForProfileAndExtension(*i, shortcut_info.profile_path, | |
| 314 shortcut_info.title); | |
| 315 for (std::vector<base::FilePath>::const_iterator j = shortcut_files.begin(); | |
| 316 j != shortcut_files.end(); ++j) { | |
| 317 // Any shortcut could have been pinned, either by chrome or the user, so | |
| 318 // they are all unpinned. | |
| 319 base::win::TaskbarUnpinShortcutLink(j->value().c_str()); | |
| 320 file_util::Delete(*j, false); | |
| 321 } | |
| 322 } | |
| 323 | 398 |
| 324 // If there are no more shortcuts in the Chrome Apps subdirectory, remove it. | 399 // If there are no more shortcuts in the Chrome Apps subdirectory, remove it. |
| 325 base::FilePath chrome_apps_dir; | 400 base::FilePath chrome_apps_dir; |
| 326 if (PathService::Get(base::DIR_START_MENU, &chrome_apps_dir)) { | 401 if (PathService::Get(base::DIR_START_MENU, &chrome_apps_dir)) { |
| 327 chrome_apps_dir = chrome_apps_dir.Append(start_menu_subdir); | 402 chrome_apps_dir = chrome_apps_dir.Append(GetAppShortcutsSubdirName()); |
| 328 if (file_util::IsDirectoryEmpty(chrome_apps_dir)) | 403 if (file_util::IsDirectoryEmpty(chrome_apps_dir)) |
| 329 file_util::Delete(chrome_apps_dir, false); | 404 file_util::Delete(chrome_apps_dir, false); |
| 330 } | 405 } |
| 331 } | 406 } |
| 332 | 407 |
| 333 std::vector<base::FilePath> GetShortcutPaths( | 408 std::vector<base::FilePath> GetShortcutPaths( |
| 334 const ShellIntegration::ShortcutLocations& creation_locations) { | 409 const ShellIntegration::ShortcutLocations& creation_locations) { |
| 335 // Shortcut paths under which to create shortcuts. | 410 // Shortcut paths under which to create shortcuts. |
| 336 std::vector<base::FilePath> shortcut_paths; | 411 std::vector<base::FilePath> shortcut_paths; |
| 337 // Locations to add to shortcut_paths. | 412 // Locations to add to shortcut_paths. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 path = path.Append(locations[i].subdir); | 451 path = path.Append(locations[i].subdir); |
| 377 shortcut_paths.push_back(path); | 452 shortcut_paths.push_back(path); |
| 378 } | 453 } |
| 379 } | 454 } |
| 380 return shortcut_paths; | 455 return shortcut_paths; |
| 381 } | 456 } |
| 382 | 457 |
| 383 } // namespace internals | 458 } // namespace internals |
| 384 | 459 |
| 385 } // namespace web_app | 460 } // namespace web_app |
| OLD | NEW |