/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * Authors: * Matthew Allum * Robert Bragg * Kristian Høgsberg */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "../clutter-debug.h" #include "../clutter-private.h" #include "../clutter-keysyms.h" #include "clutter-stage-wayland.h" #define CLUTTER_TYPE_INPUT_DEVICE_WAYLAND (clutter_input_device_wayland_get_type ()) #define CLUTTER_INPUT_DEVICE_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_WAYLAND, ClutterInputDeviceWayland)) #define CLUTTER_IS_INPUT_DEVICE_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_WAYLAND)) typedef struct _ClutterInputDeviceWayland ClutterInputDeviceWayland; GType clutter_input_device_wayland_get_type (void) G_GNUC_CONST; typedef struct _ClutterInputDeviceClass ClutterInputDeviceWaylandClass; struct _ClutterInputDeviceWayland { ClutterInputDevice device; struct wl_input_device *input_device; ClutterStageWayland *pointer_focus; ClutterStageWayland *keyboard_focus; uint32_t modifier_state; int32_t x, y, surface_x, surface_y; struct xkb_desc *xkb; }; G_DEFINE_TYPE (ClutterInputDeviceWayland, clutter_input_device_wayland, CLUTTER_TYPE_INPUT_DEVICE); static void clutter_backend_wayland_handle_motion (void *data, struct wl_input_device *input_device, uint32_t _time, int32_t x, int32_t y, int32_t sx, int32_t sy) { ClutterInputDeviceWayland *device = data; ClutterStageWayland *stage_wayland = device->pointer_focus; ClutterMainContext *clutter_context; ClutterEvent *event; event = clutter_event_new (CLUTTER_MOTION); event->motion.stage = stage_wayland->wrapper; event->motion.device = CLUTTER_INPUT_DEVICE (device); event->motion.time = _time; event->motion.modifier_state = 0; event->motion.x = sx; event->motion.y = sy; device->surface_x = sx; device->surface_y = sy; device->x = x; device->y = y; clutter_context = _clutter_context_get_default (); g_queue_push_head (clutter_context->events_queue, event); } static void clutter_backend_wayland_handle_button (void *data, struct wl_input_device *input_device, uint32_t _time, uint32_t button, uint32_t state) { ClutterInputDeviceWayland *device = data; ClutterStageWayland *stage_wayland = device->pointer_focus; ClutterMainContext *clutter_context; ClutterEvent *event; ClutterEventType type; if (state) type = CLUTTER_BUTTON_PRESS; else type = CLUTTER_BUTTON_RELEASE; event = clutter_event_new (type); event->button.stage = stage_wayland->wrapper; event->button.device = CLUTTER_INPUT_DEVICE (device); event->button.time = _time; event->button.x = device->surface_x; event->button.y = device->surface_y; event->button.modifier_state = device->modifier_state; /* evdev button codes */ switch (button) { case 272: event->button.button = 1; break; case 273: event->button.button = 3; break; case 274: event->button.button = 2; break; } clutter_context = _clutter_context_get_default (); g_queue_push_head (clutter_context->events_queue, event); } static void clutter_backend_wayland_handle_key (void *data, struct wl_input_device *input_device, uint32_t _time, uint32_t key, uint32_t state) { ClutterInputDeviceWayland *device = data; ClutterStageWayland *stage_wayland = device->keyboard_focus; ClutterMainContext *clutter_context; ClutterEvent *event; uint32_t code, sym, level; if (state) event = clutter_event_new (CLUTTER_KEY_PRESS); else event = clutter_event_new (CLUTTER_KEY_RELEASE); code = key + device->xkb->min_key_code; level = 0; if (device->modifier_state & CLUTTER_SHIFT_MASK && XkbKeyGroupWidth (device->xkb, code, 0) > 1) level = 1; sym = XkbKeySymEntry (device->xkb, code, level, 0); if (state) device->modifier_state |= device->xkb->map->modmap[code]; else device->modifier_state &= ~device->xkb->map->modmap[code]; event->key.device = CLUTTER_INPUT_DEVICE (device); event->key.stage = stage_wayland->wrapper; event->key.time = _time; event->key.modifier_state = device->modifier_state; event->key.hardware_keycode = key; event->key.keyval = sym; event->key.unicode_value = sym; clutter_context = _clutter_context_get_default (); g_queue_push_head (clutter_context->events_queue, event); } static void clutter_backend_wayland_handle_pointer_focus (void *data, struct wl_input_device *input_device, uint32_t _time, struct wl_surface *surface, int32_t x, int32_t y, int32_t sx, int32_t sy) { ClutterInputDeviceWayland *device = data; ClutterStageWayland *stage_wayland; ClutterMainContext *clutter_context; ClutterEvent *event; if (device->pointer_focus) { stage_wayland = device->pointer_focus; event = clutter_event_new (CLUTTER_LEAVE); event->crossing.stage = stage_wayland->wrapper; event->crossing.time = _time; event->crossing.x = sx; event->crossing.y = sy; event->crossing.source = CLUTTER_ACTOR (stage_wayland->wrapper); event->crossing.device = CLUTTER_INPUT_DEVICE (device); clutter_context = _clutter_context_get_default (); g_queue_push_head (clutter_context->events_queue, event); device->pointer_focus = NULL; _clutter_input_device_set_stage (CLUTTER_INPUT_DEVICE (device), NULL); } if (surface) { stage_wayland = wl_surface_get_user_data (surface); device->pointer_focus = stage_wayland; _clutter_input_device_set_stage (CLUTTER_INPUT_DEVICE (device), stage_wayland->wrapper); event = clutter_event_new (CLUTTER_MOTION); event->motion.time = _time; event->motion.x = sx; event->motion.y = sy; event->motion.modifier_state = device->modifier_state; event->motion.source = CLUTTER_ACTOR (stage_wayland->wrapper); event->motion.device = CLUTTER_INPUT_DEVICE (device); clutter_context = _clutter_context_get_default (); g_queue_push_head (clutter_context->events_queue, event); device->surface_x = sx; device->surface_y = sy; device->x = x; device->y = y; /* Revert back to default pointer for now. */ wl_input_device_attach (input_device, _time, NULL, 0, 0); } } static void clutter_backend_wayland_handle_keyboard_focus (void *data, struct wl_input_device *input_device, uint32_t _time, struct wl_surface *surface, struct wl_array *keys) { ClutterInputDeviceWayland *device = data; ClutterStageWayland *stage_wayland; ClutterMainContext *clutter_context; ClutterEvent *event; uint32_t *k, *end; if (device->keyboard_focus) { stage_wayland = device->keyboard_focus; device->keyboard_focus = NULL; event = clutter_event_new (CLUTTER_STAGE_STATE); event->stage_state.time = _time; event->stage_state.stage = stage_wayland->wrapper; event->stage_state.stage = stage_wayland->wrapper; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; event->stage_state.new_state = 0; clutter_context = _clutter_context_get_default (); g_queue_push_head (clutter_context->events_queue, event); } if (surface) { stage_wayland = wl_surface_get_user_data (surface); device->keyboard_focus = stage_wayland; event = clutter_event_new (CLUTTER_STAGE_STATE); event->stage_state.stage = stage_wayland->wrapper; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; event->stage_state.new_state = CLUTTER_STAGE_STATE_ACTIVATED; end = keys->data + keys->size; device->modifier_state = 0; for (k = keys->data; k < end; k++) device->modifier_state |= device->xkb->map->modmap[*k]; clutter_context = _clutter_context_get_default (); g_queue_push_head (clutter_context->events_queue, event); } } static const struct wl_input_device_listener input_device_listener = { clutter_backend_wayland_handle_motion, clutter_backend_wayland_handle_button, clutter_backend_wayland_handle_key, clutter_backend_wayland_handle_pointer_focus, clutter_backend_wayland_handle_keyboard_focus, }; static void clutter_input_device_wayland_class_init (ClutterInputDeviceWaylandClass *klass) { } static void clutter_input_device_wayland_init (ClutterInputDeviceWayland *self) { } const char *option_xkb_layout = "us"; const char *option_xkb_variant = ""; const char *option_xkb_options = ""; void _clutter_backend_add_input_device (ClutterBackendWayland *backend_wayland, uint32_t id) { ClutterInputDeviceWayland *device; struct xkb_rule_names names; device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_WAYLAND, "id", id, "device-type", CLUTTER_POINTER_DEVICE, "name", "wayland device", NULL); device->input_device = wl_input_device_create (backend_wayland->wayland_display, id); wl_input_device_add_listener (device->input_device, &input_device_listener, device); wl_input_device_set_user_data (device->input_device, device); names.rules = "evdev"; names.model = "pc105"; names.layout = option_xkb_layout; names.variant = option_xkb_variant; names.options = option_xkb_options; device->xkb = xkb_compile_keymap_from_rules (&names); if (!device->xkb) CLUTTER_NOTE (BACKEND, "Failed to compile keymap"); }