[gtk+/gtk-2-24] Bug 575767: fix crashes when XInput device disappears.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gtk-2-24] Bug 575767: fix crashes when XInput device disappears.
- Date: Wed, 22 May 2013 20:50:29 +0000 (UTC)
commit 8368de2bc35056d466f0a536eadc353c69c0e6e3
Author: Jehan <jehan girinstud io>
Date: Fri May 17 23:04:40 2013 +0900
Bug 575767: fix crashes when XInput device disappears.
Ignore X11 errors from querying state of unplugged input devices.
GTK+ 3 handle this better with hotplugging support in XInput 2, but
this is working workaround for avoiding ugly crashes and data loss
with GTK+ 2.
gdk/x11/gdkinput-x11.c | 38 +++++++++++++++++++++++++++++++++++++-
gdk/x11/gdkinput-xfree.c | 35 +++++++++++++++++++++++++++++++----
2 files changed, 68 insertions(+), 5 deletions(-)
---
diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c
index 767b070..83b5b28 100644
--- a/gdk/x11/gdkinput-x11.c
+++ b/gdk/x11/gdkinput-x11.c
@@ -51,6 +51,13 @@ static void gdk_input_update_axes (GdkDevicePrivate *gdkd
static guint gdk_input_translate_state (guint state,
guint device_state);
+/* A temporary error handler for ignoring device unplugging-related errors. */
+static int
+ignore_errors (Display *display, XErrorEvent *event)
+{
+ return True;
+}
+
GdkDevicePrivate *
_gdk_input_find_device (GdkDisplay *display,
guint32 id)
@@ -314,6 +321,7 @@ void
_gdk_input_select_events (GdkWindow *impl_window,
GdkDevicePrivate *gdkdev)
{
+ int (*old_handler) (Display *, XErrorEvent *);
XEventClass classes[GDK_MAX_DEVICE_CLASSES];
gint num_classes;
guint event_mask;
@@ -341,9 +349,22 @@ _gdk_input_select_events (GdkWindow *impl_window,
_gdk_input_common_find_events (gdkdev, event_mask,
classes, &num_classes);
+
+ /* From X11 doc:
+ * "XSelectExtensionEvent can generate a BadWindow or BadClass error."
+ * In particular when a device is unplugged, a requested event class
+ * could no longer be valid and raise a BadClass, which would cause
+ * the program to crash.
+ *
+ * To handle this case gracefully, we simply ignore XSelectExtensionEvent() errors.
+ * This is OK since there is no events to report for the unplugged device anyway.
+ * So simply the device remains "silent".
+ */
+ old_handler = XSetErrorHandler (ignore_errors);
XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (impl_window),
GDK_WINDOW_XWINDOW (impl_window),
classes, num_classes);
+ XSetErrorHandler (old_handler);
}
gint
@@ -893,8 +914,9 @@ gdk_device_get_state (GdkDevice *device,
}
else
{
+ int (*old_handler) (Display *, XErrorEvent *);
GdkDevicePrivate *gdkdev;
- XDeviceState *state;
+ XDeviceState *state = NULL;
XInputClass *input_class;
if (mask)
@@ -902,8 +924,22 @@ gdk_device_get_state (GdkDevice *device,
gdkdev = (GdkDevicePrivate *)device;
+ /* From X11 doc: "XQueryDeviceState can generate a BadDevice error."
+ * This would occur in particular when a device is unplugged,
+ * which would cause the program to crash (see bug 575767).
+ *
+ * To handle this case gracefully, we simply ignore the device.
+ * GTK+ 3 handles this better with XInput 2's hotplugging support;
+ * but this is better than a crash in GTK+ 2.
+ */
+ old_handler = XSetErrorHandler (ignore_errors);
state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
gdkdev->xdevice);
+ XSetErrorHandler (old_handler);
+
+ if (! state)
+ return;
+
input_class = state->data;
for (i=0; i<state->num_classes; i++)
{
diff --git a/gdk/x11/gdkinput-xfree.c b/gdk/x11/gdkinput-xfree.c
index 5d87ccd..566a0c0 100644
--- a/gdk/x11/gdkinput-xfree.c
+++ b/gdk/x11/gdkinput-xfree.c
@@ -76,6 +76,12 @@ gdk_device_set_mode (GdkDevice *device,
return TRUE;
}
+static int
+ignore_errors (Display *display, XErrorEvent *event)
+{
+ return True;
+}
+
static void
gdk_input_check_proximity (GdkDisplay *display)
{
@@ -91,10 +97,31 @@ gdk_input_check_proximity (GdkDisplay *display)
&& !GDK_IS_CORE (gdkdev)
&& gdkdev->xdevice)
{
- XDeviceState *state = XQueryDeviceState(display_impl->xdisplay,
- gdkdev->xdevice);
- XInputClass *xic;
- int i;
+ int (*old_handler) (Display *, XErrorEvent *);
+ XDeviceState *state = NULL;
+ XInputClass *xic;
+ int i;
+
+ /* From X11 doc: "XQueryDeviceState can generate a BadDevice error."
+ * This would occur in particular when a device is unplugged,
+ * which would cause the program to crash (see bug 575767).
+ *
+ * To handle this case gracefully, we simply ignore the device.
+ * GTK+ 3 handles this better with XInput 2's hotplugging support;
+ * but this is better than a crash in GTK+ 2.
+ */
+ old_handler = XSetErrorHandler (ignore_errors);
+ state = XQueryDeviceState(display_impl->xdisplay, gdkdev->xdevice);
+ XSetErrorHandler (old_handler);
+
+ if (! state)
+ {
+ /* Broken device. It may have been disconnected.
+ * Ignore it.
+ */
+ tmp_list = tmp_list->next;
+ continue;
+ }
xic = state->data;
for (i=0; i<state->num_classes; i++)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]