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 // Pass |max_popup_size| to specify the maximal size to which the popup |
111 : dispatcher_(dispatcher), popup_(NULL) { | 112 // will expand. A width or height of 0 will result in the popup making use |
| 113 // of the default max width or height, respectively: ExtensionPopup:kMaxWidth, |
| 114 // and ExtensionPopup::kMaxHeight. |
| 115 explicit ExtensionPopupHost(ExtensionFunctionDispatcher* dispatcher, |
| 116 const gfx::Size& max_popup_size) |
| 117 : dispatcher_(dispatcher), popup_(NULL), max_popup_size_(max_popup_size) { |
112 AddRef(); // Balanced in DispatchPopupClosedEvent(). | 118 AddRef(); // Balanced in DispatchPopupClosedEvent(). |
113 views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this); | 119 views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this); |
114 } | 120 } |
115 | 121 |
116 ~ExtensionPopupHost() { | 122 ~ExtensionPopupHost() { |
117 views::FocusManager::GetWidgetFocusManager()-> | 123 views::FocusManager::GetWidgetFocusManager()-> |
118 RemoveFocusChangeListener(this); | 124 RemoveFocusChangeListener(this); |
119 } | 125 } |
120 | 126 |
121 void set_popup(ExtensionPopup* popup) { | 127 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 | 176 // Extension hosts created for popup contents exist in the same tab |
171 // contents as the ExtensionFunctionDispatcher that requested the popup. | 177 // contents as the ExtensionFunctionDispatcher that requested the popup. |
172 // For example, '_blank' link navigation should be routed through the tab | 178 // For example, '_blank' link navigation should be routed through the tab |
173 // contents that requested the popup. | 179 // contents that requested the popup. |
174 if (dispatcher_ && dispatcher_->delegate()) { | 180 if (dispatcher_ && dispatcher_->delegate()) { |
175 host->set_associated_tab_contents( | 181 host->set_associated_tab_contents( |
176 dispatcher_->delegate()->associated_tab_contents()); | 182 dispatcher_->delegate()->associated_tab_contents()); |
177 } | 183 } |
178 } | 184 } |
179 | 185 |
| 186 virtual void ExtensionPopupCreated(ExtensionPopup* popup) { |
| 187 // The popup has been created, but not yet displayed, so install the max |
| 188 // size overrides before the first positioning. |
| 189 if (max_popup_size_.width()) |
| 190 popup->set_max_width(max_popup_size_.width()); |
| 191 |
| 192 if (max_popup_size_.height()) |
| 193 popup->set_max_height(max_popup_size_.height()); |
| 194 } |
| 195 |
180 virtual void ExtensionPopupResized(ExtensionPopup* popup) { | 196 virtual void ExtensionPopupResized(ExtensionPopup* popup) { |
181 // Reposition the location of the arrow on the popup so that the popup | 197 // Reposition the location of the arrow on the popup so that the popup |
182 // better fits on the working monitor. | 198 // better fits on the working monitor. |
183 gfx::Rect popup_rect = popup->GetOuterBounds(); | 199 gfx::Rect popup_rect = popup->GetOuterBounds(); |
184 if (popup_rect.IsEmpty()) | 200 if (popup_rect.IsEmpty()) |
185 return; | 201 return; |
186 | 202 |
187 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( | 203 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( |
188 WindowSizer::CreateDefaultMonitorInfoProvider()); | 204 WindowSizer::CreateDefaultMonitorInfoProvider()); |
189 gfx::Rect monitor_bounds( | 205 gfx::Rect monitor_bounds( |
(...skipping 19 matching lines...) Expand all Loading... |
209 // situation - the popup will be contained entirely in its working monitor | 225 // situation - the popup will be contained entirely in its working monitor |
210 // bounds. | 226 // bounds. |
211 gfx::Rect flipped_bounds = popup->GetOuterBounds(); | 227 gfx::Rect flipped_bounds = popup->GetOuterBounds(); |
212 gfx::Rect updated_monitor_bounds = | 228 gfx::Rect updated_monitor_bounds = |
213 monitor_provider->GetMonitorWorkAreaMatching(flipped_bounds); | 229 monitor_provider->GetMonitorWorkAreaMatching(flipped_bounds); |
214 if (!updated_monitor_bounds.Contains(flipped_bounds)) | 230 if (!updated_monitor_bounds.Contains(flipped_bounds)) |
215 popup->SetArrowPosition(previous_location); | 231 popup->SetArrowPosition(previous_location); |
216 } | 232 } |
217 } | 233 } |
218 | 234 |
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 | 235 // Overridden from views::WidgetFocusChangeListener |
230 virtual void NativeFocusWillChange(gfx::NativeView focused_before, | 236 virtual void NativeFocusWillChange(gfx::NativeView focused_before, |
231 gfx::NativeView focused_now) { | 237 gfx::NativeView focused_now) { |
232 // If the popup doesn't exist, then do nothing. | 238 // If the popup doesn't exist, then do nothing. |
233 if (!popup_) | 239 if (!popup_) |
234 return; | 240 return; |
235 | 241 |
236 // If no view is to be focused, then Chrome was deactivated, so hide the | 242 // If no view is to be focused, then Chrome was deactivated, so hide the |
237 // popup. | 243 // popup. |
238 if (focused_now) { | 244 if (focused_now) { |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 if (!dispatcher) | 322 if (!dispatcher) |
317 return NULL; | 323 return NULL; |
318 | 324 |
319 RenderViewHost* render_view_host = dispatcher->render_view_host(); | 325 RenderViewHost* render_view_host = dispatcher->render_view_host(); |
320 RenderViewHostDelegate* delegate = | 326 RenderViewHostDelegate* delegate = |
321 render_view_host ? render_view_host->delegate() : NULL; | 327 render_view_host ? render_view_host->delegate() : NULL; |
322 | 328 |
323 return delegate ? delegate->GetAutomationResourceRoutingDelegate() : NULL; | 329 return delegate ? delegate->GetAutomationResourceRoutingDelegate() : NULL; |
324 } | 330 } |
325 | 331 |
| 332 void DispatchPopupClosedEvent() { |
| 333 if (dispatcher_) { |
| 334 PopupEventRouter::OnPopupClosed( |
| 335 dispatcher_->profile(), |
| 336 dispatcher_->render_view_host()->routing_id()); |
| 337 dispatcher_ = NULL; |
| 338 } |
| 339 Release(); // Balanced in ctor. |
| 340 } |
| 341 |
326 // A pointer to the dispatcher that handled the request that opened this | 342 // A pointer to the dispatcher that handled the request that opened this |
327 // popup view. | 343 // popup view. |
328 ExtensionFunctionDispatcher* dispatcher_; | 344 ExtensionFunctionDispatcher* dispatcher_; |
329 | 345 |
330 // A pointer to the popup. | 346 // A pointer to the popup. |
331 ExtensionPopup* popup_; | 347 ExtensionPopup* popup_; |
332 | 348 |
| 349 // The maximal size to which the popup is permitted to expand. |
| 350 gfx::Size max_popup_size_; |
| 351 |
333 NotificationRegistrar registrar_; | 352 NotificationRegistrar registrar_; |
334 | 353 |
335 DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost); | 354 DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost); |
336 }; | 355 }; |
337 #endif // TOOLKIT_VIEWS | 356 #endif // TOOLKIT_VIEWS |
338 | 357 |
339 PopupShowFunction::PopupShowFunction() | 358 PopupShowFunction::PopupShowFunction() |
340 #if defined (TOOLKIT_VIEWS) | 359 #if defined (TOOLKIT_VIEWS) |
341 : popup_(NULL) | 360 : popup_(NULL) |
342 #endif | 361 #endif |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 EXTENSION_FUNCTION_VALIDATE(dom_top >= 0 && dom_left >= 0 && | 418 EXTENSION_FUNCTION_VALIDATE(dom_top >= 0 && dom_left >= 0 && |
400 dom_width >= 0 && dom_height >= 0); | 419 dom_width >= 0 && dom_height >= 0); |
401 | 420 |
402 // The default behaviour is to give the focus to the pop-up window. | 421 // The default behaviour is to give the focus to the pop-up window. |
403 bool give_focus = true; | 422 bool give_focus = true; |
404 if (show_details->HasKey(kGiveFocusKey)) { | 423 if (show_details->HasKey(kGiveFocusKey)) { |
405 EXTENSION_FUNCTION_VALIDATE(show_details->GetBoolean(kGiveFocusKey, | 424 EXTENSION_FUNCTION_VALIDATE(show_details->GetBoolean(kGiveFocusKey, |
406 &give_focus)); | 425 &give_focus)); |
407 } | 426 } |
408 | 427 |
| 428 int max_width = 0; |
| 429 int max_height = 0; |
| 430 if (show_details->HasKey(kMaxSizeKey)) { |
| 431 DictionaryValue* max_size = NULL; |
| 432 EXTENSION_FUNCTION_VALIDATE(show_details->GetDictionary(kMaxSizeKey, |
| 433 &max_size)); |
| 434 |
| 435 if (max_size->HasKey(kWidthKey)) |
| 436 EXTENSION_FUNCTION_VALIDATE(max_size->GetInteger(kWidthKey, &max_width)); |
| 437 |
| 438 if (max_size->HasKey(kHeightKey)) |
| 439 EXTENSION_FUNCTION_VALIDATE(max_size->GetInteger(kHeightKey, |
| 440 &max_height)); |
| 441 } |
| 442 |
409 #if defined(TOOLKIT_VIEWS) | 443 #if defined(TOOLKIT_VIEWS) |
410 // The default behaviour is to provide the bubble-chrome to the popup. | 444 // The default behaviour is to provide the bubble-chrome to the popup. |
411 ExtensionPopup::PopupChrome chrome = ExtensionPopup::BUBBLE_CHROME; | 445 ExtensionPopup::PopupChrome chrome = ExtensionPopup::BUBBLE_CHROME; |
412 if (show_details->HasKey(kBorderStyleKey)) { | 446 if (show_details->HasKey(kBorderStyleKey)) { |
413 std::string chrome_string; | 447 std::string chrome_string; |
414 EXTENSION_FUNCTION_VALIDATE(show_details->GetString(kBorderStyleKey, | 448 EXTENSION_FUNCTION_VALIDATE(show_details->GetString(kBorderStyleKey, |
415 &chrome_string)); | 449 &chrome_string)); |
416 if (chrome_string == kRectangleChrome) | 450 if (chrome_string == kRectangleChrome) |
417 chrome = ExtensionPopup::RECTANGLE_CHROME; | 451 chrome = ExtensionPopup::RECTANGLE_CHROME; |
418 } | 452 } |
(...skipping 30 matching lines...) Expand all Loading... |
449 // of this. | 483 // of this. |
450 gfx::NativeWindow window = | 484 gfx::NativeWindow window = |
451 dispatcher()->delegate()->GetCustomFrameNativeWindow(); | 485 dispatcher()->delegate()->GetCustomFrameNativeWindow(); |
452 if (!window) | 486 if (!window) |
453 window = GetCurrentBrowser()->window()->GetNativeHandle(); | 487 window = GetCurrentBrowser()->window()->GetNativeHandle(); |
454 | 488 |
455 #if defined(TOOLKIT_VIEWS) | 489 #if defined(TOOLKIT_VIEWS) |
456 BubbleBorder::ArrowLocation arrow_location = BubbleBorder::TOP_LEFT; | 490 BubbleBorder::ArrowLocation arrow_location = BubbleBorder::TOP_LEFT; |
457 | 491 |
458 // ExtensionPopupHost manages it's own lifetime. | 492 // ExtensionPopupHost manages it's own lifetime. |
459 ExtensionPopupHost* popup_host = new ExtensionPopupHost(dispatcher()); | 493 ExtensionPopupHost* popup_host = |
| 494 new ExtensionPopupHost(dispatcher(), gfx::Size(max_width, max_height)); |
460 popup_ = ExtensionPopup::Show(url, | 495 popup_ = ExtensionPopup::Show(url, |
461 GetCurrentBrowser(), | 496 GetCurrentBrowser(), |
462 dispatcher()->profile(), | 497 dispatcher()->profile(), |
463 window, | 498 window, |
464 rect, | 499 rect, |
465 arrow_location, | 500 arrow_location, |
466 give_focus, | 501 give_focus, |
467 false, // inspect_with_devtools | 502 false, // inspect_with_devtools |
468 chrome, | 503 chrome, |
469 popup_host); // ExtensionPopup::Observer | 504 popup_host); // ExtensionPopup::Observer |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
504 // static | 539 // static |
505 void PopupEventRouter::OnPopupClosed(Profile* profile, | 540 void PopupEventRouter::OnPopupClosed(Profile* profile, |
506 int routing_id) { | 541 int routing_id) { |
507 std::string full_event_name = base::StringPrintf( | 542 std::string full_event_name = base::StringPrintf( |
508 extension_popup_module_events::kOnPopupClosed, | 543 extension_popup_module_events::kOnPopupClosed, |
509 routing_id); | 544 routing_id); |
510 | 545 |
511 profile->GetExtensionEventRouter()->DispatchEventToRenderers( | 546 profile->GetExtensionEventRouter()->DispatchEventToRenderers( |
512 full_event_name, base::JSONWriter::kEmptyArray, profile, GURL()); | 547 full_event_name, base::JSONWriter::kEmptyArray, profile, GURL()); |
513 } | 548 } |
OLD | NEW |