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 // Deletes all shortcuts for an app, recording the paths they were found at. | |
224 // This will search for shortcuts named |title|. | |
225 // Note that |title| does not necessarily have to be the title found in | |
226 // |shortcut_info| (for example, when an app's title changes, |title| is set to | |
227 // the old title so we can clean up old shortcuts before creating new ones). | |
228 // |was_pinned_to_taskbar| will be set to true if there was previously a | |
229 // shortcut pinned to the taskbar for this app; false otherwise. | |
230 // |shortcut_paths| will be populated with a list of directories where shortcuts | |
231 // for this app were found (and deleted). Both of these may be NULL. | |
232 void DeleteAndRememberShortcuts( | |
233 const base::FilePath& web_app_path, | |
234 const ShellIntegration::ShortcutInfo& shortcut_info, | |
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( | |
261 taskbar_pin_path, shortcut_info.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, shortcut_info.profile_path, | |
272 title); | |
Sam McNally
2013/05/27 06:24:08
Indentation.
Matt Giuca
2013/05/28 00:41:15
Done.
| |
273 if (shortcut_paths && !shortcut_files.empty()) { | |
274 shortcut_paths->push_back(*i); | |
275 } | |
276 for (std::vector<base::FilePath>::const_iterator j = shortcut_files.begin(); | |
277 j != shortcut_files.end(); ++j) { | |
278 // Any shortcut could have been pinned, either by chrome or the user, so | |
279 // they are all unpinned. | |
280 base::win::TaskbarUnpinShortcutLink(j->value().c_str()); | |
281 file_util::Delete(*j, false); | |
282 } | |
283 } | |
284 } | |
285 | |
286 } // namespace | |
287 | |
288 namespace web_app { | |
289 | |
290 namespace internals { | |
291 | |
292 // Saves |image| to |icon_file| if the file is outdated and refresh shell's | |
293 // icon cache to ensure correct icon is displayed. Returns true if icon_file | |
294 // is up to date or successfully updated. | |
295 bool CheckAndSaveIcon(const base::FilePath& icon_file, | |
296 const gfx::ImageFamily& image) { | |
297 if (ShouldUpdateIcon(icon_file, image)) { | |
298 if (SaveIconWithCheckSum(icon_file, image)) { | |
299 // Refresh shell's icon cache. This call is quite disruptive as user would | |
300 // see explorer rebuilding the icon cache. It would be great that we find | |
301 // a better way to achieve this. | |
302 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, | |
303 NULL, NULL); | |
304 } else { | |
305 return false; | |
306 } | |
307 } | |
308 | |
309 return true; | |
310 } | |
311 | |
312 bool CreatePlatformShortcuts( | |
313 const base::FilePath& web_app_path, | |
314 const ShellIntegration::ShortcutInfo& shortcut_info, | |
315 const ShellIntegration::ShortcutLocations& creation_locations) { | |
316 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
317 | |
318 // Shortcut paths under which to create shortcuts. | |
319 std::vector<base::FilePath> shortcut_paths = | |
320 GetShortcutPaths(creation_locations); | |
321 | |
322 bool pin_to_taskbar = creation_locations.in_quick_launch_bar && | |
323 (base::win::GetVersion() >= base::win::VERSION_WIN7); | |
324 | |
325 // Create/update the shortcut in the web app path for the "Pin To Taskbar" | |
326 // option in Win7. We use the web app path shortcut because we will overwrite | |
327 // it rather than appending unique numbers if the shortcut already exists. | |
328 // This prevents pinned apps from having unique numbers in their names. | |
329 if (pin_to_taskbar) | |
330 shortcut_paths.push_back(web_app_path); | |
331 | |
332 if (shortcut_paths.empty()) | |
333 return false; | |
334 | |
335 if (!CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths)) | |
336 return false; | |
337 | |
338 if (pin_to_taskbar) { | |
339 base::FilePath file_name = | |
340 web_app::internals::GetSanitizedFileName(shortcut_info.title); | |
341 // Use the web app path shortcut for pinning to avoid having unique numbers | |
342 // in the application name. | |
343 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). | |
344 AddExtension(installer::kLnkExt); | |
345 if (!base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str())) | |
346 return false; | |
347 } | |
348 | |
349 return true; | |
350 } | |
351 | |
272 void UpdatePlatformShortcuts( | 352 void UpdatePlatformShortcuts( |
273 const base::FilePath& web_app_path, | 353 const base::FilePath& web_app_path, |
354 const string16& old_app_title, | |
274 const ShellIntegration::ShortcutInfo& shortcut_info) { | 355 const ShellIntegration::ShortcutInfo& shortcut_info) { |
275 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 356 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
276 | 357 |
277 // Generates file name to use with persisted ico and shortcut file. | 358 // Generates file name to use with persisted ico and shortcut file. |
278 base::FilePath file_name = | 359 base::FilePath file_name = |
279 web_app::internals::GetSanitizedFileName(shortcut_info.title); | 360 web_app::internals::GetSanitizedFileName(shortcut_info.title); |
280 | 361 |
362 if (old_app_title != shortcut_info.title) { | |
363 // The app's title has changed. Delete all existing app shortcuts and | |
364 // recreate them in any locations they already existed (but do not add them | |
365 // to locations where they do not currently exist). | |
366 bool was_pinned_to_taskbar; | |
367 std::vector<base::FilePath> shortcut_paths; | |
368 DeleteAndRememberShortcuts(web_app_path, shortcut_info, 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, DeleteAndRememberShortcuts | |
372 // will have deleted it. In that case, re-pin it. | |
373 if (was_pinned_to_taskbar) { | |
374 base::FilePath file_name = | |
375 web_app::internals::GetSanitizedFileName(shortcut_info.title); | |
376 // Use the web app path shortcut for pinning to avoid having unique | |
377 // numbers in the application name. | |
378 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). | |
379 AddExtension(installer::kLnkExt); | |
380 base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str()); | |
381 } | |
382 } | |
383 | |
281 // If an icon file exists, and is out of date, replace it with the new icon | 384 // 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. | 385 // and let the shell know the icon has been modified. |
283 base::FilePath icon_file = web_app_path.Append(file_name).AddExtension( | 386 base::FilePath icon_file = web_app_path.Append(file_name).AddExtension( |
284 FILE_PATH_LITERAL(".ico")); | 387 FILE_PATH_LITERAL(".ico")); |
285 if (file_util::PathExists(icon_file)) { | 388 if (file_util::PathExists(icon_file)) { |
286 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon); | 389 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon); |
287 } | 390 } |
288 } | 391 } |
289 | 392 |
290 void DeletePlatformShortcuts( | 393 void DeletePlatformShortcuts( |
291 const base::FilePath& web_app_path, | 394 const base::FilePath& web_app_path, |
292 const ShellIntegration::ShortcutInfo& shortcut_info) { | 395 const ShellIntegration::ShortcutInfo& shortcut_info) { |
293 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 396 DeleteAndRememberShortcuts(web_app_path, shortcut_info, shortcut_info.title, |
Sam McNally
2013/05/27 06:24:08
Consider adding a "DeleteShortcuts" overload.
Matt Giuca
2013/05/28 00:41:15
I assume you mean adding a function:
DeleteShortc
| |
294 | 397 NULL, NULL); |
295 // Get all possible locations for shortcuts. | |
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 |