1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_ 6 #define CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_ 7 8 #include <map> 9 #include <string> 10 11 #include "base/basictypes.h" 12 #include "base/compiler_specific.h" 13 #include "chrome/browser/extensions/api/tabs/tabs_api.h" 14 #include "chrome/browser/ui/browser_list_observer.h" 15 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" 16 #include "chrome/browser/ui/zoom/zoom_observer.h" 17 #include "content/public/browser/notification_registrar.h" 18 #include "extensions/browser/event_router.h" 19 20 namespace content { 21 class WebContents; 22 } 23 24 namespace extensions { 25 26 // The TabsEventRouter listens to tab events and routes them to listeners inside 27 // extension process renderers. 28 // TabsEventRouter will only route events from windows/tabs within a profile to 29 // extension processes in the same profile. 30 class TabsEventRouter : public TabStripModelObserver, 31 public chrome::BrowserListObserver, 32 public content::NotificationObserver, 33 public ZoomObserver { 34 public: 35 explicit TabsEventRouter(Profile* profile); 36 virtual ~TabsEventRouter(); 37 38 // chrome::BrowserListObserver 39 virtual void OnBrowserAdded(Browser* browser) OVERRIDE; 40 virtual void OnBrowserRemoved(Browser* browser) OVERRIDE; 41 virtual void OnBrowserSetLastActive(Browser* browser) OVERRIDE; 42 43 // TabStripModelObserver 44 virtual void TabInsertedAt(content::WebContents* contents, int index, 45 bool active) OVERRIDE; 46 virtual void TabClosingAt(TabStripModel* tab_strip_model, 47 content::WebContents* contents, 48 int index) OVERRIDE; 49 virtual void TabDetachedAt(content::WebContents* contents, 50 int index) OVERRIDE; 51 virtual void ActiveTabChanged(content::WebContents* old_contents, 52 content::WebContents* new_contents, 53 int index, 54 int reason) OVERRIDE; 55 virtual void TabSelectionChanged( 56 TabStripModel* tab_strip_model, 57 const ui::ListSelectionModel& old_model) OVERRIDE; 58 virtual void TabMoved(content::WebContents* contents, 59 int from_index, 60 int to_index) OVERRIDE; 61 virtual void TabChangedAt(content::WebContents* contents, 62 int index, 63 TabChangeType change_type) OVERRIDE; 64 virtual void TabReplacedAt(TabStripModel* tab_strip_model, 65 content::WebContents* old_contents, 66 content::WebContents* new_contents, 67 int index) OVERRIDE; 68 virtual void TabPinnedStateChanged(content::WebContents* contents, 69 int index) OVERRIDE; 70 71 // content::NotificationObserver. 72 virtual void Observe(int type, 73 const content::NotificationSource& source, 74 const content::NotificationDetails& details) OVERRIDE; 75 76 // ZoomObserver. 77 virtual void OnZoomChanged( 78 const ZoomController::ZoomChangedEventData& data) OVERRIDE; 79 80 private: 81 // "Synthetic" event. Called from TabInsertedAt if new tab is detected. 82 void TabCreatedAt(content::WebContents* contents, int index, bool active); 83 84 // Internal processing of tab updated events. Is called by both TabChangedAt 85 // and Observe/NAV_ENTRY_COMMITTED. 86 void TabUpdated(content::WebContents* contents, bool did_navigate); 87 88 // Triggers a tab updated event if the favicon URL changes. 89 void FaviconUrlUpdated(content::WebContents* contents); 90 91 // The DispatchEvent methods forward events to the |profile|'s event router. 92 // The TabsEventRouter listens to events for all profiles, 93 // so we avoid duplication by dropping events destined for other profiles. 94 void DispatchEvent(Profile* profile, 95 const std::string& event_name, 96 scoped_ptr<base::ListValue> args, 97 EventRouter::UserGestureState user_gesture); 98 99 void DispatchEventsAcrossIncognito( 100 Profile* profile, 101 const std::string& event_name, 102 scoped_ptr<base::ListValue> event_args, 103 scoped_ptr<base::ListValue> cross_incognito_args); 104 105 void DispatchSimpleBrowserEvent(Profile* profile, 106 const int window_id, 107 const std::string& event_name); 108 109 // Packages |changed_properties| as a tab updated event for the tab |contents| 110 // and dispatches the event to the extension. 111 void DispatchTabUpdatedEvent( 112 content::WebContents* contents, 113 scoped_ptr<base::DictionaryValue> changed_properties); 114 115 // Register ourselves to receive the various notifications we are interested 116 // in for a browser. 117 void RegisterForBrowserNotifications(Browser* browser); 118 119 // Register ourselves to receive the various notifications we are interested 120 // in for a tab. 121 void RegisterForTabNotifications(content::WebContents* contents); 122 123 // Removes notifications added in RegisterForTabNotifications. 124 void UnregisterForTabNotifications(content::WebContents* contents); 125 126 content::NotificationRegistrar registrar_; 127 128 // Maintain some information about known tabs, so we can: 129 // 130 // - distinguish between tab creation and tab insertion 131 // - not send tab-detached after tab-removed 132 // - reduce the "noise" of TabChangedAt() when sending events to extensions 133 class TabEntry { 134 public: 135 // Create a new tab entry whose initial state is TAB_COMPLETE. This 136 // constructor is required because TabEntry objects placed inside an 137 // std::map<> by value. 138 TabEntry(); 139 140 // Update the load state of the tab based on its WebContents. Returns true 141 // if the state changed, false otherwise. Whether the state has changed or 142 // not is used to determine if events needs to be sent to extensions during 143 // processing of TabChangedAt(). This method will "hold" a state-change 144 // to "loading", until the DidNavigate() method which should always follow 145 // it. Returns NULL if no updates should be sent. 146 base::DictionaryValue* UpdateLoadState( 147 const content::WebContents* contents); 148 149 // Indicates that a tab load has resulted in a navigation and the 150 // destination url is available for inspection. Returns NULL if no updates 151 // should be sent. 152 base::DictionaryValue* DidNavigate(const content::WebContents* contents); 153 154 private: 155 // Whether we are waiting to fire the 'complete' status change. This will 156 // occur the first time the WebContents stops loading after the 157 // NAV_ENTRY_COMMITTED was fired. The tab may go back into and out of the 158 // loading state subsequently, but we will ignore those changes. 159 bool complete_waiting_on_load_; 160 161 GURL url_; 162 }; 163 164 // Gets the TabEntry for the given |contents|. Returns TabEntry* if 165 // found, NULL if not. 166 TabEntry* GetTabEntry(content::WebContents* contents); 167 168 std::map<int, TabEntry> tab_entries_; 169 170 // The main profile that owns this event router. 171 Profile* profile_; 172 173 DISALLOW_COPY_AND_ASSIGN(TabsEventRouter); 174 }; 175 176 } // namespace extensions 177 178 #endif // CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_ 179