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. 4 5#include "chrome/browser/extensions/api/tabs/windows_event_router.h" 6 7#include "base/values.h" 8#include "chrome/browser/chrome_notification_types.h" 9#include "chrome/browser/extensions/extension_service.h" 10#include "chrome/browser/extensions/extension_util.h" 11#include "chrome/browser/extensions/window_controller.h" 12#include "chrome/browser/extensions/window_controller_list.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/common/extensions/api/windows.h" 15#include "chrome/common/extensions/extension_constants.h" 16#include "content/public/browser/notification_service.h" 17#include "extensions/browser/event_router.h" 18#include "extensions/common/constants.h" 19 20using content::BrowserContext; 21 22namespace extensions { 23 24namespace windows = extensions::api::windows; 25 26WindowsEventRouter::WindowsEventRouter(Profile* profile) 27 : profile_(profile), 28 focused_profile_(NULL), 29 focused_window_id_(extension_misc::kUnknownWindowId) { 30 DCHECK(!profile->IsOffTheRecord()); 31 32 WindowControllerList::GetInstance()->AddObserver(this); 33#if defined(TOOLKIT_VIEWS) 34 views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); 35#elif defined(OS_MACOSX) 36 // Needed for when no suitable window can be passed to an extension as the 37 // currently focused window. 38 registrar_.Add(this, chrome::NOTIFICATION_NO_KEY_WINDOW, 39 content::NotificationService::AllSources()); 40#endif 41} 42 43WindowsEventRouter::~WindowsEventRouter() { 44 WindowControllerList::GetInstance()->RemoveObserver(this); 45#if defined(TOOLKIT_VIEWS) 46 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); 47#endif 48} 49 50void WindowsEventRouter::OnWindowControllerAdded( 51 WindowController* window_controller) { 52 if (!profile_->IsSameProfile(window_controller->profile())) 53 return; 54 55 scoped_ptr<base::ListValue> args(new base::ListValue()); 56 base::DictionaryValue* window_dictionary = 57 window_controller->CreateWindowValue(); 58 args->Append(window_dictionary); 59 DispatchEvent(windows::OnCreated::kEventName, window_controller->profile(), 60 args.Pass()); 61} 62 63void WindowsEventRouter::OnWindowControllerRemoved( 64 WindowController* window_controller) { 65 if (!profile_->IsSameProfile(window_controller->profile())) 66 return; 67 68 int window_id = window_controller->GetWindowId(); 69 scoped_ptr<base::ListValue> args(new base::ListValue()); 70 args->Append(new base::FundamentalValue(window_id)); 71 DispatchEvent(windows::OnRemoved::kEventName, 72 window_controller->profile(), 73 args.Pass()); 74} 75 76#if defined(TOOLKIT_VIEWS) 77void WindowsEventRouter::OnNativeFocusChange( 78 gfx::NativeView focused_before, 79 gfx::NativeView focused_now) { 80 if (!focused_now) 81 OnActiveWindowChanged(NULL); 82} 83#endif 84 85void WindowsEventRouter::Observe( 86 int type, 87 const content::NotificationSource& source, 88 const content::NotificationDetails& details) { 89#if defined(OS_MACOSX) 90 if (chrome::NOTIFICATION_NO_KEY_WINDOW == type) { 91 OnActiveWindowChanged(NULL); 92 return; 93 } 94#endif 95} 96 97static void WillDispatchWindowFocusedEvent(BrowserContext* new_active_context, 98 int window_id, 99 BrowserContext* context, 100 const Extension* extension, 101 base::ListValue* event_args) { 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 if (new_active_context && new_active_context != context && 107 !util::CanCrossIncognito(extension, context)) { 108 event_args->Clear(); 109 event_args->Append(new base::FundamentalValue( 110 extension_misc::kUnknownWindowId)); 111 } else { 112 event_args->Clear(); 113 event_args->Append(new base::FundamentalValue(window_id)); 114 } 115} 116 117void WindowsEventRouter::OnActiveWindowChanged( 118 WindowController* window_controller) { 119 Profile* window_profile = NULL; 120 int window_id = extension_misc::kUnknownWindowId; 121 if (window_controller && 122 profile_->IsSameProfile(window_controller->profile())) { 123 window_profile = window_controller->profile(); 124 window_id = window_controller->GetWindowId(); 125 } 126 127 if (focused_window_id_ == window_id) 128 return; 129 130 // window_profile is either the default profile for the active window, its 131 // incognito profile, or NULL iff the previous profile is losing focus. 132 focused_profile_ = window_profile; 133 focused_window_id_ = window_id; 134 135 scoped_ptr<Event> event(new Event(windows::OnFocusChanged::kEventName, 136 make_scoped_ptr(new base::ListValue()))); 137 event->will_dispatch_callback = 138 base::Bind(&WillDispatchWindowFocusedEvent, 139 static_cast<BrowserContext*>(window_profile), 140 window_id); 141 EventRouter::Get(profile_)->BroadcastEvent(event.Pass()); 142} 143 144void WindowsEventRouter::DispatchEvent(const std::string& event_name, 145 Profile* profile, 146 scoped_ptr<base::ListValue> args) { 147 scoped_ptr<Event> event(new Event(event_name, args.Pass())); 148 event->restrict_to_browser_context = profile; 149 EventRouter::Get(profile)->BroadcastEvent(event.Pass()); 150} 151 152} // namespace extensions 153