Chromium Code Reviews| 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 { | 14 namespace { |
| 29 | 15 |
| 30 // Size of the icon in the shelf launcher in display-independent pixels. | 16 // Functor for std::find_if used in AppLauncherItemController. |
| 31 const int kAppListIconSize = 24; | 17 class WindowHasNativeWindow { |
| 18 public: | |
| 19 explicit WindowHasNativeWindow(aura::Window* window) : window_(window) {} | |
| 32 | 20 |
| 33 // This will return a slightly smaller icon than the app icon to be used in | 21 bool operator()(ui::BaseWindow* window) const { |
| 34 // the application list menu. | 22 return window->GetNativeWindow() == window_; |
| 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 } | 23 } |
| 60 | |
| 61 private: | 24 private: |
| 62 const aura::Window* window_; | 25 const aura::Window* window_; |
| 63 }; | 26 }; |
| 64 | 27 |
| 65 } // namespace | 28 } // namespace |
| 66 | 29 |
| 67 AppWindowLauncherItemController::AppWindowLauncherItemController( | 30 AppWindowLauncherItemController::AppWindowLauncherItemController( |
| 68 Type type, | 31 Type type, |
| 69 const std::string& app_shelf_id, | 32 const std::string& app_shelf_id, |
| 70 const std::string& app_id, | 33 const std::string& app_id, |
| 71 ChromeLauncherController* controller) | 34 ChromeLauncherController* controller) |
| 72 : LauncherItemController(type, app_id, controller), | 35 : LauncherItemController(type, app_id, controller), |
| 73 last_active_app_window_(NULL), | |
| 74 app_shelf_id_(app_shelf_id), | 36 app_shelf_id_(app_shelf_id), |
| 75 observed_windows_(this) {} | 37 observed_windows_(this) {} |
| 76 | 38 |
| 77 AppWindowLauncherItemController::~AppWindowLauncherItemController() {} | 39 AppWindowLauncherItemController::~AppWindowLauncherItemController() {} |
| 78 | 40 |
| 79 void AppWindowLauncherItemController::AddAppWindow( | 41 void AppWindowLauncherItemController::AddWindow(ui::BaseWindow* window) { |
| 80 AppWindow* app_window, | 42 windows_.push_front(window); |
| 81 ash::ShelfItemStatus status) { | 43 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 } | 44 } |
| 87 | 45 |
| 88 void AppWindowLauncherItemController::RemoveAppWindowForWindow( | 46 void AppWindowLauncherItemController::RemoveWindowForNativeWindow( |
| 89 aura::Window* window) { | 47 aura::Window* window) { |
| 90 AppWindowList::iterator iter = std::find_if( | 48 WindowList::iterator iter = std::find_if(windows_.begin(), windows_.end(), |
| 91 app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window)); | 49 WindowHasNativeWindow(window)); |
|
xiyuan
2016/03/23 23:22:53
nit: we can use lambda
e.g.
auto iter = std::fin
khmel
2016/03/24 16:30:37
Thanks for idea, also use helper function to reduc
| |
| 92 if (iter != app_windows_.end()) { | 50 if (iter != windows_.end()) { |
| 93 if (*iter == last_active_app_window_) | 51 if (*iter == last_active_window_) |
| 94 last_active_app_window_ = NULL; | 52 last_active_window_ = nullptr; |
| 95 app_windows_.erase(iter); | 53 OnWindowRemoved(*iter); |
| 54 windows_.erase(iter); | |
| 96 } | 55 } |
| 97 observed_windows_.Remove(window); | 56 observed_windows_.Remove(window); |
| 98 } | 57 } |
| 99 | 58 |
| 100 void AppWindowLauncherItemController::SetActiveWindow(aura::Window* window) { | 59 void AppWindowLauncherItemController::SetActiveWindow(aura::Window* window) { |
| 101 AppWindowList::iterator iter = std::find_if( | 60 WindowList::iterator iter = std::find_if(windows_.begin(), windows_.end(), |
| 102 app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window)); | 61 WindowHasNativeWindow(window)); |
|
xiyuan
2016/03/23 23:22:53
nit: use lambda ?
khmel
2016/03/24 16:30:37
Done.
| |
| 103 if (iter != app_windows_.end()) | 62 if (iter != windows_.end()) |
| 104 last_active_app_window_ = *iter; | 63 last_active_window_ = *iter; |
| 105 } | 64 } |
| 106 | 65 |
| 107 bool AppWindowLauncherItemController::IsOpen() const { | 66 bool AppWindowLauncherItemController::IsOpen() const { |
| 108 return !app_windows_.empty(); | 67 return !windows_.empty(); |
| 109 } | 68 } |
| 110 | 69 |
| 111 bool AppWindowLauncherItemController::IsVisible() const { | 70 bool AppWindowLauncherItemController::IsVisible() const { |
| 112 // Return true if any windows are visible. | 71 // Return true if any windows are visible. |
| 113 for (AppWindowList::const_iterator iter = app_windows_.begin(); | 72 for (WindowList::const_iterator iter = windows_.begin(); |
| 114 iter != app_windows_.end(); | 73 iter != windows_.end(); ++iter) { |
|
xiyuan
2016/03/23 23:22:52
nit: We can use range loop now.
i.e.
for (const a
khmel
2016/03/24 16:30:37
Done.
| |
| 115 ++iter) { | |
| 116 if ((*iter)->GetNativeWindow()->IsVisible()) | 74 if ((*iter)->GetNativeWindow()->IsVisible()) |
| 117 return true; | 75 return true; |
| 118 } | 76 } |
| 119 return false; | 77 return false; |
| 120 } | 78 } |
| 121 | 79 |
| 122 void AppWindowLauncherItemController::Launch(ash::LaunchSource source, | 80 void AppWindowLauncherItemController::Launch(ash::LaunchSource source, |
| 123 int event_flags) { | 81 int event_flags) { |
| 124 launcher_controller()->LaunchApp(app_id(), source, ui::EF_NONE); | 82 launcher_controller()->LaunchApp(app_id(), source, ui::EF_NONE); |
| 125 } | 83 } |
| 126 | 84 |
| 127 ash::ShelfItemDelegate::PerformedAction | 85 ash::ShelfItemDelegate::PerformedAction |
| 128 AppWindowLauncherItemController::Activate(ash::LaunchSource source) { | 86 AppWindowLauncherItemController::Activate(ash::LaunchSource source) { |
| 129 DCHECK(!app_windows_.empty()); | 87 DCHECK(!windows_.empty()); |
| 130 AppWindow* window_to_activate = | 88 ui::BaseWindow* window_to_activate = |
| 131 last_active_app_window_ ? last_active_app_window_ : app_windows_.back(); | 89 last_active_window_ ? last_active_window_ : windows_.back(); |
| 132 window_to_activate->GetBaseWindow()->Activate(); | 90 window_to_activate->Activate(); |
| 133 return kExistingWindowActivated; | 91 return kExistingWindowActivated; |
| 134 } | 92 } |
| 135 | 93 |
| 136 void AppWindowLauncherItemController::Close() { | 94 void AppWindowLauncherItemController::Close() { |
| 137 // Note: Closing windows may affect the contents of app_windows_. | 95 // Note: Closing windows may affect the contents of app_windows_. |
| 138 AppWindowList windows_to_close = app_windows_; | 96 WindowList windows_to_close = windows_; |
| 139 for (AppWindowList::iterator iter = windows_to_close.begin(); | 97 for (WindowList::iterator iter = windows_to_close.begin(); |
| 140 iter != windows_to_close.end(); | 98 iter != windows_to_close.end(); ++iter) { |
|
xiyuan
2016/03/23 23:22:52
nit: range loop?
khmel
2016/03/24 16:30:37
Done.
| |
| 141 ++iter) { | 99 (*iter)->Close(); |
| 142 (*iter)->GetBaseWindow()->Close(); | |
| 143 } | 100 } |
| 144 } | 101 } |
| 145 | 102 |
| 146 void AppWindowLauncherItemController::ActivateIndexedApp(size_t index) { | 103 void AppWindowLauncherItemController::ActivateIndexedApp(size_t index) { |
| 147 if (index >= app_windows_.size()) | 104 if (index >= windows_.size()) |
| 148 return; | 105 return; |
| 149 AppWindowList::iterator it = app_windows_.begin(); | 106 WindowList::iterator it = windows_.begin(); |
| 150 std::advance(it, index); | 107 std::advance(it, index); |
| 151 ShowAndActivateOrMinimize(*it); | 108 ShowAndActivateOrMinimize(*it); |
| 152 } | 109 } |
| 153 | 110 |
| 154 ChromeLauncherAppMenuItems AppWindowLauncherItemController::GetApplicationList( | 111 ChromeLauncherAppMenuItems AppWindowLauncherItemController::GetApplicationList( |
| 155 int event_flags) { | 112 int event_flags) { |
| 156 ChromeLauncherAppMenuItems items; | 113 ChromeLauncherAppMenuItems items; |
| 157 items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false)); | 114 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; | 115 return items; |
| 183 } | 116 } |
| 184 | 117 |
| 185 ash::ShelfItemDelegate::PerformedAction | 118 ash::ShelfItemDelegate::PerformedAction |
| 186 AppWindowLauncherItemController::ItemSelected(const ui::Event& event) { | 119 AppWindowLauncherItemController::ItemSelected(const ui::Event& event) { |
| 187 if (app_windows_.empty()) | 120 if (windows_.empty()) |
| 188 return kNoAction; | 121 return kNoAction; |
| 189 if (type() == TYPE_APP_PANEL) { | 122 |
| 190 DCHECK_EQ(app_windows_.size(), 1u); | 123 DCHECK(type() == TYPE_APP); |
|
xiyuan
2016/03/23 23:22:53
nit: DCHECK_EQ(TYPE_APP, type());
khmel
2016/03/24 16:30:37
Done.
| |
| 191 AppWindow* panel = app_windows_.front(); | 124 ui::BaseWindow* window_to_show = |
| 192 aura::Window* panel_window = panel->GetNativeWindow(); | 125 last_active_window_ ? last_active_window_ : windows_.front(); |
| 193 // If the panel is attached on another display, move it to the current | 126 // If the event was triggered by a keystroke, we try to advance to the next |
| 194 // display and activate it. | 127 // item if the window we are trying to activate is already active. |
| 195 if (ash::wm::GetWindowState(panel_window)->panel_attached() && | 128 if (windows_.size() >= 1 && window_to_show->IsActive() && |
| 196 ash::wm::MoveWindowToEventRoot(panel_window, event)) { | 129 event.type() == ui::ET_KEY_RELEASED) { |
| 197 if (!panel->GetBaseWindow()->IsActive()) | 130 return ActivateOrAdvanceToNextAppWindow(window_to_show); |
| 198 return ShowAndActivateOrMinimize(panel); | |
| 199 } else { | |
| 200 return ShowAndActivateOrMinimize(panel); | |
| 201 } | |
| 202 } else { | 131 } else { |
| 203 AppWindow* window_to_show = last_active_app_window_ | 132 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 } | 133 } |
| 216 return kNoAction; | |
| 217 } | 134 } |
| 218 | 135 |
| 219 base::string16 AppWindowLauncherItemController::GetTitle() { | 136 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(); | 137 return GetAppTitle(); |
| 231 } | 138 } |
| 232 | 139 |
| 233 ash::ShelfMenuModel* AppWindowLauncherItemController::CreateApplicationMenu( | 140 ash::ShelfMenuModel* AppWindowLauncherItemController::CreateApplicationMenu( |
| 234 int event_flags) { | 141 int event_flags) { |
| 235 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); | 142 return nullptr; |
|
xiyuan
2016/03/23 23:22:52
ArcAppWindowLauncherItemController does not overid
khmel
2016/03/24 16:30:37
For better reading it is better remove it here.
| |
| 236 } | 143 } |
| 237 | 144 |
| 238 bool AppWindowLauncherItemController::IsDraggable() { | 145 bool AppWindowLauncherItemController::IsDraggable() { |
| 239 if (type() == TYPE_APP_PANEL) | 146 DCHECK(type() == TYPE_APP); |
|
xiyuan
2016/03/23 23:22:53
nit: DCHECK_EQ(TYPE_APP, type());
khmel
2016/03/24 16:30:37
Done.
| |
| 240 return true; | |
| 241 return CanPin(); | 147 return CanPin(); |
| 242 } | 148 } |
| 243 | 149 |
| 244 bool AppWindowLauncherItemController::CanPin() const { | 150 bool AppWindowLauncherItemController::CanPin() const { |
| 245 return launcher_controller()->CanPin(app_id()); | 151 return launcher_controller()->CanPin(app_id()); |
| 246 } | 152 } |
| 247 | 153 |
| 248 bool AppWindowLauncherItemController::ShouldShowTooltip() { | 154 bool AppWindowLauncherItemController::ShouldShowTooltip() { |
| 249 if (type() == TYPE_APP_PANEL && IsVisible()) | 155 DCHECK(type() == TYPE_APP); |
|
xiyuan
2016/03/23 23:22:53
nit: DCHECK_EQ(TYPE_APP, type());
khmel
2016/03/24 16:30:37
Done.
| |
| 250 return false; | |
| 251 return true; | 156 return true; |
| 252 } | 157 } |
| 253 | 158 |
| 254 void AppWindowLauncherItemController::OnWindowPropertyChanged( | 159 void AppWindowLauncherItemController::OnWindowPropertyChanged( |
| 255 aura::Window* window, | 160 aura::Window* window, |
| 256 const void* key, | 161 const void* key, |
| 257 intptr_t old) { | 162 intptr_t old) { |
| 258 if (key == aura::client::kDrawAttentionKey) { | 163 if (key == aura::client::kDrawAttentionKey) { |
| 259 ash::ShelfItemStatus status; | 164 ash::ShelfItemStatus status; |
| 260 if (ash::wm::IsActiveWindow(window)) { | 165 if (ash::wm::IsActiveWindow(window)) { |
| 261 status = ash::STATUS_ACTIVE; | 166 status = ash::STATUS_ACTIVE; |
| 262 } else if (window->GetProperty(aura::client::kDrawAttentionKey)) { | 167 } else if (window->GetProperty(aura::client::kDrawAttentionKey)) { |
| 263 status = ash::STATUS_ATTENTION; | 168 status = ash::STATUS_ATTENTION; |
| 264 } else { | 169 } else { |
| 265 status = ash::STATUS_RUNNING; | 170 status = ash::STATUS_RUNNING; |
| 266 } | 171 } |
| 267 launcher_controller()->SetItemStatus(shelf_id(), status); | 172 launcher_controller()->SetItemStatus(shelf_id(), status); |
| 268 } | 173 } |
| 269 } | 174 } |
| 270 | 175 |
| 271 ash::ShelfItemDelegate::PerformedAction | 176 ash::ShelfItemDelegate::PerformedAction |
| 272 AppWindowLauncherItemController::ShowAndActivateOrMinimize( | 177 AppWindowLauncherItemController::ShowAndActivateOrMinimize( |
| 273 AppWindow* app_window) { | 178 ui::BaseWindow* app_window) { |
| 274 // Either show or minimize windows when shown from the launcher. | 179 // Either show or minimize windows when shown from the launcher. |
| 275 return launcher_controller()->ActivateWindowOrMinimizeIfActive( | 180 return launcher_controller()->ActivateWindowOrMinimizeIfActive( |
| 276 app_window->GetBaseWindow(), GetApplicationList(0).size() == 2); | 181 app_window, GetApplicationList(0).size() == 2); |
| 277 } | 182 } |
| 278 | 183 |
| 279 ash::ShelfItemDelegate::PerformedAction | 184 ash::ShelfItemDelegate::PerformedAction |
| 280 AppWindowLauncherItemController::ActivateOrAdvanceToNextAppWindow( | 185 AppWindowLauncherItemController::ActivateOrAdvanceToNextAppWindow( |
| 281 AppWindow* window_to_show) { | 186 ui::BaseWindow* window_to_show) { |
| 282 AppWindowList::iterator i( | 187 WindowList::iterator i( |
| 283 std::find(app_windows_.begin(), app_windows_.end(), window_to_show)); | 188 std::find(windows_.begin(), windows_.end(), window_to_show)); |
| 284 if (i != app_windows_.end()) { | 189 if (i != windows_.end()) { |
| 285 if (++i != app_windows_.end()) | 190 if (++i != windows_.end()) |
| 286 window_to_show = *i; | 191 window_to_show = *i; |
| 287 else | 192 else |
| 288 window_to_show = app_windows_.front(); | 193 window_to_show = windows_.front(); |
| 289 } | 194 } |
| 290 if (window_to_show->GetBaseWindow()->IsActive()) { | 195 if (window_to_show->IsActive()) { |
| 291 // Coming here, only a single window is active. For keyboard activations | 196 // Coming here, only a single window is active. For keyboard activations |
| 292 // the window gets animated. | 197 // the window gets animated. |
| 293 AnimateWindow(window_to_show->GetNativeWindow(), | 198 AnimateWindow(window_to_show->GetNativeWindow(), |
| 294 wm::WINDOW_ANIMATION_TYPE_BOUNCE); | 199 wm::WINDOW_ANIMATION_TYPE_BOUNCE); |
| 295 } else { | 200 } else { |
| 296 return ShowAndActivateOrMinimize(window_to_show); | 201 return ShowAndActivateOrMinimize(window_to_show); |
| 297 } | 202 } |
| 298 return kNoAction; | 203 return kNoAction; |
| 299 } | 204 } |
| OLD | NEW |