• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
6 
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"
25 
26 using apps::ShellWindow;
27 
28 namespace {
29 
30 // Size of the icon in the shelf launcher in display-independent pixels.
31 const int kAppListIconSize = 24;
32 
33 // This will return a slightly smaller icon than the app icon to be used in
34 // the application list menu.
GetAppListIcon(ShellWindow * shell_window)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
40   // time being.
41   if (shell_window->app_icon().IsEmpty())
42     return make_scoped_ptr(new gfx::Image());
43 
44   SkBitmap bmp =
45       skia::ImageOperations::Resize(*shell_window->app_icon().ToSkBitmap(),
46                                     skia::ImageOperations::RESIZE_BEST,
47                                     kAppListIconSize,
48                                     kAppListIconSize);
49   return make_scoped_ptr(
50       new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp)));
51 }
52 
53 // Functor for std::find_if used in AppLauncherItemController.
54 class ShellWindowHasWindow {
55  public:
ShellWindowHasWindow(aura::Window * window)56   explicit ShellWindowHasWindow(aura::Window* window) : window_(window) { }
57 
operator ()(ShellWindow * shell_window) const58   bool operator()(ShellWindow* shell_window) const {
59     return shell_window->GetNativeWindow() == window_;
60   }
61 
62  private:
63   const aura::Window* window_;
64 };
65 
66 }  // namespace
67 
ShellWindowLauncherItemController(Type type,const std::string & app_launcher_id,const std::string & app_id,ChromeLauncherController * controller)68 ShellWindowLauncherItemController::ShellWindowLauncherItemController(
69     Type type,
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) {
77 }
78 
~ShellWindowLauncherItemController()79 ShellWindowLauncherItemController::~ShellWindowLauncherItemController() {
80 }
81 
AddShellWindow(ShellWindow * shell_window,ash::LauncherItemStatus status)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());
89 }
90 
RemoveShellWindowForWindow(aura::Window * window)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);
100   }
101   observed_windows_.Remove(window);
102 }
103 
SetActiveWindow(aura::Window * 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;
110 }
111 
IsOpen() const112 bool ShellWindowLauncherItemController::IsOpen() const {
113   return !shell_windows_.empty();
114 }
115 
IsVisible() const116 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())
121       return true;
122   }
123   return false;
124 }
125 
Launch(ash::LaunchSource source,int event_flags)126 void ShellWindowLauncherItemController::Launch(ash::LaunchSource source,
127                                                int event_flags) {
128   launcher_controller()->LaunchApp(app_id(),
129                                    source,
130                                    ui::EF_NONE);
131 }
132 
Activate(ash::LaunchSource source)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();
138   return false;
139 }
140 
Close()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();
147   }
148 }
149 
ActivateIndexedApp(size_t index)150 void ShellWindowLauncherItemController::ActivateIndexedApp(size_t index) {
151   if (index >= shell_windows_.size())
152     return;
153   ShellWindowList::iterator it = shell_windows_.begin();
154   std::advance(it, index);
155   ShowAndActivateOrMinimize(*it);
156 }
157 
158 ChromeLauncherAppMenuItems
GetApplicationList(int event_flags)159 ShellWindowLauncherItemController::GetApplicationList(int event_flags) {
160   ChromeLauncherAppMenuItems items;
161   items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false));
162   int index = 0;
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
170         app_id(),
171         launcher_controller(),
172         index,
173         index == 0 /* has_leading_separator */));
174     ++index;
175   }
176   return items.Pass();
177 }
178 
ItemSelected(const ui::Event & event)179 bool ShellWindowLauncherItemController::ItemSelected(const ui::Event& event) {
180   if (shell_windows_.empty())
181     return false;
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);
192     } else {
193       ShowAndActivateOrMinimize(panel);
194     }
195   } else {
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);
204     } else {
205       ShowAndActivateOrMinimize(window_to_show);
206     }
207   }
208   return false;
209 }
210 
GetTitle()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();
218       if (!title.empty())
219         return title;
220     }
221   }
222   return GetAppTitle();
223 }
224 
CreateContextMenu(aura::Window * root_window)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);
230 }
231 
CreateApplicationMenu(int event_flags)232 ash::ShelfMenuModel* ShellWindowLauncherItemController::CreateApplicationMenu(
233     int event_flags) {
234   return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags));
235 }
236 
IsDraggable()237 bool ShellWindowLauncherItemController::IsDraggable() {
238   if (type() == TYPE_APP_PANEL)
239     return true;
240   return launcher_controller()->CanPin() ? true : false;
241 }
242 
ShouldShowTooltip()243 bool ShellWindowLauncherItemController::ShouldShowTooltip() {
244   if (type() == TYPE_APP_PANEL && IsVisible())
245     return false;
246   return true;
247 }
248 
OnWindowPropertyChanged(aura::Window * window,const void * key,intptr_t old)249 void ShellWindowLauncherItemController::OnWindowPropertyChanged(
250     aura::Window* window,
251     const void* key,
252     intptr_t old) {
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;
259     } else {
260       status = ash::STATUS_RUNNING;
261     }
262     launcher_controller()->SetItemStatus(launcher_id(), status);
263   }
264 }
265 
ShowAndActivateOrMinimize(ShellWindow * shell_window)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);
272 }
273 
ActivateOrAdvanceToNextShellWindow(ShellWindow * window_to_show)274 void ShellWindowLauncherItemController::ActivateOrAdvanceToNextShellWindow(
275     ShellWindow* window_to_show) {
276   ShellWindowList::iterator i(
277       std::find(shell_windows_.begin(),
278                 shell_windows_.end(),
279                 window_to_show));
280   if (i != shell_windows_.end()) {
281     if (++i != shell_windows_.end())
282       window_to_show = *i;
283     else
284       window_to_show = shell_windows_.front();
285   }
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);
291   } else {
292     ShowAndActivateOrMinimize(window_to_show);
293   }
294 }
295