app_list_linux.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 "base/command_line.h"
8#include "base/location.h"
9#include "base/single_thread_task_runner.h"
10#include "base/thread_task_runner_handle.h"
11#include "chrome/browser/profiles/profile.h"
12#include "chrome/browser/ui/app_list/app_list_positioner.h"
13#include "ui/app_list/app_list_switches.h"
14#include "ui/app_list/views/app_list_view.h"
15#include "ui/gfx/screen.h"
16#include "ui/views/widget/widget.h"
17
18AppListLinux::AppListLinux(app_list::AppListView* view,
19                           const base::Closure& on_should_dismiss)
20    : view_(view),
21      window_icon_updated_(false),
22      on_should_dismiss_(on_should_dismiss) {
23  view_->AddObserver(this);
24}
25
26AppListLinux::~AppListLinux() {
27  view_->RemoveObserver(this);
28}
29
30// static
31gfx::Point AppListLinux::FindAnchorPoint(const gfx::Size& view_size,
32                                         const gfx::Display& display,
33                                         const gfx::Point& cursor,
34                                         AppListPositioner::ScreenEdge edge) {
35  AppListPositioner positioner(display, view_size, 0);
36
37  // The experimental app list is placed in the center of the screen.
38  if (app_list::switches::IsExperimentalAppListPositionEnabled())
39    return positioner.GetAnchorPointForScreenCenter();
40
41  gfx::Point anchor;
42  // Snap to the shelf edge. If the cursor is greater than the window
43  // width/height away, anchor to the corner. Otherwise, anchor to the cursor
44  // position.
45  if (edge == AppListPositioner::SCREEN_EDGE_UNKNOWN) {
46    // If we can't find the shelf, snap to the top left.
47    return positioner.GetAnchorPointForScreenCorner(
48        AppListPositioner::SCREEN_CORNER_TOP_LEFT);
49  }
50
51  int snap_distance = edge == AppListPositioner::SCREEN_EDGE_BOTTOM ||
52                              edge == AppListPositioner::SCREEN_EDGE_TOP
53                          ? view_size.height()
54                          : view_size.width();
55  if (positioner.GetCursorDistanceFromShelf(edge, cursor) > snap_distance)
56    return positioner.GetAnchorPointForShelfCorner(edge);
57
58  return positioner.GetAnchorPointForShelfCursor(edge, cursor);
59}
60
61void AppListLinux::Show() {
62  view_->GetWidget()->Show();
63  if (!window_icon_updated_) {
64    view_->GetWidget()->GetTopLevelWidget()->UpdateWindowIcon();
65    window_icon_updated_ = true;
66  }
67  view_->GetWidget()->Activate();
68}
69
70void AppListLinux::Hide() {
71  view_->GetWidget()->Hide();
72}
73
74void AppListLinux::MoveNearCursor() {
75  gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
76  gfx::Screen* screen =
77      gfx::Screen::GetScreenFor(view_->GetWidget()->GetNativeView());
78  gfx::Display display = screen->GetDisplayNearestPoint(cursor);
79
80  view_->SetBubbleArrow(views::BubbleBorder::FLOAT);
81  // Find which edge of the screen the shelf is attached to. For now, just
82  // assume Ubuntu Unity (fixed to left edge).
83  // TODO(mgiuca): Support other window manager configurations, and multiple
84  // monitors (where the current display may not have an edge).
85  AppListPositioner::ScreenEdge edge = AppListPositioner::SCREEN_EDGE_LEFT;
86  view_->SetAnchorPoint(FindAnchorPoint(view_->GetPreferredSize(), display,
87                                        cursor, edge));
88}
89
90bool AppListLinux::IsVisible() {
91  return view_->GetWidget()->IsVisible();
92}
93
94void AppListLinux::Prerender() {
95  view_->Prerender();
96}
97
98void AppListLinux::ReactivateOnNextFocusLoss() {
99  // This is only used on Windows 8, so we ignore it on Linux.
100}
101
102gfx::NativeWindow AppListLinux::GetWindow() {
103  return view_->GetWidget()->GetNativeWindow();
104}
105
106void AppListLinux::SetProfile(Profile* profile) {
107  view_->SetProfileByPath(profile->GetPath());
108}
109
110void AppListLinux::OnActivationChanged(
111    views::Widget* /*widget*/, bool active) {
112  if (active)
113    return;
114
115  // Call |on_should_dismiss_| asynchronously. This must be done asynchronously
116  // or our caller will crash, as it expects the app list to remain alive.
117  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, on_should_dismiss_);
118}
119