Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/browser_shortcut_launcher_item_controll er.h" | 5 #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controll er.h" |
| 6 | 6 |
| 7 #include <limits> | |
| 7 #include <vector> | 8 #include <vector> |
| 8 | 9 |
| 9 #include "ash/common/shelf/shelf_delegate.h" | 10 #include "ash/common/shelf/shelf_delegate.h" |
| 10 #include "ash/common/shelf/shelf_model.h" | 11 #include "ash/common/shelf/shelf_model.h" |
| 11 #include "ash/common/wm_shell.h" | 12 #include "ash/common/wm_shell.h" |
| 12 #include "ash/common/wm_window.h" | 13 #include "ash/common/wm_window.h" |
| 13 #include "ash/common/wm_window_property.h" | 14 #include "ash/common/wm_window_property.h" |
| 14 #include "ash/public/cpp/shelf_application_menu_item.h" | 15 #include "ash/public/cpp/shelf_application_menu_item.h" |
| 15 #include "ash/resources/grit/ash_resources.h" | 16 #include "ash/resources/grit/ash_resources.h" |
| 16 #include "ash/wm/window_util.h" | 17 #include "ash/wm/window_util.h" |
| 17 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
| 19 #include "chrome/browser/chrome_notification_types.h" | |
| 18 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h " | |
| 20 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h" | |
| 21 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" | 21 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" |
| 22 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" | 22 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" |
| 23 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" | 23 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" |
| 24 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" | |
| 24 #include "chrome/browser/ui/browser.h" | 25 #include "chrome/browser/ui/browser.h" |
| 25 #include "chrome/browser/ui/browser_commands.h" | 26 #include "chrome/browser/ui/browser_commands.h" |
| 26 #include "chrome/browser/ui/browser_finder.h" | 27 #include "chrome/browser/ui/browser_finder.h" |
| 27 #include "chrome/browser/ui/browser_window.h" | 28 #include "chrome/browser/ui/browser_window.h" |
| 28 #include "chrome/browser/ui/chrome_pages.h" | 29 #include "chrome/browser/ui/chrome_pages.h" |
| 29 #include "chrome/browser/ui/settings_window_manager.h" | 30 #include "chrome/browser/ui/settings_window_manager.h" |
| 30 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 31 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 31 #include "chrome/browser/web_applications/web_app.h" | 32 #include "chrome/browser/web_applications/web_app.h" |
| 32 #include "chrome/common/extensions/extension_constants.h" | 33 #include "chrome/common/extensions/extension_constants.h" |
| 33 #include "chrome/grit/chromium_strings.h" | 34 #include "chrome/grit/chromium_strings.h" |
| 34 #include "chrome/grit/generated_resources.h" | 35 #include "chrome/grit/generated_resources.h" |
| 35 #include "components/strings/grit/components_strings.h" | 36 #include "components/strings/grit/components_strings.h" |
| 37 #include "content/public/browser/notification_service.h" | |
| 36 #include "content/public/browser/web_contents.h" | 38 #include "content/public/browser/web_contents.h" |
| 37 #include "content/public/common/url_constants.h" | 39 #include "content/public/common/url_constants.h" |
| 38 #include "ui/aura/window.h" | 40 #include "ui/aura/window.h" |
| 39 #include "ui/base/l10n/l10n_util.h" | 41 #include "ui/base/l10n/l10n_util.h" |
| 40 #include "ui/base/resource/resource_bundle.h" | 42 #include "ui/base/resource/resource_bundle.h" |
| 41 #include "ui/events/event.h" | 43 #include "ui/events/event.h" |
| 44 #include "ui/events/event_constants.h" | |
| 42 #include "ui/gfx/image/image.h" | 45 #include "ui/gfx/image/image.h" |
| 43 #include "ui/wm/core/window_animations.h" | 46 #include "ui/wm/core/window_animations.h" |
| 44 | 47 |
| 45 namespace { | 48 namespace { |
| 46 | 49 |
| 50 // The maximum number of browser or tab items supported in the application menu. | |
| 51 // Also used as a tab-index flag for browser-specific commands that ignore tabs. | |
|
James Cook
2017/03/01 19:50:48
It might be nice to have a separate constant for t
msw
2017/03/02 02:59:20
Done.
| |
| 52 const uint16_t kMaxItems = std::numeric_limits<uint16_t>::max(); | |
| 53 | |
| 47 bool IsSettingsBrowser(Browser* browser) { | 54 bool IsSettingsBrowser(Browser* browser) { |
| 48 // Normally this test is sufficient. TODO(stevenjb): Replace this with a | 55 // Normally this test is sufficient. TODO(stevenjb): Replace this with a |
| 49 // better mechanism (Settings WebUI or Browser type). | 56 // better mechanism (Settings WebUI or Browser type). |
| 50 if (chrome::IsTrustedPopupWindowWithScheme(browser, content::kChromeUIScheme)) | 57 if (chrome::IsTrustedPopupWindowWithScheme(browser, content::kChromeUIScheme)) |
| 51 return true; | 58 return true; |
| 52 // If a settings window navigates away from a kChromeUIScheme (e.g. after a | 59 // If a settings window navigates away from a kChromeUIScheme (e.g. after a |
| 53 // crash), the above may not be true, so also test against the known list | 60 // crash), the above may not be true, so also test against the known list |
| 54 // of settings browsers (which will not be valid during chrome::Navigate | 61 // of settings browsers (which will not be valid during chrome::Navigate |
| 55 // which is why we still need the above test). | 62 // which is why we still need the above test). |
| 56 if (chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(browser)) | 63 if (chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(browser)) |
| 57 return true; | 64 return true; |
| 58 return false; | 65 return false; |
| 59 } | 66 } |
| 60 | 67 |
| 68 // Returns a 32-bit command id from 16-bit browser and web-contents indices. | |
| 69 uint32_t GetCommandId(uint16_t browser_index, uint16_t web_contents_index) { | |
| 70 return (browser_index << 16) | web_contents_index; | |
| 71 } | |
| 72 | |
| 73 // Get the 16-bit browser index from a 32-bit command id. | |
| 74 uint16_t GetBrowserIndex(uint32_t command_id) { | |
| 75 return base::checked_cast<uint16_t>((command_id >> 16) & 0xFFFF); | |
| 76 } | |
| 77 | |
| 78 // Get the 16-bit web-contents index from a 32-bit command id. | |
| 79 uint16_t GetWebContentsIndex(uint32_t command_id) { | |
| 80 return base::checked_cast<uint16_t>(command_id & 0xFFFF); | |
| 81 } | |
| 82 | |
| 83 // Check if the given |web_contents| is in incognito mode. | |
| 84 bool IsIncognito(content::WebContents* web_contents) { | |
| 85 const Profile* profile = | |
| 86 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | |
| 87 return profile->IsOffTheRecord() && !profile->IsGuestSession(); | |
| 88 } | |
| 89 | |
| 90 // Get the favicon for the browser list entry for |web_contents|. | |
| 91 // Note that for incognito windows the incognito icon will be returned. | |
| 92 gfx::Image GetBrowserListIcon(content::WebContents* web_contents) { | |
| 93 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 94 return rb.GetImageNamed(IsIncognito(web_contents) | |
| 95 ? IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER | |
| 96 : IDR_ASH_SHELF_LIST_BROWSER); | |
| 97 } | |
| 98 | |
| 99 // Get the title for the browser list entry for |web_contents|. | |
| 100 // If |web_contents| has not loaded, returns "New Tab". | |
| 101 base::string16 GetBrowserListTitle(content::WebContents* web_contents) { | |
| 102 const base::string16& title = web_contents->GetTitle(); | |
| 103 return title.empty() ? l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE) : title; | |
| 104 } | |
| 105 | |
| 61 } // namespace | 106 } // namespace |
| 62 | 107 |
| 63 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController( | 108 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController( |
| 64 ChromeLauncherController* launcher_controller, | 109 ChromeLauncherController* launcher_controller, |
| 65 ash::ShelfModel* shelf_model) | 110 ash::ShelfModel* shelf_model) |
| 66 : LauncherItemController(extension_misc::kChromeAppId, | 111 : LauncherItemController(extension_misc::kChromeAppId, |
| 67 std::string(), | 112 std::string(), |
| 68 launcher_controller), | 113 launcher_controller), |
| 69 shelf_model_(shelf_model) {} | 114 shelf_model_(shelf_model) {} |
| 70 | 115 |
| 71 BrowserShortcutLauncherItemController:: | 116 BrowserShortcutLauncherItemController:: |
| 72 ~BrowserShortcutLauncherItemController() {} | 117 ~BrowserShortcutLauncherItemController() { |
| 118 registrar_.RemoveAll(); | |
|
James Cook
2017/03/01 19:50:48
This isn't handled automatically by the registrar'
msw
2017/03/02 02:59:20
You're right, it's automatically handled; I remove
| |
| 119 } | |
| 73 | 120 |
| 74 void BrowserShortcutLauncherItemController::UpdateBrowserItemState() { | 121 void BrowserShortcutLauncherItemController::UpdateBrowserItemState() { |
| 75 // Determine the new browser's active state and change if necessary. | 122 // Determine the new browser's active state and change if necessary. |
| 76 int browser_index = | 123 int browser_index = |
| 77 shelf_model_->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT); | 124 shelf_model_->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT); |
| 78 DCHECK_GE(browser_index, 0); | 125 DCHECK_GE(browser_index, 0); |
| 79 ash::ShelfItem browser_item = shelf_model_->items()[browser_index]; | 126 ash::ShelfItem browser_item = shelf_model_->items()[browser_index]; |
| 80 ash::ShelfItemStatus browser_status = ash::STATUS_CLOSED; | 127 ash::ShelfItemStatus browser_status = ash::STATUS_CLOSED; |
| 81 | 128 |
| 82 aura::Window* window = ash::wm::GetActiveWindow(); | 129 aura::Window* window = ash::wm::GetActiveWindow(); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 chrome::NewEmptyWindow(launcher_controller()->profile()); | 197 chrome::NewEmptyWindow(launcher_controller()->profile()); |
| 151 return ash::SHELF_ACTION_NEW_WINDOW_CREATED; | 198 return ash::SHELF_ACTION_NEW_WINDOW_CREATED; |
| 152 } | 199 } |
| 153 | 200 |
| 154 return launcher_controller()->ActivateWindowOrMinimizeIfActive( | 201 return launcher_controller()->ActivateWindowOrMinimizeIfActive( |
| 155 last_browser->window(), GetAppMenuItems(0).size() == 1); | 202 last_browser->window(), GetAppMenuItems(0).size() == 1); |
| 156 } | 203 } |
| 157 | 204 |
| 158 ash::ShelfAppMenuItemList | 205 ash::ShelfAppMenuItemList |
| 159 BrowserShortcutLauncherItemController::GetAppMenuItems(int event_flags) { | 206 BrowserShortcutLauncherItemController::GetAppMenuItems(int event_flags) { |
| 207 browser_menu_items_.clear(); | |
| 208 registrar_.RemoveAll(); | |
| 209 | |
| 160 ash::ShelfAppMenuItemList items; | 210 ash::ShelfAppMenuItemList items; |
| 161 bool found_tabbed_browser = false; | 211 bool found_tabbed_browser = false; |
| 162 for (auto* browser : GetListOfActiveBrowsers()) { | 212 for (auto* browser : GetListOfActiveBrowsers()) { |
| 213 if (browser_menu_items_.size() >= kMaxItems) | |
|
James Cook
2017/03/01 19:50:48
LOL. I'd hate to meet this power-user. :-)
msw
2017/03/02 02:59:20
Haha, yeah; I'm not sure what would break first if
| |
| 214 break; | |
| 163 TabStripModel* tab_strip = browser->tab_strip_model(); | 215 TabStripModel* tab_strip = browser->tab_strip_model(); |
| 164 if (tab_strip->active_index() == -1) | 216 const int tab_index = tab_strip->active_index(); |
| 217 if (tab_index < 0 || tab_index >= kMaxItems) | |
| 165 continue; | 218 continue; |
| 166 if (browser->is_type_tabbed()) | 219 if (browser->is_type_tabbed()) |
| 167 found_tabbed_browser = true; | 220 found_tabbed_browser = true; |
| 168 if (!(event_flags & ui::EF_SHIFT_DOWN)) { | 221 if (!(event_flags & ui::EF_SHIFT_DOWN)) { |
| 169 content::WebContents* web_contents = | 222 content::WebContents* tab = tab_strip->GetWebContentsAt(tab_index); |
|
James Cook
2017/03/01 19:50:48
I like "tab" -- briefer and clearer!
msw
2017/03/02 02:59:20
Acknowledged.
| |
| 170 tab_strip->GetWebContentsAt(tab_strip->active_index()); | 223 gfx::Image icon = GetBrowserListIcon(tab); |
| 171 gfx::Image app_icon = GetBrowserListIcon(web_contents); | 224 base::string16 title = GetBrowserListTitle(tab); |
| 172 base::string16 title = GetBrowserListTitle(web_contents); | 225 items.push_back(base::MakeUnique<ash::ShelfApplicationMenuItem>( |
| 173 items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemBrowser>( | 226 GetCommandId(browser_menu_items_.size(), kMaxItems), title, &icon)); |
| 174 title, &app_icon, browser)); | |
| 175 } else { | 227 } else { |
| 176 for (int index = 0; index < tab_strip->count(); ++index) { | 228 for (uint16_t i = 0; i < tab_strip->count() && i < kMaxItems; ++i) { |
| 177 content::WebContents* web_contents = | 229 content::WebContents* tab = tab_strip->GetWebContentsAt(i); |
| 178 tab_strip->GetWebContentsAt(index); | 230 gfx::Image icon = launcher_controller()->GetAppListIcon(tab); |
| 179 gfx::Image app_icon = | 231 base::string16 title = launcher_controller()->GetAppListTitle(tab); |
| 180 launcher_controller()->GetAppListIcon(web_contents); | 232 items.push_back(base::MakeUnique<ash::ShelfApplicationMenuItem>( |
| 181 base::string16 title = | 233 GetCommandId(browser_menu_items_.size(), i), title, &icon)); |
| 182 launcher_controller()->GetAppListTitle(web_contents); | |
| 183 items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemTab>( | |
| 184 title, &app_icon, web_contents)); | |
| 185 } | 234 } |
| 186 } | 235 } |
| 236 browser_menu_items_.push_back(browser); | |
| 237 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSING, | |
| 238 content::Source<Browser>(browser)); | |
| 187 } | 239 } |
| 188 // If only windowed applications are open, we return an empty list to | 240 // If only windowed applications are open, we return an empty list to |
| 189 // enforce the creation of a new browser. | 241 // enforce the creation of a new browser. |
| 190 if (!found_tabbed_browser) | 242 if (!found_tabbed_browser) { |
| 191 items.clear(); | 243 items.clear(); |
| 244 browser_menu_items_.clear(); | |
| 245 registrar_.RemoveAll(); | |
| 246 } | |
| 192 return items; | 247 return items; |
| 193 } | 248 } |
| 194 | 249 |
| 250 void BrowserShortcutLauncherItemController::ExecuteCommand( | |
| 251 uint32_t command_id, | |
| 252 int32_t event_flags) { | |
| 253 const uint16_t browser_index = GetBrowserIndex(command_id); | |
| 254 if (browser_index >= browser_menu_items_.size()) | |
| 255 return; | |
| 256 | |
| 257 // The indicated browser may have closed while the menu was open. | |
| 258 Browser* browser = browser_menu_items_[browser_index]; | |
| 259 if (!browser) | |
| 260 return; | |
| 261 | |
| 262 TabStripModel* tab_strip = browser->tab_strip_model(); | |
| 263 const uint16_t tab_index = GetWebContentsIndex(command_id); | |
| 264 if (event_flags & (ui::EF_SHIFT_DOWN | ui::EF_MIDDLE_MOUSE_BUTTON)) { | |
| 265 if (tab_index == kMaxItems) { | |
| 266 tab_strip->CloseAllTabs(); | |
| 267 } else if (tab_strip->ContainsIndex(tab_index)) { | |
| 268 tab_strip->CloseWebContentsAt(tab_index, | |
| 269 TabStripModel::CLOSE_USER_GESTURE); | |
| 270 } | |
| 271 } else { | |
| 272 multi_user_util::MoveWindowToCurrentDesktop( | |
| 273 browser->window()->GetNativeWindow()); | |
| 274 if (tab_index != kMaxItems && tab_strip->ContainsIndex(tab_index)) | |
| 275 tab_strip->ActivateTabAt(tab_index, false); | |
| 276 browser->window()->Show(); | |
| 277 browser->window()->Activate(); | |
| 278 } | |
| 279 } | |
|
James Cook
2017/03/01 19:50:48
Should this wipe the items and registrar?
msw
2017/03/02 02:59:20
It doesn't seem too important either way, and I'd
James Cook
2017/03/02 15:43:00
Does this controller object get deleted when the m
msw
2017/03/02 18:37:47
Done. (here and for app shortcuts' cached menu ite
| |
| 280 | |
| 195 void BrowserShortcutLauncherItemController::Close() { | 281 void BrowserShortcutLauncherItemController::Close() { |
| 196 for (auto* browser : GetListOfActiveBrowsers()) | 282 for (auto* browser : GetListOfActiveBrowsers()) |
| 197 browser->window()->Close(); | 283 browser->window()->Close(); |
| 198 } | 284 } |
| 199 | 285 |
| 200 bool BrowserShortcutLauncherItemController::IsListOfActiveBrowserEmpty() { | 286 bool BrowserShortcutLauncherItemController::IsListOfActiveBrowserEmpty() { |
| 201 return GetListOfActiveBrowsers().empty(); | 287 return GetListOfActiveBrowsers().empty(); |
| 202 } | 288 } |
| 203 | 289 |
| 204 gfx::Image BrowserShortcutLauncherItemController::GetBrowserListIcon( | |
| 205 content::WebContents* web_contents) const { | |
| 206 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 207 return rb.GetImageNamed(IsIncognito(web_contents) ? | |
| 208 IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER : | |
| 209 IDR_ASH_SHELF_LIST_BROWSER); | |
| 210 } | |
| 211 | |
| 212 base::string16 BrowserShortcutLauncherItemController::GetBrowserListTitle( | |
| 213 content::WebContents* web_contents) const { | |
| 214 base::string16 title = web_contents->GetTitle(); | |
| 215 if (!title.empty()) | |
| 216 return title; | |
| 217 return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE); | |
| 218 } | |
| 219 | |
| 220 bool BrowserShortcutLauncherItemController::IsIncognito( | |
| 221 content::WebContents* web_contents) const { | |
| 222 const Profile* profile = | |
| 223 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | |
| 224 return profile->IsOffTheRecord() && !profile->IsGuestSession(); | |
| 225 } | |
| 226 | |
| 227 ash::ShelfAction | 290 ash::ShelfAction |
| 228 BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() { | 291 BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() { |
| 229 // Create a list of all suitable running browsers. | 292 // Create a list of all suitable running browsers. |
| 230 std::vector<Browser*> items; | 293 std::vector<Browser*> items; |
| 231 // We use the list in the order of how the browsers got created - not the LRU | 294 // We use the list in the order of how the browsers got created - not the LRU |
| 232 // order. | 295 // order. |
| 233 const BrowserList* browser_list = BrowserList::GetInstance(); | 296 const BrowserList* browser_list = BrowserList::GetInstance(); |
| 234 for (BrowserList::const_iterator it = browser_list->begin(); | 297 for (BrowserList::const_iterator it = browser_list->begin(); |
| 235 it != browser_list->end(); ++it) { | 298 it != browser_list->end(); ++it) { |
| 236 if (IsBrowserRepresentedInBrowserList(*it)) | 299 if (IsBrowserRepresentedInBrowserList(*it)) |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 304 !browser->window()->IsMinimized()) { | 367 !browser->window()->IsMinimized()) { |
| 305 continue; | 368 continue; |
| 306 } | 369 } |
| 307 if (!IsBrowserRepresentedInBrowserList(browser) && | 370 if (!IsBrowserRepresentedInBrowserList(browser) && |
| 308 !browser->is_type_tabbed()) | 371 !browser->is_type_tabbed()) |
| 309 continue; | 372 continue; |
| 310 active_browsers.push_back(browser); | 373 active_browsers.push_back(browser); |
| 311 } | 374 } |
| 312 return active_browsers; | 375 return active_browsers; |
| 313 } | 376 } |
| 377 | |
| 378 void BrowserShortcutLauncherItemController::Observe( | |
| 379 int type, | |
| 380 const content::NotificationSource& source, | |
| 381 const content::NotificationDetails& details) { | |
| 382 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSING, type); | |
| 383 Browser* browser = content::Source<Browser>(source).ptr(); | |
| 384 DCHECK(browser); | |
| 385 BrowserList::BrowserVector::iterator item = std::find( | |
| 386 browser_menu_items_.begin(), browser_menu_items_.end(), browser); | |
| 387 DCHECK(item != browser_menu_items_.end()); | |
| 388 // Clear the entry for the closed browser and leave other indices intact. | |
| 389 *item = nullptr; | |
| 390 registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_CLOSING, | |
| 391 content::Source<Browser>(browser)); | |
| 392 } | |
| OLD | NEW |