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