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