Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(948)

Side by Side Diff: ash/wm/screen_pinning_controller.cc

Issue 2072853002: Implement "pinned" mode in ash. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comments Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ash/wm/screen_pinning_controller.h ('k') | ash/wm/screen_pinning_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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/wm/screen_pinning_controller.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "ash/aura/wm_window_aura.h"
11 #include "ash/common/shell_window_ids.h"
12 #include "ash/common/wm/window_state.h"
13 #include "ash/common/wm_shell_common.h"
14 #include "ash/common/wm_window.h"
15 #include "ash/common/wm_window_observer.h"
16 #include "ash/display/window_tree_host_manager.h"
17 #include "ash/shell.h"
18 #include "ash/wm/dim_window.h"
19 #include "base/auto_reset.h"
20 #include "base/logging.h"
21 #include "base/stl_util.h"
22 #include "ui/aura/window_observer.h"
23
24 namespace ash {
25 namespace {
26
27 WmWindow* CreateDimWindow(WmWindow* container) {
28 DimWindow* dim_window = new DimWindow(WmWindowAura::GetAuraWindow(container));
29 dim_window->SetDimOpacity(1); // Set whole black.
30 WmWindow* result = WmWindowAura::Get(dim_window);
31 result->SetFullscreen();
32 result->Show();
33 return result;
34 }
35
36 // Returns a list of WmWindows corresponding to SystemModalContainers,
37 // except ones whose root is shared with |pinned_window|.
38 std::vector<WmWindow*> GetSystemModalWindowsExceptPinned(
39 WmWindow* pinned_window) {
40 WmWindow* pinned_root = pinned_window->GetRootWindow();
41
42 std::vector<WmWindow*> result;
43 for (WmWindow* system_modal : WmWindowAura::FromAuraWindows(
44 ash::Shell::GetContainersFromAllRootWindows(
45 kShellWindowId_SystemModalContainer, nullptr))) {
46 if (system_modal->GetRootWindow() == pinned_root)
47 continue;
48 result.push_back(system_modal);
49 }
50 return result;
51 }
52
53 void AddObserverToChildren(WmWindow* container,
54 aura::WindowObserver* observer) {
55 for (WmWindow* child : container->GetChildren()) {
56 WmWindowAura::GetAuraWindow(child)->AddObserver(observer);
57 }
58 }
59
60 void RemoveObserverFromChildren(WmWindow* container,
61 aura::WindowObserver* observer) {
62 for (WmWindow* child : container->GetChildren()) {
63 WmWindowAura::GetAuraWindow(child)->RemoveObserver(observer);
64 }
65 }
66
67 } // namespace
68
69 // Adapter to fire OnPinnedContainerWindowStackingChanged().
70 class ScreenPinningController::PinnedContainerChildWindowObserver
71 : public aura::WindowObserver {
72 public:
73 explicit PinnedContainerChildWindowObserver(
74 ScreenPinningController* controller)
75 : controller_(controller) {}
76
77 void OnWindowStackingChanged(aura::Window* window) override {
78 controller_->OnPinnedContainerWindowStackingChanged(
79 WmWindowAura::Get(window));
80 }
81
82 private:
83 ScreenPinningController* controller_;
84 DISALLOW_COPY_AND_ASSIGN(PinnedContainerChildWindowObserver);
85 };
86
87 // Adapter to translate OnWindowAdded/OnWillRemoveWindow for the container
88 // containing the pinned window, to the corresponding controller's methods.
89 class ScreenPinningController::PinnedContainerWindowObserver
90 : public aura::WindowObserver {
91 public:
92 explicit PinnedContainerWindowObserver(ScreenPinningController* controller)
93 : controller_(controller) {}
94
95 void OnWindowAdded(aura::Window* new_window) override {
96 controller_->OnWindowAddedToPinnedContainer(WmWindowAura::Get(new_window));
97 }
98 void OnWillRemoveWindow(aura::Window* window) override {
99 controller_->OnWillRemoveWindowFromPinnedContainer(
100 WmWindowAura::Get(window));
101 }
102 void OnWindowDestroying(aura::Window* window) override {
103 // Just in case. There is nothing we can do here.
104 window->RemoveObserver(this);
105 }
106
107 private:
108 ScreenPinningController* controller_;
109 DISALLOW_COPY_AND_ASSIGN(PinnedContainerWindowObserver);
110 };
111
112 // Adapter to fire OnSystemModalContainerWindowStackingChanged().
113 class ScreenPinningController::SystemModalContainerChildWindowObserver
114 : public aura::WindowObserver {
115 public:
116 explicit SystemModalContainerChildWindowObserver(
117 ScreenPinningController* controller)
118 : controller_(controller) {}
119
120 void OnWindowStackingChanged(aura::Window* window) override {
121 controller_->OnSystemModalContainerWindowStackingChanged(
122 WmWindowAura::Get(window));
123 }
124
125 private:
126 ScreenPinningController* controller_;
127 DISALLOW_COPY_AND_ASSIGN(SystemModalContainerChildWindowObserver);
128 };
129
130 // Adapter to translate OnWindowAdded/OnWillRemoveWindow for the
131 // SystemModalContainer to the corresponding controller's methods.
132 class ScreenPinningController::SystemModalContainerWindowObserver
133 : public aura::WindowObserver {
134 public:
135 explicit SystemModalContainerWindowObserver(
136 ScreenPinningController* controller)
137 : controller_(controller) {}
138
139 void OnWindowAdded(aura::Window* new_window) override {
140 controller_->OnWindowAddedToSystemModalContainer(
141 WmWindowAura::Get(new_window));
142 }
143 void OnWillRemoveWindow(aura::Window* window) override {
144 controller_->OnWillRemoveWindowFromSystemModalContainer(
145 WmWindowAura::Get(window));
146 }
147 void OnWindowDestroying(aura::Window* window) override {
148 // Just in case. There is nothing we can do here.
149 window->RemoveObserver(this);
150 }
151
152 private:
153 ScreenPinningController* controller_;
154 DISALLOW_COPY_AND_ASSIGN(SystemModalContainerWindowObserver);
155 };
156
157 // Tracks DimWindow's life.
158 class ScreenPinningController::DimWindowObserver : public aura::WindowObserver {
159 public:
160 explicit DimWindowObserver(ScreenPinningController* controller)
161 : controller_(controller) {}
162
163 void OnWindowParentChanged(aura::Window* window,
164 aura::Window* parent) override {
165 // In case of parent change, there is nothing we can do for that change.
166 // Also, it is unsafe to delete the moving window here, because it could
167 // cause SEGV. Instead, we just hide it.
168 // Note that, the window is still tracked by the ScreenPinningController,
169 // so that it should be deleted on "unpin", at least.
170 window->Hide();
171 }
172
173 void OnWindowDestroying(aura::Window* window) override {
174 controller_->OnDimWindowDestroying(WmWindowAura::Get(window));
175 }
176
177 private:
178 ScreenPinningController* controller_;
179 DISALLOW_COPY_AND_ASSIGN(DimWindowObserver);
180 };
181
182 ScreenPinningController::ScreenPinningController(
183 WmShellCommon* wm_shell_common,
184 WindowTreeHostManager* window_tree_host_manager)
185 : wm_shell_common_(wm_shell_common),
186 window_tree_host_manager_(window_tree_host_manager),
187 pinned_container_window_observer_(
188 new PinnedContainerWindowObserver(this)),
189 pinned_container_child_window_observer_(
190 new PinnedContainerChildWindowObserver(this)),
191 system_modal_container_window_observer_(
192 new SystemModalContainerWindowObserver(this)),
193 system_modal_container_child_window_observer_(
194 new SystemModalContainerChildWindowObserver(this)),
195 dim_window_observer_(new DimWindowObserver(this)) {
196 window_tree_host_manager_->AddObserver(this);
197 }
198
199 ScreenPinningController::~ScreenPinningController() {
200 window_tree_host_manager_->RemoveObserver(this);
201 }
202
203 bool ScreenPinningController::IsPinned() const {
204 return pinned_window_ != nullptr;
205 }
206
207 void ScreenPinningController::SetPinnedWindow(WmWindow* pinned_window) {
208 if (pinned_window->GetWindowState()->IsPinned()) {
209 if (pinned_window_) {
210 LOG(DFATAL) << "Pinned mode is enabled, while it is already in "
211 << "the pinned mode";
212 return;
213 }
214
215 WmWindow* container = pinned_window->GetParent();
216 std::vector<WmWindow*> system_modal_containers =
217 GetSystemModalWindowsExceptPinned(pinned_window);
218
219 // Set up the container which has the pinned window.
220 pinned_window_ = pinned_window;
221 background_window_ = CreateDimWindow(container);
222 container->StackChildAtTop(pinned_window);
223 container->StackChildBelow(background_window_, pinned_window);
224
225 // Set the dim windows to the system containers, other than the one which
226 // the root window of the pinned window holds.
227 for (WmWindow* system_modal : system_modal_containers) {
228 WmWindow* dim_window = CreateDimWindow(system_modal);
229 system_modal->StackChildAtBottom(dim_window);
230 dim_windows_.push_back(dim_window);
231 WmWindowAura::GetAuraWindow(dim_window)
232 ->AddObserver(dim_window_observer_.get());
233 }
234
235 // Set observers.
236 WmWindowAura::GetAuraWindow(container)->AddObserver(
237 pinned_container_window_observer_.get());
238 AddObserverToChildren(container,
239 pinned_container_child_window_observer_.get());
240 for (WmWindow* system_modal : system_modal_containers) {
241 WmWindowAura::GetAuraWindow(system_modal)
242 ->AddObserver(system_modal_container_window_observer_.get());
243 AddObserverToChildren(
244 system_modal, system_modal_container_child_window_observer_.get());
245 }
246 } else {
247 if (pinned_window != pinned_window_) {
248 LOG(DFATAL) << "Pinned mode is being disabled, but for the different "
249 << "target window.";
250 return;
251 }
252
253 WmWindow* container = pinned_window->GetParent();
254 std::vector<WmWindow*> system_modal_containers =
255 GetSystemModalWindowsExceptPinned(pinned_window_);
256
257 // Unset observers.
258 for (WmWindow* system_modal :
259 GetSystemModalWindowsExceptPinned(pinned_window_)) {
260 RemoveObserverFromChildren(
261 system_modal, system_modal_container_child_window_observer_.get());
262 WmWindowAura::GetAuraWindow(system_modal)
263 ->RemoveObserver(system_modal_container_window_observer_.get());
264 }
265 RemoveObserverFromChildren(container,
266 pinned_container_child_window_observer_.get());
267 WmWindowAura::GetAuraWindow(container)->RemoveObserver(
268 pinned_container_window_observer_.get());
269
270 // Delete the dim windows. This works, but do not use RAII, because
271 // the window is owned by the parent.
272 // Note: dim_windows_ will be updated during the deletion. So, copy is
273 // needed.
274 for (WmWindow* dim_window : std::vector<WmWindow*>(dim_windows_)) {
275 delete WmWindowAura::GetAuraWindow(dim_window);
276 }
277 DCHECK(dim_windows_.empty());
278 delete WmWindowAura::GetAuraWindow(background_window_);
279 background_window_ = nullptr;
280
281 pinned_window_ = nullptr;
282 }
283
284 wm_shell_common_->NotifyPinnedStateChanged(pinned_window);
285 }
286
287 void ScreenPinningController::OnWindowAddedToPinnedContainer(
288 WmWindow* new_window) {
289 KeepPinnedWindowOnTop();
290 WmWindowAura::GetAuraWindow(new_window)
291 ->AddObserver(pinned_container_child_window_observer_.get());
292 }
293
294 void ScreenPinningController::OnWillRemoveWindowFromPinnedContainer(
295 WmWindow* window) {
296 WmWindowAura::GetAuraWindow(window)->RemoveObserver(
297 pinned_container_child_window_observer_.get());
298 if (window == pinned_window_) {
299 pinned_window_->GetWindowState()->Restore();
300 return;
301 }
302 if (window == background_window_) {
303 background_window_ = nullptr;
304 return;
305 }
306 }
307
308 void ScreenPinningController::OnPinnedContainerWindowStackingChanged(
309 WmWindow* window) {
310 KeepPinnedWindowOnTop();
311 }
312
313 void ScreenPinningController::OnWindowAddedToSystemModalContainer(
314 WmWindow* new_window) {
315 KeepDimWindowAtBottom(new_window->GetParent());
316 WmWindowAura::GetAuraWindow(new_window)
317 ->AddObserver(system_modal_container_child_window_observer_.get());
318 }
319
320 void ScreenPinningController::OnWillRemoveWindowFromSystemModalContainer(
321 WmWindow* window) {
322 WmWindowAura::GetAuraWindow(window)->RemoveObserver(
323 system_modal_container_child_window_observer_.get());
324 }
325
326 void ScreenPinningController::OnSystemModalContainerWindowStackingChanged(
327 WmWindow* window) {
328 KeepDimWindowAtBottom(window->GetParent());
329 }
330
331 void ScreenPinningController::OnDimWindowDestroying(WmWindow* window) {
332 dim_windows_.erase(
333 std::find(dim_windows_.begin(), dim_windows_.end(), window));
334 }
335
336 void ScreenPinningController::OnDisplayConfigurationChanged() {
337 // Note: this is called on display attached or detached.
338 if (!IsPinned())
339 return;
340
341 // On display detaching, all necessary windows are transfered to the
342 // primary display's tree, and called this.
343 // So, delete the dim windows which are not a part of target system modal
344 // container.
345 // On display attaching, the new system modal container does not have the
346 // dim window. So create it.
347
348 // First, delete unnecessary dim windows.
349 // The delete will update dim_windows_, so create the copy is needed.
350 for (WmWindow* dim_window : std::vector<WmWindow*>(dim_windows_)) {
351 if (!dim_window->GetTargetVisibility())
352 delete WmWindowAura::GetAuraWindow(dim_window);
353 }
354
355 // Then, create missing dim_windows.
356 std::vector<WmWindow*> system_modal_containers =
357 GetSystemModalWindowsExceptPinned(pinned_window_);
358 for (WmWindow* system_modal : system_modal_containers) {
359 const std::vector<WmWindow*> children = system_modal->GetChildren();
360 if (!children.empty() && ContainsValue(dim_windows_, children[0])) {
361 // The system modal dialog has the dim window.
362 continue;
363 }
364
365 // This is the new system modal dialog.
366 WmWindow* dim_window = CreateDimWindow(system_modal);
367 system_modal->StackChildAtBottom(dim_window);
368 dim_windows_.push_back(dim_window);
369 WmWindowAura::GetAuraWindow(dim_window)
370 ->AddObserver(dim_window_observer_.get());
371
372 // Set observers to the tree.
373 WmWindowAura::GetAuraWindow(system_modal)
374 ->AddObserver(system_modal_container_window_observer_.get());
375 AddObserverToChildren(system_modal,
376 system_modal_container_child_window_observer_.get());
377 }
378 }
379
380 void ScreenPinningController::KeepPinnedWindowOnTop() {
381 if (in_restacking_)
382 return;
383
384 base::AutoReset<bool> auto_reset(&in_restacking_, true);
385 WmWindow* container = pinned_window_->GetParent();
386 container->StackChildAtTop(pinned_window_);
387 container->StackChildBelow(background_window_, pinned_window_);
388 }
389
390 void ScreenPinningController::KeepDimWindowAtBottom(WmWindow* container) {
391 if (in_restacking_)
392 return;
393
394 base::AutoReset<bool> auto_reset(&in_restacking_, true);
395 for (WmWindow* dim_window : dim_windows_) {
396 if (dim_window->GetParent() == container) {
397 container->StackChildAtBottom(dim_window);
398 break;
399 }
400 }
401 }
402
403 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/screen_pinning_controller.h ('k') | ash/wm/screen_pinning_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698