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

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

Issue 8785006: Badge Windows profile shortcuts with multi-user avatar. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Added a missing NULL check to icon_util. Created 9 years 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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_win.h" 5 #include "chrome/browser/profiles/profile_shortcut_manager_win.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/path_service.h" 10 #include "base/path_service.h"
11 #include "base/stringprintf.h" 11 #include "base/stringprintf.h"
12 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/app_icon_win.h"
13 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/prefs/pref_service.h" 15 #include "chrome/browser/prefs/pref_service.h"
15 #include "chrome/browser/profiles/profile_info_cache.h" 16 #include "chrome/browser/profiles/profile_info_cache.h"
17 #include "chrome/browser/profiles/profile_info_util.h"
16 #include "chrome/browser/profiles/profile_manager.h" 18 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/common/chrome_constants.h" 19 #include "chrome/common/chrome_constants.h"
18 #include "chrome/common/chrome_switches.h" 20 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/pref_names.h" 21 #include "chrome/common/pref_names.h"
20 #include "chrome/installer/util/browser_distribution.h" 22 #include "chrome/installer/util/browser_distribution.h"
21 #include "chrome/installer/util/shell_util.h" 23 #include "chrome/installer/util/shell_util.h"
22 #include "content/public/browser/browser_thread.h" 24 #include "content/public/browser/browser_thread.h"
23 #include "grit/generated_resources.h" 25 #include "grit/generated_resources.h"
26 #include "skia/ext/image_operations.h"
27 #include "skia/ext/platform_canvas.h"
24 #include "ui/base/l10n/l10n_util.h" 28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/gfx/icon_util.h"
30 #include "ui/gfx/image/image.h"
25 31
26 using content::BrowserThread; 32 using content::BrowserThread;
27 33
28 namespace { 34 namespace {
29 35
36 const char kProfileIconFileName[] = "Google Profile.ico";
37 const int kProfileAvatarShortcutBadgeWidth = 28;
38 const int kProfileAvatarShortcutBadgeHeight = 28;
39 const int kShortcutIconSize = 48;
40
30 // Creates the argument to pass to the Windows executable that launches Chrome 41 // Creates the argument to pass to the Windows executable that launches Chrome
31 // with the profile in |profile_base_dir|. 42 // with the profile in |profile_base_dir|.
32 // For example: --profile-directory="Profile 2" 43 // For example: --profile-directory="Profile 2"
33 string16 CreateProfileShortcutSwitch(string16 profile_base_dir) { 44 string16 CreateProfileShortcutSwitch(string16 profile_base_dir) {
34 string16 profile_directory = base::StringPrintf(L"--%ls=\"%ls\"", 45 string16 profile_directory = base::StringPrintf(L"--%ls=\"%ls\"",
35 ASCIIToUTF16(switches::kProfileDirectory).c_str(), 46 ASCIIToUTF16(switches::kProfileDirectory).c_str(),
36 profile_base_dir.c_str()); 47 profile_base_dir.c_str());
37 return profile_directory; 48 return profile_directory;
38 } 49 }
39 50
40 // Wrap a ShellUtil function that returns a bool so it can be posted in a 51 // Wrap a ShellUtil function that returns a bool so it can be posted in a
41 // task to the FILE thread. 52 // task to the FILE thread.
42 void CallShellUtilBoolFunction( 53 void CallShellUtilBoolFunction(
43 const base::Callback<bool(void)>& bool_function) { 54 const base::Callback<bool(void)>& bool_function) {
44 bool_function.Run(); 55 bool_function.Run();
45 } 56 }
46 57
58 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile,
59 // badging the browser distribution icon with the profile avatar.
60 // |profile_base_dir| is the base directory (and key) of the profile. Returns
61 // a path to the shortcut icon file on disk, which is empty if this fails.
62 // Use index 0 when assigning the resulting file as the icon.
63 FilePath CreateChromeDesktopShortcutIconForProfile(
64 const FilePath& profile_path,
65 const gfx::Image* avatar_image) {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
67 if (!avatar_image)
68 return FilePath();
69 const SkBitmap* avatar_bitmap = avatar_image->ToSkBitmap();
70 DCHECK(avatar_bitmap);
71 HICON app_icon_handle = GetAppIconForSize(kShortcutIconSize);
72 scoped_ptr<SkBitmap> app_icon_bitmap(
73 IconUtil::CreateSkBitmapFromHICON(app_icon_handle));
74 DestroyIcon(app_icon_handle);
75 if (!app_icon_bitmap.get())
76 return FilePath();
77
78 // TODO(stevet): Share this chunk of code with
79 // avatar_menu_button::DrawTaskBarDecoration.
80 const SkBitmap* source_bitmap = NULL;
81 SkBitmap squarer_bitmap;
82 if ((avatar_bitmap->width() == profiles::kAvatarIconWidth) &&
83 (avatar_bitmap->height() == profiles::kAvatarIconHeight)) {
84 // Shave a couple of columns so the bitmap is more square. So when
85 // resized to a square aspect ratio it looks pretty.
86 int x = 2;
87 avatar_bitmap->extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0,
88 profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight));
89 source_bitmap = &squarer_bitmap;
90 } else {
91 source_bitmap = avatar_bitmap;
92 }
93 SkBitmap sk_icon = skia::ImageOperations::Resize(
94 *source_bitmap,
95 skia::ImageOperations::RESIZE_LANCZOS3,
96 kProfileAvatarShortcutBadgeWidth,
97 kProfileAvatarShortcutBadgeHeight);
98
99 // Overlay the avatar on the icon, anchoring it to the bottom-right of the
100 // icon.
101 scoped_ptr<SkCanvas> offscreen_canvas(
102 skia::CreateBitmapCanvas(app_icon_bitmap->width(),
103 app_icon_bitmap->height(),
104 false));
105 DCHECK(offscreen_canvas.get());
106 offscreen_canvas->drawBitmap(*app_icon_bitmap, 0, 0);
107 offscreen_canvas->drawBitmap(
108 sk_icon,
109 app_icon_bitmap->width() - kProfileAvatarShortcutBadgeWidth,
110 app_icon_bitmap->height() - kProfileAvatarShortcutBadgeHeight);
111 const SkBitmap& final_bitmap =
112 offscreen_canvas->getDevice()->accessBitmap(false);
113
114 // Finally, write the .ico file containing this new bitmap.
115 FilePath icon_path = profile_path.AppendASCII(kProfileIconFileName);
116 if (!IconUtil::CreateIconFileFromSkBitmap(final_bitmap, icon_path))
117 return FilePath();
118
119 return icon_path;
120 }
121
122 // Creates a desktop shortcut to open Chrome with the given profile name and
123 // base directory. Iff |create|, create shortcut if it doesn't already exist.
124 // Must be called on the FILE thread. This method retains ownership of
grt (UTC plus 2) 2011/12/05 14:48:27 update comment
SteveT 2011/12/05 15:24:46 Done.
125 // |avatar_image| and will delete it when it is done with it.
126 void CreateChromeDesktopShortcutForProfile(
127 const string16& profile_name,
128 const string16& profile_base_dir,
129 const FilePath& profile_path,
130 const gfx::Image* avatar_image,
131 bool create) {
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
133 FilePath chrome_exe;
134 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
135 return;
136 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
137 string16 description;
138 if (!dist)
139 return;
140 else
141 description = WideToUTF16(dist->GetAppDescription());
142 const string16& directory = CreateProfileShortcutSwitch(profile_base_dir);
143 FilePath icon_path =
144 CreateChromeDesktopShortcutIconForProfile(profile_path, avatar_image);
145
146 ShellUtil::CreateChromeDesktopShortcut(
147 dist,
148 chrome_exe.value(),
149 description,
150 profile_name,
151 directory,
152 icon_path.empty() ? chrome_exe.value() : icon_path.value(),
153 icon_path.empty() ? dist->GetIconIndex() : 0,
154 ShellUtil::CURRENT_USER,
155 false, // Use alternate text.
156 create); // Create if it doesn't already exist.
157
grt (UTC plus 2) 2011/12/05 14:48:27 end function here
SteveT 2011/12/05 15:24:46 Done.
158 // We have ownership of avatar_image, so clean it up here.
159 if (avatar_image) {
160 delete avatar_image;
161 avatar_image = NULL;
162 }
163 }
164
165 // Renames an existing Chrome desktop profile shortcut. Must be called on the
166 // FILE thread.
167 void RenameChromeDesktopShortcutForProfile(
168 const string16& old_shortcut,
169 const string16& new_shortcut) {
170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
171 FilePath shortcut_path;
172 if (ShellUtil::GetDesktopPath(false, // User's directory instead of system.
173 &shortcut_path)) {
174 FilePath old_profile = shortcut_path.Append(old_shortcut);
175 FilePath new_profile = shortcut_path.Append(new_shortcut);
176 file_util::Move(old_profile, new_profile);
177 }
178 }
179
180 // Updates the arguments to a Chrome desktop shortcut for a profile. Must be
181 // called on the FILE thread. This method retains ownership of |avatar_image|
grt (UTC plus 2) 2011/12/05 14:48:27 update comment
SteveT 2011/12/05 15:24:46 Done.
182 // and will delete it when it is done with it.
183 void UpdateChromeDesktopShortcutForProfile(
184 const string16& shortcut,
185 const string16& arguments,
186 const FilePath& profile_path,
187 const gfx::Image* avatar_image) {
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
189 FilePath shortcut_path;
190 if (!ShellUtil::GetDesktopPath(false, &shortcut_path))
191 return;
192
193 shortcut_path = shortcut_path.Append(shortcut);
194 FilePath chrome_exe;
195 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
196 return;
197 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
198 string16 description;
199 if (!dist)
200 return;
201 else
202 description = WideToUTF16(dist->GetAppDescription());
203 FilePath icon_path =
204 CreateChromeDesktopShortcutIconForProfile(profile_path, avatar_image);
205
206 ShellUtil::UpdateChromeShortcut(
207 dist,
208 chrome_exe.value(),
209 shortcut_path.value(),
210 arguments,
211 description,
212 icon_path.empty() ? chrome_exe.value() : icon_path.value(),
213 icon_path.empty() ? dist->GetIconIndex() : 0,
214 false);
215
grt (UTC plus 2) 2011/12/05 14:48:27 end the function here
SteveT 2011/12/05 15:24:46 Done.
216 // We have ownership of avatar_image, so clean it up here.
217 if (avatar_image) {
218 delete avatar_image;
219 avatar_image = NULL;
220 }
221 }
222
47 } // namespace 223 } // namespace
48 224
49 ProfileShortcutManagerWin::ProfileShortcutManagerWin() { 225 ProfileShortcutManagerWin::ProfileShortcutManagerWin() {
50 } 226 }
51 227
52 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { 228 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() {
53 } 229 }
54 230
55 void ProfileShortcutManagerWin::OnProfileAdded( 231 void ProfileShortcutManagerWin::OnProfileAdded(
56 const string16& profile_name, 232 const string16& profile_name,
57 const string16& profile_base_dir) { 233 const string16& profile_base_dir,
234 const FilePath& profile_path,
235 const gfx::Image* avatar_image) {
58 // Launch task to add shortcut to desktop on Windows. If this is the very 236 // Launch task to add shortcut to desktop on Windows. If this is the very
59 // first profile created, don't add the user name to the shortcut. 237 // first profile created, don't add the user name to the shortcut.
60 // TODO(mirandac): respect master_preferences choice to create no shortcuts 238 // TODO(mirandac): respect master_preferences choice to create no shortcuts
61 // (see http://crbug.com/104463) 239 // (see http://crbug.com/104463)
62 if (g_browser_process->profile_manager()->GetNumberOfProfiles() > 1) { 240 if (g_browser_process->profile_manager()->GetNumberOfProfiles() > 1) {
63 string16 profile_directory = 241 // There is no guarantee that avatar_image won't be deleted before it's
64 CreateProfileShortcutSwitch(profile_base_dir); 242 // used, so we'll make a deep copy of it and rely on the user to delete the
65 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 243 // copy.
66 base::Bind(&CreateChromeDesktopShortcutForProfile, 244 {
grt (UTC plus 2) 2011/12/05 14:48:27 use Bind(..., Owned(avatar_copy), ...) and remove
SteveT 2011/12/05 15:24:46 Done.
67 profile_name, profile_directory, true)); 245 gfx::Image* avatar_copy = avatar_image ?
grt (UTC plus 2) 2011/12/05 14:48:27 the current memory model for this image leaves a l
SteveT 2011/12/05 15:24:46 Excellent - thanks for the pointer.
246 new gfx::Image(avatar_image->CopySkBitmap()) : NULL;
247 if (!BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
248 base::Bind(&CreateChromeDesktopShortcutForProfile,
249 profile_name, profile_base_dir, profile_path,
250 avatar_copy, true))) {
251 delete avatar_copy;
252 }
253 }
68 254
69 // If this is the very first multi-user account created, change the 255 // If this is the very first multi-user account created, change the
70 // original shortcut to launch with the First User profile. 256 // original shortcut to launch with the First User profile.
71 PrefService* local_state = g_browser_process->local_state(); 257 PrefService* local_state = g_browser_process->local_state();
72 if (local_state->GetInteger(prefs::kProfilesNumCreated) == 2) { 258 if (local_state->GetInteger(prefs::kProfilesNumCreated) == 2) {
73 string16 default_name = l10n_util::GetStringUTF16( 259 string16 default_name = l10n_util::GetStringUTF16(
74 IDS_DEFAULT_PROFILE_NAME); 260 IDS_DEFAULT_PROFILE_NAME);
75 string16 default_directory =
76 CreateProfileShortcutSwitch(UTF8ToUTF16(chrome::kInitialProfile));
77 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 261 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
78 262
79 string16 old_shortcut; 263 string16 old_shortcut;
80 string16 new_shortcut; 264 string16 new_shortcut;
81 if (ShellUtil::GetChromeShortcutName(dist, false, L"", &old_shortcut) && 265 if (ShellUtil::GetChromeShortcutName(dist, false, L"", &old_shortcut) &&
82 ShellUtil::GetChromeShortcutName(dist, false, default_name, 266 ShellUtil::GetChromeShortcutName(dist, false, default_name,
83 &new_shortcut)) { 267 &new_shortcut)) {
84 // Update doesn't allow changing the target, so rename first. 268 // Update doesn't allow changing the target, so rename first.
85 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 269 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
86 base::Bind(&RenameChromeDesktopShortcutForProfile, 270 base::Bind(&RenameChromeDesktopShortcutForProfile,
87 old_shortcut, new_shortcut)); 271 old_shortcut, new_shortcut));
272 // TODO(stevet): We actually need to retrieve the newly assigned avatar
273 // icon for the original profile here and update it with that.
88 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 274 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
89 base::Bind(&UpdateChromeDesktopShortcutForProfile, 275 base::Bind(&UpdateChromeDesktopShortcutForProfile,
90 new_shortcut, default_directory)); 276 new_shortcut, UTF8ToUTF16(chrome::kInitialProfile),
277 profile_path, static_cast<gfx::Image*>(NULL)));
91 } 278 }
92 } 279 }
93 } else { // Only one profile, so create original shortcut. 280 } else { // Only one profile, so create original shortcut, with no avatar.
94 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 281 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
95 base::Bind(&CreateChromeDesktopShortcutForProfile, 282 base::Bind(&CreateChromeDesktopShortcutForProfile,
96 L"", L"", true)); 283 L"", L"", FilePath(), static_cast<gfx::Image*>(NULL), true));
97 } 284 }
98 } 285 }
99 286
100 void ProfileShortcutManagerWin::OnProfileRemoved( 287 void ProfileShortcutManagerWin::OnProfileRemoved(
101 const string16& profile_name) { 288 const string16& profile_name) {
102 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 289 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
103 string16 shortcut; 290 string16 shortcut;
104 if (ShellUtil::GetChromeShortcutName(dist, false, profile_name, &shortcut)) { 291 if (ShellUtil::GetChromeShortcutName(dist, false, profile_name, &shortcut)) {
105 std::vector<string16> shortcuts(1, shortcut); 292 std::vector<string16> shortcuts(1, shortcut);
106 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 293 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
(...skipping 17 matching lines...) Expand all
124 dist, false, old_profile_name, &old_shortcut) && 311 dist, false, old_profile_name, &old_shortcut) &&
125 ShellUtil::GetChromeShortcutName( 312 ShellUtil::GetChromeShortcutName(
126 dist, false, new_profile_name, &new_shortcut)) { 313 dist, false, new_profile_name, &new_shortcut)) {
127 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 314 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
128 base::Bind(&RenameChromeDesktopShortcutForProfile, 315 base::Bind(&RenameChromeDesktopShortcutForProfile,
129 old_shortcut, 316 old_shortcut,
130 new_shortcut)); 317 new_shortcut));
131 } 318 }
132 } 319 }
133 320
321 void ProfileShortcutManagerWin::OnProfileAvatarChanged(
322 const string16& profile_name,
323 const string16& profile_base_dir,
324 const FilePath& profile_path,
325 const gfx::Image* avatar_image) {
326 // Launch task to change the icon of the desktop shortcut on windows.
327 string16 new_shortcut;
328 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
329 if (ShellUtil::GetChromeShortcutName(dist, false, profile_name,
330 &new_shortcut)) {
331 // There is no guarantee that avatar_image won't be deleted before it's
332 // used, so we'll make a deep copy of it and rely on the user to delete the
333 // copy.
334 gfx::Image* avatar_copy = avatar_image ?
335 new gfx::Image(avatar_image->CopySkBitmap()) : NULL;
336 if (!BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
337 base::Bind(&UpdateChromeDesktopShortcutForProfile,
grt (UTC plus 2) 2011/12/05 14:48:27 same comment here: use Owned(avatar_copy) and remo
SteveT 2011/12/05 15:24:46 Done.
338 new_shortcut,
339 CreateProfileShortcutSwitch(profile_base_dir),
340 profile_path,
341 avatar_copy))) {
342 delete avatar_copy;
343 }
344 }
345 }
346
134 // static 347 // static
135 std::vector<string16> ProfileShortcutManagerWin::GenerateShortcutsFromProfiles( 348 std::vector<string16> ProfileShortcutManagerWin::GenerateShortcutsFromProfiles(
136 const std::vector<string16>& profile_names) { 349 const std::vector<string16>& profile_names) {
137 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 350 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
138 std::vector<string16> shortcuts; 351 std::vector<string16> shortcuts;
139 shortcuts.reserve(profile_names.size()); 352 shortcuts.reserve(profile_names.size());
140 for (std::vector<string16>::const_iterator it = profile_names.begin(); 353 for (std::vector<string16>::const_iterator it = profile_names.begin();
141 it != profile_names.end(); 354 it != profile_names.end();
142 ++it) { 355 ++it) {
143 string16 shortcut; 356 string16 shortcut;
144 if (ShellUtil::GetChromeShortcutName(dist, false, *it, &shortcut)) 357 if (ShellUtil::GetChromeShortcutName(dist, false, *it, &shortcut))
145 shortcuts.push_back(shortcut); 358 shortcuts.push_back(shortcut);
146 } 359 }
147 return shortcuts; 360 return shortcuts;
148 } 361 }
149
150 // static
151 void ProfileShortcutManagerWin::CreateChromeDesktopShortcutForProfile(
152 const string16& profile_name,
153 const string16& directory,
154 bool create) {
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
156 FilePath chrome_exe;
157 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
158 return;
159 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
160 string16 description;
161 if (!dist)
162 return;
163 else
164 description = WideToUTF16(dist->GetAppDescription());
165 ShellUtil::CreateChromeDesktopShortcut(
166 dist,
167 chrome_exe.value(),
168 description,
169 profile_name,
170 directory,
171 ShellUtil::CURRENT_USER,
172 false, // Use alternate text.
173 create); // Create if it doesn't already exist.
174 }
175
176 // static
177 void ProfileShortcutManagerWin::RenameChromeDesktopShortcutForProfile(
178 const string16& old_shortcut,
179 const string16& new_shortcut) {
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
181 FilePath shortcut_path;
182 if (ShellUtil::GetDesktopPath(false, // User's directory instead of system.
183 &shortcut_path)) {
184 FilePath old_profile = shortcut_path.Append(old_shortcut);
185 FilePath new_profile = shortcut_path.Append(new_shortcut);
186 file_util::Move(old_profile, new_profile);
187 }
188 }
189
190 // static
191 void ProfileShortcutManagerWin::UpdateChromeDesktopShortcutForProfile(
192 const string16& shortcut,
193 const string16& arguments) {
194 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
195 FilePath shortcut_path;
196 if (!ShellUtil::GetDesktopPath(false, &shortcut_path))
197 return;
198
199 shortcut_path = shortcut_path.Append(shortcut);
200 FilePath chrome_exe;
201 if (!PathService::Get(base::FILE_EXE, &chrome_exe))
202 return;
203 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
204 string16 description;
205 if (!dist)
206 return;
207 else
208 description = WideToUTF16(dist->GetAppDescription());
209 ShellUtil::UpdateChromeShortcut(
210 dist,
211 chrome_exe.value(),
212 shortcut_path.value(),
213 arguments,
214 description,
215 false);
216 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698