summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authortwiz@google.com <twiz@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-20 01:08:17 +0000
committertwiz@google.com <twiz@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-20 01:08:17 +0000
commit9d7c69e5006a874d7f127db46bdb0e76aaa60ec7 (patch)
tree6800bce34fb919c11246d7492a190ee739216a36 /chrome/browser
parent074248931d91c43c612ee611342a5c354f580b2e (diff)
downloadchromium_src-9d7c69e5006a874d7f127db46bdb0e76aaa60ec7.zip
chromium_src-9d7c69e5006a874d7f127db46bdb0e76aaa60ec7.tar.gz
chromium_src-9d7c69e5006a874d7f127db46bdb0e76aaa60ec7.tar.bz2
Simple change that re-positions the arrow location on displayed extension popup views. This change allows popups to re-orient themselves if they are partially clipped by the working monitor. Note that this only applies to popups created via the experimental extension popup API.
BUG=42779 TEST=None Review URL: http://codereview.chromium.org/1774012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47760 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/extensions/extension_popup_api.cc70
-rw-r--r--chrome/browser/views/extensions/extension_popup.cc66
-rw-r--r--chrome/browser/views/extensions/extension_popup.h23
3 files changed, 129 insertions, 30 deletions
diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc
index 6dbae99..acc47e3 100644
--- a/chrome/browser/extensions/extension_popup_api.cc
+++ b/chrome/browser/extensions/extension_popup_api.cc
@@ -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 @@ const wchar_t kBorderStyleKey[] = L"borderStyle";
// 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 @@ class ExtensionPopupHost : public ExtensionPopup::Observer,
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());
diff --git a/chrome/browser/views/extensions/extension_popup.cc b/chrome/browser/views/extensions/extension_popup.cc
index f30aac9..b3c4b23 100644
--- a/chrome/browser/views/extensions/extension_popup.cc
+++ b/chrome/browser/views/extensions/extension_popup.cc
@@ -41,11 +41,15 @@ const int ExtensionPopup::kMinHeight = 25;
const int ExtensionPopup::kMaxWidth = 800;
const int ExtensionPopup::kMaxHeight = 600;
+namespace {
+
// The width, in pixels, of the black-border on a popup.
const int kPopupBorderWidth = 1;
const int kPopupBubbleCornerRadius = BubbleBorder::GetCornerRadius() / 2;
+} // namespace
+
ExtensionPopup::ExtensionPopup(ExtensionHost* host,
views::Widget* frame,
const gfx::Rect& relative_to,
@@ -138,6 +142,16 @@ ExtensionPopup::~ExtensionPopup() {
border_widget_->Close();
}
+void ExtensionPopup::SetArrowPosition(
+ BubbleBorder::ArrowLocation arrow_location) {
+ DCHECK_NE(BubbleBorder::NONE, arrow_location) <<
+ "Extension popups must be positioned relative to an arrow.";
+
+ anchor_position_ = arrow_location;
+ if (border_)
+ border_->set_arrow_location(anchor_position_);
+}
+
void ExtensionPopup::Hide() {
BrowserBubble::Hide();
if (border_widget_)
@@ -162,19 +176,14 @@ void ExtensionPopup::Show(bool activate) {
}
void ExtensionPopup::ResizeToView() {
- // We'll be sizing ourselves to this size shortly, but wait until we
- // know our position to do it.
- gfx::Size new_size = view()->size();
+ if (observer_)
+ observer_->ExtensionPopupResized(this);
- // Convert rect to screen coordinates.
- gfx::Rect rect = relative_to_;
- gfx::Point origin = rect.origin();
- views::View::ConvertPointToScreen(frame_->GetRootView(), &origin);
- rect.set_origin(origin);
+ gfx::Rect rect = GetOuterBounds();
- rect = GetOuterBounds(rect, new_size);
- origin = rect.origin();
+ gfx::Point origin = rect.origin();
views::View::ConvertPointToView(NULL, frame_->GetRootView(), &origin);
+
if (border_widget_) {
// Set the bubble-chrome widget according to the outer bounds of the entire
// popup.
@@ -189,6 +198,7 @@ void ExtensionPopup::ResizeToView() {
origin.set_x(origin.x() + border_insets.left() + kPopupBubbleCornerRadius);
origin.set_y(origin.y() + border_insets.top() + kPopupBubbleCornerRadius);
+ gfx::Size new_size = view()->size();
SetBounds(origin.x(), origin.y(), new_size.width(), new_size.height());
} else {
SetBounds(origin.x(), origin.y(), rect.width(), rect.height());
@@ -296,8 +306,14 @@ void ExtensionPopup::OnExtensionPreferredSizeChanged(ExtensionView* view) {
ResizeToView();
}
-gfx::Rect ExtensionPopup::GetOuterBounds(const gfx::Rect& position_relative_to,
- const gfx::Size& contents_size) const {
+gfx::Rect ExtensionPopup::GetOuterBounds() const {
+ gfx::Rect relative_rect = relative_to_;
+ gfx::Point origin = relative_rect.origin();
+ views::View::ConvertPointToScreen(frame_->GetRootView(), &origin);
+ relative_rect.set_origin(origin);
+
+ gfx::Size contents_size = view()->size();
+
// If the popup has a bubble-chrome, then let the BubbleBorder compute
// the bounds.
if (BUBBLE_CHROME == popup_chrome_) {
@@ -305,23 +321,25 @@ gfx::Rect ExtensionPopup::GetOuterBounds(const gfx::Rect& position_relative_to,
// claim. Since we can't clip the ExtensionView's corners, we need to
// increase the inset by half the corner radius as well as lying about the
// size of the contents size to compensate.
- gfx::Size adjusted_size = contents_size;
- adjusted_size.Enlarge(2 * kPopupBubbleCornerRadius,
+ contents_size.Enlarge(2 * kPopupBubbleCornerRadius,
2 * kPopupBubbleCornerRadius);
- return border_->GetBounds(position_relative_to, adjusted_size);
+ return border_->GetBounds(relative_rect, contents_size);
}
// Position the bounds according to the location of the |anchor_position_|.
int y;
- if ((anchor_position_ == BubbleBorder::TOP_LEFT) ||
- (anchor_position_ == BubbleBorder::TOP_RIGHT)) {
- y = position_relative_to.bottom();
- } else {
- y = position_relative_to.y() - contents_size.height();
- }
-
- return gfx::Rect(position_relative_to.x(), y, contents_size.width(),
- contents_size.height());
+ if (BubbleBorder::is_arrow_on_top(anchor_position_))
+ y = relative_rect.bottom();
+ else
+ y = relative_rect.y() - contents_size.height();
+
+ int x;
+ if (BubbleBorder::is_arrow_on_left(anchor_position_))
+ x = relative_rect.x();
+ else
+ x = relative_rect.x() - contents_size.width();
+
+ return gfx::Rect(x, y, contents_size.width(), contents_size.height());
}
// static
diff --git a/chrome/browser/views/extensions/extension_popup.h b/chrome/browser/views/extensions/extension_popup.h
index 5c62b5d..aafe5d1 100644
--- a/chrome/browser/views/extensions/extension_popup.h
+++ b/chrome/browser/views/extensions/extension_popup.h
@@ -43,6 +43,11 @@ class ExtensionPopup : public BrowserBubble,
// into the popup. An example use is for automation resource routing in
// Chrome-Frame. See extension_popup_api.cc.
virtual void ExtensionHostCreated(ExtensionHost* host) {}
+
+ // Called when the ExtensionPopup is resized. Note that the popup may have
+ // an empty bounds, if a popup is repositioned before the hosted content
+ // has loaded.
+ virtual void ExtensionPopupResized(ExtensionPopup* popup) {}
};
enum PopupChrome {
@@ -100,6 +105,18 @@ class ExtensionPopup : public BrowserBubble,
ExtensionHost* host() const { return extension_host_.get(); }
+ // Assigns the arrow location of the popup view, and updates the popup
+ // border widget, if necessary.
+ void SetArrowPosition(BubbleBorder::ArrowLocation arrow_location);
+ BubbleBorder::ArrowLocation arrow_position() const {
+ return anchor_position_;
+ }
+
+ // Gives the desired bounds (in screen coordinates) given the rect to point
+ // to and the size of the contained contents. Includes all of the
+ // border-chrome surrounding the pop-up as well.
+ gfx::Rect GetOuterBounds() const;
+
// BrowserBubble overrides.
virtual void Hide();
virtual void Show(bool activate);
@@ -138,12 +155,6 @@ class ExtensionPopup : public BrowserBubble,
PopupChrome chrome,
Observer* observer);
- // Gives the desired bounds (in screen coordinates) given the rect to point
- // to and the size of the contained contents. Includes all of the
- // border-chrome surrounding the pop-up as well.
- gfx::Rect GetOuterBounds(const gfx::Rect& position_relative_to,
- const gfx::Size& contents_size) const;
-
// The area on the screen that the popup should be positioned relative to.
gfx::Rect relative_to_;