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/app_window.h"
8 #include "ash/shelf/shelf_util.h"
10 #include "ash/wm/window_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
14 #include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
15 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
16 #include "chrome/browser/ui/host_desktop.h"
17 #include "extensions/common/extension.h"
18 #include "ui/aura/client/activation_client.h"
19 #include "ui/aura/root_window.h"
21 using apps::AppWindow
;
25 std::string
GetAppShelfId(AppWindow
* app_window
) {
26 if (app_window
->window_type_is_panel())
27 return base::StringPrintf("panel:%d", app_window
->session_id().id());
28 return app_window
->extension()->id();
31 bool ControlsWindow(aura::Window
* window
) {
32 return chrome::GetHostDesktopTypeForNativeWindow(window
) ==
33 chrome::HOST_DESKTOP_TYPE_ASH
;
38 ShellWindowLauncherController::ShellWindowLauncherController(
39 ChromeLauncherController
* owner
)
41 activation_client_(NULL
) {
42 apps::AppWindowRegistry
* registry
=
43 apps::AppWindowRegistry::Get(owner
->profile());
44 registry_
.insert(registry
);
45 registry
->AddObserver(this);
46 if (ash::Shell::HasInstance()) {
47 if (ash::Shell::GetInstance()->GetPrimaryRootWindow()) {
48 activation_client_
= aura::client::GetActivationClient(
49 ash::Shell::GetInstance()->GetPrimaryRootWindow());
50 if (activation_client_
)
51 activation_client_
->AddObserver(this);
56 ShellWindowLauncherController::~ShellWindowLauncherController() {
57 for (std::set
<apps::AppWindowRegistry
*>::iterator it
= registry_
.begin();
58 it
!= registry_
.end();
60 (*it
)->RemoveObserver(this);
62 if (activation_client_
)
63 activation_client_
->RemoveObserver(this);
64 for (WindowToAppShelfIdMap::iterator iter
=
65 window_to_app_shelf_id_map_
.begin();
66 iter
!= window_to_app_shelf_id_map_
.end(); ++iter
) {
67 iter
->first
->RemoveObserver(this);
71 void ShellWindowLauncherController::AdditionalUserAddedToSession(
73 // TODO(skuhne): This was added for the legacy side by side mode in M32. If
74 // this mode gets no longer pursued this special case can be removed.
75 if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
76 chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_MIXED
)
79 apps::AppWindowRegistry
* registry
= apps::AppWindowRegistry::Get(profile
);
80 if (registry_
.find(registry
) != registry_
.end())
83 registry
->AddObserver(this);
84 registry_
.insert(registry
);
87 void ShellWindowLauncherController::OnAppWindowAdded(AppWindow
* app_window
) {
88 if (!ControlsWindow(app_window
->GetNativeWindow()))
90 RegisterApp(app_window
);
93 void ShellWindowLauncherController::OnAppWindowIconChanged(
94 AppWindow
* app_window
) {
95 if (!ControlsWindow(app_window
->GetNativeWindow()))
98 const std::string app_shelf_id
= GetAppShelfId(app_window
);
99 AppControllerMap::iterator iter
= app_controller_map_
.find(app_shelf_id
);
100 if (iter
== app_controller_map_
.end())
102 ShellWindowLauncherItemController
* controller
= iter
->second
;
103 controller
->set_image_set_by_controller(true);
104 owner_
->SetLauncherItemImage(controller
->shelf_id(),
105 app_window
->app_icon().AsImageSkia());
108 void ShellWindowLauncherController::OnAppWindowRemoved(AppWindow
* app_window
) {
109 // Do nothing here; app_window->window() has already been deleted and
110 // OnWindowDestroying() has been called, doing the removal.
113 // Called from aura::Window::~Window(), before delegate_->OnWindowDestroyed()
114 // which destroys AppWindow, so both |window| and the associated AppWindow
116 void ShellWindowLauncherController::OnWindowDestroying(aura::Window
* window
) {
117 if (!ControlsWindow(window
))
119 UnregisterApp(window
);
122 void ShellWindowLauncherController::OnWindowActivated(
123 aura::Window
* new_active
,
124 aura::Window
* old_active
) {
125 // Make the newly active window the active (first) entry in the controller.
126 ShellWindowLauncherItemController
* new_controller
=
127 ControllerForWindow(new_active
);
128 if (new_controller
) {
129 new_controller
->SetActiveWindow(new_active
);
130 owner_
->SetItemStatus(new_controller
->shelf_id(), ash::STATUS_ACTIVE
);
133 // Mark the old active window's launcher item as running (if different).
134 ShellWindowLauncherItemController
* old_controller
=
135 ControllerForWindow(old_active
);
136 if (old_controller
&& old_controller
!= new_controller
)
137 owner_
->SetItemStatus(old_controller
->shelf_id(), ash::STATUS_RUNNING
);
140 void ShellWindowLauncherController::RegisterApp(AppWindow
* app_window
) {
141 aura::Window
* window
= app_window
->GetNativeWindow();
142 // Get the app's shelf identifier and add an entry to the map.
143 DCHECK(window_to_app_shelf_id_map_
.find(window
) ==
144 window_to_app_shelf_id_map_
.end());
145 const std::string app_shelf_id
= GetAppShelfId(app_window
);
146 window_to_app_shelf_id_map_
[window
] = app_shelf_id
;
147 window
->AddObserver(this);
149 // Find or create an item controller and launcher item.
150 std::string app_id
= app_window
->extension()->id();
151 ash::ShelfItemStatus status
= ash::wm::IsActiveWindow(window
) ?
152 ash::STATUS_ACTIVE
: ash::STATUS_RUNNING
;
153 AppControllerMap::iterator iter
= app_controller_map_
.find(app_shelf_id
);
154 ash::ShelfID shelf_id
= 0;
155 if (iter
!= app_controller_map_
.end()) {
156 ShellWindowLauncherItemController
* controller
= iter
->second
;
157 DCHECK(controller
->app_id() == app_id
);
158 shelf_id
= controller
->shelf_id();
159 controller
->AddAppWindow(app_window
, status
);
161 LauncherItemController::Type type
=
162 app_window
->window_type_is_panel()
163 ? LauncherItemController::TYPE_APP_PANEL
164 : LauncherItemController::TYPE_APP
;
165 ShellWindowLauncherItemController
* controller
=
166 new ShellWindowLauncherItemController(
167 type
, app_shelf_id
, app_id
, owner_
);
168 controller
->AddAppWindow(app_window
, status
);
169 // If the app shelf id is not unique, and there is already a shelf
170 // item for this app id (e.g. pinned), use that shelf item.
171 if (app_shelf_id
== app_id
)
172 shelf_id
= owner_
->GetShelfIDForAppID(app_id
);
174 shelf_id
= owner_
->CreateAppLauncherItem(controller
, app_id
, status
);
175 // Restore any existing app icon and flag as set.
176 const gfx::Image
& app_icon
= app_window
->app_icon();
177 if (!app_icon
.IsEmpty()) {
178 owner_
->SetLauncherItemImage(shelf_id
, app_icon
.AsImageSkia());
179 controller
->set_image_set_by_controller(true);
182 owner_
->SetItemController(shelf_id
, controller
);
184 const std::string app_shelf_id
= GetAppShelfId(app_window
);
185 app_controller_map_
[app_shelf_id
] = controller
;
187 owner_
->SetItemStatus(shelf_id
, status
);
188 ash::SetShelfIDForWindow(shelf_id
, window
);
191 void ShellWindowLauncherController::UnregisterApp(aura::Window
* window
) {
192 WindowToAppShelfIdMap::iterator iter1
=
193 window_to_app_shelf_id_map_
.find(window
);
194 DCHECK(iter1
!= window_to_app_shelf_id_map_
.end());
195 std::string app_shelf_id
= iter1
->second
;
196 window_to_app_shelf_id_map_
.erase(iter1
);
197 window
->RemoveObserver(this);
199 AppControllerMap::iterator iter2
= app_controller_map_
.find(app_shelf_id
);
200 DCHECK(iter2
!= app_controller_map_
.end());
201 ShellWindowLauncherItemController
* controller
= iter2
->second
;
202 controller
->RemoveShellWindowForWindow(window
);
203 if (controller
->app_window_count() == 0) {
204 // If this is the last window associated with the app shelf id, close the
206 ash::ShelfID shelf_id
= controller
->shelf_id();
207 owner_
->CloseLauncherItem(shelf_id
);
208 app_controller_map_
.erase(iter2
);
212 bool ShellWindowLauncherController::IsRegisteredApp(aura::Window
* window
) {
213 return window_to_app_shelf_id_map_
.find(window
) !=
214 window_to_app_shelf_id_map_
.end();
219 ShellWindowLauncherItemController
*
220 ShellWindowLauncherController::ControllerForWindow(
221 aura::Window
* window
) {
222 WindowToAppShelfIdMap::iterator iter1
=
223 window_to_app_shelf_id_map_
.find(window
);
224 if (iter1
== window_to_app_shelf_id_map_
.end())
226 std::string app_shelf_id
= iter1
->second
;
227 AppControllerMap::iterator iter2
= app_controller_map_
.find(app_shelf_id
);
228 if (iter2
== app_controller_map_
.end())
230 return iter2
->second
;