summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2011-01-27 11:57:19 -0500
committerKristian Høgsberg <krh@bitplanet.net>2011-01-27 11:57:19 -0500
commit3ba4858c4b62a5d253bd757944ceccae3764d6ce (patch)
tree5b89aa0b6607a11266b347c4a2830d9476773099
parentac5c5e78533d093d9f790564bea114194a387c3a (diff)
compositor-x11: Handle keyboard focus correctly so we avoid stuck modifiers
-rw-r--r--clients/window.c1
-rw-r--r--compositor/compositor-x11.c45
-rw-r--r--compositor/compositor.c22
-rw-r--r--compositor/compositor.h6
-rw-r--r--wayland/wayland-util.c8
-rw-r--r--wayland/wayland-util.h1
6 files changed, 80 insertions, 3 deletions
diff --git a/clients/window.c b/clients/window.c
index 7567cce..da9055c 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 4a5f10b..7ca3fdb 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 ed7656b..b6cdbe6 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 e40006c..3418b53 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 {
@@ -162,6 +163,11 @@ notify_pointer_focus(struct wl_input_device *device,
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
wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor);
diff --git a/wayland/wayland-util.c b/wayland/wayland-util.c
index a287cce..3643274 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 76d703a..6c1231a 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
}