Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(703)

Side by Side Diff: chrome/browser/web_applications/web_app_win.cc

Issue 14993013: Windows: When an app is updated and its name changes, recreate shortcuts. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Respond to reviewer feedback. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/web_applications/web_app_mac.mm ('k') | chrome/common/extensions/extension.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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). This will delete duplicate shortcuts,
230 // but only return each path once, even if it contained multiple deleted
231 // shortcuts. Both of these may be NULL.
232 void GetShortcutLocationsAndDeleteShortcuts(
233 const base::FilePath& web_app_path,
234 const base::FilePath& profile_path,
235 const string16& title,
236 bool* was_pinned_to_taskbar,
237 std::vector<base::FilePath>* shortcut_paths) {
238 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
239
240 // Get all possible locations for shortcuts.
241 ShellIntegration::ShortcutLocations all_shortcut_locations;
242 all_shortcut_locations.in_applications_menu = true;
243 all_shortcut_locations.in_quick_launch_bar = true;
244 all_shortcut_locations.on_desktop = true;
245 // Delete shortcuts from the Chrome Apps subdirectory.
246 // This matches the subdir name set by CreateApplicationShortcutView::Accept
247 // for Chrome apps (not URL apps, but this function does not apply for them).
248 all_shortcut_locations.applications_menu_subdir =
249 web_app::GetAppShortcutsSubdirName();
250 std::vector<base::FilePath> all_paths = web_app::internals::GetShortcutPaths(
251 all_shortcut_locations);
252 if (base::win::GetVersion() >= base::win::VERSION_WIN7)
253 all_paths.push_back(web_app_path);
254
255 if (was_pinned_to_taskbar) {
256 // Determine if there is a link to this app in the TaskBar pin directory.
257 base::FilePath taskbar_pin_path;
258 if (PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pin_path)) {
259 std::vector<base::FilePath> taskbar_pin_files =
260 MatchingShortcutsForProfileAndExtension(taskbar_pin_path,
261 profile_path, title);
262 *was_pinned_to_taskbar = !taskbar_pin_files.empty();
263 } else {
264 *was_pinned_to_taskbar = false;
265 }
266 }
267
268 for (std::vector<base::FilePath>::const_iterator i = all_paths.begin();
269 i != all_paths.end(); ++i) {
270 std::vector<base::FilePath> shortcut_files =
271 MatchingShortcutsForProfileAndExtension(*i, profile_path, title);
272 if (shortcut_paths && !shortcut_files.empty()) {
273 shortcut_paths->push_back(*i);
274 }
275 for (std::vector<base::FilePath>::const_iterator j = shortcut_files.begin();
276 j != shortcut_files.end(); ++j) {
277 // Any shortcut could have been pinned, either by chrome or the user, so
278 // they are all unpinned.
279 base::win::TaskbarUnpinShortcutLink(j->value().c_str());
280 file_util::Delete(*j, false);
281 }
282 }
283 }
284
285 } // namespace
286
287 namespace web_app {
288
289 namespace internals {
290
291 // Saves |image| to |icon_file| if the file is outdated and refresh shell's
292 // icon cache to ensure correct icon is displayed. Returns true if icon_file
293 // is up to date or successfully updated.
294 bool CheckAndSaveIcon(const base::FilePath& icon_file,
295 const gfx::ImageFamily& image) {
296 if (ShouldUpdateIcon(icon_file, image)) {
297 if (SaveIconWithCheckSum(icon_file, image)) {
298 // Refresh shell's icon cache. This call is quite disruptive as user would
299 // see explorer rebuilding the icon cache. It would be great that we find
300 // a better way to achieve this.
301 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT,
302 NULL, NULL);
303 } else {
304 return false;
305 }
306 }
307
308 return true;
309 }
310
311 bool CreatePlatformShortcuts(
312 const base::FilePath& web_app_path,
313 const ShellIntegration::ShortcutInfo& shortcut_info,
314 const ShellIntegration::ShortcutLocations& creation_locations) {
315 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
316
317 // Shortcut paths under which to create shortcuts.
318 std::vector<base::FilePath> shortcut_paths =
319 GetShortcutPaths(creation_locations);
320
321 bool pin_to_taskbar = creation_locations.in_quick_launch_bar &&
322 (base::win::GetVersion() >= base::win::VERSION_WIN7);
323
324 // Create/update the shortcut in the web app path for the "Pin To Taskbar"
325 // option in Win7. We use the web app path shortcut because we will overwrite
326 // it rather than appending unique numbers if the shortcut already exists.
327 // This prevents pinned apps from having unique numbers in their names.
328 if (pin_to_taskbar)
329 shortcut_paths.push_back(web_app_path);
330
331 if (shortcut_paths.empty())
332 return false;
333
334 if (!CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths))
335 return false;
336
337 if (pin_to_taskbar) {
338 base::FilePath file_name =
339 web_app::internals::GetSanitizedFileName(shortcut_info.title);
340 // Use the web app path shortcut for pinning to avoid having unique numbers
341 // in the application name.
342 base::FilePath shortcut_to_pin = web_app_path.Append(file_name).
343 AddExtension(installer::kLnkExt);
344 if (!base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str()))
345 return false;
346 }
347
348 return true;
349 }
350
272 void UpdatePlatformShortcuts( 351 void UpdatePlatformShortcuts(
273 const base::FilePath& web_app_path, 352 const base::FilePath& web_app_path,
353 const string16& old_app_title,
274 const ShellIntegration::ShortcutInfo& shortcut_info) { 354 const ShellIntegration::ShortcutInfo& shortcut_info) {
275 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 355 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
276 356
277 // Generates file name to use with persisted ico and shortcut file. 357 // Generates file name to use with persisted ico and shortcut file.
278 base::FilePath file_name = 358 base::FilePath file_name =
279 web_app::internals::GetSanitizedFileName(shortcut_info.title); 359 web_app::internals::GetSanitizedFileName(shortcut_info.title);
280 360
361 if (old_app_title != shortcut_info.title) {
362 // The app's title has changed. Delete all existing app shortcuts and
363 // recreate them in any locations they already existed (but do not add them
364 // to locations where they do not currently exist).
365 bool was_pinned_to_taskbar;
366 std::vector<base::FilePath> shortcut_paths;
367 GetShortcutLocationsAndDeleteShortcuts(
368 web_app_path, shortcut_info.profile_path, old_app_title,
369 &was_pinned_to_taskbar, &shortcut_paths);
370 CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths);
371 // If the shortcut was pinned to the taskbar,
372 // GetShortcutLocationsAndDeleteShortcuts will have deleted it. In that
373 // case, re-pin it.
374 if (was_pinned_to_taskbar) {
375 base::FilePath file_name =
376 web_app::internals::GetSanitizedFileName(shortcut_info.title);
377 // Use the web app path shortcut for pinning to avoid having unique
378 // numbers in the application name.
379 base::FilePath shortcut_to_pin = web_app_path.Append(file_name).
380 AddExtension(installer::kLnkExt);
381 base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str());
382 }
383 }
384
281 // If an icon file exists, and is out of date, replace it with the new icon 385 // 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. 386 // and let the shell know the icon has been modified.
283 base::FilePath icon_file = web_app_path.Append(file_name).AddExtension( 387 base::FilePath icon_file = web_app_path.Append(file_name).AddExtension(
284 FILE_PATH_LITERAL(".ico")); 388 FILE_PATH_LITERAL(".ico"));
285 if (file_util::PathExists(icon_file)) { 389 if (file_util::PathExists(icon_file)) {
286 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon); 390 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon);
287 } 391 }
288 } 392 }
289 393
290 void DeletePlatformShortcuts( 394 void DeletePlatformShortcuts(
291 const base::FilePath& web_app_path, 395 const base::FilePath& web_app_path,
292 const ShellIntegration::ShortcutInfo& shortcut_info) { 396 const ShellIntegration::ShortcutInfo& shortcut_info) {
293 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 397 GetShortcutLocationsAndDeleteShortcuts(
294 398 web_app_path, shortcut_info.profile_path, shortcut_info.title, NULL,
295 // Get all possible locations for shortcuts. 399 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 400
324 // If there are no more shortcuts in the Chrome Apps subdirectory, remove it. 401 // If there are no more shortcuts in the Chrome Apps subdirectory, remove it.
325 base::FilePath chrome_apps_dir; 402 base::FilePath chrome_apps_dir;
326 if (PathService::Get(base::DIR_START_MENU, &chrome_apps_dir)) { 403 if (PathService::Get(base::DIR_START_MENU, &chrome_apps_dir)) {
327 chrome_apps_dir = chrome_apps_dir.Append(start_menu_subdir); 404 chrome_apps_dir = chrome_apps_dir.Append(GetAppShortcutsSubdirName());
328 if (file_util::IsDirectoryEmpty(chrome_apps_dir)) 405 if (file_util::IsDirectoryEmpty(chrome_apps_dir))
329 file_util::Delete(chrome_apps_dir, false); 406 file_util::Delete(chrome_apps_dir, false);
330 } 407 }
331 } 408 }
332 409
333 std::vector<base::FilePath> GetShortcutPaths( 410 std::vector<base::FilePath> GetShortcutPaths(
334 const ShellIntegration::ShortcutLocations& creation_locations) { 411 const ShellIntegration::ShortcutLocations& creation_locations) {
335 // Shortcut paths under which to create shortcuts. 412 // Shortcut paths under which to create shortcuts.
336 std::vector<base::FilePath> shortcut_paths; 413 std::vector<base::FilePath> shortcut_paths;
337 // Locations to add to shortcut_paths. 414 // Locations to add to shortcut_paths.
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 path = path.Append(locations[i].subdir); 453 path = path.Append(locations[i].subdir);
377 shortcut_paths.push_back(path); 454 shortcut_paths.push_back(path);
378 } 455 }
379 } 456 }
380 return shortcut_paths; 457 return shortcut_paths;
381 } 458 }
382 459
383 } // namespace internals 460 } // namespace internals
384 461
385 } // namespace web_app 462 } // namespace web_app
OLDNEW
« no previous file with comments | « chrome/browser/web_applications/web_app_mac.mm ('k') | chrome/common/extensions/extension.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698