summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/browser_event_router.cc117
-rw-r--r--chrome/browser/extensions/browser_event_router.h34
-rw-r--r--chrome/browser/extensions/browser_extension_window_controller.cc6
-rw-r--r--chrome/browser/extensions/browser_extension_window_controller.h1
-rw-r--r--chrome/browser/extensions/extension_service.cc3
-rw-r--r--chrome/browser/extensions/extension_service.h23
-rw-r--r--chrome/browser/extensions/window_controller.cc2
-rw-r--r--chrome/browser/extensions/window_controller.h2
-rw-r--r--chrome/browser/extensions/window_controller_list.cc17
-rw-r--r--chrome/browser/extensions/window_controller_list.h8
-rw-r--r--chrome/browser/extensions/window_controller_list_observer.h28
-rw-r--r--chrome/browser/extensions/window_event_router.cc174
-rw-r--r--chrome/browser/extensions/window_event_router.h90
-rw-r--r--chrome/browser/ui/panels/panel.cc21
-rw-r--r--chrome/browser/ui/panels/panel_cocoa.mm6
-rw-r--r--chrome/browser/ui/views/ash/panel_view_aura.cc7
-rw-r--r--chrome/chrome_browser_extensions.gypi3
-rw-r--r--chrome/test/data/extensions/api_test/window_open/panel/test.js6
18 files changed, 395 insertions, 153 deletions
diff --git a/chrome/browser/extensions/browser_event_router.cc b/chrome/browser/extensions/browser_event_router.cc
index 58c2061..f184152 100644
--- a/chrome/browser/extensions/browser_event_router.cc
+++ b/chrome/browser/extensions/browser_event_router.cc
@@ -11,25 +11,23 @@
#include "chrome/browser/extensions/event_names.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/extensions/window_event_router.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
#include "content/public/browser/web_contents.h"
-#if defined(TOOLKIT_GTK)
-#include "ui/base/x/active_window_watcher_x.h"
-#endif
-
namespace events = extensions::event_names;
namespace tab_keys = extensions::tabs_constants;
namespace page_action_keys = extension_page_actions_api_constants;
@@ -80,16 +78,6 @@ void BrowserEventRouter::Init() {
if (initialized_)
return;
BrowserList::AddObserver(this);
-#if defined(TOOLKIT_VIEWS)
- views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
-#elif defined(TOOLKIT_GTK)
- ui::ActiveWindowWatcherX::AddObserver(this);
-#elif defined(OS_MACOSX)
- // Needed for when no suitable window can be passed to an extension as the
- // currently focused window.
- registrar_.Add(this, chrome::NOTIFICATION_NO_KEY_WINDOW,
- content::NotificationService::AllSources());
-#endif
// Init() can happen after the browser is running, so catch up with any
// windows that already exist.
@@ -114,19 +102,12 @@ void BrowserEventRouter::Init() {
BrowserEventRouter::BrowserEventRouter(Profile* profile)
: initialized_(false),
- profile_(profile),
- focused_profile_(NULL),
- focused_window_id_(extension_misc::kUnknownWindowId) {
+ profile_(profile) {
DCHECK(!profile->IsOffTheRecord());
}
BrowserEventRouter::~BrowserEventRouter() {
BrowserList::RemoveObserver(this);
-#if defined(TOOLKIT_VIEWS)
- views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
-#elif defined(TOOLKIT_GTK)
- ui::ActiveWindowWatcherX::RemoveObserver(this);
-#endif
}
void BrowserEventRouter::OnBrowserAdded(Browser* browser) {
@@ -139,12 +120,6 @@ void BrowserEventRouter::RegisterForBrowserNotifications(Browser* browser) {
// Start listening to TabStripModel events for this browser.
browser->tab_strip_model()->AddObserver(this);
- // If this is a new window, it isn't ready at this point, so we register to be
- // notified when it is. If this is an existing window, this is a no-op that we
- // just do to reduce code complexity.
- registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
- content::Source<Browser>(browser));
-
for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
RegisterForTabNotifications(
chrome::GetTabContentsAt(browser, i)->web_contents());
@@ -171,88 +146,21 @@ void BrowserEventRouter::UnregisterForTabNotifications(WebContents* contents) {
content::Source<WebContents>(contents));
}
-void BrowserEventRouter::OnBrowserWindowReady(Browser* browser) {
- ListValue args;
-
- DCHECK(browser->extension_window_controller());
- DictionaryValue* window_dictionary =
- browser->extension_window_controller()->CreateWindowValue();
- args.Append(window_dictionary);
-
- std::string json_args;
- base::JSONWriter::Write(&args, &json_args);
-
- DispatchEvent(browser->profile(), events::kOnWindowCreated, json_args);
-}
-
void BrowserEventRouter::OnBrowserRemoved(Browser* browser) {
if (!profile_->IsSameProfile(browser->profile()))
return;
// Stop listening to TabStripModel events for this browser.
browser->tab_strip_model()->RemoveObserver(this);
-
- registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
- content::Source<Browser>(browser));
-
- DispatchSimpleBrowserEvent(browser->profile(),
- ExtensionTabUtil::GetWindowId(browser),
- events::kOnWindowRemoved);
-}
-
-#if defined(TOOLKIT_VIEWS)
-void BrowserEventRouter::OnNativeFocusChange(gfx::NativeView focused_before,
- gfx::NativeView focused_now) {
- if (!focused_now)
- OnBrowserSetLastActive(NULL);
-}
-#elif defined(TOOLKIT_GTK)
-void BrowserEventRouter::ActiveWindowChanged(GdkWindow* active_window) {
- if (!active_window)
- OnBrowserSetLastActive(NULL);
}
-#endif
void BrowserEventRouter::OnBrowserSetLastActive(Browser* browser) {
- Profile* window_profile = NULL;
- int window_id = extension_misc::kUnknownWindowId;
- if (browser && profile_->IsSameProfile(browser->profile())) {
- window_profile = browser->profile();
- window_id = ExtensionTabUtil::GetWindowId(browser);
+ ExtensionService* service =
+ extensions::ExtensionSystem::Get(profile_)->extension_service();
+ if (service) {
+ service->window_event_router()->OnActiveWindowChanged(
+ browser ? browser->extension_window_controller() : NULL);
}
-
- if (focused_window_id_ == window_id)
- return;
-
- // window_profile is either this profile's default profile, its
- // incognito profile, or NULL iff this profile is losing focus.
- Profile* previous_focused_profile = focused_profile_;
- focused_profile_ = window_profile;
- focused_window_id_ = window_id;
-
- ListValue real_args;
- real_args.Append(Value::CreateIntegerValue(window_id));
- std::string real_json_args;
- base::JSONWriter::Write(&real_args, &real_json_args);
-
- // When switching between windows in the default and incognitoi profiles,
- // dispatch WINDOW_ID_NONE to extensions whose profile lost focus that
- // can't see the new focused window across the incognito boundary.
- // See crbug.com/46610.
- std::string none_json_args;
- if (focused_profile_ != NULL && previous_focused_profile != NULL &&
- focused_profile_ != previous_focused_profile) {
- ListValue none_args;
- none_args.Append(
- Value::CreateIntegerValue(extension_misc::kUnknownWindowId));
- base::JSONWriter::Write(&none_args, &none_json_args);
- }
-
- DispatchEventsAcrossIncognito((focused_profile_ ? focused_profile_ :
- previous_focused_profile),
- events::kOnWindowFocusedChanged,
- real_json_args,
- none_json_args);
}
void BrowserEventRouter::TabCreatedAt(WebContents* contents,
@@ -556,13 +464,6 @@ void BrowserEventRouter::Observe(int type,
content::Source<NavigationController>(&contents->GetController()));
registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
content::Source<WebContents>(contents));
- } else if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) {
- Browser* browser = content::Source<Browser>(source).ptr();
- OnBrowserWindowReady(browser);
-#if defined(OS_MACOSX)
- } else if (type == chrome::NOTIFICATION_NO_KEY_WINDOW) {
- OnBrowserSetLastActive(NULL);
-#endif
} else {
NOTREACHED();
}
diff --git a/chrome/browser/extensions/browser_event_router.h b/chrome/browser/extensions/browser_event_router.h
index a82ced1..d9a48a3 100644
--- a/chrome/browser/extensions/browser_event_router.h
+++ b/chrome/browser/extensions/browser_event_router.h
@@ -15,11 +15,6 @@
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "content/public/browser/notification_registrar.h"
-#if defined(TOOLKIT_VIEWS)
-#include "ui/views/focus/widget_focus_manager.h"
-#elif defined(TOOLKIT_GTK)
-#include "ui/base/x/active_window_watcher_x_observer.h"
-#endif
namespace content {
class WebContents;
@@ -33,13 +28,8 @@ namespace extensions {
// events from windows/tabs within a profile to extension processes in the same
// profile.
class BrowserEventRouter : public TabStripModelObserver,
-#if defined(TOOLKIT_VIEWS)
- public views::WidgetFocusChangeListener,
-#elif defined(TOOLKIT_GTK)
- public ui::ActiveWindowWatcherXObserver,
-#endif
- public chrome::BrowserListObserver,
- public content::NotificationObserver {
+ public chrome::BrowserListObserver,
+ public content::NotificationObserver {
public:
explicit BrowserEventRouter(Profile* profile);
virtual ~BrowserEventRouter();
@@ -52,17 +42,6 @@ class BrowserEventRouter : public TabStripModelObserver,
virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
virtual void OnBrowserSetLastActive(Browser* browser) OVERRIDE;
-#if defined(TOOLKIT_VIEWS)
- virtual void OnNativeFocusChange(gfx::NativeView focused_before,
- gfx::NativeView focused_now) OVERRIDE;
-#elif defined(TOOLKIT_GTK)
- virtual void ActiveWindowChanged(GdkWindow* active_window) OVERRIDE;
-#endif
-
- // Called from Observe() on BROWSER_WINDOW_READY (not a part of
- // chrome::BrowserListObserver).
- void OnBrowserWindowReady(Browser* browser);
-
// TabStripModelObserver
virtual void TabInsertedAt(TabContents* contents, int index,
bool active) OVERRIDE;
@@ -229,15 +208,6 @@ class BrowserEventRouter : public TabStripModelObserver,
// The main profile that owns this event router.
Profile* profile_;
- // The profile the currently focused window belongs to; either the main or
- // incognito profile or NULL (none of the above). We remember this in order
- // to correctly handle focus changes between non-OTR and OTR windows.
- Profile* focused_profile_;
-
- // The currently focused window. We keep this so as to avoid sending multiple
- // windows.onFocusChanged events with the same windowId.
- int focused_window_id_;
-
DISALLOW_COPY_AND_ASSIGN(BrowserEventRouter);
};
diff --git a/chrome/browser/extensions/browser_extension_window_controller.cc b/chrome/browser/extensions/browser_extension_window_controller.cc
index 32f2900..54792bc 100644
--- a/chrome/browser/extensions/browser_extension_window_controller.cc
+++ b/chrome/browser/extensions/browser_extension_window_controller.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/window_controller_list.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/ui/browser.h"
@@ -17,6 +18,11 @@ BrowserExtensionWindowController::BrowserExtensionWindowController(
Browser* browser)
: extensions::WindowController(browser->window(), browser->profile()),
browser_(browser) {
+ extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this);
+}
+
+BrowserExtensionWindowController::~BrowserExtensionWindowController() {
+ extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
}
int BrowserExtensionWindowController::GetWindowId() const {
diff --git a/chrome/browser/extensions/browser_extension_window_controller.h b/chrome/browser/extensions/browser_extension_window_controller.h
index 61b7c80..9837422 100644
--- a/chrome/browser/extensions/browser_extension_window_controller.h
+++ b/chrome/browser/extensions/browser_extension_window_controller.h
@@ -12,6 +12,7 @@ class Browser;
class BrowserExtensionWindowController : public extensions::WindowController {
public:
explicit BrowserExtensionWindowController(Browser* browser);
+ virtual ~BrowserExtensionWindowController();
// extensions::WindowController implementation.
virtual int GetWindowId() const OVERRIDE;
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index c839a17..81d70f9 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -64,6 +64,7 @@
#include "chrome/browser/extensions/settings/settings_frontend.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
+#include "chrome/browser/extensions/window_event_router.h"
#include "chrome/browser/history/history_extension_api.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/prefs/pref_service.h"
@@ -471,6 +472,8 @@ void ExtensionService::InitEventRouters() {
history_event_router_->ObserveProfile(profile_);
browser_event_router_.reset(new extensions::BrowserEventRouter(profile_));
browser_event_router_->Init();
+ window_event_router_.reset(new extensions::WindowEventRouter(profile_));
+ window_event_router_->Init();
preference_event_router_.reset(new ExtensionPreferenceEventRouter(profile_));
bookmark_event_router_.reset(new BookmarkExtensionEventRouter(
profile_->GetBookmarkModel()));
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index e749119..68c1b34 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -67,27 +67,24 @@ class ExtensionInputMethodEventRouter;
}
namespace extensions {
-class ExtensionBrowserEventRouter;
-class ExtensionManagedModeEventRouter;
-}
-
-namespace syncer {
-class SyncData;
-class SyncErrorFactory;
-}
-
-namespace extensions {
class AppSyncData;
class BrowserEventRouter;
class ComponentLoader;
class ContentSettingsStore;
class Extension;
class ExtensionCookiesEventRouter;
+class ExtensionManagedModeEventRouter;
class ExtensionSyncData;
class ExtensionSystem;
class ExtensionUpdater;
class SettingsFrontend;
class WebNavigationEventRouter;
+class WindowEventRouter;
+}
+
+namespace syncer {
+class SyncData;
+class SyncErrorFactory;
}
// This is an interface class to encapsulate the dependencies that
@@ -505,6 +502,10 @@ class ExtensionService
return browser_event_router_.get();
}
+ extensions::WindowEventRouter* window_event_router() {
+ return window_event_router_.get();
+ }
+
#if defined(OS_CHROMEOS)
chromeos::ExtensionBluetoothEventRouter* bluetooth_event_router() {
return bluetooth_event_router_.get();
@@ -802,6 +803,8 @@ class ExtensionService
scoped_ptr<extensions::BrowserEventRouter> browser_event_router_;
+ scoped_ptr<extensions::WindowEventRouter> window_event_router_;
+
scoped_ptr<ExtensionPreferenceEventRouter> preference_event_router_;
scoped_ptr<BookmarkExtensionEventRouter> bookmark_event_router_;
diff --git a/chrome/browser/extensions/window_controller.cc b/chrome/browser/extensions/window_controller.cc
index 28e1e2e..a81e677 100644
--- a/chrome/browser/extensions/window_controller.cc
+++ b/chrome/browser/extensions/window_controller.cc
@@ -18,11 +18,9 @@ namespace extensions {
WindowController::WindowController(BaseWindow* window, Profile* profile)
: window_(window), profile_(profile) {
- WindowControllerList::GetInstance()->AddExtensionWindow(this);
}
WindowController::~WindowController() {
- WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
}
Browser* WindowController::GetBrowser() const {
diff --git a/chrome/browser/extensions/window_controller.h b/chrome/browser/extensions/window_controller.h
index 6e82bed..e6e4554 100644
--- a/chrome/browser/extensions/window_controller.h
+++ b/chrome/browser/extensions/window_controller.h
@@ -29,6 +29,8 @@ class Extension;
// This API needs to be implemented by any window that might be accessed
// through chrome.windows or chrome.tabs (e.g. browser windows and panels).
+// Subclasses must add/remove themselves from the WindowControllerList
+// upon construction/destruction.
class WindowController {
public:
enum Reason {
diff --git a/chrome/browser/extensions/window_controller_list.cc b/chrome/browser/extensions/window_controller_list.cc
index 0b221f7..0dfdffa 100644
--- a/chrome/browser/extensions/window_controller_list.cc
+++ b/chrome/browser/extensions/window_controller_list.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/window_controller_list_observer.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/ui/base_window.h"
@@ -28,13 +29,27 @@ WindowControllerList::~WindowControllerList() {
void WindowControllerList::AddExtensionWindow(WindowController* window) {
windows_.push_back(window);
+ FOR_EACH_OBSERVER(WindowControllerListObserver, observers_,
+ OnWindowControllerAdded(window));
}
void WindowControllerList::RemoveExtensionWindow(WindowController* window) {
ControllerList::iterator iter = std::find(
windows_.begin(), windows_.end(), window);
- if (iter != windows_.end())
+ if (iter != windows_.end()) {
windows_.erase(iter);
+ FOR_EACH_OBSERVER(WindowControllerListObserver, observers_,
+ OnWindowControllerRemoved(window));
+ }
+}
+
+void WindowControllerList::AddObserver(WindowControllerListObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void WindowControllerList::RemoveObserver(
+ WindowControllerListObserver* observer) {
+ observers_.RemoveObserver(observer);
}
WindowController* WindowControllerList::FindWindowForFunctionById(
diff --git a/chrome/browser/extensions/window_controller_list.h b/chrome/browser/extensions/window_controller_list.h
index 3c6915b..a32baf6 100644
--- a/chrome/browser/extensions/window_controller_list.h
+++ b/chrome/browser/extensions/window_controller_list.h
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/memory/singleton.h"
+#include "base/observer_list.h"
#include "chrome/browser/extensions/window_controller.h"
class Profile;
@@ -16,6 +17,8 @@ class UIThreadExtensionFunction;
namespace extensions {
+class WindowControllerListObserver;
+
// Class to maintain a list of WindowControllers.
class WindowControllerList {
public:
@@ -27,6 +30,9 @@ class WindowControllerList {
void AddExtensionWindow(WindowController* window);
void RemoveExtensionWindow(WindowController* window);
+ void AddObserver(WindowControllerListObserver* observer);
+ void RemoveObserver(WindowControllerListObserver* observer);
+
// Returns a window matching the context the function was invoked in.
WindowController* FindWindowForFunctionById(
const UIThreadExtensionFunction* function,
@@ -47,6 +53,8 @@ class WindowControllerList {
// Entries are not owned by this class and must be removed when destroyed.
ControllerList windows_;
+ ObserverList<WindowControllerListObserver> observers_;
+
DISALLOW_COPY_AND_ASSIGN(WindowControllerList);
};
diff --git a/chrome/browser/extensions/window_controller_list_observer.h b/chrome/browser/extensions/window_controller_list_observer.h
new file mode 100644
index 0000000..daa1a8e
--- /dev/null
+++ b/chrome/browser/extensions/window_controller_list_observer.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_WINDOW_CONTROLLER_LIST_OBSERVER_H_
+#define CHROME_BROWSER_EXTENSIONS_WINDOW_CONTROLLER_LIST_OBSERVER_H_
+
+namespace extensions {
+
+class WindowController;
+
+// Implementations must not change the contents of the WindowControllerList
+// inside any of these methods.
+class WindowControllerListObserver {
+ public:
+ // Called immediately after a window controller is added to the list
+ virtual void OnWindowControllerAdded(WindowController* window_controller) {}
+
+ // Called immediately after a window controller is removed from the list
+ virtual void OnWindowControllerRemoved(WindowController* window_controller) {}
+
+ protected:
+ virtual ~WindowControllerListObserver() {}
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_WINDOW_CONTROLLER_LIST_OBSERVER_H_
diff --git a/chrome/browser/extensions/window_event_router.cc b/chrome/browser/extensions/window_event_router.cc
new file mode 100644
index 0000000..3804d0c
--- /dev/null
+++ b/chrome/browser/extensions/window_event_router.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/window_event_router.h"
+
+#include "base/json/json_writer.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/event_names.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/extensions/window_controller_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "content/public/browser/notification_service.h"
+
+#if defined(TOOLKIT_GTK)
+#include "ui/base/x/active_window_watcher_x.h"
+#endif
+
+namespace event_names = extensions::event_names;
+
+namespace extensions {
+
+WindowEventRouter::WindowEventRouter(Profile* profile)
+ : initialized_(false),
+ profile_(profile),
+ focused_profile_(NULL),
+ focused_window_id_(extension_misc::kUnknownWindowId) {
+ DCHECK(!profile->IsOffTheRecord());
+}
+
+WindowEventRouter::~WindowEventRouter() {
+ if (initialized_) {
+ WindowControllerList::GetInstance()->RemoveObserver(this);
+#if defined(TOOLKIT_VIEWS)
+ views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
+#elif defined(TOOLKIT_GTK)
+ ui::ActiveWindowWatcherX::RemoveObserver(this);
+#endif
+ }
+}
+
+void WindowEventRouter::Init() {
+ if (initialized_)
+ return;
+
+ WindowControllerList::GetInstance()->AddObserver(this);
+#if defined(TOOLKIT_VIEWS)
+ views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
+#elif defined(TOOLKIT_GTK)
+ ui::ActiveWindowWatcherX::AddObserver(this);
+#elif defined(OS_MACOSX)
+ // Needed for when no suitable window can be passed to an extension as the
+ // currently focused window.
+ registrar_.Add(this, chrome::NOTIFICATION_NO_KEY_WINDOW,
+ content::NotificationService::AllSources());
+#endif
+
+ initialized_ = true;
+}
+
+void WindowEventRouter::OnWindowControllerAdded(
+ WindowController* window_controller) {
+ if (!profile_->IsSameProfile(window_controller->profile()))
+ return;
+
+ base::ListValue args;
+ DictionaryValue* window_dictionary = window_controller->CreateWindowValue();
+ args.Append(window_dictionary);
+ DispatchEvent(event_names::kOnWindowCreated, window_controller->profile(),
+ &args);
+}
+
+void WindowEventRouter::OnWindowControllerRemoved(
+ WindowController* window_controller) {
+ if (!profile_->IsSameProfile(window_controller->profile()))
+ return;
+
+ int window_id = window_controller->GetWindowId();
+ base::ListValue args;
+ args.Append(Value::CreateIntegerValue(window_id));
+ DispatchEvent(event_names::kOnWindowRemoved, window_controller->profile(),
+ &args);
+}
+
+#if defined(TOOLKIT_VIEWS)
+void WindowEventRouter::OnNativeFocusChange(
+ gfx::NativeView focused_before,
+ gfx::NativeView focused_now) {
+ if (!focused_now)
+ OnActiveWindowChanged(NULL);
+}
+#elif defined(TOOLKIT_GTK)
+void WindowEventRouter::ActiveWindowChanged(
+ GdkWindow* active_window) {
+ if (!active_window)
+ OnActiveWindowChanged(NULL);
+}
+#endif
+
+void WindowEventRouter::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+#if defined(OS_MACOSX)
+ if (chrome::NOTIFICATION_NO_KEY_WINDOW == type) {
+ OnActiveWindowChanged(NULL);
+ return;
+ }
+#endif
+}
+
+void WindowEventRouter::OnActiveWindowChanged(
+ WindowController* window_controller) {
+ Profile* window_profile = NULL;
+ int window_id = extension_misc::kUnknownWindowId;
+ if (window_controller &&
+ profile_->IsSameProfile(window_controller->profile())) {
+ window_profile = window_controller->profile();
+ window_id = window_controller->GetWindowId();
+ }
+
+ if (focused_window_id_ == window_id)
+ return;
+
+ // window_profile is either the default profile for the active window, its
+ // incognito profile, or NULL iff the previous profile is losing focus.
+ Profile* previous_focused_profile = focused_profile_;
+ focused_profile_ = window_profile;
+ focused_window_id_ = window_id;
+
+ base::ListValue real_args;
+ real_args.Append(Value::CreateIntegerValue(window_id));
+ std::string real_json_args;
+ base::JSONWriter::Write(&real_args, &real_json_args);
+
+ // When switching between windows in the default and incognitoi profiles,
+ // dispatch WINDOW_ID_NONE to extensions whose profile lost focus that
+ // can't see the new focused window across the incognito boundary.
+ // See crbug.com/46610.
+ std::string none_json_args;
+ if (focused_profile_ != NULL && previous_focused_profile != NULL &&
+ focused_profile_ != previous_focused_profile) {
+ ListValue none_args;
+ none_args.Append(
+ Value::CreateIntegerValue(extension_misc::kUnknownWindowId));
+ base::JSONWriter::Write(&none_args, &none_json_args);
+ }
+
+ if (!window_profile)
+ window_profile = previous_focused_profile;
+
+ ExtensionSystem::Get(window_profile)->event_router()->
+ DispatchEventsToRenderersAcrossIncognito(
+ event_names::kOnWindowFocusedChanged,
+ real_json_args,
+ window_profile,
+ none_json_args,
+ GURL());
+}
+
+void WindowEventRouter::DispatchEvent(const char* event_name,
+ Profile* profile,
+ base::ListValue* args) {
+ std::string json_args;
+ base::JSONWriter::Write(args, &json_args);
+ ExtensionSystem::Get(profile)->event_router()->
+ DispatchEventToRenderers(event_name, json_args, profile, GURL());
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/window_event_router.h b/chrome/browser/extensions/window_event_router.h
new file mode 100644
index 0000000..17ac0ff
--- /dev/null
+++ b/chrome/browser/extensions/window_event_router.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_WINDOW_EVENT_ROUTER_H_
+#define CHROME_BROWSER_EXTENSIONS_WINDOW_EVENT_ROUTER_H_
+
+#include "base/basictypes.h"
+#include "chrome/browser/extensions/window_controller_list_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#if defined(TOOLKIT_VIEWS)
+#include "ui/views/focus/widget_focus_manager.h"
+#elif defined(TOOLKIT_GTK)
+#include "ui/base/x/active_window_watcher_x_observer.h"
+#endif
+
+class Profile;
+
+namespace base {
+class ListValue;
+}
+
+namespace extensions {
+
+// The WindowEventRouter sends chrome.windows.* events to listeners
+// inside extension process renderers. The router listens to *all* events,
+// but will only route eventes within a profile to extension processes in the
+// same profile.
+class WindowEventRouter : public WindowControllerListObserver,
+#if defined(TOOLKIT_VIEWS)
+ public views::WidgetFocusChangeListener,
+#elif defined(TOOLKIT_GTK)
+ public ui::ActiveWindowWatcherXObserver,
+#endif
+ public content::NotificationObserver {
+ public:
+ explicit WindowEventRouter(Profile* profile);
+ virtual ~WindowEventRouter();
+
+ // Must be called once. Subsequent calls have no effect.
+ void Init();
+
+ // WindowControllerListObserver methods:
+ virtual void OnWindowControllerAdded(
+ WindowController* window_controller) OVERRIDE;
+ virtual void OnWindowControllerRemoved(
+ WindowController* window) OVERRIDE;
+
+#if defined(TOOLKIT_VIEWS)
+ virtual void OnNativeFocusChange(gfx::NativeView focused_before,
+ gfx::NativeView focused_now) OVERRIDE;
+#elif defined(TOOLKIT_GTK)
+ virtual void ActiveWindowChanged(GdkWindow* active_window) OVERRIDE;
+#endif
+
+ // content::NotificationObserver.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // |window_controller| is NULL to indicate a focused window has lost focus.
+ void OnActiveWindowChanged(WindowController* window_controller);
+
+ private:
+ void DispatchEvent(const char* event_name,
+ Profile* profile,
+ base::ListValue* args);
+
+ content::NotificationRegistrar registrar_;
+ bool initialized_;
+
+ // The main profile that owns this event router.
+ Profile* profile_;
+
+ // The profile the currently focused window belongs to; either the main or
+ // incognito profile or NULL (none of the above). We remember this in order
+ // to correctly handle focus changes between non-OTR and OTR windows.
+ Profile* focused_profile_;
+
+ // The currently focused window. We keep this so as to avoid sending multiple
+ // windows.onFocusChanged events with the same windowId.
+ int focused_window_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowEventRouter);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_WINDOW_EVENT_ROUTER_H_
diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc
index 835d745..a2e1eb0 100644
--- a/chrome/browser/ui/panels/panel.cc
+++ b/chrome/browser/ui/panels/panel.cc
@@ -9,7 +9,11 @@
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/extensions/window_controller_list.h"
+#include "chrome/browser/extensions/window_event_router.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/theme_service.h"
@@ -38,6 +42,7 @@ namespace panel_internal {
class PanelExtensionWindowController : public extensions::WindowController {
public:
PanelExtensionWindowController(Panel* panel, Profile* profile);
+ virtual ~PanelExtensionWindowController();
// Overridden from extensions::WindowController.
virtual int GetWindowId() const OVERRIDE;
@@ -58,6 +63,11 @@ PanelExtensionWindowController::PanelExtensionWindowController(
Panel* panel, Profile* profile)
: extensions::WindowController(panel, profile),
panel_(panel) {
+ extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this);
+}
+
+PanelExtensionWindowController::~PanelExtensionWindowController() {
+ extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
}
int PanelExtensionWindowController::GetWindowId() const {
@@ -618,6 +628,17 @@ void Panel::OnActiveStateChanged(bool active) {
if (panel_strip_)
panel_strip_->OnPanelActiveStateChanged(this);
+ // Send extension event about window becoming active.
+ // TODO(jennb): remove extension_window_controller_ guard after refactor.
+ if (active && extension_window_controller_.get()) {
+ ExtensionService* service =
+ extensions::ExtensionSystem::Get(profile())->extension_service();
+ if (service) {
+ service->window_event_router()->OnActiveWindowChanged(
+ extension_window_controller_.get());
+ }
+ }
+
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PANEL_CHANGED_ACTIVE_STATUS,
content::Source<Panel>(this),
diff --git a/chrome/browser/ui/panels/panel_cocoa.mm b/chrome/browser/ui/panels/panel_cocoa.mm
index eb38a92..4fbdb02 100644
--- a/chrome/browser/ui/panels/panel_cocoa.mm
+++ b/chrome/browser/ui/panels/panel_cocoa.mm
@@ -51,6 +51,12 @@ bool PanelCocoa::isClosed() {
void PanelCocoa::ShowPanel() {
ShowPanelInactive();
ActivatePanel();
+
+ // |-makeKeyAndOrderFront:| won't send |-windowDidBecomeKey:| until we
+ // return to the runloop. This causes extension tests that wait for the
+ // active status change notification to fail, so we send an active status
+ // notification here.
+ panel_->OnActiveStateChanged(true);
}
void PanelCocoa::ShowPanelInactive() {
diff --git a/chrome/browser/ui/views/ash/panel_view_aura.cc b/chrome/browser/ui/views/ash/panel_view_aura.cc
index 41d4eec..5e23291 100644
--- a/chrome/browser/ui/views/ash/panel_view_aura.cc
+++ b/chrome/browser/ui/views/ash/panel_view_aura.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/extensions/window_controller_list.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/ui/browser.h"
@@ -182,6 +183,7 @@ class PanelExtensionWindowController : public extensions::WindowController {
public:
PanelExtensionWindowController(PanelViewAura* panel_view,
PanelHost* panel_host);
+ virtual ~PanelExtensionWindowController();
// Overriden from extensions::WindowController:
virtual int GetWindowId() const OVERRIDE;
@@ -207,6 +209,11 @@ PanelExtensionWindowController::PanelExtensionWindowController(
: extensions::WindowController(panel_view, panel_host->profile()),
panel_view_(panel_view),
panel_host_(panel_host) {
+ extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this);
+}
+
+PanelExtensionWindowController::~PanelExtensionWindowController() {
+ extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
}
int PanelExtensionWindowController::GetWindowId() const {
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 20949c6..bc3cd9bf 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -515,6 +515,9 @@
'browser/extensions/window_controller.h',
'browser/extensions/window_controller_list.cc',
'browser/extensions/window_controller_list.h',
+ 'browser/extensions/window_controller_list_observer.h',
+ 'browser/extensions/window_event_router.cc',
+ 'browser/extensions/window_event_router.h',
],
'conditions': [
['chromeos==0', {
diff --git a/chrome/test/data/extensions/api_test/window_open/panel/test.js b/chrome/test/data/extensions/api_test/window_open/panel/test.js
index b8fb4b3..b9b9c26 100644
--- a/chrome/test/data/extensions/api_test/window_open/panel/test.js
+++ b/chrome/test/data/extensions/api_test/window_open/panel/test.js
@@ -4,6 +4,12 @@
chrome.test.runTests([
function openPanel() {
+ chrome.test.listenOnce(chrome.windows.onCreated, function(window) {
+ chrome.test.assertTrue(window.width > 0);
+ chrome.test.assertTrue(window.height > 0);
+ chrome.test.assertEq("panel", window.type);
+ chrome.test.assertTrue(!window.incognito);
+ });
chrome.windows.create(
{ 'url': 'about:blank', 'type': 'panel' },
chrome.test.callbackPass(function(win) {