libweston/backend-x11: Tracking previous events over multiple calls

Rather than doing it with a local variable, track any previous events by
hanging it out of the x11 backend and use it to handle keymap notify
events.

In this way we avoid corrupting the surface destroy signal list, in
notify_keyboard_focus_out(), ultimately leading to a crash.

Fixes #649, #650

Suggested-by: Daniel Stone <daniel.stone@collabora.com>
Reported-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
dev
Marius Vlad 2 years ago
parent 4cde507be6
commit d6ab6da988
  1. 34
      libweston/backend-x11/x11.c

@ -119,6 +119,7 @@ struct x11_backend {
xcb_atom_t cardinal; xcb_atom_t cardinal;
xcb_atom_t xkb_names; xcb_atom_t xkb_names;
} atom; } atom;
xcb_generic_event_t *prev_event;
}; };
struct x11_head { struct x11_head {
@ -1494,7 +1495,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
{ {
struct x11_backend *b = data; struct x11_backend *b = data;
struct x11_output *output; struct x11_output *output;
xcb_generic_event_t *event, *prev; xcb_generic_event_t *event;
xcb_client_message_event_t *client_message; xcb_client_message_event_t *client_message;
xcb_enter_notify_event_t *enter_notify; xcb_enter_notify_event_t *enter_notify;
xcb_key_press_event_t *key_press, *key_release; xcb_key_press_event_t *key_press, *key_release;
@ -1510,16 +1511,15 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
int count; int count;
struct timespec time; struct timespec time;
prev = NULL;
count = 0; count = 0;
while (x11_backend_next_event(b, &event, mask)) { while (x11_backend_next_event(b, &event, mask)) {
response_type = event->response_type & ~0x80; response_type = event->response_type & ~0x80;
switch (prev ? prev->response_type & ~0x80 : 0x80) { switch (b->prev_event ? b->prev_event->response_type & ~0x80 : 0x80) {
case XCB_KEY_RELEASE: case XCB_KEY_RELEASE:
/* Suppress key repeat events; this is only used if we /* Suppress key repeat events; this is only used if we
* don't have XCB XKB support. */ * don't have XCB XKB support. */
key_release = (xcb_key_press_event_t *) prev; key_release = (xcb_key_press_event_t *) b->prev_event;
key_press = (xcb_key_press_event_t *) event; key_press = (xcb_key_press_event_t *) event;
if (response_type == XCB_KEY_PRESS && if (response_type == XCB_KEY_PRESS &&
key_release->time == key_press->time && key_release->time == key_press->time &&
@ -1527,8 +1527,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
/* Don't deliver the held key release /* Don't deliver the held key release
* event or the new key press event. */ * event or the new key press event. */
free(event); free(event);
free(prev); free(b->prev_event);
prev = NULL; b->prev_event = NULL;
continue; continue;
} else { } else {
/* Deliver the held key release now /* Deliver the held key release now
@ -1541,8 +1541,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
key_release->detail - 8, key_release->detail - 8,
WL_KEYBOARD_KEY_STATE_RELEASED, WL_KEYBOARD_KEY_STATE_RELEASED,
STATE_UPDATE_AUTOMATIC); STATE_UPDATE_AUTOMATIC);
free(prev); free(b->prev_event);
prev = NULL; b->prev_event = NULL;
break; break;
} }
@ -1566,8 +1566,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
notify_keyboard_focus_in(&b->core_seat, &b->keys, notify_keyboard_focus_in(&b->core_seat, &b->keys,
STATE_UPDATE_AUTOMATIC); STATE_UPDATE_AUTOMATIC);
free(prev); free(b->prev_event);
prev = NULL; b->prev_event = NULL;
break; break;
default: default:
@ -1592,7 +1592,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
/* If we don't have XKB, we need to use the lame /* If we don't have XKB, we need to use the lame
* autorepeat detection above. */ * autorepeat detection above. */
if (!b->has_xkb) { if (!b->has_xkb) {
prev = event; b->prev_event = event;
break; break;
} }
key_release = (xcb_key_press_event_t *) event; key_release = (xcb_key_press_event_t *) event;
@ -1687,7 +1687,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED) if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
break; break;
prev = event; b->prev_event = event;
break; break;
case XCB_FOCUS_OUT: case XCB_FOCUS_OUT:
@ -1721,13 +1721,13 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
#endif #endif
count++; count++;
if (prev != event) if (b->prev_event != event)
free(event); free(event);
} }
switch (prev ? prev->response_type & ~0x80 : 0x80) { switch (b->prev_event ? b->prev_event->response_type & ~0x80 : 0x80) {
case XCB_KEY_RELEASE: case XCB_KEY_RELEASE:
key_release = (xcb_key_press_event_t *) prev; key_release = (xcb_key_press_event_t *) b->prev_event;
update_xkb_state_from_core(b, key_release->state); update_xkb_state_from_core(b, key_release->state);
weston_compositor_get_time(&time); weston_compositor_get_time(&time);
notify_key(&b->core_seat, notify_key(&b->core_seat,
@ -1735,8 +1735,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
key_release->detail - 8, key_release->detail - 8,
WL_KEYBOARD_KEY_STATE_RELEASED, WL_KEYBOARD_KEY_STATE_RELEASED,
STATE_UPDATE_AUTOMATIC); STATE_UPDATE_AUTOMATIC);
free(prev); free(b->prev_event);
prev = NULL; b->prev_event = NULL;
break; break;
default: default:
break; break;

Loading…
Cancel
Save