mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-12 13:30:19 +00:00
Bug 56070 – Can't click button after setting it sensitive.
2008-07-31 Cody Russell <bratsche@gnome.org> Bug 56070 – Can't click button after setting it sensitive. * gtk/gtkwidget.[ch] * gtk/gtkwindow.c * gtk/gtkmain.c * gtk/gtkbutton.c * gtk/gtkprivate.h * gdk/gdkevents.h: Synthesize crossing events events where necessary. * gtk/tests/crossingevents.c: Add unit tests for crossing events. Big thanks to Ed Catmur, Matthias Clasen, and everyone else who has worked on and helped out with this. svn path=/trunk/; revision=20924
This commit is contained in:
parent
e9d978dff9
commit
4e3c97b3f2
16
ChangeLog
16
ChangeLog
@ -1,3 +1,19 @@
|
||||
2008-07-31 Cody Russell <bratsche@gnome.org>
|
||||
|
||||
Bug 56070 – Can't click button after setting it sensitive.
|
||||
|
||||
* gtk/gtkwidget.[ch]
|
||||
* gtk/gtkwindow.c
|
||||
* gtk/gtkmain.c
|
||||
* gtk/gtkbutton.c
|
||||
* gtk/gtkprivate.h
|
||||
* gdk/gdkevents.h: Synthesize crossing events events where necessary.
|
||||
|
||||
* gtk/tests/crossingevents.c: Add unit tests for crossing events.
|
||||
|
||||
Big thanks to Ed Catmur, Matthias Clasen, and everyone else who
|
||||
has worked on and helped out with this.
|
||||
|
||||
2008-07-31 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
Bug 424207 – printing hangs on unreachable cups server
|
||||
|
@ -259,8 +259,11 @@ Generated when the pointer enters or leaves a window.
|
||||
@y: the y coordinate of the pointer relative to the window.
|
||||
@x_root: the x coordinate of the pointer relative to the root of the screen.
|
||||
@y_root: the y coordinate of the pointer relative to the root of the screen.
|
||||
@mode: the crossing mode (%GDK_CROSSING_NORMAL, %GDK_CROSSING_GRAB or
|
||||
%GDK_CROSSING_UNGRAB).
|
||||
@mode: the crossing mode (%GDK_CROSSING_NORMAL, %GDK_CROSSING_GRAB,
|
||||
%GDK_CROSSING_UNGRAB, %GDK_CROSSING_GTK_GRAB, %GDK_CROSSING_GTK_UNGRAB or
|
||||
%GDK_CROSSING_STATE_CHANGED). %GDK_CROSSING_GTK_GRAB, %GDK_CROSSING_GTK_UNGRAB,
|
||||
and %GDK_CROSSING_STATE_CHANGED were added in 2.14 and are always synthesized,
|
||||
never native.
|
||||
@detail: the kind of crossing that happened (%GDK_NOTIFY_INFERIOR,
|
||||
%GDK_NOTIFY_ANCESTOR, %GDK_NOTIFY_VIRTUAL, %GDK_NOTIFY_NONLINEAR or
|
||||
%GDK_NOTIFY_NONLINEAR_VIRTUAL).
|
||||
@ -474,6 +477,10 @@ Specifies the crossing mode for #GdkEventCrossing.
|
||||
@GDK_CROSSING_NORMAL: crossing because of pointer motion.
|
||||
@GDK_CROSSING_GRAB: crossing because a grab is activated.
|
||||
@GDK_CROSSING_UNGRAB: crossing because a grab is deactivated.
|
||||
@GDK_CROSSING_GTK_GRAB: crossing because a GTK+ grab is activated.
|
||||
@GDK_CROSSING_GTK_UNGRAB: crossing because a GTK+ grab is deactivated.
|
||||
@GDK_CROSSING_STATE_CHANGED: crossing because a GTK+ widget changed state (e.g.
|
||||
sensitivity).
|
||||
|
||||
<!-- ##### ENUM GdkNotifyType ##### -->
|
||||
<para>
|
||||
|
@ -225,7 +225,10 @@ typedef enum
|
||||
{
|
||||
GDK_CROSSING_NORMAL,
|
||||
GDK_CROSSING_GRAB,
|
||||
GDK_CROSSING_UNGRAB
|
||||
GDK_CROSSING_UNGRAB,
|
||||
GDK_CROSSING_GTK_GRAB,
|
||||
GDK_CROSSING_GTK_UNGRAB,
|
||||
GDK_CROSSING_STATE_CHANGED
|
||||
} GdkCrossingMode;
|
||||
|
||||
typedef enum
|
||||
|
@ -1457,7 +1457,8 @@ gtk_button_leave_notify (GtkWidget *widget,
|
||||
event_widget = gtk_get_event_widget ((GdkEvent*) event);
|
||||
|
||||
if ((event_widget == widget) &&
|
||||
(event->detail != GDK_NOTIFY_INFERIOR))
|
||||
(event->detail != GDK_NOTIFY_INFERIOR) &&
|
||||
(GTK_WIDGET_SENSITIVE (event_widget)))
|
||||
{
|
||||
button->in_button = FALSE;
|
||||
gtk_button_leave (button);
|
||||
|
@ -1569,25 +1569,15 @@ gtk_main_do_event (GdkEvent *event)
|
||||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
GTK_PRIVATE_SET_FLAG (event_widget, GTK_HAS_POINTER);
|
||||
_gtk_widget_set_pointer_window (event_widget, event->any.window);
|
||||
if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
|
||||
{
|
||||
g_object_ref (event_widget);
|
||||
|
||||
gtk_widget_event (grab_widget, event);
|
||||
if (event_widget == grab_widget)
|
||||
GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
|
||||
|
||||
g_object_unref (event_widget);
|
||||
}
|
||||
gtk_widget_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
if (GTK_WIDGET_LEAVE_PENDING (event_widget))
|
||||
{
|
||||
GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
|
||||
gtk_widget_event (event_widget, event);
|
||||
}
|
||||
else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
|
||||
GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_HAS_POINTER);
|
||||
if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
|
||||
gtk_widget_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
@ -1660,6 +1650,7 @@ typedef struct
|
||||
GtkWidget *new_grab_widget;
|
||||
gboolean was_grabbed;
|
||||
gboolean is_grabbed;
|
||||
gboolean from_grab;
|
||||
} GrabNotifyInfo;
|
||||
|
||||
static void
|
||||
@ -1681,13 +1672,31 @@ gtk_grab_notify_foreach (GtkWidget *child,
|
||||
is_shadowed = info->new_grab_widget && !info->is_grabbed;
|
||||
|
||||
g_object_ref (child);
|
||||
|
||||
if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
|
||||
gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
|
||||
|
||||
if (is_shadowed)
|
||||
{
|
||||
GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
|
||||
if (!was_shadowed && GTK_WIDGET_HAS_POINTER (child)
|
||||
&& GTK_WIDGET_IS_SENSITIVE (child))
|
||||
_gtk_widget_synthesize_crossing (child, info->new_grab_widget,
|
||||
GDK_CROSSING_GTK_GRAB);
|
||||
}
|
||||
else
|
||||
{
|
||||
GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
|
||||
if (was_shadowed && GTK_WIDGET_HAS_POINTER (child)
|
||||
&& GTK_WIDGET_IS_SENSITIVE (child))
|
||||
_gtk_widget_synthesize_crossing (info->old_grab_widget, child,
|
||||
info->from_grab ? GDK_CROSSING_GTK_GRAB
|
||||
: GDK_CROSSING_GTK_UNGRAB);
|
||||
}
|
||||
|
||||
if (was_shadowed != is_shadowed)
|
||||
_gtk_widget_grab_notify (child, was_shadowed);
|
||||
|
||||
if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
|
||||
gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
|
||||
|
||||
g_object_unref (child);
|
||||
|
||||
info->was_grabbed = was_grabbed;
|
||||
@ -1697,7 +1706,8 @@ gtk_grab_notify_foreach (GtkWidget *child,
|
||||
static void
|
||||
gtk_grab_notify (GtkWindowGroup *group,
|
||||
GtkWidget *old_grab_widget,
|
||||
GtkWidget *new_grab_widget)
|
||||
GtkWidget *new_grab_widget,
|
||||
gboolean from_grab)
|
||||
{
|
||||
GList *toplevels;
|
||||
GrabNotifyInfo info;
|
||||
@ -1707,6 +1717,7 @@ gtk_grab_notify (GtkWindowGroup *group,
|
||||
|
||||
info.old_grab_widget = old_grab_widget;
|
||||
info.new_grab_widget = new_grab_widget;
|
||||
info.from_grab = from_grab;
|
||||
|
||||
g_object_ref (group);
|
||||
|
||||
@ -1751,7 +1762,7 @@ gtk_grab_add (GtkWidget *widget)
|
||||
g_object_ref (widget);
|
||||
group->grabs = g_slist_prepend (group->grabs, widget);
|
||||
|
||||
gtk_grab_notify (group, old_grab_widget, widget);
|
||||
gtk_grab_notify (group, old_grab_widget, widget, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1787,7 +1798,7 @@ gtk_grab_remove (GtkWidget *widget)
|
||||
else
|
||||
new_grab_widget = NULL;
|
||||
|
||||
gtk_grab_notify (group, widget, new_grab_widget);
|
||||
gtk_grab_notify (group, widget, new_grab_widget, FALSE);
|
||||
|
||||
g_object_unref (widget);
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ typedef enum
|
||||
{
|
||||
PRIVATE_GTK_USER_STYLE = 1 << 0,
|
||||
PRIVATE_GTK_RESIZE_PENDING = 1 << 2,
|
||||
PRIVATE_GTK_LEAVE_PENDING = 1 << 4,
|
||||
PRIVATE_GTK_HAS_POINTER = 1 << 3, /* If the pointer is above a window belonging to the widget */
|
||||
PRIVATE_GTK_SHADOWED = 1 << 4, /* If there is a grab in effect shadowing the widget */
|
||||
PRIVATE_GTK_HAS_SHAPE_MASK = 1 << 5,
|
||||
PRIVATE_GTK_IN_REPARENT = 1 << 6,
|
||||
PRIVATE_GTK_DIRECTION_SET = 1 << 7, /* If the reading direction is not DIR_NONE */
|
||||
@ -54,7 +55,8 @@ typedef enum
|
||||
#define GTK_PRIVATE_FLAGS(wid) (GTK_WIDGET (wid)->private_flags)
|
||||
#define GTK_WIDGET_USER_STYLE(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_USER_STYLE) != 0)
|
||||
#define GTK_CONTAINER_RESIZE_PENDING(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_RESIZE_PENDING) != 0)
|
||||
#define GTK_WIDGET_LEAVE_PENDING(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_LEAVE_PENDING) != 0)
|
||||
#define GTK_WIDGET_HAS_POINTER(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_HAS_POINTER) != 0)
|
||||
#define GTK_WIDGET_SHADOWED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_SHADOWED) != 0)
|
||||
#define GTK_WIDGET_HAS_SHAPE_MASK(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_HAS_SHAPE_MASK) != 0)
|
||||
#define GTK_WIDGET_IN_REPARENT(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_IN_REPARENT) != 0)
|
||||
#define GTK_WIDGET_DIRECTION_SET(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_DIRECTION_SET) != 0)
|
||||
|
288
gtk/gtkwidget.c
288
gtk/gtkwidget.c
@ -298,6 +298,7 @@ static GQuark quark_accel_closures = 0;
|
||||
static GQuark quark_event_mask = 0;
|
||||
static GQuark quark_extension_event_mode = 0;
|
||||
static GQuark quark_parent_window = 0;
|
||||
static GQuark quark_pointer_window = 0;
|
||||
static GQuark quark_shape_info = 0;
|
||||
static GQuark quark_input_shape_info = 0;
|
||||
static GQuark quark_colormap = 0;
|
||||
@ -385,6 +386,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
quark_event_mask = g_quark_from_static_string ("gtk-event-mask");
|
||||
quark_extension_event_mode = g_quark_from_static_string ("gtk-extension-event-mode");
|
||||
quark_parent_window = g_quark_from_static_string ("gtk-parent-window");
|
||||
quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
|
||||
quark_shape_info = g_quark_from_static_string ("gtk-shape-info");
|
||||
quark_input_shape_info = g_quark_from_static_string ("gtk-input-shape-info");
|
||||
quark_colormap = g_quark_from_static_string ("gtk-colormap");
|
||||
@ -8053,6 +8055,282 @@ _gtk_widget_peek_colormap (void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* _gtk_widget_set_pointer_window:
|
||||
* @widget: a #GtkWidget.
|
||||
* @pointer_window: the new pointer window.
|
||||
*
|
||||
* Sets pointer window for @widget. Does not ref @pointer_window.
|
||||
* Actually stores it on the #GdkScreen, but you don't need to know that.
|
||||
**/
|
||||
void
|
||||
_gtk_widget_set_pointer_window (GtkWidget *widget,
|
||||
GdkWindow *pointer_window)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
|
||||
GdkScreen *screen = gdk_drawable_get_screen (GDK_DRAWABLE (widget->window));
|
||||
g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, pointer_window);
|
||||
}
|
||||
|
||||
/**
|
||||
* _gtk_widget_get_pointer_window:
|
||||
* @widget: a #GtkWidget.
|
||||
*
|
||||
* Return value: the pointer window set on the #GdkScreen @widget is attached
|
||||
* to, or %NULL.
|
||||
**/
|
||||
GdkWindow *
|
||||
_gtk_widget_get_pointer_window (GtkWidget *widget)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
|
||||
|
||||
GdkScreen *screen = gdk_drawable_get_screen (GDK_DRAWABLE (widget->window));
|
||||
return g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
|
||||
}
|
||||
|
||||
static void
|
||||
synth_crossing (GtkWidget *widget,
|
||||
GdkEventType type,
|
||||
GdkWindow *window,
|
||||
GdkCrossingMode mode,
|
||||
GdkNotifyType detail)
|
||||
{
|
||||
GdkEvent *event;
|
||||
|
||||
event = gdk_event_new (type);
|
||||
|
||||
event->crossing.window = g_object_ref (window);
|
||||
event->crossing.send_event = TRUE;
|
||||
event->crossing.subwindow = g_object_ref (window);
|
||||
event->crossing.time = GDK_CURRENT_TIME;
|
||||
event->crossing.x = event->crossing.y = 0;
|
||||
event->crossing.x_root = event->crossing.y_root = 0;
|
||||
event->crossing.mode = mode;
|
||||
event->crossing.detail = detail;
|
||||
event->crossing.focus = FALSE;
|
||||
event->crossing.state = 0;
|
||||
|
||||
if (!widget)
|
||||
widget = gtk_get_event_widget (event);
|
||||
|
||||
if (widget)
|
||||
gtk_widget_event_internal (widget, event);
|
||||
|
||||
gdk_event_free (event);
|
||||
}
|
||||
|
||||
/**
|
||||
* _gtk_widget_is_pointer_widget:
|
||||
* @widget: a #GtkWidget
|
||||
*
|
||||
* Returns %TRUE if the pointer window belongs to @widget.
|
||||
*
|
||||
*/
|
||||
gboolean
|
||||
_gtk_widget_is_pointer_widget (GtkWidget *widget)
|
||||
{
|
||||
if (GTK_WIDGET_HAS_POINTER (widget))
|
||||
{
|
||||
GdkWindow *win;
|
||||
GtkWidget *wid;
|
||||
|
||||
win = _gtk_widget_get_pointer_window (widget);
|
||||
if (win)
|
||||
{
|
||||
gdk_window_get_user_data (win, &wid);
|
||||
if (wid == widget)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* _gtk_widget_synthesize_crossing:
|
||||
* @from: the #GtkWidget the virtual pointer is leaving.
|
||||
* @to: the #GtkWidget the virtual pointer is moving to.
|
||||
* @mode: the #GdkCrossingMode to place on the synthesized events.
|
||||
*
|
||||
* Generate crossing event(s) on widget state (sensitivity) or GTK+ grab change.
|
||||
*
|
||||
* The real pointer window is the window that most recently received an enter notify
|
||||
* event. Windows that don't select for crossing events can't become the real
|
||||
* poiner window. The real pointer widget that owns the real pointer window. The
|
||||
* effective pointer window is the same as the real pointer window unless the real
|
||||
* pointer widget is either insensitive or there is a grab on a widget that is not
|
||||
* an ancestor of the real pointer widget (in which case the effective pointer
|
||||
* window should be the root window).
|
||||
*
|
||||
* When the effective pointer window is the same as the real poiner window, we
|
||||
* receive crossing events from the windowing system. When the effective pointer
|
||||
* window changes to become different from the real pointer window we synthesize
|
||||
* crossing events, attempting to follow X protocol rules:
|
||||
*
|
||||
* When the root window becomes the effective pointer window:
|
||||
* - leave notify on real pointer window, detail Ancestor
|
||||
* - leave notify on all of its ancestors, detail Virtual
|
||||
* - enter notify on root window, detail Inferior
|
||||
*
|
||||
* When the root window ceases to be the effective pointer window:
|
||||
* - leave notify on root window, detail Inferior
|
||||
* - enter notify on all ancestors of real pointer window, detail Virtual
|
||||
* - enter notify on real pointer window, detail Ancestor
|
||||
*/
|
||||
void
|
||||
_gtk_widget_synthesize_crossing (GtkWidget *from,
|
||||
GtkWidget *to,
|
||||
GdkCrossingMode mode)
|
||||
{
|
||||
GdkWindow *from_window = NULL, *to_window = NULL;
|
||||
|
||||
g_return_if_fail (from != NULL || to != NULL);
|
||||
|
||||
if (from != NULL)
|
||||
from_window = GTK_WIDGET_HAS_POINTER (from)
|
||||
? _gtk_widget_get_pointer_window (from) : from->window;
|
||||
if (to != NULL)
|
||||
to_window = GTK_WIDGET_HAS_POINTER (to)
|
||||
? _gtk_widget_get_pointer_window (to) : to->window;
|
||||
|
||||
if (from_window == NULL && to_window == NULL)
|
||||
;
|
||||
else if (from_window != NULL && to_window == NULL)
|
||||
{
|
||||
GList *from_ancestors = NULL, *list;
|
||||
GdkWindow *from_ancestor = from_window;
|
||||
|
||||
while (from_ancestor != NULL)
|
||||
{
|
||||
if (from_ancestor != NULL)
|
||||
{
|
||||
from_ancestor = gdk_window_get_parent (from_ancestor);
|
||||
if (from_ancestor == NULL)
|
||||
break;
|
||||
from_ancestors = g_list_prepend (from_ancestors, from_ancestor);
|
||||
}
|
||||
}
|
||||
|
||||
synth_crossing (from, GDK_LEAVE_NOTIFY, from_window,
|
||||
mode, GDK_NOTIFY_ANCESTOR);
|
||||
for (list = g_list_last (from_ancestors); list; list = list->prev)
|
||||
{
|
||||
synth_crossing (NULL, GDK_LEAVE_NOTIFY, (GdkWindow *) list->data,
|
||||
mode, GDK_NOTIFY_VIRTUAL);
|
||||
}
|
||||
|
||||
/* XXX: enter/inferior on root window? */
|
||||
|
||||
g_list_free (from_ancestors);
|
||||
}
|
||||
else if (from_window == NULL && to_window != NULL)
|
||||
{
|
||||
GList *to_ancestors = NULL, *list;
|
||||
GdkWindow *to_ancestor = to_window;
|
||||
|
||||
while (to_ancestor != NULL)
|
||||
{
|
||||
if (to_ancestor != NULL)
|
||||
{
|
||||
to_ancestor = gdk_window_get_parent (to_ancestor);
|
||||
if (to_ancestor == NULL)
|
||||
break;
|
||||
to_ancestors = g_list_prepend (to_ancestors, to_ancestor);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: leave/inferior on root window? */
|
||||
|
||||
for (list = to_ancestors; list; list = list->next)
|
||||
{
|
||||
synth_crossing (NULL, GDK_ENTER_NOTIFY, (GdkWindow *) list->data,
|
||||
mode, GDK_NOTIFY_VIRTUAL);
|
||||
}
|
||||
synth_crossing (to, GDK_ENTER_NOTIFY, to_window,
|
||||
mode, GDK_NOTIFY_ANCESTOR);
|
||||
|
||||
g_list_free (to_ancestors);
|
||||
}
|
||||
else if (from_window == to_window)
|
||||
;
|
||||
else
|
||||
{
|
||||
GList *from_ancestors = NULL, *to_ancestors = NULL, *list;
|
||||
GdkWindow *from_ancestor = from_window, *to_ancestor = to_window;
|
||||
|
||||
while (from_ancestor != NULL || to_ancestor != NULL)
|
||||
{
|
||||
if (from_ancestor != NULL)
|
||||
{
|
||||
from_ancestor = gdk_window_get_parent (from_ancestor);
|
||||
if (from_ancestor == to_window)
|
||||
break;
|
||||
from_ancestors = g_list_prepend (from_ancestors, from_ancestor);
|
||||
}
|
||||
if (to_ancestor != NULL)
|
||||
{
|
||||
to_ancestor = gdk_window_get_parent (to_ancestor);
|
||||
if (to_ancestor == from_window)
|
||||
break;
|
||||
to_ancestors = g_list_prepend (to_ancestors, to_ancestor);
|
||||
}
|
||||
}
|
||||
if (to_ancestor == from_window)
|
||||
{
|
||||
if (mode != GDK_CROSSING_GTK_UNGRAB)
|
||||
synth_crossing (from, GDK_LEAVE_NOTIFY, from_window,
|
||||
mode, GDK_NOTIFY_INFERIOR);
|
||||
for (list = to_ancestors; list; list = list->next)
|
||||
synth_crossing (NULL, GDK_ENTER_NOTIFY, (GdkWindow *) list->data,
|
||||
mode, GDK_NOTIFY_VIRTUAL);
|
||||
synth_crossing (to, GDK_ENTER_NOTIFY, to_window,
|
||||
mode, GDK_NOTIFY_ANCESTOR);
|
||||
}
|
||||
else if (from_ancestor == to_window)
|
||||
{
|
||||
synth_crossing (from, GDK_LEAVE_NOTIFY, from_window,
|
||||
mode, GDK_NOTIFY_ANCESTOR);
|
||||
for (list = g_list_last (from_ancestors); list; list = list->prev)
|
||||
{
|
||||
synth_crossing (NULL, GDK_LEAVE_NOTIFY, (GdkWindow *) list->data,
|
||||
mode, GDK_NOTIFY_VIRTUAL);
|
||||
}
|
||||
if (mode != GDK_CROSSING_GTK_GRAB)
|
||||
synth_crossing (to, GDK_ENTER_NOTIFY, to_window,
|
||||
mode, GDK_NOTIFY_INFERIOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (from_ancestors != NULL && to_ancestors != NULL
|
||||
&& from_ancestors->data == to_ancestors->data)
|
||||
{
|
||||
from_ancestors = g_list_delete_link (from_ancestors,
|
||||
from_ancestors);
|
||||
to_ancestors = g_list_delete_link (to_ancestors, to_ancestors);
|
||||
}
|
||||
|
||||
synth_crossing (from, GDK_LEAVE_NOTIFY, from_window,
|
||||
mode, GDK_NOTIFY_NONLINEAR);
|
||||
|
||||
for (list = g_list_last (from_ancestors); list; list = list->prev)
|
||||
{
|
||||
synth_crossing (NULL, GDK_LEAVE_NOTIFY, (GdkWindow *) list->data,
|
||||
mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
|
||||
}
|
||||
for (list = to_ancestors; list; list = list->next)
|
||||
{
|
||||
synth_crossing (NULL, GDK_ENTER_NOTIFY, (GdkWindow *) list->data,
|
||||
mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
|
||||
}
|
||||
synth_crossing (to, GDK_ENTER_NOTIFY, to_window,
|
||||
mode, GDK_NOTIFY_NONLINEAR);
|
||||
}
|
||||
g_list_free (from_ancestors);
|
||||
g_list_free (to_ancestors);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_widget_propagate_state (GtkWidget *widget,
|
||||
GtkStateData *data)
|
||||
@ -8108,6 +8386,16 @@ gtk_widget_propagate_state (GtkWidget *widget,
|
||||
|
||||
g_signal_emit (widget, widget_signals[STATE_CHANGED], 0, old_state);
|
||||
|
||||
if (GTK_WIDGET_HAS_POINTER (widget) && !GTK_WIDGET_SHADOWED (widget))
|
||||
{
|
||||
if (!GTK_WIDGET_IS_SENSITIVE (widget))
|
||||
_gtk_widget_synthesize_crossing (widget, NULL,
|
||||
GDK_CROSSING_STATE_CHANGED);
|
||||
else if (old_state == GTK_STATE_INSENSITIVE)
|
||||
_gtk_widget_synthesize_crossing (NULL, widget,
|
||||
GDK_CROSSING_STATE_CHANGED);
|
||||
}
|
||||
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
{
|
||||
data->parent_sensitive = (GTK_WIDGET_IS_SENSITIVE (widget) != FALSE);
|
||||
|
@ -833,6 +833,14 @@ void _gtk_widget_propagate_screen_changed (GtkWidget *widget,
|
||||
GdkScreen *previous_screen);
|
||||
void _gtk_widget_propagate_composited_changed (GtkWidget *widget);
|
||||
|
||||
void _gtk_widget_set_pointer_window (GtkWidget *widget,
|
||||
GdkWindow *pointer_window);
|
||||
GdkWindow *_gtk_widget_get_pointer_window (GtkWidget *widget);
|
||||
gboolean _gtk_widget_is_pointer_widget (GtkWidget *widget);
|
||||
void _gtk_widget_synthesize_crossing (GtkWidget *from,
|
||||
GtkWidget *to,
|
||||
GdkCrossingMode mode);
|
||||
|
||||
GdkColormap* _gtk_widget_peek_colormap (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -2052,10 +2052,6 @@ gtk_window_unset_transient_for (GtkWindow *window)
|
||||
|
||||
if (window->transient_parent)
|
||||
{
|
||||
if (priv->transient_parent_group)
|
||||
gtk_window_group_remove_window (window->group,
|
||||
window);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (window->transient_parent,
|
||||
gtk_window_transient_parent_realized,
|
||||
window);
|
||||
@ -2073,7 +2069,13 @@ gtk_window_unset_transient_for (GtkWindow *window)
|
||||
disconnect_parent_destroyed (window);
|
||||
|
||||
window->transient_parent = NULL;
|
||||
priv->transient_parent_group = FALSE;
|
||||
|
||||
if (priv->transient_parent_group)
|
||||
{
|
||||
priv->transient_parent_group = FALSE;
|
||||
gtk_window_group_remove_window (window->group,
|
||||
window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,10 @@ TEST_PROGS += object
|
||||
object_SOURCES = object.c pixbuf-init.c
|
||||
object_LDADD = $(progs_ldadd)
|
||||
|
||||
TEST_PROGS += crossingevents
|
||||
crossingevents_SOURCES = crossingevents.c
|
||||
crossingevents_LDADD = $(progs_ldadd)
|
||||
|
||||
# this doesn't work in make distcheck, since it doesn't
|
||||
# find file-chooser-test-dir
|
||||
# TEST_PROGS += filechooser
|
||||
|
1254
gtk/tests/crossingevents.c
Normal file
1254
gtk/tests/crossingevents.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user