Home | History | Annotate | Download | only in frame
      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