1// Copyright (c) 2012 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/frame/minimize_button_metrics_win.h"
6
7#include "base/logging.h"
8#include "base/i18n/rtl.h"
9#include "ui/base/win/shell.h"
10#include "ui/gfx/win/dpi.h"
11
12namespace {
13
14int GetMinimizeButtonOffsetForWindow(HWND hwnd) {
15  // The WM_GETTITLEBARINFOEX message can fail if we are not active/visible. By
16  // fail we get a location of 0; the return status code is always the same and
17  // similarly the state never seems to change (titlebar_info.rgstate).
18  TITLEBARINFOEX titlebar_info = {0};
19  titlebar_info.cbSize = sizeof(TITLEBARINFOEX);
20  SendMessage(hwnd, WM_GETTITLEBARINFOEX, 0,
21              reinterpret_cast<WPARAM>(&titlebar_info));
22
23  if (titlebar_info.rgrect[2].left == titlebar_info.rgrect[2].right ||
24      (titlebar_info.rgstate[2] & (STATE_SYSTEM_INVISIBLE |
25                                   STATE_SYSTEM_OFFSCREEN |
26                                   STATE_SYSTEM_UNAVAILABLE))) {
27    return 0;
28  }
29
30  // WM_GETTITLEBARINFOEX returns rects in screen coordinates in pixels.
31  // We need to convert the minimize button corner offset to DIP before
32  // returning it.
33  POINT minimize_button_corner = { titlebar_info.rgrect[2].left, 0 };
34  MapWindowPoints(HWND_DESKTOP, hwnd, &minimize_button_corner, 1);
35  return minimize_button_corner.x / gfx::win::GetDeviceScaleFactor();
36}
37
38}  // namespace
39
40// static
41int MinimizeButtonMetrics::last_cached_minimize_button_x_delta_ = 0;
42
43MinimizeButtonMetrics::MinimizeButtonMetrics()
44    : hwnd_(NULL),
45      cached_minimize_button_x_delta_(last_cached_minimize_button_x_delta_),
46      was_activated_(false) {
47}
48
49MinimizeButtonMetrics::~MinimizeButtonMetrics() {
50}
51
52void MinimizeButtonMetrics::Init(HWND hwnd) {
53  DCHECK(!hwnd_);
54  hwnd_ = hwnd;
55}
56
57void MinimizeButtonMetrics::OnHWNDActivated() {
58  was_activated_ = true;
59  // NOTE: we don't cache here as it seems only after the activate is the value
60  // correct.
61}
62
63int MinimizeButtonMetrics::GetMinimizeButtonOffsetX() const {
64  // Under DWM WM_GETTITLEBARINFOEX won't return the right thing until after
65  // WM_NCACTIVATE (maybe it returns classic values?). In an attempt to return a
66  // consistant value we cache the last value across instances and use it until
67  // we get the activate.
68  if (was_activated_ || !ui::win::IsAeroGlassEnabled() ||
69      cached_minimize_button_x_delta_ == 0) {
70    const int minimize_button_offset = GetAndCacheMinimizeButtonOffsetX();
71    if (minimize_button_offset > 0)
72      return minimize_button_offset;
73  }
74
75  // If we fail to get the minimize button offset via the WM_GETTITLEBARINFOEX
76  // message then calculate and return this via the
77  // cached_minimize_button_x_delta_ member value. Please see
78  // CacheMinimizeButtonDelta() for more details.
79  DCHECK(cached_minimize_button_x_delta_);
80
81  if (base::i18n::IsRTL())
82    return cached_minimize_button_x_delta_;
83
84  RECT client_rect = {0};
85  GetClientRect(hwnd_, &client_rect);
86  return client_rect.right - cached_minimize_button_x_delta_;
87}
88
89int MinimizeButtonMetrics::GetAndCacheMinimizeButtonOffsetX() const {
90  const int minimize_button_offset = GetMinimizeButtonOffsetForWindow(hwnd_);
91  if (minimize_button_offset <= 0)
92    return 0;
93
94  if (base::i18n::IsRTL()) {
95    cached_minimize_button_x_delta_ = minimize_button_offset;
96  } else {
97    RECT client_rect = {0};
98    GetClientRect(hwnd_, &client_rect);
99    cached_minimize_button_x_delta_ =
100        client_rect.right - minimize_button_offset;
101  }
102  last_cached_minimize_button_x_delta_ = cached_minimize_button_x_delta_;
103  return minimize_button_offset;
104}
105