blob: 290fe0f066990d1d5ab01599817125f86f848ee7 [file] [log] [blame]
James Cookb0bf8e82017-04-09 17:01:441// Copyright 2016 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 "ash/shelf/shelf_controller.h"
6
msw19b30c2c2017-06-01 03:21:407#include "ash/public/cpp/config.h"
8#include "ash/public/cpp/remote_shelf_item_delegate.h"
James Cookb0bf8e82017-04-09 17:01:449#include "ash/root_window_controller.h"
jamescook788b4fc2017-05-18 16:16:0610#include "ash/session/session_controller.h"
James Cookb0bf8e82017-04-09 17:01:4411#include "ash/shelf/app_list_shelf_item_delegate.h"
James Cook840177e2017-05-25 02:20:0112#include "ash/shelf/shelf.h"
James Cookb0bf8e82017-04-09 17:01:4413#include "ash/shell.h"
msw109806d2017-06-02 20:11:5714#include "ash/strings/grit/ash_strings.h"
msw19b30c2c2017-06-01 03:21:4015#include "base/auto_reset.h"
James Cookb0bf8e82017-04-09 17:01:4416#include "base/strings/utf_string_conversions.h"
msw109806d2017-06-02 20:11:5717#include "ui/base/l10n/l10n_util.h"
James Cookb0bf8e82017-04-09 17:01:4418#include "ui/base/models/simple_menu_model.h"
James Cookb0bf8e82017-04-09 17:01:4419#include "ui/display/display.h"
20#include "ui/display/screen.h"
James Cookb0bf8e82017-04-09 17:01:4421
22namespace ash {
23
24namespace {
25
James Cook840177e2017-05-25 02:20:0126// Returns the Shelf instance for the display with the given |display_id|.
27Shelf* GetShelfForDisplay(int64_t display_id) {
James Cookb0bf8e82017-04-09 17:01:4428 // The controller may be null for invalid ids or for displays being removed.
29 RootWindowController* root_window_controller =
30 Shell::GetRootWindowControllerWithDisplayId(display_id);
jamescookaa9f49f2017-05-30 20:48:4531 return root_window_controller ? root_window_controller->shelf() : nullptr;
James Cookb0bf8e82017-04-09 17:01:4432}
33
34} // namespace
35
36ShelfController::ShelfController() {
msw109806d2017-06-02 20:11:5737 // Set the delegate and title string for the app list item.
msw19b30c2c2017-06-01 03:21:4038 model_.SetShelfItemDelegate(ShelfID(kAppListId),
39 base::MakeUnique<AppListShelfItemDelegate>());
msw109806d2017-06-02 20:11:5740 DCHECK_EQ(0, model_.ItemIndexByID(ShelfID(kAppListId)));
41 ShelfItem item = model_.items()[0];
42 item.title = l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE);
43 model_.Set(0, item);
44
msw19b30c2c2017-06-01 03:21:4045 model_.AddObserver(this);
James Cookb0bf8e82017-04-09 17:01:4446}
47
msw19b30c2c2017-06-01 03:21:4048ShelfController::~ShelfController() {
49 model_.RemoveObserver(this);
50}
James Cookb0bf8e82017-04-09 17:01:4451
52void ShelfController::BindRequest(mojom::ShelfControllerRequest request) {
53 bindings_.AddBinding(this, std::move(request));
54}
55
James Cook840177e2017-05-25 02:20:0156void ShelfController::NotifyShelfInitialized(Shelf* shelf) {
James Cookb0bf8e82017-04-09 17:01:4457 // Notify observers, Chrome will set alignment and auto-hide from prefs.
varkha6b016b0f2017-05-26 16:14:1858 display::Display display =
59 display::Screen::GetScreen()->GetDisplayNearestWindow(shelf->GetWindow());
60 int64_t display_id = display.id();
James Cookb0bf8e82017-04-09 17:01:4461 observers_.ForAllPtrs([display_id](mojom::ShelfObserver* observer) {
jamescook788b4fc2017-05-18 16:16:0662 observer->OnShelfInitialized(display_id);
James Cookb0bf8e82017-04-09 17:01:4463 });
64}
65
James Cook840177e2017-05-25 02:20:0166void ShelfController::NotifyShelfAlignmentChanged(Shelf* shelf) {
James Cookb0bf8e82017-04-09 17:01:4467 ShelfAlignment alignment = shelf->alignment();
varkha6b016b0f2017-05-26 16:14:1868 display::Display display =
69 display::Screen::GetScreen()->GetDisplayNearestWindow(shelf->GetWindow());
70 int64_t display_id = display.id();
James Cookb0bf8e82017-04-09 17:01:4471 observers_.ForAllPtrs(
72 [alignment, display_id](mojom::ShelfObserver* observer) {
73 observer->OnAlignmentChanged(alignment, display_id);
74 });
75}
76
James Cook840177e2017-05-25 02:20:0177void ShelfController::NotifyShelfAutoHideBehaviorChanged(Shelf* shelf) {
James Cookb0bf8e82017-04-09 17:01:4478 ShelfAutoHideBehavior behavior = shelf->auto_hide_behavior();
varkha6b016b0f2017-05-26 16:14:1879 display::Display display =
80 display::Screen::GetScreen()->GetDisplayNearestWindow(shelf->GetWindow());
81 int64_t display_id = display.id();
James Cookb0bf8e82017-04-09 17:01:4482 observers_.ForAllPtrs([behavior, display_id](mojom::ShelfObserver* observer) {
83 observer->OnAutoHideBehaviorChanged(behavior, display_id);
84 });
85}
86
87void ShelfController::AddObserver(
88 mojom::ShelfObserverAssociatedPtrInfo observer) {
89 mojom::ShelfObserverAssociatedPtr observer_ptr;
90 observer_ptr.Bind(std::move(observer));
msw19b30c2c2017-06-01 03:21:4091
92 if (Shell::GetAshConfig() == Config::MASH) {
93 // Mash synchronizes two ShelfModel instances, owned by Ash and Chrome.
94 // Notify Chrome of existing ShelfModel items created by Ash.
95 for (int i = 0; i < model_.item_count(); ++i) {
96 const ShelfItem& item = model_.items()[i];
97 observer_ptr->OnShelfItemAdded(i, item);
98 ShelfItemDelegate* delegate = model_.GetShelfItemDelegate(item.id);
Michael Wasserman78b6f3e2017-07-20 19:51:2099 if (delegate) {
100 observer_ptr->OnShelfItemDelegateChanged(
101 item.id, delegate->CreateInterfacePtrAndBind());
102 }
msw19b30c2c2017-06-01 03:21:40103 }
104 }
105
James Cookb0bf8e82017-04-09 17:01:44106 observers_.AddPtr(std::move(observer_ptr));
107}
108
109void ShelfController::SetAlignment(ShelfAlignment alignment,
110 int64_t display_id) {
James Cook840177e2017-05-25 02:20:01111 Shelf* shelf = GetShelfForDisplay(display_id);
jamescook788b4fc2017-05-18 16:16:06112 // TODO(jamescook): The session state check should not be necessary, but
James Cookb0bf8e82017-04-09 17:01:44113 // otherwise this wrongly tries to set the alignment on a secondary display
jamescook788b4fc2017-05-18 16:16:06114 // during login before the ShelfLockingManager is created.
115 if (shelf && Shell::Get()->session_controller()->IsActiveUserSessionStarted())
James Cookb0bf8e82017-04-09 17:01:44116 shelf->SetAlignment(alignment);
117}
118
119void ShelfController::SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide,
120 int64_t display_id) {
James Cook840177e2017-05-25 02:20:01121 Shelf* shelf = GetShelfForDisplay(display_id);
jamescook788b4fc2017-05-18 16:16:06122 // TODO(jamescook): The session state check should not be necessary, but
James Cookb0bf8e82017-04-09 17:01:44123 // otherwise this wrongly tries to set auto-hide state on a secondary display
jamescook788b4fc2017-05-18 16:16:06124 // during login.
125 if (shelf && Shell::Get()->session_controller()->IsActiveUserSessionStarted())
James Cookb0bf8e82017-04-09 17:01:44126 shelf->SetAutoHideBehavior(auto_hide);
127}
128
msw19b30c2c2017-06-01 03:21:40129void ShelfController::AddShelfItem(int32_t index, const ShelfItem& item) {
msw70ac45f2017-06-05 02:02:45130 DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << " Unexpected model sync";
131 DCHECK(!applying_remote_shelf_model_changes_) << " Unexpected model change";
msw19b30c2c2017-06-01 03:21:40132 index = index < 0 ? model_.item_count() : index;
Julien Brianceau293917a82017-08-01 17:32:59133 DCHECK_GT(index, 0) << " Items can not precede the AppList";
msw70ac45f2017-06-05 02:02:45134 DCHECK_LE(index, model_.item_count()) << " Index out of bounds";
msw19b30c2c2017-06-01 03:21:40135 index = std::min(std::max(index, 1), model_.item_count());
136 base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
137 model_.AddAt(index, item);
James Cookb0bf8e82017-04-09 17:01:44138}
139
msw19b30c2c2017-06-01 03:21:40140void ShelfController::RemoveShelfItem(const ShelfID& id) {
msw70ac45f2017-06-05 02:02:45141 DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << " Unexpected model sync";
142 DCHECK(!applying_remote_shelf_model_changes_) << " Unexpected model change";
msw19b30c2c2017-06-01 03:21:40143 const int index = model_.ItemIndexByID(id);
msw70ac45f2017-06-05 02:02:45144 DCHECK_GE(index, 0) << " No item found with the id: " << id;
145 DCHECK_NE(index, 0) << " The AppList shelf item cannot be removed";
msw19b30c2c2017-06-01 03:21:40146 if (index <= 0)
147 return;
148 base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
149 model_.RemoveItemAt(index);
James Cookb0bf8e82017-04-09 17:01:44150}
151
msw19b30c2c2017-06-01 03:21:40152void ShelfController::MoveShelfItem(const ShelfID& id, int32_t index) {
msw70ac45f2017-06-05 02:02:45153 DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << " Unexpected model sync";
154 DCHECK(!applying_remote_shelf_model_changes_) << " Unexpected model change";
msw19b30c2c2017-06-01 03:21:40155 const int current_index = model_.ItemIndexByID(id);
msw70ac45f2017-06-05 02:02:45156 DCHECK_GE(current_index, 0) << " No item found with the id: " << id;
157 DCHECK_NE(current_index, 0) << " The AppList shelf item cannot be moved";
msw19b30c2c2017-06-01 03:21:40158 if (current_index <= 0)
159 return;
Julien Brianceau293917a82017-08-01 17:32:59160 DCHECK_GT(index, 0) << " Items can not precede the AppList";
msw70ac45f2017-06-05 02:02:45161 DCHECK_LT(index, model_.item_count()) << " Index out of bounds";
msw19b30c2c2017-06-01 03:21:40162 index = std::min(std::max(index, 1), model_.item_count() - 1);
msw70ac45f2017-06-05 02:02:45163 DCHECK_NE(current_index, index) << " The item is already at the given index";
msw19b30c2c2017-06-01 03:21:40164 if (current_index == index)
165 return;
166 base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
167 model_.Move(current_index, index);
168}
169
170void ShelfController::UpdateShelfItem(const ShelfItem& item) {
msw70ac45f2017-06-05 02:02:45171 DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << " Unexpected model sync";
172 DCHECK(!applying_remote_shelf_model_changes_) << " Unexpected model change";
msw19b30c2c2017-06-01 03:21:40173 const int index = model_.ItemIndexByID(item.id);
msw70ac45f2017-06-05 02:02:45174 DCHECK_GE(index, 0) << " No item found with the id: " << item.id;
msw19b30c2c2017-06-01 03:21:40175 if (index < 0)
176 return;
177 base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
178 model_.Set(index, item);
179}
180
181void ShelfController::SetShelfItemDelegate(
182 const ShelfID& id,
183 mojom::ShelfItemDelegatePtr delegate) {
msw70ac45f2017-06-05 02:02:45184 DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << " Unexpected model sync";
185 DCHECK(!applying_remote_shelf_model_changes_) << " Unexpected model change";
msw19b30c2c2017-06-01 03:21:40186 base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
187 if (delegate.is_bound())
188 model_.SetShelfItemDelegate(
189 id, base::MakeUnique<RemoteShelfItemDelegate>(id, std::move(delegate)));
190 else
191 model_.SetShelfItemDelegate(id, nullptr);
192}
193
194void ShelfController::ShelfItemAdded(int index) {
195 if (applying_remote_shelf_model_changes_ ||
196 Shell::GetAshConfig() != Config::MASH) {
197 return;
198 }
199
200 const ShelfItem& item = model_.items()[index];
201 observers_.ForAllPtrs([index, item](mojom::ShelfObserver* observer) {
202 observer->OnShelfItemAdded(index, item);
203 });
204}
205
206void ShelfController::ShelfItemRemoved(int index, const ShelfItem& old_item) {
207 if (applying_remote_shelf_model_changes_ ||
208 Shell::GetAshConfig() != Config::MASH) {
209 return;
210 }
211
212 observers_.ForAllPtrs([old_item](mojom::ShelfObserver* observer) {
213 observer->OnShelfItemRemoved(old_item.id);
214 });
215}
216
217void ShelfController::ShelfItemMoved(int start_index, int target_index) {
218 if (applying_remote_shelf_model_changes_ ||
219 Shell::GetAshConfig() != Config::MASH) {
220 return;
221 }
222
223 const ShelfItem& item = model_.items()[target_index];
224 observers_.ForAllPtrs([item, target_index](mojom::ShelfObserver* observer) {
225 observer->OnShelfItemMoved(item.id, target_index);
226 });
227}
228
229void ShelfController::ShelfItemChanged(int index, const ShelfItem& old_item) {
230 if (applying_remote_shelf_model_changes_ ||
231 Shell::GetAshConfig() != Config::MASH) {
232 return;
233 }
234
235 const ShelfItem& item = model_.items()[index];
236 observers_.ForAllPtrs([item](mojom::ShelfObserver* observer) {
237 observer->OnShelfItemUpdated(item);
238 });
239}
240
241void ShelfController::ShelfItemDelegateChanged(const ShelfID& id,
242 ShelfItemDelegate* delegate) {
243 if (applying_remote_shelf_model_changes_ ||
244 Shell::GetAshConfig() != Config::MASH) {
245 return;
246 }
247
248 observers_.ForAllPtrs([id, delegate](mojom::ShelfObserver* observer) {
249 observer->OnShelfItemDelegateChanged(
250 id, delegate ? delegate->CreateInterfacePtrAndBind()
251 : mojom::ShelfItemDelegatePtr());
252 });
James Cookb0bf8e82017-04-09 17:01:44253}
254
255} // namespace ash