15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/tabs/windows_event_router.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/extensions/extension_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/window_controller.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/window_controller_list.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/extensions/api/windows.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/constants.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using content::BrowserContext;
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace windows = extensions::api::windows;
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WindowsEventRouter::WindowsEventRouter(Profile* profile)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(profile),
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      focused_profile_(NULL),
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      focused_window_id_(extension_misc::kUnknownWindowId) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!profile->IsOffTheRecord());
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WindowControllerList::GetInstance()->AddObserver(this);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_VIEWS)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Needed for when no suitable window can be passed to an extension as the
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently focused window.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_NO_KEY_WINDOW,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::NotificationService::AllSources());
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WindowsEventRouter::~WindowsEventRouter() {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WindowControllerList::GetInstance()->RemoveObserver(this);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_VIEWS)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WindowsEventRouter::OnWindowControllerAdded(
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WindowController* window_controller) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!profile_->IsSameProfile(window_controller->profile()))
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::ListValue> args(new base::ListValue());
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* window_dictionary =
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      window_controller->CreateWindowValue();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(window_dictionary);
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DispatchEvent(windows::OnCreated::kEventName, window_controller->profile(),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                args.Pass());
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WindowsEventRouter::OnWindowControllerRemoved(
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WindowController* window_controller) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!profile_->IsSameProfile(window_controller->profile()))
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int window_id = window_controller->GetWindowId();
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::ListValue> args(new base::ListValue());
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  args->Append(new base::FundamentalValue(window_id));
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DispatchEvent(windows::OnRemoved::kEventName,
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                window_controller->profile(),
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                args.Pass());
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_VIEWS)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WindowsEventRouter::OnNativeFocusChange(
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::NativeView focused_before,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::NativeView focused_now) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!focused_now)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnActiveWindowChanged(NULL);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WindowsEventRouter::Observe(
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationSource& source,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationDetails& details) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (chrome::NOTIFICATION_NO_KEY_WINDOW == type) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OnActiveWindowChanged(NULL);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)static void WillDispatchWindowFocusedEvent(BrowserContext* new_active_context,
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           int window_id,
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                           BrowserContext* context,
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           const Extension* extension,
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                           base::ListValue* event_args) {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When switching between windows in the default and incognito profiles,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // dispatch WINDOW_ID_NONE to extensions whose profile lost focus that
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // can't see the new focused window across the incognito boundary.
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See crbug.com/46610.
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (new_active_context && new_active_context != context &&
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !util::CanCrossIncognito(extension, context)) {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event_args->Clear();
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    event_args->Append(new base::FundamentalValue(
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extension_misc::kUnknownWindowId));
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event_args->Clear();
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    event_args->Append(new base::FundamentalValue(window_id));
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WindowsEventRouter::OnActiveWindowChanged(
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WindowController* window_controller) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* window_profile = NULL;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int window_id = extension_misc::kUnknownWindowId;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (window_controller &&
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_->IsSameProfile(window_controller->profile())) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window_profile = window_controller->profile();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window_id = window_controller->GetWindowId();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (focused_window_id_ == window_id)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // window_profile is either the default profile for the active window, its
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // incognito profile, or NULL iff the previous profile is losing focus.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  focused_profile_ = window_profile;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  focused_window_id_ = window_id;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_ptr<Event> event(new Event(windows::OnFocusChanged::kEventName,
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                    make_scoped_ptr(new base::ListValue())));
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->will_dispatch_callback =
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(&WillDispatchWindowFocusedEvent,
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 static_cast<BrowserContext*>(window_profile),
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 window_id);
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter::Get(profile_)->BroadcastEvent(event.Pass());
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void WindowsEventRouter::DispatchEvent(const std::string& event_name,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      Profile* profile,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      scoped_ptr<base::ListValue> args) {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  event->restrict_to_browser_context = profile;
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter::Get(profile)->BroadcastEvent(event.Pass());
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
153