Events delivered to not-viewable windows
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gnome org
- Cc: timj gtk org
- Subject: Events delivered to not-viewable windows
- Date: 06 Jun 2003 11:35:06 -0400
http://bugzilla.gnome.org/show_bug.cgi?id=105642 points out
a very long-standing problem in GTK+ - you can get events
delivered to windows that are no longer viewable. (Viewable
means that the window and all it's parents are mapped.)
The case in the bug report is:
Application hides window after gtk_dialog_run(), but
Escape keypress is queued up and causes the dialog
to be destroyed
But you can easily construct other examples as well, for
example:
User clicks on a notebook tab the dialog, then quickly
clicks on a window-widget in the dialog before the
page changes.
The attach patch is an attempt to solve the problem;
what it does is is that before emitting ::event,
::<foo>-event ::event-after check that the window is
viewable.
I think this patch considerably improves the current situation;
though I have two small concerns about the re-checking between
the 3 signals:
- The repeated checks don't catch the case where one handler
for the signal unmaps the window or a parent, so they
are still imperfect. (The point could be made about
the current WIDGET_REALIZED_FOR_EVENT() check)
- It's slightly conceivable that an app might rely on
still receiving an event in ::event-after even if the
main handlers resulted in the widget being hidden.
It's possible that considering these points, it would be
simpler o just check once at the top of the function, and
ignore the possibility of handlers in the course of
gtk_widget_event() making the widget not-viewable.
Regards,
Owen
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.4220
diff -u -p -r1.4220 ChangeLog
--- ChangeLog 6 Jun 2003 00:52:17 -0000 1.4220
+++ ChangeLog 6 Jun 2003 15:19:20 -0000
@@ -1,6 +1,20 @@
+Fri Jun 6 11:07:33 2003 Owen Taylor <otaylor redhat com>
+
+ * gtk/gtkwidget.c (event_window_still_viewable):
+ Before delivering an event to a widget, check that
+ (if relevant), the event's window is still viewable.
+
+ * gdk/gdkwindow.c (_gdk_window_destroy_hierarchy):
+ NULL out private->parent, since after destruction
+ it might not be valid any more.
+
+ * gdk/gdkwindow.c (gdk_window_is_viewable): Fix some
+ accesses before g_return_val_if_fail(). Treat
+ DESTROYED windows as unmaped.
+
Thu Jun 5 20:35:40 2003 Owen Taylor <otaylor redhat com>
- * demos/Makefile.am: Conditionalize deendencies for
+ * demos/Makefile.am: Conditionalize dependencies for
gdk-pixbuf-csource on cross-compilation (#112391, J. Ali Harlowe).
Buildtest-inline-pixbufs.h in srcdir. Don't try to build
test-inline-pixbufs.h if we don't have libpng.
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.344
diff -u -p -r1.344 gtkwidget.c
--- gtk/gtkwidget.c 21 May 2003 23:08:27 -0000 1.344
+++ gtk/gtkwidget.c 6 Jun 2003 15:19:20 -0000
@@ -3040,16 +3040,53 @@ gtk_widget_send_expose (GtkWidget *widge
return gtk_widget_event_internal (widget, event);
}
+static gboolean
+event_window_is_still_viewable (GdkEvent *event)
+{
+ /* Check that we think the event's window is viewable before
+ * delivering the event, to prevent suprises. We do this here
+ * at the last moment, since the event may have been queued
+ * up behind other events, held over a recursive main loop, etc.
+ */
+ switch (event->type)
+ {
+ case GDK_EXPOSE:
+ case GDK_MOTION_NOTIFY:
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ case GDK_SCROLL:
+ return event->any.window && gdk_window_is_viewable (event->any.window);
+
+ default:
+ /* Remaining events would make sense on an not-viewable window,
+ * or don't have an associated window.
+ */
+ return TRUE;
+ }
+}
+
static gint
gtk_widget_event_internal (GtkWidget *widget,
GdkEvent *event)
{
gboolean return_val = FALSE;
+ if (!event_window_is_still_viewable (event))
+ return TRUE;
+
g_object_ref (widget);
g_signal_emit (widget, widget_signals[EVENT], 0, event, &return_val);
- return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
+ return_val |= !(WIDGET_REALIZED_FOR_EVENT (widget, event) &&
+ event_window_is_still_viewable (event));
if (!return_val)
{
gint signal_num;
@@ -3144,7 +3181,8 @@ gtk_widget_event_internal (GtkWidget *wi
if (signal_num != -1)
g_signal_emit (widget, widget_signals[signal_num], 0, event, &return_val);
}
- if (WIDGET_REALIZED_FOR_EVENT (widget, event))
+ if (WIDGET_REALIZED_FOR_EVENT (widget, event) &&
+ event_window_is_still_viewable (event))
g_signal_emit (widget, widget_signals[EVENT_AFTER], 0, event);
else
return_val = TRUE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]