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.
This commit is contained in:
@ -51,6 +51,13 @@ static void gdk_input_update_axes (GdkDevicePrivate *gdkd
|
|||||||
static guint gdk_input_translate_state (guint state,
|
static guint gdk_input_translate_state (guint state,
|
||||||
guint device_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 *
|
GdkDevicePrivate *
|
||||||
_gdk_input_find_device (GdkDisplay *display,
|
_gdk_input_find_device (GdkDisplay *display,
|
||||||
guint32 id)
|
guint32 id)
|
||||||
@ -314,6 +321,7 @@ void
|
|||||||
_gdk_input_select_events (GdkWindow *impl_window,
|
_gdk_input_select_events (GdkWindow *impl_window,
|
||||||
GdkDevicePrivate *gdkdev)
|
GdkDevicePrivate *gdkdev)
|
||||||
{
|
{
|
||||||
|
int (*old_handler) (Display *, XErrorEvent *);
|
||||||
XEventClass classes[GDK_MAX_DEVICE_CLASSES];
|
XEventClass classes[GDK_MAX_DEVICE_CLASSES];
|
||||||
gint num_classes;
|
gint num_classes;
|
||||||
guint event_mask;
|
guint event_mask;
|
||||||
@ -341,9 +349,22 @@ _gdk_input_select_events (GdkWindow *impl_window,
|
|||||||
|
|
||||||
_gdk_input_common_find_events (gdkdev, event_mask,
|
_gdk_input_common_find_events (gdkdev, event_mask,
|
||||||
classes, &num_classes);
|
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),
|
XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (impl_window),
|
||||||
GDK_WINDOW_XWINDOW (impl_window),
|
GDK_WINDOW_XWINDOW (impl_window),
|
||||||
classes, num_classes);
|
classes, num_classes);
|
||||||
|
XSetErrorHandler (old_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
gint
|
gint
|
||||||
@ -893,8 +914,9 @@ gdk_device_get_state (GdkDevice *device,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int (*old_handler) (Display *, XErrorEvent *);
|
||||||
GdkDevicePrivate *gdkdev;
|
GdkDevicePrivate *gdkdev;
|
||||||
XDeviceState *state;
|
XDeviceState *state = NULL;
|
||||||
XInputClass *input_class;
|
XInputClass *input_class;
|
||||||
|
|
||||||
if (mask)
|
if (mask)
|
||||||
@ -902,8 +924,22 @@ gdk_device_get_state (GdkDevice *device,
|
|||||||
|
|
||||||
gdkdev = (GdkDevicePrivate *)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),
|
state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
|
||||||
gdkdev->xdevice);
|
gdkdev->xdevice);
|
||||||
|
XSetErrorHandler (old_handler);
|
||||||
|
|
||||||
|
if (! state)
|
||||||
|
return;
|
||||||
|
|
||||||
input_class = state->data;
|
input_class = state->data;
|
||||||
for (i=0; i<state->num_classes; i++)
|
for (i=0; i<state->num_classes; i++)
|
||||||
{
|
{
|
||||||
|
@ -76,6 +76,12 @@ gdk_device_set_mode (GdkDevice *device,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ignore_errors (Display *display, XErrorEvent *event)
|
||||||
|
{
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gdk_input_check_proximity (GdkDisplay *display)
|
gdk_input_check_proximity (GdkDisplay *display)
|
||||||
{
|
{
|
||||||
@ -91,10 +97,31 @@ gdk_input_check_proximity (GdkDisplay *display)
|
|||||||
&& !GDK_IS_CORE (gdkdev)
|
&& !GDK_IS_CORE (gdkdev)
|
||||||
&& gdkdev->xdevice)
|
&& gdkdev->xdevice)
|
||||||
{
|
{
|
||||||
XDeviceState *state = XQueryDeviceState(display_impl->xdisplay,
|
int (*old_handler) (Display *, XErrorEvent *);
|
||||||
gdkdev->xdevice);
|
XDeviceState *state = NULL;
|
||||||
XInputClass *xic;
|
XInputClass *xic;
|
||||||
int i;
|
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;
|
xic = state->data;
|
||||||
for (i=0; i<state->num_classes; i++)
|
for (i=0; i<state->num_classes; i++)
|
||||||
|
Reference in New Issue
Block a user