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

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

Issue 2072853002: Implement "pinned" mode in ash. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix linux build breakage 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
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 <algorithm>
6 #include <vector>
7
8 #include "ash/aura/wm_window_aura.h"
9 #include "ash/common/shell_window_ids.h"
10 #include "ash/common/wm/window_state.h"
11 #include "ash/common/wm_window.h"
12 #include "ash/shell.h"
13 #include "ash/wm/dim_window.h"
14 #include "ash/wm/pinned_controller.h"
15 #include "base/auto_reset.h"
16 #include "base/logging.h"
17
18 namespace ash {
19 namespace wm {
20 namespace {
21
22 WmWindow* CreateDimWindow(WmWindow* container) {
23 DimWindow* dim_window = new DimWindow(WmWindowAura::GetAuraWindow(container));
24 dim_window->SetDimOpacity(1); // Set whole black.
25 dim_window->Show();
26 WmWindow* result = WmWindowAura::Get(dim_window);
27 result->SetFullscreen();
28 return result;
29 }
30
31 // Returns a list of WmWindows corresponding to SystemModalContainers,
32 // except ones whose root is shared with |pinned_window|.
33 std::vector<WmWindow*> GetSystemModalWindowsExceptPinned(
34 WmWindow* pinned_window) {
35 WmWindow* pinned_root = pinned_window->GetRootWindow();
36
37 ash::Shell* shell = ash::Shell::GetInstance();
38 std::vector<WmWindow*> result;
39 for (WmWindow* system_modal :
40 WmWindowAura::FromAuraWindows(shell->GetContainersFromAllRootWindows(
41 kShellWindowId_SystemModalContainer, nullptr))) {
42 if (system_modal->GetRootWindow() == pinned_root)
43 continue;
44 result.push_back(system_modal);
45 }
46 return result;
47 }
48
49 template <typename T>
50 bool Contains(const std::vector<T>& container, const T& target) {
51 return std::find(container.begin(), container.end(), target) !=
52 container.end();
53 }
oshima 2016/06/17 10:26:54 use ContainsValue in stl_util.h
hidehiko 2016/06/17 17:19:22 Good to know. Done.
54
55 } // namespace
56
57 PinnedController::PinnedController() = default;
58 PinnedController::~PinnedController() = default;
59
60 bool PinnedController::IsPinned() const {
61 return pinned_window_ != nullptr;
62 }
63
64 void PinnedController::OnPinnedStateChanged(WmWindow* pinned_window) {
65 if (pinned_window->GetWindowState()->IsPinned()) {
66 if (pinned_window_) {
67 LOG(ERROR) << "Pinned mode is enabled, while it is already in "
68 << "the pinned mode";
oshima 2016/06/17 10:26:54 can this happen? If not, DCHECK
hidehiko 2016/06/17 17:19:22 Replaced by LOG(DFATAL).
69 return;
70 }
71
72 WmWindow* container = pinned_window->GetParent();
73 std::vector<WmWindow*> system_modal_containers =
74 GetSystemModalWindowsExceptPinned(pinned_window);
75
76 // Set up the container which has the pinned window.
77 pinned_window_ = pinned_window;
78 background_window_ = CreateDimWindow(container);
79 container->StackChildAtTop(pinned_window);
80 container->StackChildBelow(background_window_, pinned_window);
oshima 2016/06/17 10:26:54 Another option is to create a layer above, and use
hidehiko 2016/06/17 17:19:22 Can we keep it? The window can have a transparent
oshima 2016/06/18 04:47:44 It'll be visually same. It's not a big deal so if
81
82 // Set the dim windows to the system containers, other than the one which
83 // the root window of the pinned window holds.
84 for (WmWindow* system_modal : system_modal_containers) {
85 WmWindow* dim_window = CreateDimWindow(system_modal);
86 system_modal->StackChildAtTop(dim_window);
oshima 2016/06/17 10:26:54 This may hide existing modal window if any.
hidehiko 2016/06/17 17:19:22 Good catch. As we decided not to hide system modal
87 dim_windows_.push_back(dim_window);
88 }
oshima 2016/06/17 10:26:54 bye the way, we can't (and shouldn't) suppress scr
hidehiko 2016/06/17 17:19:22 No, as it is consistent with the referenced behavi
oshima 2016/06/18 04:47:44 Acknowledged.
89
90 // Set observers.
91 container->AddObserver(this);
92 for (WmWindow* child : container->GetChildren())
93 child->AddObserver(this);
94 for (WmWindow* dim_window : dim_windows_)
95 dim_window->AddObserver(this);
96 for (WmWindow* system_modal : system_modal_containers)
97 system_modal->AddObserver(this);
98 } else {
99 if (pinned_window != pinned_window_) {
100 LOG(ERROR) << "Pinned mode is being disabled, but for the different "
101 << "target window.";
oshima 2016/06/17 10:26:54 ditto
hidehiko 2016/06/17 17:19:22 Done.
102 return;
103 }
104
105 WmWindow* container = pinned_window->GetParent();
106 std::vector<WmWindow*> system_modal_containers =
107 GetSystemModalWindowsExceptPinned(pinned_window_);
108
109 // Unset observers.
110 for (WmWindow* system_modal : system_modal_containers)
111 system_modal->RemoveObserver(this);
112 for (WmWindow* dim_window : dim_windows_)
113 dim_window->RemoveObserver(this);
114 for (WmWindow* child : container->GetChildren())
115 child->RemoveObserver(this);
116 container->RemoveObserver(this);
117
118 // Delete the dim windows. This works, but do not use RAII, because
119 // the window is owned by the parent.
120 for (WmWindow* dim_window : dim_windows_) {
121 dim_window->RemoveObserver(this);
122 delete WmWindowAura::GetAuraWindow(dim_window);
123 }
124 dim_windows_.clear();
125 delete WmWindowAura::GetAuraWindow(background_window_);
126 background_window_ = nullptr;
127
128 pinned_window_ = nullptr;
129 }
130 }
131
132 void PinnedController::OnWindowTreeChanging(WmWindow* window,
133 const TreeChangeParams& params) {
134 DCHECK(IsPinned());
135 DCHECK(params.target != pinned_window_);
136 DCHECK(params.target != background_window_);
137 DCHECK(!Contains(dim_windows_, params.target));
138
139 // Here, only events to remove a window directly from a container should be
140 // handled.
141 if ((window != pinned_window_->GetParent() &&
142 window->GetShellWindowId() != kShellWindowId_SystemModalContainer) ||
143 window != params.old_parent)
144 return;
145
146 // If a window is being removed from the parent, stop observing it.
oshima 2016/06/17 10:56:51 new_parent == nullptr is removal. I actually wond
hidehiko 2016/06/17 17:19:22 Good to know. I'm tempted to use it, but it is a s
oshima 2016/06/18 04:47:44 You can use it for this type of feature too. Good
hidehiko 2016/06/18 05:32:45 Yes, that is why I was actually tempted to use.
147 params.target->RemoveObserver(this);
148 }
149
150 void PinnedController::OnWindowTreeChanged(WmWindow* window,
151 const TreeChangeParams& params) {
152 DCHECK(IsPinned());
153 DCHECK(params.target != pinned_window_);
154 DCHECK(params.target != background_window_);
155 DCHECK(!Contains(dim_windows_, params.target));
156
157 // Here, only events to add a window directly into a container should be
158 // handled.
oshima 2016/06/17 10:56:51 What if someone add a window to AlwaysOnTop?
hidehiko 2016/06/17 17:19:22 Good catch. It should be handled by WorkspaceLayou
159 if ((window != pinned_window_->GetParent() &&
160 window->GetShellWindowId() != kShellWindowId_SystemModalContainer) ||
161 window != params.new_parent)
162 return;
163
164 // Observe the window to see the stacking change.
165 // Also, keep the pinned window at the top.
166 params.target->AddObserver(this);
167 if (window == pinned_window_->GetParent())
168 KeepPinnedWindowOnTop();
169 else
170 KeepDimWindowOnTop(window);
171 }
172
173 void PinnedController::OnWindowStackingChanged(WmWindow* window) {
174 DCHECK(IsPinned());
175
176 if (in_restacking_)
177 return;
178
179 if (window->GetParent() == pinned_window_->GetParent())
180 KeepPinnedWindowOnTop();
181 else if (window->GetParent()->GetShellWindowId() ==
182 kShellWindowId_SystemModalContainer)
183 KeepDimWindowOnTop(window->GetParent());
184 }
185
186 void PinnedController::OnWindowDestroying(WmWindow* window) {
oshima 2016/06/17 10:56:51 or you can listen to OnWndowAdded/Removed on conta
hidehiko 2016/06/17 17:19:22 Done. Though it needs to fully change the callback
187 DCHECK(IsPinned());
188
189 if (window == pinned_window_) {
190 pinned_window_->GetWindowState()->Restore();
191 } else if (window == background_window_) {
192 background_window_ = nullptr;
193 } else if (Contains(dim_windows_, window)) {
194 dim_windows_.erase(
195 std::find(dim_windows_.begin(), dim_windows_.end(), window));
196 }
197 }
198
199 void PinnedController::OnDisplayConfigurationChanged() {
200 // Note: this is called on display attached or detached.
201 if (!IsPinned())
202 return;
203
204 std::vector<WmWindow*> system_modal_containers =
205 GetSystemModalWindowsExceptPinned(pinned_window_);
206 for (WmWindow* system_modal : system_modal_containers) {
207 if (Contains(dim_windows_, system_modal->GetChildren().back()))
208 continue;
209 WmWindow* dim_window = CreateDimWindow(system_modal);
210 system_modal->StackChildAtTop(dim_window);
211 dim_windows_.push_back(dim_window);
212 system_modal->AddObserver(this);
213 dim_window->AddObserver(this);
214 }
215 }
216
217 void PinnedController::KeepPinnedWindowOnTop() {
218 DCHECK(!in_restacking_);
219
220 base::AutoReset<bool> auto_reset(&in_restacking_, true);
221 WmWindow* container = pinned_window_->GetParent();
222 container->StackChildAtTop(pinned_window_);
223 container->StackChildBelow(background_window_, pinned_window_);
224 }
225
226 void PinnedController::KeepDimWindowOnTop(WmWindow* container) {
227 DCHECK(!in_restacking_);
228
229 base::AutoReset<bool> auto_reset(&in_restacking_, true);
230 for (WmWindow* dim_window : dim_windows_) {
231 if (dim_window->GetParent() == container) {
232 container->StackChildAtTop(dim_window);
233 break;
234 }
235 }
236 }
237
238 } // namespace wm
239 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698