1 // Copyright (c) 2011 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/tabs/dock_info.h"
6
7 #include "base/logging.h"
8 #if defined(TOOLKIT_VIEWS)
9 #include "chrome/browser/ui/views/tabs/tab.h"
10 #else
11 #include "chrome/browser/ui/gtk/tabs/tab_gtk.h"
12 #endif
13
14 namespace {
15
16 // Distance in pixels between the hotspot and when the hint should be shown.
17 const int kHotSpotDeltaX = 120;
18 const int kHotSpotDeltaY = 120;
19
20 // Size of the popup window.
21 const int kPopupWidth = 70;
22 const int kPopupHeight = 70;
23
24 } // namespace
25
26 // static
27 DockInfo::Factory* DockInfo::factory_ = NULL;
28
29 // static
IsCloseToPoint(const gfx::Point & screen_loc,int x,int y,bool * in_enable_area)30 bool DockInfo::IsCloseToPoint(const gfx::Point& screen_loc,
31 int x,
32 int y,
33 bool* in_enable_area) {
34 int delta_x = abs(x - screen_loc.x());
35 int delta_y = abs(y - screen_loc.y());
36 *in_enable_area = (delta_x < kPopupWidth / 2 && delta_y < kPopupHeight / 2);
37 return *in_enable_area || (delta_x < kHotSpotDeltaX &&
38 delta_y < kHotSpotDeltaY);
39 }
40
41 // static
IsCloseToMonitorPoint(const gfx::Point & screen_loc,int x,int y,DockInfo::Type type,bool * in_enable_area)42 bool DockInfo::IsCloseToMonitorPoint(const gfx::Point& screen_loc,
43 int x,
44 int y,
45 DockInfo::Type type,
46 bool* in_enable_area) {
47 // Because the monitor relative positions are aligned with the edge of the
48 // monitor these need to be handled differently.
49 int delta_x = abs(x - screen_loc.x());
50 int delta_y = abs(y - screen_loc.y());
51
52 int enable_delta_x = kPopupWidth / 2;
53 int enable_delta_y = kPopupHeight / 2;
54 int hot_spot_delta_x = kHotSpotDeltaX;
55 int hot_spot_delta_y = kHotSpotDeltaY;
56
57 switch (type) {
58 case DockInfo::LEFT_HALF:
59 case DockInfo::RIGHT_HALF:
60 enable_delta_x += enable_delta_x;
61 hot_spot_delta_x += hot_spot_delta_x;
62 break;
63
64
65 case DockInfo::MAXIMIZE: {
66 // Make the maximize height smaller than the tab height to avoid showing
67 // the dock indicator when close to maximized browser.
68 #if defined(TOOLKIT_VIEWS)
69 hot_spot_delta_y = Tab::GetMinimumUnselectedSize().height() - 1;
70 #else
71 hot_spot_delta_y = TabGtk::GetMinimumUnselectedSize().height() - 1;
72 #endif
73 enable_delta_y = hot_spot_delta_y / 2;
74 break;
75 }
76 case DockInfo::BOTTOM_HALF:
77 enable_delta_y += enable_delta_y;
78 hot_spot_delta_y += hot_spot_delta_y;
79 break;
80
81 default:
82 NOTREACHED();
83 return false;
84 }
85 *in_enable_area = (delta_x < enable_delta_x && delta_y < enable_delta_y);
86 bool result = (*in_enable_area || (delta_x < hot_spot_delta_x &&
87 delta_y < hot_spot_delta_y));
88 if (type != DockInfo::MAXIMIZE)
89 return result;
90
91 // Make the hot spot/enable spot for maximized windows the whole top of the
92 // monitor.
93 int max_delta_y = abs(screen_loc.y() - y);
94 *in_enable_area = (*in_enable_area || (max_delta_y < enable_delta_y));
95 return *in_enable_area || (max_delta_y < hot_spot_delta_y);
96 }
97
98 // static
popup_width()99 int DockInfo::popup_width() {
100 return kPopupWidth;
101 }
102
103 // static
popup_height()104 int DockInfo::popup_height() {
105 return kPopupHeight;
106 }
107
IsValidForPoint(const gfx::Point & screen_point)108 bool DockInfo::IsValidForPoint(const gfx::Point& screen_point) {
109 if (type_ == NONE)
110 return false;
111
112 if (window_) {
113 return IsCloseToPoint(screen_point, hot_spot_.x(), hot_spot_.y(),
114 &in_enable_area_);
115 }
116
117 return monitor_bounds_.Contains(screen_point) &&
118 IsCloseToMonitorPoint(screen_point, hot_spot_.x(),
119 hot_spot_.y(), type_, &in_enable_area_);
120 }
121
GetNewWindowBounds(gfx::Rect * new_window_bounds,bool * maximize_new_window) const122 bool DockInfo::GetNewWindowBounds(gfx::Rect* new_window_bounds,
123 bool* maximize_new_window) const {
124 if (type_ == NONE || !in_enable_area_)
125 return false;
126
127 gfx::Rect window_bounds;
128 if (window_ && !GetWindowBounds(&window_bounds))
129 return false;
130
131 int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2;
132 int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2;
133
134 *maximize_new_window = false;
135
136 switch (type_) {
137 case LEFT_OF_WINDOW:
138 new_window_bounds->SetRect(monitor_bounds_.x(), window_bounds.y(),
139 half_m_width, window_bounds.height());
140 break;
141
142 case RIGHT_OF_WINDOW:
143 new_window_bounds->SetRect(monitor_bounds_.x() + half_m_width,
144 window_bounds.y(), half_m_width,
145 window_bounds.height());
146 break;
147
148 case TOP_OF_WINDOW:
149 new_window_bounds->SetRect(window_bounds.x(), monitor_bounds_.y(),
150 window_bounds.width(), half_m_height);
151 break;
152
153 case BOTTOM_OF_WINDOW:
154 new_window_bounds->SetRect(window_bounds.x(),
155 monitor_bounds_.y() + half_m_height,
156 window_bounds.width(), half_m_height);
157 break;
158
159 case LEFT_HALF:
160 new_window_bounds->SetRect(monitor_bounds_.x(), monitor_bounds_.y(),
161 half_m_width, monitor_bounds_.height());
162 break;
163
164 case RIGHT_HALF:
165 new_window_bounds->SetRect(monitor_bounds_.right() - half_m_width,
166 monitor_bounds_.y(), half_m_width, monitor_bounds_.height());
167 break;
168
169 case BOTTOM_HALF:
170 new_window_bounds->SetRect(monitor_bounds_.x(),
171 monitor_bounds_.y() + half_m_height,
172 monitor_bounds_.width(), half_m_height);
173 break;
174
175 case MAXIMIZE:
176 *maximize_new_window = true;
177 break;
178
179 default:
180 NOTREACHED();
181 }
182 return true;
183 }
184
AdjustOtherWindowBounds() const185 void DockInfo::AdjustOtherWindowBounds() const {
186 if (!in_enable_area_)
187 return;
188
189 gfx::Rect window_bounds;
190 if (!window_ || !GetWindowBounds(&window_bounds))
191 return;
192
193 gfx::Rect other_window_bounds;
194 int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2;
195 int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2;
196
197 switch (type_) {
198 case LEFT_OF_WINDOW:
199 other_window_bounds.SetRect(monitor_bounds_.x() + half_m_width,
200 window_bounds.y(), half_m_width,
201 window_bounds.height());
202 break;
203
204 case RIGHT_OF_WINDOW:
205 other_window_bounds.SetRect(monitor_bounds_.x(), window_bounds.y(),
206 half_m_width, window_bounds.height());
207 break;
208
209 case TOP_OF_WINDOW:
210 other_window_bounds.SetRect(window_bounds.x(),
211 monitor_bounds_.y() + half_m_height,
212 window_bounds.width(), half_m_height);
213 break;
214
215 case BOTTOM_OF_WINDOW:
216 other_window_bounds.SetRect(window_bounds.x(), monitor_bounds_.y(),
217 window_bounds.width(), half_m_height);
218 break;
219
220 default:
221 return;
222 }
223
224 SizeOtherWindowTo(other_window_bounds);
225 }
226
GetPopupRect() const227 gfx::Rect DockInfo::GetPopupRect() const {
228 int x = hot_spot_.x() - popup_width() / 2;
229 int y = hot_spot_.y() - popup_height() / 2;
230 switch (type_) {
231 case LEFT_OF_WINDOW:
232 case RIGHT_OF_WINDOW:
233 case TOP_OF_WINDOW:
234 case BOTTOM_OF_WINDOW: {
235 // Constrain the popup to the monitor's bounds.
236 gfx::Rect ideal_bounds(x, y, popup_width(), popup_height());
237 ideal_bounds = ideal_bounds.AdjustToFit(monitor_bounds_);
238 return ideal_bounds;
239 }
240 case DockInfo::MAXIMIZE:
241 y += popup_height() / 2;
242 break;
243 case DockInfo::LEFT_HALF:
244 x += popup_width() / 2;
245 break;
246 case DockInfo::RIGHT_HALF:
247 x -= popup_width() / 2;
248 break;
249 case DockInfo::BOTTOM_HALF:
250 y -= popup_height() / 2;
251 break;
252
253 default:
254 NOTREACHED();
255 }
256 return gfx::Rect(x, y, popup_width(), popup_height());
257 }
258
CheckMonitorPoint(const gfx::Point & screen_loc,int x,int y,Type type)259 bool DockInfo::CheckMonitorPoint(const gfx::Point& screen_loc,
260 int x,
261 int y,
262 Type type) {
263 if (IsCloseToMonitorPoint(screen_loc, x, y, type, &in_enable_area_)) {
264 hot_spot_.SetPoint(x, y);
265 type_ = type;
266 return true;
267 }
268 return false;
269 }
270