--- gtk/gtkmain.c	2006/05/26 03:25:48	1.1
+++ gtk/gtkmain.c	2006/05/26 14:03:24
@@ -1431,6 +1431,7 @@ gtk_main_do_event (GdkEvent *event)
 	  
 	  g_object_unref (event_widget);
 	}
+      GTK_PRIVATE_SET_FLAG (event_widget, GTK_SYNTH_CROSSING);
       break;
       
     case GDK_LEAVE_NOTIFY:
@@ -1441,6 +1442,7 @@ gtk_main_do_event (GdkEvent *event)
 	}
       else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
 	gtk_widget_event (grab_widget, event);
+      GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_SYNTH_CROSSING);
       break;
       
     case GDK_DRAG_STATUS:
--- gtk/gtkprivate.h	2006/05/26 03:25:41	1.1
+++ gtk/gtkprivate.h	2006/05/26 13:46:22
@@ -49,7 +49,8 @@ typedef enum
   PRIVATE_GTK_CHILD_VISIBLE     = 1 <<  10,  /* If widget should be mapped when parent is mapped */
   PRIVATE_GTK_REDRAW_ON_ALLOC   = 1 <<  11,  /* If we should queue a draw on the entire widget when it is reallocated */
   PRIVATE_GTK_ALLOC_NEEDED      = 1 <<  12,  /* If we we should allocate even if the allocation is the same */
-  PRIVATE_GTK_REQUEST_NEEDED    = 1 <<  13   /* Whether we need to call gtk_widget_size_request */
+  PRIVATE_GTK_REQUEST_NEEDED    = 1 <<  13,  /* Whether we need to call gtk_widget_size_request */
+  PRIVATE_GTK_SYNTH_CROSSING    = 1 <<  14   /* Whether to synthesise enter/leave events on making the widget (in)sensitive */
 } GtkPrivateFlags;
 
 /* Macros for extracting a widgets private_flags from GtkWidget.
@@ -67,6 +68,7 @@ typedef enum
 #define GTK_WIDGET_REDRAW_ON_ALLOC(obj)   ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_REDRAW_ON_ALLOC) != 0)
 #define GTK_WIDGET_ALLOC_NEEDED(obj)      ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_ALLOC_NEEDED) != 0)
 #define GTK_WIDGET_REQUEST_NEEDED(obj)    ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_REQUEST_NEEDED) != 0)
+#define GTK_WIDGET_SYNTH_CROSSING(obj)    ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_SYNTH_CROSSING) != 0)
 
 /* Macros for setting and clearing private widget flags.
  * we use a preprocessor string concatenation here for a clear
--- gtk/gtktypebuiltins.c	2006/05/26 03:28:30	1.1
+++ gtk/gtktypebuiltins.c	2006/05/26 13:47:33
@@ -1466,6 +1466,7 @@ gtk_private_flags_get_type (void)
       { PRIVATE_GTK_REDRAW_ON_ALLOC, "PRIVATE_GTK_REDRAW_ON_ALLOC", "redraw-on-alloc" },
       { PRIVATE_GTK_ALLOC_NEEDED, "PRIVATE_GTK_ALLOC_NEEDED", "alloc-needed" },
       { PRIVATE_GTK_REQUEST_NEEDED, "PRIVATE_GTK_REQUEST_NEEDED", "request-needed" },
+      { PRIVATE_GTK_SYNTH_CROSSING, "PRIVATE_GTK_SYNTH_CROSSING", "synth-crossing" },
       { 0, NULL, NULL }
     };
     etype = g_flags_register_static (g_intern_static_string ("GtkPrivateFlags"), values);
--- gtk/gtkwidget.c	2006/05/26 03:36:46	1.2
+++ gtk/gtkwidget.c	2006/05/26 13:46:22
@@ -4060,6 +4060,11 @@ _gtk_widget_grab_notify (GtkWidget *widg
 			 gboolean   was_grabbed)
 {
   g_signal_emit (widget, widget_signals[GRAB_NOTIFY], 0, was_grabbed);
+
+  if (GTK_WIDGET_SYNTH_CROSSING (widget) && 
+      !GTK_WIDGET_NO_WINDOW (widget) && widget->window)
+    _gtk_widget_synthesise_crossing_from_grab_notify (widget, widget->window, 
+						      was_grabbed);
 }
 
 /**
@@ -6944,6 +6949,106 @@ _gtk_widget_peek_colormap (void)
   return NULL;
 }
 
+/**
+ * _gtk_widget_synthesise_crossing_event:
+ * @widget: a #GtkWidget
+ * @window: the #GdkWindow to synthesise events for
+ * @enter: %TRUE for an enter event, %FALSE for a leave event
+ *
+ * Synthesise enter/leave events upon changing the sensitivity or global grab
+ * state of a widget.
+ **/
+static void
+_gtk_widget_synthesise_crossing_event (GtkWidget    *widget,
+				       GdkWindow    *window,
+				       gboolean      enter)
+{
+  gint x, y;
+  GdkEvent *event;
+  GdkEventType type = enter ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
+
+  g_return_if_fail (widget);
+  g_return_if_fail (window);
+
+  event = gdk_event_new (type);
+  event->crossing.type = type;
+  event->crossing.window = window;
+  event->crossing.send_event = FALSE;
+  event->crossing.subwindow = window;
+  event->crossing.time = GDK_CURRENT_TIME;
+  gdk_display_get_pointer (gdk_drawable_get_display (window), NULL, 
+			   &x, &y, &event->crossing.state);
+  event->crossing.x_root = (gdouble) x;
+  event->crossing.y_root = (gdouble) y;
+  gdk_window_get_origin (window, &x, &y);
+  event->crossing.x = event->crossing.x_root - (gdouble) x;
+  event->crossing.y = event->crossing.y_root - (gdouble) y;
+  event->crossing.mode = GDK_CROSSING_NORMAL;
+  event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+  event->crossing.focus = FALSE;
+
+  g_object_ref (widget);
+  gtk_widget_event (widget, event);
+  if (enter)
+    GTK_PRIVATE_SET_FLAG (widget, GTK_LEAVE_PENDING);
+  else
+    GTK_PRIVATE_UNSET_FLAG (widget, GTK_LEAVE_PENDING);
+  g_object_unref (widget);
+}
+
+/**
+ * _gtk_widget_synthesise_crossing_from_grab_notify:
+ * @widget: a #GtkWidget
+ * @window: the #GdkWindow to synthesise events for
+ * @was_grabbed: the previous grab state
+ *
+ * Synthesise enter/leave events upon changing the global grab state of a 
+ * widget.
+ **/
+void
+_gtk_widget_synthesise_crossing_from_grab_notify (GtkWidget      *widget,
+						  GdkWindow      *window,
+						  gboolean        was_grabbed)
+{
+  if (GTK_WIDGET_IS_SENSITIVE (widget))
+    _gtk_widget_synthesise_crossing_event (widget, window, was_grabbed);
+}
+
+static gboolean
+is_shadowed (GtkWidget *widget)
+{
+  GtkWidget *toplevel;
+  GtkWindowGroup *group;
+  GtkWidget *grab_widget;
+  
+  toplevel = gtk_widget_get_toplevel (widget);
+  group = gtk_window_get_group ((toplevel && GTK_IS_WINDOW (toplevel))
+				? (GtkWindow *) toplevel : NULL);
+  grab_widget = _gtk_window_group_get_current_grab (group);
+  return (grab_widget != NULL && grab_widget != widget &&
+	  !gtk_widget_is_ancestor (widget, grab_widget));
+}
+
+/**
+ * _gtk_widget_synthesise_crossing_event_from_state_changed:
+ * @widget: a #GtkWidget
+ * @window: the #GdkWindow to synthesise events for
+ * @previous_state: the previous state
+ *
+ * Synthesise enter/leave events upon changing the sensitivity of a widget.
+ **/
+void
+_gtk_widget_synthesise_crossing_from_state_changed (GtkWidget    *widget,
+						    GdkWindow    *window,
+						    GtkStateType  previous_state)
+{
+  gboolean sensitive = GTK_WIDGET_IS_SENSITIVE (widget);
+
+  if ((!sensitive || previous_state == GTK_STATE_INSENSITIVE) &&
+      !is_shadowed (widget))
+    _gtk_widget_synthesise_crossing_event (widget, window, sensitive);
+}
+
 static void
 gtk_widget_propagate_state (GtkWidget           *widget,
 			    GtkStateData        *data)
@@ -7005,6 +7110,12 @@ gtk_widget_propagate_state (GtkWidget   
 	gtk_grab_remove (widget);
       
       g_signal_emit (widget, widget_signals[STATE_CHANGED], 0, old_state);
+
+      if (GTK_WIDGET_SYNTH_CROSSING (widget) && 
+	  !GTK_WIDGET_NO_WINDOW (widget) && widget->window)
+	_gtk_widget_synthesise_crossing_from_state_changed (widget, 
+							    widget->window, 
+							    old_state);
       
       if (GTK_IS_CONTAINER (widget))
 	{
--- gtk/gtkwidget.h	2006/05/26 07:13:14	1.1
+++ gtk/gtkwidget.h	2006/05/26 13:46:22
@@ -794,6 +794,13 @@ void              _gtk_widget_propagate_
 							   GdkScreen    *previous_screen);
 void		  _gtk_widget_propagate_composited_changed (GtkWidget    *widget);
 
+void _gtk_widget_synthesise_crossing_from_grab_notify (GtkWidget      *widget,
+						       GdkWindow      *window,
+						       gboolean        was_grabbed);
+void _gtk_widget_synthesise_crossing_from_state_changed (GtkWidget    *widget,
+							 GdkWindow    *window,
+							 GtkStateType  previous_state);
+
 GdkColormap* _gtk_widget_peek_colormap (void);
 
 G_END_DECLS
--- gtk/gtkbutton.c	2006/05/26 06:18:30	1.1
+++ gtk/gtkbutton.c	2006/05/26 13:46:22
@@ -1830,6 +1830,11 @@ gtk_button_state_changed (GtkWidget    *
       button->in_button = FALSE;
       gtk_real_button_released (button);
     }
+
+  if (GTK_WIDGET_SYNTH_CROSSING (widget) && button->event_window)
+    _gtk_widget_synthesise_crossing_from_state_changed (widget, 
+							button->event_window, 
+							previous_state);
 }
 
 static void
@@ -1843,6 +1848,11 @@ gtk_button_grab_notify (GtkWidget *widge
       button->in_button = FALSE;
       gtk_real_button_released (button);
     }
+
+  if (GTK_WIDGET_SYNTH_CROSSING (widget) && button->event_window)
+    _gtk_widget_synthesise_crossing_from_grab_notify (widget, 
+						      button->event_window, 
+						      was_grabbed);
 }
 
 /**
