extension_browser_event_router.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_browser_event_router.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/json/json_writer.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_event_names.h"
10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/extensions/extension_event_router.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_page_actions_module_constants.h"
124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/extensions/extension_tabs_module_constants.h"
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/navigation_entry.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents.h"
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/tabs/tab_strip_model.h"
174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_constants.h"
204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/extensions/extension.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_service.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace events = extension_event_names;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace tab_keys = extension_tabs_module_constants;
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace page_action_keys = extension_page_actions_module_constants;
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionBrowserEventRouter::TabEntry::TabEntry()
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : complete_waiting_on_load_(false),
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_() {
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDictionaryValue* ExtensionBrowserEventRouter::TabEntry::UpdateLoadState(
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TabContents* contents) {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tab may go in & out of loading (for instance if iframes navigate).
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We only want to respond to the first change from loading to !loading after
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the NAV_ENTRY_COMMITTED was fired.
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!complete_waiting_on_load_ || contents->is_loading())
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Send "complete" state change.
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  complete_waiting_on_load_ = false;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* changed_properties = new DictionaryValue();
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  changed_properties->SetString(tab_keys::kStatusKey,
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_keys::kStatusValueComplete);
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return changed_properties;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDictionaryValue* ExtensionBrowserEventRouter::TabEntry::DidNavigate(
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TabContents* contents) {
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Send "loading" state change.
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  complete_waiting_on_load_ = true;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* changed_properties = new DictionaryValue();
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  changed_properties->SetString(tab_keys::kStatusKey,
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_keys::kStatusValueLoading);
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (contents->GetURL() != url_) {
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_ = contents->GetURL();
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    changed_properties->SetString(tab_keys::kUrlKey, url_.spec());
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return changed_properties;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void DispatchEvent(Profile* profile,
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const char* event_name,
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          const std::string& json_args) {
67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (profile->GetExtensionEventRouter()) {
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    profile->GetExtensionEventRouter()->DispatchEventToRenderers(
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        event_name, json_args, profile, GURL());
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstatic void DispatchEventToExtension(Profile* profile,
74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     const std::string& extension_id,
75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     const char* event_name,
76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     const std::string& json_args) {
77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (profile->GetExtensionEventRouter()) {
78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    profile->GetExtensionEventRouter()->DispatchEventToExtension(
79731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        extension_id, event_name, json_args, profile, GURL());
80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void DispatchEventWithTab(Profile* profile,
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                 const std::string& extension_id,
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const char* event_name,
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const TabContents* tab_contents) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(ExtensionTabUtil::CreateTabValue(tab_contents));
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!extension_id.empty()) {
92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DispatchEventToExtension(profile, extension_id, event_name, json_args);
93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DispatchEvent(profile, event_name, json_args);
95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void DispatchSimpleBrowserEvent(Profile* profile,
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const int window_id,
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const char* event_name) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(Value::CreateIntegerValue(window_id));
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(profile, event_name, json_args);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionBrowserEventRouter::Init() {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (initialized_)
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserList::AddObserver(this);
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_VIEWS)
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(TOOLKIT_GTK)
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ui::ActiveWindowWatcherX::AddObserver(this);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_MACOSX)
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Needed for when no suitable window can be passed to an extension as the
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // currently focused window.
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::NO_KEY_WINDOW,
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Init() can happen after the browser is running, so catch up with any
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windows that already exist.
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator iter = BrowserList::begin();
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != BrowserList::end(); ++iter) {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RegisterForBrowserNotifications(*iter);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Also catch up our internal bookkeeping of tab entries.
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser* browser = *iter;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (browser->tabstrip_model()) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (int i = 0; i < browser->tabstrip_model()->count(); ++i) {
135201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        TabContents* contents = browser->GetTabContentsAt(i);
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        int tab_id = ExtensionTabUtil::GetTabId(contents);
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab_entries_[tab_id] = TabEntry();
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  initialized_ = true;
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionBrowserEventRouter::ExtensionBrowserEventRouter(Profile* profile)
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : initialized_(false),
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      focused_window_id_(extension_misc::kUnknownWindowId),
14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      profile_(profile) {
14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(!profile->IsOffTheRecord());
15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionBrowserEventRouter::~ExtensionBrowserEventRouter() {
15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  BrowserList::RemoveObserver(this);
15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(TOOLKIT_VIEWS)
15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  views::FocusManager::GetWidgetFocusManager()->RemoveFocusChangeListener(this);
15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#elif defined(TOOLKIT_GTK)
15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ui::ActiveWindowWatcherX::RemoveObserver(this);
15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif
15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::OnBrowserAdded(const Browser* browser) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RegisterForBrowserNotifications(browser);
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::RegisterForBrowserNotifications(
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const Browser* browser) {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start listening to TabStripModel events for this browser.
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser->tabstrip_model()->AddObserver(this);
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If this is a new window, it isn't ready at this point, so we register to be
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // notified when it is. If this is an existing window, this is a no-op that we
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // just do to reduce code complexity.
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::BROWSER_WINDOW_READY,
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Source<const Browser>(browser));
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (browser->tabstrip_model()) {
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < browser->tabstrip_model()->count(); ++i)
178201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      RegisterForTabNotifications(browser->GetTabContentsAt(i));
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::RegisterForTabNotifications(
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabContents* contents) {
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 Source<NavigationController>(&contents->controller()));
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Observing TAB_CONTENTS_DESTROYED is necessary because it's
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // possible for tabs to be created, detached and then destroyed without
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ever having been re-attached and closed. This happens in the case of
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a devtools TabContents that is opened in window, docked, then closed.
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 Source<TabContents>(contents));
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ExtensionBrowserEventRouter::UnregisterForTabNotifications(
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    TabContents* contents) {
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Source<NavigationController>(&contents->controller()));
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Source<TabContents>(contents));
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::OnBrowserWindowReady(const Browser* browser) {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* window_dictionary = ExtensionTabUtil::CreateWindowValue(
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser, false);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(window_dictionary);
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(browser->profile(), events::kOnWindowCreated, json_args);
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ExtensionBrowserEventRouter::OnBrowserRemoved(const Browser* browser) {
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Stop listening to TabStripModel events for this browser.
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser->tabstrip_model()->RemoveObserver(this);
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Remove(this, NotificationType::BROWSER_WINDOW_READY,
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Source<const Browser>(browser));
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchSimpleBrowserEvent(browser->profile(),
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             ExtensionTabUtil::GetWindowId(browser),
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             events::kOnWindowRemoved);
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_VIEWS)
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::NativeFocusWillChange(
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::NativeView focused_before,
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::NativeView focused_now) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!focused_now)
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnBrowserSetLastActive(NULL);
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(TOOLKIT_GTK)
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::ActiveWindowChanged(
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GdkWindow* active_window) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!active_window)
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnBrowserSetLastActive(NULL);
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::OnBrowserSetLastActive(
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const Browser* browser) {
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = extension_misc::kUnknownWindowId;
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (browser)
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    window_id = ExtensionTabUtil::GetWindowId(browser);
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (focused_window_id_ == window_id)
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  focused_window_id_ = window_id;
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Note: because we use the default profile when |browser| is NULL, it means
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that all extensions hear about the event regardless of whether the browser
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that lost focus was OTR or if the extension is OTR-enabled.
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See crbug.com/46610.
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchSimpleBrowserEvent(browser ? browser->profile() : profile_,
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             focused_window_id_,
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             events::kOnWindowFocusedChanged);
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::TabCreatedAt(TabContents* contents,
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               int index,
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               bool foreground) {
265731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DispatchEventWithTab(contents->profile(), "", events::kOnTabCreated,
266731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       contents);
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RegisterForTabNotifications(contents);
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabInsertedAt(TabContentsWrapper* contents,
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                int index,
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                bool foreground) {
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If tab is new, send created event.
275201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int tab_id = ExtensionTabUtil::GetTabId(contents->tab_contents());
276201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!GetTabEntry(contents->tab_contents())) {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_entries_[tab_id] = TabEntry();
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
279201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabCreatedAt(contents->tab_contents(), index, foreground);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(Value::CreateIntegerValue(tab_id));
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* object_args = new DictionaryValue();
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kNewWindowIdKey, Value::CreateIntegerValue(
288201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetWindowIdOfTab(contents->tab_contents())));
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kNewPositionKey, Value::CreateIntegerValue(
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      index));
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(object_args);
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(contents->profile(), events::kOnTabAttached, json_args);
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
299201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabDetachedAt(TabContentsWrapper* contents,
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                int index) {
301201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!GetTabEntry(contents->tab_contents())) {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The tab was removed. Don't send detach event.
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
307201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  args.Append(Value::CreateIntegerValue(
308201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetTabId(contents->tab_contents())));
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* object_args = new DictionaryValue();
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kOldWindowIdKey, Value::CreateIntegerValue(
312201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetWindowIdOfTab(contents->tab_contents())));
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kOldPositionKey, Value::CreateIntegerValue(
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      index));
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(object_args);
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(contents->profile(), events::kOnTabDetached, json_args);
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
323731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ExtensionBrowserEventRouter::TabClosingAt(TabStripModel* tab_strip_model,
324201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                               TabContentsWrapper* contents,
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               int index) {
326201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int tab_id = ExtensionTabUtil::GetTabId(contents->tab_contents());
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(Value::CreateIntegerValue(tab_id));
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
331731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DictionaryValue* object_args = new DictionaryValue();
332731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  object_args->SetBoolean(tab_keys::kWindowClosing,
333731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          tab_strip_model->closing_all());
334731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  args.Append(object_args);
335731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(contents->profile(), events::kOnTabRemoved, json_args);
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int removed_count = tab_entries_.erase(tab_id);
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(removed_count, 0);
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
344201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  UnregisterForTabNotifications(contents->tab_contents());
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
347201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabSelectedAt(
348201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* old_contents,
349201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* new_contents,
350201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int index,
351201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    bool user_gesture) {
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(Value::CreateIntegerValue(
354201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetTabId(new_contents->tab_contents())));
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* object_args = new DictionaryValue();
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue(
358201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetWindowIdOfTab(new_contents->tab_contents())));
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(object_args);
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(new_contents->profile(), events::kOnTabSelectionChanged,
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                json_args);
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
368201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabMoved(TabContentsWrapper* contents,
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           int from_index,
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           int to_index) {
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
372201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  args.Append(Value::CreateIntegerValue(
373201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetTabId(contents->tab_contents())));
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* object_args = new DictionaryValue();
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue(
377201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetWindowIdOfTab(contents->tab_contents())));
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kFromIndexKey, Value::CreateIntegerValue(
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      from_index));
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kToIndexKey, Value::CreateIntegerValue(
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      to_index));
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(object_args);
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(contents->profile(), events::kOnTabMoved, json_args);
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::TabUpdated(TabContents* contents,
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             bool did_navigate) {
392513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TabEntry* entry = GetTabEntry(contents);
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* changed_properties = NULL;
394513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
395513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(entry);
396513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (did_navigate)
398513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    changed_properties = entry->DidNavigate(contents);
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
400513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    changed_properties = entry->UpdateLoadState(contents);
401513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
402513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (changed_properties)
403513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DispatchTabUpdatedEvent(contents, changed_properties);
404513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
406513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ExtensionBrowserEventRouter::DispatchTabUpdatedEvent(
407513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    TabContents* contents, DictionaryValue* changed_properties) {
408513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(changed_properties);
409513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(contents);
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
411513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // The state of the tab (as seen from the extension point of view) has
412513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // changed.  Send a notification to the extension.
413513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ListValue args;
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
415513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // First arg: The id of the tab that changed.
416513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  args.Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents)));
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
418513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Second arg: An object containing the changes to the tab state.
419513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  args.Append(changed_properties);
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Third arg: An object containing the state of the tab.
422513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  args.Append(ExtensionTabUtil::CreateTabValue(contents));
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
424513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::string json_args;
425513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::JSONWriter::Write(&args, false, &json_args);
426513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
427513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DispatchEvent(contents->profile(), events::kOnTabUpdated, json_args);
428513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
429513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
430513209b27ff55e2841eac0e4120199c23acce758Ben MurdochExtensionBrowserEventRouter::TabEntry* ExtensionBrowserEventRouter::GetTabEntry(
431513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const TabContents* contents) {
432513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int tab_id = ExtensionTabUtil::GetTabId(contents);
433513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::map<int, TabEntry>::iterator i = tab_entries_.find(tab_id);
434513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (tab_entries_.end() == i)
435513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return NULL;
436513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return &i->second;
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::Observe(NotificationType type,
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const NotificationSource& source,
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const NotificationDetails& details) {
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type == NotificationType::NAV_ENTRY_COMMITTED) {
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NavigationController* source_controller =
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Source<NavigationController>(source).ptr();
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabUpdated(source_controller->tab_contents(), true);
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Tab was destroyed after being detached (without being re-attached).
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabContents* contents = Source<TabContents>(source).ptr();
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Source<NavigationController>(&contents->controller()));
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Source<TabContents>(contents));
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type == NotificationType::BROWSER_WINDOW_READY) {
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const Browser* browser = Source<const Browser>(source).ptr();
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnBrowserWindowReady(browser);
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type == NotificationType::NO_KEY_WINDOW) {
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnBrowserSetLastActive(NULL);
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
465201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabChangedAt(TabContentsWrapper* contents,
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               int index,
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               TabChangeType change_type) {
468201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabUpdated(contents->tab_contents(), false);
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
471201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabReplacedAt(
47272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    TabStripModel* tab_strip_model,
473201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* old_contents,
474201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* new_contents,
475201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int index) {
47672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  TabClosingAt(tab_strip_model, old_contents, index);
47772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  TabInsertedAt(new_contents, index,
47872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                tab_strip_model->selected_index() == index);
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
481201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabPinnedStateChanged(
482201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* contents,
483201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int index) {
484513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TabStripModel* tab_strip = NULL;
485513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int tab_index;
486513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
487201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (ExtensionTabUtil::GetTabStripModel(
488201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        contents->tab_contents(), &tab_strip, &tab_index)) {
489513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DictionaryValue* changed_properties = new DictionaryValue();
490513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    changed_properties->SetBoolean(tab_keys::kPinnedKey,
491513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                   tab_strip->IsTabPinned(tab_index));
492201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DispatchTabUpdatedEvent(contents->tab_contents(), changed_properties);
493513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
494513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
495513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::TabStripEmpty() {}
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::DispatchOldPageActionEvent(
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile,
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& extension_id,
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& page_action_id,
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_id,
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& url,
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int button) {
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(Value::CreateStringValue(page_action_id));
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* data = new DictionaryValue();
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data->Set(tab_keys::kTabIdKey, Value::CreateIntegerValue(tab_id));
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data->Set(tab_keys::kTabUrlKey, Value::CreateStringValue(url));
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data->Set(page_action_keys::kButtonKey, Value::CreateIntegerValue(button));
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(data);
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
517731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DispatchEventToExtension(profile, extension_id, "pageActions", json_args);
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::PageActionExecuted(
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile,
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& extension_id,
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& page_action_id,
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_id,
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& url,
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int button) {
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchOldPageActionEvent(profile, extension_id, page_action_id, tab_id, url,
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             button);
529201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* tab_contents = NULL;
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    NULL, NULL, &tab_contents, NULL)) {
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
534731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DispatchEventWithTab(profile, extension_id, "pageAction.onClicked",
535201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                       tab_contents->tab_contents());
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::BrowserActionExecuted(
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile, const std::string& extension_id, Browser* browser) {
540201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* tab_contents = NULL;
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id = 0;
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ExtensionTabUtil::GetDefaultTab(browser, &tab_contents, &tab_id))
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
544731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DispatchEventWithTab(profile, extension_id, "browserAction.onClicked",
545201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                       tab_contents->tab_contents());
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
547