diff --git a/connection.c b/connection.c index 112ee4f9..b37e9402 100644 --- a/connection.c +++ b/connection.c @@ -229,6 +229,7 @@ wl_connection_vmarshal(struct wl_connection *connection, { struct wl_object *object; uint32_t args[32], length, *p, size; + struct wl_array *array; const char *s; int i, count; @@ -254,6 +255,16 @@ wl_connection_vmarshal(struct wl_connection *connection, object = va_arg(ap, struct wl_object *); *p++ = object ? object->id : 0; break; + case 'a': + array = va_arg(ap, struct wl_array *); + if (array == NULL || array->size == 0) { + *p++ = 0; + break; + } + *p++ = array->size; + memcpy(p, array->data, array->size); + p = (void *) p + array->size; + break; default: assert(0); break; @@ -283,6 +294,7 @@ wl_connection_demarshal(struct wl_connection *connection, char *string; void *object; uint32_t new_id; + struct wl_array *array; } values[20]; void *args[20]; struct wl_object *object; @@ -344,6 +356,20 @@ wl_connection_demarshal(struct wl_connection *connection, printf("object already exists (%d)\n", *p); p++; break; + case 'a': + types[i] = &ffi_type_pointer; + length = *p++; + values[i].array = malloc(length + sizeof *values[i].array); + if (values[i].array == NULL) { + /* FIXME: Send NO_MEMORY */ + return; + } + values[i].array->size = length; + values[i].array->alloc = 0; + values[i].array->data = values[i].array + 1; + memcpy(values[i].array->data, p, length); + p += DIV_ROUNDUP(length, sizeof *p); + break; default: printf("unknown type\n"); break; @@ -359,6 +385,9 @@ wl_connection_demarshal(struct wl_connection *connection, case 's': free(values[i].string); break; + case 'a': + free(values[i].array); + break; } } } diff --git a/wayland-client.h b/wayland-client.h index 8e8850ac..cb2bd294 100644 --- a/wayland-client.h +++ b/wayland-client.h @@ -124,7 +124,8 @@ struct wl_input_device_listener { struct wl_surface *surface); void (*keyboard_focus)(void *data, struct wl_input_device *input_device, - struct wl_surface *surface); + struct wl_surface *surface, + struct wl_array *keys); }; int diff --git a/wayland-protocol.c b/wayland-protocol.c index c542205a..464af2b8 100644 --- a/wayland-protocol.c +++ b/wayland-protocol.c @@ -77,7 +77,7 @@ static const struct wl_message input_device_events[] = { { "button", "uuiiii" }, { "key", "uu" }, { "pointer_focus", "o" }, - { "keyboard_focus", "o" }, + { "keyboard_focus", "oa" }, }; WL_EXPORT const struct wl_interface wl_input_device_interface = { diff --git a/wayland-system-compositor.c b/wayland-system-compositor.c index d0674ec3..5524dbb0 100644 --- a/wayland-system-compositor.c +++ b/wayland-system-compositor.c @@ -88,6 +88,7 @@ struct wlsc_input_device { struct wlsc_surface *grab_surface; struct wlsc_surface *pointer_focus; struct wlsc_surface *keyboard_focus; + struct wl_array keys; }; struct wlsc_compositor { @@ -870,14 +871,13 @@ wlsc_input_device_set_keyboard_focus(struct wlsc_input_device *device, (!surface || device->keyboard_focus->base.client != surface->base.client)) wl_surface_post_event(&device->keyboard_focus->base, &device->base, - WL_INPUT_KEYBOARD_FOCUS, NULL); + WL_INPUT_KEYBOARD_FOCUS, NULL, NULL); - /* FIXME: We need to send the currently held down keys in the - * keyboard focus event. */ if (surface) wl_surface_post_event(&surface->base, &device->base, - WL_INPUT_KEYBOARD_FOCUS, &surface->base); + WL_INPUT_KEYBOARD_FOCUS, + &surface->base, &device->keys); device->keyboard_focus = surface; } @@ -1051,6 +1051,10 @@ notify_key(struct wlsc_input_device *device, uint32_t key, uint32_t state) { struct wlsc_compositor *ec = device->ec; + uint32_t *k, *end; + + if (!ec->vt_active) + return; switch (key | ec->meta_state) { case KEY_EJECTCD | META_DOWN: @@ -1083,8 +1087,16 @@ notify_key(struct wlsc_input_device *device, return; } - if (!ec->vt_active) - return; + end = device->keys.data + device->keys.size; + for (k = device->keys.data; k < end; k++) { + if (*k == key) + *k = *--end; + } + device->keys.size = (void *) end - device->keys.data; + if (state) { + k = wl_array_add(&device->keys, sizeof *k); + *k = key; + } if (device->keyboard_focus != NULL) wl_surface_post_event(&device->keyboard_focus->base, diff --git a/wayland-util.c b/wayland-util.c index 4fae4359..a5ab8be4 100644 --- a/wayland-util.c +++ b/wayland-util.c @@ -137,3 +137,47 @@ wl_list_empty(struct wl_list *list) { return list->next == list; } + +void +wl_array_init(struct wl_array *array) +{ + memset(array, 0, sizeof *array); +} + +void +wl_array_release(struct wl_array *array) +{ + free(array->data); +} + +void * +wl_array_add(struct wl_array *array, int size) +{ + int alloc; + void *data, *p; + + if (array->alloc > 0) + alloc = array->alloc; + else + alloc = 16; + + while (alloc < array->size + size) + alloc *= 2; + + if (array->alloc < alloc) { + if (array->alloc > 0) + data = realloc(array->data, alloc); + else + data = malloc(alloc); + + if (data == NULL) + return 0; + array->data = data; + array->alloc = alloc; + } + + p = array->data + array->size; + array->size += size; + + return p; +} diff --git a/wayland-util.h b/wayland-util.h index ffb6f6d0..9da870cd 100644 --- a/wayland-util.h +++ b/wayland-util.h @@ -82,5 +82,14 @@ void wl_list_remove(struct wl_list *elm); int wl_list_length(struct wl_list *list); int wl_list_empty(struct wl_list *list); +struct wl_array { + uint32_t size; + uint32_t alloc; + void *data; +}; + +void wl_array_init(struct wl_array *array); +void wl_array_release(struct wl_array *array); +void *wl_array_add(struct wl_array *array, int size); #endif diff --git a/window.c b/window.c index b306a23c..9c29b620 100644 --- a/window.c +++ b/window.c @@ -33,6 +33,7 @@ #include #include +#include "wayland-util.h" #include "wayland-client.h" #include "wayland-glib.h" @@ -490,7 +491,8 @@ window_handle_pointer_focus(void *data, static void window_handle_keyboard_focus(void *data, struct wl_input_device *input_device, - struct wl_surface *surface) + struct wl_surface *surface, + struct wl_array *keys) { struct window *window = data;