diff options
5 files changed, 187 insertions, 15 deletions
diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc index b278258..cefef15 100644 --- a/chrome/browser/extensions/extension_browser_event_router.cc +++ b/chrome/browser/extensions/extension_browser_event_router.cc @@ -13,12 +13,24 @@ #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/common/notification_service.h" +const char* kOnTabCreated = "tab-created"; const char* kOnTabMoved = "tab-moved"; +const char* kOnTabSelectionChanged = "tab-selection-changed"; +const char* kOnTabAttached = "tab-attached"; +const char* kOnTabDetached = "tab-detached"; +const char* kOnTabRemoved = "tab-removed"; ExtensionBrowserEventRouter* ExtensionBrowserEventRouter::GetInstance() { return Singleton<ExtensionBrowserEventRouter>::get(); } +static void DispatchEvent(Profile *profile, + const char* event_name, + const std::string json_args) { + ExtensionMessageService::GetInstance(profile->GetRequestContext())-> + DispatchEventToRenderers(event_name, json_args); +} + void ExtensionBrowserEventRouter::Init() { if (initialized_) return; @@ -56,41 +68,103 @@ void ExtensionBrowserEventRouter::Observe(NotificationType type, void ExtensionBrowserEventRouter::TabInsertedAt(TabContents* contents, int index, - bool foreground) { } + bool foreground) { + const char* event_name = kOnTabAttached; + // If tab is new, send tab-created event. + int tab_id = ExtensionTabUtil::GetTabId(contents); + if (tab_ids_.find(tab_id) == tab_ids_.end()) { + tab_ids_.insert(tab_id); + event_name = kOnTabCreated; + } -void ExtensionBrowserEventRouter::TabClosingAt(TabContents* contents, - int index) { } + ListValue args; + DictionaryValue *object_args = new DictionaryValue(); + object_args->Set(L"tabId", Value::CreateIntegerValue(tab_id)); + object_args->Set(L"windowId", Value::CreateIntegerValue( + ExtensionTabUtil::GetWindowIdOfTab(contents))); + object_args->Set(L"index", Value::CreateIntegerValue(index)); + args.Append(object_args); + + std::string json_args; + JSONWriter::Write(&args, false, &json_args); + + DispatchEvent(contents->profile(), event_name, json_args); +} void ExtensionBrowserEventRouter::TabDetachedAt(TabContents* contents, - int index) { } + int index) { + int tab_id = ExtensionTabUtil::GetTabId(contents); + if (tab_ids_.find(tab_id) == tab_ids_.end()) { + // The tab was removed. Don't send detach event. + return; + } + + ListValue args; + DictionaryValue *object_args = new DictionaryValue(); + object_args->Set(L"tabId", Value::CreateIntegerValue(tab_id)); + object_args->Set(L"windowId", Value::CreateIntegerValue( + ExtensionTabUtil::GetWindowIdOfTab(contents))); + object_args->Set(L"index", Value::CreateIntegerValue(index)); + args.Append(object_args); + + std::string json_args; + JSONWriter::Write(&args, false, &json_args); + + DispatchEvent(contents->profile(), kOnTabDetached, json_args); +} + +void ExtensionBrowserEventRouter::TabClosingAt(TabContents* contents, + int index) { + int tab_id = ExtensionTabUtil::GetTabId(contents); + + ListValue args; + args.Append(Value::CreateIntegerValue(tab_id)); + + std::string json_args; + JSONWriter::Write(&args, false, &json_args); + + DispatchEvent(contents->profile(), kOnTabRemoved, json_args); + + int removed_count = tab_ids_.erase(tab_id); + DCHECK(removed_count > 0); +} void ExtensionBrowserEventRouter::TabSelectedAt(TabContents* old_contents, TabContents* new_contents, int index, - bool user_gesture) { } + bool user_gesture) { + ListValue args; + DictionaryValue *object_args = new DictionaryValue(); + object_args->Set(L"tabId", Value::CreateIntegerValue( + ExtensionTabUtil::GetTabId(new_contents))); + object_args->Set(L"windowId", Value::CreateIntegerValue( + ExtensionTabUtil::GetWindowIdOfTab(new_contents))); + object_args->Set(L"index", Value::CreateIntegerValue(index)); + args.Append(object_args); + + std::string json_args; + JSONWriter::Write(&args, false, &json_args); + + DispatchEvent(new_contents->profile(), kOnTabSelectionChanged, json_args); +} void ExtensionBrowserEventRouter::TabMoved(TabContents* contents, int from_index, int to_index) { - Profile *profile = contents->profile(); - ListValue args; DictionaryValue *object_args = new DictionaryValue(); - object_args->Set(L"tabId", Value::CreateIntegerValue( ExtensionTabUtil::GetTabId(contents))); object_args->Set(L"windowId", Value::CreateIntegerValue( ExtensionTabUtil::GetWindowIdOfTab(contents))); object_args->Set(L"fromIndex", Value::CreateIntegerValue(from_index)); object_args->Set(L"toIndex", Value::CreateIntegerValue(to_index)); - args.Append(object_args); std::string json_args; JSONWriter::Write(&args, false, &json_args); - ExtensionMessageService::GetInstance(profile->GetRequestContext())-> - DispatchEventToRenderers(kOnTabMoved, json_args); + DispatchEvent(contents->profile(), kOnTabMoved, json_args); } void ExtensionBrowserEventRouter::TabChangedAt(TabContents* contents, diff --git a/chrome/browser/extensions/extension_browser_event_router.h b/chrome/browser/extensions/extension_browser_event_router.h index a438e66..3a2f5ec 100644 --- a/chrome/browser/extensions/extension_browser_event_router.h +++ b/chrome/browser/extensions/extension_browser_event_router.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSER_EVENT_ROUTER_H_ #include <vector> +#include <set> #include <string> #include "base/basictypes.h" @@ -49,6 +50,10 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver, bool initialized_; + // Maintain set of known tab ids, so we can distinguish between tab creation + // and tab insertion. Also used to not send tab-detached after tab-removed. + std::set<int> tab_ids_; + DISALLOW_COPY_AND_ASSIGN(ExtensionBrowserEventRouter); }; diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index cda253b..c59e98c 100755 --- a/chrome/renderer/renderer_resources.grd +++ b/chrome/renderer/renderer_resources.grd @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- This comment is only here because changes to resources are not picked up -without changes to the corresponding grd file. --> +without changes to the corresponding grd file. --> <grit latest_public_release="0" current_release="1"> <outputs> <output filename="grit/renderer_resources.h" type="rc_header"> diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index 54ed9d7..e84b725 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -189,9 +189,31 @@ var chromium; chromium.types.pInt ]; - // onTabMoved sends ({tabId, windowId, fromIndex, toIndex}) as named - // arguments. + // sends ({tabId, windowId, index}). + // will *NOT* be followed by tab-attached - it is implied. + // *MAY* be followed by tab-selection-changed. + chromium.tabs.onTabCreated = new chromium.Event("tab-created"); + + // sends ({tabId, windowId, fromIndex, toIndex}). + // tabs can only "move" within a window. chromium.tabs.onTabMoved = new chromium.Event("tab-moved"); + + // sends ({tabId, windowId, index}). + chromium.tabs.onTabSelectionChanged = + new chromium.Event("tab-selection-changed"); + + // sends ({tabId, windowId, index}). + // *MAY* be followed by tab-selection-changed. + chromium.tabs.onTabAttached = new chromium.Event("tab-attached"); + + // sends ({tabId, windowId, index}). + // *WILL* be followed by tab-selection-changed. + chromium.tabs.onTabDetached = new chromium.Event("tab-detached"); + + // sends (tabId). + // *WILL* be followed by tab-selection-changed. + // will *NOT* be followed or preceded by tab-detached. + chromium.tabs.onTabRemoved = new chromium.Event("tab-removed"); //---------------------------------------------------------------------------- diff --git a/chrome/test/data/extensions/test/TabsAPI/1/tabs_api.html b/chrome/test/data/extensions/test/TabsAPI/1/tabs_api.html index 8f2c277..a506fd2 100644 --- a/chrome/test/data/extensions/test/TabsAPI/1/tabs_api.html +++ b/chrome/test/data/extensions/test/TabsAPI/1/tabs_api.html @@ -84,11 +84,63 @@ function clearLog() { document.getElementById('log').innerHTML = ''; } +chromium.tabs.onTabCreated.addListener(function(data) { + appendToLog('onTabCreated -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); + loadWindowList(); +}); + +chromium.tabs.onTabAttached.addListener(function(data) { + appendToLog('onTabAttached -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); + loadWindowList(); +}); + chromium.tabs.onTabMoved.addListener(function(data) { - appendToLog('onTabMoved: ' + data.tabId + ' from ' + data.fromIndex + ' to ' + data.toIndex); + appendToLog('onTabMoved -- window: ' + data.windowId + ' tab: ' + data.tabId + ' from ' + data.fromIndex + ' to ' + data.toIndex); + loadWindowList(); +}); + +chromium.tabs.onTabDetached.addListener(function(data) { + appendToLog('onTabDetached -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); + loadWindowList(); +}); + +chromium.tabs.onTabSelectionChanged.addListener(function(data) { + appendToLog('onTabSelectionChanged -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); loadWindowList(); }); +chromium.tabs.onTabRemoved.addListener(function(data) { + appendToLog('onTabRemoved -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); + loadWindowList(); +}); + +function isInt(i) { + return (typeof i == "number") && !(i % 1) && !isNaN(i); +} + +function createWindow() { + var args = { + 'left': parseInt(document.getElementById('new_window_left').value), + 'top': parseInt(document.getElementById('new_window_top').value), + 'width': parseInt(document.getElementById('new_window_width').value), + 'height': parseInt(document.getElementById('new_window_height').value), + 'url': document.getElementById('new_window_url').value + } + + if (!isInt(args.left)) + delete args.left; + if (!isInt(args.top)) + delete args.top; + if (!isInt(args.width)) + delete args.width; + if (!isInt(args.height)) + delete args.height; + if (!args.url) + delete args.url; + + chromium.tabs.createWindow(args); +} + </script> </head> <body onload="loadWindowList();"> @@ -131,6 +183,24 @@ chromium.tabs.onTabMoved.addListener(function(data) { </div> </div> </div> + <div style="background-color: #EEEEBB; margin: 20px; padding: 8px"> + <h3 style="text-align: center; margin: 8px"> Create Window</h3> + <div style="margin: 8px"> + <div style="width: 300px; display: inline-block"> + left: <input style="width: 20px" type="text" id="new_window_left" /> + top: <input style="width: 20px" type="text" id="new_window_top" /> + width: <input style="width: 20px" type="text" id="new_window_width" /> + height: <input style="width: 20px" type="text" id="new_window_height" /> + </div> + </div> + <div style="margin: 8px"> + <div> + <div style="width: 40px; display:inline-block">url:</div> + <input style="width: 90%" type="text" id="new_window_url" /> + </div> + </div> + <button onclick="createWindow();">Create</button> + </div> <div style="background-color: #EEEEAA; margin: 20px; padding: 8px"> <h3 style="text-align: center; margin: 8px"> Create Tab</h3> <div style="margin: 8px"> @@ -158,6 +228,7 @@ chromium.tabs.onTabMoved.addListener(function(data) { <button onclick="updateAll();">Update All</button> <button onclick="moveAll();">Move All</button> <button onclick="clearLog();">-->Clear Log</button> + <button onclick="chromium.tabs.createWindow();">New Window</button> </div> <div id="log" style="background-color: #EEAAEE; margin: 20px; padding: 8px"> </div> |