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.
5 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
7 #include "ash/ash_switches.h"
8 #include "ash/multi_profile_uma.h"
9 #include "ash/root_window_controller.h"
10 #include "ash/session/session_state_delegate.h"
11 #include "ash/shelf/shelf.h"
12 #include "ash/shell.h"
13 #include "ash/shell_delegate.h"
14 #include "ash/shell_window_ids.h"
15 #include "ash/system/tray/system_tray_notifier.h"
16 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
17 #include "ash/wm/window_state.h"
18 #include "base/auto_reset.h"
19 #include "base/message_loop/message_loop.h"
20 #include "base/strings/string_util.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/profiles/profile_manager.h"
26 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
27 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
28 #include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/browser_finder.h"
31 #include "chrome/browser/ui/browser_list.h"
32 #include "chrome/browser/ui/browser_window.h"
33 #include "content/public/browser/notification_service.h"
34 #include "extensions/browser/app_window/app_window.h"
35 #include "extensions/browser/app_window/app_window_registry.h"
36 #include "google_apis/gaia/gaia_auth_util.h"
37 #include "ui/aura/client/aura_constants.h"
38 #include "ui/aura/window.h"
39 #include "ui/aura/window_event_dispatcher.h"
40 #include "ui/base/ui_base_types.h"
41 #include "ui/events/event.h"
42 #include "ui/message_center/message_center.h"
43 #include "ui/wm/core/transient_window_manager.h"
44 #include "ui/wm/core/window_animations.h"
45 #include "ui/wm/core/window_util.h"
49 // The animation time in milliseconds for a single window which is fading
51 const int kAnimationTimeMS
= 100;
53 // The animation time in milliseconds for the fade in and / or out when
55 const int kUserFadeTimeMS
= 110;
57 // The animation time in ms for a window which get teleported to another screen.
58 const int kTeleportAnimationTimeMS
= 300;
60 // Checks if a given event is a user event.
61 bool IsUserEvent(const ui::Event
* e
) {
63 ui::EventType type
= e
->type();
64 if (type
!= ui::ET_CANCEL_MODE
&&
65 type
!= ui::ET_UMA_DATA
&&
66 type
!= ui::ET_UNKNOWN
)
72 // Test if we are currently processing a user event which might lead to a
73 // browser / app creation.
74 bool IsProcessingUserEvent() {
75 // When there is a nested message loop (e.g. active menu or drag and drop
76 // operation) - we are in a nested loop and can ignore this.
77 // Note: Unit tests might not have a message loop.
78 base::MessageLoop
* message_loop
= base::MessageLoop::current();
79 if (message_loop
&& message_loop
->is_running() && message_loop
->IsNested())
82 // TODO(skuhne): "Open link in new window" will come here after the menu got
83 // closed, executing the command from the nested menu loop. However at that
84 // time there is no active event processed. A solution for that need to be
85 // found past M-32. A global event handler filter (pre and post) might fix
86 // that problem in conjunction with a depth counter - but - for the menu
87 // execution we come here after the loop was finished (so it's not nested
88 // anymore) and the root window should therefore still have the event which
89 // lead to the menu invocation, but it is not. By fixing that problem this
90 // would "magically work".
91 aura::Window::Windows root_window_list
= ash::Shell::GetAllRootWindows();
92 for (aura::Window::Windows::iterator it
= root_window_list
.begin();
93 it
!= root_window_list
.end();
95 if (IsUserEvent((*it
)->GetHost()->dispatcher()->current_event()))
101 // Records the type of window which was transferred to another desktop.
102 void RecordUMAForTransferredWindowType(aura::Window
* window
) {
103 // We need to figure out what kind of window this is to record the transfer.
104 Browser
* browser
= chrome::FindBrowserWithWindow(window
);
105 ash::MultiProfileUMA::TeleportWindowType window_type
=
106 ash::MultiProfileUMA::TELEPORT_WINDOW_UNKNOWN
;
108 if (browser
->profile()->IsOffTheRecord()) {
109 window_type
= ash::MultiProfileUMA::TELEPORT_WINDOW_INCOGNITO_BROWSER
;
110 } else if (browser
->is_app()) {
111 window_type
= ash::MultiProfileUMA::TELEPORT_WINDOW_V1_APP
;
112 } else if (browser
->is_type_popup()) {
113 window_type
= ash::MultiProfileUMA::TELEPORT_WINDOW_POPUP
;
115 window_type
= ash::MultiProfileUMA::TELEPORT_WINDOW_BROWSER
;
118 // Unit tests might come here without a profile manager.
119 if (!g_browser_process
->profile_manager())
121 // If it is not a browser, it is probably be a V2 application. In that case
122 // one of the AppWindowRegistry instances should know about it.
123 extensions::AppWindow
* app_window
= NULL
;
124 std::vector
<Profile
*> profiles
=
125 g_browser_process
->profile_manager()->GetLoadedProfiles();
126 for (std::vector
<Profile
*>::iterator it
= profiles
.begin();
127 it
!= profiles
.end() && app_window
== NULL
;
129 app_window
= extensions::AppWindowRegistry::Get(*it
)
130 ->GetAppWindowForNativeWindow(window
);
133 if (app_window
->window_type() ==
134 extensions::AppWindow::WINDOW_TYPE_PANEL
||
135 app_window
->window_type() ==
136 extensions::AppWindow::WINDOW_TYPE_V1_PANEL
) {
137 window_type
= ash::MultiProfileUMA::TELEPORT_WINDOW_PANEL
;
139 window_type
= ash::MultiProfileUMA::TELEPORT_WINDOW_V2_APP
;
143 ash::MultiProfileUMA::RecordTeleportWindowType(window_type
);
150 // A class to temporarily change the animation properties for a window.
151 class AnimationSetter
{
153 AnimationSetter(aura::Window
* window
, int animation_time_in_ms
)
155 previous_animation_type_(
156 wm::GetWindowVisibilityAnimationType(window_
)),
157 previous_animation_time_(
158 wm::GetWindowVisibilityAnimationDuration(*window_
)) {
159 wm::SetWindowVisibilityAnimationType(
161 wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE
);
162 wm::SetWindowVisibilityAnimationDuration(
164 base::TimeDelta::FromMilliseconds(animation_time_in_ms
));
168 wm::SetWindowVisibilityAnimationType(window_
,
169 previous_animation_type_
);
170 wm::SetWindowVisibilityAnimationDuration(
172 previous_animation_time_
);
176 // The window which gets used.
177 aura::Window
* window_
;
179 // Previous animation type.
180 const int previous_animation_type_
;
182 // Previous animation time.
183 const base::TimeDelta previous_animation_time_
;
185 DISALLOW_COPY_AND_ASSIGN(AnimationSetter
);
188 // This class keeps track of all applications which were started for a user.
189 // When an app gets created, the window will be tagged for that user. Note
190 // that the destruction does not need to be tracked here since the universal
191 // window observer will take care of that.
192 class AppObserver
: public extensions::AppWindowRegistry::Observer
{
194 explicit AppObserver(const std::string
& user_id
) : user_id_(user_id
) {}
195 ~AppObserver() override
{}
197 // AppWindowRegistry::Observer overrides:
198 void OnAppWindowAdded(extensions::AppWindow
* app_window
) override
{
199 aura::Window
* window
= app_window
->GetNativeWindow();
201 MultiUserWindowManagerChromeOS::GetInstance()->SetWindowOwner(window
,
206 std::string user_id_
;
208 DISALLOW_COPY_AND_ASSIGN(AppObserver
);
211 MultiUserWindowManagerChromeOS::MultiUserWindowManagerChromeOS(
212 const std::string
& current_user_id
)
213 : current_user_id_(current_user_id
),
214 notification_blocker_(new MultiUserNotificationBlockerChromeOS(
215 message_center::MessageCenter::Get(), current_user_id
)),
216 suppress_visibility_changes_(false),
217 animation_speed_(ANIMATION_SPEED_NORMAL
) {
220 MultiUserWindowManagerChromeOS::~MultiUserWindowManagerChromeOS() {
221 // When the MultiUserWindowManager gets destroyed, ash::Shell is mostly gone.
222 // As such we should not try to finalize any outstanding user animations.
223 // Note that the destruction of the object can be done later.
224 if (animation_
.get())
225 animation_
->CancelAnimation();
227 // Remove all window observers.
228 WindowToEntryMap::iterator window
= window_to_entry_
.begin();
229 while (window
!= window_to_entry_
.end()) {
230 OnWindowDestroyed(window
->first
);
231 window
= window_to_entry_
.begin();
234 // Remove all app observers.
235 UserIDToAppWindowObserver::iterator app_observer_iterator
=
236 user_id_to_app_observer_
.begin();
237 while (app_observer_iterator
!= user_id_to_app_observer_
.end()) {
238 Profile
* profile
= multi_user_util::GetProfileFromUserID(
239 app_observer_iterator
->first
);
241 extensions::AppWindowRegistry::Get(profile
)
242 ->RemoveObserver(app_observer_iterator
->second
);
243 delete app_observer_iterator
->second
;
244 user_id_to_app_observer_
.erase(app_observer_iterator
);
245 app_observer_iterator
= user_id_to_app_observer_
.begin();
248 if (ash::Shell::HasInstance())
249 ash::Shell::GetInstance()->session_state_delegate()->
250 RemoveSessionStateObserver(this);
253 void MultiUserWindowManagerChromeOS::Init() {
254 // Since we are setting the SessionStateObserver and adding the user, this
255 // function should get called only once.
256 DCHECK(user_id_to_app_observer_
.find(current_user_id_
) ==
257 user_id_to_app_observer_
.end());
259 // Add a session state observer to be able to monitor session changes.
260 if (ash::Shell::HasInstance()) {
261 ash::Shell::GetInstance()->session_state_delegate()->
262 AddSessionStateObserver(this);
265 // The BrowserListObserver would have been better to use then the old
266 // notification system, but that observer fires before the window got created.
267 registrar_
.Add(this, NOTIFICATION_BROWSER_WINDOW_READY
,
268 content::NotificationService::AllSources());
270 // Add an app window observer & all already running apps.
271 Profile
* profile
= multi_user_util::GetProfileFromUserID(current_user_id_
);
276 void MultiUserWindowManagerChromeOS::SetWindowOwner(
277 aura::Window
* window
,
278 const std::string
& user_id
) {
279 // Make sure the window is valid and there was no owner yet.
281 DCHECK(!user_id
.empty());
282 if (GetWindowOwner(window
) == user_id
)
284 DCHECK(GetWindowOwner(window
).empty());
285 window_to_entry_
[window
] = new WindowEntry(user_id
);
287 // Remember the initial visibility of the window.
288 window_to_entry_
[window
]->set_show(window
->IsVisible());
290 // Add observers to track state changes.
291 window
->AddObserver(this);
292 wm::TransientWindowManager::Get(window
)->AddObserver(this);
294 // Check if this window was created due to a user interaction. If it was,
295 // transfer it to the current user.
296 if (IsProcessingUserEvent())
297 window_to_entry_
[window
]->set_show_for_user(current_user_id_
);
299 // Add all transient children to our set of windows. Note that the function
300 // will add the children but not the owner to the transient children map.
301 AddTransientOwnerRecursive(window
, window
);
303 // Notify entry adding.
304 FOR_EACH_OBSERVER(Observer
, observers_
, OnOwnerEntryAdded(window
));
306 if (!IsWindowOnDesktopOfUser(window
, current_user_id_
))
307 SetWindowVisibility(window
, false, 0);
310 const std::string
& MultiUserWindowManagerChromeOS::GetWindowOwner(
311 aura::Window
* window
) const {
312 WindowToEntryMap::const_iterator it
= window_to_entry_
.find(window
);
313 return it
!= window_to_entry_
.end() ? it
->second
->owner()
314 : base::EmptyString();
317 void MultiUserWindowManagerChromeOS::ShowWindowForUser(
318 aura::Window
* window
,
319 const std::string
& user_id
) {
320 std::string
previous_owner(GetUserPresentingWindow(window
));
321 if (!ShowWindowForUserIntern(window
, user_id
))
323 // The window switched to a new desktop and we have to switch to that desktop,
324 // but only when it was on the visible desktop and the the target is not the
326 if (user_id
== current_user_id_
|| previous_owner
!= current_user_id_
)
329 ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
333 bool MultiUserWindowManagerChromeOS::AreWindowsSharedAmongUsers() const {
334 WindowToEntryMap::const_iterator it
= window_to_entry_
.begin();
335 for (; it
!= window_to_entry_
.end(); ++it
) {
336 if (it
->second
->owner() != it
->second
->show_for_user())
342 void MultiUserWindowManagerChromeOS::GetOwnersOfVisibleWindows(
343 std::set
<std::string
>* user_ids
) const {
344 for (WindowToEntryMap::const_iterator it
= window_to_entry_
.begin();
345 it
!= window_to_entry_
.end();
347 if (it
->first
->IsVisible())
348 user_ids
->insert(it
->second
->owner());
352 bool MultiUserWindowManagerChromeOS::IsWindowOnDesktopOfUser(
353 aura::Window
* window
,
354 const std::string
& user_id
) const {
355 const std::string
& presenting_user
= GetUserPresentingWindow(window
);
356 return presenting_user
.empty() || presenting_user
== user_id
;
359 const std::string
& MultiUserWindowManagerChromeOS::GetUserPresentingWindow(
360 aura::Window
* window
) const {
361 WindowToEntryMap::const_iterator it
= window_to_entry_
.find(window
);
362 // If the window is not owned by anyone it is shown on all desktops and we
363 // return the empty string.
364 if (it
== window_to_entry_
.end())
365 return base::EmptyString();
366 // Otherwise we ask the object for its desktop.
367 return it
->second
->show_for_user();
370 void MultiUserWindowManagerChromeOS::AddUser(content::BrowserContext
* context
) {
371 Profile
* profile
= Profile::FromBrowserContext(context
);
372 const std::string
& user_id
= multi_user_util::GetUserIDFromProfile(profile
);
373 if (user_id_to_app_observer_
.find(user_id
) != user_id_to_app_observer_
.end())
376 user_id_to_app_observer_
[user_id
] = new AppObserver(user_id
);
377 extensions::AppWindowRegistry::Get(profile
)
378 ->AddObserver(user_id_to_app_observer_
[user_id
]);
380 // Account all existing application windows of this user accordingly.
381 const extensions::AppWindowRegistry::AppWindowList
& app_windows
=
382 extensions::AppWindowRegistry::Get(profile
)->app_windows();
383 extensions::AppWindowRegistry::AppWindowList::const_iterator it
=
385 for (; it
!= app_windows
.end(); ++it
)
386 user_id_to_app_observer_
[user_id
]->OnAppWindowAdded(*it
);
388 // Account all existing browser windows of this user accordingly.
389 BrowserList
* browser_list
= BrowserList::GetInstance(HOST_DESKTOP_TYPE_ASH
);
390 BrowserList::const_iterator browser_it
= browser_list
->begin();
391 for (; browser_it
!= browser_list
->end(); ++browser_it
) {
392 if ((*browser_it
)->profile()->GetOriginalProfile() == profile
)
393 AddBrowserWindow(*browser_it
);
395 // When adding another user to the session, we auto switch users.
396 if (user_id_to_app_observer_
.size() == 1)
399 // Don't do anything special in case of user session restore after crash.
400 // In that case session restore process will automatically switch to the
401 // last active user session after whole process is complete.
402 if (!chromeos::UserSessionManager::GetInstance()->
403 UserSessionsRestoreInProgress()) {
404 // Immediately hide the windows of the current user.
405 base::AutoReset
<AnimationSpeed
> animation_speed(&animation_speed_
,
406 ANIMATION_SPEED_DISABLED
);
407 ActiveUserChanged(user_id
);
411 void MultiUserWindowManagerChromeOS::AddObserver(Observer
* observer
) {
412 observers_
.AddObserver(observer
);
415 void MultiUserWindowManagerChromeOS::RemoveObserver(Observer
* observer
) {
416 observers_
.RemoveObserver(observer
);
419 void MultiUserWindowManagerChromeOS::ActiveUserChanged(
420 const std::string
& user_id
) {
421 // This needs to be set before the animation starts.
422 current_user_id_
= user_id
;
425 new UserSwitchAnimatorChromeOS(
426 this, user_id
, GetAdjustedAnimationTimeInMS(kUserFadeTimeMS
)));
427 // Call notifier here instead of observing ActiveUserChanged because
428 // this must happen after MultiUserWindowManagerChromeOS is notified.
429 ash::Shell::GetInstance()
430 ->system_tray_notifier()
431 ->NotifyMediaCaptureChanged();
434 void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window
* window
) {
435 if (GetWindowOwner(window
).empty()) {
436 // This must be a window in the transient chain - remove it and its
437 // children from the owner.
438 RemoveTransientOwnerRecursive(window
);
441 wm::TransientWindowManager::Get(window
)->RemoveObserver(this);
442 // Remove the window from the owners list.
443 delete window_to_entry_
[window
];
444 window_to_entry_
.erase(window
);
446 // Notify entry change.
447 FOR_EACH_OBSERVER(Observer
, observers_
, OnOwnerEntryRemoved(window
));
450 void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanging(
451 aura::Window
* window
, bool visible
) {
452 // This command gets called first and immediately when show or hide gets
453 // called. We remember here the desired state for restoration IF we were
454 // not ourselves issuing the call.
455 // Note also that using the OnWindowVisibilityChanged callback cannot be
457 if (suppress_visibility_changes_
)
460 WindowToEntryMap::iterator it
= window_to_entry_
.find(window
);
461 // If the window is not owned by anyone it is shown on all desktops.
462 if (it
!= window_to_entry_
.end()) {
463 // Remember what was asked for so that we can restore this when the user's
464 // desktop gets restored.
465 it
->second
->set_show(visible
);
467 TransientWindowToVisibility::iterator it
=
468 transient_window_to_visibility_
.find(window
);
469 if (it
!= transient_window_to_visibility_
.end())
470 it
->second
= visible
;
474 void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanged(
475 aura::Window
* window
, bool visible
) {
476 if (suppress_visibility_changes_
)
479 // Don't allow to make the window visible if it shouldn't be.
480 if (visible
&& !IsWindowOnDesktopOfUser(window
, current_user_id_
)) {
481 SetWindowVisibility(window
, false, 0);
484 aura::Window
* owned_parent
= GetOwningWindowInTransientChain(window
);
485 if (owned_parent
&& owned_parent
!= window
&& visible
&&
486 !IsWindowOnDesktopOfUser(owned_parent
, current_user_id_
))
487 SetWindowVisibility(window
, false, 0);
490 void MultiUserWindowManagerChromeOS::OnTransientChildAdded(
491 aura::Window
* window
,
492 aura::Window
* transient_window
) {
493 if (!GetWindowOwner(window
).empty()) {
494 AddTransientOwnerRecursive(transient_window
, window
);
497 aura::Window
* owned_parent
=
498 GetOwningWindowInTransientChain(transient_window
);
502 AddTransientOwnerRecursive(transient_window
, owned_parent
);
505 void MultiUserWindowManagerChromeOS::OnTransientChildRemoved(
506 aura::Window
* window
,
507 aura::Window
* transient_window
) {
508 // Remove the transient child if the window itself is owned, or one of the
509 // windows in its transient parents chain.
510 if (!GetWindowOwner(window
).empty() ||
511 GetOwningWindowInTransientChain(window
))
512 RemoveTransientOwnerRecursive(transient_window
);
515 void MultiUserWindowManagerChromeOS::Observe(
517 const content::NotificationSource
& source
,
518 const content::NotificationDetails
& details
) {
519 if (type
== NOTIFICATION_BROWSER_WINDOW_READY
)
520 AddBrowserWindow(content::Source
<Browser
>(source
).ptr());
523 void MultiUserWindowManagerChromeOS::SetAnimationSpeedForTest(
524 MultiUserWindowManagerChromeOS::AnimationSpeed speed
) {
525 animation_speed_
= speed
;
528 bool MultiUserWindowManagerChromeOS::IsAnimationRunningForTest() {
529 return animation_
.get() != NULL
&& !animation_
->IsAnimationFinished();
532 const std::string
& MultiUserWindowManagerChromeOS::GetCurrentUserForTest()
534 return current_user_id_
;
537 bool MultiUserWindowManagerChromeOS::ShowWindowForUserIntern(
538 aura::Window
* window
,
539 const std::string
& user_id
) {
540 // If there is either no owner, or the owner is the current user, no action
542 const std::string
& owner
= GetWindowOwner(window
);
544 (owner
== user_id
&& IsWindowOnDesktopOfUser(window
, user_id
)))
547 bool minimized
= ash::wm::GetWindowState(window
)->IsMinimized();
548 // Check that we are not trying to transfer ownership of a minimized window.
549 if (user_id
!= owner
&& minimized
)
553 // If it is minimized it falls back to the original desktop.
554 ash::MultiProfileUMA::RecordTeleportAction(
555 ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_MINIMIZE
);
557 // If the window was transferred without getting minimized, we should record
559 RecordUMAForTransferredWindowType(window
);
562 WindowToEntryMap::iterator it
= window_to_entry_
.find(window
);
563 it
->second
->set_show_for_user(user_id
);
565 // Show the window if the added user is the current one.
566 if (user_id
== current_user_id_
) {
567 // Only show the window if it should be shown according to its state.
568 if (it
->second
->show())
569 SetWindowVisibility(window
, true, kTeleportAnimationTimeMS
);
571 SetWindowVisibility(window
, false, kTeleportAnimationTimeMS
);
574 // Notify entry change.
575 FOR_EACH_OBSERVER(Observer
, observers_
, OnOwnerEntryChanged(window
));
579 void MultiUserWindowManagerChromeOS::SetWindowVisibility(
580 aura::Window
* window
, bool visible
, int animation_time_in_ms
) {
581 if (window
->IsVisible() == visible
)
584 // Hiding a system modal dialog should not be allowed. Instead we switch to
585 // the user which is showing the system modal window.
586 // Note that in some cases (e.g. unit test) windows might not have a root
588 if (!visible
&& window
->GetRootWindow()) {
589 // Get the system modal container for the window's root window.
590 aura::Window
* system_modal_container
=
591 window
->GetRootWindow()->GetChildById(
592 ash::kShellWindowId_SystemModalContainer
);
593 if (window
->parent() == system_modal_container
) {
594 // The window is system modal and we need to find the parent which owns
595 // it so that we can switch to the desktop accordingly.
596 std::string user_id
= GetUserPresentingWindow(window
);
597 if (user_id
.empty()) {
598 aura::Window
* owning_window
= GetOwningWindowInTransientChain(window
);
599 DCHECK(owning_window
);
600 user_id
= GetUserPresentingWindow(owning_window
);
601 DCHECK(!user_id
.empty());
603 ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
609 // To avoid that these commands are recorded as any other commands, we are
610 // suppressing any window entry changes while this is going on.
611 base::AutoReset
<bool> suppressor(&suppress_visibility_changes_
, true);
614 ShowWithTransientChildrenRecursive(window
, animation_time_in_ms
);
616 if (window
->HasFocus())
618 SetWindowVisible(window
, false, animation_time_in_ms
);
622 void MultiUserWindowManagerChromeOS::AddBrowserWindow(Browser
* browser
) {
623 // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
624 // come here with no valid window.
625 if (!browser
->window() || !browser
->window()->GetNativeWindow())
627 SetWindowOwner(browser
->window()->GetNativeWindow(),
628 multi_user_util::GetUserIDFromProfile(browser
->profile()));
631 void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive(
632 aura::Window
* window
, int animation_time_in_ms
) {
633 aura::Window::Windows::const_iterator it
=
634 wm::GetTransientChildren(window
).begin();
635 for (; it
!= wm::GetTransientChildren(window
).end(); ++it
)
636 ShowWithTransientChildrenRecursive(*it
, animation_time_in_ms
);
638 // We show all children which were not explicitly hidden.
639 TransientWindowToVisibility::iterator it2
=
640 transient_window_to_visibility_
.find(window
);
641 if (it2
== transient_window_to_visibility_
.end() || it2
->second
)
642 SetWindowVisible(window
, true, animation_time_in_ms
);
645 aura::Window
* MultiUserWindowManagerChromeOS::GetOwningWindowInTransientChain(
646 aura::Window
* window
) const {
647 if (!GetWindowOwner(window
).empty())
649 aura::Window
* parent
= wm::GetTransientParent(window
);
651 if (!GetWindowOwner(parent
).empty())
653 parent
= wm::GetTransientParent(parent
);
658 void MultiUserWindowManagerChromeOS::AddTransientOwnerRecursive(
659 aura::Window
* window
,
660 aura::Window
* owned_parent
) {
661 // First add all child windows.
662 aura::Window::Windows::const_iterator it
=
663 wm::GetTransientChildren(window
).begin();
664 for (; it
!= wm::GetTransientChildren(window
).end(); ++it
)
665 AddTransientOwnerRecursive(*it
, owned_parent
);
667 // If this window is the owned window, we do not have to handle it again.
668 if (window
== owned_parent
)
671 // Remember the current visibility.
672 DCHECK(transient_window_to_visibility_
.find(window
) ==
673 transient_window_to_visibility_
.end());
674 transient_window_to_visibility_
[window
] = window
->IsVisible();
676 // Add observers to track state changes.
677 window
->AddObserver(this);
678 wm::TransientWindowManager::Get(window
)->AddObserver(this);
680 // Hide the window if it should not be shown. Note that this hide operation
681 // will hide recursively this and all children - but we have already collected
682 // their initial view state.
683 if (!IsWindowOnDesktopOfUser(owned_parent
, current_user_id_
))
684 SetWindowVisibility(window
, false, kAnimationTimeMS
);
687 void MultiUserWindowManagerChromeOS::RemoveTransientOwnerRecursive(
688 aura::Window
* window
) {
689 // First remove all child windows.
690 aura::Window::Windows::const_iterator it
=
691 wm::GetTransientChildren(window
).begin();
692 for (; it
!= wm::GetTransientChildren(window
).end(); ++it
)
693 RemoveTransientOwnerRecursive(*it
);
695 // Find from transient window storage the visibility for the given window,
696 // set the visibility accordingly and delete the window from the map.
697 TransientWindowToVisibility::iterator visibility_item
=
698 transient_window_to_visibility_
.find(window
);
699 DCHECK(visibility_item
!= transient_window_to_visibility_
.end());
701 window
->RemoveObserver(this);
702 wm::TransientWindowManager::Get(window
)->RemoveObserver(this);
704 bool unowned_view_state
= visibility_item
->second
;
705 transient_window_to_visibility_
.erase(visibility_item
);
706 if (unowned_view_state
&& !window
->IsVisible()) {
707 // To prevent these commands from being recorded as any other commands, we
708 // are suppressing any window entry changes while this is going on.
709 // Instead of calling SetWindowVisible, only show gets called here since all
710 // dependents have been shown previously already.
711 base::AutoReset
<bool> suppressor(&suppress_visibility_changes_
, true);
716 void MultiUserWindowManagerChromeOS::SetWindowVisible(
717 aura::Window
* window
,
719 int animation_time_in_ms
) {
720 // The MaximizeModeWindowManager will not handle invisible windows since they
721 // are not user activatable. Since invisible windows are not being tracked,
722 // we tell it to maximize / track this window now before it gets shown, to
723 // reduce animation jank from multiple resizes.
725 ash::Shell::GetInstance()->maximize_mode_controller()->AddWindow(window
);
727 AnimationSetter
animation_setter(
729 GetAdjustedAnimationTimeInMS(animation_time_in_ms
));
736 // Make sure that animations have no influence on the window state after the
738 DCHECK_EQ(visible
, window
->IsVisible());
741 int MultiUserWindowManagerChromeOS::GetAdjustedAnimationTimeInMS(
742 int default_time_in_ms
) const {
743 return animation_speed_
== ANIMATION_SPEED_NORMAL
? default_time_in_ms
:
744 (animation_speed_
== ANIMATION_SPEED_FAST
? 10 : 0);
747 } // namespace chrome