OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "base/stringprintf.h" | 9 #include "base/stringprintf.h" |
10 #include "base/values.h" | 10 #include "base/values.h" |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
50 "Popups are only supported from tab-contents views."; | 50 "Popups are only supported from tab-contents views."; |
51 | 51 |
52 // Keys. | 52 // Keys. |
53 const char kWidthKey[] = "width"; | 53 const char kWidthKey[] = "width"; |
54 const char kHeightKey[] = "height"; | 54 const char kHeightKey[] = "height"; |
55 const char kTopKey[] = "top"; | 55 const char kTopKey[] = "top"; |
56 const char kLeftKey[] = "left"; | 56 const char kLeftKey[] = "left"; |
57 const char kGiveFocusKey[] = "giveFocus"; | 57 const char kGiveFocusKey[] = "giveFocus"; |
58 const char kDomAnchorKey[] = "domAnchor"; | 58 const char kDomAnchorKey[] = "domAnchor"; |
59 const char kBorderStyleKey[] = "borderStyle"; | 59 const char kBorderStyleKey[] = "borderStyle"; |
60 const char kMaxSizeKey[] = "maxSize"; | |
60 | 61 |
61 // chrome enumeration values | 62 // chrome enumeration values |
62 const char kRectangleChrome[] = "rectangle"; | 63 const char kRectangleChrome[] = "rectangle"; |
63 | 64 |
64 #if defined(TOOLKIT_VIEWS) | 65 #if defined(TOOLKIT_VIEWS) |
65 // Returns an updated arrow location, conditioned on the type of intersection | 66 // Returns an updated arrow location, conditioned on the type of intersection |
66 // between the popup window, and the screen. |location| is the current position | 67 // between the popup window, and the screen. |location| is the current position |
67 // of the arrow on the popup. |intersection| is the rect representing the | 68 // of the arrow on the popup. |intersection| is the rect representing the |
68 // intersection between the popup view and its working screen. |popup_rect| | 69 // intersection between the popup view and its working screen. |popup_rect| |
69 // is the rect of the popup window in screen space coordinates. | 70 // is the rect of the popup window in screen space coordinates. |
(...skipping 30 matching lines...) Expand all Loading... | |
100 // and browser action, it also manages its own focus change listening. The | 101 // and browser action, it also manages its own focus change listening. The |
101 // difference in close-on-focus-lost is that in the page action and browser | 102 // difference in close-on-focus-lost is that in the page action and browser |
102 // action cases, the popup closes when the focus leaves the popup or any of its | 103 // action cases, the popup closes when the focus leaves the popup or any of its |
103 // children. In this case, the popup closes when the focus leaves the popups | 104 // children. In this case, the popup closes when the focus leaves the popups |
104 // containing view or any of *its* children. | 105 // containing view or any of *its* children. |
105 class ExtensionPopupHost : public ExtensionPopup::Observer, | 106 class ExtensionPopupHost : public ExtensionPopup::Observer, |
106 public views::WidgetFocusChangeListener, | 107 public views::WidgetFocusChangeListener, |
107 public base::RefCounted<ExtensionPopupHost>, | 108 public base::RefCounted<ExtensionPopupHost>, |
108 public NotificationObserver { | 109 public NotificationObserver { |
109 public: | 110 public: |
110 explicit ExtensionPopupHost(ExtensionFunctionDispatcher* dispatcher) | 111 explicit ExtensionPopupHost(ExtensionFunctionDispatcher* dispatcher, |
111 : dispatcher_(dispatcher), popup_(NULL) { | 112 const gfx::Size& max_popup_size) |
Jói
2010/11/25 13:50:30
would be good to document that setting a dimension
Jeff Timanus
2010/11/25 23:35:30
Good point. Done.
| |
113 : dispatcher_(dispatcher), popup_(NULL), max_popup_size_(max_popup_size) { | |
112 AddRef(); // Balanced in DispatchPopupClosedEvent(). | 114 AddRef(); // Balanced in DispatchPopupClosedEvent(). |
113 views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this); | 115 views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this); |
114 } | 116 } |
115 | 117 |
116 ~ExtensionPopupHost() { | 118 ~ExtensionPopupHost() { |
117 views::FocusManager::GetWidgetFocusManager()-> | 119 views::FocusManager::GetWidgetFocusManager()-> |
118 RemoveFocusChangeListener(this); | 120 RemoveFocusChangeListener(this); |
119 } | 121 } |
120 | 122 |
121 void set_popup(ExtensionPopup* popup) { | 123 void set_popup(ExtensionPopup* popup) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 // Extension hosts created for popup contents exist in the same tab | 172 // Extension hosts created for popup contents exist in the same tab |
171 // contents as the ExtensionFunctionDispatcher that requested the popup. | 173 // contents as the ExtensionFunctionDispatcher that requested the popup. |
172 // For example, '_blank' link navigation should be routed through the tab | 174 // For example, '_blank' link navigation should be routed through the tab |
173 // contents that requested the popup. | 175 // contents that requested the popup. |
174 if (dispatcher_ && dispatcher_->delegate()) { | 176 if (dispatcher_ && dispatcher_->delegate()) { |
175 host->set_associated_tab_contents( | 177 host->set_associated_tab_contents( |
176 dispatcher_->delegate()->associated_tab_contents()); | 178 dispatcher_->delegate()->associated_tab_contents()); |
177 } | 179 } |
178 } | 180 } |
179 | 181 |
182 virtual void ExtensionPopupCreated(ExtensionPopup* popup) { | |
183 // The popup has been created, but not yet displayed, so install the max | |
184 // size overrides before the first positioning. | |
185 if (max_popup_size_.width()) | |
186 popup->set_max_width(max_popup_size_.width()); | |
187 | |
188 if (max_popup_size_.height()) | |
189 popup->set_max_height(max_popup_size_.height()); | |
190 } | |
191 | |
180 virtual void ExtensionPopupResized(ExtensionPopup* popup) { | 192 virtual void ExtensionPopupResized(ExtensionPopup* popup) { |
181 // Reposition the location of the arrow on the popup so that the popup | 193 // Reposition the location of the arrow on the popup so that the popup |
182 // better fits on the working monitor. | 194 // better fits on the working monitor. |
183 gfx::Rect popup_rect = popup->GetOuterBounds(); | 195 gfx::Rect popup_rect = popup->GetOuterBounds(); |
184 if (popup_rect.IsEmpty()) | 196 if (popup_rect.IsEmpty()) |
185 return; | 197 return; |
186 | 198 |
187 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( | 199 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( |
188 WindowSizer::CreateDefaultMonitorInfoProvider()); | 200 WindowSizer::CreateDefaultMonitorInfoProvider()); |
189 gfx::Rect monitor_bounds( | 201 gfx::Rect monitor_bounds( |
(...skipping 19 matching lines...) Expand all Loading... | |
209 // situation - the popup will be contained entirely in its working monitor | 221 // situation - the popup will be contained entirely in its working monitor |
210 // bounds. | 222 // bounds. |
211 gfx::Rect flipped_bounds = popup->GetOuterBounds(); | 223 gfx::Rect flipped_bounds = popup->GetOuterBounds(); |
212 gfx::Rect updated_monitor_bounds = | 224 gfx::Rect updated_monitor_bounds = |
213 monitor_provider->GetMonitorWorkAreaMatching(flipped_bounds); | 225 monitor_provider->GetMonitorWorkAreaMatching(flipped_bounds); |
214 if (!updated_monitor_bounds.Contains(flipped_bounds)) | 226 if (!updated_monitor_bounds.Contains(flipped_bounds)) |
215 popup->SetArrowPosition(previous_location); | 227 popup->SetArrowPosition(previous_location); |
216 } | 228 } |
217 } | 229 } |
218 | 230 |
219 virtual void DispatchPopupClosedEvent() { | |
220 if (dispatcher_) { | |
221 PopupEventRouter::OnPopupClosed( | |
222 dispatcher_->profile(), | |
223 dispatcher_->render_view_host()->routing_id()); | |
224 dispatcher_ = NULL; | |
225 } | |
226 Release(); // Balanced in ctor. | |
227 } | |
228 | |
229 // Overridden from views::WidgetFocusChangeListener | 231 // Overridden from views::WidgetFocusChangeListener |
230 virtual void NativeFocusWillChange(gfx::NativeView focused_before, | 232 virtual void NativeFocusWillChange(gfx::NativeView focused_before, |
231 gfx::NativeView focused_now) { | 233 gfx::NativeView focused_now) { |
232 // If the popup doesn't exist, then do nothing. | 234 // If the popup doesn't exist, then do nothing. |
233 if (!popup_) | 235 if (!popup_) |
234 return; | 236 return; |
235 | 237 |
236 // If no view is to be focused, then Chrome was deactivated, so hide the | 238 // If no view is to be focused, then Chrome was deactivated, so hide the |
237 // popup. | 239 // popup. |
238 if (focused_now) { | 240 if (focused_now) { |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 if (!dispatcher) | 318 if (!dispatcher) |
317 return NULL; | 319 return NULL; |
318 | 320 |
319 RenderViewHost* render_view_host = dispatcher->render_view_host(); | 321 RenderViewHost* render_view_host = dispatcher->render_view_host(); |
320 RenderViewHostDelegate* delegate = | 322 RenderViewHostDelegate* delegate = |
321 render_view_host ? render_view_host->delegate() : NULL; | 323 render_view_host ? render_view_host->delegate() : NULL; |
322 | 324 |
323 return delegate ? delegate->GetAutomationResourceRoutingDelegate() : NULL; | 325 return delegate ? delegate->GetAutomationResourceRoutingDelegate() : NULL; |
324 } | 326 } |
325 | 327 |
328 void DispatchPopupClosedEvent() { | |
329 if (dispatcher_) { | |
330 PopupEventRouter::OnPopupClosed( | |
331 dispatcher_->profile(), | |
332 dispatcher_->render_view_host()->routing_id()); | |
333 dispatcher_ = NULL; | |
334 } | |
335 Release(); // Balanced in ctor. | |
336 } | |
337 | |
326 // A pointer to the dispatcher that handled the request that opened this | 338 // A pointer to the dispatcher that handled the request that opened this |
327 // popup view. | 339 // popup view. |
328 ExtensionFunctionDispatcher* dispatcher_; | 340 ExtensionFunctionDispatcher* dispatcher_; |
329 | 341 |
330 // A pointer to the popup. | 342 // A pointer to the popup. |
331 ExtensionPopup* popup_; | 343 ExtensionPopup* popup_; |
332 | 344 |
345 // The maximal size to which the popup is permitted to expand. | |
346 gfx::Size max_popup_size_; | |
347 | |
333 NotificationRegistrar registrar_; | 348 NotificationRegistrar registrar_; |
334 | 349 |
335 DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost); | 350 DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost); |
336 }; | 351 }; |
337 #endif // TOOLKIT_VIEWS | 352 #endif // TOOLKIT_VIEWS |
338 | 353 |
339 PopupShowFunction::PopupShowFunction() | 354 PopupShowFunction::PopupShowFunction() |
340 #if defined (TOOLKIT_VIEWS) | 355 #if defined (TOOLKIT_VIEWS) |
341 : popup_(NULL) | 356 : popup_(NULL) |
342 #endif | 357 #endif |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
399 EXTENSION_FUNCTION_VALIDATE(dom_top >= 0 && dom_left >= 0 && | 414 EXTENSION_FUNCTION_VALIDATE(dom_top >= 0 && dom_left >= 0 && |
400 dom_width >= 0 && dom_height >= 0); | 415 dom_width >= 0 && dom_height >= 0); |
401 | 416 |
402 // The default behaviour is to give the focus to the pop-up window. | 417 // The default behaviour is to give the focus to the pop-up window. |
403 bool give_focus = true; | 418 bool give_focus = true; |
404 if (show_details->HasKey(kGiveFocusKey)) { | 419 if (show_details->HasKey(kGiveFocusKey)) { |
405 EXTENSION_FUNCTION_VALIDATE(show_details->GetBoolean(kGiveFocusKey, | 420 EXTENSION_FUNCTION_VALIDATE(show_details->GetBoolean(kGiveFocusKey, |
406 &give_focus)); | 421 &give_focus)); |
407 } | 422 } |
408 | 423 |
424 int max_width = 0; | |
425 int max_height = 0; | |
426 if (show_details->HasKey(kMaxSizeKey)) { | |
427 DictionaryValue* max_size = NULL; | |
428 EXTENSION_FUNCTION_VALIDATE(show_details->GetDictionary(kMaxSizeKey, | |
429 &max_size)); | |
430 | |
431 if (max_size->HasKey(kWidthKey)) | |
432 EXTENSION_FUNCTION_VALIDATE(max_size->GetInteger(kWidthKey, &max_width)); | |
Jói
2010/11/25 13:50:30
Should perhaps validate (here and below) that the
Jeff Timanus
2010/11/25 23:35:30
Yup! I resisted the urge to double validate - I r
| |
433 | |
434 if (max_size->HasKey(kHeightKey)) | |
435 EXTENSION_FUNCTION_VALIDATE(max_size->GetInteger(kHeightKey, | |
436 &max_height)); | |
437 } | |
438 | |
409 #if defined(TOOLKIT_VIEWS) | 439 #if defined(TOOLKIT_VIEWS) |
410 // The default behaviour is to provide the bubble-chrome to the popup. | 440 // The default behaviour is to provide the bubble-chrome to the popup. |
411 ExtensionPopup::PopupChrome chrome = ExtensionPopup::BUBBLE_CHROME; | 441 ExtensionPopup::PopupChrome chrome = ExtensionPopup::BUBBLE_CHROME; |
412 if (show_details->HasKey(kBorderStyleKey)) { | 442 if (show_details->HasKey(kBorderStyleKey)) { |
413 std::string chrome_string; | 443 std::string chrome_string; |
414 EXTENSION_FUNCTION_VALIDATE(show_details->GetString(kBorderStyleKey, | 444 EXTENSION_FUNCTION_VALIDATE(show_details->GetString(kBorderStyleKey, |
415 &chrome_string)); | 445 &chrome_string)); |
416 if (chrome_string == kRectangleChrome) | 446 if (chrome_string == kRectangleChrome) |
417 chrome = ExtensionPopup::RECTANGLE_CHROME; | 447 chrome = ExtensionPopup::RECTANGLE_CHROME; |
418 } | 448 } |
(...skipping 30 matching lines...) Expand all Loading... | |
449 // of this. | 479 // of this. |
450 gfx::NativeWindow window = | 480 gfx::NativeWindow window = |
451 dispatcher()->delegate()->GetCustomFrameNativeWindow(); | 481 dispatcher()->delegate()->GetCustomFrameNativeWindow(); |
452 if (!window) | 482 if (!window) |
453 window = GetCurrentBrowser()->window()->GetNativeHandle(); | 483 window = GetCurrentBrowser()->window()->GetNativeHandle(); |
454 | 484 |
455 #if defined(TOOLKIT_VIEWS) | 485 #if defined(TOOLKIT_VIEWS) |
456 BubbleBorder::ArrowLocation arrow_location = BubbleBorder::TOP_LEFT; | 486 BubbleBorder::ArrowLocation arrow_location = BubbleBorder::TOP_LEFT; |
457 | 487 |
458 // ExtensionPopupHost manages it's own lifetime. | 488 // ExtensionPopupHost manages it's own lifetime. |
459 ExtensionPopupHost* popup_host = new ExtensionPopupHost(dispatcher()); | 489 ExtensionPopupHost* popup_host = |
490 new ExtensionPopupHost(dispatcher(), gfx::Size(max_width, max_height)); | |
460 popup_ = ExtensionPopup::Show(url, | 491 popup_ = ExtensionPopup::Show(url, |
461 GetCurrentBrowser(), | 492 GetCurrentBrowser(), |
462 dispatcher()->profile(), | 493 dispatcher()->profile(), |
463 window, | 494 window, |
464 rect, | 495 rect, |
465 arrow_location, | 496 arrow_location, |
466 give_focus, | 497 give_focus, |
467 false, // inspect_with_devtools | 498 false, // inspect_with_devtools |
468 chrome, | 499 chrome, |
469 popup_host); // ExtensionPopup::Observer | 500 popup_host); // ExtensionPopup::Observer |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
504 // static | 535 // static |
505 void PopupEventRouter::OnPopupClosed(Profile* profile, | 536 void PopupEventRouter::OnPopupClosed(Profile* profile, |
506 int routing_id) { | 537 int routing_id) { |
507 std::string full_event_name = base::StringPrintf( | 538 std::string full_event_name = base::StringPrintf( |
508 extension_popup_module_events::kOnPopupClosed, | 539 extension_popup_module_events::kOnPopupClosed, |
509 routing_id); | 540 routing_id); |
510 | 541 |
511 profile->GetExtensionEventRouter()->DispatchEventToRenderers( | 542 profile->GetExtensionEventRouter()->DispatchEventToRenderers( |
512 full_event_name, base::JSONWriter::kEmptyArray, profile, GURL()); | 543 full_event_name, base::JSONWriter::kEmptyArray, profile, GURL()); |
513 } | 544 } |
OLD | NEW |