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

Side by Side Diff: chrome/browser/profiles/profile_shortcut_manager_win.cc

Issue 10837352: Update profile desktop shortcuts (Closed) Base URL: https://src.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 4 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
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/profiles/profile_shortcut_manager.h" 5 #include "chrome/browser/profiles/profile_shortcut_manager.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "base/path_service.h" 12 #include "base/path_service.h"
13 #include "base/stringprintf.h" 13 #include "base/stringprintf.h"
14 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
15 #include "chrome/browser/app_icon_win.h" 15 #include "chrome/browser/app_icon_win.h"
16 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/prefs/pref_service.h" 17 #include "chrome/browser/prefs/pref_service.h"
18 #include "chrome/browser/profiles/profile_info_cache.h" 18 #include "chrome/browser/profiles/profile_info_cache_observer.h"
19 #include "chrome/browser/profiles/profile_info_util.h" 19 #include "chrome/browser/profiles/profile_info_util.h"
20 #include "chrome/browser/profiles/profile_manager.h" 20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/common/chrome_constants.h" 21 #include "chrome/common/chrome_constants.h"
22 #include "chrome/common/chrome_switches.h" 22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/pref_names.h" 23 #include "chrome/common/pref_names.h"
24 #include "chrome/installer/util/auto_launch_util.h" 24 #include "chrome/installer/util/auto_launch_util.h"
25 #include "chrome/installer/util/browser_distribution.h" 25 #include "chrome/installer/util/browser_distribution.h"
26 #include "chrome/installer/util/shell_util.h" 26 #include "chrome/installer/util/shell_util.h"
27 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
28 #include "grit/generated_resources.h" 28 #include "grit/generated_resources.h"
(...skipping 12 matching lines...) Expand all
41 const int kProfileAvatarShortcutBadgeHeight = 28; 41 const int kProfileAvatarShortcutBadgeHeight = 28;
42 const int kShortcutIconSize = 48; 42 const int kShortcutIconSize = 48;
43 43
44 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile, 44 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile,
45 // badging the browser distribution icon with the profile avatar. 45 // badging the browser distribution icon with the profile avatar.
46 // |profile_base_dir| is the base directory (and key) of the profile. Returns 46 // |profile_base_dir| is the base directory (and key) of the profile. Returns
47 // a path to the shortcut icon file on disk, which is empty if this fails. 47 // a path to the shortcut icon file on disk, which is empty if this fails.
48 // Use index 0 when assigning the resulting file as the icon. 48 // Use index 0 when assigning the resulting file as the icon.
49 FilePath CreateChromeDesktopShortcutIconForProfile( 49 FilePath CreateChromeDesktopShortcutIconForProfile(
50 const FilePath& profile_path, 50 const FilePath& profile_path,
51 const gfx::Image& avatar_image) { 51 const SkBitmap& avatar_bitmap) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
53 const SkBitmap* avatar_bitmap = avatar_image.ToSkBitmap();
54 HICON app_icon_handle = GetAppIconForSize(kShortcutIconSize); 53 HICON app_icon_handle = GetAppIconForSize(kShortcutIconSize);
55 scoped_ptr<SkBitmap> app_icon_bitmap( 54 scoped_ptr<SkBitmap> app_icon_bitmap(
56 IconUtil::CreateSkBitmapFromHICON(app_icon_handle)); 55 IconUtil::CreateSkBitmapFromHICON(app_icon_handle));
57 DestroyIcon(app_icon_handle); 56 DestroyIcon(app_icon_handle);
58 if (!app_icon_bitmap.get()) 57 if (!app_icon_bitmap.get())
59 return FilePath(); 58 return FilePath();
60 59
61 // TODO(hallielaine): Share this chunk of code with 60 // TODO(hallielaine): Share this chunk of code with
62 // avatar_menu_button::DrawTaskBarDecoration. 61 // avatar_menu_button::DrawTaskBarDecoration.
63 const SkBitmap* source_bitmap = NULL; 62 const SkBitmap* source_bitmap = NULL;
64 SkBitmap squarer_bitmap; 63 SkBitmap squarer_bitmap;
65 if ((avatar_bitmap->width() == profiles::kAvatarIconWidth) && 64 if ((avatar_bitmap.width() == profiles::kAvatarIconWidth) &&
66 (avatar_bitmap->height() == profiles::kAvatarIconHeight)) { 65 (avatar_bitmap.height() == profiles::kAvatarIconHeight)) {
67 // Shave a couple of columns so the bitmap is more square. So when 66 // Shave a couple of columns so the bitmap is more square. So when
68 // resized to a square aspect ratio it looks pretty. 67 // resized to a square aspect ratio it looks pretty.
69 int x = 2; 68 int x = 2;
70 avatar_bitmap->extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0, 69 avatar_bitmap.extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0,
71 profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight)); 70 profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight));
72 source_bitmap = &squarer_bitmap; 71 source_bitmap = &squarer_bitmap;
73 } else { 72 } else {
74 source_bitmap = avatar_bitmap; 73 source_bitmap = &avatar_bitmap;
75 } 74 }
76 SkBitmap sk_icon = skia::ImageOperations::Resize( 75 SkBitmap sk_icon = skia::ImageOperations::Resize(
77 *source_bitmap, 76 *source_bitmap,
78 skia::ImageOperations::RESIZE_LANCZOS3, 77 skia::ImageOperations::RESIZE_LANCZOS3,
79 kProfileAvatarShortcutBadgeWidth, 78 kProfileAvatarShortcutBadgeWidth,
80 kProfileAvatarShortcutBadgeHeight); 79 kProfileAvatarShortcutBadgeHeight);
81 80
82 // Overlay the avatar on the icon, anchoring it to the bottom-right of the 81 // Overlay the avatar on the icon, anchoring it to the bottom-right of the
83 // icon. 82 // icon.
84 scoped_ptr<SkCanvas> offscreen_canvas( 83 scoped_ptr<SkCanvas> offscreen_canvas(
(...skipping 16 matching lines...) Expand all
101 100
102 return icon_path; 101 return icon_path;
103 } 102 }
104 103
105 string16 CreateProfileShortcutFlags(const FilePath& profile_path) { 104 string16 CreateProfileShortcutFlags(const FilePath& profile_path) {
106 return base::StringPrintf(L"--%ls=\"%ls\"", 105 return base::StringPrintf(L"--%ls=\"%ls\"",
107 ASCIIToUTF16(switches::kProfileDirectory).c_str(), 106 ASCIIToUTF16(switches::kProfileDirectory).c_str(),
108 profile_path.BaseName().value().c_str()); 107 profile_path.BaseName().value().c_str());
109 } 108 }
110 109
111 // Wrap a ShellUtil function that returns a bool so it can be posted in a 110 // Wrap a ShellUtil/FileUtil function that returns a bool so it can be posted
112 // task to the FILE thread. 111 // in a task to the FILE thread.
113 void CallShellUtilBoolFunction( 112 void CallBoolFunction(
114 const base::Callback<bool(void)>& bool_function) { 113 const base::Callback<bool(void)>& bool_function) {
115 bool_function.Run(); 114 bool_function.Run();
116 } 115 }
117 116
117 // Renames an existing Chrome desktop profile shortcut. Must be called on the
118 // FILE thread.
119 void RenameChromeDesktopShortcutForProfile(
120 const string16& old_shortcut_file,
121 const string16& new_shortcut_file) {
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
123 FilePath shortcut_path;
124 if (ShellUtil::GetDesktopPath(false, // User's directory instead of system.
125 &shortcut_path)) {
126 FilePath old_shortcut_path = shortcut_path.Append(old_shortcut_file);
127 FilePath new_shortcut_path = shortcut_path.Append(new_shortcut_file);
128 if (!file_util::Move(old_shortcut_path, new_shortcut_path))
129 LOG(ERROR) << "Could not rename Windows profile desktop shortcut.";
130 }
131 }
132
133 // Create or update a profile desktop shortcut. Must be called on the FILE
134 // thread.
135 void CreateOrUpdateProfileDesktopShortcut(
136 const FilePath& profile_path,
137 const string16& profile_name,
138 const SkBitmap& avatar_image,
139 bool create) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
141 FilePath shortcut_icon = CreateChromeDesktopShortcutIconForProfile(
142 profile_path, avatar_image);
143
144 FilePath chrome_exe;
145 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
146 return;
147 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
148 if (!dist)
149 return;
150 string16 description(dist->GetAppDescription());
151
152 uint32 options = create ? ShellUtil::SHORTCUT_CREATE_ALWAYS :
153 ShellUtil::SHORTCUT_NO_OPTIONS;
154 ShellUtil::CreateChromeDesktopShortcut(
155 dist,
156 chrome_exe.value(),
157 description,
158 profile_name,
159 CreateProfileShortcutFlags(profile_path),
160 shortcut_icon.empty() ? chrome_exe.value() : shortcut_icon.value(),
161 shortcut_icon.empty() ? dist->GetIconIndex() : 0,
162 ShellUtil::CURRENT_USER,
163 options);
164 }
165
118 } // namespace 166 } // namespace
119 167
120 class ProfileShortcutManagerWin : public ProfileShortcutManager { 168 class ProfileShortcutManagerWin : public ProfileShortcutManager,
169 public ProfileInfoCacheObserver {
121 public: 170 public:
122 ProfileShortcutManagerWin(); 171 explicit ProfileShortcutManagerWin(ProfileInfoCache& cache);
123 virtual ~ProfileShortcutManagerWin(); 172 virtual ~ProfileShortcutManagerWin();
124 173
125 virtual void CreateChromeDesktopShortcut( 174 virtual void StartProfileDesktopShortcutCreation(
126 const FilePath& profile_path, const string16& profile_name, 175 const FilePath& profile_path, const string16& profile_name,
127 const gfx::Image& avatar_image) OVERRIDE; 176 const gfx::Image& avatar_image) OVERRIDE;
128 virtual void DeleteChromeDesktopShortcut(const FilePath& profile_path) 177 virtual void DeleteProfileDesktopShortcut(const FilePath& profile_path,
129 OVERRIDE; 178 const string16& profile_name) OVERRIDE;
179
180 virtual void OnProfileAdded(const FilePath& profile_path) OVERRIDE;
181 virtual void OnProfileWillBeRemoved(const FilePath& profile_path) OVERRIDE;
182 virtual void OnProfileWasRemoved(const FilePath& profile_path,
183 const string16& profile_name) OVERRIDE;
184 virtual void OnProfileNameChanged(const FilePath& profile_path,
185 const string16& old_profile_name) OVERRIDE;
186 virtual void OnProfileAvatarChanged(const FilePath& profile_path) OVERRIDE;
130 187
131 private: 188 private:
132 struct ProfileShortcutInfo { 189 ProfileInfoCache& profile_info_cache_;
133 string16 flags;
134 string16 profile_name;
135 gfx::Image avatar_image;
136
137 ProfileShortcutInfo()
138 : flags(string16()),
139 profile_name(string16()),
140 avatar_image(gfx::Image()) {
141 }
142
143 ProfileShortcutInfo(
144 string16 p_flags,
145 string16 p_profile_name,
146 gfx::Image p_avatar_image)
147 : flags(p_flags),
148 profile_name(p_profile_name),
149 avatar_image(p_avatar_image) {
150 }
151 };
152
153 // TODO(hallielaine): Repopulate this map on chrome session startup
154 typedef std::map<FilePath, ProfileShortcutInfo> ProfileShortcutsMap;
155 ProfileShortcutsMap profile_shortcuts_;
156 }; 190 };
157 191
158 // static 192 // static
159 bool ProfileShortcutManager::IsFeatureEnabled() { 193 bool ProfileShortcutManager::IsFeatureEnabled() {
160 if (CommandLine::ForCurrentProcess()->HasSwitch( 194 if (CommandLine::ForCurrentProcess()->HasSwitch(
161 switches::kProfileDesktopShortcuts)) { 195 switches::kProfileDesktopShortcuts)) {
162 return true; 196 return true;
163 } 197 }
164 return false; 198 return false;
165 } 199 }
166 200
167 // static 201 // static
168 ProfileShortcutManager* ProfileShortcutManager::Create() { 202 ProfileShortcutManager* ProfileShortcutManager::Create(
169 return new ProfileShortcutManagerWin(); 203 ProfileInfoCache& cache) {
204 return new ProfileShortcutManagerWin(cache);
170 } 205 }
171 206
172 ProfileShortcutManagerWin::ProfileShortcutManagerWin() { 207 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileInfoCache& cache)
208 : profile_info_cache_(cache) {
209 cache.AddObserver(this);
173 } 210 }
174 211
175 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { 212 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() {
213 profile_info_cache_.RemoveObserver(this);
176 } 214 }
177 215
178 void ProfileShortcutManagerWin::CreateChromeDesktopShortcut( 216 void ProfileShortcutManagerWin::StartProfileDesktopShortcutCreation(
179 const FilePath& profile_path, const string16& profile_name, 217 const FilePath& profile_path, const string16& profile_name,
180 const gfx::Image& avatar_image) { 218 const gfx::Image& avatar_image) {
181 FilePath shortcut_icon = CreateChromeDesktopShortcutIconForProfile( 219 DCHECK(!avatar_image.IsEmpty());
182 profile_path, avatar_image); 220 const SkBitmap* avatar_bitmap = avatar_image.ToSkBitmap();
183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
184 FilePath chrome_exe;
185 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
186 return;
187 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
188 string16 description;
189 if (!dist)
190 return;
191 description = WideToUTF16(dist->GetAppDescription());
192 221
193 // Add the profile to the map if it doesn't exist already 222 // Make a copy of the SkBitmap to ensure that we can safely use the image
194 if (!profile_shortcuts_.count(profile_path)) { 223 // data on the FILE thread.
195 string16 flags = CreateProfileShortcutFlags(profile_path); 224 SkBitmap avatar_bitmap_copy;
196 profile_shortcuts_.insert(std::make_pair(profile_path, 225 DCHECK(avatar_bitmap->deepCopyTo(&avatar_bitmap_copy,
197 ProfileShortcutInfo(flags, profile_name, 226 avatar_bitmap->getConfig()));
198 avatar_image))); 227 BrowserThread::PostTask(
199 } 228 BrowserThread::FILE, FROM_HERE,
200 229 base::Bind(&CreateOrUpdateProfileDesktopShortcut,
201 ShellUtil::CreateChromeDesktopShortcut( 230 profile_path, profile_name, avatar_bitmap_copy, true));
202 dist,
203 chrome_exe.value(),
204 description,
205 profile_shortcuts_[profile_path].profile_name,
206 profile_shortcuts_[profile_path].flags,
207 shortcut_icon.empty() ? chrome_exe.value() : shortcut_icon.value(),
208 shortcut_icon.empty() ? dist->GetIconIndex() : 0,
209 ShellUtil::CURRENT_USER,
210 ShellUtil::SHORTCUT_CREATE_ALWAYS);
211 } 231 }
212 232
213 void ProfileShortcutManagerWin::DeleteChromeDesktopShortcut( 233 void ProfileShortcutManagerWin::DeleteProfileDesktopShortcut(
214 const FilePath& profile_path) { 234 const FilePath& profile_path, const string16& profile_name) {
215 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 235 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
216 string16 shortcut; 236 string16 shortcut;
217 // If we can find the shortcut, delete it 237 // If we can find the shortcut, delete it
218 if (ShellUtil::GetChromeShortcutName(dist, false, 238 if (ShellUtil::GetChromeShortcutName(dist, false,
219 profile_shortcuts_[profile_path].profile_name, &shortcut)) { 239 profile_name, &shortcut)) {
220 std::vector<string16> appended_names(1, shortcut); 240 std::vector<string16> appended_names(1, shortcut);
221 BrowserThread::PostTask( 241 BrowserThread::PostTask(
222 BrowserThread::FILE, FROM_HERE, 242 BrowserThread::FILE, FROM_HERE,
223 base::Bind(&CallShellUtilBoolFunction, base::Bind( 243 base::Bind(&CallBoolFunction, base::Bind(
224 &ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames, 244 &ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames,
225 appended_names))); 245 appended_names)));
226 profile_shortcuts_.erase(profile_path); 246 }
247 FilePath icon_path = profile_path.AppendASCII(kProfileIconFileName);
248 BrowserThread::PostTask(
249 BrowserThread::FILE, FROM_HERE,
250 base::Bind(&CallBoolFunction, base::Bind(
251 &file_util::Delete, icon_path, false)));
252 }
253
254 void ProfileShortcutManagerWin::OnProfileAdded(const FilePath& profile_path) {
255 }
256
257 void ProfileShortcutManagerWin::OnProfileWillBeRemoved(
258 const FilePath& profile_path) {
259 }
260
261 void ProfileShortcutManagerWin::OnProfileWasRemoved(
262 const FilePath& profile_path,
263 const string16& profile_name) {
264 }
265
266 void ProfileShortcutManagerWin::OnProfileNameChanged(
267 const FilePath& profile_path,
268 const string16& old_profile_name) {
269 size_t profile_index = profile_info_cache_.GetIndexOfProfileWithPath(
270 profile_path);
271 if (profile_index == std::string::npos)
272 return;
273
274 string16 new_profile_name =
275 profile_info_cache_.GetNameOfProfileAtIndex(profile_index);
276
277 string16 old_shortcut_file;
278 string16 new_shortcut_file;
279 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
280 if (ShellUtil::GetChromeShortcutName(
281 dist, false, old_profile_name, &old_shortcut_file) &&
282 ShellUtil::GetChromeShortcutName(
283 dist, false, new_profile_name, &new_shortcut_file)) {
284 BrowserThread::PostTask(
285 BrowserThread::FILE, FROM_HERE,
286 base::Bind(&RenameChromeDesktopShortcutForProfile,
287 old_shortcut_file,
288 new_shortcut_file));
227 } 289 }
228 } 290 }
229 291
292 void ProfileShortcutManagerWin::OnProfileAvatarChanged(
293 const FilePath& profile_path) {
294 size_t profile_index = profile_info_cache_.GetIndexOfProfileWithPath(
295 profile_path);
296 if (profile_index == std::string::npos)
297 return;
298
299 string16 profile_name =
300 profile_info_cache_.GetNameOfProfileAtIndex(profile_index);
301 string16 shortcut;
302
303 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
304 if (ShellUtil::GetChromeShortcutName(
305 dist, false, profile_name, &shortcut)) {
306 size_t new_icon_index = profile_info_cache_.
307 GetAvatarIconIndexOfProfileAtIndex(profile_index);
308 gfx::Image avatar_image =
309 ResourceBundle::GetSharedInstance().GetNativeImageNamed(
310 profile_info_cache_.GetDefaultAvatarIconResourceIDAtIndex(
311 new_icon_index));
312
313 DCHECK(!avatar_image.IsEmpty());
314 const SkBitmap* avatar_bitmap = avatar_image.ToSkBitmap();
315
316 // Make a copy of the SkBitmap to ensure that we can safely use the image
317 // data on the FILE thread.
318 SkBitmap avatar_bitmap_copy;
319 DCHECK(avatar_bitmap->deepCopyTo(&avatar_bitmap_copy,
320 avatar_bitmap->getConfig()));
321 BrowserThread::PostTask(
322 BrowserThread::FILE, FROM_HERE,
323 base::Bind(&CreateOrUpdateProfileDesktopShortcut,
324 profile_path, profile_name, avatar_bitmap_copy, false));
325 }
326 }
327
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698