1 // Copyright (c) 2012 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/launcher/shell_window_launcher_controller.h"
7 #include "apps/shell_window.h"
9 #include "ash/wm/window_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
13 #include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
14 #include "chrome/browser/ui/host_desktop.h"
15 #include "ui/aura/client/activation_client.h"
16 #include "ui/aura/root_window.h"
18 #if defined(OS_CHROMEOS)
19 #include "chrome/browser/ui/ash/multi_user_window_manager.h"
22 using apps::ShellWindow;
26 std::string GetAppLauncherId(ShellWindow* shell_window) {
27 if (shell_window->window_type_is_panel())
28 return base::StringPrintf("panel:%d", shell_window->session_id().id());
29 return shell_window->extension()->id();
32 bool ControlsWindow(aura::Window* window) {
33 return chrome::GetHostDesktopTypeForNativeWindow(window) ==
34 chrome::HOST_DESKTOP_TYPE_ASH;
39 ShellWindowLauncherController::ShellWindowLauncherController(
40 ChromeLauncherController* owner)
42 activation_client_(NULL) {
43 apps::ShellWindowRegistry* registry =
44 apps::ShellWindowRegistry::Get(owner->profile());
45 registry_.insert(registry);
46 registry->AddObserver(this);
47 if (ash::Shell::HasInstance()) {
48 if (ash::Shell::GetInstance()->GetPrimaryRootWindow()) {
49 activation_client_ = aura::client::GetActivationClient(
50 ash::Shell::GetInstance()->GetPrimaryRootWindow());
51 if (activation_client_)
52 activation_client_->AddObserver(this);
57 ShellWindowLauncherController::~ShellWindowLauncherController() {
58 for (std::set<apps::ShellWindowRegistry*>::iterator it = registry_.begin();
59 it != registry_.end(); ++it)
60 (*it)->RemoveObserver(this);
62 if (activation_client_)
63 activation_client_->RemoveObserver(this);
64 for (WindowToAppLauncherIdMap::iterator iter =
65 window_to_app_launcher_id_map_.begin();
66 iter != window_to_app_launcher_id_map_.end(); ++iter) {
67 iter->first->RemoveObserver(this);
71 void ShellWindowLauncherController::AdditionalUserAddedToSession(
73 #if defined(OS_CHROMEOS)
74 // TODO(skuhne): This was added for the legacy side by side mode in M32. If
75 // this mode gets no longer pursued this special case can be removed.
76 if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
77 chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_MIXED)
80 apps::ShellWindowRegistry* registry = apps::ShellWindowRegistry::Get(profile);
81 if (registry_.find(registry) != registry_.end())
84 registry->AddObserver(this);
85 registry_.insert(registry);
89 void ShellWindowLauncherController::OnShellWindowAdded(
90 ShellWindow* shell_window) {
91 if (!ControlsWindow(shell_window->GetNativeWindow()))
93 RegisterApp(shell_window);
96 void ShellWindowLauncherController::OnShellWindowIconChanged(
97 ShellWindow* shell_window) {
98 if (!ControlsWindow(shell_window->GetNativeWindow()))
101 const std::string app_launcher_id = GetAppLauncherId(shell_window);
102 AppControllerMap::iterator iter = app_controller_map_.find(app_launcher_id);
103 if (iter == app_controller_map_.end())
105 ShellWindowLauncherItemController* controller = iter->second;
106 controller->set_image_set_by_controller(true);
107 owner_->SetLauncherItemImage(controller->launcher_id(),
108 shell_window->app_icon().AsImageSkia());
111 void ShellWindowLauncherController::OnShellWindowRemoved(
112 ShellWindow* shell_window) {
113 // Do nothing here; shell_window->window() has already been deleted and
114 // OnWindowDestroying() has been called, doing the removal.
117 // Called from aura::Window::~Window(), before delegate_->OnWindowDestroyed()
118 // which destroys ShellWindow, so both |window| and the associated ShellWindow
120 void ShellWindowLauncherController::OnWindowDestroying(aura::Window* window) {
121 if (!ControlsWindow(window))
123 UnregisterApp(window);
126 void ShellWindowLauncherController::OnWindowActivated(
127 aura::Window* new_active,
128 aura::Window* old_active) {
129 // Make the newly active window the active (first) entry in the controller.
130 ShellWindowLauncherItemController* new_controller =
131 ControllerForWindow(new_active);
132 if (new_controller) {
133 new_controller->SetActiveWindow(new_active);
134 owner_->SetItemStatus(new_controller->launcher_id(), ash::STATUS_ACTIVE);
137 // Mark the old active window's launcher item as running (if different).
138 ShellWindowLauncherItemController* old_controller =
139 ControllerForWindow(old_active);
140 if (old_controller && old_controller != new_controller)
141 owner_->SetItemStatus(old_controller->launcher_id(), ash::STATUS_RUNNING);
144 void ShellWindowLauncherController::RegisterApp(ShellWindow* shell_window) {
145 aura::Window* window = shell_window->GetNativeWindow();
146 // Get the app's launcher identifier and add an entry to the map.
147 DCHECK(window_to_app_launcher_id_map_.find(window) ==
148 window_to_app_launcher_id_map_.end());
149 const std::string app_launcher_id = GetAppLauncherId(shell_window);
150 window_to_app_launcher_id_map_[window] = app_launcher_id;
151 window->AddObserver(this);
153 // Find or create an item controller and launcher item.
154 std::string app_id = shell_window->extension()->id();
155 ash::LauncherItemStatus status = ash::wm::IsActiveWindow(window) ?
156 ash::STATUS_ACTIVE : ash::STATUS_RUNNING;
157 AppControllerMap::iterator iter = app_controller_map_.find(app_launcher_id);
158 ash::LauncherID launcher_id = 0;
159 if (iter != app_controller_map_.end()) {
160 ShellWindowLauncherItemController* controller = iter->second;
161 DCHECK(controller->app_id() == app_id);
162 launcher_id = controller->launcher_id();
163 controller->AddShellWindow(shell_window, status);
165 LauncherItemController::Type type = shell_window->window_type_is_panel()
166 ? LauncherItemController::TYPE_APP_PANEL
167 : LauncherItemController::TYPE_APP;
168 ShellWindowLauncherItemController* controller =
169 new ShellWindowLauncherItemController(
170 type, app_launcher_id, app_id, owner_);
171 controller->AddShellWindow(shell_window, status);
172 // If the app launcher id is not unique, and there is already a launcher
173 // item for this app id (e.g. pinned), use that launcher item.
174 if (app_launcher_id == app_id)
175 launcher_id = owner_->GetLauncherIDForAppID(app_id);
176 if (launcher_id == 0)
177 launcher_id = owner_->CreateAppLauncherItem(controller, app_id, status);
179 owner_->SetItemController(launcher_id, controller);
180 const std::string app_launcher_id = GetAppLauncherId(shell_window);
181 app_controller_map_[app_launcher_id] = controller;
183 owner_->SetItemStatus(launcher_id, status);
186 void ShellWindowLauncherController::UnregisterApp(aura::Window* window) {
187 WindowToAppLauncherIdMap::iterator iter1 =
188 window_to_app_launcher_id_map_.find(window);
189 DCHECK(iter1 != window_to_app_launcher_id_map_.end());
190 std::string app_launcher_id = iter1->second;
191 window_to_app_launcher_id_map_.erase(iter1);
192 window->RemoveObserver(this);
194 AppControllerMap::iterator iter2 = app_controller_map_.find(app_launcher_id);
195 DCHECK(iter2 != app_controller_map_.end());
196 ShellWindowLauncherItemController* controller = iter2->second;
197 controller->RemoveShellWindowForWindow(window);
198 if (controller->shell_window_count() == 0) {
199 // If this is the last window associated with the app launcher id, close the
201 ash::LauncherID launcher_id = controller->launcher_id();
202 owner_->CloseLauncherItem(launcher_id);
203 app_controller_map_.erase(iter2);
207 bool ShellWindowLauncherController::IsRegisteredApp(aura::Window* window) {
208 return window_to_app_launcher_id_map_.find(window) !=
209 window_to_app_launcher_id_map_.end();
214 ShellWindowLauncherItemController*
215 ShellWindowLauncherController::ControllerForWindow(
216 aura::Window* window) {
217 WindowToAppLauncherIdMap::iterator iter1 =
218 window_to_app_launcher_id_map_.find(window);
219 if (iter1 == window_to_app_launcher_id_map_.end())
221 std::string app_launcher_id = iter1->second;
222 AppControllerMap::iterator iter2 = app_controller_map_.find(app_launcher_id);
223 if (iter2 == app_controller_map_.end())
225 return iter2->second;