1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 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"
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/tabs/tab_strip_model.h"
154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/extensions/extension.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension_constants.h"
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_entry.h"
20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/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) {
352dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (old_contents == new_contents)
353dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
354dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(Value::CreateIntegerValue(
357201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetTabId(new_contents->tab_contents())));
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* object_args = new DictionaryValue();
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue(
361201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetWindowIdOfTab(new_contents->tab_contents())));
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(object_args);
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(new_contents->profile(), events::kOnTabSelectionChanged,
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                json_args);
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
371201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabMoved(TabContentsWrapper* contents,
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           int from_index,
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           int to_index) {
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
375201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  args.Append(Value::CreateIntegerValue(
376201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetTabId(contents->tab_contents())));
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* object_args = new DictionaryValue();
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue(
380201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ExtensionTabUtil::GetWindowIdOfTab(contents->tab_contents())));
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kFromIndexKey, Value::CreateIntegerValue(
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      from_index));
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  object_args->Set(tab_keys::kToIndexKey, Value::CreateIntegerValue(
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      to_index));
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(object_args);
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchEvent(contents->profile(), events::kOnTabMoved, json_args);
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::TabUpdated(TabContents* contents,
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             bool did_navigate) {
395513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TabEntry* entry = GetTabEntry(contents);
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* changed_properties = NULL;
397513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
398513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(entry);
399513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (did_navigate)
401513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    changed_properties = entry->DidNavigate(contents);
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
403513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    changed_properties = entry->UpdateLoadState(contents);
404513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
405513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (changed_properties)
406513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DispatchTabUpdatedEvent(contents, changed_properties);
407513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
409513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ExtensionBrowserEventRouter::DispatchTabUpdatedEvent(
410513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    TabContents* contents, DictionaryValue* changed_properties) {
411513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(changed_properties);
412513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(contents);
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // The state of the tab (as seen from the extension point of view) has
415513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // changed.  Send a notification to the extension.
416513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ListValue args;
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
418513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // First arg: The id of the tab that changed.
419513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  args.Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents)));
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Second arg: An object containing the changes to the tab state.
422513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  args.Append(changed_properties);
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
424513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Third arg: An object containing the state of the tab.
425513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  args.Append(ExtensionTabUtil::CreateTabValue(contents));
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
427513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::string json_args;
428513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::JSONWriter::Write(&args, false, &json_args);
429513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
430513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DispatchEvent(contents->profile(), events::kOnTabUpdated, json_args);
431513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
432513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
433513209b27ff55e2841eac0e4120199c23acce758Ben MurdochExtensionBrowserEventRouter::TabEntry* ExtensionBrowserEventRouter::GetTabEntry(
434513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const TabContents* contents) {
435513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int tab_id = ExtensionTabUtil::GetTabId(contents);
436513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::map<int, TabEntry>::iterator i = tab_entries_.find(tab_id);
437513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (tab_entries_.end() == i)
438513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return NULL;
439513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return &i->second;
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::Observe(NotificationType type,
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const NotificationSource& source,
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const NotificationDetails& details) {
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type == NotificationType::NAV_ENTRY_COMMITTED) {
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NavigationController* source_controller =
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Source<NavigationController>(source).ptr();
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabUpdated(source_controller->tab_contents(), true);
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Tab was destroyed after being detached (without being re-attached).
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabContents* contents = Source<TabContents>(source).ptr();
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Source<NavigationController>(&contents->controller()));
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Source<TabContents>(contents));
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type == NotificationType::BROWSER_WINDOW_READY) {
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const Browser* browser = Source<const Browser>(source).ptr();
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnBrowserWindowReady(browser);
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type == NotificationType::NO_KEY_WINDOW) {
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnBrowserSetLastActive(NULL);
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
468201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabChangedAt(TabContentsWrapper* contents,
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               int index,
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               TabChangeType change_type) {
471201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabUpdated(contents->tab_contents(), false);
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
474201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabReplacedAt(
47572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    TabStripModel* tab_strip_model,
476201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* old_contents,
477201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* new_contents,
478201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int index) {
47972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  TabClosingAt(tab_strip_model, old_contents, index);
480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TabInsertedAt(new_contents, index, tab_strip_model->active_index() == index);
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
483201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid ExtensionBrowserEventRouter::TabPinnedStateChanged(
484201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TabContentsWrapper* contents,
485201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int index) {
486513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TabStripModel* tab_strip = NULL;
487513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int tab_index;
488513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
489201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (ExtensionTabUtil::GetTabStripModel(
490201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        contents->tab_contents(), &tab_strip, &tab_index)) {
491513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DictionaryValue* changed_properties = new DictionaryValue();
492513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    changed_properties->SetBoolean(tab_keys::kPinnedKey,
493513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                   tab_strip->IsTabPinned(tab_index));
494201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DispatchTabUpdatedEvent(contents->tab_contents(), changed_properties);
495513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
496513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
497513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::TabStripEmpty() {}
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::DispatchOldPageActionEvent(
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile,
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& extension_id,
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& page_action_id,
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_id,
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& url,
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int button) {
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(Value::CreateStringValue(page_action_id));
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* data = new DictionaryValue();
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data->Set(tab_keys::kTabIdKey, Value::CreateIntegerValue(tab_id));
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data->Set(tab_keys::kTabUrlKey, Value::CreateStringValue(url));
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data->Set(page_action_keys::kButtonKey, Value::CreateIntegerValue(button));
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(data);
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string json_args;
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONWriter::Write(&args, false, &json_args);
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
519731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DispatchEventToExtension(profile, extension_id, "pageActions", json_args);
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::PageActionExecuted(
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile,
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& extension_id,
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& page_action_id,
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_id,
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& url,
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int button) {
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DispatchOldPageActionEvent(profile, extension_id, page_action_id, tab_id, url,
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             button);
531201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* tab_contents = NULL;
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    NULL, NULL, &tab_contents, NULL)) {
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
536731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DispatchEventWithTab(profile, extension_id, "pageAction.onClicked",
537201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                       tab_contents->tab_contents());
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionBrowserEventRouter::BrowserActionExecuted(
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile, const std::string& extension_id, Browser* browser) {
542201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* tab_contents = NULL;
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id = 0;
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ExtensionTabUtil::GetDefaultTab(browser, &tab_contents, &tab_id))
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
546731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DispatchEventWithTab(profile, extension_id, "browserAction.onClicked",
547201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                       tab_contents->tab_contents());
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
549