blob: 1548025c654904b100104a11cc8f8228bd0bb98f [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/elevation_icon_setter.h"
#include "base/callback.h"
#include "base/task_runner_util.h"
#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
#include "ui/views/controls/button/label_button.h"
#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "ui/gfx/icon_util.h"
#include "ui/gfx/win/dpi.h"
#endif
// Helpers --------------------------------------------------------------------
namespace {
scoped_ptr<SkBitmap> GetElevationIcon() {
scoped_ptr<SkBitmap> icon;
#if defined(OS_WIN)
if ((base::win::GetVersion() < base::win::VERSION_VISTA) ||
!base::win::UserAccountControlIsEnabled())
return icon.Pass();
SHSTOCKICONINFO icon_info = { sizeof(SHSTOCKICONINFO) };
typedef HRESULT (STDAPICALLTYPE *GetStockIconInfo)(SHSTOCKICONID,
UINT,
SHSTOCKICONINFO*);
// Even with the runtime guard above, we have to use GetProcAddress()
// here, because otherwise the loader will try to resolve the function
// address on startup, which will break on XP.
GetStockIconInfo func = reinterpret_cast<GetStockIconInfo>(
GetProcAddress(GetModuleHandle(L"shell32.dll"), "SHGetStockIconInfo"));
// TODO(pkasting): Run on a background thread since this call spins a nested
// message loop.
if (FAILED((*func)(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &icon_info)))
return icon.Pass();
icon.reset(IconUtil::CreateSkBitmapFromHICON(
icon_info.hIcon,
gfx::Size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON))));
DestroyIcon(icon_info.hIcon);
#endif
return icon;
}
} // namespace
// ElevationIconSetter --------------------------------------------------------
ElevationIconSetter::ElevationIconSetter(views::LabelButton* button,
const base::Closure& callback)
: button_(button),
weak_factory_(this) {
base::PostTaskAndReplyWithResult(
content::BrowserThread::GetBlockingPool(),
FROM_HERE,
base::Bind(&GetElevationIcon),
base::Bind(&ElevationIconSetter::SetButtonIcon,
weak_factory_.GetWeakPtr(),
callback));
}
ElevationIconSetter::~ElevationIconSetter() {
}
void ElevationIconSetter::SetButtonIcon(const base::Closure& callback,
scoped_ptr<SkBitmap> icon) {
if (icon) {
float device_scale_factor = 1.0f;
#if defined(OS_WIN)
// Windows gives us back a correctly-scaled image for the current DPI, so
// mark this image as having been scaled for the current DPI already.
device_scale_factor = gfx::GetDPIScale();
#endif
button_->SetImage(
views::Button::STATE_NORMAL,
gfx::ImageSkia(gfx::ImageSkiaRep(*icon, device_scale_factor)));
button_->SizeToPreferredSize();
if (button_->parent())
button_->parent()->Layout();
if (!callback.is_null())
callback.Run();
}
}