| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h" | 5 #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h" |
| 6 | 6 |
| 7 #include "ash/wm/window_state.h" | |
| 8 #include "ash/wm/window_util.h" | 7 #include "ash/wm/window_util.h" |
| 9 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" | |
| 10 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h" | |
| 11 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" | 8 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" |
| 12 #include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" | |
| 13 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" | |
| 14 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h" | |
| 15 #include "components/favicon/content/content_favicon_driver.h" | |
| 16 #include "content/public/browser/web_contents.h" | |
| 17 #include "extensions/browser/app_window/app_window.h" | |
| 18 #include "extensions/browser/app_window/native_app_window.h" | |
| 19 #include "skia/ext/image_operations.h" | |
| 20 #include "ui/aura/client/aura_constants.h" | 9 #include "ui/aura/client/aura_constants.h" |
| 21 #include "ui/aura/window.h" | 10 #include "ui/aura/window.h" |
| 22 #include "ui/events/event.h" | 11 #include "ui/base/base_window.h" |
| 23 #include "ui/gfx/image/image_skia.h" | |
| 24 #include "ui/wm/core/window_animations.h" | 12 #include "ui/wm/core/window_animations.h" |
| 25 | 13 |
| 26 using extensions::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 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 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 gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp)); | |
| 50 } | |
| 51 | |
| 52 // Functor for std::find_if used in AppLauncherItemController. | |
| 53 class AppWindowHasWindow { | |
| 54 public: | |
| 55 explicit AppWindowHasWindow(aura::Window* window) : window_(window) {} | |
| 56 | |
| 57 bool operator()(AppWindow* app_window) const { | |
| 58 return app_window->GetNativeWindow() == window_; | |
| 59 } | |
| 60 | |
| 61 private: | |
| 62 const aura::Window* window_; | |
| 63 }; | |
| 64 | |
| 65 } // namespace | |
| 66 | |
| 67 AppWindowLauncherItemController::AppWindowLauncherItemController( | 14 AppWindowLauncherItemController::AppWindowLauncherItemController( |
| 68 Type type, | 15 Type type, |
| 69 const std::string& app_shelf_id, | 16 const std::string& app_shelf_id, |
| 70 const std::string& app_id, | 17 const std::string& app_id, |
| 71 ChromeLauncherController* controller) | 18 ChromeLauncherController* controller) |
| 72 : LauncherItemController(type, app_id, controller), | 19 : LauncherItemController(type, app_id, controller), |
| 73 last_active_app_window_(NULL), | |
| 74 app_shelf_id_(app_shelf_id), | 20 app_shelf_id_(app_shelf_id), |
| 75 observed_windows_(this) {} | 21 observed_windows_(this) {} |
| 76 | 22 |
| 77 AppWindowLauncherItemController::~AppWindowLauncherItemController() {} | 23 AppWindowLauncherItemController::~AppWindowLauncherItemController() {} |
| 78 | 24 |
| 79 void AppWindowLauncherItemController::AddAppWindow( | 25 void AppWindowLauncherItemController::AddWindow(ui::BaseWindow* window) { |
| 80 AppWindow* app_window, | 26 windows_.push_front(window); |
| 81 ash::ShelfItemStatus status) { | 27 observed_windows_.Add(window->GetNativeWindow()); |
| 82 if (app_window->window_type_is_panel() && type() != TYPE_APP_PANEL) | |
| 83 LOG(ERROR) << "AppWindow of type Panel added to non-panel launcher item"; | |
| 84 app_windows_.push_front(app_window); | |
| 85 observed_windows_.Add(app_window->GetNativeWindow()); | |
| 86 } | 28 } |
| 87 | 29 |
| 88 void AppWindowLauncherItemController::RemoveAppWindowForWindow( | 30 AppWindowLauncherItemController::WindowList::iterator |
| 31 AppWindowLauncherItemController::GetFromNativeWindow(aura::Window* window) { |
| 32 return std::find_if(windows_.begin(), windows_.end(), |
| 33 [window](ui::BaseWindow* base_window) { |
| 34 return base_window->GetNativeWindow() == window; |
| 35 }); |
| 36 } |
| 37 |
| 38 void AppWindowLauncherItemController::RemoveWindowForNativeWindow( |
| 89 aura::Window* window) { | 39 aura::Window* window) { |
| 90 AppWindowList::iterator iter = std::find_if( | 40 auto iter = GetFromNativeWindow(window); |
| 91 app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window)); | 41 if (iter != windows_.end()) { |
| 92 if (iter != app_windows_.end()) { | 42 if (*iter == last_active_window_) |
| 93 if (*iter == last_active_app_window_) | 43 last_active_window_ = nullptr; |
| 94 last_active_app_window_ = NULL; | 44 OnWindowRemoved(*iter); |
| 95 app_windows_.erase(iter); | 45 windows_.erase(iter); |
| 96 } | 46 } |
| 97 observed_windows_.Remove(window); | 47 observed_windows_.Remove(window); |
| 98 } | 48 } |
| 99 | 49 |
| 100 void AppWindowLauncherItemController::SetActiveWindow(aura::Window* window) { | 50 void AppWindowLauncherItemController::SetActiveWindow(aura::Window* window) { |
| 101 AppWindowList::iterator iter = std::find_if( | 51 auto iter = GetFromNativeWindow(window); |
| 102 app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window)); | 52 if (iter != windows_.end()) |
| 103 if (iter != app_windows_.end()) | 53 last_active_window_ = *iter; |
| 104 last_active_app_window_ = *iter; | |
| 105 } | 54 } |
| 106 | 55 |
| 107 bool AppWindowLauncherItemController::IsOpen() const { | 56 bool AppWindowLauncherItemController::IsOpen() const { |
| 108 return !app_windows_.empty(); | 57 return !windows_.empty(); |
| 109 } | 58 } |
| 110 | 59 |
| 111 bool AppWindowLauncherItemController::IsVisible() const { | 60 bool AppWindowLauncherItemController::IsVisible() const { |
| 112 // Return true if any windows are visible. | 61 // Return true if any windows are visible. |
| 113 for (AppWindowList::const_iterator iter = app_windows_.begin(); | 62 for (const auto& window : windows_) { |
| 114 iter != app_windows_.end(); | 63 if (window->GetNativeWindow()->IsVisible()) |
| 115 ++iter) { | |
| 116 if ((*iter)->GetNativeWindow()->IsVisible()) | |
| 117 return true; | 64 return true; |
| 118 } | 65 } |
| 119 return false; | 66 return false; |
| 120 } | 67 } |
| 121 | 68 |
| 122 void AppWindowLauncherItemController::Launch(ash::LaunchSource source, | 69 void AppWindowLauncherItemController::Launch(ash::LaunchSource source, |
| 123 int event_flags) { | 70 int event_flags) { |
| 124 launcher_controller()->LaunchApp(app_id(), source, ui::EF_NONE); | 71 launcher_controller()->LaunchApp(app_id(), source, ui::EF_NONE); |
| 125 } | 72 } |
| 126 | 73 |
| 127 ash::ShelfItemDelegate::PerformedAction | 74 ash::ShelfItemDelegate::PerformedAction |
| 128 AppWindowLauncherItemController::Activate(ash::LaunchSource source) { | 75 AppWindowLauncherItemController::Activate(ash::LaunchSource source) { |
| 129 DCHECK(!app_windows_.empty()); | 76 DCHECK(!windows_.empty()); |
| 130 AppWindow* window_to_activate = | 77 ui::BaseWindow* window_to_activate = |
| 131 last_active_app_window_ ? last_active_app_window_ : app_windows_.back(); | 78 last_active_window_ ? last_active_window_ : windows_.back(); |
| 132 window_to_activate->GetBaseWindow()->Activate(); | 79 window_to_activate->Activate(); |
| 133 return kExistingWindowActivated; | 80 return kExistingWindowActivated; |
| 134 } | 81 } |
| 135 | 82 |
| 136 void AppWindowLauncherItemController::Close() { | 83 void AppWindowLauncherItemController::Close() { |
| 137 // Note: Closing windows may affect the contents of app_windows_. | 84 // Note: Closing windows may affect the contents of app_windows_. |
| 138 AppWindowList windows_to_close = app_windows_; | 85 WindowList windows_to_close = windows_; |
| 139 for (AppWindowList::iterator iter = windows_to_close.begin(); | 86 for (const auto& window : windows_) |
| 140 iter != windows_to_close.end(); | 87 window->Close(); |
| 141 ++iter) { | |
| 142 (*iter)->GetBaseWindow()->Close(); | |
| 143 } | |
| 144 } | 88 } |
| 145 | 89 |
| 146 void AppWindowLauncherItemController::ActivateIndexedApp(size_t index) { | 90 void AppWindowLauncherItemController::ActivateIndexedApp(size_t index) { |
| 147 if (index >= app_windows_.size()) | 91 if (index >= windows_.size()) |
| 148 return; | 92 return; |
| 149 AppWindowList::iterator it = app_windows_.begin(); | 93 auto it = windows_.begin(); |
| 150 std::advance(it, index); | 94 std::advance(it, index); |
| 151 ShowAndActivateOrMinimize(*it); | 95 ShowAndActivateOrMinimize(*it); |
| 152 } | 96 } |
| 153 | 97 |
| 154 ChromeLauncherAppMenuItems AppWindowLauncherItemController::GetApplicationList( | 98 ChromeLauncherAppMenuItems AppWindowLauncherItemController::GetApplicationList( |
| 155 int event_flags) { | 99 int event_flags) { |
| 156 ChromeLauncherAppMenuItems items; | 100 ChromeLauncherAppMenuItems items; |
| 157 items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false)); | 101 items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false)); |
| 158 int index = 0; | |
| 159 for (AppWindowList::iterator iter = app_windows_.begin(); | |
| 160 iter != app_windows_.end(); | |
| 161 ++iter) { | |
| 162 AppWindow* app_window = *iter; | |
| 163 | |
| 164 // If the app's web contents provides a favicon, use it. Otherwise, use a | |
| 165 // scaled down app icon. | |
| 166 favicon::FaviconDriver* favicon_driver = | |
| 167 favicon::ContentFaviconDriver::FromWebContents( | |
| 168 app_window->web_contents()); | |
| 169 gfx::Image result = favicon_driver->GetFavicon(); | |
| 170 if (result.IsEmpty()) | |
| 171 result = GetAppListIcon(app_window); | |
| 172 | |
| 173 items.push_back(new ChromeLauncherAppMenuItemV2App( | |
| 174 app_window->GetTitle(), | |
| 175 &result, // Will be copied | |
| 176 app_id(), | |
| 177 launcher_controller(), | |
| 178 index, | |
| 179 index == 0 /* has_leading_separator */)); | |
| 180 ++index; | |
| 181 } | |
| 182 return items; | 102 return items; |
| 183 } | 103 } |
| 184 | 104 |
| 185 ash::ShelfItemDelegate::PerformedAction | 105 ash::ShelfItemDelegate::PerformedAction |
| 186 AppWindowLauncherItemController::ItemSelected(const ui::Event& event) { | 106 AppWindowLauncherItemController::ItemSelected(const ui::Event& event) { |
| 187 if (app_windows_.empty()) | 107 if (windows_.empty()) |
| 188 return kNoAction; | 108 return kNoAction; |
| 189 if (type() == TYPE_APP_PANEL) { | 109 |
| 190 DCHECK_EQ(app_windows_.size(), 1u); | 110 DCHECK_EQ(TYPE_APP, type()); |
| 191 AppWindow* panel = app_windows_.front(); | 111 ui::BaseWindow* window_to_show = |
| 192 aura::Window* panel_window = panel->GetNativeWindow(); | 112 last_active_window_ ? last_active_window_ : windows_.front(); |
| 193 // If the panel is attached on another display, move it to the current | 113 // If the event was triggered by a keystroke, we try to advance to the next |
| 194 // display and activate it. | 114 // item if the window we are trying to activate is already active. |
| 195 if (ash::wm::GetWindowState(panel_window)->panel_attached() && | 115 if (windows_.size() >= 1 && window_to_show->IsActive() && |
| 196 ash::wm::MoveWindowToEventRoot(panel_window, event)) { | 116 event.type() == ui::ET_KEY_RELEASED) { |
| 197 if (!panel->GetBaseWindow()->IsActive()) | 117 return ActivateOrAdvanceToNextAppWindow(window_to_show); |
| 198 return ShowAndActivateOrMinimize(panel); | |
| 199 } else { | |
| 200 return ShowAndActivateOrMinimize(panel); | |
| 201 } | |
| 202 } else { | 118 } else { |
| 203 AppWindow* window_to_show = last_active_app_window_ | 119 return ShowAndActivateOrMinimize(window_to_show); |
| 204 ? last_active_app_window_ | |
| 205 : app_windows_.front(); | |
| 206 // If the event was triggered by a keystroke, we try to advance to the next | |
| 207 // item if the window we are trying to activate is already active. | |
| 208 if (app_windows_.size() >= 1 && | |
| 209 window_to_show->GetBaseWindow()->IsActive() && | |
| 210 event.type() == ui::ET_KEY_RELEASED) { | |
| 211 return ActivateOrAdvanceToNextAppWindow(window_to_show); | |
| 212 } else { | |
| 213 return ShowAndActivateOrMinimize(window_to_show); | |
| 214 } | |
| 215 } | 120 } |
| 216 return kNoAction; | |
| 217 } | 121 } |
| 218 | 122 |
| 219 base::string16 AppWindowLauncherItemController::GetTitle() { | 123 base::string16 AppWindowLauncherItemController::GetTitle() { |
| 220 // For panels return the title of the contents if set. | |
| 221 // Otherwise return the title of the app. | |
| 222 if (type() == TYPE_APP_PANEL && !app_windows_.empty()) { | |
| 223 AppWindow* app_window = app_windows_.front(); | |
| 224 if (app_window->web_contents()) { | |
| 225 base::string16 title = app_window->web_contents()->GetTitle(); | |
| 226 if (!title.empty()) | |
| 227 return title; | |
| 228 } | |
| 229 } | |
| 230 return GetAppTitle(); | 124 return GetAppTitle(); |
| 231 } | 125 } |
| 232 | 126 |
| 233 ash::ShelfMenuModel* AppWindowLauncherItemController::CreateApplicationMenu( | |
| 234 int event_flags) { | |
| 235 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); | |
| 236 } | |
| 237 | |
| 238 bool AppWindowLauncherItemController::IsDraggable() { | 127 bool AppWindowLauncherItemController::IsDraggable() { |
| 239 if (type() == TYPE_APP_PANEL) | 128 DCHECK_EQ(TYPE_APP, type()); |
| 240 return true; | |
| 241 return CanPin(); | 129 return CanPin(); |
| 242 } | 130 } |
| 243 | 131 |
| 244 bool AppWindowLauncherItemController::CanPin() const { | 132 bool AppWindowLauncherItemController::CanPin() const { |
| 245 return launcher_controller()->CanPin(app_id()); | 133 return launcher_controller()->CanPin(app_id()); |
| 246 } | 134 } |
| 247 | 135 |
| 248 bool AppWindowLauncherItemController::ShouldShowTooltip() { | 136 bool AppWindowLauncherItemController::ShouldShowTooltip() { |
| 249 if (type() == TYPE_APP_PANEL && IsVisible()) | 137 DCHECK_EQ(TYPE_APP, type()); |
| 250 return false; | |
| 251 return true; | 138 return true; |
| 252 } | 139 } |
| 253 | 140 |
| 254 void AppWindowLauncherItemController::OnWindowPropertyChanged( | 141 void AppWindowLauncherItemController::OnWindowPropertyChanged( |
| 255 aura::Window* window, | 142 aura::Window* window, |
| 256 const void* key, | 143 const void* key, |
| 257 intptr_t old) { | 144 intptr_t old) { |
| 258 if (key == aura::client::kDrawAttentionKey) { | 145 if (key == aura::client::kDrawAttentionKey) { |
| 259 ash::ShelfItemStatus status; | 146 ash::ShelfItemStatus status; |
| 260 if (ash::wm::IsActiveWindow(window)) { | 147 if (ash::wm::IsActiveWindow(window)) { |
| 261 status = ash::STATUS_ACTIVE; | 148 status = ash::STATUS_ACTIVE; |
| 262 } else if (window->GetProperty(aura::client::kDrawAttentionKey)) { | 149 } else if (window->GetProperty(aura::client::kDrawAttentionKey)) { |
| 263 status = ash::STATUS_ATTENTION; | 150 status = ash::STATUS_ATTENTION; |
| 264 } else { | 151 } else { |
| 265 status = ash::STATUS_RUNNING; | 152 status = ash::STATUS_RUNNING; |
| 266 } | 153 } |
| 267 launcher_controller()->SetItemStatus(shelf_id(), status); | 154 launcher_controller()->SetItemStatus(shelf_id(), status); |
| 268 } | 155 } |
| 269 } | 156 } |
| 270 | 157 |
| 271 ash::ShelfItemDelegate::PerformedAction | 158 ash::ShelfItemDelegate::PerformedAction |
| 272 AppWindowLauncherItemController::ShowAndActivateOrMinimize( | 159 AppWindowLauncherItemController::ShowAndActivateOrMinimize( |
| 273 AppWindow* app_window) { | 160 ui::BaseWindow* app_window) { |
| 274 // Either show or minimize windows when shown from the launcher. | 161 // Either show or minimize windows when shown from the launcher. |
| 275 return launcher_controller()->ActivateWindowOrMinimizeIfActive( | 162 return launcher_controller()->ActivateWindowOrMinimizeIfActive( |
| 276 app_window->GetBaseWindow(), GetApplicationList(0).size() == 2); | 163 app_window, GetApplicationList(0).size() == 2); |
| 277 } | 164 } |
| 278 | 165 |
| 279 ash::ShelfItemDelegate::PerformedAction | 166 ash::ShelfItemDelegate::PerformedAction |
| 280 AppWindowLauncherItemController::ActivateOrAdvanceToNextAppWindow( | 167 AppWindowLauncherItemController::ActivateOrAdvanceToNextAppWindow( |
| 281 AppWindow* window_to_show) { | 168 ui::BaseWindow* window_to_show) { |
| 282 AppWindowList::iterator i( | 169 WindowList::iterator i( |
| 283 std::find(app_windows_.begin(), app_windows_.end(), window_to_show)); | 170 std::find(windows_.begin(), windows_.end(), window_to_show)); |
| 284 if (i != app_windows_.end()) { | 171 if (i != windows_.end()) { |
| 285 if (++i != app_windows_.end()) | 172 if (++i != windows_.end()) |
| 286 window_to_show = *i; | 173 window_to_show = *i; |
| 287 else | 174 else |
| 288 window_to_show = app_windows_.front(); | 175 window_to_show = windows_.front(); |
| 289 } | 176 } |
| 290 if (window_to_show->GetBaseWindow()->IsActive()) { | 177 if (window_to_show->IsActive()) { |
| 291 // Coming here, only a single window is active. For keyboard activations | 178 // Coming here, only a single window is active. For keyboard activations |
| 292 // the window gets animated. | 179 // the window gets animated. |
| 293 AnimateWindow(window_to_show->GetNativeWindow(), | 180 AnimateWindow(window_to_show->GetNativeWindow(), |
| 294 wm::WINDOW_ANIMATION_TYPE_BOUNCE); | 181 wm::WINDOW_ANIMATION_TYPE_BOUNCE); |
| 295 } else { | 182 } else { |
| 296 return ShowAndActivateOrMinimize(window_to_show); | 183 return ShowAndActivateOrMinimize(window_to_show); |
| 297 } | 184 } |
| 298 return kNoAction; | 185 return kNoAction; |
| 299 } | 186 } |
| OLD | NEW |