| /* |
| * Copyright © 2011-2012 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial |
| * portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| |
| #include "config.h" |
| |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <linux/input.h> |
| |
| #include "compositor.h" |
| #include "shared/helpers.h" |
| #include "shared/timespec-util.h" |
| |
| struct weston_binding { |
| uint32_t key; |
| uint32_t button; |
| uint32_t axis; |
| uint32_t modifier; |
| void *handler; |
| void *data; |
| struct wl_list link; |
| }; |
| |
| static struct weston_binding * |
| weston_compositor_add_binding(struct weston_compositor *compositor, |
| uint32_t key, uint32_t button, uint32_t axis, |
| uint32_t modifier, void *handler, void *data) |
| { |
| struct weston_binding *binding; |
| |
| binding = malloc(sizeof *binding); |
| if (binding == NULL) |
| return NULL; |
| |
| binding->key = key; |
| binding->button = button; |
| binding->axis = axis; |
| binding->modifier = modifier; |
| binding->handler = handler; |
| binding->data = data; |
| |
| return binding; |
| } |
| |
| WL_EXPORT struct weston_binding * |
| weston_compositor_add_key_binding(struct weston_compositor *compositor, |
| uint32_t key, uint32_t modifier, |
| weston_key_binding_handler_t handler, |
| void *data) |
| { |
| struct weston_binding *binding; |
| |
| binding = weston_compositor_add_binding(compositor, key, 0, 0, |
| modifier, handler, data); |
| if (binding == NULL) |
| return NULL; |
| |
| wl_list_insert(compositor->key_binding_list.prev, &binding->link); |
| |
| return binding; |
| } |
| |
| WL_EXPORT struct weston_binding * |
| weston_compositor_add_modifier_binding(struct weston_compositor *compositor, |
| uint32_t modifier, |
| weston_modifier_binding_handler_t handler, |
| void *data) |
| { |
| struct weston_binding *binding; |
| |
| binding = weston_compositor_add_binding(compositor, 0, 0, 0, |
| modifier, handler, data); |
| if (binding == NULL) |
| return NULL; |
| |
| wl_list_insert(compositor->modifier_binding_list.prev, &binding->link); |
| |
| return binding; |
| } |
| |
| WL_EXPORT struct weston_binding * |
| weston_compositor_add_button_binding(struct weston_compositor *compositor, |
| uint32_t button, uint32_t modifier, |
| weston_button_binding_handler_t handler, |
| void *data) |
| { |
| struct weston_binding *binding; |
| |
| binding = weston_compositor_add_binding(compositor, 0, button, 0, |
| modifier, handler, data); |
| if (binding == NULL) |
| return NULL; |
| |
| wl_list_insert(compositor->button_binding_list.prev, &binding->link); |
| |
| return binding; |
| } |
| |
| WL_EXPORT struct weston_binding * |
| weston_compositor_add_touch_binding(struct weston_compositor *compositor, |
| uint32_t modifier, |
| weston_touch_binding_handler_t handler, |
| void *data) |
| { |
| struct weston_binding *binding; |
| |
| binding = weston_compositor_add_binding(compositor, 0, 0, 0, |
| modifier, handler, data); |
| if (binding == NULL) |
| return NULL; |
| |
| wl_list_insert(compositor->touch_binding_list.prev, &binding->link); |
| |
| return binding; |
| } |
| |
| WL_EXPORT struct weston_binding * |
| weston_compositor_add_axis_binding(struct weston_compositor *compositor, |
| uint32_t axis, uint32_t modifier, |
| weston_axis_binding_handler_t handler, |
| void *data) |
| { |
| struct weston_binding *binding; |
| |
| binding = weston_compositor_add_binding(compositor, 0, 0, axis, |
| modifier, handler, data); |
| if (binding == NULL) |
| return NULL; |
| |
| wl_list_insert(compositor->axis_binding_list.prev, &binding->link); |
| |
| return binding; |
| } |
| |
| WL_EXPORT struct weston_binding * |
| weston_compositor_add_debug_binding(struct weston_compositor *compositor, |
| uint32_t key, |
| weston_key_binding_handler_t handler, |
| void *data) |
| { |
| struct weston_binding *binding; |
| |
| binding = weston_compositor_add_binding(compositor, key, 0, 0, 0, |
| handler, data); |
| |
| wl_list_insert(compositor->debug_binding_list.prev, &binding->link); |
| |
| return binding; |
| } |
| |
| WL_EXPORT void |
| weston_binding_destroy(struct weston_binding *binding) |
| { |
| wl_list_remove(&binding->link); |
| free(binding); |
| } |
| |
| void |
| weston_binding_list_destroy_all(struct wl_list *list) |
| { |
| struct weston_binding *binding, *tmp; |
| |
| wl_list_for_each_safe(binding, tmp, list, link) |
| weston_binding_destroy(binding); |
| } |
| |
| struct binding_keyboard_grab { |
| uint32_t key; |
| struct weston_keyboard_grab grab; |
| }; |
| |
| static void |
| binding_key(struct weston_keyboard_grab *grab, |
| const struct timespec *time, uint32_t key, uint32_t state_w) |
| { |
| struct binding_keyboard_grab *b = |
| container_of(grab, struct binding_keyboard_grab, grab); |
| struct wl_resource *resource; |
| enum wl_keyboard_key_state state = state_w; |
| uint32_t serial; |
| struct weston_keyboard *keyboard = grab->keyboard; |
| struct wl_display *display = keyboard->seat->compositor->wl_display; |
| uint32_t msecs; |
| |
| if (key == b->key) { |
| if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { |
| weston_keyboard_end_grab(grab->keyboard); |
| if (keyboard->input_method_resource) |
| keyboard->grab = &keyboard->input_method_grab; |
| free(b); |
| } else { |
| /* Don't send the key press event for the binding key */ |
| return; |
| } |
| } |
| if (!wl_list_empty(&keyboard->focus_resource_list)) { |
| serial = wl_display_next_serial(display); |
| msecs = timespec_to_msec(time); |
| wl_resource_for_each(resource, &keyboard->focus_resource_list) { |
| wl_keyboard_send_key(resource, |
| serial, |
| msecs, |
| key, |
| state); |
| } |
| } |
| } |
| |
| static void |
| binding_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 wl_resource *resource; |
| |
| wl_resource_for_each(resource, &grab->keyboard->focus_resource_list) { |
| wl_keyboard_send_modifiers(resource, serial, mods_depressed, |
| mods_latched, mods_locked, group); |
| } |
| } |
| |
| static void |
| binding_cancel(struct weston_keyboard_grab *grab) |
| { |
| struct binding_keyboard_grab *binding_grab = |
| container_of(grab, struct binding_keyboard_grab, grab); |
| |
| weston_keyboard_end_grab(grab->keyboard); |
| free(binding_grab); |
| } |
| |
| static const struct weston_keyboard_grab_interface binding_grab = { |
| binding_key, |
| binding_modifiers, |
| binding_cancel, |
| }; |
| |
| static void |
| install_binding_grab(struct weston_keyboard *keyboard, |
| const struct timespec *time, uint32_t key, |
| struct weston_surface *focus) |
| { |
| struct binding_keyboard_grab *grab; |
| |
| grab = malloc(sizeof *grab); |
| grab->key = key; |
| grab->grab.interface = &binding_grab; |
| weston_keyboard_start_grab(keyboard, &grab->grab); |
| |
| /* Notify the surface which had the focus before this binding |
| * triggered that we stole a keypress from under it, by forcing |
| * a wl_keyboard leave/enter pair. The enter event will contain |
| * the pressed key in the keys array, so the client will know |
| * the exact state of the keyboard. |
| * If the old focus surface is different than the new one it |
| * means it was changed in the binding handler, so it received |
| * the enter event already. */ |
| if (focus && keyboard->focus == focus) { |
| weston_keyboard_set_focus(keyboard, NULL); |
| weston_keyboard_set_focus(keyboard, focus); |
| } |
| } |
| |
| void |
| weston_compositor_run_key_binding(struct weston_compositor *compositor, |
| struct weston_keyboard *keyboard, |
| const struct timespec *time, uint32_t key, |
| enum wl_keyboard_key_state state) |
| { |
| struct weston_binding *b, *tmp; |
| struct weston_surface *focus; |
| struct weston_seat *seat = keyboard->seat; |
| |
| if (state == WL_KEYBOARD_KEY_STATE_RELEASED) |
| return; |
| |
| /* Invalidate all active modifier bindings. */ |
| wl_list_for_each(b, &compositor->modifier_binding_list, link) |
| b->key = key; |
| |
| wl_list_for_each_safe(b, tmp, &compositor->key_binding_list, link) { |
| if (b->key == key && b->modifier == seat->modifier_state) { |
| weston_key_binding_handler_t handler = b->handler; |
| focus = keyboard->focus; |
| handler(keyboard, time, key, b->data); |
| |
| /* If this was a key binding and it didn't |
| * install a keyboard grab, install one now to |
| * swallow the key press. */ |
| if (keyboard->grab == |
| &keyboard->default_grab) |
| install_binding_grab(keyboard, |
| time, |
| key, |
| focus); |
| } |
| } |
| } |
| |
| void |
| weston_compositor_run_modifier_binding(struct weston_compositor *compositor, |
| struct weston_keyboard *keyboard, |
| enum weston_keyboard_modifier modifier, |
| enum wl_keyboard_key_state state) |
| { |
| struct weston_binding *b, *tmp; |
| |
| if (keyboard->grab != &keyboard->default_grab) |
| return; |
| |
| wl_list_for_each_safe(b, tmp, &compositor->modifier_binding_list, link) { |
| weston_modifier_binding_handler_t handler = b->handler; |
| |
| if (b->modifier != modifier) |
| continue; |
| |
| /* Prime the modifier binding. */ |
| if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { |
| b->key = 0; |
| continue; |
| } |
| /* Ignore the binding if a key was pressed in between. */ |
| else if (b->key != 0) { |
| return; |
| } |
| |
| handler(keyboard, modifier, b->data); |
| } |
| } |
| |
| void |
| weston_compositor_run_button_binding(struct weston_compositor *compositor, |
| struct weston_pointer *pointer, |
| const struct timespec *time, |
| uint32_t button, |
| enum wl_pointer_button_state state) |
| { |
| struct weston_binding *b, *tmp; |
| |
| if (state == WL_POINTER_BUTTON_STATE_RELEASED) |
| return; |
| |
| /* Invalidate all active modifier bindings. */ |
| wl_list_for_each(b, &compositor->modifier_binding_list, link) |
| b->key = button; |
| |
| wl_list_for_each_safe(b, tmp, &compositor->button_binding_list, link) { |
| if (b->button == button && |
| b->modifier == pointer->seat->modifier_state) { |
| weston_button_binding_handler_t handler = b->handler; |
| handler(pointer, time, button, b->data); |
| } |
| } |
| } |
| |
| void |
| weston_compositor_run_touch_binding(struct weston_compositor *compositor, |
| struct weston_touch *touch, |
| const struct timespec *time, |
| int touch_type) |
| { |
| struct weston_binding *b, *tmp; |
| |
| if (touch->num_tp != 1 || touch_type != WL_TOUCH_DOWN) |
| return; |
| |
| wl_list_for_each_safe(b, tmp, &compositor->touch_binding_list, link) { |
| if (b->modifier == touch->seat->modifier_state) { |
| weston_touch_binding_handler_t handler = b->handler; |
| handler(touch, time, b->data); |
| } |
| } |
| } |
| |
| int |
| weston_compositor_run_axis_binding(struct weston_compositor *compositor, |
| struct weston_pointer *pointer, |
| const struct timespec *time, |
| struct weston_pointer_axis_event *event) |
| { |
| struct weston_binding *b, *tmp; |
| |
| /* Invalidate all active modifier bindings. */ |
| wl_list_for_each(b, &compositor->modifier_binding_list, link) |
| b->key = event->axis; |
| |
| wl_list_for_each_safe(b, tmp, &compositor->axis_binding_list, link) { |
| if (b->axis == event->axis && |
| b->modifier == pointer->seat->modifier_state) { |
| weston_axis_binding_handler_t handler = b->handler; |
| handler(pointer, time, event, b->data); |
| return 1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int |
| weston_compositor_run_debug_binding(struct weston_compositor *compositor, |
| struct weston_keyboard *keyboard, |
| const struct timespec *time, uint32_t key, |
| enum wl_keyboard_key_state state) |
| { |
| weston_key_binding_handler_t handler; |
| struct weston_binding *binding, *tmp; |
| int count = 0; |
| |
| wl_list_for_each_safe(binding, tmp, &compositor->debug_binding_list, link) { |
| if (key != binding->key) |
| continue; |
| |
| count++; |
| handler = binding->handler; |
| handler(keyboard, time, key, binding->data); |
| } |
| |
| return count; |
| } |
| |
| struct debug_binding_grab { |
| struct weston_keyboard_grab grab; |
| struct weston_seat *seat; |
| uint32_t key[2]; |
| int key_released[2]; |
| }; |
| |
| static void |
| debug_binding_key(struct weston_keyboard_grab *grab, const struct timespec *time, |
| uint32_t key, uint32_t state) |
| { |
| struct debug_binding_grab *db = (struct debug_binding_grab *) grab; |
| struct weston_compositor *ec = db->seat->compositor; |
| struct wl_display *display = ec->wl_display; |
| struct wl_resource *resource; |
| uint32_t serial; |
| int send = 0, terminate = 0; |
| int check_binding = 1; |
| int i; |
| struct wl_list *resource_list; |
| uint32_t msecs; |
| |
| if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { |
| /* Do not run bindings on key releases */ |
| check_binding = 0; |
| |
| for (i = 0; i < 2; i++) |
| if (key == db->key[i]) |
| db->key_released[i] = 1; |
| |
| if (db->key_released[0] && db->key_released[1]) { |
| /* All key releases been swalled so end the grab */ |
| terminate = 1; |
| } else if (key != db->key[0] && key != db->key[1]) { |
| /* Should not swallow release of other keys */ |
| send = 1; |
| } |
| } else if (key == db->key[0] && !db->key_released[0]) { |
| /* Do not check bindings for the first press of the binding |
| * key. This allows it to be used as a debug shortcut. |
| * We still need to swallow this event. */ |
| check_binding = 0; |
| } else if (db->key[1]) { |
| /* If we already ran a binding don't process another one since |
| * we can't keep track of all the binding keys that were |
| * pressed in order to swallow the release events. */ |
| send = 1; |
| check_binding = 0; |
| } |
| |
| if (check_binding) { |
| if (weston_compositor_run_debug_binding(ec, grab->keyboard, |
| time, key, state)) { |
| /* We ran a binding so swallow the press and keep the |
| * grab to swallow the released too. */ |
| send = 0; |
| terminate = 0; |
| db->key[1] = key; |
| } else { |
| /* Terminate the grab since the key pressed is not a |
| * debug binding key. */ |
| send = 1; |
| terminate = 1; |
| } |
| } |
| |
| if (send) { |
| serial = wl_display_next_serial(display); |
| resource_list = &grab->keyboard->focus_resource_list; |
| msecs = timespec_to_msec(time); |
| wl_resource_for_each(resource, resource_list) { |
| wl_keyboard_send_key(resource, serial, msecs, key, state); |
| } |
| } |
| |
| if (terminate) { |
| weston_keyboard_end_grab(grab->keyboard); |
| if (grab->keyboard->input_method_resource) |
| grab->keyboard->grab = &grab->keyboard->input_method_grab; |
| free(db); |
| } |
| } |
| |
| static void |
| debug_binding_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 wl_resource *resource; |
| struct wl_list *resource_list; |
| |
| resource_list = &grab->keyboard->focus_resource_list; |
| |
| wl_resource_for_each(resource, resource_list) { |
| wl_keyboard_send_modifiers(resource, serial, mods_depressed, |
| mods_latched, mods_locked, group); |
| } |
| } |
| |
| static void |
| debug_binding_cancel(struct weston_keyboard_grab *grab) |
| { |
| struct debug_binding_grab *db = (struct debug_binding_grab *) grab; |
| |
| weston_keyboard_end_grab(grab->keyboard); |
| free(db); |
| } |
| |
| struct weston_keyboard_grab_interface debug_binding_keyboard_grab = { |
| debug_binding_key, |
| debug_binding_modifiers, |
| debug_binding_cancel, |
| }; |
| |
| static void |
| debug_binding(struct weston_keyboard *keyboard, const struct timespec *time, |
| uint32_t key, void *data) |
| { |
| struct debug_binding_grab *grab; |
| |
| grab = calloc(1, sizeof *grab); |
| if (!grab) |
| return; |
| |
| grab->seat = keyboard->seat; |
| grab->key[0] = key; |
| grab->grab.interface = &debug_binding_keyboard_grab; |
| weston_keyboard_start_grab(keyboard, &grab->grab); |
| } |
| |
| /** Install the trigger binding for debug bindings. |
| * |
| * \param compositor The compositor. |
| * \param mod The modifier. |
| * |
| * This will add a key binding for modifier+SHIFT+SPACE that will trigger |
| * debug key bindings. |
| */ |
| WL_EXPORT void |
| weston_install_debug_key_binding(struct weston_compositor *compositor, |
| uint32_t mod) |
| { |
| weston_compositor_add_key_binding(compositor, KEY_SPACE, |
| mod | MODIFIER_SHIFT, |
| debug_binding, NULL); |
| } |