summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/views/elevation_icon_setter.cc
blob: 1548025c654904b100104a11cc8f8228bd0bb98f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// 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();
  }
}