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.
5 #include "chrome/browser/ui/views/app_list/linux/app_list_linux.h"
7 #include "ui/app_list/app_list_switches.h"
8 #include "ui/app_list/views/app_list_view.h"
9 #include "ui/gfx/screen.h"
10 #include "ui/views/linux_ui/linux_ui.h"
11 #include "ui/views/widget/widget.h"
14 AppListPositioner::ScreenEdge AppListLinux::ShelfLocationInDisplay(
15 const gfx::Display& display) {
16 // On Linux, it is difficult to find the shelf (due to the large variety of
17 // desktop environments). The shelf can usually be found on the edge where the
18 // display edge and work area do not match up, but there can be more than one
19 // such edge. The shelf is assumed to be on the side of the screen with the
20 // largest delta between the display edge and the work area edge. Ties are
21 // broken in the order: top, left, right, bottom.
22 const gfx::Rect work_area = display.work_area();
23 const gfx::Rect display_bounds = display.bounds();
25 int winning_margin = 0;
26 AppListPositioner::ScreenEdge winning_edge =
27 AppListPositioner::SCREEN_EDGE_UNKNOWN;
29 if (work_area.y() - display_bounds.y() > winning_margin) {
30 winning_margin = work_area.y() - display_bounds.y();
31 winning_edge = AppListPositioner::SCREEN_EDGE_TOP;
34 if (work_area.x() - display_bounds.x() > winning_margin) {
35 winning_margin = work_area.x() - display_bounds.x();
36 winning_edge = AppListPositioner::SCREEN_EDGE_LEFT;
39 if (display_bounds.right() - work_area.right() > winning_margin) {
40 winning_margin = display_bounds.right() - work_area.right();
41 winning_edge = AppListPositioner::SCREEN_EDGE_RIGHT;
44 if (display_bounds.bottom() - work_area.bottom() > winning_margin) {
45 winning_margin = display_bounds.bottom() - work_area.bottom();
46 winning_edge = AppListPositioner::SCREEN_EDGE_BOTTOM;
53 gfx::Point AppListLinux::FindAnchorPoint(const gfx::Size& view_size,
54 const gfx::Display& display,
55 const gfx::Point& cursor,
56 AppListPositioner::ScreenEdge edge,
58 AppListPositioner positioner(display, view_size, 0);
60 // Special case for app list in the center of the screen.
62 return positioner.GetAnchorPointForScreenCenter();
65 // Snap to the shelf edge. If the cursor is greater than the window
66 // width/height away, anchor to the corner. Otherwise, anchor to the cursor
68 if (edge == AppListPositioner::SCREEN_EDGE_UNKNOWN) {
69 // If we can't find the shelf, snap to the top left.
70 return positioner.GetAnchorPointForScreenCorner(
71 AppListPositioner::SCREEN_CORNER_TOP_LEFT);
74 int snap_distance = edge == AppListPositioner::SCREEN_EDGE_BOTTOM ||
75 edge == AppListPositioner::SCREEN_EDGE_TOP
78 if (positioner.GetCursorDistanceFromShelf(edge, cursor) > snap_distance)
79 return positioner.GetAnchorPointForShelfCorner(edge);
81 return positioner.GetAnchorPointForShelfCursor(edge, cursor);
85 void AppListLinux::MoveNearCursor(app_list::AppListView* view) {
86 gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
88 gfx::Screen::GetScreenFor(view->GetWidget()->GetNativeView());
89 gfx::Display display = screen->GetDisplayNearestPoint(cursor);
91 view->SetBubbleArrow(views::BubbleBorder::FLOAT);
93 // In the Unity desktop environment, special case SCREEN_EDGE_LEFT. It is
94 // always on the left side in Unity, but ShelfLocationInDisplay will not
95 // detect this if the shelf is hidden.
96 // TODO(mgiuca): Apply this special case in Gnome Shell also. The same logic
97 // applies, but we currently have no way to detect whether Gnome Shell is
99 views::LinuxUI* ui = views::LinuxUI::instance();
100 AppListPositioner::ScreenEdge edge;
101 if (ui && ui->UnityIsRunning())
102 edge = AppListPositioner::SCREEN_EDGE_LEFT;
104 edge = ShelfLocationInDisplay(display);
105 view->SetAnchorPoint(FindAnchorPoint(view->GetPreferredSize(),
109 view->ShouldCenterWindow()));