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_item_controller.h"
7 #include "apps/shell_window.h"
8 #include "apps/ui/native_app_window.h"
9 #include "ash/shelf/shelf_model.h"
10 #include "ash/wm/window_state.h"
11 #include "ash/wm/window_util.h"
12 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
13 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
14 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
15 #include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
16 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
17 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
18 #include "content/public/browser/web_contents.h"
19 #include "skia/ext/image_operations.h"
20 #include "ui/aura/client/aura_constants.h"
21 #include "ui/aura/window.h"
22 #include "ui/events/event.h"
23 #include "ui/gfx/image/image_skia.h"
24 #include "ui/views/corewm/window_animations.h"
26 using apps::ShellWindow
;
30 // Size of the icon in the shelf launcher in display-independent pixels.
31 const int kAppListIconSize
= 24;
33 // This will return a slightly smaller icon than the app icon to be used in
34 // the application list menu.
35 scoped_ptr
<gfx::Image
> GetAppListIcon(ShellWindow
* shell_window
) {
36 // TODO(skuhne): We instead might want to use LoadImages in
37 // ShellWindow::UpdateExtensionAppIcon() to let the extension give us
38 // pre-defined icons in the launcher and the launcher list sizes. Since there
39 // is no mock yet, doing this now seems a bit premature and we scale for the
41 if (shell_window
->app_icon().IsEmpty())
42 return make_scoped_ptr(new gfx::Image());
45 skia::ImageOperations::Resize(*shell_window
->app_icon().ToSkBitmap(),
46 skia::ImageOperations::RESIZE_BEST
,
49 return make_scoped_ptr(
50 new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp
)));
53 // Functor for std::find_if used in AppLauncherItemController.
54 class ShellWindowHasWindow
{
56 explicit ShellWindowHasWindow(aura::Window
* window
) : window_(window
) { }
58 bool operator()(ShellWindow
* shell_window
) const {
59 return shell_window
->GetNativeWindow() == window_
;
63 const aura::Window
* window_
;
68 ShellWindowLauncherItemController::ShellWindowLauncherItemController(
70 const std::string
& app_launcher_id
,
71 const std::string
& app_id
,
72 ChromeLauncherController
* controller
)
73 : LauncherItemController(type
, app_id
, controller
),
74 last_active_shell_window_(NULL
),
75 app_launcher_id_(app_launcher_id
),
76 observed_windows_(this) {
79 ShellWindowLauncherItemController::~ShellWindowLauncherItemController() {
82 void ShellWindowLauncherItemController::AddShellWindow(
83 ShellWindow
* shell_window
,
84 ash::LauncherItemStatus status
) {
85 if (shell_window
->window_type_is_panel() && type() != TYPE_APP_PANEL
)
86 LOG(ERROR
) << "ShellWindow of type Panel added to non-panel launcher item";
87 shell_windows_
.push_front(shell_window
);
88 observed_windows_
.Add(shell_window
->GetNativeWindow());
91 void ShellWindowLauncherItemController::RemoveShellWindowForWindow(
92 aura::Window
* window
) {
93 ShellWindowList::iterator iter
=
94 std::find_if(shell_windows_
.begin(), shell_windows_
.end(),
95 ShellWindowHasWindow(window
));
96 if (iter
!= shell_windows_
.end()) {
97 if (*iter
== last_active_shell_window_
)
98 last_active_shell_window_
= NULL
;
99 shell_windows_
.erase(iter
);
101 observed_windows_
.Remove(window
);
104 void ShellWindowLauncherItemController::SetActiveWindow(aura::Window
* window
) {
105 ShellWindowList::iterator iter
=
106 std::find_if(shell_windows_
.begin(), shell_windows_
.end(),
107 ShellWindowHasWindow(window
));
108 if (iter
!= shell_windows_
.end())
109 last_active_shell_window_
= *iter
;
112 bool ShellWindowLauncherItemController::IsOpen() const {
113 return !shell_windows_
.empty();
116 bool ShellWindowLauncherItemController::IsVisible() const {
117 // Return true if any windows are visible.
118 for (ShellWindowList::const_iterator iter
= shell_windows_
.begin();
119 iter
!= shell_windows_
.end(); ++iter
) {
120 if ((*iter
)->GetNativeWindow()->IsVisible())
126 void ShellWindowLauncherItemController::Launch(ash::LaunchSource source
,
128 launcher_controller()->LaunchApp(app_id(),
133 bool ShellWindowLauncherItemController::Activate(ash::LaunchSource source
) {
134 DCHECK(!shell_windows_
.empty());
135 ShellWindow
* window_to_activate
= last_active_shell_window_
?
136 last_active_shell_window_
: shell_windows_
.back();
137 window_to_activate
->GetBaseWindow()->Activate();
141 void ShellWindowLauncherItemController::Close() {
142 // Note: Closing windows may affect the contents of shell_windows_.
143 ShellWindowList windows_to_close
= shell_windows_
;
144 for (ShellWindowList::iterator iter
= windows_to_close
.begin();
145 iter
!= windows_to_close
.end(); ++iter
) {
146 (*iter
)->GetBaseWindow()->Close();
150 void ShellWindowLauncherItemController::ActivateIndexedApp(size_t index
) {
151 if (index
>= shell_windows_
.size())
153 ShellWindowList::iterator it
= shell_windows_
.begin();
154 std::advance(it
, index
);
155 ShowAndActivateOrMinimize(*it
);
158 ChromeLauncherAppMenuItems
159 ShellWindowLauncherItemController::GetApplicationList(int event_flags
) {
160 ChromeLauncherAppMenuItems items
;
161 items
.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL
, false));
163 for (ShellWindowList::iterator iter
= shell_windows_
.begin();
164 iter
!= shell_windows_
.end(); ++iter
) {
165 ShellWindow
* shell_window
= *iter
;
166 scoped_ptr
<gfx::Image
> image(GetAppListIcon(shell_window
));
167 items
.push_back(new ChromeLauncherAppMenuItemV2App(
168 shell_window
->GetTitle(),
169 image
.get(), // Will be copied
171 launcher_controller(),
173 index
== 0 /* has_leading_separator */));
179 bool ShellWindowLauncherItemController::ItemSelected(const ui::Event
& event
) {
180 if (shell_windows_
.empty())
182 if (type() == TYPE_APP_PANEL
) {
183 DCHECK(shell_windows_
.size() == 1);
184 ShellWindow
* panel
= shell_windows_
.front();
185 aura::Window
* panel_window
= panel
->GetNativeWindow();
186 // If the panel is attached on another display, move it to the current
187 // display and activate it.
188 if (ash::wm::GetWindowState(panel_window
)->panel_attached() &&
189 ash::wm::MoveWindowToEventRoot(panel_window
, event
)) {
190 if (!panel
->GetBaseWindow()->IsActive())
191 ShowAndActivateOrMinimize(panel
);
193 ShowAndActivateOrMinimize(panel
);
196 ShellWindow
* window_to_show
= last_active_shell_window_
?
197 last_active_shell_window_
: shell_windows_
.front();
198 // If the event was triggered by a keystroke, we try to advance to the next
199 // item if the window we are trying to activate is already active.
200 if (shell_windows_
.size() >= 1 &&
201 window_to_show
->GetBaseWindow()->IsActive() &&
202 event
.type() == ui::ET_KEY_RELEASED
) {
203 ActivateOrAdvanceToNextShellWindow(window_to_show
);
205 ShowAndActivateOrMinimize(window_to_show
);
211 base::string16
ShellWindowLauncherItemController::GetTitle() {
212 // For panels return the title of the contents if set.
213 // Otherwise return the title of the app.
214 if (type() == TYPE_APP_PANEL
&& !shell_windows_
.empty()) {
215 ShellWindow
* shell_window
= shell_windows_
.front();
216 if (shell_window
->web_contents()) {
217 base::string16 title
= shell_window
->web_contents()->GetTitle();
222 return GetAppTitle();
225 ui::MenuModel
* ShellWindowLauncherItemController::CreateContextMenu(
226 aura::Window
* root_window
) {
227 ash::LauncherItem item
=
228 *(launcher_controller()->model()->ItemByID(launcher_id()));
229 return new LauncherContextMenu(launcher_controller(), &item
, root_window
);
232 ash::ShelfMenuModel
* ShellWindowLauncherItemController::CreateApplicationMenu(
234 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags
));
237 bool ShellWindowLauncherItemController::IsDraggable() {
238 if (type() == TYPE_APP_PANEL
)
240 return launcher_controller()->CanPin() ? true : false;
243 bool ShellWindowLauncherItemController::ShouldShowTooltip() {
244 if (type() == TYPE_APP_PANEL
&& IsVisible())
249 void ShellWindowLauncherItemController::OnWindowPropertyChanged(
250 aura::Window
* window
,
253 if (key
== aura::client::kDrawAttentionKey
) {
254 ash::LauncherItemStatus status
;
255 if (ash::wm::IsActiveWindow(window
)) {
256 status
= ash::STATUS_ACTIVE
;
257 } else if (window
->GetProperty(aura::client::kDrawAttentionKey
)) {
258 status
= ash::STATUS_ATTENTION
;
260 status
= ash::STATUS_RUNNING
;
262 launcher_controller()->SetItemStatus(launcher_id(), status
);
266 void ShellWindowLauncherItemController::ShowAndActivateOrMinimize(
267 ShellWindow
* shell_window
) {
268 // Either show or minimize windows when shown from the launcher.
269 launcher_controller()->ActivateWindowOrMinimizeIfActive(
270 shell_window
->GetBaseWindow(),
271 GetApplicationList(0).size() == 2);
274 void ShellWindowLauncherItemController::ActivateOrAdvanceToNextShellWindow(
275 ShellWindow
* window_to_show
) {
276 ShellWindowList::iterator
i(
277 std::find(shell_windows_
.begin(),
278 shell_windows_
.end(),
280 if (i
!= shell_windows_
.end()) {
281 if (++i
!= shell_windows_
.end())
284 window_to_show
= shell_windows_
.front();
286 if (window_to_show
->GetBaseWindow()->IsActive()) {
287 // Coming here, only a single window is active. For keyboard activations
288 // the window gets animated.
289 AnimateWindow(window_to_show
->GetNativeWindow(),
290 views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE
);
292 ShowAndActivateOrMinimize(window_to_show
);