| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/ash/multi_user_window_manager.h" | 5 #include "chrome/browser/ui/ash/multi_user_window_manager.h" |
| 6 | 6 |
| 7 #include "apps/shell_window.h" | 7 #include "apps/shell_window.h" |
| 8 #include "apps/shell_window_registry.h" | 8 #include "apps/shell_window_registry.h" |
| 9 #include "ash/ash_switches.h" | 9 #include "ash/ash_switches.h" |
| 10 #include "ash/session_state_delegate.h" | 10 #include "ash/session_state_delegate.h" |
| 11 #include "ash/shell.h" | 11 #include "ash/shell.h" |
| 12 #include "ash/shell_delegate.h" | 12 #include "ash/shell_delegate.h" |
| 13 #include "ash/wm/mru_window_tracker.h" | 13 #include "ash/wm/mru_window_tracker.h" |
| 14 #include "ash/wm/window_positioner.h" | 14 #include "ash/wm/window_positioner.h" |
| 15 #include "ash/wm/window_state.h" | 15 #include "ash/wm/window_state.h" |
| 16 #include "base/auto_reset.h" | 16 #include "base/auto_reset.h" |
| 17 #include "base/message_loop/message_loop.h" |
| 17 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
| 18 #include "chrome/browser/browser_process.h" | 19 #include "chrome/browser/browser_process.h" |
| 19 #include "chrome/browser/chrome_notification_types.h" | 20 #include "chrome/browser/chrome_notification_types.h" |
| 20 #include "chrome/browser/chromeos/login/user_manager.h" | 21 #include "chrome/browser/chromeos/login/user_manager.h" |
| 21 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
| 22 #include "chrome/browser/profiles/profile_manager.h" | 23 #include "chrome/browser/profiles/profile_manager.h" |
| 23 #include "chrome/browser/ui/browser.h" | 24 #include "chrome/browser/ui/browser.h" |
| 24 #include "chrome/browser/ui/browser_list.h" | 25 #include "chrome/browser/ui/browser_list.h" |
| 25 #include "chrome/browser/ui/browser_window.h" | 26 #include "chrome/browser/ui/browser_window.h" |
| 26 #include "content/public/browser/notification_service.h" | 27 #include "content/public/browser/notification_service.h" |
| 27 #include "google_apis/gaia/gaia_auth_util.h" | 28 #include "google_apis/gaia/gaia_auth_util.h" |
| 28 #include "ui/aura/client/activation_client.h" | 29 #include "ui/aura/client/activation_client.h" |
| 29 #include "ui/aura/client/aura_constants.h" | 30 #include "ui/aura/client/aura_constants.h" |
| 30 #include "ui/aura/root_window.h" | 31 #include "ui/aura/root_window.h" |
| 31 #include "ui/aura/window.h" | 32 #include "ui/aura/window.h" |
| 32 #include "ui/base/ui_base_types.h" | 33 #include "ui/base/ui_base_types.h" |
| 34 #include "ui/events/event.h" |
| 33 | 35 |
| 34 namespace { | 36 namespace { |
| 35 chrome::MultiUserWindowManager* g_instance = NULL; | 37 chrome::MultiUserWindowManager* g_instance = NULL; |
| 38 |
| 39 |
| 40 // Checks if a given event is a user event. |
| 41 bool IsUserEvent(ui::Event* e) { |
| 42 if (e) { |
| 43 ui::EventType type = e->type(); |
| 44 if (type != ui::ET_CANCEL_MODE && |
| 45 type != ui::ET_UMA_DATA && |
| 46 type != ui::ET_UNKNOWN) |
| 47 return true; |
| 48 } |
| 49 return false; |
| 50 } |
| 51 |
| 52 // Test if we are currently processing a user event which might lead to a |
| 53 // browser / app creation. |
| 54 bool IsProcessingUserEvent() { |
| 55 // When there is a nested message loop (e.g. active menu or drag and drop |
| 56 // operation) - we are in a nested loop and can ignore this. |
| 57 // Note: Unit tests might not have a message loop. |
| 58 base::MessageLoop* message_loop = base::MessageLoop::current(); |
| 59 if (message_loop && message_loop->is_running() && message_loop->IsNested()) |
| 60 return false; |
| 61 |
| 62 // TODO(skuhne): "Open link in new window" will come here after the menu got |
| 63 // closed, executing the command from the nested menu loop. However at that |
| 64 // time there is no active event processed. A solution for that need to be |
| 65 // found past M-32. A global event handler filter (pre and post) might fix |
| 66 // that problem in conjunction with a depth counter - but - for the menu |
| 67 // execution we come here after the loop was finished (so it's not nested |
| 68 // anymore) and the root window should therefore still have the event which |
| 69 // lead to the menu invocation, but it is not. By fixing that problem this |
| 70 // would "magically work". |
| 71 ash::Shell::RootWindowList root_window_list = ash::Shell::GetAllRootWindows(); |
| 72 for (ash::Shell::RootWindowList::iterator it = root_window_list.begin(); |
| 73 it != root_window_list.end(); |
| 74 ++it) { |
| 75 if (IsUserEvent((*it)->current_event())) |
| 76 return true; |
| 77 } |
| 78 return false; |
| 79 } |
| 80 |
| 36 } // namespace | 81 } // namespace |
| 37 | 82 |
| 38 namespace chrome { | 83 namespace chrome { |
| 39 | 84 |
| 40 // Caching the current multi profile mode since the detection which mode is | 85 // Caching the current multi profile mode since the detection which mode is |
| 41 // used is quite expensive. | 86 // used is quite expensive. |
| 42 chrome::MultiUserWindowManager::MultiProfileMode | 87 chrome::MultiUserWindowManager::MultiProfileMode |
| 43 chrome::MultiUserWindowManager::multi_user_mode_ = | 88 chrome::MultiUserWindowManager::multi_user_mode_ = |
| 44 chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_UNINITIALIZED; | 89 chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_UNINITIALIZED; |
| 45 | 90 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 void MultiUserWindowManager::SetWindowOwner(aura::Window* window, | 206 void MultiUserWindowManager::SetWindowOwner(aura::Window* window, |
| 162 const std::string& user_id) { | 207 const std::string& user_id) { |
| 163 // Make sure the window is valid and there was no owner yet. | 208 // Make sure the window is valid and there was no owner yet. |
| 164 DCHECK(window); | 209 DCHECK(window); |
| 165 DCHECK(!user_id.empty()); | 210 DCHECK(!user_id.empty()); |
| 166 if (GetWindowOwner(window) == user_id) | 211 if (GetWindowOwner(window) == user_id) |
| 167 return; | 212 return; |
| 168 DCHECK(GetWindowOwner(window).empty()); | 213 DCHECK(GetWindowOwner(window).empty()); |
| 169 window_to_entry_[window] = new WindowEntry(user_id); | 214 window_to_entry_[window] = new WindowEntry(user_id); |
| 170 | 215 |
| 216 // Remember the initial visibility of the window. |
| 217 window_to_entry_[window]->set_show(window->IsVisible()); |
| 218 |
| 171 // Set the window and the state observer. | 219 // Set the window and the state observer. |
| 172 window->AddObserver(this); | 220 window->AddObserver(this); |
| 173 ash::wm::GetWindowState(window)->AddObserver(this); | 221 ash::wm::GetWindowState(window)->AddObserver(this); |
| 174 | 222 |
| 223 // Check if this window was created due to a user interaction. If it was, |
| 224 // transfer it to the current user. |
| 225 if (IsProcessingUserEvent()) |
| 226 window_to_entry_[window]->set_show_for_user(current_user_id_); |
| 227 |
| 175 // Add all transient children to our set of windows. Note that the function | 228 // Add all transient children to our set of windows. Note that the function |
| 176 // will add the children but not the owner to the transient children map. | 229 // will add the children but not the owner to the transient children map. |
| 177 AddTransientOwnerRecursive(window, window); | 230 AddTransientOwnerRecursive(window, window); |
| 178 | 231 |
| 179 if (user_id != current_user_id_) | 232 if (!IsWindowOnDesktopOfUser(window, current_user_id_)) |
| 180 SetWindowVisibility(window, false); | 233 SetWindowVisibility(window, false); |
| 181 } | 234 } |
| 182 | 235 |
| 183 const std::string& MultiUserWindowManager::GetWindowOwner( | 236 const std::string& MultiUserWindowManager::GetWindowOwner( |
| 184 aura::Window* window) { | 237 aura::Window* window) { |
| 185 WindowToEntryMap::iterator it = window_to_entry_.find(window); | 238 WindowToEntryMap::iterator it = window_to_entry_.find(window); |
| 186 return it != window_to_entry_.end() ? it->second->owner() : EmptyString(); | 239 return it != window_to_entry_.end() ? it->second->owner() : EmptyString(); |
| 187 } | 240 } |
| 188 | 241 |
| 189 void MultiUserWindowManager::ShowWindowForUser(aura::Window* window, | 242 void MultiUserWindowManager::ShowWindowForUser(aura::Window* window, |
| 190 const std::string& user_id) { | 243 const std::string& user_id) { |
| 191 // If there is either no owner, or the owner is the current user, no action | 244 // If there is either no owner, or the owner is the current user, no action |
| 192 // is required. | 245 // is required. |
| 193 const std::string& owner = GetWindowOwner(window); | 246 const std::string& owner = GetWindowOwner(window); |
| 194 if (owner.empty() || | 247 if (owner.empty() || |
| 195 (owner == user_id && IsWindowOnDesktopOfUser(window, user_id))) | 248 (owner == user_id && IsWindowOnDesktopOfUser(window, user_id))) |
| 196 return; | 249 return; |
| 197 | 250 |
| 198 // Check that we are not trying to transfer ownership of a minimized window. | 251 // Check that we are not trying to transfer ownership of a minimized window. |
| 199 if (user_id != owner && ash::wm::GetWindowState(window)->IsMinimized()) | 252 if (user_id != owner && ash::wm::GetWindowState(window)->IsMinimized()) |
| 200 return; | 253 return; |
| 201 | 254 |
| 202 WindowToEntryMap::iterator it = window_to_entry_.find(window); | 255 WindowToEntryMap::iterator it = window_to_entry_.find(window); |
| 203 it->second->set_show_for_user(user_id); | 256 it->second->set_show_for_user(user_id); |
| 204 | 257 |
| 205 // Show the window if the added user is the current one. | 258 // Show the window if the added user is the current one. |
| 206 if (user_id == current_user_id_) | 259 if (user_id == current_user_id_) { |
| 207 SetWindowVisibility(window, true); | 260 // Only show the window if it should be shown according to its state. |
| 208 else | 261 if (it->second->show()) |
| 262 SetWindowVisibility(window, true); |
| 263 } else { |
| 209 SetWindowVisibility(window, false); | 264 SetWindowVisibility(window, false); |
| 265 } |
| 210 } | 266 } |
| 211 | 267 |
| 212 bool MultiUserWindowManager::AreWindowsSharedAmongUsers() { | 268 bool MultiUserWindowManager::AreWindowsSharedAmongUsers() { |
| 213 WindowToEntryMap::iterator it = window_to_entry_.begin(); | 269 WindowToEntryMap::iterator it = window_to_entry_.begin(); |
| 214 for (; it != window_to_entry_.end(); ++it) { | 270 for (; it != window_to_entry_.end(); ++it) { |
| 215 if (it->second->owner() != it->second->show_for_user()) | 271 if (it->second->owner() != it->second->show_for_user()) |
| 216 return true; | 272 return true; |
| 217 } | 273 } |
| 218 return false; | 274 return false; |
| 219 } | 275 } |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 | 541 |
| 486 void MultiUserWindowManager::SetWindowVisibility( | 542 void MultiUserWindowManager::SetWindowVisibility( |
| 487 aura::Window* window, bool visible) { | 543 aura::Window* window, bool visible) { |
| 488 if (window->IsVisible() == visible) | 544 if (window->IsVisible() == visible) |
| 489 return; | 545 return; |
| 490 | 546 |
| 491 // To avoid that these commands are recorded as any other commands, we are | 547 // To avoid that these commands are recorded as any other commands, we are |
| 492 // suppressing any window entry changes while this is going on. | 548 // suppressing any window entry changes while this is going on. |
| 493 base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true); | 549 base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true); |
| 494 | 550 |
| 495 if (visible) | 551 if (visible) { |
| 496 ShowWithTransientChildrenRecursive(window); | 552 ShowWithTransientChildrenRecursive(window); |
| 497 else | 553 } else { |
| 554 if (window->HasFocus()) |
| 555 window->Blur(); |
| 498 window->Hide(); | 556 window->Hide(); |
| 557 } |
| 499 } | 558 } |
| 500 | 559 |
| 501 void MultiUserWindowManager::ShowWithTransientChildrenRecursive( | 560 void MultiUserWindowManager::ShowWithTransientChildrenRecursive( |
| 502 aura::Window* window) { | 561 aura::Window* window) { |
| 503 aura::Window::Windows::const_iterator it = | 562 aura::Window::Windows::const_iterator it = |
| 504 window->transient_children().begin(); | 563 window->transient_children().begin(); |
| 505 for (; it != window->transient_children().end(); ++it) | 564 for (; it != window->transient_children().end(); ++it) |
| 506 ShowWithTransientChildrenRecursive(*it); | 565 ShowWithTransientChildrenRecursive(*it); |
| 507 | 566 |
| 508 // We show all children which were not explicitly hidden. | 567 // We show all children which were not explicitly hidden. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 // To prevent these commands from being recorded as any other commands, we | 635 // To prevent these commands from being recorded as any other commands, we |
| 577 // are suppressing any window entry changes while this is going on. | 636 // are suppressing any window entry changes while this is going on. |
| 578 // Instead of calling SetWindowVisible, only show gets called here since all | 637 // Instead of calling SetWindowVisible, only show gets called here since all |
| 579 // dependents have been shown previously already. | 638 // dependents have been shown previously already. |
| 580 base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true); | 639 base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true); |
| 581 window->Show(); | 640 window->Show(); |
| 582 } | 641 } |
| 583 } | 642 } |
| 584 | 643 |
| 585 } // namespace chrome | 644 } // namespace chrome |
| OLD | NEW |