compositor-x11: Handle keyboard focus correctly so we avoid stuck modifiers
authorKristian Høgsberg <krh@bitplanet.net>
Thu, 27 Jan 2011 16:57:19 +0000 (11:57 -0500)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 27 Jan 2011 16:57:19 +0000 (11:57 -0500)
clients/window.c
compositor/compositor-x11.c
compositor/compositor.c
compositor/compositor.h
wayland/wayland-util.c
wayland/wayland-util.h

index 7567cce..da9055c 100644 (file)
@@ -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];
 
index 4a5f10b..7ca3fdb 100644 (file)
@@ -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);
 
index ed7656b..b6cdbe6 100644 (file)
@@ -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,
index e40006c..3418b53 100644 (file)
@@ -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);
index a287cce..3643274 100644 (file)
@@ -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);
+}
index 76d703a..6c1231a 100644 (file)
@@ -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
 }