| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/extensions/browser_event_router.h" | 5 #include "chrome/browser/extensions/browser_event_router.h" |
| 6 | 6 |
| 7 #include "base/json/json_writer.h" | 7 #include "base/json/json_writer.h" |
| 8 #include "base/values.h" | 8 #include "base/values.h" |
| 9 #include "chrome/browser/extensions/api/extension_action/extension_page_actions_
api_constants.h" | 9 #include "chrome/browser/extensions/api/extension_action/extension_page_actions_
api_constants.h" |
| 10 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" | 10 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" |
| 11 #include "chrome/browser/extensions/event_names.h" | 11 #include "chrome/browser/extensions/event_names.h" |
| 12 #include "chrome/browser/extensions/event_router.h" | 12 #include "chrome/browser/extensions/event_router.h" |
| 13 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
| 14 #include "chrome/browser/extensions/extension_system.h" |
| 14 #include "chrome/browser/extensions/extension_tab_util.h" | 15 #include "chrome/browser/extensions/extension_tab_util.h" |
| 15 #include "chrome/browser/extensions/window_controller.h" | 16 #include "chrome/browser/extensions/window_controller.h" |
| 17 #include "chrome/browser/extensions/window_event_router.h" |
| 16 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/browser/ui/browser.h" | 19 #include "chrome/browser/ui/browser.h" |
| 18 #include "chrome/browser/ui/browser_list.h" | 20 #include "chrome/browser/ui/browser_list.h" |
| 19 #include "chrome/browser/ui/browser_tabstrip.h" | 21 #include "chrome/browser/ui/browser_tabstrip.h" |
| 20 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 22 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
| 21 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 23 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 22 #include "chrome/common/chrome_notification_types.h" | |
| 23 #include "chrome/common/extensions/extension.h" | 24 #include "chrome/common/extensions/extension.h" |
| 24 #include "chrome/common/extensions/extension_constants.h" | 25 #include "chrome/common/extensions/extension_constants.h" |
| 25 #include "content/public/browser/navigation_controller.h" | 26 #include "content/public/browser/navigation_controller.h" |
| 26 #include "content/public/browser/notification_service.h" | 27 #include "content/public/browser/notification_service.h" |
| 28 #include "content/public/browser/notification_types.h" |
| 27 #include "content/public/browser/web_contents.h" | 29 #include "content/public/browser/web_contents.h" |
| 28 | 30 |
| 29 #if defined(TOOLKIT_GTK) | |
| 30 #include "ui/base/x/active_window_watcher_x.h" | |
| 31 #endif | |
| 32 | |
| 33 namespace events = extensions::event_names; | 31 namespace events = extensions::event_names; |
| 34 namespace tab_keys = extensions::tabs_constants; | 32 namespace tab_keys = extensions::tabs_constants; |
| 35 namespace page_action_keys = extension_page_actions_api_constants; | 33 namespace page_action_keys = extension_page_actions_api_constants; |
| 36 | 34 |
| 37 using content::NavigationController; | 35 using content::NavigationController; |
| 38 using content::WebContents; | 36 using content::WebContents; |
| 39 | 37 |
| 40 namespace extensions { | 38 namespace extensions { |
| 41 | 39 |
| 42 BrowserEventRouter::TabEntry::TabEntry() | 40 BrowserEventRouter::TabEntry::TabEntry() |
| (...skipping 30 matching lines...) Expand all Loading... |
| 73 changed_properties->SetString(tab_keys::kUrlKey, url_.spec()); | 71 changed_properties->SetString(tab_keys::kUrlKey, url_.spec()); |
| 74 } | 72 } |
| 75 | 73 |
| 76 return changed_properties; | 74 return changed_properties; |
| 77 } | 75 } |
| 78 | 76 |
| 79 void BrowserEventRouter::Init() { | 77 void BrowserEventRouter::Init() { |
| 80 if (initialized_) | 78 if (initialized_) |
| 81 return; | 79 return; |
| 82 BrowserList::AddObserver(this); | 80 BrowserList::AddObserver(this); |
| 83 #if defined(TOOLKIT_VIEWS) | |
| 84 views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); | |
| 85 #elif defined(TOOLKIT_GTK) | |
| 86 ui::ActiveWindowWatcherX::AddObserver(this); | |
| 87 #elif defined(OS_MACOSX) | |
| 88 // Needed for when no suitable window can be passed to an extension as the | |
| 89 // currently focused window. | |
| 90 registrar_.Add(this, chrome::NOTIFICATION_NO_KEY_WINDOW, | |
| 91 content::NotificationService::AllSources()); | |
| 92 #endif | |
| 93 | 81 |
| 94 // Init() can happen after the browser is running, so catch up with any | 82 // Init() can happen after the browser is running, so catch up with any |
| 95 // windows that already exist. | 83 // windows that already exist. |
| 96 for (BrowserList::const_iterator iter = BrowserList::begin(); | 84 for (BrowserList::const_iterator iter = BrowserList::begin(); |
| 97 iter != BrowserList::end(); ++iter) { | 85 iter != BrowserList::end(); ++iter) { |
| 98 RegisterForBrowserNotifications(*iter); | 86 RegisterForBrowserNotifications(*iter); |
| 99 | 87 |
| 100 // Also catch up our internal bookkeeping of tab entries. | 88 // Also catch up our internal bookkeeping of tab entries. |
| 101 Browser* browser = *iter; | 89 Browser* browser = *iter; |
| 102 if (browser->tab_strip_model()) { | 90 if (browser->tab_strip_model()) { |
| 103 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { | 91 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { |
| 104 WebContents* contents = | 92 WebContents* contents = |
| 105 chrome::GetTabContentsAt(browser, i)->web_contents(); | 93 chrome::GetTabContentsAt(browser, i)->web_contents(); |
| 106 int tab_id = ExtensionTabUtil::GetTabId(contents); | 94 int tab_id = ExtensionTabUtil::GetTabId(contents); |
| 107 tab_entries_[tab_id] = TabEntry(); | 95 tab_entries_[tab_id] = TabEntry(); |
| 108 } | 96 } |
| 109 } | 97 } |
| 110 } | 98 } |
| 111 | 99 |
| 112 initialized_ = true; | 100 initialized_ = true; |
| 113 } | 101 } |
| 114 | 102 |
| 115 BrowserEventRouter::BrowserEventRouter(Profile* profile) | 103 BrowserEventRouter::BrowserEventRouter(Profile* profile) |
| 116 : initialized_(false), | 104 : initialized_(false), |
| 117 profile_(profile), | 105 profile_(profile) { |
| 118 focused_profile_(NULL), | |
| 119 focused_window_id_(extension_misc::kUnknownWindowId) { | |
| 120 DCHECK(!profile->IsOffTheRecord()); | 106 DCHECK(!profile->IsOffTheRecord()); |
| 121 } | 107 } |
| 122 | 108 |
| 123 BrowserEventRouter::~BrowserEventRouter() { | 109 BrowserEventRouter::~BrowserEventRouter() { |
| 124 BrowserList::RemoveObserver(this); | 110 BrowserList::RemoveObserver(this); |
| 125 #if defined(TOOLKIT_VIEWS) | |
| 126 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); | |
| 127 #elif defined(TOOLKIT_GTK) | |
| 128 ui::ActiveWindowWatcherX::RemoveObserver(this); | |
| 129 #endif | |
| 130 } | 111 } |
| 131 | 112 |
| 132 void BrowserEventRouter::OnBrowserAdded(Browser* browser) { | 113 void BrowserEventRouter::OnBrowserAdded(Browser* browser) { |
| 133 RegisterForBrowserNotifications(browser); | 114 RegisterForBrowserNotifications(browser); |
| 134 } | 115 } |
| 135 | 116 |
| 136 void BrowserEventRouter::RegisterForBrowserNotifications(Browser* browser) { | 117 void BrowserEventRouter::RegisterForBrowserNotifications(Browser* browser) { |
| 137 if (!profile_->IsSameProfile(browser->profile())) | 118 if (!profile_->IsSameProfile(browser->profile())) |
| 138 return; | 119 return; |
| 139 // Start listening to TabStripModel events for this browser. | 120 // Start listening to TabStripModel events for this browser. |
| 140 browser->tab_strip_model()->AddObserver(this); | 121 browser->tab_strip_model()->AddObserver(this); |
| 141 | 122 |
| 142 // If this is a new window, it isn't ready at this point, so we register to be | |
| 143 // notified when it is. If this is an existing window, this is a no-op that we | |
| 144 // just do to reduce code complexity. | |
| 145 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY, | |
| 146 content::Source<Browser>(browser)); | |
| 147 | |
| 148 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { | 123 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { |
| 149 RegisterForTabNotifications( | 124 RegisterForTabNotifications( |
| 150 chrome::GetTabContentsAt(browser, i)->web_contents()); | 125 chrome::GetTabContentsAt(browser, i)->web_contents()); |
| 151 } | 126 } |
| 152 } | 127 } |
| 153 | 128 |
| 154 void BrowserEventRouter::RegisterForTabNotifications(WebContents* contents) { | 129 void BrowserEventRouter::RegisterForTabNotifications(WebContents* contents) { |
| 155 registrar_.Add( | 130 registrar_.Add( |
| 156 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | 131 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 157 content::Source<NavigationController>(&contents->GetController())); | 132 content::Source<NavigationController>(&contents->GetController())); |
| 158 | 133 |
| 159 // Observing NOTIFICATION_WEB_CONTENTS_DESTROYED is necessary because it's | 134 // Observing NOTIFICATION_WEB_CONTENTS_DESTROYED is necessary because it's |
| 160 // possible for tabs to be created, detached and then destroyed without | 135 // possible for tabs to be created, detached and then destroyed without |
| 161 // ever having been re-attached and closed. This happens in the case of | 136 // ever having been re-attached and closed. This happens in the case of |
| 162 // a devtools WebContents that is opened in window, docked, then closed. | 137 // a devtools WebContents that is opened in window, docked, then closed. |
| 163 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 138 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| 164 content::Source<WebContents>(contents)); | 139 content::Source<WebContents>(contents)); |
| 165 } | 140 } |
| 166 | 141 |
| 167 void BrowserEventRouter::UnregisterForTabNotifications(WebContents* contents) { | 142 void BrowserEventRouter::UnregisterForTabNotifications(WebContents* contents) { |
| 168 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | 143 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 169 content::Source<NavigationController>(&contents->GetController())); | 144 content::Source<NavigationController>(&contents->GetController())); |
| 170 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 145 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| 171 content::Source<WebContents>(contents)); | 146 content::Source<WebContents>(contents)); |
| 172 } | 147 } |
| 173 | 148 |
| 174 void BrowserEventRouter::OnBrowserWindowReady(Browser* browser) { | |
| 175 ListValue args; | |
| 176 | |
| 177 DCHECK(browser->extension_window_controller()); | |
| 178 DictionaryValue* window_dictionary = | |
| 179 browser->extension_window_controller()->CreateWindowValue(); | |
| 180 args.Append(window_dictionary); | |
| 181 | |
| 182 std::string json_args; | |
| 183 base::JSONWriter::Write(&args, &json_args); | |
| 184 | |
| 185 DispatchEvent(browser->profile(), events::kOnWindowCreated, json_args); | |
| 186 } | |
| 187 | |
| 188 void BrowserEventRouter::OnBrowserRemoved(Browser* browser) { | 149 void BrowserEventRouter::OnBrowserRemoved(Browser* browser) { |
| 189 if (!profile_->IsSameProfile(browser->profile())) | 150 if (!profile_->IsSameProfile(browser->profile())) |
| 190 return; | 151 return; |
| 191 | 152 |
| 192 // Stop listening to TabStripModel events for this browser. | 153 // Stop listening to TabStripModel events for this browser. |
| 193 browser->tab_strip_model()->RemoveObserver(this); | 154 browser->tab_strip_model()->RemoveObserver(this); |
| 194 | |
| 195 registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY, | |
| 196 content::Source<Browser>(browser)); | |
| 197 | |
| 198 DispatchSimpleBrowserEvent(browser->profile(), | |
| 199 ExtensionTabUtil::GetWindowId(browser), | |
| 200 events::kOnWindowRemoved); | |
| 201 } | 155 } |
| 202 | 156 |
| 203 #if defined(TOOLKIT_VIEWS) | |
| 204 void BrowserEventRouter::OnNativeFocusChange(gfx::NativeView focused_before, | |
| 205 gfx::NativeView focused_now) { | |
| 206 if (!focused_now) | |
| 207 OnBrowserSetLastActive(NULL); | |
| 208 } | |
| 209 #elif defined(TOOLKIT_GTK) | |
| 210 void BrowserEventRouter::ActiveWindowChanged(GdkWindow* active_window) { | |
| 211 if (!active_window) | |
| 212 OnBrowserSetLastActive(NULL); | |
| 213 } | |
| 214 #endif | |
| 215 | |
| 216 void BrowserEventRouter::OnBrowserSetLastActive(Browser* browser) { | 157 void BrowserEventRouter::OnBrowserSetLastActive(Browser* browser) { |
| 217 Profile* window_profile = NULL; | 158 ExtensionService* service = |
| 218 int window_id = extension_misc::kUnknownWindowId; | 159 extensions::ExtensionSystem::Get(profile_)->extension_service(); |
| 219 if (browser && profile_->IsSameProfile(browser->profile())) { | 160 if (service) { |
| 220 window_profile = browser->profile(); | 161 service->window_event_router()->OnActiveWindowChanged( |
| 221 window_id = ExtensionTabUtil::GetWindowId(browser); | 162 browser ? browser->extension_window_controller() : NULL); |
| 222 } | 163 } |
| 223 | |
| 224 if (focused_window_id_ == window_id) | |
| 225 return; | |
| 226 | |
| 227 // window_profile is either this profile's default profile, its | |
| 228 // incognito profile, or NULL iff this profile is losing focus. | |
| 229 Profile* previous_focused_profile = focused_profile_; | |
| 230 focused_profile_ = window_profile; | |
| 231 focused_window_id_ = window_id; | |
| 232 | |
| 233 ListValue real_args; | |
| 234 real_args.Append(Value::CreateIntegerValue(window_id)); | |
| 235 std::string real_json_args; | |
| 236 base::JSONWriter::Write(&real_args, &real_json_args); | |
| 237 | |
| 238 // When switching between windows in the default and incognitoi profiles, | |
| 239 // dispatch WINDOW_ID_NONE to extensions whose profile lost focus that | |
| 240 // can't see the new focused window across the incognito boundary. | |
| 241 // See crbug.com/46610. | |
| 242 std::string none_json_args; | |
| 243 if (focused_profile_ != NULL && previous_focused_profile != NULL && | |
| 244 focused_profile_ != previous_focused_profile) { | |
| 245 ListValue none_args; | |
| 246 none_args.Append( | |
| 247 Value::CreateIntegerValue(extension_misc::kUnknownWindowId)); | |
| 248 base::JSONWriter::Write(&none_args, &none_json_args); | |
| 249 } | |
| 250 | |
| 251 DispatchEventsAcrossIncognito((focused_profile_ ? focused_profile_ : | |
| 252 previous_focused_profile), | |
| 253 events::kOnWindowFocusedChanged, | |
| 254 real_json_args, | |
| 255 none_json_args); | |
| 256 } | 164 } |
| 257 | 165 |
| 258 void BrowserEventRouter::TabCreatedAt(WebContents* contents, | 166 void BrowserEventRouter::TabCreatedAt(WebContents* contents, |
| 259 int index, | 167 int index, |
| 260 bool active) { | 168 bool active) { |
| 261 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); | 169 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); |
| 262 DispatchEventWithTab(profile, "", events::kOnTabCreated, contents, active); | 170 DispatchEventWithTab(profile, "", events::kOnTabCreated, contents, active); |
| 263 | 171 |
| 264 RegisterForTabNotifications(contents); | 172 RegisterForTabNotifications(contents); |
| 265 } | 173 } |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 NavigationController* source_controller = | 457 NavigationController* source_controller = |
| 550 content::Source<NavigationController>(source).ptr(); | 458 content::Source<NavigationController>(source).ptr(); |
| 551 TabUpdated(source_controller->GetWebContents(), true); | 459 TabUpdated(source_controller->GetWebContents(), true); |
| 552 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { | 460 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { |
| 553 // Tab was destroyed after being detached (without being re-attached). | 461 // Tab was destroyed after being detached (without being re-attached). |
| 554 WebContents* contents = content::Source<WebContents>(source).ptr(); | 462 WebContents* contents = content::Source<WebContents>(source).ptr(); |
| 555 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | 463 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 556 content::Source<NavigationController>(&contents->GetController())); | 464 content::Source<NavigationController>(&contents->GetController())); |
| 557 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 465 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| 558 content::Source<WebContents>(contents)); | 466 content::Source<WebContents>(contents)); |
| 559 } else if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) { | |
| 560 Browser* browser = content::Source<Browser>(source).ptr(); | |
| 561 OnBrowserWindowReady(browser); | |
| 562 #if defined(OS_MACOSX) | |
| 563 } else if (type == chrome::NOTIFICATION_NO_KEY_WINDOW) { | |
| 564 OnBrowserSetLastActive(NULL); | |
| 565 #endif | |
| 566 } else { | 467 } else { |
| 567 NOTREACHED(); | 468 NOTREACHED(); |
| 568 } | 469 } |
| 569 } | 470 } |
| 570 | 471 |
| 571 void BrowserEventRouter::TabChangedAt(TabContents* contents, | 472 void BrowserEventRouter::TabChangedAt(TabContents* contents, |
| 572 int index, | 473 int index, |
| 573 TabChangeType change_type) { | 474 TabChangeType change_type) { |
| 574 TabUpdated(contents->web_contents(), false); | 475 TabUpdated(contents->web_contents(), false); |
| 575 } | 476 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 if (event_name) { | 593 if (event_name) { |
| 693 DispatchEventWithTab(profile, | 594 DispatchEventWithTab(profile, |
| 694 extension_action.extension_id(), | 595 extension_action.extension_id(), |
| 695 event_name, | 596 event_name, |
| 696 tab_contents->web_contents(), | 597 tab_contents->web_contents(), |
| 697 true); | 598 true); |
| 698 } | 599 } |
| 699 } | 600 } |
| 700 | 601 |
| 701 } // namespace extensions | 602 } // namespace extensions |
| OLD | NEW |