minimize_button_metrics_win.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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 // 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()); 43 } 44 MapWindowPoints(HWND_DESKTOP, hwnd, &minimize_button_corner, 1); 45 return minimize_button_corner.x / gfx::win::GetDeviceScaleFactor(); 46} 47 48} // namespace 49 50// static 51int MinimizeButtonMetrics::last_cached_minimize_button_x_delta_ = 0; 52 53MinimizeButtonMetrics::MinimizeButtonMetrics() 54 : hwnd_(NULL), 55 cached_minimize_button_x_delta_(last_cached_minimize_button_x_delta_), 56 was_activated_(false) { 57} 58 59MinimizeButtonMetrics::~MinimizeButtonMetrics() { 60} 61 62void MinimizeButtonMetrics::Init(HWND hwnd) { 63 DCHECK(!hwnd_); 64 hwnd_ = hwnd; 65} 66 67void MinimizeButtonMetrics::OnHWNDActivated() { 68 was_activated_ = true; 69 // NOTE: we don't cache here as it seems only after the activate is the value 70 // correct. 71} 72 73int 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; 83 } 84 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_); 90 91 if (base::i18n::IsRTL()) 92 return cached_minimize_button_x_delta_; 93 94 RECT client_rect = {0}; 95 GetClientRect(hwnd_, &client_rect); 96 return client_rect.right - cached_minimize_button_x_delta_; 97} 98 99int MinimizeButtonMetrics::GetAndCacheMinimizeButtonOffsetX() const { 100 const int minimize_button_offset = GetMinimizeButtonOffsetForWindow(hwnd_); 101 if (minimize_button_offset <= 0) 102 return 0; 103 104 if (base::i18n::IsRTL()) { 105 cached_minimize_button_x_delta_ = minimize_button_offset; 106 } else { 107 RECT client_rect = {0}; 108 GetClientRect(hwnd_, &client_rect); 109 cached_minimize_button_x_delta_ = 110 client_rect.right - minimize_button_offset; 111 } 112 last_cached_minimize_button_x_delta_ = cached_minimize_button_x_delta_; 113 return minimize_button_offset; 114} 115