| Index: chrome/browser/profiles/profile_shortcut_manager_win.cc
|
| ===================================================================
|
| --- chrome/browser/profiles/profile_shortcut_manager_win.cc (revision 112717)
|
| +++ chrome/browser/profiles/profile_shortcut_manager_win.cc (working copy)
|
| @@ -10,9 +10,11 @@
|
| #include "base/path_service.h"
|
| #include "base/stringprintf.h"
|
| #include "base/utf_string_conversions.h"
|
| +#include "chrome/browser/app_icon_win.h"
|
| #include "chrome/browser/browser_process.h"
|
| #include "chrome/browser/prefs/pref_service.h"
|
| #include "chrome/browser/profiles/profile_info_cache.h"
|
| +#include "chrome/browser/profiles/profile_info_util.h"
|
| #include "chrome/browser/profiles/profile_manager.h"
|
| #include "chrome/common/chrome_constants.h"
|
| #include "chrome/common/chrome_switches.h"
|
| @@ -21,12 +23,21 @@
|
| #include "chrome/installer/util/shell_util.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "grit/generated_resources.h"
|
| +#include "skia/ext/image_operations.h"
|
| +#include "skia/ext/platform_canvas.h"
|
| #include "ui/base/l10n/l10n_util.h"
|
| +#include "ui/gfx/icon_util.h"
|
| +#include "ui/gfx/image/image.h"
|
|
|
| using content::BrowserThread;
|
|
|
| namespace {
|
|
|
| +const char kProfileIconFileName[] = "Google Profile.ico";
|
| +const int kProfileAvatarShortcutBadgeWidth = 28;
|
| +const int kProfileAvatarShortcutBadgeHeight = 28;
|
| +const int kShortcutIconSize = 48;
|
| +
|
| // Creates the argument to pass to the Windows executable that launches Chrome
|
| // with the profile in |profile_base_dir|.
|
| // For example: --profile-directory="Profile 2"
|
| @@ -44,6 +55,172 @@
|
| bool_function.Run();
|
| }
|
|
|
| +// Creates a desktop shortcut icon file (.ico) on the disk for a given profile,
|
| +// badging the browser distribution icon with the profile avatar.
|
| +// |profile_base_dir| is the base directory (and key) of the profile. Returns
|
| +// a path to the shortcut icon file on disk, which is empty if this fails.
|
| +// Use index 0 when assigning the resulting file as the icon.
|
| +FilePath CreateChromeDesktopShortcutIconForProfile(
|
| + const string16& profile_path,
|
| + const gfx::Image* avatar_image) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| + if (!avatar_image)
|
| + return FilePath();
|
| + const SkBitmap* avatar_bitmap = avatar_image->ToSkBitmap();
|
| + DCHECK(avatar_bitmap);
|
| + HICON app_icon_handle = GetAppIconForSize(kShortcutIconSize);
|
| + scoped_ptr<SkBitmap> app_icon_bitmap(
|
| + IconUtil::CreateSkBitmapFromHICON(app_icon_handle));
|
| + DestroyIcon(app_icon_handle);
|
| + if (!app_icon_bitmap.get())
|
| + return FilePath();
|
| +
|
| + // TODO(stevet): Share this chunk of code with
|
| + // avatar_menu_button::DrawTaskBarDecoration.
|
| + const SkBitmap* source_bitmap = NULL;
|
| + SkBitmap squarer_bitmap;
|
| + if ((avatar_bitmap->width() == profiles::kAvatarIconWidth) &&
|
| + (avatar_bitmap->height() == profiles::kAvatarIconHeight)) {
|
| + // Shave a couple of columns so the bitmap is more square. So when
|
| + // resized to a square aspect ratio it looks pretty.
|
| + int x = 2;
|
| + avatar_bitmap->extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0,
|
| + profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight));
|
| + source_bitmap = &squarer_bitmap;
|
| + } else {
|
| + source_bitmap = avatar_bitmap;
|
| + }
|
| + SkBitmap sk_icon = skia::ImageOperations::Resize(
|
| + *source_bitmap,
|
| + skia::ImageOperations::RESIZE_LANCZOS3,
|
| + kProfileAvatarShortcutBadgeWidth,
|
| + kProfileAvatarShortcutBadgeHeight);
|
| +
|
| + // Overlay the avatar on the icon, anchoring it to the bottom-right of the
|
| + // icon.
|
| + scoped_ptr<SkCanvas> offscreen_canvas(
|
| + skia::CreateBitmapCanvas(app_icon_bitmap->width(),
|
| + app_icon_bitmap->height(),
|
| + false));
|
| + DCHECK(offscreen_canvas.get());
|
| + offscreen_canvas->drawBitmap(*app_icon_bitmap, 0, 0);
|
| + offscreen_canvas->drawBitmap(
|
| + sk_icon,
|
| + app_icon_bitmap->width() - kProfileAvatarShortcutBadgeWidth,
|
| + app_icon_bitmap->height() - kProfileAvatarShortcutBadgeHeight);
|
| + const SkBitmap& final_bitmap =
|
| + offscreen_canvas->getDevice()->accessBitmap(false);
|
| +
|
| + // Finally, write the .ico file containing this new bitmap.
|
| + FilePath icon_path(profile_path);
|
| + icon_path = icon_path.AppendASCII(kProfileIconFileName);
|
| + if (!IconUtil::CreateIconFileFromSkBitmap(final_bitmap, icon_path))
|
| + return FilePath();
|
| +
|
| + return icon_path;
|
| +}
|
| +
|
| +// Creates a desktop shortcut to open Chrome with the given profile name and
|
| +// base directory. Iff |create|, create shortcut if it doesn't already exist.
|
| +// Must be called on the FILE thread. This method retains ownership of
|
| +// |avatar_image| and will delete it when it is done with it.
|
| +void CreateChromeDesktopShortcutForProfile(
|
| + const string16& profile_name,
|
| + const string16& profile_base_dir,
|
| + const string16& profile_path,
|
| + const gfx::Image* avatar_image,
|
| + bool create) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| + FilePath chrome_exe;
|
| + if (!PathService::Get(base::FILE_EXE, &chrome_exe))
|
| + return;
|
| + BrowserDistribution* dist = BrowserDistribution::GetDistribution();
|
| + string16 description;
|
| + if (!dist)
|
| + return;
|
| + else
|
| + description = WideToUTF16(dist->GetAppDescription());
|
| + const string16& directory = CreateProfileShortcutSwitch(profile_base_dir);
|
| + FilePath icon_path =
|
| + CreateChromeDesktopShortcutIconForProfile(profile_path, avatar_image);
|
| +
|
| + ShellUtil::CreateChromeDesktopShortcut(
|
| + dist,
|
| + chrome_exe.value(),
|
| + description,
|
| + profile_name,
|
| + directory,
|
| + icon_path.empty() ? chrome_exe.value() : icon_path.value(),
|
| + icon_path.empty() ? dist->GetIconIndex() : 0,
|
| + ShellUtil::CURRENT_USER,
|
| + false, // Use alternate text.
|
| + create); // Create if it doesn't already exist.
|
| +
|
| + // We have ownership of avatar_image, so clean it up here.
|
| + if (avatar_image) {
|
| + delete avatar_image;
|
| + avatar_image = NULL;
|
| + }
|
| +}
|
| +
|
| +// Renames an existing Chrome desktop profile shortcut. Must be called on the
|
| +// FILE thread.
|
| +void RenameChromeDesktopShortcutForProfile(
|
| + const string16& old_shortcut,
|
| + const string16& new_shortcut) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| + FilePath shortcut_path;
|
| + if (ShellUtil::GetDesktopPath(false, // User's directory instead of system.
|
| + &shortcut_path)) {
|
| + FilePath old_profile = shortcut_path.Append(old_shortcut);
|
| + FilePath new_profile = shortcut_path.Append(new_shortcut);
|
| + file_util::Move(old_profile, new_profile);
|
| + }
|
| +}
|
| +
|
| +// Updates the arguments to a Chrome desktop shortcut for a profile. Must be
|
| +// called on the FILE thread. This method retains ownership of |avatar_image|
|
| +// and will delete it when it is done with it.
|
| +void UpdateChromeDesktopShortcutForProfile(
|
| + const string16& shortcut,
|
| + const string16& arguments,
|
| + const string16& profile_path,
|
| + const gfx::Image* avatar_image) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| + FilePath shortcut_path;
|
| + if (!ShellUtil::GetDesktopPath(false, &shortcut_path))
|
| + return;
|
| +
|
| + shortcut_path = shortcut_path.Append(shortcut);
|
| + FilePath chrome_exe;
|
| + if (!PathService::Get(base::FILE_EXE, &chrome_exe))
|
| + return;
|
| + BrowserDistribution* dist = BrowserDistribution::GetDistribution();
|
| + string16 description;
|
| + if (!dist)
|
| + return;
|
| + else
|
| + description = WideToUTF16(dist->GetAppDescription());
|
| + FilePath icon_path =
|
| + CreateChromeDesktopShortcutIconForProfile(profile_path, avatar_image);
|
| +
|
| + ShellUtil::UpdateChromeShortcut(
|
| + dist,
|
| + chrome_exe.value(),
|
| + shortcut_path.value(),
|
| + arguments,
|
| + description,
|
| + icon_path.empty() ? chrome_exe.value() : icon_path.value(),
|
| + icon_path.empty() ? dist->GetIconIndex() : 0,
|
| + false);
|
| +
|
| + // We have ownership of avatar_image, so clean it up here.
|
| + if (avatar_image) {
|
| + delete avatar_image;
|
| + avatar_image = NULL;
|
| + }
|
| +}
|
| +
|
| } // namespace
|
|
|
| ProfileShortcutManagerWin::ProfileShortcutManagerWin() {
|
| @@ -54,17 +231,25 @@
|
|
|
| void ProfileShortcutManagerWin::OnProfileAdded(
|
| const string16& profile_name,
|
| - const string16& profile_base_dir) {
|
| + const string16& profile_base_dir,
|
| + const string16& profile_path,
|
| + const gfx::Image* avatar_image) {
|
| // Launch task to add shortcut to desktop on Windows. If this is the very
|
| // first profile created, don't add the user name to the shortcut.
|
| // TODO(mirandac): respect master_preferences choice to create no shortcuts
|
| // (see http://crbug.com/104463)
|
| if (g_browser_process->profile_manager()->GetNumberOfProfiles() > 1) {
|
| - string16 profile_directory =
|
| - CreateProfileShortcutSwitch(profile_base_dir);
|
| - BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
| - base::Bind(&CreateChromeDesktopShortcutForProfile,
|
| - profile_name, profile_directory, true));
|
| + // There is no guarantee that avatar_image won't be deleted before it's
|
| + // used, so we'll make a deep copy of it and rely on the user to delete the
|
| + // copy.
|
| + gfx::Image* avatar_copy = avatar_image ?
|
| + new gfx::Image(avatar_image->CopySkBitmap()) : NULL;
|
| + if (!BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
| + base::Bind(&CreateChromeDesktopShortcutForProfile,
|
| + profile_name, profile_base_dir, profile_path,
|
| + avatar_copy, true))) {
|
| + delete avatar_copy;
|
| + }
|
|
|
| // If this is the very first multi-user account created, change the
|
| // original shortcut to launch with the First User profile.
|
| @@ -72,8 +257,6 @@
|
| if (local_state->GetInteger(prefs::kProfilesNumCreated) == 2) {
|
| string16 default_name = l10n_util::GetStringUTF16(
|
| IDS_DEFAULT_PROFILE_NAME);
|
| - string16 default_directory =
|
| - CreateProfileShortcutSwitch(UTF8ToUTF16(chrome::kInitialProfile));
|
| BrowserDistribution* dist = BrowserDistribution::GetDistribution();
|
|
|
| string16 old_shortcut;
|
| @@ -85,15 +268,18 @@
|
| BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
| base::Bind(&RenameChromeDesktopShortcutForProfile,
|
| old_shortcut, new_shortcut));
|
| + // TODO(stevet): We actually need to retrieve the newly assigned avatar
|
| + // icon for the original profile here and update it with that.
|
| BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
| base::Bind(&UpdateChromeDesktopShortcutForProfile,
|
| - new_shortcut, default_directory));
|
| + new_shortcut, UTF8ToUTF16(chrome::kInitialProfile),
|
| + profile_path, static_cast<gfx::Image*>(NULL)));
|
| }
|
| }
|
| - } else { // Only one profile, so create original shortcut.
|
| + } else { // Only one profile, so create original shortcut, with no avatar.
|
| BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
| base::Bind(&CreateChromeDesktopShortcutForProfile,
|
| - L"", L"", true));
|
| + L"", L"", L"", static_cast<gfx::Image*>(NULL), true));
|
| }
|
| }
|
|
|
| @@ -131,6 +317,32 @@
|
| }
|
| }
|
|
|
| +void ProfileShortcutManagerWin::OnProfileAvatarChanged(
|
| + const string16& profile_name,
|
| + const string16& profile_base_dir,
|
| + const string16& profile_path,
|
| + const gfx::Image* avatar_image) {
|
| + // Launch task to change the icon of the desktop shortcut on windows.
|
| + string16 new_shortcut;
|
| + BrowserDistribution* dist = BrowserDistribution::GetDistribution();
|
| + if (ShellUtil::GetChromeShortcutName(dist, false, profile_name,
|
| + &new_shortcut)) {
|
| + // There is no guarantee that avatar_image won't be deleted before it's
|
| + // used, so we'll make a deep copy of it and rely on the user to delete the
|
| + // copy.
|
| + gfx::Image* avatar_copy = avatar_image ?
|
| + new gfx::Image(avatar_image->CopySkBitmap()) : NULL;
|
| + if (!BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
| + base::Bind(&UpdateChromeDesktopShortcutForProfile,
|
| + new_shortcut,
|
| + CreateProfileShortcutSwitch(profile_base_dir),
|
| + profile_path,
|
| + avatar_copy))) {
|
| + delete avatar_copy;
|
| + }
|
| + }
|
| +}
|
| +
|
| // static
|
| std::vector<string16> ProfileShortcutManagerWin::GenerateShortcutsFromProfiles(
|
| const std::vector<string16>& profile_names) {
|
| @@ -146,71 +358,3 @@
|
| }
|
| return shortcuts;
|
| }
|
| -
|
| -// static
|
| -void ProfileShortcutManagerWin::CreateChromeDesktopShortcutForProfile(
|
| - const string16& profile_name,
|
| - const string16& directory,
|
| - bool create) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - FilePath chrome_exe;
|
| - if (!PathService::Get(base::FILE_EXE, &chrome_exe))
|
| - return;
|
| - BrowserDistribution* dist = BrowserDistribution::GetDistribution();
|
| - string16 description;
|
| - if (!dist)
|
| - return;
|
| - else
|
| - description = WideToUTF16(dist->GetAppDescription());
|
| - ShellUtil::CreateChromeDesktopShortcut(
|
| - dist,
|
| - chrome_exe.value(),
|
| - description,
|
| - profile_name,
|
| - directory,
|
| - ShellUtil::CURRENT_USER,
|
| - false, // Use alternate text.
|
| - create); // Create if it doesn't already exist.
|
| -}
|
| -
|
| -// static
|
| -void ProfileShortcutManagerWin::RenameChromeDesktopShortcutForProfile(
|
| - const string16& old_shortcut,
|
| - const string16& new_shortcut) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - FilePath shortcut_path;
|
| - if (ShellUtil::GetDesktopPath(false, // User's directory instead of system.
|
| - &shortcut_path)) {
|
| - FilePath old_profile = shortcut_path.Append(old_shortcut);
|
| - FilePath new_profile = shortcut_path.Append(new_shortcut);
|
| - file_util::Move(old_profile, new_profile);
|
| - }
|
| -}
|
| -
|
| -// static
|
| -void ProfileShortcutManagerWin::UpdateChromeDesktopShortcutForProfile(
|
| - const string16& shortcut,
|
| - const string16& arguments) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - FilePath shortcut_path;
|
| - if (!ShellUtil::GetDesktopPath(false, &shortcut_path))
|
| - return;
|
| -
|
| - shortcut_path = shortcut_path.Append(shortcut);
|
| - FilePath chrome_exe;
|
| - if (!PathService::Get(base::FILE_EXE, &chrome_exe))
|
| - return;
|
| - BrowserDistribution* dist = BrowserDistribution::GetDistribution();
|
| - string16 description;
|
| - if (!dist)
|
| - return;
|
| - else
|
| - description = WideToUTF16(dist->GetAppDescription());
|
| - ShellUtil::UpdateChromeShortcut(
|
| - dist,
|
| - chrome_exe.value(),
|
| - shortcut_path.value(),
|
| - arguments,
|
| - description,
|
| - false);
|
| -}
|
|
|