| // 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(); |
| } |
| } |