Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: chrome/browser/extensions/extension_popup_host.cc

Issue 1001002: Initial support for inspecting extension popups. (Closed)
Patch Set: pre submit Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2009 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/extension_popup_host.h"
6
7 #include "base/message_loop.h"
8 #if defined(TOOLKIT_VIEWS)
9 #include "chrome/browser/extensions/extension_popup_api.h"
10 #endif
11 #include "chrome/browser/profile.h"
12 #include "chrome/browser/browser.h"
13 #include "chrome/browser/renderer_host/render_view_host.h"
14 #include "chrome/browser/renderer_host/render_widget_host_view.h"
15 #if defined(TOOLKIT_VIEWS)
16 #include "chrome/browser/views/extensions/extension_popup.h"
17 #endif
18 #include "chrome/common/notification_details.h"
19 #include "chrome/common/notification_source.h"
20 #include "chrome/common/notification_type.h"
21 #if defined(TOOLKIT_VIEWS)
22 #include "views/focus/focus_manager.h"
23 #include "views/widget/root_view.h"
24 #endif
25
26 #if defined(TOOLKIT_VIEWS)
27 // A helper class that monitors native focus change events. Because the views
28 // FocusManager does not listen for view-change notification across
29 // native-windows, we need to use native-listener utilities.
30 class ExtensionPopupHost::PopupFocusListener
31 : public views::WidgetFocusChangeListener {
32 public:
33 // Constructs and registers a new PopupFocusListener for the given
34 // |popup_host|.
35 explicit PopupFocusListener(ExtensionPopupHost* popup_host)
36 : popup_host_(popup_host) {
37 views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this);
38 }
39
40 virtual ~PopupFocusListener() {
41 views::FocusManager::GetWidgetFocusManager()->
42 RemoveFocusChangeListener(this);
43 }
44
45 virtual void NativeFocusWillChange(gfx::NativeView focused_before,
46 gfx::NativeView focused_now) {
47 // If no view is to be focused, then Chrome was deactivated, so hide the
48 // popup.
49 if (!focused_now) {
50 popup_host_->DismissPopupAsync();
51 return;
52 }
53
54 gfx::NativeView host_view = popup_host_->delegate()->GetNativeViewOfHost();
55
56 // If the widget hosting the popup contains the newly focused view, then
57 // don't dismiss the pop-up.
58 views::Widget* popup_root_widget =
59 popup_host_->child_popup()->host()->view()->GetWidget();
60 if (popup_root_widget &&
61 popup_root_widget->ContainsNativeView(focused_now)) {
62 return;
63 }
64
65 // If the widget or RenderWidgetHostView hosting the extension that
66 // launched the pop-up is receiving focus, then don't dismiss the popup.
67 views::Widget* host_widget =
68 views::Widget::GetWidgetFromNativeView(host_view);
69 if (host_widget && host_widget->ContainsNativeView(focused_now)) {
70 return;
71 }
72
73 RenderWidgetHostView* render_host_view =
74 RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView(
75 host_view);
76 if (render_host_view &&
77 render_host_view->ContainsNativeView(focused_now)) {
78 return;
79 }
80
81 popup_host_->DismissPopupAsync();
82 }
83
84 private:
85 ExtensionPopupHost* popup_host_;
86 DISALLOW_COPY_AND_ASSIGN(PopupFocusListener);
87 };
88 #endif // if defined(TOOLKIT_VIEWS)
89
90
91 ExtensionPopupHost::PopupDelegate::~PopupDelegate() {
92 // If the PopupDelegate is being torn down, then make sure to reset the
93 // cached pointer in the host to prevent access to a stale pointer.
94 if (popup_host_.get())
95 popup_host_->RevokeDelegate();
96 }
97
98 ExtensionPopupHost* ExtensionPopupHost::PopupDelegate::popup_host() {
99 if (!popup_host_.get())
100 popup_host_.reset(new ExtensionPopupHost(this));
101
102 return popup_host_.get();
103 }
104
105 Profile* ExtensionPopupHost::PopupDelegate::GetProfile() {
106 // If there is a browser present, return the profile associated with it.
107 // When hosting a view in an ExternalTabContainer, it is possible to have
108 // no Browser instance.
109 Browser* browser = GetBrowser();
110 if (browser) {
111 return browser->profile();
112 }
113
114 return NULL;
115 }
116
117 ExtensionPopupHost::ExtensionPopupHost(PopupDelegate* delegate)
118 : // NO LINT
119 #if defined(TOOLKIT_VIEWS)
120 listener_(NULL),
121 child_popup_(NULL),
122 #endif
123 delegate_(delegate),
124 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
125 DCHECK(delegate_);
126
127 // Listen for view close requests, so that we can dismiss a hosted pop-up
128 // view, if necessary.
129 Profile* profile = delegate_->GetProfile();
130 DCHECK(profile);
131 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
132 Source<Profile>(profile));
133 }
134
135 ExtensionPopupHost::~ExtensionPopupHost() {
136 DismissPopup();
137 }
138
139 #if defined(TOOLKIT_VIEWS)
140 void ExtensionPopupHost::set_child_popup(ExtensionPopup* popup) {
141 // An extension may only have one popup active at a given time.
142 DismissPopup();
143 if (popup)
144 listener_.reset(new PopupFocusListener(this));
145
146 child_popup_ = popup;
147 }
148
149 void ExtensionPopupHost::BubbleBrowserWindowMoved(BrowserBubble* bubble) {
150 DismissPopupAsync();
151 }
152
153 void ExtensionPopupHost::BubbleBrowserWindowClosing(BrowserBubble* bubble) {
154 DismissPopupAsync();
155 }
156 #endif // defined(TOOLKIT_VIEWS)
157
158 void ExtensionPopupHost::Observe(NotificationType type,
159 const NotificationSource& source,
160 const NotificationDetails& details) {
161 if (type == NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE) {
162 #if defined(TOOLKIT_VIEWS)
163 // If we aren't the host of the popup, then disregard the notification.
164 if (!child_popup_ ||
165 Details<ExtensionHost>(child_popup_->host()) != details) {
166 return;
167 }
168 DismissPopup();
169 #endif
170 } else {
171 NOTREACHED();
172 }
173 }
174
175 void ExtensionPopupHost::DismissPopup() {
176 #if defined(TOOLKIT_VIEWS)
177 listener_.reset(NULL);
178 if (child_popup_) {
179 child_popup_->Hide();
180 child_popup_->DetachFromBrowser();
181 delete child_popup_;
182 child_popup_ = NULL;
183
184 if (delegate_) {
185 PopupEventRouter::OnPopupClosed(
186 delegate_->GetProfile(),
187 delegate_->GetRenderViewHost()->routing_id());
188 }
189 }
190 #endif // defined(TOOLKIT_VIEWS)
191 }
192
193 void ExtensionPopupHost::DismissPopupAsync() {
194 // Dismiss the popup asynchronously, as we could be deep in a message loop
195 // processing activations, and the focus manager may get confused if the
196 // currently focused view is destroyed.
197 method_factory_.RevokeAll();
198 MessageLoop::current()->PostNonNestableTask(
199 FROM_HERE,
200 method_factory_.NewRunnableMethod(
201 &ExtensionPopupHost::DismissPopup));
202 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_popup_host.h ('k') | chrome/browser/gtk/browser_actions_toolbar_gtk.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698