1
0
Fork 0
mutter-performance-source/src/backends/native/meta-seat-native.c
Robert Mader 8e172aeecb cleanup: Use g_clear_handle_id() for g_source_remove()
It makes sure we do not forget to zero the id and lets us avoid
zero checks before. We use it for all new code, lets clean up the
existing code base.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/947
2019-11-22 01:27:40 +01:00

903 lines
28 KiB
C

/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corp.
* Copyright (C) 2014 Jonas Ådahl
* Copyright (C) 2016 Red Hat Inc.
*
* 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 <http://www.gnu.org/licenses/>.
*
* Author: Damien Lespiau <damien.lespiau@intel.com>
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#include "config.h"
#include <linux/input.h>
#include <math.h>
#include "backends/native/meta-seat-native.h"
#include "backends/native/meta-event-native.h"
#include "backends/native/meta-input-device-native.h"
#include "backends/native/meta-input-device-tool-native.h"
#include "backends/native/meta-keymap-native.h"
#include "clutter/clutter-mutter.h"
/* Try to keep the pointer inside the stage. Hopefully no one is using
* this backend with stages smaller than this. */
#define INITIAL_POINTER_X 16
#define INITIAL_POINTER_Y 16
#define AUTOREPEAT_VALUE 2
#define DISCRETE_SCROLL_STEP 10.0
#ifndef BTN_STYLUS3
#define BTN_STYLUS3 0x149 /* Linux 4.15 */
#endif
void
meta_seat_native_set_libinput_seat (MetaSeatNative *seat,
struct libinput_seat *libinput_seat)
{
g_assert (seat->libinput_seat == NULL);
libinput_seat_ref (libinput_seat);
libinput_seat_set_user_data (libinput_seat, seat);
seat->libinput_seat = libinput_seat;
}
void
meta_seat_native_sync_leds (MetaSeatNative *seat)
{
GSList *iter;
MetaInputDeviceNative *device_evdev;
int caps_lock, num_lock, scroll_lock;
enum libinput_led leds = 0;
caps_lock = xkb_state_led_index_is_active (seat->xkb, seat->caps_lock_led);
num_lock = xkb_state_led_index_is_active (seat->xkb, seat->num_lock_led);
scroll_lock = xkb_state_led_index_is_active (seat->xkb, seat->scroll_lock_led);
if (caps_lock)
leds |= LIBINPUT_LED_CAPS_LOCK;
if (num_lock)
leds |= LIBINPUT_LED_NUM_LOCK;
if (scroll_lock)
leds |= LIBINPUT_LED_SCROLL_LOCK;
for (iter = seat->devices; iter; iter = iter->next)
{
device_evdev = iter->data;
meta_input_device_native_update_leds (device_evdev, leds);
}
}
static void
clutter_touch_state_free (MetaTouchState *touch_state)
{
g_slice_free (MetaTouchState, touch_state);
}
static void
ensure_seat_slot_allocated (MetaSeatNative *seat,
int seat_slot)
{
if (seat_slot >= seat->n_alloc_touch_states)
{
const int size_increase = 5;
int i;
seat->n_alloc_touch_states += size_increase;
seat->touch_states = g_realloc_n (seat->touch_states,
seat->n_alloc_touch_states,
sizeof (MetaTouchState *));
for (i = 0; i < size_increase; i++)
seat->touch_states[seat->n_alloc_touch_states - (i + 1)] = NULL;
}
}
MetaTouchState *
meta_seat_native_acquire_touch_state (MetaSeatNative *seat,
int device_slot)
{
MetaTouchState *touch_state;
int seat_slot;
for (seat_slot = 0; seat_slot < seat->n_alloc_touch_states; seat_slot++)
{
if (!seat->touch_states[seat_slot])
break;
}
ensure_seat_slot_allocated (seat, seat_slot);
touch_state = g_slice_new0 (MetaTouchState);
*touch_state = (MetaTouchState) {
.seat = seat,
.seat_slot = seat_slot,
.device_slot = device_slot,
};
seat->touch_states[seat_slot] = touch_state;
return touch_state;
}
void
meta_seat_native_release_touch_state (MetaSeatNative *seat,
MetaTouchState *touch_state)
{
g_clear_pointer (&seat->touch_states[touch_state->seat_slot],
clutter_touch_state_free);
}
MetaSeatNative *
meta_seat_native_new (MetaDeviceManagerNative *manager_evdev)
{
ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (manager_evdev);
MetaSeatNative *seat;
ClutterInputDevice *device;
ClutterStage *stage;
ClutterKeymap *keymap;
struct xkb_keymap *xkb_keymap;
seat = g_new0 (MetaSeatNative, 1);
if (!seat)
return NULL;
seat->manager_evdev = manager_evdev;
device = meta_input_device_native_new_virtual (
manager, seat, CLUTTER_POINTER_DEVICE,
CLUTTER_INPUT_MODE_MASTER);
stage = meta_device_manager_native_get_stage (manager_evdev);
_clutter_input_device_set_stage (device, stage);
seat->pointer_x = INITIAL_POINTER_X;
seat->pointer_y = INITIAL_POINTER_Y;
_clutter_input_device_set_coords (device, NULL,
seat->pointer_x, seat->pointer_y,
NULL);
_clutter_device_manager_add_device (manager, device);
seat->core_pointer = device;
device = meta_input_device_native_new_virtual (
manager, seat, CLUTTER_KEYBOARD_DEVICE,
CLUTTER_INPUT_MODE_MASTER);
_clutter_input_device_set_stage (device, stage);
_clutter_device_manager_add_device (manager, device);
seat->core_keyboard = device;
seat->repeat = TRUE;
seat->repeat_delay = 250; /* ms */
seat->repeat_interval = 33; /* ms */
keymap = clutter_backend_get_keymap (clutter_get_default_backend ());
xkb_keymap = meta_keymap_native_get_keyboard_map (META_KEYMAP_NATIVE (keymap));
if (xkb_keymap)
{
seat->xkb = xkb_state_new (xkb_keymap);
seat->caps_lock_led =
xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_CAPS);
seat->num_lock_led =
xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_NUM);
seat->scroll_lock_led =
xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_SCROLL);
}
return seat;
}
void
meta_seat_native_clear_repeat_timer (MetaSeatNative *seat)
{
if (seat->repeat_timer)
{
g_clear_handle_id (&seat->repeat_timer, g_source_remove);
g_clear_object (&seat->repeat_device);
}
}
static gboolean
keyboard_repeat (gpointer data)
{
MetaSeatNative *seat = data;
GSource *source;
/* There might be events queued in libinput that could cancel the
repeat timer. */
meta_device_manager_native_dispatch (seat->manager_evdev);
if (!seat->repeat_timer)
return G_SOURCE_REMOVE;
g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE);
source = g_main_context_find_source_by_id (NULL, seat->repeat_timer);
meta_seat_native_notify_key (seat,
seat->repeat_device,
g_source_get_time (source),
seat->repeat_key,
AUTOREPEAT_VALUE,
FALSE);
return G_SOURCE_CONTINUE;
}
static void
queue_event (ClutterEvent *event)
{
_clutter_event_push (event, FALSE);
}
static int
update_button_count (MetaSeatNative *seat,
uint32_t button,
uint32_t state)
{
if (state)
{
return ++seat->button_count[button];
}
else
{
/* Handle cases where we newer saw the initial pressed event. */
if (seat->button_count[button] == 0)
return 0;
return --seat->button_count[button];
}
}
void
meta_seat_native_notify_key (MetaSeatNative *seat,
ClutterInputDevice *device,
uint64_t time_us,
uint32_t key,
uint32_t state,
gboolean update_keys)
{
ClutterStage *stage;
ClutterEvent *event = NULL;
enum xkb_state_component changed_state;
if (state != AUTOREPEAT_VALUE)
{
/* Drop any repeated button press (for example from virtual devices. */
int count = update_button_count (seat, key, state);
if (state && count > 1)
return;
if (!state && count != 0)
return;
}
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (device);
if (stage == NULL)
{
meta_seat_native_clear_repeat_timer (seat);
return;
}
event = meta_key_event_new_from_evdev (device,
seat->core_keyboard,
stage,
seat->xkb,
seat->button_state,
us2ms (time_us), key, state);
meta_event_native_set_event_code (event, key);
/* We must be careful and not pass multiple releases to xkb, otherwise it gets
confused and locks the modifiers */
if (state != AUTOREPEAT_VALUE)
{
changed_state = xkb_state_update_key (seat->xkb,
event->key.hardware_keycode,
state ? XKB_KEY_DOWN : XKB_KEY_UP);
}
else
{
changed_state = 0;
clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_REPEATED);
}
queue_event (event);
if (update_keys && (changed_state & XKB_STATE_LEDS))
{
ClutterBackend *backend;
backend = clutter_get_default_backend ();
g_signal_emit_by_name (clutter_backend_get_keymap (backend), "state-changed");
meta_seat_native_sync_leds (seat);
meta_input_device_native_a11y_maybe_notify_toggle_keys (META_INPUT_DEVICE_NATIVE (seat->core_keyboard));
}
if (state == 0 || /* key release */
!seat->repeat ||
!xkb_keymap_key_repeats (xkb_state_get_keymap (seat->xkb),
event->key.hardware_keycode))
{
meta_seat_native_clear_repeat_timer (seat);
return;
}
if (state == 1) /* key press */
seat->repeat_count = 0;
seat->repeat_count += 1;
seat->repeat_key = key;
switch (seat->repeat_count)
{
case 1:
case 2:
{
uint32_t interval;
meta_seat_native_clear_repeat_timer (seat);
seat->repeat_device = g_object_ref (device);
if (seat->repeat_count == 1)
interval = seat->repeat_delay;
else
interval = seat->repeat_interval;
seat->repeat_timer =
clutter_threads_add_timeout_full (CLUTTER_PRIORITY_EVENTS,
interval,
keyboard_repeat,
seat,
NULL);
return;
}
default:
return;
}
}
static ClutterEvent *
new_absolute_motion_event (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
float x,
float y,
double *axes)
{
ClutterStage *stage = _clutter_input_device_get_stage (input_device);
ClutterEvent *event;
event = clutter_event_new (CLUTTER_MOTION);
if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
{
meta_device_manager_native_constrain_pointer (seat->manager_evdev,
seat->core_pointer,
time_us,
seat->pointer_x,
seat->pointer_y,
&x, &y);
}
meta_event_native_set_time_usec (event, time_us);
event->motion.time = us2ms (time_us);
event->motion.stage = stage;
meta_xkb_translate_state (event, seat->xkb, seat->button_state);
event->motion.x = x;
event->motion.y = y;
event->motion.axes = axes;
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
MetaInputDeviceNative *device_evdev =
META_INPUT_DEVICE_NATIVE (input_device);
clutter_event_set_device_tool (event, device_evdev->last_tool);
clutter_event_set_device (event, input_device);
}
else
{
clutter_event_set_device (event, seat->core_pointer);
}
_clutter_input_device_set_stage (seat->core_pointer, stage);
if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
{
seat->pointer_x = x;
seat->pointer_y = y;
}
return event;
}
void
meta_seat_native_notify_relative_motion (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
float dx,
float dy,
float dx_unaccel,
float dy_unaccel)
{
float new_x, new_y;
ClutterEvent *event;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
if (!_clutter_input_device_get_stage (input_device))
return;
meta_device_manager_native_filter_relative_motion (seat->manager_evdev,
input_device,
seat->pointer_x,
seat->pointer_y,
&dx,
&dy);
new_x = seat->pointer_x + dx;
new_y = seat->pointer_y + dy;
event = new_absolute_motion_event (seat, input_device,
time_us, new_x, new_y, NULL);
meta_event_native_set_relative_motion (event,
dx, dy,
dx_unaccel, dy_unaccel);
queue_event (event);
}
void
meta_seat_native_notify_absolute_motion (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
float x,
float y,
double *axes)
{
ClutterEvent *event;
event = new_absolute_motion_event (seat, input_device, time_us, x, y, axes);
queue_event (event);
}
void
meta_seat_native_notify_button (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
uint32_t button,
uint32_t state)
{
MetaInputDeviceNative *device_evdev = (MetaInputDeviceNative *) input_device;
ClutterStage *stage;
ClutterEvent *event = NULL;
int button_nr;
static int maskmap[8] =
{
CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON3_MASK, CLUTTER_BUTTON2_MASK,
CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK, 0, 0, 0
};
int button_count;
/* Drop any repeated button press (for example from virtual devices. */
button_count = update_button_count (seat, button, state);
if (state && button_count > 1)
return;
if (!state && button_count != 0)
return;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (input_device);
if (stage == NULL)
return;
/* The evdev button numbers don't map sequentially to clutter button
* numbers (the right and middle mouse buttons are in the opposite
* order) so we'll map them directly with a switch statement */
switch (button)
{
case BTN_LEFT:
case BTN_TOUCH:
button_nr = CLUTTER_BUTTON_PRIMARY;
break;
case BTN_RIGHT:
case BTN_STYLUS:
button_nr = CLUTTER_BUTTON_SECONDARY;
break;
case BTN_MIDDLE:
case BTN_STYLUS2:
button_nr = CLUTTER_BUTTON_MIDDLE;
break;
case 0x149: /* BTN_STYLUS3 */
button_nr = 8;
break;
default:
/* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
button_nr = button - BTN_TOOL_PEN + 4;
else
button_nr = button - (BTN_LEFT - 1) + 4;
break;
}
if (button_nr < 1 || button_nr > 12)
{
g_warning ("Unhandled button event 0x%x", button);
return;
}
if (state)
event = clutter_event_new (CLUTTER_BUTTON_PRESS);
else
event = clutter_event_new (CLUTTER_BUTTON_RELEASE);
if (button_nr < G_N_ELEMENTS (maskmap))
{
/* Update the modifiers */
if (state)
seat->button_state |= maskmap[button_nr - 1];
else
seat->button_state &= ~maskmap[button_nr - 1];
}
meta_event_native_set_time_usec (event, time_us);
event->button.time = us2ms (time_us);
event->button.stage = CLUTTER_STAGE (stage);
meta_xkb_translate_state (event, seat->xkb, seat->button_state);
event->button.button = button_nr;
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
graphene_point_t point;
clutter_input_device_get_coords (input_device, NULL, &point);
event->button.x = point.x;
event->button.y = point.y;
}
else
{
event->button.x = seat->pointer_x;
event->button.y = seat->pointer_y;
}
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
if (device_evdev->last_tool)
{
/* Apply the button event code as per the tool mapping */
uint32_t mapped_button;
mapped_button = meta_input_device_tool_native_get_button_code (device_evdev->last_tool,
button_nr);
if (mapped_button != 0)
button = mapped_button;
}
meta_event_native_set_event_code (event, button);
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
clutter_event_set_device_tool (event, device_evdev->last_tool);
clutter_event_set_device (event, input_device);
}
else
{
clutter_event_set_device (event, seat->core_pointer);
}
_clutter_input_device_set_stage (seat->core_pointer, stage);
queue_event (event);
}
static void
notify_scroll (ClutterInputDevice *input_device,
uint64_t time_us,
double dx,
double dy,
ClutterScrollSource scroll_source,
ClutterScrollFinishFlags flags,
gboolean emulated)
{
MetaInputDeviceNative *device_evdev;
MetaSeatNative *seat;
ClutterStage *stage;
ClutterEvent *event = NULL;
double scroll_factor;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (input_device);
if (stage == NULL)
return;
device_evdev = META_INPUT_DEVICE_NATIVE (input_device);
seat = meta_input_device_native_get_seat (device_evdev);
event = clutter_event_new (CLUTTER_SCROLL);
meta_event_native_set_time_usec (event, time_us);
event->scroll.time = us2ms (time_us);
event->scroll.stage = CLUTTER_STAGE (stage);
meta_xkb_translate_state (event, seat->xkb, seat->button_state);
/* libinput pointer axis events are in pointer motion coordinate space.
* To convert to Xi2 discrete step coordinate space, multiply the factor
* 1/10. */
event->scroll.direction = CLUTTER_SCROLL_SMOOTH;
scroll_factor = 1.0 / DISCRETE_SCROLL_STEP;
clutter_event_set_scroll_delta (event,
scroll_factor * dx,
scroll_factor * dy);
event->scroll.x = seat->pointer_x;
event->scroll.y = seat->pointer_y;
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
event->scroll.scroll_source = scroll_source;
event->scroll.finish_flags = flags;
_clutter_event_set_pointer_emulated (event, emulated);
queue_event (event);
}
static void
notify_discrete_scroll (ClutterInputDevice *input_device,
uint64_t time_us,
ClutterScrollDirection direction,
ClutterScrollSource scroll_source,
gboolean emulated)
{
MetaInputDeviceNative *device_evdev;
MetaSeatNative *seat;
ClutterStage *stage;
ClutterEvent *event = NULL;
if (direction == CLUTTER_SCROLL_SMOOTH)
return;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (input_device);
if (stage == NULL)
return;
device_evdev = META_INPUT_DEVICE_NATIVE (input_device);
seat = meta_input_device_native_get_seat (device_evdev);
event = clutter_event_new (CLUTTER_SCROLL);
meta_event_native_set_time_usec (event, time_us);
event->scroll.time = us2ms (time_us);
event->scroll.stage = CLUTTER_STAGE (stage);
meta_xkb_translate_state (event, seat->xkb, seat->button_state);
event->scroll.direction = direction;
event->scroll.x = seat->pointer_x;
event->scroll.y = seat->pointer_y;
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
event->scroll.scroll_source = scroll_source;
_clutter_event_set_pointer_emulated (event, emulated);
queue_event (event);
}
static void
check_notify_discrete_scroll (MetaSeatNative *seat,
ClutterInputDevice *device,
uint64_t time_us,
ClutterScrollSource scroll_source)
{
int i, n_xscrolls, n_yscrolls;
n_xscrolls = floor (fabs (seat->accum_scroll_dx) / DISCRETE_SCROLL_STEP);
n_yscrolls = floor (fabs (seat->accum_scroll_dy) / DISCRETE_SCROLL_STEP);
for (i = 0; i < n_xscrolls; i++)
{
notify_discrete_scroll (device, time_us,
seat->accum_scroll_dx > 0 ?
CLUTTER_SCROLL_RIGHT : CLUTTER_SCROLL_LEFT,
scroll_source, TRUE);
}
for (i = 0; i < n_yscrolls; i++)
{
notify_discrete_scroll (device, time_us,
seat->accum_scroll_dy > 0 ?
CLUTTER_SCROLL_DOWN : CLUTTER_SCROLL_UP,
scroll_source, TRUE);
}
seat->accum_scroll_dx = fmodf (seat->accum_scroll_dx, DISCRETE_SCROLL_STEP);
seat->accum_scroll_dy = fmodf (seat->accum_scroll_dy, DISCRETE_SCROLL_STEP);
}
void
meta_seat_native_notify_scroll_continuous (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
double dx,
double dy,
ClutterScrollSource scroll_source,
ClutterScrollFinishFlags finish_flags)
{
if (finish_flags & CLUTTER_SCROLL_FINISHED_HORIZONTAL)
seat->accum_scroll_dx = 0;
else
seat->accum_scroll_dx += dx;
if (finish_flags & CLUTTER_SCROLL_FINISHED_VERTICAL)
seat->accum_scroll_dy = 0;
else
seat->accum_scroll_dy += dy;
notify_scroll (input_device, time_us, dx, dy, scroll_source,
finish_flags, FALSE);
check_notify_discrete_scroll (seat, input_device, time_us, scroll_source);
}
static ClutterScrollDirection
discrete_to_direction (double discrete_dx,
double discrete_dy)
{
if (discrete_dx > 0)
return CLUTTER_SCROLL_RIGHT;
else if (discrete_dx < 0)
return CLUTTER_SCROLL_LEFT;
else if (discrete_dy > 0)
return CLUTTER_SCROLL_DOWN;
else if (discrete_dy < 0)
return CLUTTER_SCROLL_UP;
else
g_assert_not_reached ();
return 0;
}
void
meta_seat_native_notify_discrete_scroll (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
double discrete_dx,
double discrete_dy,
ClutterScrollSource scroll_source)
{
notify_scroll (input_device, time_us,
discrete_dx * DISCRETE_SCROLL_STEP,
discrete_dy * DISCRETE_SCROLL_STEP,
scroll_source, CLUTTER_SCROLL_FINISHED_NONE,
TRUE);
notify_discrete_scroll (input_device, time_us,
discrete_to_direction (discrete_dx, discrete_dy),
scroll_source, FALSE);
}
void
meta_seat_native_notify_touch_event (MetaSeatNative *seat,
ClutterInputDevice *input_device,
ClutterEventType evtype,
uint64_t time_us,
int slot,
double x,
double y)
{
ClutterStage *stage;
ClutterEvent *event = NULL;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (input_device);
if (stage == NULL)
return;
event = clutter_event_new (evtype);
meta_event_native_set_time_usec (event, time_us);
event->touch.time = us2ms (time_us);
event->touch.stage = CLUTTER_STAGE (stage);
event->touch.x = x;
event->touch.y = y;
meta_input_device_native_translate_coordinates (input_device, stage,
&event->touch.x,
&event->touch.y);
/* "NULL" sequences are special cased in clutter */
event->touch.sequence = GINT_TO_POINTER (MAX (1, slot + 1));
meta_xkb_translate_state (event, seat->xkb, seat->button_state);
if (evtype == CLUTTER_TOUCH_BEGIN ||
evtype == CLUTTER_TOUCH_UPDATE)
event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
queue_event (event);
}
void
meta_seat_native_free (MetaSeatNative *seat)
{
GSList *iter;
for (iter = seat->devices; iter; iter = g_slist_next (iter))
{
ClutterInputDevice *device = iter->data;
g_object_unref (device);
}
g_slist_free (seat->devices);
g_free (seat->touch_states);
xkb_state_unref (seat->xkb);
meta_seat_native_clear_repeat_timer (seat);
if (seat->libinput_seat)
libinput_seat_unref (seat->libinput_seat);
g_free (seat);
}
ClutterInputDevice *
meta_seat_native_get_device (MetaSeatNative *seat,
int id)
{
ClutterInputDevice *device;
GSList *l;
for (l = seat->devices; l; l = l->next)
{
device = l->data;
if (clutter_input_device_get_device_id (device) == id)
return device;
}
return NULL;
}
void
meta_seat_native_set_stage (MetaSeatNative *seat,
ClutterStage *stage)
{
GSList *l;
_clutter_input_device_set_stage (seat->core_pointer, stage);
_clutter_input_device_set_stage (seat->core_keyboard, stage);
for (l = seat->devices; l; l = l->next)
{
ClutterInputDevice *device = l->data;
_clutter_input_device_set_stage (device, stage);
}
}