diff options
author | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-14 01:18:00 +0000 |
---|---|---|
committer | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-14 01:18:00 +0000 |
commit | b8595e9c25fc47e4e0e91683b38f4772b4789f1b (patch) | |
tree | 9cc63c58e432b835a3af85ac89d4cd9df0d33aa9 /chrome/browser | |
parent | 5da4928116a7168b456415f9af412f93138b6dcb (diff) | |
download | chromium_src-b8595e9c25fc47e4e0e91683b38f4772b4789f1b.zip chromium_src-b8595e9c25fc47e4e0e91683b38f4772b4789f1b.tar.gz chromium_src-b8595e9c25fc47e4e0e91683b38f4772b4789f1b.tar.bz2 |
gtk: Hide the status bubble when the mouse nears it.
This isn't as slick as other platforms, in that the bubble
just slides down and gets cropped instead of sliding down out
of the browser window -- doing the latter will probably
require reparenting the bubble into its own window when we
want to move it.
BUG=18311
TEST=ran "nc -l -p 8080", went to localhost:8080, and made sure that the bubble ran away with both LTR and RTL languages
Review URL: http://codereview.chromium.org/392007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31984 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.cc | 10 | ||||
-rw-r--r-- | chrome/browser/browser.h | 6 | ||||
-rw-r--r-- | chrome/browser/cocoa/status_bubble_mac.h | 2 | ||||
-rw-r--r-- | chrome/browser/cocoa/status_bubble_mac.mm | 10 | ||||
-rw-r--r-- | chrome/browser/gtk/download_shelf_gtk.cc | 7 | ||||
-rw-r--r-- | chrome/browser/gtk/rounded_window.cc | 18 | ||||
-rw-r--r-- | chrome/browser/gtk/rounded_window.h | 14 | ||||
-rw-r--r-- | chrome/browser/gtk/status_bubble_gtk.cc | 140 | ||||
-rw-r--r-- | chrome/browser/gtk/status_bubble_gtk.h | 35 | ||||
-rw-r--r-- | chrome/browser/gtk/tab_contents_container_gtk.cc | 14 | ||||
-rw-r--r-- | chrome/browser/status_bubble.h | 9 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_delegate.h | 9 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_gtk.cc | 6 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_mac.mm | 7 | ||||
-rw-r--r-- | chrome/browser/views/status_bubble_views.cc | 35 | ||||
-rw-r--r-- | chrome/browser/views/status_bubble_views.h | 7 | ||||
-rw-r--r-- | chrome/browser/views/tab_contents/tab_contents_view_gtk.cc | 10 | ||||
-rw-r--r-- | chrome/browser/views/tab_contents/tab_contents_view_win.cc | 10 |
18 files changed, 275 insertions, 74 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 7b728e3..ebca665 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -7,6 +7,7 @@ #include "app/animation.h" #include "app/l10n_util.h" #include "base/command_line.h" +#include "base/gfx/point.h" #include "base/keyboard_codes.h" #include "base/logging.h" #include "base/string_util.h" @@ -2020,16 +2021,15 @@ void Browser::URLStarredChanged(TabContents* source, bool starred) { window_->SetStarredState(starred); } -void Browser::ContentsMouseEvent(TabContents* source, bool motion) { +void Browser::ContentsMouseEvent( + TabContents* source, const gfx::Point& location, bool motion) { if (!GetStatusBubble()) return; if (source == GetSelectedTabContents()) { - if (motion) { - GetStatusBubble()->MouseMoved(); - } else { + GetStatusBubble()->MouseMoved(location, !motion); + if (!motion) GetStatusBubble()->SetURL(GURL(), std::wstring()); - } } } diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 243b464..6e65c6a 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -35,6 +35,9 @@ class Profile; class SkBitmap; class StatusBubble; class TabNavigation; +namespace gfx { +class Point; +} class Browser : public TabStripModelDelegate, public TabStripModelObserver, @@ -542,7 +545,8 @@ class Browser : public TabStripModelDelegate, virtual void ToolbarSizeChanged(TabContents* source, bool is_animating); virtual void URLStarredChanged(TabContents* source, bool starred); virtual void UpdateTargetURL(TabContents* source, const GURL& url); - virtual void ContentsMouseEvent(TabContents* source, bool motion); + virtual void ContentsMouseEvent( + TabContents* source, const gfx::Point& location, bool motion); virtual void ContentsZoomChange(bool zoom_in); virtual void TabContentsFocused(TabContents* tab_content); virtual bool TakeFocus(bool reverse); diff --git a/chrome/browser/cocoa/status_bubble_mac.h b/chrome/browser/cocoa/status_bubble_mac.h index f110b1d..8d33f04 100644 --- a/chrome/browser/cocoa/status_bubble_mac.h +++ b/chrome/browser/cocoa/status_bubble_mac.h @@ -36,7 +36,7 @@ class StatusBubbleMac : public StatusBubble { virtual void SetStatus(const std::wstring& status); virtual void SetURL(const GURL& url, const std::wstring& languages); virtual void Hide(); - virtual void MouseMoved(); + virtual void MouseMoved(const gfx::Point& location, bool left_content); virtual void UpdateDownloadShelfVisibility(bool visible); // Mac-specific method: Update the size and position of the status bubble to diff --git a/chrome/browser/cocoa/status_bubble_mac.mm b/chrome/browser/cocoa/status_bubble_mac.mm index 9305100..55b57df 100644 --- a/chrome/browser/cocoa/status_bubble_mac.mm +++ b/chrome/browser/cocoa/status_bubble_mac.mm @@ -8,6 +8,7 @@ #include "app/gfx/text_elider.h" #include "base/compiler_specific.h" +#include "base/gfx/point.h" #include "base/message_loop.h" #include "base/string_util.h" #include "base/sys_string_conversions.h" @@ -206,10 +207,15 @@ void StatusBubbleMac::Hide() { url_text_ = nil; } -void StatusBubbleMac::MouseMoved() { +void StatusBubbleMac::MouseMoved( + const gfx::Point& location, bool left_content) { + if (left_content) + return; + if (!window_) return; + // TODO(thakis): Use 'location' here instead of NSEvent. NSPoint cursor_location = [NSEvent mouseLocation]; --cursor_location.y; // docs say the y coord starts at 1 not 0; don't ask why @@ -330,7 +336,7 @@ void StatusBubbleMac::Create() { Attach(); [view setCornerFlags:kRoundedTopRightCorner]; - MouseMoved(); + MouseMoved(gfx::Point(), false); } void StatusBubbleMac::Attach() { diff --git a/chrome/browser/gtk/download_shelf_gtk.cc b/chrome/browser/gtk/download_shelf_gtk.cc index 336454f..1e13892 100644 --- a/chrome/browser/gtk/download_shelf_gtk.cc +++ b/chrome/browser/gtk/download_shelf_gtk.cc @@ -127,7 +127,7 @@ DownloadShelfGtk::DownloadShelfGtk(Browser* browser, GtkWidget* parent) FALSE, FALSE, 0); // Make sure we are at the very end. gtk_box_reorder_child(GTK_BOX(parent), slide_widget_->widget(), 0); - slide_widget_->Open(); + Show(); } DownloadShelfGtk::~DownloadShelfGtk() { @@ -155,6 +155,7 @@ bool DownloadShelfGtk::IsClosing() const { void DownloadShelfGtk::Show() { slide_widget_->Open(); + browser_->UpdateDownloadShelfVisibility(true); } void DownloadShelfGtk::Close() { @@ -162,8 +163,6 @@ void DownloadShelfGtk::Close() { // we are on top. gdk_window_raise(shelf_.get()->window); slide_widget_->Close(); - - // TODO(estade): Remove. The status bubble should query its window instead. browser_->UpdateDownloadShelfVisibility(false); } @@ -224,8 +223,6 @@ void DownloadShelfGtk::RemoveDownloadItem(DownloadItemGtk* download_item) { delete download_item; if (download_items_.empty()) { slide_widget_->CloseWithoutAnimation(); - - // TODO(estade): Remove. The status bubble should query its window instead. browser_->UpdateDownloadShelfVisibility(false); } } diff --git a/chrome/browser/gtk/rounded_window.cc b/chrome/browser/gtk/rounded_window.cc index 79af804..b6174b4 100644 --- a/chrome/browser/gtk/rounded_window.cc +++ b/chrome/browser/gtk/rounded_window.cc @@ -184,6 +184,8 @@ void ActAsRoundedWindow( GtkWidget* widget, const GdkColor& color, int corner_size, int rounded_edges, int drawn_borders) { DCHECK(widget); + DCHECK(!g_object_get_data(G_OBJECT(widget), kRoundedData)); + gtk_widget_set_app_paintable(widget, TRUE); g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(OnRoundedWindowExpose), NULL); @@ -209,10 +211,26 @@ void StopActingAsRoundedWindow(GtkWidget* widget) { g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<gpointer>(OnStyleSet), NULL); + delete static_cast<RoundedWindowData*>( + g_object_steal_data(G_OBJECT(widget), kRoundedData)); + if (GTK_WIDGET_REALIZED(widget)) gdk_window_shape_combine_mask(widget->window, NULL, 0, 0); } +void SetRoundedWindowEdgesAndBorders(GtkWidget* widget, + int corner_size, + int rounded_edges, + int drawn_borders) { + DCHECK(widget); + RoundedWindowData* data = static_cast<RoundedWindowData*>( + g_object_get_data(G_OBJECT(widget), kRoundedData)); + DCHECK(data); + data->corner_size = corner_size; + data->rounded_edges = rounded_edges; + data->drawn_borders = drawn_borders; +} + void SetRoundedWindowBorderColor(GtkWidget* widget, GdkColor color) { DCHECK(widget); RoundedWindowData* data = static_cast<RoundedWindowData*>( diff --git a/chrome/browser/gtk/rounded_window.h b/chrome/browser/gtk/rounded_window.h index 46287ff..95f91d9 100644 --- a/chrome/browser/gtk/rounded_window.h +++ b/chrome/browser/gtk/rounded_window.h @@ -39,13 +39,21 @@ void ActAsRoundedWindow( GtkWidget* widget, const GdkColor& color, int corner_size, int rounded_edges, int drawn_borders); -// Undo most of the actions of ActAsRoundedWindow. +// Undoes most of the actions of ActAsRoundedWindow(). void StopActingAsRoundedWindow(GtkWidget* widget); -// Sets the color of the border on a widget that was returned from -// ActAsRoundedWindow(). +// Sets edge and border properties on a widget that has already been configured +// with ActAsRoundedWindow(). +void SetRoundedWindowEdgesAndBorders(GtkWidget* widget, + int corner_size, + int rounded_edges, + int drawn_borders); + +// Sets the color of the border on a widget that has already been configured +// with ActAsRoundedWindow(). void SetRoundedWindowBorderColor(GtkWidget* widget, GdkColor color); + } // namespace gtk_util #endif // CHROME_BROWSER_GTK_ROUNDED_WINDOW_H_ diff --git a/chrome/browser/gtk/status_bubble_gtk.cc b/chrome/browser/gtk/status_bubble_gtk.cc index 5ee330d..a57c05b 100644 --- a/chrome/browser/gtk/status_bubble_gtk.cc +++ b/chrome/browser/gtk/status_bubble_gtk.cc @@ -30,11 +30,20 @@ const int kCornerSize = 3; // Milliseconds before we hide the status bubble widget when you mouseout. const int kHideDelay = 250; +// How close the mouse can get to the infobubble before it starts sliding +// off-screen. +const int kMousePadding = 20; + } // namespace StatusBubbleGtk::StatusBubbleGtk(Profile* profile) : theme_provider_(GtkThemeProvider::GetFrom(profile)), - timer_factory_(this) { + padding_(NULL), + label_(NULL), + timer_factory_(this), + flip_horizontally_(false), + y_offset_(0), + download_shelf_is_visible_(false) { InitWidgets(); theme_provider_->InitThemesFor(this); @@ -114,13 +123,77 @@ void StatusBubbleGtk::HideInASecond() { kHideDelay); } -void StatusBubbleGtk::MouseMoved() { - // We can't do that fancy sliding behaviour where the status bubble slides - // out of the window because the window manager gets in the way. So totally - // ignore this message for now. - // - // TODO(erg): At least get some sliding behaviour so that it slides out of - // the way to hide the status bubble on mouseover. +void StatusBubbleGtk::MouseMoved( + const gfx::Point& location, bool left_content) { + if (!GTK_WIDGET_REALIZED(container_.get())) + return; + + GtkWidget* parent = gtk_widget_get_parent(container_.get()); + if (!parent || !GTK_WIDGET_REALIZED(parent)) + return; + + int old_y_offset = y_offset_; + bool old_flip_horizontally = flip_horizontally_; + + if (left_content) { + SetFlipHorizontally(false); + y_offset_ = 0; + } else { + GtkWidget* toplevel = gtk_widget_get_toplevel(container_.get()); + if (!toplevel || !GTK_WIDGET_REALIZED(toplevel)) + return; + + bool ltr = (l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT); + + GtkRequisition requisition; + gtk_widget_size_request(container_.get(), &requisition); + + // Get our base position (that is, not including the current offset) + // relative to the origin of the root window. + gint toplevel_x = 0, toplevel_y = 0; + gdk_window_get_position(toplevel->window, &toplevel_x, &toplevel_y); + gfx::Rect parent_rect = + gtk_util::GetWidgetRectRelativeToToplevel(parent); + gfx::Rect bubble_rect( + toplevel_x + parent_rect.x() + + (ltr ? 0 : parent->allocation.width - requisition.width), + toplevel_y + parent_rect.y() + + parent->allocation.height - requisition.height, + requisition.width, + requisition.height); + + int left_threshold = + bubble_rect.x() - bubble_rect.height() - kMousePadding; + int right_threshold = + bubble_rect.right() + bubble_rect.height() + kMousePadding; + int top_threshold = bubble_rect.y() - kMousePadding; + + if (((ltr && location.x() < right_threshold) || + (!ltr && location.x() > left_threshold)) && + location.y() > top_threshold) { + if (download_shelf_is_visible_) { + SetFlipHorizontally(true); + y_offset_ = 0; + } else { + SetFlipHorizontally(false); + int distance = std::max(ltr ? + location.x() - right_threshold : + left_threshold - location.x(), + top_threshold - location.y()); + y_offset_ = std::min(-1 * distance, requisition.height); + } + } else { + SetFlipHorizontally(false); + y_offset_ = 0; + } + } + + if (y_offset_ != old_y_offset || flip_horizontally_ != old_flip_horizontally) + gtk_widget_queue_resize_no_redraw(parent); +} + +void StatusBubbleGtk::UpdateDownloadShelfVisibility(bool visible) { + download_shelf_is_visible_ = visible; } void StatusBubbleGtk::Observe(NotificationType type, @@ -132,14 +205,16 @@ void StatusBubbleGtk::Observe(NotificationType type, } void StatusBubbleGtk::InitWidgets() { + bool ltr = (l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT); + label_ = gtk_label_new(NULL); - GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1); - gtk_alignment_set_padding(GTK_ALIGNMENT(padding), + padding_ = gtk_alignment_new(0, 0, 1, 1); + gtk_alignment_set_padding(GTK_ALIGNMENT(padding_), kInternalTopBottomPadding, kInternalTopBottomPadding, - kInternalLeftRightPadding, - kInternalLeftRightPadding + kCornerSize); - gtk_container_add(GTK_CONTAINER(padding), label_); + kInternalLeftRightPadding + (ltr ? 0 : kCornerSize), + kInternalLeftRightPadding + (ltr ? kCornerSize : 0)); + gtk_container_add(GTK_CONTAINER(padding_), label_); container_.Own(gtk_event_box_new()); gtk_util::ActAsRoundedWindow( @@ -147,7 +222,14 @@ void StatusBubbleGtk::InitWidgets() { gtk_util::ROUNDED_TOP_RIGHT, gtk_util::BORDER_TOP | gtk_util::BORDER_RIGHT); gtk_widget_set_name(container_.get(), "status-bubble"); - gtk_container_add(GTK_CONTAINER(container_.get()), padding); + gtk_container_add(GTK_CONTAINER(container_.get()), padding_); + + // We need to listen for mouse motion events, since a fast-moving pointer may + // enter our window without us getting any motion events on the browser near + // enough for us to run away. + gtk_widget_add_events(container_.get(), GDK_POINTER_MOTION_MASK); + g_signal_connect(container_.get(), "motion-notify-event", + G_CALLBACK(HandleMotionNotifyThunk), this); UserChangedTheme(); } @@ -172,3 +254,33 @@ void StatusBubbleGtk::UserChangedTheme() { gtk_util::SetRoundedWindowBorderColor(container_.get(), theme_provider_->GetBorderColor()); } + +void StatusBubbleGtk::SetFlipHorizontally(bool flip_horizontally) { + if (flip_horizontally == flip_horizontally_) + return; + + flip_horizontally_ = flip_horizontally; + + bool ltr = (l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT); + bool on_left = (ltr && !flip_horizontally) || (!ltr && flip_horizontally); + + gtk_alignment_set_padding(GTK_ALIGNMENT(padding_), + kInternalTopBottomPadding, kInternalTopBottomPadding, + kInternalLeftRightPadding + (on_left ? 0 : kCornerSize), + kInternalLeftRightPadding + (on_left ? kCornerSize : 0)); + // The rounded window code flips these arguments if we're RTL. + gtk_util::SetRoundedWindowEdgesAndBorders( + container_.get(), + kCornerSize, + flip_horizontally ? + gtk_util::ROUNDED_TOP_LEFT : + gtk_util::ROUNDED_TOP_RIGHT, + gtk_util::BORDER_TOP | + (flip_horizontally ? gtk_util::BORDER_LEFT : gtk_util::BORDER_RIGHT)); + gtk_widget_queue_draw(container_.get()); +} + +gboolean StatusBubbleGtk::HandleMotionNotify(GdkEventMotion* event) { + MouseMoved(gfx::Point(event->x_root, event->y_root), false); + return FALSE; +} diff --git a/chrome/browser/gtk/status_bubble_gtk.h b/chrome/browser/gtk/status_bubble_gtk.h index 87b43d3..9784668 100644 --- a/chrome/browser/gtk/status_bubble_gtk.h +++ b/chrome/browser/gtk/status_bubble_gtk.h @@ -9,6 +9,7 @@ #include <string> +#include "base/gfx/point.h" #include "base/scoped_ptr.h" #include "base/task.h" #include "chrome/browser/status_bubble.h" @@ -30,16 +31,19 @@ class StatusBubbleGtk : public StatusBubble, explicit StatusBubbleGtk(Profile* profile); virtual ~StatusBubbleGtk(); + bool flip_horizontally() const { return flip_horizontally_; } + int y_offset() const { return y_offset_; } + // StatusBubble implementation. virtual void SetStatus(const std::wstring& status); virtual void SetURL(const GURL& url, const std::wstring& languages); virtual void Hide(); - virtual void MouseMoved(); + virtual void MouseMoved(const gfx::Point& location, bool left_content); // Called when the download shelf becomes visible or invisible. // This is used by to ensure that the status bubble does not obscure // the download shelf, when it is visible. - virtual void UpdateDownloadShelfVisibility(bool visible) { } + virtual void UpdateDownloadShelfVisibility(bool visible); // Overridden from NotificationObserver: void Observe(NotificationType type, @@ -69,6 +73,19 @@ class StatusBubbleGtk : public StatusBubble, // Notification from the window that we should retheme ourself. void UserChangedTheme(); + // Sets whether the bubble should be flipped horizontally and displayed on the + // opposite side of the tab contents. Reshapes the container and queues a + // redraw if necessary. + void SetFlipHorizontally(bool flip_horizontally); + + static gboolean HandleMotionNotifyThunk(GtkWidget* widget, + GdkEventMotion* event, + gpointer user_data) { + return reinterpret_cast<StatusBubbleGtk*>(user_data)-> + HandleMotionNotify(event); + } + gboolean HandleMotionNotify(GdkEventMotion* event); + NotificationRegistrar registrar_; // Provides colors. @@ -77,6 +94,9 @@ class StatusBubbleGtk : public StatusBubble, // The toplevel event box. OwnedWidgetGtk container_; + // The GtkAlignment holding |label_|. + GtkWidget* padding_; + // The GtkLabel holding the text. GtkWidget* label_; @@ -88,6 +108,17 @@ class StatusBubbleGtk : public StatusBubble, // A timer that hides our window after a delay. ScopedRunnableMethodFactory<StatusBubbleGtk> timer_factory_; + + // Should the bubble be flipped horizontally (e.g. displayed on the right for + // an LTR language)? We move the bubble to the other side of the tab contents + // rather than sliding it down when the download shelf is visible. + bool flip_horizontally_; + + // Vertical offset used to hide the status bubble as the pointer nears it. + int y_offset_; + + // If the download shelf is visible, do not obscure it. + bool download_shelf_is_visible_; }; #endif // CHROME_BROWSER_GTK_STATUS_BUBBLE_GTK_H_ diff --git a/chrome/browser/gtk/tab_contents_container_gtk.cc b/chrome/browser/gtk/tab_contents_container_gtk.cc index 9425194..a4fe973 100644 --- a/chrome/browser/gtk/tab_contents_container_gtk.cc +++ b/chrome/browser/gtk/tab_contents_container_gtk.cc @@ -188,26 +188,28 @@ void TabContentsContainerGtk::OnFixedSizeAllocate( void TabContentsContainerGtk::OnSetFloatingPosition( GtkFloatingContainer* floating_container, GtkAllocation* allocation, TabContentsContainerGtk* tab_contents_container) { - GtkWidget* status = tab_contents_container->status_bubble_->widget(); + StatusBubbleGtk* status = tab_contents_container->status_bubble_; // Look at the size request of the status bubble and tell the // GtkFloatingContainer where we want it positioned. GtkRequisition requisition; - gtk_widget_size_request(status, &requisition); + gtk_widget_size_request(status->widget(), &requisition); + + bool ltr = (l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT); GValue value = { 0, }; g_value_init(&value, G_TYPE_INT); - if (l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT) + if (ltr ^ status->flip_horizontally()) // Is it on the left? g_value_set_int(&value, 0); else g_value_set_int(&value, allocation->width - requisition.width); gtk_container_child_set_property(GTK_CONTAINER(floating_container), - status, "x", &value); + status->widget(), "x", &value); int child_y = std::max( allocation->y + allocation->height - requisition.height, 0); - g_value_set_int(&value, child_y); + g_value_set_int(&value, child_y + status->y_offset()); gtk_container_child_set_property(GTK_CONTAINER(floating_container), - status, "y", &value); + status->widget(), "y", &value); g_value_unset(&value); } diff --git a/chrome/browser/status_bubble.h b/chrome/browser/status_bubble.h index 9203b80..81379d0 100644 --- a/chrome/browser/status_bubble.h +++ b/chrome/browser/status_bubble.h @@ -8,6 +8,9 @@ #include <string> class GURL; +namespace gfx { +class Point; +} //////////////////////////////////////////////////////////////////////////////// // StatusBubble interface @@ -37,8 +40,10 @@ class StatusBubble { // Called when the user's mouse has moved over web content. This is used to // determine when the status area should move out of the way of the user's // mouse. This may be windows specific pain due to the way messages are - // processed for child HWNDs. - virtual void MouseMoved() = 0; + // processed for child HWNDs. |position| is the absolute position of the + // pointer, and |left_content| is true if the mouse just left the content + // area. + virtual void MouseMoved(const gfx::Point& position, bool left_content) = 0; // Called when the download shelf becomes visible or invisible. // This is used by to ensure that the status bubble does not obscure diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h index f5fdfcf..b4d3009 100644 --- a/chrome/browser/tab_contents/tab_contents_delegate.h +++ b/chrome/browser/tab_contents/tab_contents_delegate.h @@ -94,11 +94,14 @@ class TabContentsDelegate { // Notification that the starredness of the current URL changed. virtual void URLStarredChanged(TabContents* source, bool starred) = 0; - // Notification that the target URL has changed + // Notification that the target URL has changed. virtual void UpdateTargetURL(TabContents* source, const GURL& url) = 0; - // Notification that there was a mouse event - virtual void ContentsMouseEvent(TabContents* source, bool motion) { } + // Notification that there was a mouse event, along with the absolute + // coordinates of the mouse pointer and whether it was a normal motion event + // (otherwise, the pointer left the contents area). + virtual void ContentsMouseEvent( + TabContents* source, const gfx::Point& location, bool motion) { } // Request the delegate to change the zoom level of the current tab. virtual void ContentsZoomChange(bool zoom_in) { } diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc index 332c7cd..61c685e 100644 --- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc +++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc @@ -69,7 +69,8 @@ gboolean OnFocus(GtkWidget* widget, GtkDirectionType focus, gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event, TabContents* tab_contents) { if (tab_contents->delegate()) - tab_contents->delegate()->ContentsMouseEvent(tab_contents, false); + tab_contents->delegate()->ContentsMouseEvent( + tab_contents, gfx::Point(event->x_root, event->y_root), false); return FALSE; } @@ -77,7 +78,8 @@ gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event, gboolean OnMouseMove(GtkWidget* widget, GdkEventMotion* event, TabContents* tab_contents) { if (tab_contents->delegate()) - tab_contents->delegate()->ContentsMouseEvent(tab_contents, true); + tab_contents->delegate()->ContentsMouseEvent( + tab_contents, gfx::Point(event->x_root, event->y_root), true); return FALSE; } diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm index 9a06d66..60bc43a 100644 --- a/chrome/browser/tab_contents/tab_contents_view_mac.mm +++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm @@ -406,10 +406,13 @@ void TabContentsViewMac::Observe(NotificationType type, - (void)mouseEvent:(NSEvent *)theEvent { TabContents* tabContents = [self tabContents]; if (tabContents->delegate()) { + NSPoint location = [NSEvent mouseLocation]; if ([theEvent type] == NSMouseMoved) - tabContents->delegate()->ContentsMouseEvent(tabContents, true); + tabContents->delegate()->ContentsMouseEvent( + tabContents, gfx::Point(location.x, location.y), true); if ([theEvent type] == NSMouseExited) - tabContents->delegate()->ContentsMouseEvent(tabContents, false); + tabContents->delegate()->ContentsMouseEvent( + tabContents, gfx::Point(location.x, location.y), false); } } diff --git a/chrome/browser/views/status_bubble_views.cc b/chrome/browser/views/status_bubble_views.cc index 9642294..fbf8153 100644 --- a/chrome/browser/views/status_bubble_views.cc +++ b/chrome/browser/views/status_bubble_views.cc @@ -11,6 +11,7 @@ #include "app/l10n_util.h" #include "app/animation.h" #include "app/resource_bundle.h" +#include "base/gfx/point.h" #include "base/message_loop.h" #include "base/string_util.h" #include "chrome/browser/browser_theme_provider.h" @@ -572,14 +573,18 @@ void StatusBubbleViews::Hide() { view_->Hide(); } -void StatusBubbleViews::MouseMoved() { +void StatusBubbleViews::MouseMoved(const gfx::Point& location, + bool left_content) { + if (left_content) + return; + if (view_) { view_->ResetTimer(); if (view_->GetState() != StatusView::BUBBLE_HIDDEN && view_->GetState() != StatusView::BUBBLE_HIDING_FADE && view_->GetState() != StatusView::BUBBLE_HIDING_TIMER) { - AvoidMouse(); + AvoidMouse(location); } } } @@ -588,42 +593,40 @@ void StatusBubbleViews::UpdateDownloadShelfVisibility(bool visible) { download_shelf_is_visible_ = visible; } -void StatusBubbleViews::AvoidMouse() { +void StatusBubbleViews::AvoidMouse(const gfx::Point& location) { // Get the position of the frame. gfx::Point top_left; views::RootView* root = frame_->GetRootView(); views::View::ConvertPointToScreen(root, &top_left); int window_width = root->GetLocalBounds(true).width(); // border included. - // Our status bubble is located in screen coordinates, so we should get - // those rather than attempting to reverse decode the web contents - // coordinates. - gfx::Point cursor_location = views::Screen::GetCursorScreenPoint(); - // Get the cursor position relative to the popup. + gfx::Point relative_location = location; if (view_->UILayoutIsRightToLeft()) { int top_right_x = top_left.x() + window_width; - cursor_location.set_x(top_right_x - cursor_location.x()); + relative_location.set_x(top_right_x - relative_location.x()); } else { - cursor_location.set_x(cursor_location.x() - (top_left.x() + position_.x())); + relative_location.set_x( + relative_location.x() - (top_left.x() + position_.x())); } - cursor_location.set_y(cursor_location.y() - (top_left.y() + position_.y())); + relative_location.set_y( + relative_location.y() - (top_left.y() + position_.y())); // If the mouse is in a position where we think it would move the // status bubble, figure out where and how the bubble should be moved. - if (cursor_location.y() > -kMousePadding && - cursor_location.x() < size_.width() + kMousePadding) { - int offset = kMousePadding + cursor_location.y(); + if (relative_location.y() > -kMousePadding && + relative_location.x() < size_.width() + kMousePadding) { + int offset = kMousePadding + relative_location.y(); // Make the movement non-linear. offset = offset * offset / kMousePadding; // When the mouse is entering from the right, we want the offset to be // scaled by how horizontally far away the cursor is from the bubble. - if (cursor_location.x() > size_.width()) { + if (relative_location.x() > size_.width()) { offset = static_cast<int>(static_cast<float>(offset) * ( static_cast<float>(kMousePadding - - (cursor_location.x() - size_.width())) / + (relative_location.x() - size_.width())) / static_cast<float>(kMousePadding))); } diff --git a/chrome/browser/views/status_bubble_views.h b/chrome/browser/views/status_bubble_views.h index 06bf6bd..78d3265 100644 --- a/chrome/browser/views/status_bubble_views.h +++ b/chrome/browser/views/status_bubble_views.h @@ -11,6 +11,9 @@ #include "chrome/browser/status_bubble.h" class GURL; +namespace gfx { +class Point; +} namespace views { class Widget; } @@ -44,7 +47,7 @@ class StatusBubbleViews : public StatusBubble { virtual void SetStatus(const std::wstring& status); virtual void SetURL(const GURL& url, const std::wstring& languages); virtual void Hide(); - virtual void MouseMoved(); + virtual void MouseMoved(const gfx::Point& location, bool left_content); virtual void UpdateDownloadShelfVisibility(bool visible); private: @@ -55,7 +58,7 @@ class StatusBubbleViews : public StatusBubble { // Attempt to move the status bubble out of the way of the cursor, allowing // users to see links in the region normally occupied by the status bubble. - void AvoidMouse(); + void AvoidMouse(const gfx::Point& location); // Returns true if the frame_ is visible and not minimized. bool IsFrameVisible(); diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc index fce6c9c..7db5ad4 100644 --- a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc +++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc @@ -26,8 +26,9 @@ #include "chrome/browser/views/blocked_popup_container_view_views.h" #include "chrome/browser/views/sad_tab_view.h" #include "chrome/browser/views/tab_contents/render_view_context_menu_win.h" -#include "views/focus/view_storage.h" #include "views/controls/native/native_view_host.h" +#include "views/focus/view_storage.h" +#include "views/screen.h" #include "views/widget/root_view.h" using WebKit::WebDragOperation; @@ -62,7 +63,8 @@ gboolean OnFocus(GtkWidget* widget, GtkDirectionType focus, gboolean OnLeaveNotify2(GtkWidget* widget, GdkEventCrossing* event, TabContents* tab_contents) { if (tab_contents->delegate()) - tab_contents->delegate()->ContentsMouseEvent(tab_contents, false); + tab_contents->delegate()->ContentsMouseEvent( + tab_contents, views::Screen::GetCursorScreenPoint(), false); return FALSE; } @@ -70,7 +72,8 @@ gboolean OnLeaveNotify2(GtkWidget* widget, GdkEventCrossing* event, gboolean OnMouseMove(GtkWidget* widget, GdkEventMotion* event, TabContents* tab_contents) { if (tab_contents->delegate()) - tab_contents->delegate()->ContentsMouseEvent(tab_contents, true); + tab_contents->delegate()->ContentsMouseEvent( + tab_contents, views::Screen::GetCursorScreenPoint(), true); return FALSE; } @@ -423,4 +426,3 @@ void TabContentsViewGtk::SetFloatingPosition(const gfx::Size& size) { PositionChild(widget, child_x, 0, requisition.width, requisition.height); } } - diff --git a/chrome/browser/views/tab_contents/tab_contents_view_win.cc b/chrome/browser/views/tab_contents/tab_contents_view_win.cc index a0a0beb..9c79650 100644 --- a/chrome/browser/views/tab_contents/tab_contents_view_win.cc +++ b/chrome/browser/views/tab_contents/tab_contents_view_win.cc @@ -31,6 +31,7 @@ #include "chrome/common/url_constants.h" #include "net/base/net_util.h" #include "views/focus/view_storage.h" +#include "views/screen.h" #include "views/widget/root_view.h" #include "webkit/glue/webdropdata.h" @@ -474,7 +475,8 @@ void TabContentsViewWin::OnMouseLeave() { // Let our delegate know that the mouse moved (useful for resetting status // bubble state). if (tab_contents()->delegate()) - tab_contents()->delegate()->ContentsMouseEvent(tab_contents(), false); + tab_contents()->delegate()->ContentsMouseEvent( + tab_contents(), views::Screen::GetCursorScreenPoint(), false); SetMsgHandled(FALSE); } @@ -496,9 +498,9 @@ LRESULT TabContentsViewWin::OnMouseRange(UINT msg, case WM_MOUSEMOVE: // Let our delegate know that the mouse moved (useful for resetting status // bubble state). - if (tab_contents()->delegate()) { - tab_contents()->delegate()->ContentsMouseEvent(tab_contents(), true); - } + if (tab_contents()->delegate()) + tab_contents()->delegate()->ContentsMouseEvent( + tab_contents(), views::Screen::GetCursorScreenPoint(), true); break; default: break; |