diff --git a/clients/window.c b/clients/window.c index 7567cce3..da9055c1 100644 --- a/clients/window.c +++ b/clients/window.c @@ -1015,6 +1015,7 @@ window_handle_keyboard_focus(void *data, input->keyboard_focus = NULL; end = keys->data + keys->size; + input->modifiers = 0; for (k = keys->data; k < end; k++) input->modifiers |= d->xkb->map->modmap[*k]; diff --git a/compositor/compositor-x11.c b/compositor/compositor-x11.c index 4a5f10bb..7ca3fdbc 100644 --- a/compositor/compositor-x11.c +++ b/compositor/compositor-x11.c @@ -53,6 +53,7 @@ struct x11_compositor { xcb_cursor_t null_cursor; int dri2_major; int dri2_minor; + struct wl_array keys; struct wl_event_source *xcb_source; struct { xcb_atom_t wm_protocols; @@ -381,7 +382,9 @@ x11_compositor_create_output(struct x11_compositor *c, int width, int height) XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW | - XCB_EVENT_MASK_LEAVE_WINDOW, + XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_KEYMAP_STATE | + XCB_EVENT_MASK_FOCUS_CHANGE, 0 }; @@ -550,9 +553,13 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data) xcb_enter_notify_event_t *enter_notify; xcb_key_press_event_t *key_press; xcb_button_press_event_t *button_press; + xcb_keymap_notify_event_t *keymap_notify; + xcb_focus_in_event_t *focus_in; xcb_expose_event_t *expose; xcb_rectangle_t *r; xcb_atom_t atom; + uint32_t *k; + int i, set; loop = wl_display_get_event_loop(c->base.wl_display); while (event = xcb_poll_for_event (c->conn), event != NULL) { @@ -630,13 +637,44 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data) if (atom == c->atom.wm_delete_window) wl_display_terminate(c->base.wl_display); break; - default: + case XCB_FOCUS_IN: + focus_in = (xcb_focus_in_event_t *) event; + if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED) + break; + + output = x11_compositor_find_output(c, focus_in->event); + notify_keyboard_focus(c->base.input_device, + get_time(), + &output->base, &c->keys); + break; + + case XCB_FOCUS_OUT: + focus_in = (xcb_focus_in_event_t *) event; + if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED) + break; + notify_keyboard_focus(c->base.input_device, + get_time(), NULL, NULL); + break; + + case XCB_KEYMAP_NOTIFY: + keymap_notify = (xcb_keymap_notify_event_t *) event; + c->keys.size = 0; + for (i = 0; i < ARRAY_LENGTH(keymap_notify->keys) * 8; i++) { + set = keymap_notify->keys[i >> 3] & + (1 << (i & 7)); + if (set) { + k = wl_array_add(&c->keys, sizeof *k); + *k = i; + } + } + break; + default: break; } free (event); - } + } } #define F(field) offsetof(struct x11_compositor, field) @@ -719,6 +757,7 @@ x11_compositor_create(struct wl_display *display, int width, int height) s = xcb_setup_roots_iterator(xcb_get_setup(c->conn)); c->screen = s.data; + wl_array_init(&c->keys); x11_compositor_get_resources(c); diff --git a/compositor/compositor.c b/compositor/compositor.c index ed7656b8..b6cdbe6e 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -840,6 +840,28 @@ notify_pointer_focus(struct wl_input_device *device, wlsc_compositor_schedule_repaint(compositor); } +void +notify_keyboard_focus(struct wl_input_device *device_base, + uint32_t time, struct wlsc_output *output, + struct wl_array *keys) +{ + struct wlsc_input_device *device = + (struct wlsc_input_device *) device_base; + + if (output) { + wl_array_copy(&device->input_device.keys, keys); + wl_input_device_set_keyboard_focus(&device->input_device, + device->saved_keyboard_focus, + time); + } else { + device->saved_keyboard_focus = + device->input_device.keyboard_focus; + wl_input_device_set_keyboard_focus(&device->input_device, + NULL, time); + } +} + + static void input_device_attach(struct wl_client *client, struct wl_input_device *device_base, diff --git a/compositor/compositor.h b/compositor/compositor.h index e40006cb..3418b53b 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -70,6 +70,7 @@ struct wlsc_input_device { struct wl_list link; uint32_t modifier_state; struct wl_selection *selection; + struct wl_surface *saved_keyboard_focus; }; struct wlsc_drm { @@ -161,6 +162,11 @@ notify_pointer_focus(struct wl_input_device *device, struct wlsc_output *output, int32_t x, int32_t y); +void +notify_keyboard_focus(struct wl_input_device *device, + uint32_t time, struct wlsc_output *output, + struct wl_array *keys); + void wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs); void diff --git a/wayland/wayland-util.c b/wayland/wayland-util.c index a287cce0..36432743 100644 --- a/wayland/wayland-util.c +++ b/wayland/wayland-util.c @@ -113,3 +113,11 @@ wl_array_add(struct wl_array *array, int size) return p; } + +WL_EXPORT void +wl_array_copy(struct wl_array *array, struct wl_array *source) +{ + array->size = 0; + wl_array_add(array, source->size); + memcpy(array->data, source->data, source->size); +} diff --git a/wayland/wayland-util.h b/wayland/wayland-util.h index 76d703ad..6c1231a9 100644 --- a/wayland/wayland-util.h +++ b/wayland/wayland-util.h @@ -148,6 +148,7 @@ struct wl_array { 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); +void wl_array_copy(struct wl_array *array, struct wl_array *source); #ifdef __cplusplus }