1// Copyright (c) 2009 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/window_sizer.h"
6
7#include "chrome/browser/ui/browser.h"
8#include "chrome/browser/ui/browser_list.h"
9#include "chrome/browser/ui/browser_window.h"
10
11// How much horizontal and vertical offset there is between newly
12// opened windows.
13const int WindowSizer::kWindowTilePixels = 10;
14
15// An implementation of WindowSizer::MonitorInfoProvider that gets the actual
16// monitor information from Windows.
17class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
18 public:
19  DefaultMonitorInfoProvider() { }
20
21  // Overridden from WindowSizer::MonitorInfoProvider:
22  virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
23    return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL,
24        MONITOR_DEFAULTTOPRIMARY)).rcWork);
25  }
26
27  virtual gfx::Rect GetPrimaryMonitorBounds() const {
28    return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL,
29        MONITOR_DEFAULTTOPRIMARY)).rcMonitor);
30  }
31
32  virtual gfx::Rect GetMonitorWorkAreaMatching(
33      const gfx::Rect& match_rect) const {
34    RECT other_bounds_rect = match_rect.ToRECT();
35    MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
36        &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
37    return gfx::Rect(monitor_info.rcWork);
38  }
39
40  virtual gfx::Point GetBoundsOffsetMatching(
41      const gfx::Rect& match_rect) const {
42    RECT other_bounds_rect = match_rect.ToRECT();
43    MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
44        &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
45    return gfx::Point(monitor_info.rcWork.left - monitor_info.rcMonitor.left,
46                      monitor_info.rcWork.top - monitor_info.rcMonitor.top);
47  }
48
49  void UpdateWorkAreas() {
50    work_areas_.clear();
51    EnumDisplayMonitors(NULL, NULL,
52                        &DefaultMonitorInfoProvider::MonitorEnumProc,
53                        reinterpret_cast<LPARAM>(&work_areas_));
54  }
55
56 private:
57  // A callback for EnumDisplayMonitors that records the work area of the
58  // current monitor in the enumeration.
59  static BOOL CALLBACK MonitorEnumProc(HMONITOR monitor,
60                                       HDC monitor_dc,
61                                       LPRECT monitor_rect,
62                                       LPARAM data) {
63    reinterpret_cast<std::vector<gfx::Rect>*>(data)->push_back(
64        gfx::Rect(GetMonitorInfoForMonitor(monitor).rcWork));
65    return TRUE;
66  }
67
68  static MONITORINFO GetMonitorInfoForMonitor(HMONITOR monitor) {
69    MONITORINFO monitor_info = { 0 };
70    monitor_info.cbSize = sizeof(monitor_info);
71    GetMonitorInfo(monitor, &monitor_info);
72    return monitor_info;
73  }
74
75  DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
76};
77
78// static
79WindowSizer::MonitorInfoProvider*
80WindowSizer::CreateDefaultMonitorInfoProvider() {
81  return new DefaultMonitorInfoProvider();
82}
83
84// static
85gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
86  RECT area;
87  SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0);
88  gfx::Point corner(area.left, area.top);
89
90  if (Browser* b = BrowserList::GetLastActive()) {
91    RECT browser;
92    HWND window = reinterpret_cast<HWND>(b->window()->GetNativeHandle());
93    if (GetWindowRect(window, &browser)) {
94      // Limit to not overflow the work area right and bottom edges.
95      gfx::Point limit(
96          std::min(browser.left + kWindowTilePixels, area.right-size.width()),
97          std::min(browser.top + kWindowTilePixels, area.bottom-size.height())
98      );
99      // Adjust corner to now overflow the work area left and top edges, so
100      // that if a popup does not fit the title-bar is remains visible.
101      corner = gfx::Point(
102          std::max(corner.x(), limit.x()),
103          std::max(corner.y(), limit.y())
104      );
105    }
106  }
107  return corner;
108}
109