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/profiles/profile.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
26 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
27 #include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h"
28 #include "chrome/browser/ui/browser.h"
29 #include "chrome/browser/ui/browser_finder.h"
30 #include "chrome/browser/ui/browser_list.h"
31 #include "chrome/browser/ui/browser_window.h"
32 #include "content/public/browser/notification_service.h"
33 #include "extensions/browser/app_window/app_window.h"
34 #include "extensions/browser/app_window/app_window_registry.h"
35 #include "google_apis/gaia/gaia_auth_util.h"
36 #include "ui/aura/client/aura_constants.h"
37 #include "ui/aura/window.h"
38 #include "ui/aura/window_event_dispatcher.h"
39 #include "ui/base/ui_base_types.h"
40 #include "ui/events/event.h"
41 #include "ui/message_center/message_center.h"
42 #include "ui/wm/core/transient_window_manager.h"
43 #include "ui/wm/core/window_animations.h"
44 #include "ui/wm/core/window_util.h"
48 // The animation time in milliseconds for a single window which is fading
50 const int kAnimationTimeMS = 100;
52 // The animation time in milliseconds for the fade in and / or out when
54 const int kUserFadeTimeMS = 110;
56 // The animation time in ms for a window which get teleported to another screen.
57 const int kTeleportAnimationTimeMS = 300;
59 // Checks if a given event is a user event.
60 bool IsUserEvent(const ui::Event* e) {
62 ui::EventType type = e->type();
63 if (type != ui::ET_CANCEL_MODE &&
64 type != ui::ET_UMA_DATA &&
65 type != ui::ET_UNKNOWN)
71 // Test if we are currently processing a user event which might lead to a
72 // browser / app creation.
73 bool IsProcessingUserEvent() {
74 // When there is a nested message loop (e.g. active menu or drag and drop
75 // operation) - we are in a nested loop and can ignore this.
76 // Note: Unit tests might not have a message loop.
77 base::MessageLoop* message_loop = base::MessageLoop::current();
78 if (message_loop && message_loop->is_running() && message_loop->IsNested())
81 // TODO(skuhne): "Open link in new window" will come here after the menu got
82 // closed, executing the command from the nested menu loop. However at that
83 // time there is no active event processed. A solution for that need to be
84 // found past M-32. A global event handler filter (pre and post) might fix
85 // that problem in conjunction with a depth counter - but - for the menu
86 // execution we come here after the loop was finished (so it's not nested
87 // anymore) and the root window should therefore still have the event which
88 // lead to the menu invocation, but it is not. By fixing that problem this
89 // would "magically work".
90 aura::Window::Windows root_window_list = ash::Shell::GetAllRootWindows();
91 for (aura::Window::Windows::iterator it = root_window_list.begin();
92 it != root_window_list.end();
94 if (IsUserEvent((*it)->GetHost()->dispatcher()->current_event()))
100 // Records the type of window which was transferred to another desktop.
101 void RecordUMAForTransferredWindowType(aura::Window* window) {
102 // We need to figure out what kind of window this is to record the transfer.
103 Browser* browser = chrome::FindBrowserWithWindow(window);
104 ash::MultiProfileUMA::TeleportWindowType window_type =
105 ash::MultiProfileUMA::TELEPORT_WINDOW_UNKNOWN;
107 if (browser->profile()->IsOffTheRecord()) {
108 window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_INCOGNITO_BROWSER;
109 } else if (browser->is_app()) {
110 window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_V1_APP;
111 } else if (browser->is_type_popup()) {
112 window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_POPUP;
114 window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_BROWSER;
117 // Unit tests might come here without a profile manager.
118 if (!g_browser_process->profile_manager())
120 // If it is not a browser, it is probably be a V2 application. In that case
121 // one of the AppWindowRegistry instances should know about it.
122 extensions::AppWindow* app_window = NULL;
123 std::vector<Profile*> profiles =
124 g_browser_process->profile_manager()->GetLoadedProfiles();
125 for (std::vector<Profile*>::iterator it = profiles.begin();
126 it != profiles.end() && app_window == NULL;
128 app_window = extensions::AppWindowRegistry::Get(*it)
129 ->GetAppWindowForNativeWindow(window);
132 if (app_window->window_type() ==
133 extensions::AppWindow::WINDOW_TYPE_PANEL ||
134 app_window->window_type() ==
135 extensions::AppWindow::WINDOW_TYPE_V1_PANEL) {
136 window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_PANEL;
138 window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_V2_APP;
142 ash::MultiProfileUMA::RecordTeleportWindowType(window_type);
149 // A class to temporarily change the animation properties for a window.
150 class AnimationSetter {
152 AnimationSetter(aura::Window* window, int animation_time_in_ms)
154 previous_animation_type_(
155 wm::GetWindowVisibilityAnimationType(window_)),
156 previous_animation_time_(
157 wm::GetWindowVisibilityAnimationDuration(*window_)) {
158 wm::SetWindowVisibilityAnimationType(
160 wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
161 wm::SetWindowVisibilityAnimationDuration(
163 base::TimeDelta::FromMilliseconds(animation_time_in_ms));
167 wm::SetWindowVisibilityAnimationType(window_,
168 previous_animation_type_);
169 wm::SetWindowVisibilityAnimationDuration(
171 previous_animation_time_);
175 // The window which gets used.
176 aura::Window* window_;
178 // Previous animation type.
179 const int previous_animation_type_;
181 // Previous animation time.
182 const base::TimeDelta previous_animation_time_;
184 DISALLOW_COPY_AND_ASSIGN(AnimationSetter);
187 // This class keeps track of all applications which were started for a user.
188 // When an app gets created, the window will be tagged for that user. Note
189 // that the destruction does not need to be tracked here since the universal
190 // window observer will take care of that.
191 class AppObserver : public extensions::AppWindowRegistry::Observer {
193 explicit AppObserver(const std::string& user_id) : user_id_(user_id) {}
194 virtual ~AppObserver() {}
196 // AppWindowRegistry::Observer overrides:
197 virtual void OnAppWindowAdded(extensions::AppWindow* app_window) OVERRIDE {
198 aura::Window* window = app_window->GetNativeWindow();
200 MultiUserWindowManagerChromeOS::GetInstance()->SetWindowOwner(window,
205 std::string user_id_;
207 DISALLOW_COPY_AND_ASSIGN(AppObserver);
210 MultiUserWindowManagerChromeOS::MultiUserWindowManagerChromeOS(
211 const std::string& current_user_id)
212 : current_user_id_(current_user_id),
213 notification_blocker_(new MultiUserNotificationBlockerChromeOS(
214 message_center::MessageCenter::Get(), current_user_id)),
215 suppress_visibility_changes_(false),
216 animation_speed_(ANIMATION_SPEED_NORMAL) {
217 // Add a session state observer to be able to monitor session changes.
218 if (ash::Shell::HasInstance())
219 ash::Shell::GetInstance()->session_state_delegate()->
220 AddSessionStateObserver(this);
222 // The BrowserListObserver would have been better to use then the old
223 // notification system, but that observer fires before the window got created.
224 registrar_.Add(this, NOTIFICATION_BROWSER_WINDOW_READY,
225 content::NotificationService::AllSources());
227 // Add an app window observer & all already running apps.
228 Profile* profile = multi_user_util::GetProfileFromUserID(current_user_id);
233 MultiUserWindowManagerChromeOS::~MultiUserWindowManagerChromeOS() {
234 // When the MultiUserWindowManager gets destroyed, ash::Shell is mostly gone.
235 // As such we should not try to finalize any outstanding user animations.
236 // Note that the destruction of the object can be done later.
237 if (animation_.get())
238 animation_->CancelAnimation();
240 // Remove all window observers.
241 WindowToEntryMap::iterator window = window_to_entry_.begin();
242 while (window != window_to_entry_.end()) {
243 OnWindowDestroyed(window->first);
244 window = window_to_entry_.begin();
247 // Remove all app observers.
248 UserIDToAppWindowObserver::iterator app_observer_iterator =
249 user_id_to_app_observer_.begin();
250 while (app_observer_iterator != user_id_to_app_observer_.end()) {
251 Profile* profile = multi_user_util::GetProfileFromUserID(
252 app_observer_iterator->first);
254 extensions::AppWindowRegistry::Get(profile)
255 ->RemoveObserver(app_observer_iterator->second);
256 delete app_observer_iterator->second;
257 user_id_to_app_observer_.erase(app_observer_iterator);
258 app_observer_iterator = user_id_to_app_observer_.begin();
261 if (ash::Shell::HasInstance())
262 ash::Shell::GetInstance()->session_state_delegate()->
263 RemoveSessionStateObserver(this);
266 void MultiUserWindowManagerChromeOS::SetWindowOwner(
267 aura::Window* window,
268 const std::string& user_id) {
269 // Make sure the window is valid and there was no owner yet.
271 DCHECK(!user_id.empty());
272 if (GetWindowOwner(window) == user_id)
274 DCHECK(GetWindowOwner(window).empty());
275 window_to_entry_[window] = new WindowEntry(user_id);
277 // Remember the initial visibility of the window.
278 window_to_entry_[window]->set_show(window->IsVisible());
280 // Add observers to track state changes.
281 window->AddObserver(this);
282 wm::TransientWindowManager::Get(window)->AddObserver(this);
284 // Check if this window was created due to a user interaction. If it was,
285 // transfer it to the current user.
286 if (IsProcessingUserEvent())
287 window_to_entry_[window]->set_show_for_user(current_user_id_);
289 // Add all transient children to our set of windows. Note that the function
290 // will add the children but not the owner to the transient children map.
291 AddTransientOwnerRecursive(window, window);
293 // Notify entry adding.
294 FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryAdded(window));
296 if (!IsWindowOnDesktopOfUser(window, current_user_id_))
297 SetWindowVisibility(window, false, 0);
300 const std::string& MultiUserWindowManagerChromeOS::GetWindowOwner(
301 aura::Window* window) const {
302 WindowToEntryMap::const_iterator it = window_to_entry_.find(window);
303 return it != window_to_entry_.end() ? it->second->owner()
304 : base::EmptyString();
307 void MultiUserWindowManagerChromeOS::ShowWindowForUser(
308 aura::Window* window,
309 const std::string& user_id) {
310 std::string previous_owner(GetUserPresentingWindow(window));
311 if (!ShowWindowForUserIntern(window, user_id))
313 // The window switched to a new desktop and we have to switch to that desktop,
314 // but only when it was on the visible desktop and the the target is not the
316 if (user_id == current_user_id_ || previous_owner != current_user_id_)
319 ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
323 bool MultiUserWindowManagerChromeOS::AreWindowsSharedAmongUsers() const {
324 WindowToEntryMap::const_iterator it = window_to_entry_.begin();
325 for (; it != window_to_entry_.end(); ++it) {
326 if (it->second->owner() != it->second->show_for_user())
332 void MultiUserWindowManagerChromeOS::GetOwnersOfVisibleWindows(
333 std::set<std::string>* user_ids) const {
334 for (WindowToEntryMap::const_iterator it = window_to_entry_.begin();
335 it != window_to_entry_.end();
337 if (it->first->IsVisible())
338 user_ids->insert(it->second->owner());
342 bool MultiUserWindowManagerChromeOS::IsWindowOnDesktopOfUser(
343 aura::Window* window,
344 const std::string& user_id) const {
345 const std::string& presenting_user = GetUserPresentingWindow(window);
346 return presenting_user.empty() || presenting_user == user_id;
349 const std::string& MultiUserWindowManagerChromeOS::GetUserPresentingWindow(
350 aura::Window* window) const {
351 WindowToEntryMap::const_iterator it = window_to_entry_.find(window);
352 // If the window is not owned by anyone it is shown on all desktops and we
353 // return the empty string.
354 if (it == window_to_entry_.end())
355 return base::EmptyString();
356 // Otherwise we ask the object for its desktop.
357 return it->second->show_for_user();
360 void MultiUserWindowManagerChromeOS::AddUser(content::BrowserContext* context) {
361 Profile* profile = Profile::FromBrowserContext(context);
362 const std::string& user_id = multi_user_util::GetUserIDFromProfile(profile);
363 if (user_id_to_app_observer_.find(user_id) != user_id_to_app_observer_.end())
366 user_id_to_app_observer_[user_id] = new AppObserver(user_id);
367 extensions::AppWindowRegistry::Get(profile)
368 ->AddObserver(user_id_to_app_observer_[user_id]);
370 // Account all existing application windows of this user accordingly.
371 const extensions::AppWindowRegistry::AppWindowList& app_windows =
372 extensions::AppWindowRegistry::Get(profile)->app_windows();
373 extensions::AppWindowRegistry::AppWindowList::const_iterator it =
375 for (; it != app_windows.end(); ++it)
376 user_id_to_app_observer_[user_id]->OnAppWindowAdded(*it);
378 // Account all existing browser windows of this user accordingly.
379 BrowserList* browser_list = BrowserList::GetInstance(HOST_DESKTOP_TYPE_ASH);
380 BrowserList::const_iterator browser_it = browser_list->begin();
381 for (; browser_it != browser_list->end(); ++browser_it) {
382 if ((*browser_it)->profile()->GetOriginalProfile() == profile)
383 AddBrowserWindow(*browser_it);
387 void MultiUserWindowManagerChromeOS::AddObserver(Observer* observer) {
388 observers_.AddObserver(observer);
391 void MultiUserWindowManagerChromeOS::RemoveObserver(Observer* observer) {
392 observers_.RemoveObserver(observer);
395 void MultiUserWindowManagerChromeOS::ActiveUserChanged(
396 const std::string& user_id) {
397 DCHECK(user_id != current_user_id_);
398 // This needs to be set before the animation starts.
399 current_user_id_ = user_id;
402 new UserSwichAnimatorChromeOS(
403 this, user_id, GetAdjustedAnimationTimeInMS(kUserFadeTimeMS)));
404 // Call notifier here instead of observing ActiveUserChanged because
405 // this must happen after MultiUserWindowManagerChromeOS is notified.
406 ash::Shell::GetInstance()
407 ->system_tray_notifier()
408 ->NotifyMediaCaptureChanged();
411 void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window* window) {
412 if (GetWindowOwner(window).empty()) {
413 // This must be a window in the transient chain - remove it and its
414 // children from the owner.
415 RemoveTransientOwnerRecursive(window);
418 wm::TransientWindowManager::Get(window)->RemoveObserver(this);
419 // Remove the window from the owners list.
420 delete window_to_entry_[window];
421 window_to_entry_.erase(window);
423 // Notify entry change.
424 FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryRemoved(window));
427 void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanging(
428 aura::Window* window, bool visible) {
429 // This command gets called first and immediately when show or hide gets
430 // called. We remember here the desired state for restoration IF we were
431 // not ourselves issuing the call.
432 // Note also that using the OnWindowVisibilityChanged callback cannot be
434 if (suppress_visibility_changes_)
437 WindowToEntryMap::iterator it = window_to_entry_.find(window);
438 // If the window is not owned by anyone it is shown on all desktops.
439 if (it != window_to_entry_.end()) {
440 // Remember what was asked for so that we can restore this when the user's
441 // desktop gets restored.
442 it->second->set_show(visible);
444 TransientWindowToVisibility::iterator it =
445 transient_window_to_visibility_.find(window);
446 if (it != transient_window_to_visibility_.end())
447 it->second = visible;
451 void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanged(
452 aura::Window* window, bool visible) {
453 if (suppress_visibility_changes_)
456 // Don't allow to make the window visible if it shouldn't be.
457 if (visible && !IsWindowOnDesktopOfUser(window, current_user_id_)) {
458 SetWindowVisibility(window, false, 0);
461 aura::Window* owned_parent = GetOwningWindowInTransientChain(window);
462 if (owned_parent && owned_parent != window && visible &&
463 !IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
464 SetWindowVisibility(window, false, 0);
467 void MultiUserWindowManagerChromeOS::OnTransientChildAdded(
468 aura::Window* window,
469 aura::Window* transient_window) {
470 if (!GetWindowOwner(window).empty()) {
471 AddTransientOwnerRecursive(transient_window, window);
474 aura::Window* owned_parent =
475 GetOwningWindowInTransientChain(transient_window);
479 AddTransientOwnerRecursive(transient_window, owned_parent);
482 void MultiUserWindowManagerChromeOS::OnTransientChildRemoved(
483 aura::Window* window,
484 aura::Window* transient_window) {
485 // Remove the transient child if the window itself is owned, or one of the
486 // windows in its transient parents chain.
487 if (!GetWindowOwner(window).empty() ||
488 GetOwningWindowInTransientChain(window))
489 RemoveTransientOwnerRecursive(transient_window);
492 void MultiUserWindowManagerChromeOS::Observe(
494 const content::NotificationSource& source,
495 const content::NotificationDetails& details) {
496 if (type == NOTIFICATION_BROWSER_WINDOW_READY)
497 AddBrowserWindow(content::Source<Browser>(source).ptr());
500 void MultiUserWindowManagerChromeOS::SetAnimationSpeedForTest(
501 MultiUserWindowManagerChromeOS::AnimationSpeed speed) {
502 animation_speed_ = speed;
505 bool MultiUserWindowManagerChromeOS::IsAnimationRunningForTest() {
506 return animation_.get() != NULL && !animation_->IsAnimationFinished();
509 const std::string& MultiUserWindowManagerChromeOS::GetCurrentUserForTest()
511 return current_user_id_;
514 bool MultiUserWindowManagerChromeOS::ShowWindowForUserIntern(
515 aura::Window* window,
516 const std::string& user_id) {
517 // If there is either no owner, or the owner is the current user, no action
519 const std::string& owner = GetWindowOwner(window);
521 (owner == user_id && IsWindowOnDesktopOfUser(window, user_id)))
524 bool minimized = ash::wm::GetWindowState(window)->IsMinimized();
525 // Check that we are not trying to transfer ownership of a minimized window.
526 if (user_id != owner && minimized)
530 // If it is minimized it falls back to the original desktop.
531 ash::MultiProfileUMA::RecordTeleportAction(
532 ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_MINIMIZE);
534 // If the window was transferred without getting minimized, we should record
536 RecordUMAForTransferredWindowType(window);
539 WindowToEntryMap::iterator it = window_to_entry_.find(window);
540 it->second->set_show_for_user(user_id);
542 // Show the window if the added user is the current one.
543 if (user_id == current_user_id_) {
544 // Only show the window if it should be shown according to its state.
545 if (it->second->show())
546 SetWindowVisibility(window, true, kTeleportAnimationTimeMS);
548 SetWindowVisibility(window, false, kTeleportAnimationTimeMS);
551 // Notify entry change.
552 FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryChanged(window));
556 void MultiUserWindowManagerChromeOS::SetWindowVisibility(
557 aura::Window* window, bool visible, int animation_time_in_ms) {
558 if (window->IsVisible() == visible)
561 // Hiding a system modal dialog should not be allowed. Instead we switch to
562 // the user which is showing the system modal window.
563 // Note that in some cases (e.g. unit test) windows might not have a root
565 if (!visible && window->GetRootWindow()) {
566 // Get the system modal container for the window's root window.
567 aura::Window* system_modal_container =
568 window->GetRootWindow()->GetChildById(
569 ash::kShellWindowId_SystemModalContainer);
570 if (window->parent() == system_modal_container) {
571 // The window is system modal and we need to find the parent which owns
572 // it so that we can switch to the desktop accordingly.
573 std::string user_id = GetUserPresentingWindow(window);
574 if (user_id.empty()) {
575 aura::Window* owning_window = GetOwningWindowInTransientChain(window);
576 DCHECK(owning_window);
577 user_id = GetUserPresentingWindow(owning_window);
578 DCHECK(!user_id.empty());
580 ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
586 // To avoid that these commands are recorded as any other commands, we are
587 // suppressing any window entry changes while this is going on.
588 base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
591 ShowWithTransientChildrenRecursive(window, animation_time_in_ms);
593 if (window->HasFocus())
595 SetWindowVisible(window, false, animation_time_in_ms);
599 void MultiUserWindowManagerChromeOS::AddBrowserWindow(Browser* browser) {
600 // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
601 // come here with no valid window.
602 if (!browser->window() || !browser->window()->GetNativeWindow())
604 SetWindowOwner(browser->window()->GetNativeWindow(),
605 multi_user_util::GetUserIDFromProfile(browser->profile()));
608 void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive(
609 aura::Window* window, int animation_time_in_ms) {
610 aura::Window::Windows::const_iterator it =
611 wm::GetTransientChildren(window).begin();
612 for (; it != wm::GetTransientChildren(window).end(); ++it)
613 ShowWithTransientChildrenRecursive(*it, animation_time_in_ms);
615 // We show all children which were not explicitly hidden.
616 TransientWindowToVisibility::iterator it2 =
617 transient_window_to_visibility_.find(window);
618 if (it2 == transient_window_to_visibility_.end() || it2->second)
619 SetWindowVisible(window, true, animation_time_in_ms);
622 aura::Window* MultiUserWindowManagerChromeOS::GetOwningWindowInTransientChain(
623 aura::Window* window) const {
624 if (!GetWindowOwner(window).empty())
626 aura::Window* parent = wm::GetTransientParent(window);
628 if (!GetWindowOwner(parent).empty())
630 parent = wm::GetTransientParent(parent);
635 void MultiUserWindowManagerChromeOS::AddTransientOwnerRecursive(
636 aura::Window* window,
637 aura::Window* owned_parent) {
638 // First add all child windows.
639 aura::Window::Windows::const_iterator it =
640 wm::GetTransientChildren(window).begin();
641 for (; it != wm::GetTransientChildren(window).end(); ++it)
642 AddTransientOwnerRecursive(*it, owned_parent);
644 // If this window is the owned window, we do not have to handle it again.
645 if (window == owned_parent)
648 // Remember the current visibility.
649 DCHECK(transient_window_to_visibility_.find(window) ==
650 transient_window_to_visibility_.end());
651 transient_window_to_visibility_[window] = window->IsVisible();
653 // Add observers to track state changes.
654 window->AddObserver(this);
655 wm::TransientWindowManager::Get(window)->AddObserver(this);
657 // Hide the window if it should not be shown. Note that this hide operation
658 // will hide recursively this and all children - but we have already collected
659 // their initial view state.
660 if (!IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
661 SetWindowVisibility(window, false, kAnimationTimeMS);
664 void MultiUserWindowManagerChromeOS::RemoveTransientOwnerRecursive(
665 aura::Window* window) {
666 // First remove all child windows.
667 aura::Window::Windows::const_iterator it =
668 wm::GetTransientChildren(window).begin();
669 for (; it != wm::GetTransientChildren(window).end(); ++it)
670 RemoveTransientOwnerRecursive(*it);
672 // Find from transient window storage the visibility for the given window,
673 // set the visibility accordingly and delete the window from the map.
674 TransientWindowToVisibility::iterator visibility_item =
675 transient_window_to_visibility_.find(window);
676 DCHECK(visibility_item != transient_window_to_visibility_.end());
678 window->RemoveObserver(this);
679 wm::TransientWindowManager::Get(window)->RemoveObserver(this);
681 bool unowned_view_state = visibility_item->second;
682 transient_window_to_visibility_.erase(visibility_item);
683 if (unowned_view_state && !window->IsVisible()) {
684 // To prevent these commands from being recorded as any other commands, we
685 // are suppressing any window entry changes while this is going on.
686 // Instead of calling SetWindowVisible, only show gets called here since all
687 // dependents have been shown previously already.
688 base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
693 void MultiUserWindowManagerChromeOS::SetWindowVisible(
694 aura::Window* window,
696 int animation_time_in_ms) {
697 // The MaximizeModeWindowManager will not handle invisible windows since they
698 // are not user activatable. Since invisible windows are not being tracked,
699 // we tell it to maximize / track this window now before it gets shown, to
700 // reduce animation jank from multiple resizes.
702 ash::Shell::GetInstance()->maximize_mode_controller()->AddWindow(window);
704 AnimationSetter animation_setter(
706 GetAdjustedAnimationTimeInMS(animation_time_in_ms));
713 // Make sure that animations have no influence on the window state after the
715 DCHECK_EQ(visible, window->IsVisible());
718 int MultiUserWindowManagerChromeOS::GetAdjustedAnimationTimeInMS(
719 int default_time_in_ms) const {
720 return animation_speed_ == ANIMATION_SPEED_NORMAL ? default_time_in_ms :
721 (animation_speed_ == ANIMATION_SPEED_FAST ? 10 : 0);
724 } // namespace chrome