1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/views/elevation_icon_setter.h"
6
7#include "base/task_runner_util.h"
8#include "content/public/browser/browser_thread.h"
9#include "ui/views/controls/button/label_button.h"
10
11#if defined(OS_WIN)
12#include <windows.h>
13#include <shellapi.h>
14#include "base/win/win_util.h"
15#include "base/win/windows_version.h"
16#include "ui/gfx/icon_util.h"
17#endif
18
19
20// Helpers --------------------------------------------------------------------
21
22namespace {
23
24scoped_ptr<SkBitmap> GetElevationIcon() {
25  scoped_ptr<SkBitmap> icon;
26#if defined(OS_WIN)
27  if ((base::win::GetVersion() < base::win::VERSION_VISTA) ||
28      !base::win::UserAccountControlIsEnabled())
29    return icon.Pass();
30
31  SHSTOCKICONINFO icon_info = { sizeof(SHSTOCKICONINFO) };
32  typedef HRESULT (STDAPICALLTYPE *GetStockIconInfo)(SHSTOCKICONID,
33                                                     UINT,
34                                                     SHSTOCKICONINFO*);
35  // Even with the runtime guard above, we have to use GetProcAddress()
36  // here, because otherwise the loader will try to resolve the function
37  // address on startup, which will break on XP.
38  GetStockIconInfo func = reinterpret_cast<GetStockIconInfo>(
39      GetProcAddress(GetModuleHandle(L"shell32.dll"), "SHGetStockIconInfo"));
40  // TODO(pkasting): Run on a background thread since this call spins a nested
41  // message loop.
42  if (FAILED((*func)(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &icon_info)))
43    return icon.Pass();
44
45  icon.reset(IconUtil::CreateSkBitmapFromHICON(
46      icon_info.hIcon,
47      gfx::Size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON))));
48  DestroyIcon(icon_info.hIcon);
49#endif
50  return icon.Pass();
51}
52
53}  // namespace
54
55
56// ElevationIconSetter --------------------------------------------------------
57
58ElevationIconSetter::ElevationIconSetter(views::LabelButton* button)
59    : button_(button),
60      weak_factory_(this) {
61  base::PostTaskAndReplyWithResult(
62      content::BrowserThread::GetBlockingPool(),
63      FROM_HERE,
64      base::Bind(&GetElevationIcon),
65      base::Bind(&ElevationIconSetter::SetButtonIcon,
66                 weak_factory_.GetWeakPtr()));
67}
68
69ElevationIconSetter::~ElevationIconSetter() {
70}
71
72void ElevationIconSetter::SetButtonIcon(scoped_ptr<SkBitmap> icon) {
73  if (icon) {
74    button_->SetImage(views::Button::STATE_NORMAL,
75                      gfx::ImageSkia::CreateFrom1xBitmap(*icon));
76    button_->SizeToPreferredSize();
77    if (button_->parent())
78      button_->parent()->Layout();
79  }
80}
81