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/linux/app_list_linux.h" 6 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" 12 13// static 14AppListPositioner::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(); 24 25 int winning_margin = 0; 26 AppListPositioner::ScreenEdge winning_edge = 27 AppListPositioner::SCREEN_EDGE_UNKNOWN; 28 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; 32 } 33 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; 37 } 38 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; 42 } 43 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; 47 } 48 49 return winning_edge; 50} 51 52// static 53gfx::Point AppListLinux::FindAnchorPoint(const gfx::Size& view_size, 54 const gfx::Display& display, 55 const gfx::Point& cursor, 56 AppListPositioner::ScreenEdge edge, 57 bool center_window) { 58 AppListPositioner positioner(display, view_size, 0); 59 60 // Special case for app list in the center of the screen. 61 if (center_window) 62 return positioner.GetAnchorPointForScreenCenter(); 63 64 gfx::Point anchor; 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 67 // position. 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); 72 } 73 74 int snap_distance = edge == AppListPositioner::SCREEN_EDGE_BOTTOM || 75 edge == AppListPositioner::SCREEN_EDGE_TOP 76 ? view_size.height() 77 : view_size.width(); 78 if (positioner.GetCursorDistanceFromShelf(edge, cursor) > snap_distance) 79 return positioner.GetAnchorPointForShelfCorner(edge); 80 81 return positioner.GetAnchorPointForShelfCursor(edge, cursor); 82} 83 84// static 85void AppListLinux::MoveNearCursor(app_list::AppListView* view) { 86 gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(); 87 gfx::Screen* screen = 88 gfx::Screen::GetScreenFor(view->GetWidget()->GetNativeView()); 89 gfx::Display display = screen->GetDisplayNearestPoint(cursor); 90 91 view->SetBubbleArrow(views::BubbleBorder::FLOAT); 92 93 AppListPositioner::ScreenEdge edge; 94#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 95 // In the Unity desktop environment, special case SCREEN_EDGE_LEFT. It is 96 // always on the left side in Unity, but ShelfLocationInDisplay will not 97 // detect this if the shelf is hidden. 98 // TODO(mgiuca): Apply this special case in Gnome Shell also. The same logic 99 // applies, but we currently have no way to detect whether Gnome Shell is 100 // running. 101 views::LinuxUI* ui = views::LinuxUI::instance(); 102 if (ui && ui->UnityIsRunning()) 103 edge = AppListPositioner::SCREEN_EDGE_LEFT; 104 else 105#endif 106 edge = ShelfLocationInDisplay(display); 107 view->SetAnchorPoint(FindAnchorPoint(view->GetPreferredSize(), 108 display, 109 cursor, 110 edge, 111 view->ShouldCenterWindow())); 112} 113