1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
// 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/api/tabs/windows_event_router.h"
#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_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/common/extensions/api/windows.h"
#include "chrome/common/extensions/extension_constants.h"
#include "content/public/browser/notification_service.h"
#include "extensions/browser/event_router.h"
#include "extensions/common/constants.h"
using content::BrowserContext;
namespace extensions {
namespace windows = extensions::api::windows;
WindowsEventRouter::WindowsEventRouter(Profile* profile)
: profile_(profile),
focused_profile_(NULL),
focused_window_id_(extension_misc::kUnknownWindowId) {
DCHECK(!profile->IsOffTheRecord());
WindowControllerList::GetInstance()->AddObserver(this);
// Needed for when no suitable window can be passed to an extension as the
// currently focused window. On Mac (even in a toolkit-views build) always
// rely on the notification sent by AppControllerMac after AppKit sends
// NSWindowDidBecomeKeyNotification and there is no [NSApp keyWindow]. This
// allows windows not created by toolkit-views to be tracked.
// TODO(tapted): Remove the ifdefs (and NOTIFICATION_NO_KEY_WINDOW) when
// Chrome on Mac only makes windows with toolkit-views.
#if defined(OS_MACOSX)
registrar_.Add(this, chrome::NOTIFICATION_NO_KEY_WINDOW,
content::NotificationService::AllSources());
#elif defined(TOOLKIT_VIEWS)
views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
#else
#error Unsupported
#endif
}
WindowsEventRouter::~WindowsEventRouter() {
WindowControllerList::GetInstance()->RemoveObserver(this);
#if !defined(OS_MACOSX)
views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
#endif
}
void WindowsEventRouter::OnWindowControllerAdded(
WindowController* window_controller) {
if (!profile_->IsSameProfile(window_controller->profile()))
return;
scoped_ptr<base::ListValue> args(new base::ListValue());
base::DictionaryValue* window_dictionary =
window_controller->CreateWindowValue();
args->Append(window_dictionary);
DispatchEvent(windows::OnCreated::kEventName, window_controller->profile(),
args.Pass());
}
void WindowsEventRouter::OnWindowControllerRemoved(
WindowController* window_controller) {
if (!profile_->IsSameProfile(window_controller->profile()))
return;
int window_id = window_controller->GetWindowId();
scoped_ptr<base::ListValue> args(new base::ListValue());
args->Append(new base::FundamentalValue(window_id));
DispatchEvent(windows::OnRemoved::kEventName,
window_controller->profile(),
args.Pass());
}
#if !defined(OS_MACOSX)
void WindowsEventRouter::OnNativeFocusChange(
gfx::NativeView focused_before,
gfx::NativeView focused_now) {
if (!focused_now)
OnActiveWindowChanged(NULL);
}
#endif
void WindowsEventRouter::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
}
static bool WillDispatchWindowFocusedEvent(BrowserContext* new_active_context,
int window_id,
BrowserContext* context,
const Extension* extension,
base::ListValue* event_args) {
// When switching between windows in the default and incognito 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.
if (new_active_context && new_active_context != context &&
!util::CanCrossIncognito(extension, context)) {
event_args->Clear();
event_args->Append(new base::FundamentalValue(
extension_misc::kUnknownWindowId));
} else {
event_args->Clear();
event_args->Append(new base::FundamentalValue(window_id));
}
return true;
}
void WindowsEventRouter::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.
focused_profile_ = window_profile;
focused_window_id_ = window_id;
scoped_ptr<Event> event(new Event(windows::OnFocusChanged::kEventName,
make_scoped_ptr(new base::ListValue())));
event->will_dispatch_callback =
base::Bind(&WillDispatchWindowFocusedEvent,
static_cast<BrowserContext*>(window_profile),
window_id);
EventRouter::Get(profile_)->BroadcastEvent(event.Pass());
}
void WindowsEventRouter::DispatchEvent(const std::string& event_name,
Profile* profile,
scoped_ptr<base::ListValue> args) {
scoped_ptr<Event> event(new Event(event_name, args.Pass()));
event->restrict_to_browser_context = profile;
EventRouter::Get(profile)->BroadcastEvent(event.Pass());
}
} // namespace extensions
|