Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4038)

Unified Diff: chrome/browser/gtk/status_bubble_gtk.cc

Issue 392007: gtk: Hide the status bubble when the mouse nears it. (Closed)
Patch Set: merge again Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/gtk/status_bubble_gtk.h ('k') | chrome/browser/gtk/tab_contents_container_gtk.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/gtk/status_bubble_gtk.cc
diff --git a/chrome/browser/gtk/status_bubble_gtk.cc b/chrome/browser/gtk/status_bubble_gtk.cc
index 5ee330d5694fe3b47e9f077dc20599a38b249c09..a57c05bc0a732a86bf1821cdec2683a16fc6269c 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;
+}
« no previous file with comments | « chrome/browser/gtk/status_bubble_gtk.h ('k') | chrome/browser/gtk/tab_contents_container_gtk.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698