OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/extensions/extension_browser_event_router.h" | |
6 | |
7 #include "base/json/json_writer.h" | |
8 #include "base/values.h" | |
9 #include "chrome/browser/extensions/api/extension_action/extension_page_actions_
api_constants.h" | |
10 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" | |
11 #include "chrome/browser/extensions/extension_event_names.h" | |
12 #include "chrome/browser/extensions/extension_event_router.h" | |
13 #include "chrome/browser/extensions/extension_service.h" | |
14 #include "chrome/browser/extensions/extension_tab_util.h" | |
15 #include "chrome/browser/extensions/window_controller.h" | |
16 #include "chrome/browser/profiles/profile.h" | |
17 #include "chrome/browser/ui/browser.h" | |
18 #include "chrome/browser/ui/browser_list.h" | |
19 #include "chrome/browser/ui/browser_tabstrip.h" | |
20 #include "chrome/browser/ui/tab_contents/tab_contents.h" | |
21 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
22 #include "chrome/common/chrome_notification_types.h" | |
23 #include "chrome/common/extensions/extension.h" | |
24 #include "chrome/common/extensions/extension_constants.h" | |
25 #include "content/public/browser/navigation_controller.h" | |
26 #include "content/public/browser/notification_service.h" | |
27 #include "content/public/browser/web_contents.h" | |
28 | |
29 #if defined(TOOLKIT_GTK) | |
30 #include "ui/base/x/active_window_watcher_x.h" | |
31 #endif | |
32 | |
33 namespace events = extension_event_names; | |
34 namespace tab_keys = extensions::tabs_constants; | |
35 namespace page_action_keys = extension_page_actions_api_constants; | |
36 | |
37 using content::NavigationController; | |
38 using content::WebContents; | |
39 | |
40 ExtensionBrowserEventRouter::TabEntry::TabEntry() | |
41 : complete_waiting_on_load_(false), | |
42 url_() { | |
43 } | |
44 | |
45 DictionaryValue* ExtensionBrowserEventRouter::TabEntry::UpdateLoadState( | |
46 const WebContents* contents) { | |
47 // The tab may go in & out of loading (for instance if iframes navigate). | |
48 // We only want to respond to the first change from loading to !loading after | |
49 // the NAV_ENTRY_COMMITTED was fired. | |
50 if (!complete_waiting_on_load_ || contents->IsLoading()) | |
51 return NULL; | |
52 | |
53 // Send "complete" state change. | |
54 complete_waiting_on_load_ = false; | |
55 DictionaryValue* changed_properties = new DictionaryValue(); | |
56 changed_properties->SetString(tab_keys::kStatusKey, | |
57 tab_keys::kStatusValueComplete); | |
58 return changed_properties; | |
59 } | |
60 | |
61 DictionaryValue* ExtensionBrowserEventRouter::TabEntry::DidNavigate( | |
62 const WebContents* contents) { | |
63 // Send "loading" state change. | |
64 complete_waiting_on_load_ = true; | |
65 DictionaryValue* changed_properties = new DictionaryValue(); | |
66 changed_properties->SetString(tab_keys::kStatusKey, | |
67 tab_keys::kStatusValueLoading); | |
68 | |
69 if (contents->GetURL() != url_) { | |
70 url_ = contents->GetURL(); | |
71 changed_properties->SetString(tab_keys::kUrlKey, url_.spec()); | |
72 } | |
73 | |
74 return changed_properties; | |
75 } | |
76 | |
77 void ExtensionBrowserEventRouter::Init() { | |
78 if (initialized_) | |
79 return; | |
80 BrowserList::AddObserver(this); | |
81 #if defined(TOOLKIT_VIEWS) | |
82 views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); | |
83 #elif defined(TOOLKIT_GTK) | |
84 ui::ActiveWindowWatcherX::AddObserver(this); | |
85 #elif defined(OS_MACOSX) | |
86 // Needed for when no suitable window can be passed to an extension as the | |
87 // currently focused window. | |
88 registrar_.Add(this, chrome::NOTIFICATION_NO_KEY_WINDOW, | |
89 content::NotificationService::AllSources()); | |
90 #endif | |
91 | |
92 // Init() can happen after the browser is running, so catch up with any | |
93 // windows that already exist. | |
94 for (BrowserList::const_iterator iter = BrowserList::begin(); | |
95 iter != BrowserList::end(); ++iter) { | |
96 RegisterForBrowserNotifications(*iter); | |
97 | |
98 // Also catch up our internal bookkeeping of tab entries. | |
99 Browser* browser = *iter; | |
100 if (browser->tab_strip_model()) { | |
101 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { | |
102 WebContents* contents = | |
103 chrome::GetTabContentsAt(browser, i)->web_contents(); | |
104 int tab_id = ExtensionTabUtil::GetTabId(contents); | |
105 tab_entries_[tab_id] = TabEntry(); | |
106 } | |
107 } | |
108 } | |
109 | |
110 initialized_ = true; | |
111 } | |
112 | |
113 ExtensionBrowserEventRouter::ExtensionBrowserEventRouter(Profile* profile) | |
114 : initialized_(false), | |
115 profile_(profile), | |
116 focused_profile_(NULL), | |
117 focused_window_id_(extension_misc::kUnknownWindowId) { | |
118 DCHECK(!profile->IsOffTheRecord()); | |
119 } | |
120 | |
121 ExtensionBrowserEventRouter::~ExtensionBrowserEventRouter() { | |
122 BrowserList::RemoveObserver(this); | |
123 #if defined(TOOLKIT_VIEWS) | |
124 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); | |
125 #elif defined(TOOLKIT_GTK) | |
126 ui::ActiveWindowWatcherX::RemoveObserver(this); | |
127 #endif | |
128 } | |
129 | |
130 void ExtensionBrowserEventRouter::OnBrowserAdded(Browser* browser) { | |
131 RegisterForBrowserNotifications(browser); | |
132 } | |
133 | |
134 void ExtensionBrowserEventRouter::RegisterForBrowserNotifications( | |
135 Browser* browser) { | |
136 if (!profile_->IsSameProfile(browser->profile())) | |
137 return; | |
138 // Start listening to TabStripModel events for this browser. | |
139 browser->tab_strip_model()->AddObserver(this); | |
140 | |
141 // If this is a new window, it isn't ready at this point, so we register to be | |
142 // notified when it is. If this is an existing window, this is a no-op that we | |
143 // just do to reduce code complexity. | |
144 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY, | |
145 content::Source<Browser>(browser)); | |
146 | |
147 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { | |
148 RegisterForTabNotifications( | |
149 chrome::GetTabContentsAt(browser, i)->web_contents()); | |
150 } | |
151 } | |
152 | |
153 void ExtensionBrowserEventRouter::RegisterForTabNotifications( | |
154 WebContents* contents) { | |
155 registrar_.Add( | |
156 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
157 content::Source<NavigationController>(&contents->GetController())); | |
158 | |
159 // Observing NOTIFICATION_WEB_CONTENTS_DESTROYED is necessary because it's | |
160 // possible for tabs to be created, detached and then destroyed without | |
161 // ever having been re-attached and closed. This happens in the case of | |
162 // a devtools WebContents that is opened in window, docked, then closed. | |
163 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
164 content::Source<WebContents>(contents)); | |
165 } | |
166 | |
167 void ExtensionBrowserEventRouter::UnregisterForTabNotifications( | |
168 WebContents* contents) { | |
169 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
170 content::Source<NavigationController>(&contents->GetController())); | |
171 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
172 content::Source<WebContents>(contents)); | |
173 } | |
174 | |
175 void ExtensionBrowserEventRouter::OnBrowserWindowReady(Browser* browser) { | |
176 ListValue args; | |
177 | |
178 DCHECK(browser->extension_window_controller()); | |
179 DictionaryValue* window_dictionary = | |
180 browser->extension_window_controller()->CreateWindowValue(); | |
181 args.Append(window_dictionary); | |
182 | |
183 std::string json_args; | |
184 base::JSONWriter::Write(&args, &json_args); | |
185 | |
186 DispatchEvent(browser->profile(), events::kOnWindowCreated, json_args); | |
187 } | |
188 | |
189 void ExtensionBrowserEventRouter::OnBrowserRemoved(Browser* browser) { | |
190 if (!profile_->IsSameProfile(browser->profile())) | |
191 return; | |
192 | |
193 // Stop listening to TabStripModel events for this browser. | |
194 browser->tab_strip_model()->RemoveObserver(this); | |
195 | |
196 registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY, | |
197 content::Source<Browser>(browser)); | |
198 | |
199 DispatchSimpleBrowserEvent(browser->profile(), | |
200 ExtensionTabUtil::GetWindowId(browser), | |
201 events::kOnWindowRemoved); | |
202 } | |
203 | |
204 #if defined(TOOLKIT_VIEWS) | |
205 void ExtensionBrowserEventRouter::OnNativeFocusChange( | |
206 gfx::NativeView focused_before, | |
207 gfx::NativeView focused_now) { | |
208 if (!focused_now) | |
209 OnBrowserSetLastActive(NULL); | |
210 } | |
211 #elif defined(TOOLKIT_GTK) | |
212 void ExtensionBrowserEventRouter::ActiveWindowChanged( | |
213 GdkWindow* active_window) { | |
214 if (!active_window) | |
215 OnBrowserSetLastActive(NULL); | |
216 } | |
217 #endif | |
218 | |
219 void ExtensionBrowserEventRouter::OnBrowserSetLastActive( | |
220 Browser* browser) { | |
221 Profile* window_profile = NULL; | |
222 int window_id = extension_misc::kUnknownWindowId; | |
223 if (browser && profile_->IsSameProfile(browser->profile())) { | |
224 window_profile = browser->profile(); | |
225 window_id = ExtensionTabUtil::GetWindowId(browser); | |
226 } | |
227 | |
228 if (focused_window_id_ == window_id) | |
229 return; | |
230 | |
231 // window_profile is either this profile's default profile, its | |
232 // incognito profile, or NULL iff this profile is losing focus. | |
233 Profile* previous_focused_profile = focused_profile_; | |
234 focused_profile_ = window_profile; | |
235 focused_window_id_ = window_id; | |
236 | |
237 ListValue real_args; | |
238 real_args.Append(Value::CreateIntegerValue(window_id)); | |
239 std::string real_json_args; | |
240 base::JSONWriter::Write(&real_args, &real_json_args); | |
241 | |
242 // When switching between windows in the default and incognitoi profiles, | |
243 // dispatch WINDOW_ID_NONE to extensions whose profile lost focus that | |
244 // can't see the new focused window across the incognito boundary. | |
245 // See crbug.com/46610. | |
246 std::string none_json_args; | |
247 if (focused_profile_ != NULL && previous_focused_profile != NULL && | |
248 focused_profile_ != previous_focused_profile) { | |
249 ListValue none_args; | |
250 none_args.Append( | |
251 Value::CreateIntegerValue(extension_misc::kUnknownWindowId)); | |
252 base::JSONWriter::Write(&none_args, &none_json_args); | |
253 } | |
254 | |
255 DispatchEventsAcrossIncognito((focused_profile_ ? focused_profile_ : | |
256 previous_focused_profile), | |
257 events::kOnWindowFocusedChanged, | |
258 real_json_args, | |
259 none_json_args); | |
260 } | |
261 | |
262 void ExtensionBrowserEventRouter::TabCreatedAt(WebContents* contents, | |
263 int index, | |
264 bool active) { | |
265 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); | |
266 DispatchEventWithTab(profile, "", events::kOnTabCreated, contents, active); | |
267 | |
268 RegisterForTabNotifications(contents); | |
269 } | |
270 | |
271 void ExtensionBrowserEventRouter::TabInsertedAt(TabContents* contents, | |
272 int index, | |
273 bool active) { | |
274 // If tab is new, send created event. | |
275 int tab_id = ExtensionTabUtil::GetTabId(contents->web_contents()); | |
276 if (!GetTabEntry(contents->web_contents())) { | |
277 tab_entries_[tab_id] = TabEntry(); | |
278 | |
279 TabCreatedAt(contents->web_contents(), index, active); | |
280 return; | |
281 } | |
282 | |
283 ListValue args; | |
284 args.Append(Value::CreateIntegerValue(tab_id)); | |
285 | |
286 DictionaryValue* object_args = new DictionaryValue(); | |
287 object_args->Set(tab_keys::kNewWindowIdKey, Value::CreateIntegerValue( | |
288 ExtensionTabUtil::GetWindowIdOfTab(contents->web_contents()))); | |
289 object_args->Set(tab_keys::kNewPositionKey, Value::CreateIntegerValue( | |
290 index)); | |
291 args.Append(object_args); | |
292 | |
293 std::string json_args; | |
294 base::JSONWriter::Write(&args, &json_args); | |
295 | |
296 DispatchEvent(contents->profile(), events::kOnTabAttached, json_args); | |
297 } | |
298 | |
299 void ExtensionBrowserEventRouter::TabDetachedAt(TabContents* contents, | |
300 int index) { | |
301 if (!GetTabEntry(contents->web_contents())) { | |
302 // The tab was removed. Don't send detach event. | |
303 return; | |
304 } | |
305 | |
306 ListValue args; | |
307 args.Append(Value::CreateIntegerValue( | |
308 ExtensionTabUtil::GetTabId(contents->web_contents()))); | |
309 | |
310 DictionaryValue* object_args = new DictionaryValue(); | |
311 object_args->Set(tab_keys::kOldWindowIdKey, Value::CreateIntegerValue( | |
312 ExtensionTabUtil::GetWindowIdOfTab(contents->web_contents()))); | |
313 object_args->Set(tab_keys::kOldPositionKey, Value::CreateIntegerValue( | |
314 index)); | |
315 args.Append(object_args); | |
316 | |
317 std::string json_args; | |
318 base::JSONWriter::Write(&args, &json_args); | |
319 | |
320 DispatchEvent(contents->profile(), events::kOnTabDetached, json_args); | |
321 } | |
322 | |
323 void ExtensionBrowserEventRouter::TabClosingAt(TabStripModel* tab_strip_model, | |
324 TabContents* contents, | |
325 int index) { | |
326 int tab_id = ExtensionTabUtil::GetTabId(contents->web_contents()); | |
327 | |
328 ListValue args; | |
329 args.Append(Value::CreateIntegerValue(tab_id)); | |
330 | |
331 DictionaryValue* object_args = new DictionaryValue(); | |
332 object_args->SetBoolean(tab_keys::kWindowClosing, | |
333 tab_strip_model->closing_all()); | |
334 args.Append(object_args); | |
335 | |
336 std::string json_args; | |
337 base::JSONWriter::Write(&args, &json_args); | |
338 | |
339 DispatchEvent(contents->profile(), events::kOnTabRemoved, json_args); | |
340 | |
341 int removed_count = tab_entries_.erase(tab_id); | |
342 DCHECK_GT(removed_count, 0); | |
343 | |
344 UnregisterForTabNotifications(contents->web_contents()); | |
345 } | |
346 | |
347 void ExtensionBrowserEventRouter::ActiveTabChanged( | |
348 TabContents* old_contents, | |
349 TabContents* new_contents, | |
350 int index, | |
351 bool user_gesture) { | |
352 ListValue args; | |
353 int tab_id = ExtensionTabUtil::GetTabId(new_contents->web_contents()); | |
354 args.Append(Value::CreateIntegerValue(tab_id)); | |
355 | |
356 DictionaryValue* object_args = new DictionaryValue(); | |
357 object_args->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue( | |
358 ExtensionTabUtil::GetWindowIdOfTab(new_contents->web_contents()))); | |
359 args.Append(object_args); | |
360 | |
361 // The onActivated event replaced onActiveChanged and onSelectionChanged. The | |
362 // deprecated events take two arguments: tabId, {windowId}. | |
363 std::string old_json_args; | |
364 base::JSONWriter::Write(&args, &old_json_args); | |
365 | |
366 // The onActivated event takes one argument: {windowId, tabId}. | |
367 std::string new_json_args; | |
368 args.Remove(0, NULL); | |
369 object_args->Set(tab_keys::kTabIdKey, Value::CreateIntegerValue(tab_id)); | |
370 base::JSONWriter::Write(&args, &new_json_args); | |
371 | |
372 Profile* profile = new_contents->profile(); | |
373 DispatchEvent(profile, events::kOnTabSelectionChanged, old_json_args); | |
374 DispatchEvent(profile, events::kOnTabActiveChanged, old_json_args); | |
375 DispatchEvent(profile, events::kOnTabActivated, new_json_args); | |
376 } | |
377 | |
378 void ExtensionBrowserEventRouter::TabSelectionChanged( | |
379 TabStripModel* tab_strip_model, | |
380 const TabStripSelectionModel& old_model) { | |
381 TabStripSelectionModel::SelectedIndices new_selection = | |
382 tab_strip_model->selection_model().selected_indices(); | |
383 ListValue* all = new ListValue(); | |
384 | |
385 for (size_t i = 0; i < new_selection.size(); ++i) { | |
386 int index = new_selection[i]; | |
387 TabContents* contents = tab_strip_model->GetTabContentsAt(index); | |
388 if (!contents) | |
389 break; | |
390 int tab_id = ExtensionTabUtil::GetTabId(contents->web_contents()); | |
391 all->Append(Value::CreateIntegerValue(tab_id)); | |
392 } | |
393 | |
394 ListValue args; | |
395 DictionaryValue* select_info = new DictionaryValue(); | |
396 | |
397 select_info->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue( | |
398 ExtensionTabUtil::GetWindowIdOfTabStripModel(tab_strip_model))); | |
399 | |
400 select_info->Set(tab_keys::kTabIdsKey, all); | |
401 args.Append(select_info); | |
402 | |
403 std::string json_args; | |
404 base::JSONWriter::Write(&args, &json_args); | |
405 | |
406 // The onHighlighted event replaced onHighlightChanged. | |
407 Profile* profile = tab_strip_model->profile(); | |
408 DispatchEvent(profile, events::kOnTabHighlightChanged, json_args); | |
409 DispatchEvent(profile, events::kOnTabHighlighted, json_args); | |
410 } | |
411 | |
412 void ExtensionBrowserEventRouter::TabMoved(TabContents* contents, | |
413 int from_index, | |
414 int to_index) { | |
415 ListValue args; | |
416 args.Append(Value::CreateIntegerValue( | |
417 ExtensionTabUtil::GetTabId(contents->web_contents()))); | |
418 | |
419 DictionaryValue* object_args = new DictionaryValue(); | |
420 object_args->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue( | |
421 ExtensionTabUtil::GetWindowIdOfTab(contents->web_contents()))); | |
422 object_args->Set(tab_keys::kFromIndexKey, Value::CreateIntegerValue( | |
423 from_index)); | |
424 object_args->Set(tab_keys::kToIndexKey, Value::CreateIntegerValue( | |
425 to_index)); | |
426 args.Append(object_args); | |
427 | |
428 std::string json_args; | |
429 base::JSONWriter::Write(&args, &json_args); | |
430 | |
431 DispatchEvent(contents->profile(), events::kOnTabMoved, json_args); | |
432 } | |
433 | |
434 void ExtensionBrowserEventRouter::TabUpdated(WebContents* contents, | |
435 bool did_navigate) { | |
436 TabEntry* entry = GetTabEntry(contents); | |
437 DictionaryValue* changed_properties = NULL; | |
438 | |
439 DCHECK(entry); | |
440 | |
441 if (did_navigate) | |
442 changed_properties = entry->DidNavigate(contents); | |
443 else | |
444 changed_properties = entry->UpdateLoadState(contents); | |
445 | |
446 if (changed_properties) | |
447 DispatchTabUpdatedEvent(contents, changed_properties); | |
448 } | |
449 | |
450 void ExtensionBrowserEventRouter::DispatchEvent(Profile* profile, | |
451 const char* event_name, | |
452 const std::string& json_args) { | |
453 if (!profile_->IsSameProfile(profile) || !profile->GetExtensionEventRouter()) | |
454 return; | |
455 | |
456 profile->GetExtensionEventRouter()->DispatchEventToRenderers( | |
457 event_name, json_args, profile, GURL(), extensions::EventFilteringInfo()); | |
458 } | |
459 | |
460 void ExtensionBrowserEventRouter::DispatchEventToExtension( | |
461 Profile* profile, | |
462 const std::string& extension_id, | |
463 const char* event_name, | |
464 const std::string& json_args) { | |
465 if (!profile_->IsSameProfile(profile) || !profile->GetExtensionEventRouter()) | |
466 return; | |
467 | |
468 profile->GetExtensionEventRouter()->DispatchEventToExtension( | |
469 extension_id, event_name, json_args, profile, GURL()); | |
470 } | |
471 | |
472 void ExtensionBrowserEventRouter::DispatchEventsAcrossIncognito( | |
473 Profile* profile, | |
474 const char* event_name, | |
475 const std::string& json_args, | |
476 const std::string& cross_incognito_args) { | |
477 if (!profile_->IsSameProfile(profile) || !profile->GetExtensionEventRouter()) | |
478 return; | |
479 | |
480 profile->GetExtensionEventRouter()->DispatchEventsToRenderersAcrossIncognito( | |
481 event_name, json_args, profile, cross_incognito_args, GURL()); | |
482 } | |
483 | |
484 void ExtensionBrowserEventRouter::DispatchEventWithTab( | |
485 Profile* profile, | |
486 const std::string& extension_id, | |
487 const char* event_name, | |
488 const WebContents* web_contents, | |
489 bool active) { | |
490 if (!profile_->IsSameProfile(profile)) | |
491 return; | |
492 | |
493 ListValue args; | |
494 args.Append(ExtensionTabUtil::CreateTabValueActive( | |
495 web_contents, active)); | |
496 std::string json_args; | |
497 base::JSONWriter::Write(&args, &json_args); | |
498 if (!extension_id.empty()) { | |
499 DispatchEventToExtension(profile, extension_id, event_name, json_args); | |
500 } else { | |
501 DispatchEvent(profile, event_name, json_args); | |
502 } | |
503 } | |
504 | |
505 void ExtensionBrowserEventRouter::DispatchSimpleBrowserEvent( | |
506 Profile* profile, const int window_id, const char* event_name) { | |
507 if (!profile_->IsSameProfile(profile)) | |
508 return; | |
509 | |
510 ListValue args; | |
511 args.Append(Value::CreateIntegerValue(window_id)); | |
512 | |
513 std::string json_args; | |
514 base::JSONWriter::Write(&args, &json_args); | |
515 | |
516 DispatchEvent(profile, event_name, json_args); | |
517 } | |
518 | |
519 void ExtensionBrowserEventRouter::DispatchTabUpdatedEvent( | |
520 WebContents* contents, DictionaryValue* changed_properties) { | |
521 DCHECK(changed_properties); | |
522 DCHECK(contents); | |
523 | |
524 // The state of the tab (as seen from the extension point of view) has | |
525 // changed. Send a notification to the extension. | |
526 ListValue args; | |
527 | |
528 // First arg: The id of the tab that changed. | |
529 args.Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents))); | |
530 | |
531 // Second arg: An object containing the changes to the tab state. | |
532 args.Append(changed_properties); | |
533 | |
534 // Third arg: An object containing the state of the tab. | |
535 args.Append(ExtensionTabUtil::CreateTabValue(contents)); | |
536 | |
537 std::string json_args; | |
538 base::JSONWriter::Write(&args, &json_args); | |
539 | |
540 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); | |
541 DispatchEvent(profile, events::kOnTabUpdated, json_args); | |
542 } | |
543 | |
544 ExtensionBrowserEventRouter::TabEntry* ExtensionBrowserEventRouter::GetTabEntry( | |
545 const WebContents* contents) { | |
546 int tab_id = ExtensionTabUtil::GetTabId(contents); | |
547 std::map<int, TabEntry>::iterator i = tab_entries_.find(tab_id); | |
548 if (tab_entries_.end() == i) | |
549 return NULL; | |
550 return &i->second; | |
551 } | |
552 | |
553 void ExtensionBrowserEventRouter::Observe( | |
554 int type, | |
555 const content::NotificationSource& source, | |
556 const content::NotificationDetails& details) { | |
557 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { | |
558 NavigationController* source_controller = | |
559 content::Source<NavigationController>(source).ptr(); | |
560 TabUpdated(source_controller->GetWebContents(), true); | |
561 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { | |
562 // Tab was destroyed after being detached (without being re-attached). | |
563 WebContents* contents = content::Source<WebContents>(source).ptr(); | |
564 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
565 content::Source<NavigationController>(&contents->GetController())); | |
566 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
567 content::Source<WebContents>(contents)); | |
568 } else if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) { | |
569 Browser* browser = content::Source<Browser>(source).ptr(); | |
570 OnBrowserWindowReady(browser); | |
571 #if defined(OS_MACOSX) | |
572 } else if (type == chrome::NOTIFICATION_NO_KEY_WINDOW) { | |
573 OnBrowserSetLastActive(NULL); | |
574 #endif | |
575 } else { | |
576 NOTREACHED(); | |
577 } | |
578 } | |
579 | |
580 void ExtensionBrowserEventRouter::TabChangedAt(TabContents* contents, | |
581 int index, | |
582 TabChangeType change_type) { | |
583 TabUpdated(contents->web_contents(), false); | |
584 } | |
585 | |
586 void ExtensionBrowserEventRouter::TabReplacedAt( | |
587 TabStripModel* tab_strip_model, | |
588 TabContents* old_contents, | |
589 TabContents* new_contents, | |
590 int index) { | |
591 TabClosingAt(tab_strip_model, old_contents, index); | |
592 TabInsertedAt(new_contents, index, tab_strip_model->active_index() == index); | |
593 } | |
594 | |
595 void ExtensionBrowserEventRouter::TabPinnedStateChanged( | |
596 TabContents* contents, | |
597 int index) { | |
598 TabStripModel* tab_strip = NULL; | |
599 int tab_index; | |
600 | |
601 if (ExtensionTabUtil::GetTabStripModel( | |
602 contents->web_contents(), &tab_strip, &tab_index)) { | |
603 DictionaryValue* changed_properties = new DictionaryValue(); | |
604 changed_properties->SetBoolean(tab_keys::kPinnedKey, | |
605 tab_strip->IsTabPinned(tab_index)); | |
606 DispatchTabUpdatedEvent(contents->web_contents(), changed_properties); | |
607 } | |
608 } | |
609 | |
610 void ExtensionBrowserEventRouter::TabStripEmpty() {} | |
611 | |
612 void ExtensionBrowserEventRouter::DispatchOldPageActionEvent( | |
613 Profile* profile, | |
614 const std::string& extension_id, | |
615 const std::string& page_action_id, | |
616 int tab_id, | |
617 const std::string& url, | |
618 int button) { | |
619 ListValue args; | |
620 args.Append(Value::CreateStringValue(page_action_id)); | |
621 | |
622 DictionaryValue* data = new DictionaryValue(); | |
623 data->Set(tab_keys::kTabIdKey, Value::CreateIntegerValue(tab_id)); | |
624 data->Set(tab_keys::kTabUrlKey, Value::CreateStringValue(url)); | |
625 data->Set(page_action_keys::kButtonKey, Value::CreateIntegerValue(button)); | |
626 args.Append(data); | |
627 | |
628 std::string json_args; | |
629 base::JSONWriter::Write(&args, &json_args); | |
630 | |
631 DispatchEventToExtension(profile, extension_id, "pageActions", json_args); | |
632 } | |
633 | |
634 void ExtensionBrowserEventRouter::BrowserActionExecuted( | |
635 const ExtensionAction& browser_action, | |
636 Browser* browser) { | |
637 Profile* profile = browser->profile(); | |
638 TabContents* tab_contents = NULL; | |
639 int tab_id = 0; | |
640 if (!ExtensionTabUtil::GetDefaultTab(browser, &tab_contents, &tab_id)) | |
641 return; | |
642 ExtensionActionExecuted(profile, browser_action, tab_contents); | |
643 } | |
644 | |
645 void ExtensionBrowserEventRouter::PageActionExecuted( | |
646 Profile* profile, | |
647 const ExtensionAction& page_action, | |
648 int tab_id, | |
649 const std::string& url, | |
650 int button) { | |
651 DispatchOldPageActionEvent(profile, page_action.extension_id(), | |
652 page_action.id(), tab_id, url, button); | |
653 TabContents* tab_contents = NULL; | |
654 if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(), | |
655 NULL, NULL, &tab_contents, NULL)) { | |
656 return; | |
657 } | |
658 ExtensionActionExecuted(profile, page_action, tab_contents); | |
659 } | |
660 | |
661 void ExtensionBrowserEventRouter::ScriptBadgeExecuted( | |
662 Profile* profile, | |
663 const ExtensionAction& script_badge, | |
664 int tab_id) { | |
665 TabContents* tab_contents = NULL; | |
666 if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(), | |
667 NULL, NULL, &tab_contents, NULL)) { | |
668 return; | |
669 } | |
670 ExtensionActionExecuted(profile, script_badge, tab_contents); | |
671 } | |
672 | |
673 void ExtensionBrowserEventRouter::CommandExecuted( | |
674 Profile* profile, | |
675 const std::string& extension_id, | |
676 const std::string& command) { | |
677 ListValue args; | |
678 args.Append(Value::CreateStringValue(command)); | |
679 std::string json_args; | |
680 base::JSONWriter::Write(&args, &json_args); | |
681 | |
682 DispatchEventToExtension(profile, | |
683 extension_id, | |
684 "experimental.keybinding.onCommand", | |
685 json_args); | |
686 } | |
687 | |
688 void ExtensionBrowserEventRouter::ExtensionActionExecuted( | |
689 Profile* profile, | |
690 const ExtensionAction& extension_action, | |
691 TabContents* tab_contents) { | |
692 const char* event_name = NULL; | |
693 switch (extension_action.action_type()) { | |
694 case ExtensionAction::TYPE_BROWSER: | |
695 event_name = "browserAction.onClicked"; | |
696 break; | |
697 case ExtensionAction::TYPE_PAGE: | |
698 event_name = "pageAction.onClicked"; | |
699 break; | |
700 case ExtensionAction::TYPE_SCRIPT_BADGE: | |
701 event_name = "scriptBadge.onClicked"; | |
702 break; | |
703 } | |
704 | |
705 if (event_name) { | |
706 DispatchEventWithTab(profile, | |
707 extension_action.extension_id(), | |
708 event_name, | |
709 tab_contents->web_contents(), | |
710 true); | |
711 } | |
712 } | |
OLD | NEW |