OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/dock_info.h" | 5 #include "chrome/browser/dock_info.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "chrome/browser/browser.h" | 9 #include "chrome/browser/browser.h" |
10 #include "chrome/browser/browser_list.h" | 10 #include "chrome/browser/browser_list.h" |
11 #include "chrome/browser/browser_window.h" | 11 #include "chrome/browser/browser_window.h" |
12 #include "chrome/browser/views/frame/browser_view.h" | 12 #include "chrome/browser/views/frame/browser_view.h" |
| 13 #include "chrome/browser/views/tabs/tab.h" |
13 | 14 |
14 namespace { | 15 namespace { |
15 | 16 |
16 // Distance in pixels between the hotspot and when the hint should be shown. | 17 // Distance in pixels between the hotspot and when the hint should be shown. |
17 const int kHotSpotDeltaX = 100; | 18 const int kHotSpotDeltaX = 120; |
18 const int kHotSpotDeltaY = 80; | 19 const int kHotSpotDeltaY = 120; |
19 | 20 |
20 // Distance in pixels between the hotspot and when the hint should be shown | 21 // Size of the popup window. |
21 // and enabled. | 22 const int kPopupWidth = 70; |
22 const int kEnableDeltaX = 50; | 23 const int kPopupHeight = 70; |
23 const int kEnableDeltaY = 37; | |
24 | |
25 // Distance used when maximizing. The maximize area is the whole top of the | |
26 // monitor. | |
27 const int kMaximizeHotSpotDeltaY = 100; | |
28 const int kMaximizeEnableDeltaY = 50; | |
29 | 24 |
30 // Returns true if |screen_loc| is close to the hotspot at |x|, |y|. If the | 25 // Returns true if |screen_loc| is close to the hotspot at |x|, |y|. If the |
31 // point is close enough to the hotspot true is returned and |in_enable_area| | 26 // point is close enough to the hotspot true is returned and |in_enable_area| |
32 // is set appropriately. | 27 // is set appropriately. |
33 bool IsCloseToPoint(const gfx::Point& screen_loc, | 28 bool IsCloseToPoint(const gfx::Point& screen_loc, |
34 int x, | 29 int x, |
35 int y, | 30 int y, |
36 bool* in_enable_area) { | 31 bool* in_enable_area) { |
37 int delta_x = abs(x - screen_loc.x()); | 32 int delta_x = abs(x - screen_loc.x()); |
38 int delta_y = abs(y - screen_loc.y()); | 33 int delta_y = abs(y - screen_loc.y()); |
39 *in_enable_area = (delta_x < kEnableDeltaX && delta_y < kEnableDeltaY); | 34 *in_enable_area = (delta_x < kPopupWidth / 2 && delta_y < kPopupHeight / 2); |
40 return *in_enable_area || (delta_x < kHotSpotDeltaX && | 35 return *in_enable_area || (delta_x < kHotSpotDeltaX && |
41 delta_y < kHotSpotDeltaY); | 36 delta_y < kHotSpotDeltaY); |
42 } | 37 } |
43 | 38 |
44 // Variant of IsCloseToPoint used for monitor relative positions. | 39 // Variant of IsCloseToPoint used for monitor relative positions. |
45 bool IsCloseToMonitorPoint(const gfx::Point& screen_loc, | 40 bool IsCloseToMonitorPoint(const gfx::Point& screen_loc, |
46 int x, | 41 int x, |
47 int y, | 42 int y, |
48 DockInfo::Type type, | 43 DockInfo::Type type, |
49 bool* in_enable_area) { | 44 bool* in_enable_area) { |
50 // Because the monitor relative positions are aligned with the edge of the | 45 // Because the monitor relative positions are aligned with the edge of the |
51 // monitor these need to be handled differently. | 46 // monitor these need to be handled differently. |
52 int delta_x = abs(x - screen_loc.x()); | 47 int delta_x = abs(x - screen_loc.x()); |
53 int delta_y = abs(y - screen_loc.y()); | 48 int delta_y = abs(y - screen_loc.y()); |
54 | 49 |
55 int enable_delta_x = kEnableDeltaX; | 50 int enable_delta_x = kPopupWidth / 2; |
56 int enable_delta_y = kEnableDeltaY; | 51 int enable_delta_y = kPopupHeight / 2; |
57 int hot_spot_delta_x = kHotSpotDeltaX; | 52 int hot_spot_delta_x = kHotSpotDeltaX; |
58 int hot_spot_delta_y = kHotSpotDeltaY; | 53 int hot_spot_delta_y = kHotSpotDeltaY; |
59 | 54 |
60 switch (type) { | 55 switch (type) { |
61 case DockInfo::LEFT_HALF: | 56 case DockInfo::LEFT_HALF: |
62 case DockInfo::RIGHT_HALF: | 57 case DockInfo::RIGHT_HALF: |
63 enable_delta_x += enable_delta_x; | 58 enable_delta_x += enable_delta_x; |
64 hot_spot_delta_x += hot_spot_delta_x; | 59 hot_spot_delta_x += hot_spot_delta_x; |
65 break; | 60 break; |
66 | 61 |
67 | 62 |
68 case DockInfo::MAXIMIZE: | 63 case DockInfo::MAXIMIZE: { |
| 64 // Make the maximize height smaller than the tab height to avoid showing |
| 65 // the dock indicator when close to maximized browser. |
| 66 hot_spot_delta_y = Tab::GetMinimumUnselectedSize().height() - 1; |
| 67 enable_delta_y = hot_spot_delta_y / 2; |
| 68 break; |
| 69 } |
69 case DockInfo::BOTTOM_HALF: | 70 case DockInfo::BOTTOM_HALF: |
70 enable_delta_y += enable_delta_y; | 71 enable_delta_y += enable_delta_y; |
71 hot_spot_delta_y += hot_spot_delta_y; | 72 hot_spot_delta_y += hot_spot_delta_y; |
72 break; | 73 break; |
73 | 74 |
74 default: | 75 default: |
75 NOTREACHED(); | 76 NOTREACHED(); |
76 return false; | 77 return false; |
77 } | 78 } |
78 *in_enable_area = (delta_x < enable_delta_x && delta_y < enable_delta_y); | 79 *in_enable_area = (delta_x < enable_delta_x && delta_y < enable_delta_y); |
79 bool result = (*in_enable_area || (delta_x < hot_spot_delta_x && | 80 bool result = (*in_enable_area || (delta_x < hot_spot_delta_x && |
80 delta_y < hot_spot_delta_y)); | 81 delta_y < hot_spot_delta_y)); |
81 if (type != DockInfo::MAXIMIZE) | 82 if (type != DockInfo::MAXIMIZE) |
82 return result; | 83 return result; |
83 | 84 |
84 // Make the maximize area the whole top of the monitor. | 85 // Make the hot spot/enable spot for maximized windows the whole top of the |
| 86 // monitor. |
85 int max_delta_y = abs(screen_loc.y() - y); | 87 int max_delta_y = abs(screen_loc.y() - y); |
86 *in_enable_area = (*in_enable_area || (max_delta_y < kMaximizeEnableDeltaY)); | 88 *in_enable_area = (*in_enable_area || (max_delta_y < enable_delta_y)); |
87 return *in_enable_area || (max_delta_y < kMaximizeHotSpotDeltaY); | 89 return *in_enable_area || (max_delta_y < hot_spot_delta_y); |
88 } | |
89 | |
90 // Returns true if there is a maximized tabbed browser on the monitor | |
91 // |monitor|. | |
92 bool IsMaximizedTabbedBrowserOnMonitor(HMONITOR monitor) { | |
93 for (BrowserList::const_iterator i = BrowserList::begin(); | |
94 i != BrowserList::end(); ++i) { | |
95 Browser* browser = *i; | |
96 if (browser->type() == Browser::TYPE_NORMAL) { | |
97 HWND browser_hwnd = | |
98 reinterpret_cast<HWND>(browser->window()->GetNativeHandle()); | |
99 if (IsZoomed(browser_hwnd) && | |
100 MonitorFromWindow(browser_hwnd, MONITOR_DEFAULTTONEAREST) == | |
101 monitor) { | |
102 return true; | |
103 } | |
104 } | |
105 } | |
106 return false; | |
107 } | 90 } |
108 | 91 |
109 // BaseWindowFinder ----------------------------------------------------------- | 92 // BaseWindowFinder ----------------------------------------------------------- |
110 | 93 |
111 // Base class used to locate a window. This is intended to be used with the | 94 // Base class used to locate a window. This is intended to be used with the |
112 // various win32 functions that iterate over windows. | 95 // various win32 functions that iterate over windows. |
113 // | 96 // |
114 // A subclass need only override ShouldStopIterating to determine when | 97 // A subclass need only override ShouldStopIterating to determine when |
115 // iteration should stop. | 98 // iteration should stop. |
116 class BaseWindowFinder { | 99 class BaseWindowFinder { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 public: | 252 public: |
270 // Returns the DockInfo for the specified point. If there is no docking | 253 // Returns the DockInfo for the specified point. If there is no docking |
271 // position for the specified point the returned DockInfo has a type of NONE. | 254 // position for the specified point the returned DockInfo has a type of NONE. |
272 static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_loc, | 255 static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_loc, |
273 const std::set<HWND>& ignore) { | 256 const std::set<HWND>& ignore) { |
274 DockToWindowFinder finder(screen_loc, ignore); | 257 DockToWindowFinder finder(screen_loc, ignore); |
275 if (!finder.result_.hwnd() || | 258 if (!finder.result_.hwnd() || |
276 !TopMostFinder::IsTopMostWindowAtPoint(finder.result_.hwnd(), | 259 !TopMostFinder::IsTopMostWindowAtPoint(finder.result_.hwnd(), |
277 finder.result_.hot_spot(), | 260 finder.result_.hot_spot(), |
278 ignore)) { | 261 ignore)) { |
279 return DockInfo(); | 262 finder.result_.set_type(DockInfo::NONE); |
280 } | 263 } |
281 return finder.result_; | 264 return finder.result_; |
282 } | 265 } |
283 | 266 |
284 protected: | 267 protected: |
285 virtual bool ShouldStopIterating(HWND hwnd) { | 268 virtual bool ShouldStopIterating(HWND hwnd) { |
286 BrowserView* window = BrowserView::GetBrowserViewForHWND(hwnd); | 269 BrowserView* window = BrowserView::GetBrowserViewForHWND(hwnd); |
287 CRect bounds; | 270 CRect bounds; |
288 if (!window || !::IsWindowVisible(hwnd) || | 271 if (!window || !::IsWindowVisible(hwnd) || |
289 !::GetWindowRect(hwnd, &bounds)) { | 272 !::GetWindowRect(hwnd, &bounds)) { |
(...skipping 11 matching lines...) Expand all Loading... |
301 return true; | 284 return true; |
302 } | 285 } |
303 return false; | 286 return false; |
304 } | 287 } |
305 | 288 |
306 private: | 289 private: |
307 DockToWindowFinder(const gfx::Point& screen_loc, | 290 DockToWindowFinder(const gfx::Point& screen_loc, |
308 const std::set<HWND>& ignore) | 291 const std::set<HWND>& ignore) |
309 : BaseWindowFinder(ignore), | 292 : BaseWindowFinder(ignore), |
310 screen_loc_(screen_loc) { | 293 screen_loc_(screen_loc) { |
311 EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, | 294 HMONITOR monitor = MonitorFromPoint(screen_loc.ToPOINT(), |
312 reinterpret_cast<LPARAM>(this)); | 295 MONITOR_DEFAULTTONULL); |
| 296 MONITORINFO monitor_info = {0}; |
| 297 monitor_info.cbSize = sizeof(MONITORINFO); |
| 298 if (monitor && GetMonitorInfo(monitor, &monitor_info)) { |
| 299 result_.set_monitor_bounds(gfx::Rect(monitor_info.rcWork)); |
| 300 EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, |
| 301 reinterpret_cast<LPARAM>(this)); |
| 302 } |
313 } | 303 } |
314 | 304 |
315 bool CheckPoint(HWND hwnd, int x, int y, DockInfo::Type type) { | 305 bool CheckPoint(HWND hwnd, int x, int y, DockInfo::Type type) { |
316 bool in_enable_area; | 306 bool in_enable_area; |
317 if (IsCloseToPoint(screen_loc_, x, y, &in_enable_area)) { | 307 if (IsCloseToPoint(screen_loc_, x, y, &in_enable_area)) { |
318 result_.set_in_enable_area(in_enable_area); | 308 result_.set_in_enable_area(in_enable_area); |
319 result_.set_hwnd(hwnd); | 309 result_.set_hwnd(hwnd); |
320 result_.set_type(type); | 310 result_.set_type(type); |
321 result_.set_hot_spot(gfx::Point(x, y)); | 311 result_.set_hot_spot(gfx::Point(x, y)); |
322 return true; | 312 // Only show the hotspot if the monitor contains the bounds of the popup |
| 313 // window. Otherwise we end with a weird situation where the popup window |
| 314 // isn't completely visible. |
| 315 return result_.monitor_bounds().Contains(result_.GetPopupRect()); |
323 } | 316 } |
324 return false; | 317 return false; |
325 } | 318 } |
326 | 319 |
327 // The location to look for. | 320 // The location to look for. |
328 gfx::Point screen_loc_; | 321 gfx::Point screen_loc_; |
329 | 322 |
330 // The resulting DockInfo. | 323 // The resulting DockInfo. |
331 DockInfo result_; | 324 DockInfo result_; |
332 | 325 |
333 DISALLOW_COPY_AND_ASSIGN(DockToWindowFinder); | 326 DISALLOW_COPY_AND_ASSIGN(DockToWindowFinder); |
334 }; | 327 }; |
335 | 328 |
336 } // namespace | 329 } // namespace |
337 | 330 |
338 // DockInfo ------------------------------------------------------------------- | 331 // DockInfo ------------------------------------------------------------------- |
339 | 332 |
| 333 // static |
340 DockInfo DockInfo::GetDockInfoAtPoint(const gfx::Point& screen_point, | 334 DockInfo DockInfo::GetDockInfoAtPoint(const gfx::Point& screen_point, |
341 const std::set<HWND>& ignore) { | 335 const std::set<HWND>& ignore) { |
342 // Try docking to a window first. | 336 // Try docking to a window first. |
343 DockInfo info = DockToWindowFinder::GetDockInfoAtPoint(screen_point, ignore); | 337 DockInfo info = DockToWindowFinder::GetDockInfoAtPoint(screen_point, ignore); |
344 | |
345 HMONITOR monitor = MonitorFromPoint(screen_point.ToPOINT(), | |
346 MONITOR_DEFAULTTONULL); | |
347 MONITORINFO monitor_info = {0}; | |
348 monitor_info.cbSize = sizeof(MONITORINFO); | |
349 if (!monitor || !GetMonitorInfo(monitor, &monitor_info)) { | |
350 info.type_ = NONE; | |
351 return info; | |
352 } | |
353 info.monitor_bounds_ = gfx::Rect(monitor_info.rcWork); | |
354 | |
355 if (info.type() != DockInfo::NONE) | 338 if (info.type() != DockInfo::NONE) |
356 return info; | 339 return info; |
357 | 340 |
358 // No window relative positions. Try monitor relative positions. | 341 // No window relative positions. Try monitor relative positions. |
359 RECT& m_bounds = monitor_info.rcWork; | 342 const gfx::Rect& m_bounds = info.monitor_bounds(); |
360 int mid_x = (m_bounds.left + m_bounds.right) / 2; | 343 int mid_x = m_bounds.x() + m_bounds.width() / 2; |
361 int mid_y = (m_bounds.top + m_bounds.bottom) / 2; | 344 int mid_y = m_bounds.y() + m_bounds.height() / 2; |
362 | 345 |
363 bool result = | 346 bool result = |
364 info.CheckMonitorPoint(monitor, screen_point, mid_x, m_bounds.top, | 347 info.CheckMonitorPoint(screen_point, mid_x, m_bounds.y(), |
365 DockInfo::MAXIMIZE) || | 348 DockInfo::MAXIMIZE) || |
366 info.CheckMonitorPoint(monitor, screen_point, mid_x, m_bounds.bottom, | 349 info.CheckMonitorPoint(screen_point, mid_x, m_bounds.bottom(), |
367 DockInfo::BOTTOM_HALF) || | 350 DockInfo::BOTTOM_HALF) || |
368 info.CheckMonitorPoint(monitor, screen_point, m_bounds.left, mid_y, | 351 info.CheckMonitorPoint(screen_point, m_bounds.x(), mid_y, |
369 DockInfo::LEFT_HALF) || | 352 DockInfo::LEFT_HALF) || |
370 info.CheckMonitorPoint(monitor, screen_point, m_bounds.right, mid_y, | 353 info.CheckMonitorPoint(screen_point, m_bounds.right(), mid_y, |
371 DockInfo::RIGHT_HALF); | 354 DockInfo::RIGHT_HALF); |
372 | 355 |
373 return info; | 356 return info; |
374 } | 357 } |
375 | 358 |
| 359 // static |
| 360 int DockInfo::popup_width() { |
| 361 return kPopupWidth; |
| 362 } |
| 363 |
| 364 // static |
| 365 int DockInfo::popup_height() { |
| 366 return kPopupHeight; |
| 367 } |
| 368 |
376 HWND DockInfo::GetLocalProcessWindowAtPoint(const gfx::Point& screen_point, | 369 HWND DockInfo::GetLocalProcessWindowAtPoint(const gfx::Point& screen_point, |
377 const std::set<HWND>& ignore) { | 370 const std::set<HWND>& ignore) { |
378 return | 371 return |
379 LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore); | 372 LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore); |
380 } | 373 } |
381 | 374 |
382 bool DockInfo::IsValidForPoint(const gfx::Point& screen_point) { | 375 bool DockInfo::IsValidForPoint(const gfx::Point& screen_point) { |
383 if (type_ == NONE) | 376 if (type_ == NONE) |
384 return false; | 377 return false; |
385 | 378 |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 // We're docking relative to another window, we need to make sure the | 495 // We're docking relative to another window, we need to make sure the |
503 // window we're docking to isn't maximized. | 496 // window we're docking to isn't maximized. |
504 ShowWindow(hwnd_, SW_RESTORE | SW_SHOWNA); | 497 ShowWindow(hwnd_, SW_RESTORE | SW_SHOWNA); |
505 } | 498 } |
506 ::SetWindowPos(hwnd_, HWND_TOP, other_window_bounds.x(), | 499 ::SetWindowPos(hwnd_, HWND_TOP, other_window_bounds.x(), |
507 other_window_bounds.y(), other_window_bounds.width(), | 500 other_window_bounds.y(), other_window_bounds.width(), |
508 other_window_bounds.height(), | 501 other_window_bounds.height(), |
509 SWP_NOACTIVATE | SWP_NOOWNERZORDER); | 502 SWP_NOACTIVATE | SWP_NOOWNERZORDER); |
510 } | 503 } |
511 | 504 |
512 bool DockInfo::CheckMonitorPoint(HMONITOR monitor, | 505 gfx::Rect DockInfo::GetPopupRect() const { |
513 const gfx::Point& screen_loc, | 506 int x = hot_spot_.x() - popup_width() / 2; |
| 507 int y = hot_spot_.y() - popup_height() / 2; |
| 508 switch (type_) { |
| 509 case LEFT_OF_WINDOW: |
| 510 case RIGHT_OF_WINDOW: |
| 511 case TOP_OF_WINDOW: |
| 512 case BOTTOM_OF_WINDOW: { |
| 513 // Constrain the popup to the monitor's bounds. |
| 514 gfx::Rect ideal_bounds(x, y, popup_width(), popup_height()); |
| 515 ideal_bounds = ideal_bounds.AdjustToFit(monitor_bounds_); |
| 516 return ideal_bounds; |
| 517 } |
| 518 case DockInfo::MAXIMIZE: |
| 519 y += popup_height() / 2; |
| 520 break; |
| 521 case DockInfo::LEFT_HALF: |
| 522 x += popup_width() / 2; |
| 523 break; |
| 524 case DockInfo::RIGHT_HALF: |
| 525 x -= popup_width() / 2; |
| 526 break; |
| 527 case DockInfo::BOTTOM_HALF: |
| 528 y -= popup_height() / 2; |
| 529 break; |
| 530 |
| 531 default: |
| 532 NOTREACHED(); |
| 533 } |
| 534 return gfx::Rect(x, y, popup_width(), popup_height()); |
| 535 } |
| 536 |
| 537 bool DockInfo::CheckMonitorPoint(const gfx::Point& screen_loc, |
514 int x, | 538 int x, |
515 int y, | 539 int y, |
516 Type type) { | 540 Type type) { |
517 if (IsCloseToMonitorPoint(screen_loc, x, y, type, &in_enable_area_) && | 541 if (IsCloseToMonitorPoint(screen_loc, x, y, type, &in_enable_area_)) { |
518 (type != MAXIMIZE || | |
519 !IsMaximizedTabbedBrowserOnMonitor(monitor))) { | |
520 hot_spot_.SetPoint(x, y); | 542 hot_spot_.SetPoint(x, y); |
521 type_ = type; | 543 type_ = type; |
522 return true; | 544 return true; |
523 } | 545 } |
524 return false; | 546 return false; |
525 } | 547 } |
OLD | NEW |