1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/views/app_list/linux/app_list_linux.h" 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/app_list/app_list_switches.h" 8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/app_list/views/app_list_view.h" 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/screen.h" 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/linux_ui/linux_ui.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/widget/widget.h" 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// static 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuAppListPositioner::ScreenEdge AppListLinux::ShelfLocationInDisplay( 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const gfx::Display& display) { 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // On Linux, it is difficult to find the shelf (due to the large variety of 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // desktop environments). The shelf can usually be found on the edge where the 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // display edge and work area do not match up, but there can be more than one 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // such edge. The shelf is assumed to be on the side of the screen with the 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // largest delta between the display edge and the work area edge. Ties are 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // broken in the order: top, left, right, bottom. 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const gfx::Rect work_area = display.work_area(); 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const gfx::Rect display_bounds = display.bounds(); 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu int winning_margin = 0; 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu AppListPositioner::ScreenEdge winning_edge = 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu AppListPositioner::SCREEN_EDGE_UNKNOWN; 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (work_area.y() - display_bounds.y() > winning_margin) { 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu winning_margin = work_area.y() - display_bounds.y(); 315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu winning_edge = AppListPositioner::SCREEN_EDGE_TOP; 325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (work_area.x() - display_bounds.x() > winning_margin) { 355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu winning_margin = work_area.x() - display_bounds.x(); 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu winning_edge = AppListPositioner::SCREEN_EDGE_LEFT; 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (display_bounds.right() - work_area.right() > winning_margin) { 405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu winning_margin = display_bounds.right() - work_area.right(); 415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu winning_edge = AppListPositioner::SCREEN_EDGE_RIGHT; 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (display_bounds.bottom() - work_area.bottom() > winning_margin) { 455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu winning_margin = display_bounds.bottom() - work_area.bottom(); 465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu winning_edge = AppListPositioner::SCREEN_EDGE_BOTTOM; 475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return winning_edge; 505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)gfx::Point AppListLinux::FindAnchorPoint(const gfx::Size& view_size, 54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const gfx::Display& display, 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const gfx::Point& cursor, 56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) AppListPositioner::ScreenEdge edge, 57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) bool center_window) { 58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) AppListPositioner positioner(display, view_size, 0); 59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Special case for app list in the center of the screen. 61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (center_window) 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return positioner.GetAnchorPointForScreenCenter(); 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gfx::Point anchor; 65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Snap to the shelf edge. If the cursor is greater than the window 66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // width/height away, anchor to the corner. Otherwise, anchor to the cursor 67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // position. 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (edge == AppListPositioner::SCREEN_EDGE_UNKNOWN) { 69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // If we can't find the shelf, snap to the top left. 70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return positioner.GetAnchorPointForScreenCorner( 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) AppListPositioner::SCREEN_CORNER_TOP_LEFT); 72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int snap_distance = edge == AppListPositioner::SCREEN_EDGE_BOTTOM || 75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) edge == AppListPositioner::SCREEN_EDGE_TOP 76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ? view_size.height() 77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : view_size.width(); 78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (positioner.GetCursorDistanceFromShelf(edge, cursor) > snap_distance) 79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return positioner.GetAnchorPointForShelfCorner(edge); 80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return positioner.GetAnchorPointForShelfCursor(edge, cursor); 82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// static 85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void AppListLinux::MoveNearCursor(app_list::AppListView* view) { 86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(); 87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gfx::Screen* screen = 88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) gfx::Screen::GetScreenFor(view->GetWidget()->GetNativeView()); 89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gfx::Display display = screen->GetDisplayNearestPoint(cursor); 90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) view->SetBubbleArrow(views::BubbleBorder::FLOAT); 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) AppListPositioner::ScreenEdge edge; 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // In the Unity desktop environment, special case SCREEN_EDGE_LEFT. It is 965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // always on the left side in Unity, but ShelfLocationInDisplay will not 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // detect this if the shelf is hidden. 985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // TODO(mgiuca): Apply this special case in Gnome Shell also. The same logic 995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // applies, but we currently have no way to detect whether Gnome Shell is 1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // running. 1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu views::LinuxUI* ui = views::LinuxUI::instance(); 1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (ui && ui->UnityIsRunning()) 1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu edge = AppListPositioner::SCREEN_EDGE_LEFT; 1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu else 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu edge = ShelfLocationInDisplay(display); 107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) view->SetAnchorPoint(FindAnchorPoint(view->GetPreferredSize(), 108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) display, 109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) cursor, 110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) edge, 111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) view->ShouldCenterWindow())); 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 113