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

Side by Side Diff: ash/wm/splitview/split_view_controller.cc

Issue 2918403006: CrOS Tablet Window management - Split Screen part I (Closed)
Patch Set: Fix failed tests. Created 3 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 2017 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/splitview/split_view_controller.h"
6
7 #include "ash/ash_switches.h"
8 #include "ash/public/cpp/shell_window_ids.h"
9 #include "ash/screen_util.h"
10 #include "ash/shell.h"
11 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
12 #include "ash/wm/mru_window_tracker.h"
13 #include "ash/wm/window_state.h"
14 #include "ash/wm/window_util.h"
15 #include "ash/wm/wm_event.h"
16 #include "base/command_line.h"
17 #include "ui/aura/window.h"
18 #include "ui/wm/core/coordinate_conversion.h"
19 #include "ui/wm/public/activation_client.h"
20
21 namespace ash {
22
23 namespace {
24
25 // Returns true if |window| can be activated and snapped.
26 bool CanSnap(aura::Window* window) {
27 if (!wm::CanActivateWindow(window))
28 return false;
29 return wm::GetWindowState(window)->CanSnap();
30 }
31
32 } // namespace
33
34 SplitViewController::SplitViewController() {
35 Shell::Get()->AddShellObserver(this);
36 Shell::Get()->activation_client()->AddObserver(this);
37 }
38
39 SplitViewController::~SplitViewController() {
40 Shell::Get()->RemoveShellObserver(this);
41 Shell::Get()->activation_client()->RemoveObserver(this);
42 EndSplitView();
43 }
44
45 // static
46 bool SplitViewController::ShouldAllowSplitView() {
47 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
48 switches::kAshEnableTabletSplitView)) {
49 return false;
50 }
51 if (!Shell::Get()
52 ->maximize_mode_controller()
53 ->IsMaximizeModeWindowManagerEnabled()) {
54 return false;
55 }
56 return true;
57 }
58
59 bool SplitViewController::IsSplitViewModeActive() const {
60 return state_ != NOSNAP;
61 }
62
63 void SplitViewController::SetLeftWindow(aura::Window* left_window) {
64 if (!left_window)
65 return;
66
67 if (state_ == NOSNAP)
68 Shell::Get()->NotifySplitViewModeStarting();
69
70 if (right_window_ == left_window) {
71 StopObservingAndRestore(right_window_);
72 right_window_ = nullptr;
73 }
74 if (left_window_ != left_window) {
75 StopObservingAndRestore(left_window_);
76 left_window_ = nullptr;
77 left_window_ = left_window;
78 left_window_->AddObserver(this);
79 wm::GetWindowState(left_window_)->AddObserver(this);
80 }
81
82 State previous_state = state_;
83 switch (state_) {
84 case NOSNAP:
85 default_snap_position_ = LEFT;
86 state_ = LEFT_SNAPPED;
87 break;
88 case LEFT_SNAPPED:
89 state_ = LEFT_SNAPPED;
90 break;
91 case RIGHT_SNAPPED:
92 case BOTH_SNAPPED:
93 state_ = BOTH_SNAPPED;
94 break;
95 }
96
97 const wm::WMEvent event(wm::WM_EVENT_SNAP_LEFT);
98 wm::GetWindowState(left_window_)->OnWMEvent(&event);
99 wm::ActivateWindow(left_window_);
100
101 NotifySplitViewStateChanged(previous_state, state_);
102 }
103
104 void SplitViewController::SetRightWindow(aura::Window* right_window) {
105 if (!right_window)
106 return;
107
108 if (state_ == NOSNAP)
109 Shell::Get()->NotifySplitViewModeStarting();
110
111 if (left_window_ == right_window) {
112 StopObservingAndRestore(left_window_);
113 left_window_ = nullptr;
114 }
115 if (right_window_ != right_window) {
116 StopObservingAndRestore(right_window_);
117 right_window_ = nullptr;
118 right_window_ = right_window;
119 right_window_->AddObserver(this);
120 wm::GetWindowState(right_window_)->AddObserver(this);
121 }
122
123 State previous_state = state_;
124 switch (state_) {
125 case NOSNAP:
126 default_snap_position_ = RIGHT;
127 state_ = RIGHT_SNAPPED;
128 break;
129 case RIGHT_SNAPPED:
130 state_ = RIGHT_SNAPPED;
131 break;
132 case LEFT_SNAPPED:
133 case BOTH_SNAPPED:
134 state_ = BOTH_SNAPPED;
135 break;
136 }
137
138 const wm::WMEvent event(wm::WM_EVENT_SNAP_RIGHT);
139 wm::GetWindowState(right_window_)->OnWMEvent(&event);
140 wm::ActivateWindow(right_window_);
141
142 NotifySplitViewStateChanged(previous_state, state_);
143 }
144
145 aura::Window* SplitViewController::GetDefaultSnappedWindow() {
146 if (default_snap_position_ == LEFT)
147 return left_window_;
148 if (default_snap_position_ == RIGHT)
149 return right_window_;
150 return nullptr;
151 }
152
153 gfx::Rect SplitViewController::GetLeftWindowBoundsInParent(
154 aura::Window* window) {
155 aura::Window* root_window = window->GetRootWindow();
156 gfx::Rect bounds_in_parent = ScreenUtil::GetDisplayWorkAreaBoundsInParent(
157 root_window->GetChildById(kShellWindowId_DefaultContainer));
158 if (separator_position_ < 0)
159 separator_position_ = bounds_in_parent.width() * 0.5f;
160 gfx::Rect bounds(bounds_in_parent.x(), bounds_in_parent.y(),
161 separator_position_, bounds_in_parent.height());
162 return bounds;
163 }
164
165 gfx::Rect SplitViewController::GetRightWindowBoundsInParent(
166 aura::Window* window) {
167 aura::Window* root_window = window->GetRootWindow();
168 gfx::Rect bounds_in_parent = ScreenUtil::GetDisplayWorkAreaBoundsInParent(
169 root_window->GetChildById(kShellWindowId_DefaultContainer));
170 if (separator_position_ < 0)
171 separator_position_ = bounds_in_parent.width() * 0.5f;
172 gfx::Rect bounds(bounds_in_parent.x() + separator_position_,
173 bounds_in_parent.y(),
174 bounds_in_parent.width() - separator_position_,
175 bounds_in_parent.height());
176 return bounds;
177 }
178
179 gfx::Rect SplitViewController::GetLeftWindowBoundsInScreen(
180 aura::Window* window) {
181 gfx::Rect bounds = GetLeftWindowBoundsInParent(window);
182 ::wm::ConvertRectToScreen(window->GetRootWindow(), &bounds);
183 return bounds;
184 }
185
186 gfx::Rect SplitViewController::GetRightWindowBoundsInScreen(
187 aura::Window* window) {
188 gfx::Rect bounds = GetRightWindowBoundsInParent(window);
189 ::wm::ConvertRectToScreen(window->GetRootWindow(), &bounds);
190 return bounds;
191 }
192
193 void SplitViewController::AddObserver(Observer* observer) {
194 observers_.AddObserver(observer);
195 }
196
197 void SplitViewController::RemoveObserver(Observer* observer) {
198 observers_.RemoveObserver(observer);
199 }
200
201 void SplitViewController::OnWindowDestroying(aura::Window* window) {
202 // If one of the snapped window gets closed, end the split view mode. The
203 // behavior might change in the future.
204 DCHECK(window == left_window_ || window == right_window_);
205 EndSplitView();
oshima 2017/06/14 05:45:47 you probably should skip restroing the window bein
xdai1 2017/06/15 22:11:42 Currently StopObservingAndRestore() function only
oshima 2017/06/16 01:20:57 Sorry, I misunderstood what Restore means here.
xdai1 2017/06/16 18:49:52 I rename the function to StopObserving() to better
206 }
207
208 void SplitViewController::OnPostWindowStateTypeChange(
209 ash::wm::WindowState* window_state,
210 ash::wm::WindowStateType old_type) {
211 if (window_state->IsFullscreen() || window_state->IsMinimized() ||
212 window_state->IsMaximized()) {
213 // TODO(xdai): Decide what to do if one of the snapped windows gets
214 // minimized /maximized / full-screened. For now we end the split view mode
215 // for simplicity.
216 EndSplitView();
217 }
218 }
219
220 void SplitViewController::OnWindowActivated(ActivationReason reason,
221 aura::Window* gained_active,
222 aura::Window* lost_active) {
223 if (!IsSplitViewModeActive())
224 return;
225
226 // Only snap window that can be snapped but hasn't been snapped.
227 if (!gained_active || gained_active == left_window_ ||
228 gained_active == right_window_ || !CanSnap(gained_active)) {
229 return;
230 }
231
232 // Only window in MRU list can be snapped.
233 aura::Window::Windows windows =
234 Shell::Get()->mru_window_tracker()->BuildMruWindowList();
235 if (std::find(windows.begin(), windows.end(), gained_active) == windows.end())
236 return;
237
238 // Snap the window on the non-default side of the screen if split view mode
239 // is active.
240 if (default_snap_position_ == LEFT)
241 SetRightWindow(gained_active);
242 else
243 SetLeftWindow(gained_active);
244 }
245
246 void SplitViewController::OnOverviewModeStarting() {
247 // If split view mode is active, reset |state_| to make it be able to select
248 // another window from overview window grid.
249 if (IsSplitViewModeActive()) {
250 DCHECK(state_ == BOTH_SNAPPED);
251 if (default_snap_position_ == LEFT) {
252 StopObservingAndRestore(right_window_);
253 state_ = LEFT_SNAPPED;
254 } else {
255 StopObservingAndRestore(left_window_);
256 state_ = RIGHT_SNAPPED;
257 }
258 NotifySplitViewStateChanged(BOTH_SNAPPED, state_);
259 }
260 }
261
262 void SplitViewController::OnOverviewModeEnded() {
263 // If split view mode is active but only has one snapped window, use the MRU
264 // window list to auto select another window to snap.
265 if (IsSplitViewModeActive() && state_ != BOTH_SNAPPED) {
266 aura::Window::Windows windows =
267 Shell::Get()->mru_window_tracker()->BuildMruWindowList();
268 auto end = std::remove_if(windows.begin(), windows.end(),
269 std::not1(std::ptr_fun(&CanSnap)));
270 windows.resize(end - windows.begin());
271 for (auto* window : windows) {
272 if (window != GetDefaultSnappedWindow()) {
273 if (default_snap_position_ == LEFT)
274 SetRightWindow(window);
275 else
276 SetLeftWindow(window);
277 break;
278 }
279 }
280 }
281 }
282
283 void SplitViewController::EndSplitView() {
284 StopObservingAndRestore(left_window_);
285 StopObservingAndRestore(right_window_);
286 left_window_ = nullptr;
287 right_window_ = nullptr;
288 default_snap_position_ = LEFT;
289 separator_position_ = -1;
290
291 State previous_state = state_;
292 state_ = NOSNAP;
293 NotifySplitViewStateChanged(previous_state, state_);
294
295 Shell::Get()->NotifySplitViewModeEnded();
296 }
297
298 void SplitViewController::StopObservingAndRestore(aura::Window* window) {
299 if (window) {
300 window->RemoveObserver(this);
301 if (wm::GetWindowState(window))
302 wm::GetWindowState(window)->RemoveObserver(this);
303 }
304 }
305
306 void SplitViewController::NotifySplitViewStateChanged(State previous_state,
307 State state) {
308 for (Observer& observer : observers_)
309 observer.OnSplitViewStateChanged(previous_state, state);
310 }
311
312 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698