Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / extensions / api / tabs / windows_event_router.cc
blob8ef6ce439b3b118ed901a70d06e8a2709f3e7557
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.
5 #include "chrome/browser/extensions/api/tabs/windows_event_router.h"
7 #include "base/values.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/extensions/api/tabs/app_base_window.h"
10 #include "chrome/browser/extensions/api/tabs/app_window_controller.h"
11 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
12 #include "chrome/browser/extensions/api/tabs/windows_util.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/extensions/extension_util.h"
15 #include "chrome/browser/extensions/window_controller.h"
16 #include "chrome/browser/extensions/window_controller_list.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/extensions/api/windows.h"
19 #include "chrome/common/extensions/extension_constants.h"
20 #include "content/public/browser/notification_service.h"
21 #include "extensions/browser/app_window/app_window.h"
22 #include "extensions/browser/event_router.h"
23 #include "extensions/common/constants.h"
25 using content::BrowserContext;
27 namespace extensions {
29 namespace keys = extensions::tabs_constants;
30 namespace windows = extensions::api::windows;
32 namespace {
34 bool ControllerVisibleToListener(WindowController* window_controller,
35 const Extension* extension,
36 const base::DictionaryValue* listener_filter) {
37 if (!window_controller)
38 return false;
40 // If there is no filter the visibility is based on the extension.
41 const base::ListValue* filter_value = nullptr;
42 if (!listener_filter ||
43 !listener_filter->GetList(keys::kWindowTypesKey, &filter_value))
44 return window_controller->IsVisibleToExtension(extension);
46 // Otherwise it's based on the type filter.
47 WindowController::TypeFilter filter =
48 WindowController::GetFilterFromWindowTypesValues(filter_value);
49 return window_controller->MatchesFilter(filter);
52 bool WillDispatchWindowEvent(WindowController* window_controller,
53 BrowserContext* context,
54 const Extension* extension,
55 Event* event,
56 const base::DictionaryValue* listener_filter) {
57 bool has_filter =
58 listener_filter && listener_filter->HasKey(keys::kWindowTypesKey);
59 // Cleanup previous values.
60 event->filter_info = EventFilteringInfo();
61 // Only set the window type if the listener has set a filter.
62 // Otherwise we set the window visibility relative to the extension.
63 if (has_filter)
64 event->filter_info.SetWindowType(window_controller->GetWindowTypeText());
65 else
66 event->filter_info.SetWindowExposedByDefault(
67 window_controller->IsVisibleToExtension(extension));
68 return true;
71 bool WillDispatchWindowFocusedEvent(
72 WindowController* window_controller,
73 BrowserContext* context,
74 const Extension* extension,
75 Event* event,
76 const base::DictionaryValue* listener_filter) {
77 int window_id = extension_misc::kUnknownWindowId;
78 Profile* new_active_context = nullptr;
79 bool has_filter =
80 listener_filter && listener_filter->HasKey(keys::kWindowTypesKey);
82 // We might not have a window controller if the focus moves away
83 // from chromium's windows.
84 if (window_controller) {
85 window_id = window_controller->GetWindowId();
86 new_active_context = window_controller->profile();
89 // Cleanup previous values.
90 event->filter_info = EventFilteringInfo();
91 // Only set the window type if the listener has set a filter,
92 // otherwise set the visibility to true (if the window is not
93 // supposed to be visible by the extension, we will clear out the
94 // window id later).
95 if (has_filter)
96 event->filter_info.SetWindowType(
97 window_controller ? window_controller->GetWindowTypeText()
98 : keys::kWindowTypeValueNormal);
99 else
100 event->filter_info.SetWindowExposedByDefault(true);
102 // When switching between windows in the default and incognito profiles,
103 // dispatch WINDOW_ID_NONE to extensions whose profile lost focus that
104 // can't see the new focused window across the incognito boundary.
105 // See crbug.com/46610.
106 bool cant_cross_incognito = new_active_context &&
107 new_active_context != context &&
108 !util::CanCrossIncognito(extension, context);
109 // If the window is not visible by the listener, we also need to
110 // clear out the window id from the event.
111 bool visible_to_listener = ControllerVisibleToListener(
112 window_controller, extension, listener_filter);
114 if (cant_cross_incognito || !visible_to_listener) {
115 event->event_args->Clear();
116 event->event_args->Append(
117 new base::FundamentalValue(extension_misc::kUnknownWindowId));
118 } else {
119 event->event_args->Clear();
120 event->event_args->Append(new base::FundamentalValue(window_id));
122 return true;
125 } // namespace
127 WindowsEventRouter::WindowsEventRouter(Profile* profile)
128 : profile_(profile),
129 focused_profile_(nullptr),
130 focused_window_id_(extension_misc::kUnknownWindowId),
131 observed_app_registry_(this),
132 observed_controller_list_(this) {
133 DCHECK(!profile->IsOffTheRecord());
135 observed_app_registry_.Add(AppWindowRegistry::Get(profile_));
136 observed_controller_list_.Add(WindowControllerList::GetInstance());
137 // Needed for when no suitable window can be passed to an extension as the
138 // currently focused window. On Mac (even in a toolkit-views build) always
139 // rely on the notification sent by AppControllerMac after AppKit sends
140 // NSWindowDidBecomeKeyNotification and there is no [NSApp keyWindo7w]. This
141 // allows windows not created by toolkit-views to be tracked.
142 // TODO(tapted): Remove the ifdefs (and NOTIFICATION_NO_KEY_WINDOW) when
143 // Chrome on Mac only makes windows with toolkit-views.
144 #if defined(OS_MACOSX)
145 registrar_.Add(this, chrome::NOTIFICATION_NO_KEY_WINDOW,
146 content::NotificationService::AllSources());
147 #elif defined(TOOLKIT_VIEWS)
148 views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
149 #else
150 #error Unsupported
151 #endif
153 AppWindowRegistry* registry = AppWindowRegistry::Get(profile_);
154 for (AppWindow* app_window : registry->app_windows())
155 AddAppWindow(app_window);
158 WindowsEventRouter::~WindowsEventRouter() {
159 #if !defined(OS_MACOSX)
160 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
161 #endif
164 void WindowsEventRouter::OnAppWindowAdded(extensions::AppWindow* app_window) {
165 if (!profile_->IsSameProfile(
166 Profile::FromBrowserContext(app_window->browser_context())))
167 return;
168 AddAppWindow(app_window);
171 void WindowsEventRouter::OnAppWindowRemoved(extensions::AppWindow* app_window) {
172 if (!profile_->IsSameProfile(
173 Profile::FromBrowserContext(app_window->browser_context())))
174 return;
176 scoped_ptr<WindowController> controller =
177 app_windows_.take_and_erase(app_window->session_id().id());
180 void WindowsEventRouter::OnAppWindowActivated(
181 extensions::AppWindow* app_window) {
182 AppWindowMap::const_iterator iter =
183 app_windows_.find(app_window->session_id().id());
184 OnActiveWindowChanged(iter != app_windows_.end() ? iter->second : nullptr);
187 void WindowsEventRouter::OnWindowControllerAdded(
188 WindowController* window_controller) {
189 if (!HasEventListener(windows::OnCreated::kEventName))
190 return;
191 if (!profile_->IsSameProfile(window_controller->profile()))
192 return;
194 scoped_ptr<base::ListValue> args(new base::ListValue());
195 base::DictionaryValue* window_dictionary =
196 window_controller->CreateWindowValue();
197 args->Append(window_dictionary);
198 DispatchEvent(events::WINDOWS_ON_CREATED, windows::OnCreated::kEventName,
199 window_controller, args.Pass());
202 void WindowsEventRouter::OnWindowControllerRemoved(
203 WindowController* window_controller) {
204 if (!HasEventListener(windows::OnRemoved::kEventName))
205 return;
206 if (!profile_->IsSameProfile(window_controller->profile()))
207 return;
209 int window_id = window_controller->GetWindowId();
210 scoped_ptr<base::ListValue> args(new base::ListValue());
211 args->Append(new base::FundamentalValue(window_id));
212 DispatchEvent(events::WINDOWS_ON_REMOVED, windows::OnRemoved::kEventName,
213 window_controller, args.Pass());
216 #if !defined(OS_MACOSX)
217 void WindowsEventRouter::OnNativeFocusChanged(gfx::NativeView focused_now) {
218 if (!focused_now)
219 OnActiveWindowChanged(nullptr);
221 #endif
223 void WindowsEventRouter::Observe(
224 int type,
225 const content::NotificationSource& source,
226 const content::NotificationDetails& details) {
227 #if defined(OS_MACOSX)
228 if (chrome::NOTIFICATION_NO_KEY_WINDOW == type) {
229 OnActiveWindowChanged(nullptr);
230 return;
232 #endif
235 void WindowsEventRouter::OnActiveWindowChanged(
236 WindowController* window_controller) {
237 Profile* window_profile = nullptr;
238 int window_id = extension_misc::kUnknownWindowId;
239 if (window_controller &&
240 profile_->IsSameProfile(window_controller->profile())) {
241 window_profile = window_controller->profile();
242 window_id = window_controller->GetWindowId();
245 if (focused_window_id_ == window_id)
246 return;
248 // window_profile is either the default profile for the active window, its
249 // incognito profile, or nullptr if the previous profile is losing focus.
250 focused_profile_ = window_profile;
251 focused_window_id_ = window_id;
253 if (!HasEventListener(windows::OnFocusChanged::kEventName))
254 return;
256 scoped_ptr<Event> event(new Event(events::WINDOWS_ON_FOCUS_CHANGED,
257 windows::OnFocusChanged::kEventName,
258 make_scoped_ptr(new base::ListValue())));
259 event->will_dispatch_callback =
260 base::Bind(&WillDispatchWindowFocusedEvent, window_controller);
261 EventRouter::Get(profile_)->BroadcastEvent(event.Pass());
264 void WindowsEventRouter::DispatchEvent(events::HistogramValue histogram_value,
265 const std::string& event_name,
266 WindowController* window_controller,
267 scoped_ptr<base::ListValue> args) {
268 scoped_ptr<Event> event(new Event(histogram_value, event_name, args.Pass()));
269 event->restrict_to_browser_context = window_controller->profile();
270 event->will_dispatch_callback =
271 base::Bind(&WillDispatchWindowEvent, window_controller);
272 EventRouter::Get(profile_)->BroadcastEvent(event.Pass());
275 bool WindowsEventRouter::HasEventListener(const std::string& event_name) {
276 return EventRouter::Get(profile_)->HasEventListener(event_name);
279 void WindowsEventRouter::AddAppWindow(extensions::AppWindow* app_window) {
280 scoped_ptr<AppWindowController> controller(new AppWindowController(
281 app_window, make_scoped_ptr(new AppBaseWindow(app_window)), profile_));
282 app_windows_.set(app_window->session_id().id(), controller.Pass());
285 } // namespace extensions