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.
5 #include "chrome/browser/ui/views/frame/minimize_button_metrics_win.h"
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"
14 int 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
));
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
))) {
30 // Most versions of Windows return screen coordinates for
31 // WM_GETTITLEBARINFOEX. Since chrome is not dpi aware (currently) we need to
32 // unscale these coordinates. Surface Pro seems to be unique, in that it
33 // returns local coordinates (eg they don't need to be scaled). There doesn't
34 // appear to be a clear way to detect this, so we assume that if the minimize
35 // button is outside the bounds of the window coordinates are scaled.
36 RECT window_rect
= {0};
37 GetWindowRect(hwnd
, &window_rect
);
38 POINT minimize_button_corner
= { titlebar_info
.rgrect
[2].left
, 0 };
39 if (minimize_button_corner
.x
> window_rect
.right
) {
40 minimize_button_corner
.x
=
41 static_cast<int>(minimize_button_corner
.x
/
42 gfx::win::GetUndocumentedDPIScale());
44 MapWindowPoints(HWND_DESKTOP
, hwnd
, &minimize_button_corner
, 1);
45 return minimize_button_corner
.x
/ gfx::win::GetDeviceScaleFactor();
51 int MinimizeButtonMetrics::last_cached_minimize_button_x_delta_
= 0;
53 MinimizeButtonMetrics::MinimizeButtonMetrics()
55 cached_minimize_button_x_delta_(last_cached_minimize_button_x_delta_
),
56 was_activated_(false) {
59 MinimizeButtonMetrics::~MinimizeButtonMetrics() {
62 void MinimizeButtonMetrics::Init(HWND hwnd
) {
67 void MinimizeButtonMetrics::OnHWNDActivated() {
68 was_activated_
= true;
69 // NOTE: we don't cache here as it seems only after the activate is the value
73 int MinimizeButtonMetrics::GetMinimizeButtonOffsetX() const {
74 // Under DWM WM_GETTITLEBARINFOEX won't return the right thing until after
75 // WM_NCACTIVATE (maybe it returns classic values?). In an attempt to return a
76 // consistant value we cache the last value across instances and use it until
77 // we get the activate.
78 if (was_activated_
|| !ui::win::IsAeroGlassEnabled() ||
79 cached_minimize_button_x_delta_
== 0) {
80 const int minimize_button_offset
= GetAndCacheMinimizeButtonOffsetX();
81 if (minimize_button_offset
> 0)
82 return minimize_button_offset
;
85 // If we fail to get the minimize button offset via the WM_GETTITLEBARINFOEX
86 // message then calculate and return this via the
87 // cached_minimize_button_x_delta_ member value. Please see
88 // CacheMinimizeButtonDelta() for more details.
89 DCHECK(cached_minimize_button_x_delta_
);
91 if (base::i18n::IsRTL())
92 return cached_minimize_button_x_delta_
;
94 RECT client_rect
= {0};
95 GetClientRect(hwnd_
, &client_rect
);
96 return client_rect
.right
- cached_minimize_button_x_delta_
;
99 int MinimizeButtonMetrics::GetAndCacheMinimizeButtonOffsetX() const {
100 const int minimize_button_offset
= GetMinimizeButtonOffsetForWindow(hwnd_
);
101 if (minimize_button_offset
<= 0)
104 if (base::i18n::IsRTL()) {
105 cached_minimize_button_x_delta_
= minimize_button_offset
;
107 RECT client_rect
= {0};
108 GetClientRect(hwnd_
, &client_rect
);
109 cached_minimize_button_x_delta_
=
110 client_rect
.right
- minimize_button_offset
;
112 last_cached_minimize_button_x_delta_
= cached_minimize_button_x_delta_
;
113 return minimize_button_offset
;