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