1// Copyright 2013 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/app_list/win/app_list_win.h"
6
7#include "chrome/browser/ui/app_list/app_list_positioner.h"
8#include "ui/app_list/app_list_switches.h"
9#include "ui/app_list/views/app_list_view.h"
10#include "ui/gfx/screen.h"
11#include "ui/views/widget/widget.h"
12
13namespace {
14
15static const wchar_t kTrayClassName[] = L"Shell_TrayWnd";
16
17// If the mouse cursor is less than this distance, in pixels, away from the
18// taskbar, it is considered to be in the taskbar for the purpose of anchoring.
19static const int kSnapDistance = 50;
20
21// The minimum distance, in pixels, to position the app list from the taskbar or
22// edge of screen.
23static const int kMinDistanceFromEdge = 3;
24
25// Utility methods for showing the app list.
26// Attempts to find the bounds of the Windows taskbar. Returns true on success.
27// |rect| is in screen coordinates. If the taskbar is in autohide mode and is
28// not visible, |rect| will be outside the current monitor's bounds, except for
29// one pixel of overlap where the edge of the taskbar is shown.
30bool GetTaskbarRect(gfx::Rect* rect) {
31  HWND taskbar_hwnd = FindWindow(kTrayClassName, NULL);
32  if (!taskbar_hwnd)
33    return false;
34
35  RECT win_rect;
36  if (!GetWindowRect(taskbar_hwnd, &win_rect))
37    return false;
38
39  *rect = gfx::Rect(win_rect);
40  return true;
41}
42
43}  // namespace
44
45// static
46gfx::Point AppListWin::FindAnchorPoint(const gfx::Size& view_size,
47                                       const gfx::Display& display,
48                                       const gfx::Point& cursor,
49                                       const gfx::Rect& taskbar_rect,
50                                       bool center_window) {
51  AppListPositioner positioner(display, view_size, kMinDistanceFromEdge);
52
53  // Subtract the taskbar area since the display's default work_area will not
54  // subtract it if the taskbar is set to auto-hide, and the app list should
55  // never overlap the taskbar.
56  positioner.WorkAreaSubtract(taskbar_rect);
57
58  // Special case for app list in the center of the screen.
59  if (center_window)
60    return positioner.GetAnchorPointForScreenCenter();
61
62  // Find which edge of the screen the taskbar is attached to.
63  AppListPositioner::ScreenEdge edge = positioner.GetShelfEdge(taskbar_rect);
64
65  // Snap to the taskbar edge. If the cursor is greater than kSnapDistance away,
66  // anchor to the corner. Otherwise, anchor to the cursor position.
67  gfx::Point anchor;
68  if (edge == AppListPositioner::SCREEN_EDGE_UNKNOWN) {
69    // If we can't find the taskbar, snap to the bottom left.
70    return positioner.GetAnchorPointForScreenCorner(
71        AppListPositioner::SCREEN_CORNER_BOTTOM_LEFT);
72  }
73
74  if (positioner.GetCursorDistanceFromShelf(edge, cursor) > kSnapDistance)
75    return positioner.GetAnchorPointForShelfCorner(edge);
76
77  return positioner.GetAnchorPointForShelfCursor(edge, cursor);
78}
79
80// static
81void AppListWin::MoveNearCursor(app_list::AppListView* view) {
82  gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
83  gfx::Screen* screen =
84      gfx::Screen::GetScreenFor(view->GetWidget()->GetNativeView());
85  gfx::Display display = screen->GetDisplayNearestPoint(cursor);
86
87  view->SetBubbleArrow(views::BubbleBorder::FLOAT);
88  gfx::Rect taskbar_rect;
89  GetTaskbarRect(&taskbar_rect);
90  view->SetAnchorPoint(FindAnchorPoint(view->GetPreferredSize(),
91                                       display,
92                                       cursor,
93                                       taskbar_rect,
94                                       view->ShouldCenterWindow()));
95}
96