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 12 namespace { 13 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)); 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 41 int MinimizeButtonMetrics::last_cached_minimize_button_x_delta_ = 0; 42 43 MinimizeButtonMetrics::MinimizeButtonMetrics() 44 : hwnd_(NULL), 45 cached_minimize_button_x_delta_(last_cached_minimize_button_x_delta_), 46 was_activated_(false) { 47 } 48 49 MinimizeButtonMetrics::~MinimizeButtonMetrics() { 50 } 51 52 void MinimizeButtonMetrics::Init(HWND hwnd) { 53 DCHECK(!hwnd_); 54 hwnd_ = hwnd; 55 } 56 57 void 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 63 int 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 89 int 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