summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/window_sizer_win.cc
blob: a2952a40fcf821f1ced6070da9f253c33871f816 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/window_sizer.h"

#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"

// How much horizontal and vertical offset there is between newly
// opened windows.
const int WindowSizer::kWindowTilePixels = 10;

// An implementation of WindowSizer::MonitorInfoProvider that gets the actual
// monitor information from Windows.
class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
 public:
  DefaultMonitorInfoProvider() { }

  // Overridden from WindowSizer::MonitorInfoProvider:
  virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
    return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL,
        MONITOR_DEFAULTTOPRIMARY)).rcWork);
  }

  virtual gfx::Rect GetPrimaryMonitorBounds() const {
    return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL,
        MONITOR_DEFAULTTOPRIMARY)).rcMonitor);
  }

  virtual gfx::Rect GetMonitorWorkAreaMatching(
      const gfx::Rect& match_rect) const {
    RECT other_bounds_rect = match_rect.ToRECT();
    MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
        &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
    return gfx::Rect(monitor_info.rcWork);
  }

  virtual gfx::Point GetBoundsOffsetMatching(
      const gfx::Rect& match_rect) const {
    RECT other_bounds_rect = match_rect.ToRECT();
    MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
        &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
    return gfx::Point(monitor_info.rcWork.left - monitor_info.rcMonitor.left,
                      monitor_info.rcWork.top - monitor_info.rcMonitor.top);
  }

  void UpdateWorkAreas() {
    work_areas_.clear();
    EnumDisplayMonitors(NULL, NULL,
                        &DefaultMonitorInfoProvider::MonitorEnumProc,
                        reinterpret_cast<LPARAM>(&work_areas_));
  }

 private:
  // A callback for EnumDisplayMonitors that records the work area of the
  // current monitor in the enumeration.
  static BOOL CALLBACK MonitorEnumProc(HMONITOR monitor,
                                       HDC monitor_dc,
                                       LPRECT monitor_rect,
                                       LPARAM data) {
    reinterpret_cast<std::vector<gfx::Rect>*>(data)->push_back(
        gfx::Rect(GetMonitorInfoForMonitor(monitor).rcWork));
    return TRUE;
  }

  static MONITORINFO GetMonitorInfoForMonitor(HMONITOR monitor) {
    MONITORINFO monitor_info = { 0 };
    monitor_info.cbSize = sizeof(monitor_info);
    GetMonitorInfo(monitor, &monitor_info);
    return monitor_info;
  }

  DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
};

// static
WindowSizer::MonitorInfoProvider*
WindowSizer::CreateDefaultMonitorInfoProvider() {
  return new DefaultMonitorInfoProvider();
}

// static
gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
  RECT area;
  SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0);
  gfx::Point corner(area.left, area.top);

  if (Browser* b = BrowserList::GetLastActive()) {
    RECT browser;
    HWND window = reinterpret_cast<HWND>(b->window()->GetNativeHandle());
    if (GetWindowRect(window, &browser)) {
      // Limit to not overflow the work area right and bottom edges.
      gfx::Point limit(
          std::min(browser.left + kWindowTilePixels, area.right-size.width()),
          std::min(browser.top + kWindowTilePixels, area.bottom-size.height())
      );
      // Adjust corner to now overflow the work area left and top edges, so
      // that if a popup does not fit the title-bar is remains visible.
      corner = gfx::Point(
          std::max(corner.x(), limit.x()),
          std::max(corner.y(), limit.y())
      );
    }
  }
  return corner;
}