diff options
Diffstat (limited to 'src/input.c')
-rw-r--r-- | src/input.c | 724 |
1 files changed, 541 insertions, 183 deletions
diff --git a/src/input.c b/src/input.c index dd8e4973..157066cc 100644 --- a/src/input.c +++ b/src/input.c @@ -29,6 +29,7 @@ #include <assert.h> #include <unistd.h> #include <fcntl.h> +#include <limits.h> #include "../shared/os-compatibility.h" #include "compositor.h" @@ -71,6 +72,56 @@ weston_compositor_idle_release(struct weston_compositor *compositor) } static void +pointer_focus_view_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_pointer *pointer = + container_of(listener, struct weston_pointer, + focus_view_listener); + + weston_pointer_set_focus(pointer, NULL, 0, 0); +} + +static void +pointer_focus_resource_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_pointer *pointer = + container_of(listener, struct weston_pointer, + focus_resource_listener); + + weston_pointer_set_focus(pointer, NULL, 0, 0); +} + +static void +keyboard_focus_resource_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_keyboard *keyboard = + container_of(listener, struct weston_keyboard, + focus_resource_listener); + + weston_keyboard_set_focus(keyboard, NULL); +} + +static void +touch_focus_view_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_touch *touch = + container_of(listener, struct weston_touch, + focus_view_listener); + + weston_touch_set_focus(touch->seat, NULL); +} + +static void +touch_focus_resource_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_touch *touch = + container_of(listener, struct weston_touch, + focus_resource_listener); + + weston_touch_set_focus(touch->seat, NULL); +} + +static void move_resources(struct wl_list *destination, struct wl_list *source) { wl_list_insert_list(destination, source); @@ -93,47 +144,50 @@ move_resources_for_client(struct wl_list *destination, } static void -default_grab_focus(struct weston_pointer_grab *grab) +default_grab_pointer_focus(struct weston_pointer_grab *grab) { struct weston_pointer *pointer = grab->pointer; - struct weston_surface *surface; + struct weston_view *view; wl_fixed_t sx, sy; if (pointer->button_count > 0) return; - surface = weston_compositor_pick_surface(pointer->seat->compositor, - pointer->x, pointer->y, - &sx, &sy); + view = weston_compositor_pick_view(pointer->seat->compositor, + pointer->x, pointer->y, + &sx, &sy); - if (pointer->focus != surface) - weston_pointer_set_focus(pointer, surface, sx, sy); + if (pointer->focus != view) + weston_pointer_set_focus(pointer, view, sx, sy); } static void -default_grab_motion(struct weston_pointer_grab *grab, uint32_t time) +default_grab_pointer_motion(struct weston_pointer_grab *grab, uint32_t time, + wl_fixed_t x, wl_fixed_t y) { struct weston_pointer *pointer = grab->pointer; wl_fixed_t sx, sy; struct wl_list *resource_list; struct wl_resource *resource; + weston_pointer_move(pointer, x, y); + resource_list = &pointer->focus_resource_list; wl_resource_for_each(resource, resource_list) { - weston_surface_from_global_fixed(pointer->focus, - pointer->x, pointer->y, - &sx, &sy); + weston_view_from_global_fixed(pointer->focus, + pointer->x, pointer->y, + &sx, &sy); wl_pointer_send_motion(resource, time, sx, sy); } } static void -default_grab_button(struct weston_pointer_grab *grab, - uint32_t time, uint32_t button, uint32_t state_w) +default_grab_pointer_button(struct weston_pointer_grab *grab, + uint32_t time, uint32_t button, uint32_t state_w) { struct weston_pointer *pointer = grab->pointer; struct weston_compositor *compositor = pointer->seat->compositor; - struct weston_surface *surface; + struct weston_view *view; struct wl_resource *resource; uint32_t serial; enum wl_pointer_button_state state = state_w; @@ -154,12 +208,11 @@ default_grab_button(struct weston_pointer_grab *grab, if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED) { - surface = weston_compositor_pick_surface(compositor, - pointer->x, - pointer->y, - &sx, &sy); + view = weston_compositor_pick_view(compositor, + pointer->x, pointer->y, + &sx, &sy); - weston_pointer_set_focus(pointer, surface, sx, sy); + weston_pointer_set_focus(pointer, view, sx, sy); } } @@ -170,9 +223,9 @@ default_grab_pointer_cancel(struct weston_pointer_grab *grab) static const struct weston_pointer_grab_interface default_pointer_grab_interface = { - default_grab_focus, - default_grab_motion, - default_grab_button, + default_grab_pointer_focus, + default_grab_pointer_motion, + default_grab_pointer_button, default_grab_pointer_cancel, }; @@ -192,7 +245,7 @@ default_grab_touch_down(struct weston_touch_grab *grab, uint32_t time, serial = wl_display_next_serial(display); wl_resource_for_each(resource, resource_list) wl_touch_send_down(resource, serial, time, - touch->focus->resource, + touch->focus->surface->resource, touch_id, sx, sy); } } @@ -245,8 +298,8 @@ static const struct weston_touch_grab_interface default_touch_grab_interface = { }; static void -default_grab_key(struct weston_keyboard_grab *grab, - uint32_t time, uint32_t key, uint32_t state) +default_grab_keyboard_key(struct weston_keyboard_grab *grab, + uint32_t time, uint32_t key, uint32_t state) { struct weston_keyboard *keyboard = grab->keyboard; struct wl_resource *resource; @@ -307,10 +360,20 @@ find_resource_for_surface(struct wl_list *list, struct weston_surface *surface) return wl_resource_find_for_client(list, wl_resource_get_client(surface->resource)); } +static struct wl_resource * +find_resource_for_view(struct wl_list *list, struct weston_view *view) +{ + if (!view) + return NULL; + + return find_resource_for_surface(list, view->surface); +} + static void -default_grab_modifiers(struct weston_keyboard_grab *grab, uint32_t serial, - uint32_t mods_depressed, uint32_t mods_latched, - uint32_t mods_locked, uint32_t group) +default_grab_keyboard_modifiers(struct weston_keyboard_grab *grab, + uint32_t serial, uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) { struct weston_keyboard *keyboard = grab->keyboard; struct weston_pointer *pointer = grab->keyboard->seat->pointer; @@ -323,9 +386,10 @@ default_grab_modifiers(struct weston_keyboard_grab *grab, uint32_t serial, wl_keyboard_send_modifiers(resource, serial, mods_depressed, mods_latched, mods_locked, group); } - if (pointer && pointer->focus && pointer->focus != keyboard->focus) { + if (pointer && pointer->focus && pointer->focus->surface->resource && + pointer->focus->surface != keyboard->focus) { struct wl_client *pointer_client = - wl_resource_get_client(pointer->focus->resource); + wl_resource_get_client(pointer->focus->surface->resource); send_modifiers_to_client_in_list(pointer_client, &keyboard->resource_list, serial, @@ -340,20 +404,21 @@ default_grab_keyboard_cancel(struct weston_keyboard_grab *grab) static const struct weston_keyboard_grab_interface default_keyboard_grab_interface = { - default_grab_key, - default_grab_modifiers, + default_grab_keyboard_key, + default_grab_keyboard_modifiers, default_grab_keyboard_cancel, }; static void pointer_unmap_sprite(struct weston_pointer *pointer) { - if (weston_surface_is_mapped(pointer->sprite)) - weston_surface_unmap(pointer->sprite); + if (weston_surface_is_mapped(pointer->sprite->surface)) + weston_surface_unmap(pointer->sprite->surface); wl_list_remove(&pointer->sprite_destroy_listener.link); - pointer->sprite->configure = NULL; - pointer->sprite->configure_private = NULL; + pointer->sprite->surface->configure = NULL; + pointer->sprite->surface->configure_private = NULL; + weston_view_destroy(pointer->sprite); pointer->sprite = NULL; } @@ -367,8 +432,14 @@ pointer_handle_sprite_destroy(struct wl_listener *listener, void *data) pointer->sprite = NULL; } +static void +weston_pointer_reset_state(struct weston_pointer *pointer) +{ + pointer->button_count = 0; +} + WL_EXPORT struct weston_pointer * -weston_pointer_create(void) +weston_pointer_create(struct weston_seat *seat) { struct weston_pointer *pointer; @@ -378,10 +449,15 @@ weston_pointer_create(void) wl_list_init(&pointer->resource_list); wl_list_init(&pointer->focus_resource_list); - pointer->default_grab.interface = &default_pointer_grab_interface; + weston_pointer_set_default_grab(pointer, + seat->compositor->default_pointer_grab); + wl_list_init(&pointer->focus_resource_listener.link); + pointer->focus_resource_listener.notify = pointer_focus_resource_destroyed; pointer->default_grab.pointer = pointer; pointer->grab = &pointer->default_grab; + wl_signal_init(&pointer->motion_signal); wl_signal_init(&pointer->focus_signal); + wl_list_init(&pointer->focus_view_listener.link); pointer->sprite_destroy_listener.notify = pointer_handle_sprite_destroy; @@ -400,9 +476,22 @@ weston_pointer_destroy(struct weston_pointer *pointer) /* XXX: What about pointer->resource_list? */ + wl_list_remove(&pointer->focus_resource_listener.link); + wl_list_remove(&pointer->focus_view_listener.link); free(pointer); } +void +weston_pointer_set_default_grab(struct weston_pointer *pointer, + const struct weston_pointer_grab_interface *interface) +{ + if (interface) + pointer->default_grab.interface = interface; + else + pointer->default_grab.interface = + &default_pointer_grab_interface; +} + WL_EXPORT struct weston_keyboard * weston_keyboard_create(void) { @@ -414,6 +503,8 @@ weston_keyboard_create(void) wl_list_init(&keyboard->resource_list); wl_list_init(&keyboard->focus_resource_list); + wl_list_init(&keyboard->focus_resource_listener.link); + keyboard->focus_resource_listener.notify = keyboard_focus_resource_destroyed; wl_array_init(&keyboard->keys); keyboard->default_grab.interface = &default_keyboard_grab_interface; keyboard->default_grab.keyboard = keyboard; @@ -423,15 +514,36 @@ weston_keyboard_create(void) return keyboard; } +static void +weston_xkb_info_destroy(struct weston_xkb_info *xkb_info); + WL_EXPORT void weston_keyboard_destroy(struct weston_keyboard *keyboard) { /* XXX: What about keyboard->resource_list? */ +#ifdef ENABLE_XKBCOMMON + if (keyboard->seat->compositor->use_xkbcommon) { + if (keyboard->xkb_state.state != NULL) + xkb_state_unref(keyboard->xkb_state.state); + if (keyboard->xkb_info) + weston_xkb_info_destroy(keyboard->xkb_info); + if (keyboard->pending_keymap) + xkb_keymap_unref(keyboard->pending_keymap); + } +#endif + wl_array_release(&keyboard->keys); + wl_list_remove(&keyboard->focus_resource_listener.link); free(keyboard); } +static void +weston_touch_reset_state(struct weston_touch *touch) +{ + touch->num_tp = 0; +} + WL_EXPORT struct weston_touch * weston_touch_create(void) { @@ -443,6 +555,10 @@ weston_touch_create(void) wl_list_init(&touch->resource_list); wl_list_init(&touch->focus_resource_list); + wl_list_init(&touch->focus_view_listener.link); + touch->focus_view_listener.notify = touch_focus_view_destroyed; + wl_list_init(&touch->focus_resource_listener.link); + touch->focus_resource_listener.notify = touch_focus_resource_destroyed; touch->default_grab.interface = &default_touch_grab_interface; touch->default_grab.touch = touch; touch->grab = &touch->default_grab; @@ -456,6 +572,8 @@ weston_touch_destroy(struct weston_touch *touch) { /* XXX: What about touch->resource_list? */ + wl_list_remove(&touch->focus_view_listener.link); + wl_list_remove(&touch->focus_resource_listener.link); free(touch); } @@ -479,7 +597,7 @@ seat_send_updated_caps(struct weston_seat *seat) WL_EXPORT void weston_pointer_set_focus(struct weston_pointer *pointer, - struct weston_surface *surface, + struct weston_view *view, wl_fixed_t sx, wl_fixed_t sy) { struct weston_keyboard *kbd = pointer->seat->keyboard; @@ -487,27 +605,33 @@ weston_pointer_set_focus(struct weston_pointer *pointer, struct wl_display *display = pointer->seat->compositor->wl_display; uint32_t serial; struct wl_list *focus_resource_list; + int different_surface = 0; + + if ((!pointer->focus && view) || + (pointer->focus && !view) || + (pointer->focus && pointer->focus->surface != view->surface)) + different_surface = 1; focus_resource_list = &pointer->focus_resource_list; - if (!wl_list_empty(focus_resource_list) && pointer->focus != surface) { + if (!wl_list_empty(focus_resource_list) && different_surface) { serial = wl_display_next_serial(display); wl_resource_for_each(resource, focus_resource_list) { wl_pointer_send_leave(resource, serial, - pointer->focus->resource); + pointer->focus->surface->resource); } move_resources(&pointer->resource_list, focus_resource_list); } - if (find_resource_for_surface(&pointer->resource_list, surface) && - pointer->focus != surface) { + if (find_resource_for_view(&pointer->resource_list, view) && + different_surface) { struct wl_client *surface_client = - wl_resource_get_client(surface->resource); + wl_resource_get_client(view->surface->resource); serial = wl_display_next_serial(display); - if (kbd && kbd->focus != pointer->focus) + if (kbd && kbd->focus != view->surface) send_modifiers_to_client_in_list(surface_client, &kbd->resource_list, serial, @@ -520,14 +644,25 @@ weston_pointer_set_focus(struct weston_pointer *pointer, wl_resource_for_each(resource, focus_resource_list) { wl_pointer_send_enter(resource, serial, - surface->resource, + view->surface->resource, sx, sy); } pointer->focus_serial = serial; } - pointer->focus = surface; + wl_list_remove(&pointer->focus_view_listener.link); + wl_list_init(&pointer->focus_view_listener.link); + wl_list_remove(&pointer->focus_resource_listener.link); + wl_list_init(&pointer->focus_resource_listener.link); + if (view) + wl_signal_add(&view->destroy_signal, &pointer->focus_view_listener); + if (view && view->surface->resource) + wl_resource_add_destroy_listener(view->surface->resource, + &pointer->focus_resource_listener); + + pointer->focus = view; + pointer->focus_view_listener.notify = pointer_focus_view_destroyed; wl_signal_emit(&pointer->focus_signal, pointer); } @@ -584,6 +719,12 @@ weston_keyboard_set_focus(struct weston_keyboard *keyboard, keyboard->focus_serial = serial; } + wl_list_remove(&keyboard->focus_resource_listener.link); + wl_list_init(&keyboard->focus_resource_listener.link); + if (surface && surface->resource) + wl_resource_add_destroy_listener(surface->resource, + &keyboard->focus_resource_listener); + keyboard->focus = surface; wl_signal_emit(&keyboard->focus_signal, keyboard); } @@ -651,6 +792,28 @@ weston_touch_cancel_grab(struct weston_touch *touch) touch->grab->interface->cancel(touch->grab); } +static void +weston_pointer_clamp_for_output(struct weston_pointer *pointer, + struct weston_output *output, + wl_fixed_t *fx, wl_fixed_t *fy) +{ + int x, y; + + x = wl_fixed_to_int(*fx); + y = wl_fixed_to_int(*fy); + + if (x < output->x) + *fx = wl_fixed_from_int(output->x); + else if (x >= output->x + output->width) + *fx = wl_fixed_from_int(output->x + + output->width - 1); + if (y < output->y) + *fy = wl_fixed_from_int(output->y); + else if (y >= output->y + output->height) + *fy = wl_fixed_from_int(output->y + + output->height - 1); +} + WL_EXPORT void weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t *fy) { @@ -677,27 +840,14 @@ weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t if (!prev) prev = pointer->seat->output; - if (prev && !valid) { - if (x < prev->x) - *fx = wl_fixed_from_int(prev->x); - else if (x >= prev->x + prev->width) - *fx = wl_fixed_from_int(prev->x + - prev->width - 1); - if (y < prev->y) - *fy = wl_fixed_from_int(prev->y); - else if (y >= prev->y + prev->height) - *fy = wl_fixed_from_int(prev->y + - prev->height - 1); - } + if (prev && !valid) + weston_pointer_clamp_for_output(pointer, prev, fx, fy); } /* Takes absolute values */ -static void -move_pointer(struct weston_seat *seat, wl_fixed_t x, wl_fixed_t y) +WL_EXPORT void +weston_pointer_move(struct weston_pointer *pointer, wl_fixed_t x, wl_fixed_t y) { - struct weston_compositor *ec = seat->compositor; - struct weston_pointer *pointer = seat->pointer; - struct weston_output *output; int32_t ix, iy; weston_pointer_clamp (pointer, &x, &y); @@ -708,18 +858,54 @@ move_pointer(struct weston_seat *seat, wl_fixed_t x, wl_fixed_t y) ix = wl_fixed_to_int(x); iy = wl_fixed_to_int(y); - wl_list_for_each(output, &ec->output_list, link) - if (output->zoom.active && - pixman_region32_contains_point(&output->region, - ix, iy, NULL)) - weston_output_update_zoom(output, ZOOM_FOCUS_POINTER); - if (pointer->sprite) { - weston_surface_set_position(pointer->sprite, - ix - pointer->hotspot_x, - iy - pointer->hotspot_y); - weston_surface_schedule_repaint(pointer->sprite); + weston_view_set_position(pointer->sprite, + ix - pointer->hotspot_x, + iy - pointer->hotspot_y); + weston_view_schedule_repaint(pointer->sprite); } + + pointer->grab->interface->focus(pointer->grab); + wl_signal_emit(&pointer->motion_signal, pointer); +} + +/** Verify if the pointer is in a valid position and move it if it isn't. + */ +WL_EXPORT void +weston_pointer_verify(struct weston_pointer *pointer) +{ + struct weston_compositor *ec = pointer->seat->compositor; + struct weston_output *output, *closest = NULL; + int x, y, distance, min = INT_MAX; + wl_fixed_t fx, fy; + + x = wl_fixed_to_int(pointer->x); + y = wl_fixed_to_int(pointer->y); + + wl_list_for_each(output, &ec->output_list, link) { + if (pixman_region32_contains_point(&output->region, + x, y, NULL)) + return; + + /* Aproximante the distance from the pointer to the center of + * the output. */ + distance = abs(output->x + output->width / 2 - x) + + abs(output->y + output->height / 2 - y); + if (distance < min) { + min = distance; + closest = output; + } + } + + /* Nothing to do if there's no output left. */ + if (!closest) + return; + + fx = pointer->x; + fy = pointer->y; + + weston_pointer_clamp_for_output(pointer, closest, &fx, &fy); + weston_pointer_move(pointer, fx, fy); } WL_EXPORT void @@ -730,11 +916,43 @@ notify_motion(struct weston_seat *seat, struct weston_pointer *pointer = seat->pointer; weston_compositor_wake(ec); + pointer->grab->interface->motion(pointer->grab, time, pointer->x + dx, pointer->y + dy); +} - move_pointer(seat, pointer->x + dx, pointer->y + dy); +static void +run_modifier_bindings(struct weston_seat *seat, uint32_t old, uint32_t new) +{ + struct weston_compositor *compositor = seat->compositor; + struct weston_keyboard *keyboard = seat->keyboard; + uint32_t diff; + unsigned int i; + struct { + uint32_t xkb; + enum weston_keyboard_modifier weston; + } mods[] = { + { keyboard->xkb_info->ctrl_mod, MODIFIER_CTRL }, + { keyboard->xkb_info->alt_mod, MODIFIER_ALT }, + { keyboard->xkb_info->super_mod, MODIFIER_SUPER }, + { keyboard->xkb_info->shift_mod, MODIFIER_SHIFT }, + }; + + diff = new & ~old; + for (i = 0; i < ARRAY_LENGTH(mods); i++) { + if (diff & (1 << mods[i].xkb)) + weston_compositor_run_modifier_binding(compositor, + seat, + mods[i].weston, + WL_KEYBOARD_KEY_STATE_PRESSED); + } - pointer->grab->interface->focus(pointer->grab); - pointer->grab->interface->motion(pointer->grab, time); + diff = old & ~new; + for (i = 0; i < ARRAY_LENGTH(mods); i++) { + if (diff & (1 << mods[i].xkb)) + weston_compositor_run_modifier_binding(compositor, + seat, + mods[i].weston, + WL_KEYBOARD_KEY_STATE_RELEASED); + } } WL_EXPORT void @@ -745,11 +963,7 @@ notify_motion_absolute(struct weston_seat *seat, struct weston_pointer *pointer = seat->pointer; weston_compositor_wake(ec); - - move_pointer(seat, x, y); - - pointer->grab->interface->focus(pointer->grab); - pointer->grab->interface->motion(pointer->grab, time); + pointer->grab->interface->motion(pointer->grab, time, x, y); } WL_EXPORT void @@ -845,13 +1059,13 @@ notify_modifiers(struct weston_seat *seat, uint32_t serial) /* Serialize and update our internal state, checking to see if it's * different to the previous state. */ - mods_depressed = xkb_state_serialize_mods(seat->xkb_state.state, + mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state, XKB_STATE_DEPRESSED); - mods_latched = xkb_state_serialize_mods(seat->xkb_state.state, + mods_latched = xkb_state_serialize_mods(keyboard->xkb_state.state, XKB_STATE_LATCHED); - mods_locked = xkb_state_serialize_mods(seat->xkb_state.state, + mods_locked = xkb_state_serialize_mods(keyboard->xkb_state.state, XKB_STATE_LOCKED); - group = xkb_state_serialize_group(seat->xkb_state.state, + group = xkb_state_serialize_group(keyboard->xkb_state.state, XKB_STATE_EFFECTIVE); if (mods_depressed != seat->keyboard->modifiers.mods_depressed || @@ -860,6 +1074,9 @@ notify_modifiers(struct weston_seat *seat, uint32_t serial) group != seat->keyboard->modifiers.group) changed = 1; + run_modifier_bindings(seat, seat->keyboard->modifiers.mods_depressed, + mods_depressed); + seat->keyboard->modifiers.mods_depressed = mods_depressed; seat->keyboard->modifiers.mods_latched = mods_latched; seat->keyboard->modifiers.mods_locked = mods_locked; @@ -868,28 +1085,28 @@ notify_modifiers(struct weston_seat *seat, uint32_t serial) /* And update the modifier_state for bindings. */ mods_lookup = mods_depressed | mods_latched; seat->modifier_state = 0; - if (mods_lookup & (1 << seat->xkb_info->ctrl_mod)) + if (mods_lookup & (1 << keyboard->xkb_info->ctrl_mod)) seat->modifier_state |= MODIFIER_CTRL; - if (mods_lookup & (1 << seat->xkb_info->alt_mod)) + if (mods_lookup & (1 << keyboard->xkb_info->alt_mod)) seat->modifier_state |= MODIFIER_ALT; - if (mods_lookup & (1 << seat->xkb_info->super_mod)) + if (mods_lookup & (1 << keyboard->xkb_info->super_mod)) seat->modifier_state |= MODIFIER_SUPER; - if (mods_lookup & (1 << seat->xkb_info->shift_mod)) + if (mods_lookup & (1 << keyboard->xkb_info->shift_mod)) seat->modifier_state |= MODIFIER_SHIFT; /* Finally, notify the compositor that LEDs have changed. */ - if (xkb_state_led_index_is_active(seat->xkb_state.state, - seat->xkb_info->num_led)) + if (xkb_state_led_index_is_active(keyboard->xkb_state.state, + keyboard->xkb_info->num_led)) leds |= LED_NUM_LOCK; - if (xkb_state_led_index_is_active(seat->xkb_state.state, - seat->xkb_info->caps_led)) + if (xkb_state_led_index_is_active(keyboard->xkb_state.state, + keyboard->xkb_info->caps_led)) leds |= LED_CAPS_LOCK; - if (xkb_state_led_index_is_active(seat->xkb_state.state, - seat->xkb_info->scroll_led)) + if (xkb_state_led_index_is_active(keyboard->xkb_state.state, + keyboard->xkb_info->scroll_led)) leds |= LED_SCROLL_LOCK; - if (leds != seat->xkb_state.leds && seat->led_update) + if (leds != keyboard->xkb_state.leds && seat->led_update) seat->led_update(seat, leds); - seat->xkb_state.leds = leds; + keyboard->xkb_state.leds = leds; if (changed) { grab->interface->modifiers(grab, @@ -905,6 +1122,7 @@ static void update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key, enum wl_keyboard_key_state state) { + struct weston_keyboard *keyboard = seat->keyboard; enum xkb_key_direction direction; /* Keyboard modifiers don't exist in raw keyboard mode */ @@ -918,10 +1136,91 @@ update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key, /* Offset the keycode by 8, as the evdev XKB rules reflect X's * broken keycode system, which starts at 8. */ - xkb_state_update_key(seat->xkb_state.state, key + 8, direction); + xkb_state_update_key(keyboard->xkb_state.state, key + 8, direction); notify_modifiers(seat, serial); } + +static void +send_keymap(struct wl_resource *resource, struct weston_xkb_info *xkb_info) +{ + wl_keyboard_send_keymap(resource, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + xkb_info->keymap_fd, + xkb_info->keymap_size); +} + +static void +send_modifiers(struct wl_resource *resource, uint32_t serial, struct weston_keyboard *keyboard) +{ + wl_keyboard_send_modifiers(resource, serial, + keyboard->modifiers.mods_depressed, + keyboard->modifiers.mods_latched, + keyboard->modifiers.mods_locked, + keyboard->modifiers.group); +} + +static struct weston_xkb_info * +weston_xkb_info_create(struct xkb_keymap *keymap); + +static void +update_keymap(struct weston_seat *seat) +{ + struct weston_keyboard *keyboard = seat->keyboard; + struct wl_resource *resource; + struct weston_xkb_info *xkb_info; + struct xkb_state *state; + xkb_mod_mask_t latched_mods; + xkb_mod_mask_t locked_mods; + + xkb_info = weston_xkb_info_create(keyboard->pending_keymap); + + xkb_keymap_unref(keyboard->pending_keymap); + keyboard->pending_keymap = NULL; + + if (!xkb_info) { + weston_log("failed to create XKB info\n"); + return; + } + + state = xkb_state_new(xkb_info->keymap); + if (!state) { + weston_log("failed to initialise XKB state\n"); + weston_xkb_info_destroy(xkb_info); + return; + } + + latched_mods = xkb_state_serialize_mods(keyboard->xkb_state.state, + XKB_STATE_MODS_LATCHED); + locked_mods = xkb_state_serialize_mods(keyboard->xkb_state.state, + XKB_STATE_MODS_LOCKED); + xkb_state_update_mask(state, + 0, /* depressed */ + latched_mods, + locked_mods, + 0, 0, 0); + + weston_xkb_info_destroy(keyboard->xkb_info); + keyboard->xkb_info = xkb_info; + + xkb_state_unref(keyboard->xkb_state.state); + keyboard->xkb_state.state = state; + + wl_resource_for_each(resource, &seat->keyboard->resource_list) + send_keymap(resource, xkb_info); + wl_resource_for_each(resource, &seat->keyboard->focus_resource_list) + send_keymap(resource, xkb_info); + + notify_modifiers(seat, wl_display_next_serial(seat->compositor->wl_display)); + + if (!latched_mods && !locked_mods) + return; + + wl_resource_for_each(resource, &seat->keyboard->resource_list) + send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), seat->keyboard); + wl_resource_for_each(resource, &seat->keyboard->focus_resource_list) + send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), seat->keyboard); +} #else WL_EXPORT void notify_modifiers(struct weston_seat *seat, uint32_t serial) @@ -933,6 +1232,11 @@ update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key, enum wl_keyboard_key_state state) { } + +static void +update_keymap(struct weston_seat *seat) +{ +} #endif WL_EXPORT void @@ -942,8 +1246,7 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key, { struct weston_compositor *compositor = seat->compositor; struct weston_keyboard *keyboard = seat->keyboard; - struct weston_surface *focus = - (struct weston_surface *) keyboard->focus; + struct weston_surface *focus = keyboard->focus; struct weston_keyboard_grab *grab = keyboard->grab; uint32_t serial = wl_display_next_serial(compositor->wl_display); uint32_t *k, *end; @@ -983,6 +1286,10 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key, grab->interface->key(grab, time, key, state); + if (keyboard->pending_keymap && + keyboard->keys.size == 0) + update_keymap(seat); + if (update_state == STATE_UPDATE_AUTOMATIC) { update_modifier_state(seat, wl_display_get_serial(compositor->wl_display), @@ -995,13 +1302,9 @@ WL_EXPORT void notify_pointer_focus(struct weston_seat *seat, struct weston_output *output, wl_fixed_t x, wl_fixed_t y) { - struct weston_compositor *compositor = seat->compositor; - if (output) { - move_pointer(seat, x, y); - compositor->focus = 1; + weston_pointer_move(seat->pointer, x, y); } else { - compositor->focus = 0; /* FIXME: We should call weston_pointer_set_focus(seat, * NULL) here, but somehow that breaks re-entry... */ } @@ -1077,31 +1380,44 @@ notify_keyboard_focus_out(struct weston_seat *seat) weston_keyboard_set_focus(keyboard, NULL); weston_keyboard_cancel_grab(keyboard); + if (seat->pointer) + weston_pointer_cancel_grab(seat->pointer); } WL_EXPORT void -weston_touch_set_focus(struct weston_seat *seat, struct weston_surface *surface) +weston_touch_set_focus(struct weston_seat *seat, struct weston_view *view) { struct wl_list *focus_resource_list; focus_resource_list = &seat->touch->focus_resource_list; - if (seat->touch->focus == surface) + if (view && seat->touch->focus && + seat->touch->focus->surface == view->surface) { + seat->touch->focus = view; return; + } + + wl_list_remove(&seat->touch->focus_resource_listener.link); + wl_list_init(&seat->touch->focus_resource_listener.link); + wl_list_remove(&seat->touch->focus_view_listener.link); + wl_list_init(&seat->touch->focus_view_listener.link); if (!wl_list_empty(focus_resource_list)) { move_resources(&seat->touch->resource_list, focus_resource_list); } - if (surface) { + if (view) { struct wl_client *surface_client = - wl_resource_get_client(surface->resource); + wl_resource_get_client(view->surface->resource); move_resources_for_client(focus_resource_list, &seat->touch->resource_list, surface_client); + wl_resource_add_destroy_listener(view->surface->resource, + &seat->touch->focus_resource_listener); + wl_signal_add(&view->destroy_signal, &seat->touch->focus_view_listener); } - seat->touch->focus = surface; + seat->touch->focus = view; } /** @@ -1119,7 +1435,7 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id, struct weston_compositor *ec = seat->compositor; struct weston_touch *touch = seat->touch; struct weston_touch_grab *grab = touch->grab; - struct weston_surface *es; + struct weston_view *ev; wl_fixed_t sx, sy; /* Update grab's global coordinates. */ @@ -1132,28 +1448,28 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id, case WL_TOUCH_DOWN: weston_compositor_idle_inhibit(ec); - seat->num_tp++; + touch->num_tp++; - /* the first finger down picks the surface, and all further go - * to that surface for the remainder of the touch session i.e. + /* the first finger down picks the view, and all further go + * to that view for the remainder of the touch session i.e. * until all touch points are up again. */ - if (seat->num_tp == 1) { - es = weston_compositor_pick_surface(ec, x, y, &sx, &sy); - weston_touch_set_focus(seat, es); + if (touch->num_tp == 1) { + ev = weston_compositor_pick_view(ec, x, y, &sx, &sy); + weston_touch_set_focus(seat, ev); } else if (touch->focus) { - es = (struct weston_surface *) touch->focus; - weston_surface_from_global_fixed(es, x, y, &sx, &sy); + ev = touch->focus; + weston_view_from_global_fixed(ev, x, y, &sx, &sy); } else { /* Unexpected condition: We have non-initial touch but * there is no focused surface. */ weston_log("touch event received with %d points down" - "but no surface focused\n", seat->num_tp); + "but no surface focused\n", touch->num_tp); return; } grab->interface->down(grab, time, touch_id, sx, sy); - if (seat->num_tp == 1) { + if (touch->num_tp == 1) { touch->grab_serial = wl_display_get_serial(ec->wl_display); touch->grab_touch_id = touch_id; @@ -1164,19 +1480,27 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id, break; case WL_TOUCH_MOTION: - es = (struct weston_surface *) touch->focus; - if (!es) + ev = touch->focus; + if (!ev) break; - weston_surface_from_global_fixed(es, x, y, &sx, &sy); + weston_view_from_global_fixed(ev, x, y, &sx, &sy); grab->interface->motion(grab, time, touch_id, sx, sy); break; case WL_TOUCH_UP: + if (touch->num_tp == 0) { + /* This can happen if we start out with one or + * more fingers on the touch screen, in which + * case we didn't get the corresponding down + * event. */ + weston_log("unmatched touch up event\n"); + break; + } weston_compositor_idle_release(ec); - seat->num_tp--; + touch->num_tp--; grab->interface->up(grab, time, touch_id); - if (seat->num_tp == 0) + if (touch->num_tp == 0) weston_touch_set_focus(seat, NULL); break; } @@ -1186,15 +1510,15 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id, static void pointer_cursor_surface_configure(struct weston_surface *es, - int32_t dx, int32_t dy, int32_t width, int32_t height) + int32_t dx, int32_t dy) { struct weston_pointer *pointer = es->configure_private; int x, y; - if (width == 0) + if (es->width == 0) return; - assert(es == pointer->sprite); + assert(es == pointer->sprite->surface); pointer->hotspot_x -= dx; pointer->hotspot_y -= dy; @@ -1202,14 +1526,14 @@ pointer_cursor_surface_configure(struct weston_surface *es, x = wl_fixed_to_int(pointer->x) - pointer->hotspot_x; y = wl_fixed_to_int(pointer->y) - pointer->hotspot_y; - weston_surface_configure(pointer->sprite, x, y, width, height); + weston_view_set_position(pointer->sprite, x, y); empty_region(&es->pending.input); if (!weston_surface_is_mapped(es)) { - wl_list_insert(&es->compositor->cursor_layer.surface_list, - &es->layer_link); - weston_surface_update_transform(es); + wl_list_insert(&es->compositor->cursor_layer.view_list, + &pointer->sprite->layer_link); + weston_view_update_transform(pointer->sprite); } } @@ -1226,17 +1550,17 @@ pointer_set_cursor(struct wl_client *client, struct wl_resource *resource, if (pointer->focus == NULL) return; - /* pointer->focus->resource can be NULL. Surfaces like the + /* pointer->focus->surface->resource can be NULL. Surfaces like the black_surface used in shell.c for fullscreen don't have a resource, but can still have focus */ - if (pointer->focus->resource == NULL) + if (pointer->focus->surface->resource == NULL) return; - if (wl_resource_get_client(pointer->focus->resource) != client) + if (wl_resource_get_client(pointer->focus->surface->resource) != client) return; if (pointer->focus_serial - serial > UINT32_MAX / 2) return; - if (surface && surface != pointer->sprite) { + if (surface && pointer->sprite && surface != pointer->sprite->surface) { if (surface->configure) { wl_resource_post_error(surface->resource, WL_DISPLAY_ERROR_INVALID_OBJECT, @@ -1257,13 +1581,12 @@ pointer_set_cursor(struct wl_client *client, struct wl_resource *resource, surface->configure = pointer_cursor_surface_configure; surface->configure_private = pointer; - pointer->sprite = surface; + pointer->sprite = weston_view_create(surface); pointer->hotspot_x = x; pointer->hotspot_y = y; if (surface->buffer_ref.buffer) - pointer_cursor_surface_configure(surface, 0, 0, weston_surface_buffer_width(surface), - weston_surface_buffer_height(surface)); + pointer_cursor_surface_configure(surface, 0, 0); } static void @@ -1301,24 +1624,21 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource, wl_resource_set_implementation(cr, &pointer_interface, seat->pointer, unbind_resource); - if (seat->pointer->focus && seat->pointer->focus->resource && - wl_resource_get_client(seat->pointer->focus->resource) == client) { - struct weston_surface *surface; + if (seat->pointer->focus && seat->pointer->focus->surface->resource && + wl_resource_get_client(seat->pointer->focus->surface->resource) == client) { wl_fixed_t sx, sy; - surface = (struct weston_surface *) seat->pointer->focus; - weston_surface_from_global_fixed(surface, - seat->pointer->x, - seat->pointer->y, - &sx, - &sy); + weston_view_from_global_fixed(seat->pointer->focus, + seat->pointer->x, + seat->pointer->y, + &sx, &sy); wl_list_remove(wl_resource_get_link(cr)); wl_list_insert(&seat->pointer->focus_resource_list, wl_resource_get_link(cr)); wl_pointer_send_enter(cr, seat->pointer->focus_serial, - surface->resource, + seat->pointer->focus->surface->resource, sx, sy); } } @@ -1339,12 +1659,14 @@ should_send_modifiers_to_client(struct weston_seat *seat, { if (seat->keyboard && seat->keyboard->focus && + seat->keyboard->focus->resource && wl_resource_get_client(seat->keyboard->focus->resource) == client) return 1; if (seat->pointer && seat->pointer->focus && - wl_resource_get_client(seat->pointer->focus->resource) == client) + seat->pointer->focus->surface->resource && + wl_resource_get_client(seat->pointer->focus->surface->resource) == client) return 1; return 0; @@ -1355,6 +1677,7 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource, uint32_t id) { struct weston_seat *seat = wl_resource_get_user_data(resource); + struct weston_keyboard *keyboard = seat->keyboard; struct wl_resource *cr; if (!seat->keyboard) @@ -1376,8 +1699,8 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource, if (seat->compositor->use_xkbcommon) { wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, - seat->xkb_info->keymap_fd, - seat->xkb_info->keymap_size); + keyboard->xkb_info->keymap_fd, + keyboard->xkb_info->keymap_size); } else { int null_fd = open("/dev/null", O_RDONLY); wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP, @@ -1441,7 +1764,7 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource, } if (seat->touch->focus && - wl_resource_get_client(seat->touch->focus->resource) == client) { + wl_resource_get_client(seat->touch->focus->surface->resource) == client) { wl_list_insert(&seat->touch->resource_list, wl_resource_get_link(cr)); } else { @@ -1639,6 +1962,7 @@ weston_compositor_build_global_keymap(struct weston_compositor *ec) } ec->xkb_info = weston_xkb_info_create(keymap); + xkb_keymap_unref(keymap); if (ec->xkb_info == NULL) return -1; @@ -1658,6 +1982,24 @@ weston_compositor_xkb_destroy(struct weston_compositor *ec) } #endif +WL_EXPORT void +weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap) +{ + if (!seat->keyboard || !keymap) + return; + +#ifdef ENABLE_XKBCOMMON + if (!seat->compositor->use_xkbcommon) + return; + + xkb_keymap_unref(seat->keyboard->pending_keymap); + seat->keyboard->pending_keymap = xkb_keymap_ref(keymap); + + if (seat->keyboard->keys.size == 0) + update_keymap(seat); +#endif +} + WL_EXPORT int weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap) { @@ -1670,44 +2012,67 @@ weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap) return 0; } + keyboard = weston_keyboard_create(); + if (keyboard == NULL) { + weston_log("failed to allocate weston keyboard struct\n"); + return -1; + } + + seat->keyboard = keyboard; + seat->keyboard_device_count = 1; + keyboard->seat = seat; + #ifdef ENABLE_XKBCOMMON if (seat->compositor->use_xkbcommon) { if (keymap != NULL) { - seat->xkb_info = weston_xkb_info_create(keymap); - if (seat->xkb_info == NULL) + keyboard->xkb_info = weston_xkb_info_create(keymap); + if (keyboard->xkb_info == NULL) return -1; } else { if (weston_compositor_build_global_keymap(seat->compositor) < 0) return -1; - seat->xkb_info = seat->compositor->xkb_info; - seat->xkb_info->ref_count++; + keyboard->xkb_info = seat->compositor->xkb_info; + keyboard->xkb_info->ref_count++; } - seat->xkb_state.state = xkb_state_new(seat->xkb_info->keymap); - if (seat->xkb_state.state == NULL) { + keyboard->xkb_state.state = xkb_state_new(keyboard->xkb_info->keymap); + if (keyboard->xkb_state.state == NULL) { weston_log("failed to initialise XKB state\n"); return -1; } - seat->xkb_state.leds = 0; + keyboard->xkb_state.leds = 0; } #endif - keyboard = weston_keyboard_create(); - if (keyboard == NULL) { - weston_log("failed to allocate weston keyboard struct\n"); - return -1; - } - - seat->keyboard = keyboard; - seat->keyboard_device_count = 1; - keyboard->seat = seat; - seat_send_updated_caps(seat); return 0; } +static void +weston_keyboard_reset_state(struct weston_keyboard *keyboard) +{ + struct weston_seat *seat = keyboard->seat; + struct xkb_state *state; + +#ifdef ENABLE_XKBCOMMON + if (seat->compositor->use_xkbcommon) { + state = xkb_state_new(keyboard->xkb_info->keymap); + if (!state) { + weston_log("failed to reset XKB state\n"); + return; + } + xkb_state_unref(keyboard->xkb_state.state); + keyboard->xkb_state.state = state; + + keyboard->xkb_state.leds = 0; + } +#endif + + seat->modifier_state = 0; +} + WL_EXPORT void weston_seat_release_keyboard(struct weston_seat *seat) { @@ -1715,6 +2080,7 @@ weston_seat_release_keyboard(struct weston_seat *seat) if (seat->keyboard_device_count == 0) { weston_keyboard_set_focus(seat->keyboard, NULL); weston_keyboard_cancel_grab(seat->keyboard); + weston_keyboard_reset_state(seat->keyboard); seat_send_updated_caps(seat); } } @@ -1731,7 +2097,7 @@ weston_seat_init_pointer(struct weston_seat *seat) return; } - pointer = weston_pointer_create(); + pointer = weston_pointer_create(seat); if (pointer == NULL) return; @@ -1757,6 +2123,7 @@ weston_seat_release_pointer(struct weston_seat *seat) if (pointer->sprite) pointer_unmap_sprite(pointer); + weston_pointer_reset_state(pointer); seat_send_updated_caps(seat); } } @@ -1791,6 +2158,7 @@ weston_seat_release_touch(struct weston_seat *seat) if (seat->touch_device_count == 0) { weston_touch_set_focus(seat, NULL); weston_touch_cancel_grab(seat->touch); + weston_touch_reset_state(seat->touch); seat_send_updated_caps(seat); } } @@ -1812,7 +2180,6 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec, seat->compositor = ec; seat->modifier_state = 0; - seat->num_tp = 0; seat->seat_name = strdup(seat_name); wl_list_insert(ec->seat_list.prev, &seat->link); @@ -1827,15 +2194,6 @@ weston_seat_release(struct weston_seat *seat) { wl_list_remove(&seat->link); -#ifdef ENABLE_XKBCOMMON - if (seat->compositor->use_xkbcommon) { - if (seat->xkb_state.state != NULL) - xkb_state_unref(seat->xkb_state.state); - if (seat->xkb_info) - weston_xkb_info_destroy(seat->xkb_info); - } -#endif - if (seat->pointer) weston_pointer_destroy(seat->pointer); if (seat->keyboard) |