Update pad modes in a workproc, not during the input thread

Updating the property directly causes us to send events from the input thread
which has some "interesting" side effects like messing up the reply order or
just crashing the server.

Schedule a work proc instead and update it whenever the server is back in the
main thread.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer
2017-02-24 12:27:37 +10:00
parent 2eb5a2f0c0
commit 7c90f06d56

View File

@@ -3386,17 +3386,43 @@ static Atom prop_float;
static Atom prop_device;
static Atom prop_product_id;
static inline void
update_mode_prop(InputInfoPtr pInfo,
struct libinput_event_tablet_pad *event)
{
struct xf86libinput *driver_data = pInfo->private;
struct mode_prop_state {
int deviceid;
InputInfoPtr pInfo;
struct libinput_tablet_pad_mode_group *group;
unsigned int mode;
unsigned int idx;
};
static Bool
update_mode_prop_cb(ClientPtr client, pointer closure)
{
struct mode_prop_state *state = closure;
InputInfoPtr pInfo = state->pInfo, tmp;
struct xf86libinput *driver_data = pInfo->private;
BOOL found = FALSE;
XIPropertyValuePtr val;
int rc;
unsigned char groups[4] = {0};
struct libinput_tablet_pad_mode_group *group = state->group;
unsigned int mode = state->mode;
unsigned int idx = state->idx;
if (idx >= ARRAY_SIZE(groups))
goto out;
/* The device may have gotten removed before the WorkProc was
* scheduled. X reuses deviceids, but if the pointer value and
* device ID are what we had before, we're good */
nt_list_for_each_entry(tmp, xf86FirstLocalDevice(), next) {
if (tmp->dev->id == state->deviceid && tmp == pInfo) {
found = TRUE;
break;
}
}
if (!found)
goto out;
rc = XIGetDeviceProperty(pInfo->dev,
prop_mode_groups,
@@ -3404,18 +3430,12 @@ update_mode_prop(InputInfoPtr pInfo,
if (rc != Success ||
val->format != 8 ||
val->size <= 0)
return;
goto out;
memcpy(groups, (unsigned char*)val->data, val->size);
group = libinput_event_tablet_pad_get_mode_group(event);
mode = libinput_event_tablet_pad_get_mode(event);
idx = libinput_tablet_pad_mode_group_get_index(group);
if (idx >= ARRAY_SIZE(groups))
return;
if (groups[idx] == mode)
return;
goto out;
groups[idx] = mode;
@@ -3428,8 +3448,36 @@ update_mode_prop(InputInfoPtr pInfo,
groups,
TRUE);
driver_data->allow_mode_group_updates = false;
if (rc != Success)
out:
libinput_tablet_pad_mode_group_unref(group);
free(state);
return TRUE;
}
static inline void
update_mode_prop(InputInfoPtr pInfo,
struct libinput_event_tablet_pad *event)
{
struct libinput_tablet_pad_mode_group *group;
struct mode_prop_state *state;
state = calloc(1, sizeof(*state));
if (!state)
return;
state->deviceid = pInfo->dev->id;
state->pInfo = pInfo;
group = libinput_event_tablet_pad_get_mode_group(event);
state->group = libinput_tablet_pad_mode_group_ref(group);
state->mode = libinput_event_tablet_pad_get_mode(event);
state->idx = libinput_tablet_pad_mode_group_get_index(group);
/* Schedule a WorkProc so we don't update from within the input
thread */
QueueWorkProc(update_mode_prop_cb, serverClient, state);
}
static inline BOOL