Index: chrome/browser/extensions/extension_popup_api.cc |
=================================================================== |
--- chrome/browser/extensions/extension_popup_api.cc (revision 47515) |
+++ chrome/browser/extensions/extension_popup_api.cc (working copy) |
@@ -16,6 +16,7 @@ |
#include "chrome/browser/renderer_host/render_view_host_delegate.h" |
#include "chrome/browser/renderer_host/render_widget_host_view.h" |
#include "chrome/browser/tab_contents/tab_contents.h" |
+#include "chrome/browser/window_sizer.h" |
#include "chrome/common/extensions/extension.h" |
#include "chrome/common/notification_details.h" |
#include "chrome/common/notification_service.h" |
@@ -25,6 +26,7 @@ |
#include "gfx/point.h" |
#if defined(TOOLKIT_VIEWS) |
+#include "chrome/browser/views/bubble_border.h" |
#include "chrome/browser/views/extensions/extension_popup.h" |
#include "views/view.h" |
#include "views/focus/focus_manager.h" |
@@ -58,6 +60,35 @@ |
// chrome enumeration values |
const char kRectangleChrome[] = "rectangle"; |
+#if defined(TOOLKIT_VIEWS) |
+// Returns an updated arrow location, conditioned on the type of intersection |
+// between the popup window, and the screen. |location| is the current position |
+// of the arrow on the popup. |intersection| is the rect representing the |
+// intersection between the popup view and its working screen. |popup_rect| |
+// is the rect of the popup window in screen space coordinates. |
+// The returned location will be horizontally or vertically inverted based on |
+// if the popup has been clipped horizontally or vertically. |
+BubbleBorder::ArrowLocation ToggleArrowLocation( |
+ BubbleBorder::ArrowLocation location, const gfx::Rect& intersection, |
+ const gfx::Rect& popup_rect) { |
+ // If the popup has been clipped horizontally, flip the right-left position |
+ // of the arrow. |
+ if (intersection.right() != popup_rect.right() || |
+ intersection.x() != popup_rect.x()) { |
+ location = BubbleBorder::horizontal_mirror(location); |
+ } |
+ |
+ // If the popup has been clipped vertically, flip the bottom-top position |
+ // of the arrow. |
+ if (intersection.y() != popup_rect.y() || |
+ intersection.bottom() != popup_rect.bottom()) { |
+ location = BubbleBorder::vertical_mirror(location); |
+ } |
+ |
+ return location; |
+} |
+#endif // TOOLKIT_VIEWS |
+ |
}; // namespace |
#if defined(TOOLKIT_VIEWS) |
@@ -124,6 +155,45 @@ |
router->RegisterRenderViewHost(host->render_view_host()); |
} |
+ virtual void ExtensionPopupResized(ExtensionPopup* popup) { |
+ // Reposition the location of the arrow on the popup so that the popup |
+ // better fits on the working monitor. |
+ gfx::Rect popup_rect = popup->GetOuterBounds(); |
+ if (popup_rect.IsEmpty()) |
+ return; |
+ |
+ scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( |
+ WindowSizer::CreateDefaultMonitorInfoProvider()); |
+ gfx::Rect monitor_bounds( |
+ monitor_provider->GetMonitorWorkAreaMatching(popup_rect)); |
+ gfx::Rect intersection = monitor_bounds.Intersect(popup_rect); |
+ |
+ // If the popup is totally out of the bounds of the monitor, then toggling |
+ // the arrow location will not result in an un-clipped window. |
+ if (intersection.IsEmpty()) |
+ return; |
+ |
+ if (!intersection.Equals(popup_rect)) { |
+ // The popup was clipped by the monitor. Toggle the arrow position |
+ // to see if that improves visibility. Note: The assignment and |
+ // re-assignment of the arrow-position will not trigger an intermittent |
+ // display. |
+ BubbleBorder::ArrowLocation previous_location = popup->arrow_position(); |
+ BubbleBorder::ArrowLocation flipped_location = ToggleArrowLocation( |
+ previous_location, intersection, popup_rect); |
+ popup->SetArrowPosition(flipped_location); |
+ |
+ // Double check that toggling the position actually improved the |
+ // situation - the popup will be contained entirely in its working monitor |
+ // bounds. |
+ gfx::Rect flipped_bounds = popup->GetOuterBounds(); |
+ gfx::Rect updated_monitor_bounds = |
+ monitor_provider->GetMonitorWorkAreaMatching(flipped_bounds); |
+ if (!updated_monitor_bounds.Contains(flipped_bounds)) |
+ popup->SetArrowPosition(previous_location); |
+ } |
+ } |
+ |
virtual void DispatchPopupClosedEvent() { |
PopupEventRouter::OnPopupClosed( |
dispatcher_->profile(), dispatcher_->render_view_host()->routing_id()); |