2013-05-03 13:51:22 -04:00
|
|
|
/*
|
|
|
|
* Wayland Support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013 Intel Corporation
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
* 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright © 2010-2011 Intel Corporation
|
|
|
|
* Copyright © 2008-2011 Kristian Høgsberg
|
|
|
|
* Copyright © 2012 Collabora, Ltd.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
|
|
* that the above copyright notice appear in all copies and that both that
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
|
|
|
* documentation, and that the name of the copyright holders not be used in
|
|
|
|
* advertising or publicity pertaining to distribution of the software
|
|
|
|
* without specific, written prior permission. The copyright holders make
|
|
|
|
* no representations about the suitability of this software for any
|
|
|
|
* purpose. It is provided "as is" without express or implied warranty.
|
|
|
|
*
|
|
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
|
|
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
|
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
|
|
|
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* The file is based on src/input.c from Weston */
|
|
|
|
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/mman.h>
|
2013-08-09 11:28:41 -04:00
|
|
|
#include <clutter/evdev/clutter-evdev.h>
|
2013-05-03 13:51:22 -04:00
|
|
|
|
2013-08-30 12:03:30 -04:00
|
|
|
#include "meta-wayland-private.h"
|
2013-05-03 13:51:22 -04:00
|
|
|
|
|
|
|
static MetaWaylandSeat *
|
|
|
|
meta_wayland_keyboard_get_seat (MetaWaylandKeyboard *keyboard)
|
|
|
|
{
|
|
|
|
MetaWaylandSeat *seat = wl_container_of (keyboard, seat, keyboard);
|
|
|
|
|
|
|
|
return seat;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
create_anonymous_file (off_t size,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
static const char template[] = "mutter-shared-XXXXXX";
|
|
|
|
char *path;
|
|
|
|
int fd, flags;
|
|
|
|
|
|
|
|
fd = g_file_open_tmp (template, &path, error);
|
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
unlink (path);
|
|
|
|
g_free (path);
|
|
|
|
|
|
|
|
flags = fcntl (fd, F_GETFD);
|
|
|
|
if (flags == -1)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (ftruncate (fd, size) < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
err:
|
|
|
|
g_set_error_literal (error,
|
|
|
|
G_FILE_ERROR,
|
|
|
|
g_file_error_from_errno (errno),
|
|
|
|
strerror (errno));
|
|
|
|
close (fd);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
|
|
|
|
{
|
|
|
|
GError *error = NULL;
|
|
|
|
char *keymap_str;
|
|
|
|
|
|
|
|
xkb_info->shift_mod =
|
|
|
|
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
|
|
|
|
xkb_info->caps_mod =
|
|
|
|
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CAPS);
|
|
|
|
xkb_info->ctrl_mod =
|
|
|
|
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CTRL);
|
|
|
|
xkb_info->alt_mod =
|
|
|
|
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_ALT);
|
|
|
|
xkb_info->mod2_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod2");
|
|
|
|
xkb_info->mod3_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod3");
|
|
|
|
xkb_info->super_mod =
|
|
|
|
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_LOGO);
|
|
|
|
xkb_info->mod5_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod5");
|
|
|
|
|
|
|
|
keymap_str = xkb_map_get_as_string (xkb_info->keymap);
|
|
|
|
if (keymap_str == NULL)
|
|
|
|
{
|
|
|
|
g_warning ("failed to get string version of keymap\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
xkb_info->keymap_size = strlen (keymap_str) + 1;
|
|
|
|
|
|
|
|
xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
|
|
|
|
if (xkb_info->keymap_fd < 0)
|
|
|
|
{
|
|
|
|
g_warning ("creating a keymap file for %lu bytes failed: %s\n",
|
|
|
|
(unsigned long) xkb_info->keymap_size,
|
|
|
|
error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
goto err_keymap_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
|
|
|
|
PROT_READ | PROT_WRITE,
|
|
|
|
MAP_SHARED, xkb_info->keymap_fd, 0);
|
|
|
|
if (xkb_info->keymap_area == MAP_FAILED)
|
|
|
|
{
|
|
|
|
g_warning ("failed to mmap() %lu bytes\n",
|
|
|
|
(unsigned long) xkb_info->keymap_size);
|
|
|
|
goto err_dev_zero;
|
|
|
|
}
|
|
|
|
strcpy (xkb_info->keymap_area, keymap_str);
|
|
|
|
free (keymap_str);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
err_dev_zero:
|
|
|
|
close (xkb_info->keymap_fd);
|
|
|
|
xkb_info->keymap_fd = -1;
|
|
|
|
err_keymap_str:
|
|
|
|
free (keymap_str);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_wayland_keyboard_build_global_keymap (struct xkb_context *xkb_context,
|
|
|
|
struct xkb_rule_names *xkb_names,
|
|
|
|
MetaWaylandXkbInfo *xkb_info)
|
|
|
|
{
|
|
|
|
xkb_info->keymap = xkb_map_new_from_names (xkb_context,
|
|
|
|
xkb_names,
|
|
|
|
0 /* flags */);
|
|
|
|
if (xkb_info->keymap == NULL)
|
|
|
|
{
|
|
|
|
g_warning ("failed to compile global XKB keymap\n"
|
|
|
|
" tried rules %s, model %s, layout %s, variant %s, "
|
|
|
|
"options %s\n",
|
|
|
|
xkb_names->rules,
|
|
|
|
xkb_names->model,
|
|
|
|
xkb_names->layout,
|
|
|
|
xkb_names->variant,
|
|
|
|
xkb_names->options);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_wayland_xkb_info_new_keymap (xkb_info))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lose_keyboard_focus (struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
MetaWaylandKeyboard *keyboard =
|
|
|
|
wl_container_of (listener, keyboard, focus_listener);
|
|
|
|
|
|
|
|
keyboard->focus_resource = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
default_grab_key (MetaWaylandKeyboardGrab *grab,
|
|
|
|
uint32_t time, uint32_t key, uint32_t state)
|
|
|
|
{
|
|
|
|
MetaWaylandKeyboard *keyboard = grab->keyboard;
|
|
|
|
struct wl_resource *resource;
|
|
|
|
uint32_t serial;
|
|
|
|
|
|
|
|
resource = keyboard->focus_resource;
|
|
|
|
if (resource)
|
|
|
|
{
|
|
|
|
struct wl_client *client = wl_resource_get_client (resource);
|
|
|
|
struct wl_display *display = wl_client_get_display (client);
|
|
|
|
serial = wl_display_next_serial (display);
|
|
|
|
wl_keyboard_send_key (resource, serial, time, key, state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct wl_resource *
|
|
|
|
find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
struct wl_client *client;
|
|
|
|
|
|
|
|
if (!surface)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!surface->resource)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
client = wl_resource_get_client (surface->resource);
|
|
|
|
|
|
|
|
return wl_resource_find_for_client (list, client);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
|
|
|
|
uint32_t mods_depressed, uint32_t mods_latched,
|
|
|
|
uint32_t mods_locked, uint32_t group)
|
|
|
|
{
|
|
|
|
MetaWaylandKeyboard *keyboard = grab->keyboard;
|
|
|
|
MetaWaylandSeat *seat = meta_wayland_keyboard_get_seat (keyboard);
|
|
|
|
MetaWaylandPointer *pointer = &seat->pointer;
|
|
|
|
struct wl_resource *resource, *pr;
|
|
|
|
|
|
|
|
resource = keyboard->focus_resource;
|
|
|
|
if (!resource)
|
|
|
|
return;
|
|
|
|
|
|
|
|
wl_keyboard_send_modifiers (resource, serial, mods_depressed,
|
|
|
|
mods_latched, mods_locked, group);
|
|
|
|
|
|
|
|
if (pointer && pointer->focus && pointer->focus != keyboard->focus)
|
|
|
|
{
|
|
|
|
pr = find_resource_for_surface (&keyboard->resource_list,
|
|
|
|
pointer->focus);
|
|
|
|
if (pr)
|
|
|
|
{
|
2013-08-09 11:28:41 -04:00
|
|
|
wl_keyboard_send_modifiers (pr, serial,
|
|
|
|
mods_depressed,
|
|
|
|
mods_latched,
|
|
|
|
mods_locked,
|
|
|
|
group);
|
2013-05-03 13:51:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MetaWaylandKeyboardGrabInterface
|
|
|
|
default_keyboard_grab_interface = {
|
|
|
|
default_grab_key,
|
|
|
|
default_grab_modifiers,
|
|
|
|
};
|
|
|
|
|
2013-08-13 10:51:33 -04:00
|
|
|
static void
|
|
|
|
modal_key (MetaWaylandKeyboardGrab *grab,
|
|
|
|
uint32_t time,
|
|
|
|
uint32_t key,
|
|
|
|
uint32_t state)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
modal_modifiers (MetaWaylandKeyboardGrab *grab,
|
|
|
|
uint32_t serial,
|
|
|
|
uint32_t mods_depressed,
|
|
|
|
uint32_t mods_latched,
|
|
|
|
uint32_t mods_locked,
|
|
|
|
uint32_t group)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaWaylandKeyboardGrabInterface modal_grab = {
|
|
|
|
modal_key,
|
|
|
|
modal_modifiers,
|
|
|
|
};
|
|
|
|
|
2013-05-03 13:51:22 -04:00
|
|
|
gboolean
|
|
|
|
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
2013-08-09 11:28:41 -04:00
|
|
|
struct wl_display *display,
|
|
|
|
gboolean is_evdev)
|
2013-05-03 13:51:22 -04:00
|
|
|
{
|
2013-08-09 11:28:41 -04:00
|
|
|
ClutterDeviceManager *manager;
|
|
|
|
|
2013-05-03 13:51:22 -04:00
|
|
|
memset (keyboard, 0, sizeof *keyboard);
|
|
|
|
|
|
|
|
wl_list_init (&keyboard->resource_list);
|
|
|
|
wl_array_init (&keyboard->keys);
|
|
|
|
keyboard->focus_listener.notify = lose_keyboard_focus;
|
|
|
|
keyboard->default_grab.interface = &default_keyboard_grab_interface;
|
|
|
|
keyboard->default_grab.keyboard = keyboard;
|
|
|
|
keyboard->grab = &keyboard->default_grab;
|
|
|
|
wl_signal_init (&keyboard->focus_signal);
|
|
|
|
|
|
|
|
keyboard->display = display;
|
|
|
|
|
|
|
|
keyboard->xkb_context = xkb_context_new (0 /* flags */);
|
|
|
|
|
|
|
|
meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context,
|
2013-08-09 11:28:41 -04:00
|
|
|
&keyboard->xkb_names,
|
|
|
|
&keyboard->xkb_info);
|
|
|
|
|
|
|
|
keyboard->is_evdev = is_evdev;
|
|
|
|
if (is_evdev)
|
|
|
|
{
|
|
|
|
manager = clutter_device_manager_get_default ();
|
|
|
|
|
|
|
|
clutter_evdev_set_keyboard_map (manager, keyboard->xkb_info.keymap);
|
|
|
|
keyboard->xkb_state = clutter_evdev_get_keyboard_state (manager);
|
|
|
|
xkb_state_ref (keyboard->xkb_state);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
keyboard->xkb_state = xkb_state_new (keyboard->xkb_info.keymap);
|
|
|
|
}
|
2013-05-03 13:51:22 -04:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
|
|
|
|
{
|
|
|
|
if (xkb_info->keymap)
|
|
|
|
xkb_map_unref (xkb_info->keymap);
|
|
|
|
|
|
|
|
if (xkb_info->keymap_area)
|
|
|
|
munmap (xkb_info->keymap_area, xkb_info->keymap_size);
|
|
|
|
if (xkb_info->keymap_fd >= 0)
|
|
|
|
close (xkb_info->keymap_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-08-09 11:28:41 -04:00
|
|
|
update_state_from_clutter (MetaWaylandKeyboard *keyboard,
|
|
|
|
ClutterModifierType modifier_state)
|
2013-05-03 13:51:22 -04:00
|
|
|
{
|
|
|
|
uint32_t depressed_mods = 0;
|
|
|
|
uint32_t locked_mods = 0;
|
|
|
|
|
|
|
|
if ((modifier_state & CLUTTER_SHIFT_MASK) &&
|
|
|
|
keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
|
|
|
|
depressed_mods |= (1 << keyboard->xkb_info.shift_mod);
|
|
|
|
|
|
|
|
if ((modifier_state & CLUTTER_LOCK_MASK) &&
|
|
|
|
keyboard->xkb_info.caps_mod != XKB_MOD_INVALID)
|
|
|
|
locked_mods |= (1 << keyboard->xkb_info.caps_mod);
|
|
|
|
|
|
|
|
if ((modifier_state & CLUTTER_CONTROL_MASK) &&
|
|
|
|
keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID)
|
|
|
|
depressed_mods |= (1 << keyboard->xkb_info.ctrl_mod);
|
|
|
|
|
|
|
|
if ((modifier_state & CLUTTER_MOD1_MASK) &&
|
|
|
|
keyboard->xkb_info.alt_mod != XKB_MOD_INVALID)
|
|
|
|
depressed_mods |= (1 << keyboard->xkb_info.alt_mod);
|
|
|
|
|
|
|
|
if ((modifier_state & CLUTTER_MOD2_MASK) &&
|
|
|
|
keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID)
|
|
|
|
depressed_mods |= (1 << keyboard->xkb_info.mod2_mod);
|
|
|
|
|
|
|
|
if ((modifier_state & CLUTTER_MOD3_MASK) &&
|
|
|
|
keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID)
|
|
|
|
depressed_mods |= (1 << keyboard->xkb_info.mod3_mod);
|
|
|
|
|
|
|
|
if ((modifier_state & CLUTTER_SUPER_MASK) &&
|
|
|
|
keyboard->xkb_info.super_mod != XKB_MOD_INVALID)
|
|
|
|
depressed_mods |= (1 << keyboard->xkb_info.super_mod);
|
|
|
|
|
|
|
|
if ((modifier_state & CLUTTER_MOD5_MASK) &&
|
|
|
|
keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
|
|
|
|
depressed_mods |= (1 << keyboard->xkb_info.mod5_mod);
|
|
|
|
|
2013-08-09 11:28:41 -04:00
|
|
|
xkb_state_update_mask (keyboard->xkb_state,
|
|
|
|
depressed_mods,
|
|
|
|
0,
|
|
|
|
locked_mods,
|
|
|
|
0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
state_equal (MetaWaylandXkbState *one,
|
|
|
|
MetaWaylandXkbState *two)
|
|
|
|
{
|
|
|
|
return one->mods_depressed == two->mods_depressed &&
|
|
|
|
one->mods_latched == two->mods_latched &&
|
|
|
|
one->mods_locked == two->mods_locked &&
|
|
|
|
one->group == two->group;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_modifiers (MetaWaylandKeyboard *keyboard,
|
|
|
|
guint32 serial,
|
|
|
|
ClutterModifierType modifier_state)
|
|
|
|
{
|
|
|
|
MetaWaylandKeyboardGrab *grab = keyboard->grab;
|
|
|
|
MetaWaylandXkbState new_state;
|
|
|
|
|
|
|
|
/* In the evdev case, the state is shared with the clutter backend, so
|
|
|
|
we don't need to update it */
|
|
|
|
if (!keyboard->is_evdev)
|
|
|
|
update_state_from_clutter (keyboard, modifier_state);
|
|
|
|
|
|
|
|
new_state.mods_depressed = xkb_state_serialize_mods (keyboard->xkb_state,
|
|
|
|
XKB_STATE_MODS_DEPRESSED);
|
|
|
|
new_state.mods_latched = xkb_state_serialize_mods (keyboard->xkb_state,
|
|
|
|
XKB_STATE_MODS_LATCHED);
|
|
|
|
new_state.mods_locked = xkb_state_serialize_mods (keyboard->xkb_state,
|
|
|
|
XKB_STATE_MODS_LOCKED);
|
|
|
|
new_state.group = xkb_state_serialize_layout (keyboard->xkb_state,
|
|
|
|
XKB_STATE_LAYOUT_EFFECTIVE);
|
|
|
|
|
|
|
|
if (state_equal (&keyboard->modifier_state, &new_state))
|
|
|
|
return;
|
|
|
|
|
|
|
|
keyboard->modifier_state = new_state;
|
2013-05-03 13:51:22 -04:00
|
|
|
|
|
|
|
grab->interface->modifiers (grab,
|
|
|
|
serial,
|
2013-08-09 11:28:41 -04:00
|
|
|
new_state.mods_depressed,
|
|
|
|
new_state.mods_latched,
|
|
|
|
new_state.mods_locked,
|
|
|
|
new_state.group);
|
2013-05-03 13:51:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
|
|
|
const ClutterKeyEvent *event)
|
|
|
|
{
|
|
|
|
gboolean state = event->type == CLUTTER_KEY_PRESS;
|
|
|
|
guint evdev_code;
|
|
|
|
uint32_t serial;
|
|
|
|
|
|
|
|
/* We can't do anything with the event if we can't get an evdev
|
|
|
|
keycode for it */
|
|
|
|
if (event->device == NULL ||
|
|
|
|
!clutter_input_device_keycode_to_evdev (event->device,
|
|
|
|
event->hardware_keycode,
|
|
|
|
&evdev_code))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* We want to ignore events that are sent because of auto-repeat. In
|
|
|
|
the Clutter event stream these appear as a single key press
|
|
|
|
event. We can detect that because the key will already have been
|
|
|
|
pressed */
|
|
|
|
if (state)
|
|
|
|
{
|
|
|
|
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
|
|
|
keyboard->keys.size);
|
|
|
|
uint32_t *k;
|
|
|
|
|
|
|
|
/* Ignore the event if the key is already down */
|
|
|
|
for (k = keyboard->keys.data; k < end; k++)
|
|
|
|
if (*k == evdev_code)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Otherwise add the key to the list of pressed keys */
|
|
|
|
k = wl_array_add (&keyboard->keys, sizeof (*k));
|
|
|
|
*k = evdev_code;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
|
|
|
keyboard->keys.size);
|
|
|
|
uint32_t *k;
|
|
|
|
|
|
|
|
/* Remove the key from the array */
|
|
|
|
for (k = keyboard->keys.data; k < end; k++)
|
|
|
|
if (*k == evdev_code)
|
|
|
|
{
|
|
|
|
*k = *(end - 1);
|
|
|
|
keyboard->keys.size -= sizeof (*k);
|
|
|
|
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_warning ("unexpected key release event for key 0x%x", evdev_code);
|
|
|
|
|
|
|
|
found:
|
|
|
|
(void) 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
serial = wl_display_next_serial (keyboard->display);
|
|
|
|
|
|
|
|
set_modifiers (keyboard, serial, event->modifier_state);
|
|
|
|
|
|
|
|
keyboard->grab->interface->key (keyboard->grab,
|
|
|
|
event->time,
|
|
|
|
evdev_code,
|
|
|
|
state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
|
|
|
|
MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
struct wl_resource *resource;
|
|
|
|
uint32_t serial;
|
|
|
|
|
|
|
|
if (keyboard->focus_resource && keyboard->focus != surface)
|
|
|
|
{
|
|
|
|
struct wl_display *display;
|
|
|
|
struct wl_client *client;
|
|
|
|
|
|
|
|
resource = keyboard->focus_resource;
|
|
|
|
client = wl_resource_get_client (resource);
|
|
|
|
display = wl_client_get_display (client);
|
|
|
|
serial = wl_display_next_serial (display);
|
|
|
|
wl_keyboard_send_leave (resource, serial, keyboard->focus->resource);
|
|
|
|
wl_list_remove (&keyboard->focus_listener.link);
|
|
|
|
}
|
|
|
|
|
|
|
|
resource = find_resource_for_surface (&keyboard->resource_list, surface);
|
|
|
|
if (resource &&
|
|
|
|
(keyboard->focus != surface || keyboard->focus_resource != resource))
|
|
|
|
{
|
|
|
|
struct wl_client *client = wl_resource_get_client (resource);
|
|
|
|
struct wl_display *display;
|
|
|
|
|
|
|
|
display = wl_client_get_display (client);
|
|
|
|
serial = wl_display_next_serial (display);
|
2013-08-13 10:51:33 -04:00
|
|
|
|
|
|
|
/* If we're in a modal grab, the client is focused but doesn't see
|
|
|
|
modifiers or pressed keys (and fix that up when we exit the modal) */
|
|
|
|
if (keyboard->grab->interface == &modal_grab)
|
|
|
|
{
|
|
|
|
struct wl_array empty;
|
|
|
|
wl_array_init (&empty);
|
|
|
|
|
|
|
|
wl_keyboard_send_modifiers (resource, serial,
|
|
|
|
0, 0, 0, 0);
|
|
|
|
wl_keyboard_send_enter (resource, serial, surface->resource,
|
|
|
|
&empty);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wl_keyboard_send_modifiers (resource, serial,
|
|
|
|
keyboard->modifier_state.mods_depressed,
|
|
|
|
keyboard->modifier_state.mods_latched,
|
|
|
|
keyboard->modifier_state.mods_locked,
|
|
|
|
keyboard->modifier_state.group);
|
|
|
|
wl_keyboard_send_enter (resource, serial, surface->resource,
|
|
|
|
&keyboard->keys);
|
|
|
|
}
|
2013-05-03 13:51:22 -04:00
|
|
|
wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
|
|
|
|
keyboard->focus_serial = serial;
|
|
|
|
}
|
|
|
|
|
|
|
|
keyboard->focus_resource = resource;
|
|
|
|
keyboard->focus = surface;
|
|
|
|
wl_signal_emit (&keyboard->focus_signal, keyboard);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *keyboard,
|
|
|
|
MetaWaylandKeyboardGrab *grab)
|
|
|
|
{
|
|
|
|
keyboard->grab = grab;
|
|
|
|
grab->keyboard = keyboard;
|
|
|
|
|
|
|
|
/* XXX focus? */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard)
|
|
|
|
{
|
|
|
|
keyboard->grab = &keyboard->default_grab;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
|
|
|
|
{
|
|
|
|
g_free ((char *) keyboard->xkb_names.rules);
|
|
|
|
g_free ((char *) keyboard->xkb_names.model);
|
|
|
|
g_free ((char *) keyboard->xkb_names.layout);
|
|
|
|
g_free ((char *) keyboard->xkb_names.variant);
|
|
|
|
g_free ((char *) keyboard->xkb_names.options);
|
|
|
|
|
|
|
|
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
|
|
|
|
xkb_context_unref (keyboard->xkb_context);
|
2013-08-09 11:28:41 -04:00
|
|
|
xkb_state_unref (keyboard->xkb_state);
|
2013-05-03 13:51:22 -04:00
|
|
|
|
|
|
|
/* XXX: What about keyboard->resource_list? */
|
|
|
|
if (keyboard->focus_resource)
|
|
|
|
wl_list_remove (&keyboard->focus_listener.link);
|
|
|
|
wl_array_release (&keyboard->keys);
|
|
|
|
}
|
2013-08-13 10:51:33 -04:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
|
|
|
|
guint32 timestamp)
|
|
|
|
{
|
|
|
|
MetaWaylandKeyboardGrab *grab;
|
|
|
|
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
|
|
|
keyboard->keys.size);
|
|
|
|
uint32_t *k;
|
|
|
|
uint32_t serial;
|
|
|
|
|
|
|
|
if (keyboard->grab != &keyboard->default_grab)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (keyboard->focus)
|
|
|
|
{
|
|
|
|
/* Fake key release events for the focused app */
|
|
|
|
serial = wl_display_next_serial (keyboard->display);
|
|
|
|
keyboard->grab->interface->modifiers (keyboard->grab,
|
|
|
|
serial,
|
|
|
|
0, 0, 0, 0);
|
|
|
|
|
|
|
|
for (k = keyboard->keys.data; k < end; k++)
|
|
|
|
keyboard->grab->interface->key (keyboard->grab,
|
|
|
|
timestamp,
|
|
|
|
*k, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
grab = g_slice_new0 (MetaWaylandKeyboardGrab);
|
|
|
|
grab->interface = &modal_grab;
|
|
|
|
meta_wayland_keyboard_start_grab (keyboard, grab);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
|
|
|
|
guint32 timestamp)
|
|
|
|
{
|
|
|
|
MetaWaylandKeyboardGrab *grab;
|
|
|
|
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
|
|
|
keyboard->keys.size);
|
|
|
|
uint32_t *k;
|
|
|
|
uint32_t serial;
|
|
|
|
|
|
|
|
grab = keyboard->grab;
|
|
|
|
|
|
|
|
g_assert (grab->interface == &modal_grab);
|
|
|
|
|
|
|
|
meta_wayland_keyboard_end_grab (keyboard);
|
|
|
|
g_slice_free (MetaWaylandKeyboardGrab, grab);
|
|
|
|
|
|
|
|
if (keyboard->focus)
|
|
|
|
{
|
|
|
|
/* Fake key press events for the focused app */
|
|
|
|
serial = wl_display_next_serial (keyboard->display);
|
|
|
|
keyboard->grab->interface->modifiers (keyboard->grab,
|
|
|
|
serial,
|
|
|
|
keyboard->modifier_state.mods_depressed,
|
|
|
|
keyboard->modifier_state.mods_latched,
|
|
|
|
keyboard->modifier_state.mods_locked,
|
|
|
|
keyboard->modifier_state.group);
|
|
|
|
|
|
|
|
for (k = keyboard->keys.data; k < end; k++)
|
|
|
|
keyboard->grab->interface->key (keyboard->grab,
|
|
|
|
timestamp,
|
|
|
|
*k, 1);
|
|
|
|
}
|
|
|
|
}
|