diff options
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) { |