OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_popup_api.h" | 5 #include "chrome/browser/extensions/extension_popup_api.h" |
6 | 6 |
7 #include "base/json/json_writer.h" | 7 #include "base/json/json_writer.h" |
8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
9 #include "chrome/common/extensions/extension.h" | 9 #include "chrome/common/extensions/extension.h" |
10 #include "chrome/common/notification_details.h" | 10 #include "chrome/common/notification_details.h" |
11 #include "chrome/common/notification_service.h" | 11 #include "chrome/common/notification_service.h" |
12 #include "chrome/common/notification_source.h" | 12 #include "chrome/common/notification_source.h" |
13 #include "chrome/common/notification_type.h" | 13 #include "chrome/common/notification_type.h" |
14 #include "chrome/common/url_constants.h" | 14 #include "chrome/common/url_constants.h" |
15 #include "chrome/browser/extensions/extension_dom_ui.h" | 15 #include "chrome/browser/extensions/extension_dom_ui.h" |
16 #include "chrome/browser/extensions/extension_host.h" | 16 #include "chrome/browser/extensions/extension_host.h" |
17 #include "chrome/browser/extensions/extension_message_service.h" | 17 #include "chrome/browser/extensions/extension_message_service.h" |
18 #include "chrome/browser/browser.h" | 18 #include "chrome/browser/browser.h" |
19 #include "chrome/browser/profile.h" | 19 #include "chrome/browser/profile.h" |
20 #include "chrome/browser/tab_contents/tab_contents.h" | 20 #include "chrome/browser/tab_contents/tab_contents.h" |
21 #include "gfx/point.h" | 21 #include "gfx/point.h" |
22 | 22 |
23 #if defined(TOOLKIT_VIEWS) | 23 #if defined(TOOLKIT_VIEWS) |
| 24 #include "chrome/browser/renderer_host/render_view_host.h" |
| 25 #include "chrome/browser/renderer_host/render_widget_host_view.h" |
24 #include "chrome/browser/views/extensions/extension_popup.h" | 26 #include "chrome/browser/views/extensions/extension_popup.h" |
25 #include "views/view.h" | 27 #include "views/view.h" |
26 #endif | 28 #include "views/focus/focus_manager.h" |
| 29 #endif // TOOLKIT_VIEWS |
27 | 30 |
28 namespace extension_popup_module_events { | 31 namespace extension_popup_module_events { |
29 | 32 |
30 const char kOnPopupClosed[] = "experimental.popup.onClosed.%d"; | 33 const char kOnPopupClosed[] = "experimental.popup.onClosed.%d"; |
31 | 34 |
32 } // namespace extension_popup_module_events | 35 } // namespace extension_popup_module_events |
33 | 36 |
34 namespace { | 37 namespace { |
35 | 38 |
36 // Errors. | 39 // Errors. |
37 const char kBadAnchorArgument[] = "Invalid anchor argument."; | 40 const char kBadAnchorArgument[] = "Invalid anchor argument."; |
38 const char kInvalidURLError[] = "Invalid URL."; | 41 const char kInvalidURLError[] = "Invalid URL."; |
39 const char kNotAnExtension[] = "Not an extension view."; | 42 const char kNotAnExtension[] = "Not an extension view."; |
40 | 43 |
41 // Keys. | 44 // Keys. |
42 const wchar_t kUrlKey[] = L"url"; | 45 const wchar_t kUrlKey[] = L"url"; |
43 const wchar_t kWidthKey[] = L"width"; | 46 const wchar_t kWidthKey[] = L"width"; |
44 const wchar_t kHeightKey[] = L"height"; | 47 const wchar_t kHeightKey[] = L"height"; |
45 const wchar_t kTopKey[] = L"top"; | 48 const wchar_t kTopKey[] = L"top"; |
46 const wchar_t kLeftKey[] = L"left"; | 49 const wchar_t kLeftKey[] = L"left"; |
47 const wchar_t kGiveFocusKey[] = L"giveFocus"; | 50 const wchar_t kGiveFocusKey[] = L"giveFocus"; |
48 const wchar_t kDomAnchorKey[] = L"domAnchor"; | 51 const wchar_t kDomAnchorKey[] = L"domAnchor"; |
49 const wchar_t kBorderStyleKey[] = L"borderStyle"; | 52 const wchar_t kBorderStyleKey[] = L"borderStyle"; |
50 | 53 |
51 // chrome enumeration values | 54 // chrome enumeration values |
52 const char kRectangleChrome[] = "rectangle"; | 55 const char kRectangleChrome[] = "rectangle"; |
53 | 56 |
54 }; // namespace | 57 }; // namespace |
55 | 58 |
| 59 #if defined(TOOLKIT_VIEWS) |
| 60 // ExtensionPopupHost objects implement the environment necessary to host |
| 61 // an ExtensionPopup views for the popup api. Its main job is to handle |
| 62 // its lifetime and to fire the popup-closed event when the popup is closed. |
| 63 // Because the close-on-focus-lost behavior is different from page action |
| 64 // and browser action, it also manages its own focus change listening. The |
| 65 // difference in close-on-focus-lost is that in the page action and browser |
| 66 // action cases, the popup closes when the focus leaves the popup or any of its |
| 67 // children. In this case, the popup closes when the focus leaves the popups |
| 68 // containing view or any of *its* children. |
| 69 class ExtensionPopupHost : public ExtensionPopup::Observer, |
| 70 public views::WidgetFocusChangeListener, |
| 71 public base::RefCounted<ExtensionPopupHost> { |
| 72 public: |
| 73 explicit ExtensionPopupHost(ExtensionFunctionDispatcher* dispatcher) |
| 74 : dispatcher_(dispatcher), popup_(NULL) { |
| 75 AddRef(); // Balanced in ExtensionPopupClosed(). |
| 76 views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this); |
| 77 } |
| 78 |
| 79 ~ExtensionPopupHost() { |
| 80 views::FocusManager::GetWidgetFocusManager()-> |
| 81 RemoveFocusChangeListener(this); |
| 82 } |
| 83 |
| 84 void set_popup(ExtensionPopup* popup) { |
| 85 popup_ = popup; |
| 86 } |
| 87 |
| 88 // Overriden from ExtensionPopup::Observer |
| 89 virtual void ExtensionPopupClosed(ExtensionPopup* popup) { |
| 90 RenderViewHost* render_view_host = dispatcher_->GetExtensionHost() ? |
| 91 dispatcher_->GetExtensionHost()->render_view_host() : |
| 92 dispatcher_->GetExtensionDOMUI()->GetRenderViewHost(); |
| 93 |
| 94 PopupEventRouter::OnPopupClosed(dispatcher_->profile(), |
| 95 render_view_host->routing_id()); |
| 96 dispatcher_ = NULL; |
| 97 Release(); // Balanced in ctor. |
| 98 } |
| 99 |
| 100 // Overriden from views::WidgetFocusChangeListener |
| 101 virtual void NativeFocusWillChange(gfx::NativeView focused_before, |
| 102 gfx::NativeView focused_now) { |
| 103 // If no view is to be focused, then Chrome was deactivated, so hide the |
| 104 // popup. |
| 105 if (focused_now) { |
| 106 gfx::NativeView host_view = dispatcher_->GetExtensionHost() ? |
| 107 dispatcher_->GetExtensionHost()->GetNativeViewOfHost() : |
| 108 dispatcher_->GetExtensionDOMUI()->GetNativeViewOfHost(); |
| 109 |
| 110 // If the widget hosting the popup contains the newly focused view, then |
| 111 // don't dismiss the pop-up. |
| 112 views::Widget* popup_root_widget = popup_->host()->view()->GetWidget(); |
| 113 if (popup_root_widget && |
| 114 popup_root_widget->ContainsNativeView(focused_now)) |
| 115 return; |
| 116 |
| 117 // If the widget or RenderWidgetHostView hosting the extension that |
| 118 // launched the pop-up is receiving focus, then don't dismiss the popup. |
| 119 views::Widget* host_widget = |
| 120 views::Widget::GetWidgetFromNativeView(host_view); |
| 121 if (host_widget && host_widget->ContainsNativeView(focused_now)) |
| 122 return; |
| 123 |
| 124 RenderWidgetHostView* render_host_view = |
| 125 RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView( |
| 126 host_view); |
| 127 if (render_host_view && |
| 128 render_host_view->ContainsNativeView(focused_now)) |
| 129 return; |
| 130 } |
| 131 |
| 132 // We are careful here to let the current event loop unwind before |
| 133 // causing the popup to be closed. |
| 134 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(popup_, |
| 135 &ExtensionPopup::Close)); |
| 136 } |
| 137 |
| 138 private: |
| 139 // A pointer to the dispatcher that handled the request that opened this |
| 140 // popup view. |
| 141 ExtensionFunctionDispatcher* dispatcher_; |
| 142 |
| 143 // A pointer to the popup. |
| 144 ExtensionPopup* popup_; |
| 145 |
| 146 DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost); |
| 147 }; |
| 148 #endif // TOOLKIT_VIEWS |
| 149 |
56 PopupShowFunction::PopupShowFunction() | 150 PopupShowFunction::PopupShowFunction() |
57 #if defined (TOOLKIT_VIEWS) | 151 #if defined (TOOLKIT_VIEWS) |
58 : popup_(NULL) | 152 : popup_(NULL) |
59 #endif | 153 #endif |
60 {} | 154 {} |
61 | 155 |
62 void PopupShowFunction::Run() { | 156 void PopupShowFunction::Run() { |
63 #if defined(TOOLKIT_VIEWS) | 157 #if defined(TOOLKIT_VIEWS) |
64 if (!RunImpl()) { | 158 if (!RunImpl()) { |
65 SendResponse(false); | 159 SendResponse(false); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 error_ = kNotAnExtension; | 244 error_ = kNotAnExtension; |
151 return false; | 245 return false; |
152 } | 246 } |
153 gfx::Rect rect(origin.x(), origin.y(), dom_width, dom_height); | 247 gfx::Rect rect(origin.x(), origin.y(), dom_width, dom_height); |
154 | 248 |
155 // Pop-up from extension views (ExtensionShelf, etc.), and drop-down when | 249 // Pop-up from extension views (ExtensionShelf, etc.), and drop-down when |
156 // in a TabContents view. | 250 // in a TabContents view. |
157 BubbleBorder::ArrowLocation arrow_location = | 251 BubbleBorder::ArrowLocation arrow_location = |
158 (NULL != dispatcher()->GetExtensionHost()) ? BubbleBorder::BOTTOM_LEFT : | 252 (NULL != dispatcher()->GetExtensionHost()) ? BubbleBorder::BOTTOM_LEFT : |
159 BubbleBorder::TOP_LEFT; | 253 BubbleBorder::TOP_LEFT; |
160 popup_ = ExtensionPopup::Show(url, GetBrowser(), | 254 |
| 255 // ExtensionPopupHost manages it's own lifetime. |
| 256 ExtensionPopupHost* popup_host = new ExtensionPopupHost(dispatcher()); |
| 257 popup_ = ExtensionPopup::Show(url, |
| 258 GetBrowser(), |
161 dispatcher()->profile(), | 259 dispatcher()->profile(), |
162 dispatcher()->GetFrameNativeWindow(), | 260 dispatcher()->GetFrameNativeWindow(), |
163 rect, | 261 rect, |
164 arrow_location, | 262 arrow_location, |
165 give_focus, | 263 give_focus, |
166 chrome); | 264 false, // inspect_with_devtools |
| 265 chrome, |
| 266 popup_host); // ExtensionPopup::Observer |
167 | 267 |
168 ExtensionPopupHost* popup_host = dispatcher()->GetPopupHost(); | 268 // popup_host will handle focus change listening and close the popup when |
169 DCHECK(popup_host); | 269 // focus leaves the containing views hierarchy. |
170 | 270 popup_->set_close_on_lost_focus(false); |
171 popup_host->set_child_popup(popup_); | 271 popup_host->set_popup(popup_); |
172 popup_->set_delegate(popup_host); | |
173 #endif // defined(TOOLKIT_VIEWS) | 272 #endif // defined(TOOLKIT_VIEWS) |
174 return true; | 273 return true; |
175 } | 274 } |
176 | 275 |
177 bool PopupShowFunction::ConvertHostPointToScreen(gfx::Point* point) { | 276 bool PopupShowFunction::ConvertHostPointToScreen(gfx::Point* point) { |
178 DCHECK(point); | 277 DCHECK(point); |
179 | 278 |
180 // If the popup is being requested from an ExtensionHost, then compute | 279 // If the popup is being requested from an ExtensionHost, then compute |
181 // the sreen coordinates based on the views::View object of the ExtensionHost. | 280 // the sreen coordinates based on the views::View object of the ExtensionHost. |
182 if (dispatcher()->GetExtensionHost()) { | 281 if (dispatcher()->GetExtensionHost()) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 int routing_id) { | 335 int routing_id) { |
237 std::string full_event_name = StringPrintf( | 336 std::string full_event_name = StringPrintf( |
238 extension_popup_module_events::kOnPopupClosed, | 337 extension_popup_module_events::kOnPopupClosed, |
239 routing_id); | 338 routing_id); |
240 | 339 |
241 profile->GetExtensionMessageService()->DispatchEventToRenderers( | 340 profile->GetExtensionMessageService()->DispatchEventToRenderers( |
242 full_event_name, | 341 full_event_name, |
243 base::JSONWriter::kEmptyArray, | 342 base::JSONWriter::kEmptyArray, |
244 profile->IsOffTheRecord()); | 343 profile->IsOffTheRecord()); |
245 } | 344 } |
OLD | NEW |