Re: Tooltips patch [take 1]



On Thu, 26 Oct 2006, Kristian Rietveld wrote:

On Wed, Oct 11, 2006 at 04:42:02PM +0200, Kristian Rietveld wrote:

I think I finally managed to process Tim's comments, so here is another
iteration of the tooltips patch.  Biggest changes are:

- Event handling and "widget finder" have basically been rewritten
  using Tim's comments.

- Code to handle screen-changed and display closure has been added.

- All timeouts are now configurable through GtkSettings.

- gtk-tooltip RC style, and lots of small changes.


Some thoughts:

- The positioning code might need some more love, for example I don't fully
  like the behaviour in tree view yet.  Though a tooltip following
  the mouse pointer on the tree view is probably pretty annoying.
  Also the header and row tooltips show up at the same location
  when still in browse mode (we can fix this to determine the location
  based on GdkWindow instead of GtkWidget, but that breaks other stuff
  again).

i've not commented on positioning in this email.
i suspect that at some point we'll want to factor this out into a seperate (maybe pluggable) function anyway, and possibly provide
alternative positioning schemes.
it's definitely one of the areas that can/will be worked on in SVN.

- I will fill in the doc comments as soon as this code hits CVS.

great. ;)


diff -u -p -r1.446 gtkwidget.c
--- gtk/gtkwidget.c	8 Oct 2006 05:07:45 -0000	1.446
+++ gtk/gtkwidget.c	26 Oct 2006 11:04:26 -0000

+static void
+gtk_widget_set_has_tooltip (GtkWidget *widget,
+			    gboolean   has_tooltip,
+			    gboolean   force)
+{
+  gboolean priv_has_tooltip;
+
+  priv_has_tooltip = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (widget),
+				       quark_has_tooltip));
+
+  if (priv_has_tooltip != has_tooltip || force)
+    {
+      priv_has_tooltip = has_tooltip;
+
+      if (priv_has_tooltip)
+        {
+	  /* FIXME: do we need to walk the GdkWindow children of
+	   * widget->window?
+	   */

i'm fairly sure the answer to this FIXME is no.
since X sends events a child window is not interested in to the
parent/ancestor window that subscribed to the respective event type.
in this case, that'd be widget->window.

+	  if (GTK_WIDGET_REALIZED (widget) && GTK_WIDGET_NO_WINDOW (widget))
+	    gdk_window_set_events (widget->window,
+				   gdk_window_get_events (widget->window) |
+				   GDK_LEAVE_NOTIFY_MASK |
+				   GDK_POINTER_MOTION_MASK |
+				   GDK_POINTER_MOTION_HINT_MASK);
+
+	  if (!GTK_WIDGET_NO_WINDOW (widget))
+	      gtk_widget_add_events (widget,
+				     GDK_LEAVE_NOTIFY_MASK |
+				     GDK_POINTER_MOTION_MASK |
+				     GDK_POINTER_MOTION_HINT_MASK);
+	}
+
+      g_object_set_qdata (G_OBJECT (widget), quark_has_tooltip,
+			  GUINT_TO_POINTER (priv_has_tooltip));
+    }
+}

+void
+gtk_widget_set_tooltip_window (GtkWidget *widget,
+			       GtkWindow *custom_window)
+{
+  gboolean tmp;
+  gchar *tooltip_markup;
+  GtkWindow *tooltip_window;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  if (custom_window)
+    g_return_if_fail (GTK_IS_WINDOW (custom_window));
+
+  tooltip_window = g_object_get_qdata (G_OBJECT (widget), quark_tooltip_window);
+  tooltip_markup = g_object_get_qdata (G_OBJECT (widget), quark_tooltip_markup);
+
+  if (custom_window)
+    g_object_ref (custom_window);
+
+  if (tooltip_window)
+    g_object_unref (tooltip_window);
+
+  tooltip_window = custom_window;
+  g_object_set_qdata_full (G_OBJECT (widget), quark_tooltip_window,
+			   tooltip_window, g_object_unref);
+
+  tmp = (tooltip_window != NULL || tooltip_markup != NULL);
+  gtk_widget_set_has_tooltip (widget, tmp, FALSE);
+
+  gtk_widget_trigger_tooltip_query (widget);

as a slight optimization, this could be changed like this, right?

  +  if (tmp)
  +    gtk_widget_trigger_tooltip_query (widget);

+}



diff -N gtk/gtktooltip.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gtk/gtktooltip.c	26 Oct 2006 11:04:26 -0000

+void
+gtk_tooltip_set_custom (GtkTooltip *tooltip,
+			GtkWidget  *custom_widget)
+{
+  g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
+  if (custom_widget)
+    g_return_if_fail (GTK_IS_WIDGET (custom_widget));
+
+  if (tooltip->custom_widget)
+    gtk_container_remove (GTK_CONTAINER (tooltip->box), tooltip->custom_widget);

this lacks an unref on tooltip->custom_widget after gtk_container_remove.

+
+  if (custom_widget)
+    {
+      tooltip->custom_widget = g_object_ref (custom_widget);

it is this ref that is leaked above.

+
+      gtk_container_add (GTK_CONTAINER (tooltip->box), custom_widget);
+      gtk_widget_show (custom_widget);
+    }
+  else
+    tooltip->custom_widget = NULL;
+}

+static gboolean
+gtk_tooltip_paint_window (GtkTooltip *tooltip)
+{
+  GtkRequisition req;
+
+  gtk_widget_size_request (tooltip->window, &req);
+  gtk_paint_flat_box (tooltip->window->style,
+		      tooltip->window->window,
+		      GTK_STATE_NORMAL,
+		      GTK_SHADOW_OUT,
+		      NULL,
+		      tooltip->window,
+		      "tooltip",
+		      0, 0,
+		      req.width, req.height);

erm, this paints a box at the size the window would like to have, not
necessarily the size it has. size requisition is always a bad figure
to use for painint, people should always only use the actual allocation
which may be gotten via widget->allocation or gdk_window_get_size.

+
+  return FALSE;
+}
+
+static void
+gtk_tooltip_window_hide (GtkWidget *widget,
+			 gpointer   user_data)
+{
+  GtkTooltip *tooltip = GTK_TOOLTIP (user_data);
+
+  if (tooltip->custom_widget)
+    {
+      g_object_unref (tooltip->custom_widget);
+      tooltip->custom_widget = NULL;

ah, here you seem to be handling the custom_widget unref.
i think the code is a bit risky this way though, i'd recommend to:
- always use gtk_tooltip_set_custom (tooltip, NULL); tu clean up the
  custom widget, like you do in gtk_tooltip_reset
- always perform the gtk_container_remove (, custom_widget) together
  with unref (custom_widget); and preferably implement this only once.

+    }
+}
+
+/* event handling, etc */
+
+struct ChildLocation
+{
+  GtkWidget *child;
+  GtkWidget *container;
+
+  gint x;
+  gint y;
+};
+
+static void
+child_location_foreach (GtkWidget *child,
+			gpointer   data)
+{
+  struct ChildLocation *child_loc = data;
+
+  if (!child_loc->child)
+    {
+      gint x, y;
+
+      gtk_widget_translate_coordinates (child_loc->container, child,
+					child_loc->x, child_loc->y,
+					&x, &y);
+
+      if (x >= 0 && x < child->allocation.width
+	  && y >= 0 && y < child->allocation.height)
+        {
+	  if (GTK_IS_CONTAINER (child))
+	    {
+	      struct ChildLocation tmp = { NULL, NULL, 0, 0 };
+
+	      tmp.x = x;
+	      tmp.y = y;
+	      tmp.container = child;
+
+	      gtk_container_foreach (GTK_CONTAINER (child),
+				     child_location_foreach, &tmp);
+
+	      if (tmp.child)
+		child_loc->child = tmp.child;
+	      else
+		child_loc->child = child;
+	    }
+	  else
+	    child_loc->child = child;
+	}
+    }
+}
+
+static void
+window_to_alloc (GtkWidget *dest_widget,
+		 gint       src_x,
+		 gint       src_y,
+		 gint      *dest_x,
+		 gint      *dest_y)
+{
+  /* Translate from window relative to allocation relative */
+  if (!GTK_WIDGET_NO_WINDOW (dest_widget) && dest_widget->parent)
+    {
+      gint wx, wy;
+      gdk_window_get_position (dest_widget->window, &wx, &wy);
+
+      src_x += wx - dest_widget->allocation.x;
+      src_y += wy - dest_widget->allocation.y;
+    }
+  else
+    {
+      src_x -= dest_widget->allocation.x;
+      src_y -= dest_widget->allocation.y;
+    }

this doesn't seem right to me. is this code copied from somewhere?
to go from window relative to allocaiton relative, the necessary
steps are (should work regardless of NO_WINDOW (widget)):
1- figure the window offset relative to the window returned by
   gtk_widget_get_parent_window().
2- add the window offset to the coords (this makes them parent_window
   relative)
3- subtract widget->allocation from the coords (this goes from
   parent_window relative to widget->allocation relative)
here, 1 has to be able to deal with an arbitrary intermediate hierarchy
of gdkwindows.

+
+  if (dest_x)
+    *dest_x = src_x;
+  if (dest_y)
+    *dest_y = src_y;
+}
+
+static GtkWidget *
+find_widget_under_pointer (GdkWindow *window,
+			   gint      *x,
+			   gint      *y)
+{
+  GtkWidget *event_widget;
+  struct ChildLocation child_loc = { NULL, NULL, 0, 0 };
+
+  child_loc.x = *x;
+  child_loc.y = *y;
+
+  gdk_window_get_user_data (window, (void **)&event_widget);
+  if (GTK_IS_CONTAINER (event_widget))
+    {

huh? event->window may as well belong to a non-container widget,
so i think you need to use GTK_IS_WIDGET instead here.

+      child_loc.child = event_widget;

this line...

+
+      window_to_alloc (event_widget,
+		       child_loc.x, child_loc.y,
+		       &child_loc.x, &child_loc.y);
+
+      event_widget = child_loc.container = child_loc.child;
+      child_loc.child = NULL;

and these two could be reworked to be less confusing, since
you don't need child_loc.child readily setup in window_to_alloc().

+
+      gtk_container_foreach (GTK_CONTAINER (event_widget),
+			     child_location_foreach, &child_loc);
+
+      if (child_loc.child)
+	event_widget = child_loc.child;
+      else if (child_loc.container)
+	event_widget = child_loc.container;
+    }
+
+  if (x)
+    *x = child_loc.x;
+  if (y)
+    *y = child_loc.y;
+
+  return event_widget;
+}
+
+static GtkWidget *
+find_has_tooltip_widget (GdkEvent *event,
+			 gint     *x,
+			 gint     *y)

please let me suggest a slight rename here (already considering
below comments):
s/find_has_tooltip_widget/find_topmost_widget_coords_from_event/

+{
+  gint tx, ty;
+  gdouble dx, dy;
+  GtkWidget *tmp;
+  GtkWidget *orig;
+  gboolean has_tooltip;
+
+  gdk_event_get_coords (event, &dx, &dy);
+  tx = dx;
+  ty = dy;
+
+  orig = tmp = find_widget_under_pointer (event->any.window, &tx, &ty);
+
+  g_object_get (tmp, "has-tooltip", &has_tooltip, NULL);
+
+  /* We now have the toplevel widget under the mouse pointer, now find the
+   * widget with the tooltip in the stack
+   */
+  while (tmp && !has_tooltip)
+    {
+      tmp = tmp->parent;
+      if (tmp)
+	g_object_get (tmp, "has-tooltip", &has_tooltip, NULL);
+    }

i don't think you need to have this loop here, because it just
duplicates logic that is implemented in gtk_tooltip_run_requery()
already. so handling out the topmost stacked widget is good enough
at this point.

+
+  if (tmp && (x != NULL || y != NULL))
+    {
+      if (tmp != orig)
+	gtk_widget_translate_coordinates (orig, tmp, tx, ty, x, y);
+      else
+        {
+	  if (x)
+	    *x = tx;
+	  if (y)
+	    *y = ty;
+	}
+    }
+
+  return tmp;
+}
+
+static gint
+tooltip_browse_mode_timeout (gpointer data)
+{

hm, wouldn't tooltip_browse_mode_expired be a better name here,
since you essentially reset browse mode state?

+  GtkTooltip *tooltip;
+
+  GDK_THREADS_ENTER ();
+
+  tooltip = GTK_TOOLTIP (data);
+
+  tooltip->browse_mode_enabled = FALSE;
+  tooltip->browse_mode_timeout_id = 0;
+
+  /* destroy tooltip */
+  g_object_set_data (G_OBJECT (gtk_widget_get_display (tooltip->window)),
+		     "gdk-display-current-tooltip", NULL);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}

+static void
+gtk_tooltip_show_tooltip (GdkDisplay *display)
+{
+  gint x, y;
+  gint w, h;
+  gint monitor_num, px, py;
+  GdkScreen *screen;
+  GdkScreen *pointer_screen;
+  GdkRectangle monitor;
+
+  GdkWindow *window;
+  GtkWidget *tooltip_widget;
+  GtkWidget *pointer_widget;
+  GtkTooltip *tooltip;
+  gboolean has_tooltip;
+  gboolean return_value = FALSE;
+
+  tooltip = g_object_get_data (G_OBJECT (display),
+			       "gdk-display-current-tooltip");
+
+  if (tooltip->keyboard_mode_enabled)
+    {
+      pointer_widget = tooltip_widget = tooltip->keyboard_widget;
+    }
+  else
+    {
+      window = gdk_display_get_window_at_pointer (display, &x, &y);

note, this is a server round trip and gets pointer coords.

+      if (!window)
+	return;
+
+      pointer_widget = tooltip_widget = find_widget_under_pointer (window,
+								   &x, &y);
+    }
+
+  if (!tooltip_widget)
+    return;
+
+  g_object_get (tooltip_widget, "has-tooltip", &has_tooltip, NULL);
+
+  /* We now have the toplevel widget under the mouse pointer, now find the
+   * widget with the tooltip in the stack

this loop also shouldn't be here, gtk_tooltip_run_requery() handles skipping
non-tooltip widgets.

+   */
+  while (tooltip_widget && !has_tooltip)
+    {
+      tooltip_widget = tooltip_widget->parent;
+      if (tooltip_widget)
+	g_object_get (tooltip_widget, "has-tooltip", &has_tooltip, NULL);
+    }
+
+  if (!tooltip_widget || !has_tooltip)
+    return;
+
+  g_assert (tooltip != NULL);
+
+  if (tooltip->keyboard_mode_enabled)
+    {
+      if (tooltip_widget != pointer_widget)
+	gtk_widget_translate_coordinates (pointer_widget, tooltip_widget,
+					  x, y, &x, &y);

this is also handled by gtk_tooltip_run_requery().

+    }
+
+  if (!tooltip->current_window)
+    {
+      if (gtk_widget_get_tooltip_window (tooltip_widget))
+	tooltip->current_window = gtk_widget_get_tooltip_window (tooltip_widget);
+      else
+	tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window);
+    }
+
+  return_value = gtk_tooltip_run_requery (&tooltip_widget, tooltip, &x, &y);
+
+  if (!return_value)
+    return;
+
+  /* Position the tooltip */
+  /* FIXME: should we swap this when RTL is enabled? */
+  if (tooltip->keyboard_mode_enabled)
+    {
+      gdk_window_get_origin (tooltip_widget->window, &x, &y);
+      if (GTK_WIDGET_NO_WINDOW (tooltip_widget))
+        {
+	  x += tooltip_widget->allocation.x;
+	  y += tooltip_widget->allocation.y;
+	}
+
+      /* For keyboard mode we position the tooltip below the widget,
+       * right of the center of the widget.
+       */
+      x += tooltip_widget->allocation.width / 2;
+      y += tooltip_widget->allocation.height + 4;
+    }
+  else
+    {
+      guint cursor_size;
+
+      gdk_window_get_pointer (gdk_screen_get_root_window (gtk_widget_get_screen (tooltip_widget)), &x, &y, NULL);

as pointed out in an above note, we did 'get_pointer' already.
each _get_pointer is a server round trip, so we should reuse the coords
from above.
also, the coords we really want to use are in the event structure, to
avoid bugs where a slow application/connections causes the tooltip to be
positioned completely off-target because the mouse moved since the event
was originally queued (happens regularly here with v1.2.1 for instance).
but well, for the moment we don't have those here...

+
+      /* For mouse mode, we position the tooltip right of the cursor,
+       * a little below the cursor's center.
+       */
+      cursor_size = gdk_display_get_default_cursor_size (display);
+      x += cursor_size / 2;
+      y += cursor_size / 2;
+    }
+
+  if (tooltip->current_window)
+    {
+      GtkRequisition requisition;
+
+      gtk_widget_size_request (GTK_WIDGET (tooltip->current_window), &requisition);
+      w = requisition.width;
+      h = requisition.height;
+    }
+
+  screen = gtk_widget_get_screen (tooltip_widget);
+
+  if (screen != gtk_widget_get_screen (tooltip->window))
+    {
+      g_signal_handlers_disconnect_by_func (display,
+					    gtk_tooltip_display_closed,
+					    tooltip);
+
+      gtk_window_set_screen (GTK_WINDOW (tooltip->window), screen);
+
+      g_signal_connect (display, "closed",
+			G_CALLBACK (gtk_tooltip_display_closed), tooltip);
+    }
+
+  tooltip->tooltip_widget = tooltip_widget;
+
+  gdk_display_get_pointer (gdk_screen_get_display (screen),
+			   &pointer_screen, &px, &py, NULL);

urgs, another round trip ;)

+  if (pointer_screen != screen)
+    {
+      px = x;
+      py = y;
+    }
+  monitor_num = gdk_screen_get_monitor_at_point (screen, px, py);
+  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+  if (x > monitor.x + monitor.width)
+    x -= x - (monitor.x + monitor.width + w);
+  else if (x < monitor.x)
+    x = monitor.x;
+
+  if (y > monitor.y + monitor.height)
+    y -= y - (monitor.y + monitor.height + h);
+
+  /* Show it */
+  if (tooltip->current_window)
+    {
+      gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y);
+      gtk_widget_show (GTK_WIDGET (tooltip->current_window));
+    }
+
+  /* Now a tooltip is visible again on the display, make sure browse
+   * mode is enabled.
+   */
+  tooltip->browse_mode_enabled = TRUE;
+  if (tooltip->browse_mode_timeout_id)
+    {
+      g_source_remove (tooltip->browse_mode_timeout_id);
+      tooltip->browse_mode_timeout_id = 0;
+    }
+
+  tooltip->visible = TRUE;

isn't this field duplicating the state of
  (tooltip->current_window && GTK_WIDGET_VISIBLE (tooltip->current_window))
?

+}

+static gint
+tooltip_timeout (gpointer data)

similar to the above timeout, a more elaborate function name would
help to more easily grasp the funcitonality, rather than just naming
it after the fact that it's hooked up as a timeout.
e.g. tooltip_initial_delay_expired() or tooltip_popup_timer().

+{
+  GdkDisplay *display;
+  GtkTooltip *tooltip;
+
+  GDK_THREADS_ENTER ();
+
+  display = GDK_DISPLAY_OBJECT (data);
+
+  gtk_tooltip_show_tooltip (display);
+
+  tooltip = g_object_get_data (G_OBJECT (display),
+			       "gdk-display-current-tooltip");
+  tooltip->timeout_id = 0;
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void
+gtk_tooltip_start_delay (GdkDisplay *display)

this should probably be gtk_tooltip_start_delayed() ?

+{
+  guint timeout;
+  GtkTooltip *tooltip;
+  GtkSettings *settings;
+
+  tooltip = g_object_get_data (G_OBJECT (display),
+			       "gdk-display-current-tooltip");
+
+  if (tooltip && tooltip->visible)
+    return;
+
+  if (tooltip->timeout_id)
+    g_source_remove (tooltip->timeout_id);
+
+  settings = gtk_widget_get_settings (GTK_WIDGET (tooltip->window));
+
+  if (tooltip->browse_mode_enabled)
+    g_object_get (settings, "gtk-tooltip-browse-timeout", &timeout, NULL);
+  else
+    g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL);
+
+  tooltip->timeout_id = g_timeout_add_full (0, timeout,
+					    tooltip_timeout,
+					    g_object_ref (display),
+					    g_object_unref);
+}
+
+void
+_gtk_tooltip_focus_in (GtkWidget *widget)
+{
+  gint x, y;
+  gboolean has_tooltip = FALSE;
+  gboolean return_value = FALSE;
+  GdkDisplay *display;
+  GtkTooltip *tooltip;
+
+  /* Get current tooltip for this display */
+  display = gtk_widget_get_display (widget);
+  tooltip = g_object_get_data (G_OBJECT (display),
+			       "gdk-display-current-tooltip");
+
+  g_object_get (widget, "has-tooltip", &has_tooltip, NULL);
+
+  /* Check if keyboard mode is enabled at this moment */
+  if (!tooltip || !tooltip->keyboard_mode_enabled || !has_tooltip)
+    return;

i don't quite see why you're checking has_tooltip here. a widget
may still have no tooltip eventhough it's has_tooltip=TRUE, and
it's ancestors may still have a tooltip eventhough it's has_tooltip=FALSE.

+
+  if (tooltip->keyboard_widget)
+    g_object_unref (tooltip->keyboard_widget);
+
+  tooltip->keyboard_widget = g_object_ref (widget);
+
+  gdk_window_get_pointer (widget->window, &x, &y, NULL);
+
+  if (!tooltip->current_window)
+    {
+      if (gtk_widget_get_tooltip_window (widget))
+	tooltip->current_window = gtk_widget_get_tooltip_window (widget);
+      else
+	tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window);
+    }
+
+  return_value = gtk_tooltip_run_requery (&widget, tooltip, &x, &y);
+
+  if (!return_value)
+    gtk_tooltip_hide_tooltip (tooltip);
+  else
+    gtk_tooltip_show_tooltip (display);
+}
+
+void
+_gtk_tooltip_focus_out (GtkWidget *widget)
+{
+  gboolean has_tooltip;
+  GdkDisplay *display;
+  GtkTooltip *tooltip;
+
+  /* Get current tooltip for this display */
+  display = gtk_widget_get_display (widget);
+  tooltip = g_object_get_data (G_OBJECT (display),
+			       "gdk-display-current-tooltip");
+
+  g_object_get (widget, "has-tooltip", &has_tooltip, NULL);
+
+  if (!tooltip)
+    return;


+
+  /* Handle case where mouse pointer moves out of the window */
+  if (!tooltip->keyboard_mode_enabled && tooltip->tooltip_widget != widget)

hm, as i said above, the tooltip might come from an ancestory of the widget,
so "tooltip->tooltip_widget != widget" looks wrong to me.
also, i don't quite get why you talk about pointer moves in focus_out.
for one, gtk+ widget's don't implement focous-out-on-window-leave,
and for another we already have motion/enter/leave handling ina different
place.

+    {
+      gtk_tooltip_hide_tooltip (tooltip);
+      return;
+    }
+
+  if (!tooltip || !tooltip->keyboard_mode_enabled || !has_tooltip)
+    return;

the comment from _gtk_tooltip_focus_in applies here as well.

+
+  if (tooltip->keyboard_widget)
+    {
+      g_object_unref (tooltip->keyboard_widget);
+      tooltip->keyboard_widget = NULL;
+    }
+
+  /* Hide tooltip */
+  gtk_tooltip_hide_tooltip (tooltip);

this comment is redundant to a certain extend ;)

+}
+
+void
+_gtk_tooltip_toggle_keyboard_mode (GtkWidget *widget)
+{
+  GdkDisplay *display;
+  GtkTooltip *tooltip;
+
+  display = gtk_widget_get_display (widget);
+  tooltip = g_object_get_data (G_OBJECT (display),
+			       "gdk-display-current-tooltip");
+
+  if (!tooltip)
+    {
+      tooltip = g_object_new (GTK_TYPE_TOOLTIP, NULL);
+      g_object_set_data_full (G_OBJECT (display),
+			      "gdk-display-current-tooltip",
+			      tooltip, g_object_unref);
+    }
+
+  tooltip->keyboard_mode_enabled ^= 1;
+
+  if (tooltip->keyboard_mode_enabled)
+    {
+      tooltip->keyboard_widget = g_object_ref (widget);
+      _gtk_tooltip_focus_in (widget);
+    }
+  else
+    {
+      if (tooltip->keyboard_widget)
+        {
+	  g_object_unref (tooltip->keyboard_widget);
+	  tooltip->keyboard_widget = NULL;
+	}
+
+      gtk_tooltip_hide_tooltip (tooltip);
+    }
+}

+void
+_gtk_tooltip_handle_event (GdkEvent *event)
+{
+  gint x, y;
+  gboolean return_value = FALSE;
+  GtkWidget *has_tooltip_widget = NULL;
+  GdkDisplay *display;
+  GtkTooltip *current_tooltip;
+
+  has_tooltip_widget = find_has_tooltip_widget (event, &x, &y);
+  display = gdk_drawable_get_display (event->any.window);
+  current_tooltip = g_object_get_data (G_OBJECT (display),
+				       "gdk-display-current-tooltip");
+
+  if (current_tooltip && current_tooltip->keyboard_mode_enabled)
+    {
+      has_tooltip_widget = current_tooltip->keyboard_widget;
+      if (!has_tooltip_widget)
+	return;
+
+      return_value = gtk_tooltip_run_requery (&has_tooltip_widget,
+					      current_tooltip,
+					      &x, &y);
+
+      if (!return_value)
+	gtk_tooltip_hide_tooltip (current_tooltip);
+      else
+	gtk_tooltip_start_delay (display);
+
+      return;
+    }
+
+  /* Always poll for a next motion event */
+  if (event->motion.is_hint)
+    gdk_window_get_pointer (event->any.window, NULL, NULL, NULL);

you need to check for event->type == MOTION if you access event->motion.*.

thanks,

-kris.

thanks for the new patch. all in all, the code looks fairly complete already.
there're some logic issues that still need to be worked out, but
that should be done in SVN. please check this in as soon as possible,
if you want to keep the history, even before fixing my above comments.

---
ciaoTJ



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]