- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / multi_user_window_manager.cc
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.
4
5 #include "chrome/browser/ui/ash/multi_user_window_manager.h"
6
7 #include "apps/shell_window.h"
8 #include "apps/shell_window_registry.h"
9 #include "ash/ash_switches.h"
10 #include "ash/multi_profile_uma.h"
11 #include "ash/session_state_delegate.h"
12 #include "ash/shell.h"
13 #include "ash/shell_delegate.h"
14 #include "ash/wm/mru_window_tracker.h"
15 #include "ash/wm/window_positioner.h"
16 #include "ash/wm/window_state.h"
17 #include "base/auto_reset.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/strings/string_util.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/chromeos/login/user_manager.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_list.h"
27 #include "chrome/browser/ui/browser_window.h"
28 #include "content/public/browser/notification_service.h"
29 #include "google_apis/gaia/gaia_auth_util.h"
30 #include "ui/aura/client/activation_client.h"
31 #include "ui/aura/client/aura_constants.h"
32 #include "ui/aura/root_window.h"
33 #include "ui/aura/window.h"
34 #include "ui/base/ui_base_types.h"
35 #include "ui/events/event.h"
36
37 namespace {
38 chrome::MultiUserWindowManager* g_instance = NULL;
39
40
41 // Checks if a given event is a user event.
42 bool IsUserEvent(ui::Event* e) {
43   if (e) {
44     ui::EventType type = e->type();
45     if (type != ui::ET_CANCEL_MODE &&
46         type != ui::ET_UMA_DATA &&
47         type != ui::ET_UNKNOWN)
48       return true;
49   }
50   return false;
51 }
52
53 // Test if we are currently processing a user event which might lead to a
54 // browser / app creation.
55 bool IsProcessingUserEvent() {
56   // When there is a nested message loop (e.g. active menu or drag and drop
57   // operation) - we are in a nested loop and can ignore this.
58   // Note: Unit tests might not have a message loop.
59   base::MessageLoop* message_loop = base::MessageLoop::current();
60   if (message_loop && message_loop->is_running() && message_loop->IsNested())
61     return false;
62
63   // TODO(skuhne): "Open link in new window" will come here after the menu got
64   // closed, executing the command from the nested menu loop. However at that
65   // time there is no active event processed. A solution for that need to be
66   // found past M-32. A global event handler filter (pre and post) might fix
67   // that problem in conjunction with a depth counter - but - for the menu
68   // execution we come here after the loop was finished (so it's not nested
69   // anymore) and the root window should therefore still have the event which
70   // lead to the menu invocation, but it is not. By fixing that problem this
71   // would "magically work".
72   ash::Shell::RootWindowList root_window_list = ash::Shell::GetAllRootWindows();
73   for (ash::Shell::RootWindowList::iterator it = root_window_list.begin();
74        it != root_window_list.end();
75        ++it) {
76     if (IsUserEvent((*it)->current_event()))
77       return true;
78   }
79   return false;
80 }
81
82 }  // namespace
83
84 namespace chrome {
85
86 // Caching the current multi profile mode since the detection which mode is
87 // used is quite expensive.
88 chrome::MultiUserWindowManager::MultiProfileMode
89     chrome::MultiUserWindowManager::multi_user_mode_ =
90         chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_UNINITIALIZED;
91
92 // A class to disable updates to the MRU window list and the auto positioning
93 // logic while the user gets switched.
94 class UserChangeActionDisabler {
95  public:
96   UserChangeActionDisabler() {
97     ash::WindowPositioner::DisableAutoPositioning(true);
98     ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
99   }
100
101   ~UserChangeActionDisabler() {
102     ash::WindowPositioner::DisableAutoPositioning(false);
103     ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(
104         false);
105   }
106  private:
107
108   DISALLOW_COPY_AND_ASSIGN(UserChangeActionDisabler);
109 };
110
111 // This class keeps track of all applications which were started for a user.
112 // When an app gets created, the window will be tagged for that user. Note
113 // that the destruction does not need to be tracked here since the universal
114 // window observer will take care of that.
115 class AppObserver : public apps::ShellWindowRegistry::Observer {
116  public:
117   explicit AppObserver(const std::string& user_id) : user_id_(user_id) {}
118   virtual ~AppObserver() {}
119
120   // ShellWindowRegistry::Observer overrides:
121   virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {
122     aura::Window* window = shell_window->GetNativeWindow();
123     DCHECK(window);
124     chrome::MultiUserWindowManager::GetInstance()->SetWindowOwner(window,
125                                                                   user_id_);
126   }
127   virtual void OnShellWindowIconChanged(apps::ShellWindow* shell_window)
128       OVERRIDE {}
129   virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window)
130       OVERRIDE {}
131
132  private:
133   std::string user_id_;
134
135   DISALLOW_COPY_AND_ASSIGN(AppObserver);
136 };
137
138 // static
139 MultiUserWindowManager* MultiUserWindowManager::GetInstance() {
140   return g_instance;
141 }
142
143 MultiUserWindowManager* MultiUserWindowManager::CreateInstance() {
144   ash::MultiProfileUMA::SessionMode mode =
145       ash::MultiProfileUMA::SESSION_SINGLE_USER_MODE;
146   if (!g_instance &&
147       ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled() &&
148       !ash::switches::UseFullMultiProfileMode()) {
149     g_instance = CreateInstanceInternal(
150         ash::Shell::GetInstance()->session_state_delegate()->GetUserID(0));
151     multi_user_mode_ = MULTI_PROFILE_MODE_SEPARATED;
152     mode = ash::MultiProfileUMA::SESSION_SEPARATE_DESKTOP_MODE;
153   } else if (ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled()) {
154     multi_user_mode_ = MULTI_PROFILE_MODE_MIXED;
155     mode = ash::MultiProfileUMA::SESSION_SIDE_BY_SIDE_MODE;
156   } else {
157     multi_user_mode_ = MULTI_PROFILE_MODE_OFF;
158   }
159   ash::MultiProfileUMA::RecordSessionMode(mode);
160   return g_instance;
161 }
162
163 // static
164 MultiUserWindowManager::MultiProfileMode
165 MultiUserWindowManager::GetMultiProfileMode() {
166   return multi_user_mode_;
167 }
168
169 // static
170 void MultiUserWindowManager::DeleteInstance() {
171   if (g_instance)
172     delete g_instance;
173   g_instance = NULL;
174   multi_user_mode_ = MULTI_PROFILE_MODE_UNINITIALIZED;
175 }
176
177 // static
178 std::string MultiUserWindowManager::GetUserIDFromProfile(Profile* profile) {
179   return GetUserIDFromEmail(profile->GetOriginalProfile()->GetProfileName());
180 }
181
182 // static
183 std::string MultiUserWindowManager::GetUserIDFromEmail(
184     const std::string& email) {
185   return gaia::CanonicalizeEmail(gaia::SanitizeEmail(email));
186 }
187
188 // static
189 Profile* MultiUserWindowManager::GetProfileFromUserID(
190     const std::string& user_id) {
191   // This can only happen for unit tests. If it happens we return NULL.
192   if (!g_browser_process || !g_browser_process->profile_manager())
193     return NULL;
194
195   std::vector<Profile*> profiles =
196       g_browser_process->profile_manager()->GetLoadedProfiles();
197
198   std::vector<Profile*>::const_iterator profile_iterator = profiles.begin();
199   for (; profile_iterator != profiles.end(); ++profile_iterator) {
200     if (GetUserIDFromProfile(*profile_iterator) == user_id)
201       return *profile_iterator;
202   }
203   return NULL;
204 }
205
206 // static
207 bool MultiUserWindowManager::ProfileIsFromActiveUser(Profile* profile) {
208   return MultiUserWindowManager::GetUserIDFromProfile(profile) ==
209          chromeos::UserManager::Get()->GetActiveUser()->email();
210 }
211
212 void MultiUserWindowManager::SetWindowOwner(aura::Window* window,
213                                             const std::string& user_id) {
214   // Make sure the window is valid and there was no owner yet.
215   DCHECK(window);
216   DCHECK(!user_id.empty());
217   if (GetWindowOwner(window) == user_id)
218     return;
219   DCHECK(GetWindowOwner(window).empty());
220   window_to_entry_[window] = new WindowEntry(user_id);
221
222   // Remember the initial visibility of the window.
223   window_to_entry_[window]->set_show(window->IsVisible());
224
225   // Set the window and the state observer.
226   window->AddObserver(this);
227   ash::wm::GetWindowState(window)->AddObserver(this);
228
229   // Check if this window was created due to a user interaction. If it was,
230   // transfer it to the current user.
231   if (IsProcessingUserEvent())
232     window_to_entry_[window]->set_show_for_user(current_user_id_);
233
234   // Add all transient children to our set of windows. Note that the function
235   // will add the children but not the owner to the transient children map.
236   AddTransientOwnerRecursive(window, window);
237
238   if (!IsWindowOnDesktopOfUser(window, current_user_id_))
239     SetWindowVisibility(window, false);
240 }
241
242 const std::string& MultiUserWindowManager::GetWindowOwner(
243     aura::Window* window) {
244   WindowToEntryMap::iterator it = window_to_entry_.find(window);
245   return it != window_to_entry_.end() ? it->second->owner() : EmptyString();
246 }
247
248 void MultiUserWindowManager::ShowWindowForUser(aura::Window* window,
249                                                const std::string& user_id) {
250   // If there is either no owner, or the owner is the current user, no action
251   // is required.
252   const std::string& owner = GetWindowOwner(window);
253   if (owner.empty() ||
254       (owner == user_id && IsWindowOnDesktopOfUser(window, user_id)))
255     return;
256
257   // Check that we are not trying to transfer ownership of a minimized window.
258   if (user_id != owner && ash::wm::GetWindowState(window)->IsMinimized())
259     return;
260
261   ash::MultiProfileUMA::RecordTeleportAction(
262       ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_MINIMIZE);
263
264   WindowToEntryMap::iterator it = window_to_entry_.find(window);
265   it->second->set_show_for_user(user_id);
266
267   // Show the window if the added user is the current one.
268   if (user_id == current_user_id_) {
269     // Only show the window if it should be shown according to its state.
270     if (it->second->show())
271       SetWindowVisibility(window, true);
272   } else {
273     SetWindowVisibility(window, false);
274   }
275 }
276
277 bool MultiUserWindowManager::AreWindowsSharedAmongUsers() {
278   WindowToEntryMap::iterator it = window_to_entry_.begin();
279   for (; it != window_to_entry_.end(); ++it) {
280     if (it->second->owner() != it->second->show_for_user())
281       return true;
282   }
283   return false;
284 }
285
286 bool MultiUserWindowManager::IsWindowOnDesktopOfUser(
287     aura::Window* window,
288     const std::string& user_id) {
289   const std::string& presenting_user = GetUserPresentingWindow(window);
290   return presenting_user.empty() || presenting_user == user_id;
291 }
292
293 const std::string& MultiUserWindowManager::GetUserPresentingWindow(
294     aura::Window* window) {
295   WindowToEntryMap::iterator it = window_to_entry_.find(window);
296   // If the window is not owned by anyone it is shown on all desktops and we
297   // return the empty string.
298   if (it == window_to_entry_.end())
299     return EmptyString();
300   // Otherwise we ask the object for its desktop.
301   return it->second->show_for_user();
302 }
303
304 void MultiUserWindowManager::ActiveUserChanged(const std::string& user_id) {
305   DCHECK(user_id != current_user_id_);
306   std::string old_user = current_user_id_;
307   current_user_id_ = user_id;
308   // Disable the window position manager and the MRU window tracker temporarily.
309   scoped_ptr<UserChangeActionDisabler> disabler(new UserChangeActionDisabler);
310
311   // We need to show/hide the windows in the same order as they were created in
312   // their parent window(s) to keep the layer / window hierarchy in sync. To
313   // achieve that we first collect all parent windows and then enumerate all
314   // windows in those parent windows and show or hide them accordingly.
315
316   // Create a list of all parent windows we have to check and their parents.
317   std::set<aura::Window*> parent_list;
318   for (WindowToEntryMap::iterator it = window_to_entry_.begin();
319        it != window_to_entry_.end(); ++it) {
320     aura::Window* parent = it->first->parent();
321     if (parent_list.find(parent) == parent_list.end())
322       parent_list.insert(parent);
323   }
324
325   // Traverse the found parent windows to handle their child windows in order of
326   // their appearance.
327   for (std::set<aura::Window*>::iterator it_parents = parent_list.begin();
328        it_parents != parent_list.end(); ++it_parents) {
329     const aura::Window::Windows window_list = (*it_parents)->children();
330     for (aura::Window::Windows::const_iterator it_window = window_list.begin();
331          it_window != window_list.end(); ++it_window) {
332       aura::Window* window = *it_window;
333       WindowToEntryMap::iterator it_map = window_to_entry_.find(window);
334       if (it_map != window_to_entry_.end()) {
335         bool should_be_visible = it_map->second->show_for_user() == user_id &&
336                                  it_map->second->show();
337         bool is_visible = window->IsVisible();
338         if (should_be_visible != is_visible)
339           SetWindowVisibility(window, should_be_visible);
340       }
341     }
342   }
343
344   // Finally we need to restore the previously active window.
345   ash::MruWindowTracker::WindowList mru_list =
346       ash::Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
347   if (mru_list.size()) {
348     aura::Window* window = mru_list[0];
349     ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
350     if (IsWindowOnDesktopOfUser(window, user_id) &&
351         !window_state->IsMinimized()) {
352       aura::client::ActivationClient* client =
353           aura::client::GetActivationClient(window->GetRootWindow());
354       // Several unit tests come here without an activation client.
355       if (client)
356         client->ActivateWindow(window);
357     }
358   }
359 }
360
361 void MultiUserWindowManager::OnWindowDestroyed(aura::Window* window) {
362   if (GetWindowOwner(window).empty()) {
363     // This must be a window in the transient chain - remove it and its
364     // children from the owner.
365     RemoveTransientOwnerRecursive(window);
366     return;
367   }
368   // Remove the state and the window observer.
369   ash::wm::GetWindowState(window)->RemoveObserver(this);
370   window->RemoveObserver(this);
371   // Remove the window from the owners list.
372   delete window_to_entry_[window];
373   window_to_entry_.erase(window);
374 }
375
376 void MultiUserWindowManager::OnWindowVisibilityChanging(
377     aura::Window* window, bool visible) {
378   // This command gets called first and immediately when show or hide gets
379   // called. We remember here the desired state for restoration IF we were
380   // not ourselves issuing the call.
381   // Note also that using the OnWindowVisibilityChanged callback cannot be
382   // used for this.
383   if (suppress_visibility_changes_)
384     return;
385
386   WindowToEntryMap::iterator it = window_to_entry_.find(window);
387   // If the window is not owned by anyone it is shown on all desktops.
388   if (it != window_to_entry_.end()) {
389     // Remember what was asked for so that we can restore this when the user's
390     // desktop gets restored.
391     it->second->set_show(visible);
392   } else {
393     TransientWindowToVisibility::iterator it =
394         transient_window_to_visibility_.find(window);
395     if (it != transient_window_to_visibility_.end())
396       it->second = visible;
397   }
398 }
399
400 void MultiUserWindowManager::OnWindowVisibilityChanged(
401     aura::Window* window, bool visible) {
402   if (suppress_visibility_changes_)
403     return;
404
405   // Don't allow to make the window visible if it shouldn't be.
406   if (visible && !IsWindowOnDesktopOfUser(window, current_user_id_)) {
407     SetWindowVisibility(window, false);
408     return;
409   }
410   aura::Window* owned_parent = GetOwningWindowInTransientChain(window);
411   if (owned_parent && owned_parent != window && visible &&
412       !IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
413     SetWindowVisibility(window, false);
414 }
415
416 void MultiUserWindowManager::OnAddTransientChild(
417     aura::Window* window,
418     aura::Window* transient_window) {
419   if (!GetWindowOwner(window).empty()) {
420     AddTransientOwnerRecursive(transient_window, window);
421     return;
422   }
423   aura::Window* owned_parent =
424       GetOwningWindowInTransientChain(transient_window);
425   if (!owned_parent)
426     return;
427
428   AddTransientOwnerRecursive(transient_window, owned_parent);
429 }
430
431 void MultiUserWindowManager::OnRemoveTransientChild(
432     aura::Window* window,
433     aura::Window* transient_window) {
434   // Remove the transient child if the window itself is owned, or one of the
435   // windows in its transient parents chain.
436   if (!GetWindowOwner(window).empty() ||
437       GetOwningWindowInTransientChain(window))
438     RemoveTransientOwnerRecursive(transient_window);
439 }
440
441 void MultiUserWindowManager::OnWindowShowTypeChanged(
442     ash::wm::WindowState* window_state,
443     ash::wm::WindowShowType old_type) {
444   if (!window_state->IsMinimized())
445     return;
446
447   aura::Window* window = window_state->window();
448   // If the window was shown on a different users desktop: move it back.
449   const std::string& owner = GetWindowOwner(window);
450   if (!IsWindowOnDesktopOfUser(window, owner))
451     ShowWindowForUser(window, owner);
452 }
453
454 void MultiUserWindowManager::Observe(
455     int type,
456     const content::NotificationSource& source,
457     const content::NotificationDetails& details) {
458   if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY)
459     AddBrowserWindow(content::Source<Browser>(source).ptr());
460 }
461
462 // static
463 MultiUserWindowManager* MultiUserWindowManager::CreateInstanceInternal(
464     std::string active_user_id) {
465   DCHECK(!g_instance);
466   g_instance = new MultiUserWindowManager(active_user_id);
467   return g_instance;
468 }
469
470 MultiUserWindowManager::MultiUserWindowManager(
471     const std::string& current_user_id)
472     : current_user_id_(current_user_id),
473       suppress_visibility_changes_(false) {
474   // Add a session state observer to be able to monitor session changes.
475   if (ash::Shell::HasInstance())
476     ash::Shell::GetInstance()->session_state_delegate()->
477         AddSessionStateObserver(this);
478
479   // The BrowserListObserver would have been better to use then the old
480   // notification system, but that observer fires before the window got created.
481   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
482                  content::NotificationService::AllSources());
483
484   // Add an app window observer & all already running apps.
485   Profile* profile = GetProfileFromUserID(current_user_id);
486   if (profile)
487     AddUser(profile);
488 }
489
490 MultiUserWindowManager::~MultiUserWindowManager() {
491   // Remove all window observers.
492   WindowToEntryMap::iterator window_observer = window_to_entry_.begin();
493   while (window_observer != window_to_entry_.end()) {
494     OnWindowDestroyed(window_observer->first);
495     window_observer = window_to_entry_.begin();
496   }
497
498   // Remove all app observers.
499   UserIDToShellWindowObserver::iterator app_observer_iterator =
500       user_id_to_app_observer_.begin();
501   while (app_observer_iterator != user_id_to_app_observer_.end()) {
502     Profile* profile = GetProfileFromUserID(app_observer_iterator->first);
503     DCHECK(profile);
504     apps::ShellWindowRegistry::Get(profile)->RemoveObserver(
505         app_observer_iterator->second);
506     delete app_observer_iterator->second;
507     user_id_to_app_observer_.erase(app_observer_iterator);
508     app_observer_iterator = user_id_to_app_observer_.begin();
509   }
510
511   if (ash::Shell::HasInstance())
512     ash::Shell::GetInstance()->session_state_delegate()->
513         RemoveSessionStateObserver(this);
514 }
515
516 void MultiUserWindowManager::AddUser(Profile* profile) {
517   const std::string& user_id = GetUserIDFromProfile(profile);
518   if (user_id_to_app_observer_.find(user_id) != user_id_to_app_observer_.end())
519     return;
520
521   user_id_to_app_observer_[user_id] = new AppObserver(user_id);
522   apps::ShellWindowRegistry::Get(profile)->AddObserver(
523       user_id_to_app_observer_[user_id]);
524
525   // Account all existing application windows of this user accordingly.
526   const apps::ShellWindowRegistry::ShellWindowList& shell_windows =
527       apps::ShellWindowRegistry::Get(profile)->shell_windows();
528   apps::ShellWindowRegistry::ShellWindowList::const_iterator it =
529       shell_windows.begin();
530   for (; it != shell_windows.end(); ++it)
531     user_id_to_app_observer_[user_id]->OnShellWindowAdded(*it);
532
533   // Account all existing browser windows of this user accordingly.
534   BrowserList* browser_list = BrowserList::GetInstance(HOST_DESKTOP_TYPE_ASH);
535   BrowserList::const_iterator browser_it = browser_list->begin();
536   for (; browser_it != browser_list->end(); ++browser_it) {
537     if ((*browser_it)->profile()->GetOriginalProfile() == profile)
538       AddBrowserWindow(*browser_it);
539   }
540 }
541
542 void MultiUserWindowManager::AddBrowserWindow(Browser* browser) {
543   // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
544   // come here with no valid window.
545   if (!browser->window() || !browser->window()->GetNativeWindow())
546     return;
547   SetWindowOwner(browser->window()->GetNativeWindow(),
548                  GetUserIDFromProfile(browser->profile()));
549 }
550
551 void MultiUserWindowManager::SetWindowVisibility(
552     aura::Window* window, bool visible) {
553   if (window->IsVisible() == visible)
554     return;
555
556   // To avoid that these commands are recorded as any other commands, we are
557   // suppressing any window entry changes while this is going on.
558   base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
559
560   if (visible) {
561     ShowWithTransientChildrenRecursive(window);
562   } else {
563     if (window->HasFocus())
564       window->Blur();
565     window->Hide();
566   }
567 }
568
569 void MultiUserWindowManager::ShowWithTransientChildrenRecursive(
570     aura::Window* window) {
571   aura::Window::Windows::const_iterator it =
572       window->transient_children().begin();
573   for (; it !=  window->transient_children().end(); ++it)
574     ShowWithTransientChildrenRecursive(*it);
575
576   // We show all children which were not explicitly hidden.
577   TransientWindowToVisibility::iterator it2 =
578       transient_window_to_visibility_.find(window);
579   if (it2 == transient_window_to_visibility_.end() || it2->second)
580     window->Show();
581 }
582
583 aura::Window* MultiUserWindowManager::GetOwningWindowInTransientChain(
584     aura::Window* window) {
585   if (!GetWindowOwner(window).empty())
586     return NULL;
587   aura::Window* parent = window->transient_parent();
588   while (parent) {
589     if (!GetWindowOwner(parent).empty())
590       return parent;
591     parent = parent->transient_parent();
592   }
593   return NULL;
594 }
595
596 void MultiUserWindowManager::AddTransientOwnerRecursive(
597     aura::Window* window,
598     aura::Window* owned_parent) {
599   // First add all child windows.
600   aura::Window::Windows::const_iterator it =
601       window->transient_children().begin();
602   for (; it !=  window->transient_children().end(); ++it)
603     AddTransientOwnerRecursive(*it, owned_parent);
604
605   // If this window is the owned window, we do not have to handle it again.
606   if (window == owned_parent)
607     return;
608
609   // Remember the current visibility.
610   DCHECK(transient_window_to_visibility_.find(window) ==
611              transient_window_to_visibility_.end());
612   transient_window_to_visibility_[window] = window->IsVisible();
613
614   // Add a window observer to make sure that we catch status changes.
615   window->AddObserver(this);
616
617   // Hide the window if it should not be shown. Note that this hide operation
618   // will hide recursively this and all children - but we have already collected
619   // their initial view state.
620   if (!IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
621     SetWindowVisibility(window, false);
622 }
623
624 void MultiUserWindowManager::RemoveTransientOwnerRecursive(
625     aura::Window* window) {
626   // First remove all child windows.
627   aura::Window::Windows::const_iterator it =
628       window->transient_children().begin();
629   for (; it !=  window->transient_children().end(); ++it)
630     RemoveTransientOwnerRecursive(*it);
631
632   // Find from transient window storage the visibility for the given window,
633   // set the visibility accordingly and delete the window from the map.
634   TransientWindowToVisibility::iterator visibility_item =
635       transient_window_to_visibility_.find(window);
636   DCHECK(visibility_item != transient_window_to_visibility_.end());
637
638   // Remove the window observer.
639   window->RemoveObserver(this);
640
641   bool unowned_view_state = visibility_item->second;
642   transient_window_to_visibility_.erase(visibility_item);
643   if (unowned_view_state && !window->IsVisible()) {
644     // To prevent these commands from being recorded as any other commands, we
645     // are suppressing any window entry changes while this is going on.
646     // Instead of calling SetWindowVisible, only show gets called here since all
647     // dependents have been shown previously already.
648     base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
649     window->Show();
650   }
651 }
652
653 }  // namespace chrome