| OLD | NEW |
| (Empty) |
| 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/app_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::AppWindow; | |
| 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. | |
| 35 scoped_ptr<gfx::Image> GetAppListIcon(AppWindow* app_window) { | |
| 36 // TODO(skuhne): We instead might want to use LoadImages in | |
| 37 // AppWindow::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 (app_window->app_icon().IsEmpty()) | |
| 42 return make_scoped_ptr(new gfx::Image()); | |
| 43 | |
| 44 SkBitmap bmp = | |
| 45 skia::ImageOperations::Resize(*app_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 AppWindowHasWindow { | |
| 55 public: | |
| 56 explicit AppWindowHasWindow(aura::Window* window) : window_(window) {} | |
| 57 | |
| 58 bool operator()(AppWindow* app_window) const { | |
| 59 return app_window->GetNativeWindow() == window_; | |
| 60 } | |
| 61 | |
| 62 private: | |
| 63 const aura::Window* window_; | |
| 64 }; | |
| 65 | |
| 66 } // namespace | |
| 67 | |
| 68 ShellWindowLauncherItemController::ShellWindowLauncherItemController( | |
| 69 Type type, | |
| 70 const std::string& app_shelf_id, | |
| 71 const std::string& app_id, | |
| 72 ChromeLauncherController* controller) | |
| 73 : LauncherItemController(type, app_id, controller), | |
| 74 last_active_app_window_(NULL), | |
| 75 app_shelf_id_(app_shelf_id), | |
| 76 observed_windows_(this) {} | |
| 77 | |
| 78 ShellWindowLauncherItemController::~ShellWindowLauncherItemController() { | |
| 79 } | |
| 80 | |
| 81 void ShellWindowLauncherItemController::AddAppWindow( | |
| 82 AppWindow* app_window, | |
| 83 ash::ShelfItemStatus status) { | |
| 84 if (app_window->window_type_is_panel() && type() != TYPE_APP_PANEL) | |
| 85 LOG(ERROR) << "AppWindow of type Panel added to non-panel launcher item"; | |
| 86 app_windows_.push_front(app_window); | |
| 87 observed_windows_.Add(app_window->GetNativeWindow()); | |
| 88 } | |
| 89 | |
| 90 void ShellWindowLauncherItemController::RemoveShellWindowForWindow( | |
| 91 aura::Window* window) { | |
| 92 AppWindowList::iterator iter = std::find_if( | |
| 93 app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window)); | |
| 94 if (iter != app_windows_.end()) { | |
| 95 if (*iter == last_active_app_window_) | |
| 96 last_active_app_window_ = NULL; | |
| 97 app_windows_.erase(iter); | |
| 98 } | |
| 99 observed_windows_.Remove(window); | |
| 100 } | |
| 101 | |
| 102 void ShellWindowLauncherItemController::SetActiveWindow(aura::Window* window) { | |
| 103 AppWindowList::iterator iter = std::find_if( | |
| 104 app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window)); | |
| 105 if (iter != app_windows_.end()) | |
| 106 last_active_app_window_ = *iter; | |
| 107 } | |
| 108 | |
| 109 bool ShellWindowLauncherItemController::IsOpen() const { | |
| 110 return !app_windows_.empty(); | |
| 111 } | |
| 112 | |
| 113 bool ShellWindowLauncherItemController::IsVisible() const { | |
| 114 // Return true if any windows are visible. | |
| 115 for (AppWindowList::const_iterator iter = app_windows_.begin(); | |
| 116 iter != app_windows_.end(); | |
| 117 ++iter) { | |
| 118 if ((*iter)->GetNativeWindow()->IsVisible()) | |
| 119 return true; | |
| 120 } | |
| 121 return false; | |
| 122 } | |
| 123 | |
| 124 void ShellWindowLauncherItemController::Launch(ash::LaunchSource source, | |
| 125 int event_flags) { | |
| 126 launcher_controller()->LaunchApp(app_id(), | |
| 127 source, | |
| 128 ui::EF_NONE); | |
| 129 } | |
| 130 | |
| 131 bool ShellWindowLauncherItemController::Activate(ash::LaunchSource source) { | |
| 132 DCHECK(!app_windows_.empty()); | |
| 133 AppWindow* window_to_activate = | |
| 134 last_active_app_window_ ? last_active_app_window_ : app_windows_.back(); | |
| 135 window_to_activate->GetBaseWindow()->Activate(); | |
| 136 return false; | |
| 137 } | |
| 138 | |
| 139 void ShellWindowLauncherItemController::Close() { | |
| 140 // Note: Closing windows may affect the contents of app_windows_. | |
| 141 AppWindowList windows_to_close = app_windows_; | |
| 142 for (AppWindowList::iterator iter = windows_to_close.begin(); | |
| 143 iter != windows_to_close.end(); | |
| 144 ++iter) { | |
| 145 (*iter)->GetBaseWindow()->Close(); | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 void ShellWindowLauncherItemController::ActivateIndexedApp(size_t index) { | |
| 150 if (index >= app_windows_.size()) | |
| 151 return; | |
| 152 AppWindowList::iterator it = app_windows_.begin(); | |
| 153 std::advance(it, index); | |
| 154 ShowAndActivateOrMinimize(*it); | |
| 155 } | |
| 156 | |
| 157 ChromeLauncherAppMenuItems | |
| 158 ShellWindowLauncherItemController::GetApplicationList(int event_flags) { | |
| 159 ChromeLauncherAppMenuItems items; | |
| 160 items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false)); | |
| 161 int index = 0; | |
| 162 for (AppWindowList::iterator iter = app_windows_.begin(); | |
| 163 iter != app_windows_.end(); | |
| 164 ++iter) { | |
| 165 AppWindow* app_window = *iter; | |
| 166 scoped_ptr<gfx::Image> image(GetAppListIcon(app_window)); | |
| 167 items.push_back(new ChromeLauncherAppMenuItemV2App( | |
| 168 app_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 | |
| 179 bool ShellWindowLauncherItemController::ItemSelected(const ui::Event& event) { | |
| 180 if (app_windows_.empty()) | |
| 181 return false; | |
| 182 if (type() == TYPE_APP_PANEL) { | |
| 183 DCHECK(app_windows_.size() == 1); | |
| 184 AppWindow* panel = app_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 AppWindow* window_to_show = last_active_app_window_ | |
| 197 ? last_active_app_window_ | |
| 198 : app_windows_.front(); | |
| 199 // If the event was triggered by a keystroke, we try to advance to the next | |
| 200 // item if the window we are trying to activate is already active. | |
| 201 if (app_windows_.size() >= 1 && | |
| 202 window_to_show->GetBaseWindow()->IsActive() && | |
| 203 event.type() == ui::ET_KEY_RELEASED) { | |
| 204 ActivateOrAdvanceToNextShellWindow(window_to_show); | |
| 205 } else { | |
| 206 ShowAndActivateOrMinimize(window_to_show); | |
| 207 } | |
| 208 } | |
| 209 return false; | |
| 210 } | |
| 211 | |
| 212 base::string16 ShellWindowLauncherItemController::GetTitle() { | |
| 213 // For panels return the title of the contents if set. | |
| 214 // Otherwise return the title of the app. | |
| 215 if (type() == TYPE_APP_PANEL && !app_windows_.empty()) { | |
| 216 AppWindow* app_window = app_windows_.front(); | |
| 217 if (app_window->web_contents()) { | |
| 218 base::string16 title = app_window->web_contents()->GetTitle(); | |
| 219 if (!title.empty()) | |
| 220 return title; | |
| 221 } | |
| 222 } | |
| 223 return GetAppTitle(); | |
| 224 } | |
| 225 | |
| 226 ui::MenuModel* ShellWindowLauncherItemController::CreateContextMenu( | |
| 227 aura::Window* root_window) { | |
| 228 ash::ShelfItem item = | |
| 229 *(launcher_controller()->model()->ItemByID(shelf_id())); | |
| 230 return new LauncherContextMenu(launcher_controller(), &item, root_window); | |
| 231 } | |
| 232 | |
| 233 ash::ShelfMenuModel* ShellWindowLauncherItemController::CreateApplicationMenu( | |
| 234 int event_flags) { | |
| 235 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); | |
| 236 } | |
| 237 | |
| 238 bool ShellWindowLauncherItemController::IsDraggable() { | |
| 239 if (type() == TYPE_APP_PANEL) | |
| 240 return true; | |
| 241 return launcher_controller()->CanPin() ? true : false; | |
| 242 } | |
| 243 | |
| 244 bool ShellWindowLauncherItemController::ShouldShowTooltip() { | |
| 245 if (type() == TYPE_APP_PANEL && IsVisible()) | |
| 246 return false; | |
| 247 return true; | |
| 248 } | |
| 249 | |
| 250 void ShellWindowLauncherItemController::OnWindowPropertyChanged( | |
| 251 aura::Window* window, | |
| 252 const void* key, | |
| 253 intptr_t old) { | |
| 254 if (key == aura::client::kDrawAttentionKey) { | |
| 255 ash::ShelfItemStatus status; | |
| 256 if (ash::wm::IsActiveWindow(window)) { | |
| 257 status = ash::STATUS_ACTIVE; | |
| 258 } else if (window->GetProperty(aura::client::kDrawAttentionKey)) { | |
| 259 status = ash::STATUS_ATTENTION; | |
| 260 } else { | |
| 261 status = ash::STATUS_RUNNING; | |
| 262 } | |
| 263 launcher_controller()->SetItemStatus(shelf_id(), status); | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 void ShellWindowLauncherItemController::ShowAndActivateOrMinimize( | |
| 268 AppWindow* app_window) { | |
| 269 // Either show or minimize windows when shown from the launcher. | |
| 270 launcher_controller()->ActivateWindowOrMinimizeIfActive( | |
| 271 app_window->GetBaseWindow(), GetApplicationList(0).size() == 2); | |
| 272 } | |
| 273 | |
| 274 void ShellWindowLauncherItemController::ActivateOrAdvanceToNextShellWindow( | |
| 275 AppWindow* window_to_show) { | |
| 276 AppWindowList::iterator i( | |
| 277 std::find(app_windows_.begin(), app_windows_.end(), window_to_show)); | |
| 278 if (i != app_windows_.end()) { | |
| 279 if (++i != app_windows_.end()) | |
| 280 window_to_show = *i; | |
| 281 else | |
| 282 window_to_show = app_windows_.front(); | |
| 283 } | |
| 284 if (window_to_show->GetBaseWindow()->IsActive()) { | |
| 285 // Coming here, only a single window is active. For keyboard activations | |
| 286 // the window gets animated. | |
| 287 AnimateWindow(window_to_show->GetNativeWindow(), | |
| 288 views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE); | |
| 289 } else { | |
| 290 ShowAndActivateOrMinimize(window_to_show); | |
| 291 } | |
| 292 } | |
| OLD | NEW |