1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2010  Intel Corp.
7  * Copyright (C) 2014  Jonas Ådahl
8  * Copyright (C) 2016  Red Hat Inc.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22  *
23  * Author: Damien Lespiau <damien.lespiau@intel.com>
24  * Author: Jonas Ådahl <jadahl@gmail.com>
25  */
26 
27 #include "config.h"
28 
29 #include "backends/native/meta-seat-native.h"
30 
31 #include "backends/meta-cursor-tracker-private.h"
32 #include "backends/meta-keymap-utils.h"
33 #include "backends/native/meta-barrier-native.h"
34 #include "backends/native/meta-input-thread.h"
35 #include "backends/native/meta-keymap-native.h"
36 #include "backends/native/meta-virtual-input-device-native.h"
37 #include "clutter/clutter-mutter.h"
38 #include "core/bell.h"
39 
40 #include "meta-private-enum-types.h"
41 
42 enum
43 {
44   PROP_0,
45   PROP_SEAT_ID,
46   PROP_FLAGS,
47   PROP_BACKEND,
48   N_PROPS,
49 
50   /* This property is overridden */
51   PROP_TOUCH_MODE,
52 };
53 
54 static GParamSpec *props[N_PROPS] = { NULL };
55 
G_DEFINE_TYPE(MetaSeatNative,meta_seat_native,CLUTTER_TYPE_SEAT)56 G_DEFINE_TYPE (MetaSeatNative, meta_seat_native, CLUTTER_TYPE_SEAT)
57 
58 static gboolean
59 meta_seat_native_handle_event_post (ClutterSeat        *seat,
60                                     const ClutterEvent *event)
61 {
62   MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
63   ClutterInputDevice *device = clutter_event_get_source_device (event);
64   ClutterEventType event_type = event->type;
65 
66   if (event_type == CLUTTER_PROXIMITY_IN)
67     {
68       MetaCursorRenderer *cursor_renderer;
69 
70       if (!seat_native->tablet_cursors)
71         {
72           seat_native->tablet_cursors = g_hash_table_new_full (NULL, NULL, NULL,
73                                                                g_object_unref);
74         }
75 
76       cursor_renderer = meta_cursor_renderer_new (meta_get_backend (), device);
77       g_hash_table_insert (seat_native->tablet_cursors,
78                            device, cursor_renderer);
79       return TRUE;
80     }
81   else if (event_type == CLUTTER_PROXIMITY_OUT)
82     {
83       if (seat_native->tablet_cursors)
84         g_hash_table_remove (seat_native->tablet_cursors, device);
85       return TRUE;
86     }
87   else if (event_type == CLUTTER_DEVICE_ADDED)
88     {
89       if (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL)
90         seat_native->devices = g_list_prepend (seat_native->devices, g_object_ref (device));
91     }
92   else if (event_type == CLUTTER_DEVICE_REMOVED)
93     {
94       GList *l = g_list_find (seat_native->devices, device);
95 
96       if (l)
97         {
98           seat_native->devices = g_list_delete_link (seat_native->devices, l);
99           g_object_unref (device);
100         }
101     }
102 
103   return FALSE;
104 }
105 
106 static void
proxy_kbd_a11y_flags_changed(MetaSeatImpl * seat_impl,MetaKeyboardA11yFlags new_flags,MetaKeyboardA11yFlags what_changed,MetaSeatNative * seat_native)107 proxy_kbd_a11y_flags_changed (MetaSeatImpl          *seat_impl,
108                               MetaKeyboardA11yFlags  new_flags,
109                               MetaKeyboardA11yFlags  what_changed,
110                               MetaSeatNative        *seat_native)
111 {
112   g_signal_emit_by_name (seat_native,
113                          "kbd-a11y-flags-changed",
114                          new_flags, what_changed);
115 }
116 
117 static void
proxy_kbd_a11y_mods_state_changed(MetaSeatImpl * seat_impl,xkb_mod_mask_t new_latched_mods,xkb_mod_mask_t new_locked_mods,MetaSeatNative * seat_native)118 proxy_kbd_a11y_mods_state_changed (MetaSeatImpl   *seat_impl,
119                                    xkb_mod_mask_t  new_latched_mods,
120                                    xkb_mod_mask_t  new_locked_mods,
121                                    MetaSeatNative *seat_native)
122 {
123   g_signal_emit_by_name (seat_native,
124                          "kbd-a11y-mods-state-changed",
125                          new_latched_mods,
126                          new_locked_mods);
127 }
128 
129 static void
proxy_touch_mode_changed(MetaSeatImpl * seat_impl,gboolean enabled,MetaSeatNative * seat_native)130 proxy_touch_mode_changed (MetaSeatImpl   *seat_impl,
131                           gboolean        enabled,
132                           MetaSeatNative *seat_native)
133 {
134   seat_native->touch_mode = enabled;
135   g_object_notify (G_OBJECT (seat_native), "touch-mode");
136 }
137 
138 static void
proxy_bell(MetaSeatImpl * seat_impl,MetaSeatNative * seat_native)139 proxy_bell (MetaSeatImpl   *seat_impl,
140             MetaSeatNative *seat_native)
141 {
142   clutter_seat_bell_notify (CLUTTER_SEAT (seat_native));
143 }
144 
145 static void
proxy_mods_state_changed(MetaSeatImpl * seat_impl,ClutterSeat * seat)146 proxy_mods_state_changed (MetaSeatImpl   *seat_impl,
147                           ClutterSeat    *seat)
148 {
149   ClutterKeymap *keymap;
150 
151   keymap = clutter_seat_get_keymap (seat);
152   g_signal_emit_by_name (keymap, "state-changed");
153 }
154 
155 static void
meta_seat_native_constructed(GObject * object)156 meta_seat_native_constructed (GObject *object)
157 {
158   MetaSeatNative *seat = META_SEAT_NATIVE (object);
159 
160   seat->impl = meta_seat_impl_new (seat, seat->seat_id, seat->flags);
161   g_signal_connect (seat->impl, "kbd-a11y-flags-changed",
162                     G_CALLBACK (proxy_kbd_a11y_flags_changed), seat);
163   g_signal_connect (seat->impl, "kbd-a11y-mods-state-changed",
164                     G_CALLBACK (proxy_kbd_a11y_mods_state_changed), seat);
165   g_signal_connect (seat->impl, "touch-mode",
166                     G_CALLBACK (proxy_touch_mode_changed), seat);
167   g_signal_connect (seat->impl, "bell",
168                     G_CALLBACK (proxy_bell), seat);
169   g_signal_connect (seat->impl, "mods-state-changed",
170                     G_CALLBACK (proxy_mods_state_changed), seat);
171 
172   seat->core_pointer = meta_seat_impl_get_pointer (seat->impl);
173   seat->core_keyboard = meta_seat_impl_get_keyboard (seat->impl);
174 
175   meta_seat_native_set_keyboard_map (seat, "us", "", "");
176 
177   if (G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed)
178     G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed (object);
179 }
180 
181 static void
meta_seat_native_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)182 meta_seat_native_set_property (GObject      *object,
183                                guint         prop_id,
184                                const GValue *value,
185                                GParamSpec   *pspec)
186 {
187   MetaSeatNative *seat_native = META_SEAT_NATIVE (object);
188 
189   switch (prop_id)
190     {
191     case PROP_SEAT_ID:
192       seat_native->seat_id = g_value_dup_string (value);
193       break;
194     case PROP_FLAGS:
195       seat_native->flags = g_value_get_flags (value);
196       break;
197     case PROP_BACKEND:
198       seat_native->backend = g_value_get_object (value);
199       break;
200     case PROP_TOUCH_MODE:
201     default:
202       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
203     }
204 }
205 
206 static void
meta_seat_native_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)207 meta_seat_native_get_property (GObject    *object,
208                                guint       prop_id,
209                                GValue     *value,
210                                GParamSpec *pspec)
211 {
212   MetaSeatNative *seat_native = META_SEAT_NATIVE (object);
213 
214   switch (prop_id)
215     {
216     case PROP_SEAT_ID:
217       g_value_set_string (value, seat_native->seat_id);
218       break;
219     case PROP_TOUCH_MODE:
220       g_value_set_boolean (value, seat_native->touch_mode);
221       break;
222     case PROP_FLAGS:
223       g_value_set_flags (value, seat_native->flags);
224       break;
225     case PROP_BACKEND:
226       g_value_set_object (value, seat_native->backend);
227       break;
228     default:
229       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
230     }
231 }
232 
233 static void
meta_seat_native_dispose(GObject * object)234 meta_seat_native_dispose (GObject *object)
235 {
236   MetaSeatNative *seat = META_SEAT_NATIVE (object);
237 
238   g_clear_pointer (&seat->xkb_keymap, xkb_keymap_unref);
239   g_clear_object (&seat->core_pointer);
240   g_clear_object (&seat->core_keyboard);
241   g_clear_pointer (&seat->impl, meta_seat_impl_destroy);
242   g_list_free_full (g_steal_pointer (&seat->devices), g_object_unref);
243   g_clear_pointer (&seat->reserved_virtual_slots, g_hash_table_destroy);
244   g_clear_pointer (&seat->tablet_cursors, g_hash_table_unref);
245   g_clear_object (&seat->cursor_renderer);
246 
247   g_clear_pointer (&seat->seat_id, g_free);
248 
249   G_OBJECT_CLASS (meta_seat_native_parent_class)->dispose (object);
250 }
251 
252 static ClutterInputDevice *
meta_seat_native_get_pointer(ClutterSeat * seat)253 meta_seat_native_get_pointer (ClutterSeat *seat)
254 {
255   MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
256 
257   return seat_native->core_pointer;
258 }
259 
260 static ClutterInputDevice *
meta_seat_native_get_keyboard(ClutterSeat * seat)261 meta_seat_native_get_keyboard (ClutterSeat *seat)
262 {
263   MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
264 
265   return seat_native->core_keyboard;
266 }
267 
268 static const GList *
meta_seat_native_peek_devices(ClutterSeat * seat)269 meta_seat_native_peek_devices (ClutterSeat *seat)
270 {
271   MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
272 
273   return (const GList *) seat_native->devices;
274 }
275 
276 static void
meta_seat_native_bell_notify(ClutterSeat * seat)277 meta_seat_native_bell_notify (ClutterSeat *seat)
278 {
279   MetaDisplay *display = meta_get_display ();
280 
281   meta_bell_notify (display, NULL);
282 }
283 
284 static ClutterKeymap *
meta_seat_native_get_keymap(ClutterSeat * seat)285 meta_seat_native_get_keymap (ClutterSeat *seat)
286 {
287   MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
288 
289   if (!seat_native->keymap)
290     seat_native->keymap = meta_seat_impl_get_keymap (seat_native->impl);
291 
292   return CLUTTER_KEYMAP (seat_native->keymap);
293 }
294 
295 static guint
bump_virtual_touch_slot_base(MetaSeatNative * seat_native)296 bump_virtual_touch_slot_base (MetaSeatNative *seat_native)
297 {
298   while (TRUE)
299     {
300       if (seat_native->virtual_touch_slot_base < 0x100)
301         seat_native->virtual_touch_slot_base = 0x100;
302 
303       seat_native->virtual_touch_slot_base +=
304         CLUTTER_VIRTUAL_INPUT_DEVICE_MAX_TOUCH_SLOTS;
305 
306       if (!g_hash_table_lookup (seat_native->reserved_virtual_slots,
307                                 GUINT_TO_POINTER (seat_native->virtual_touch_slot_base)))
308         break;
309     }
310 
311   return seat_native->virtual_touch_slot_base;
312 }
313 
314 static ClutterVirtualInputDevice *
meta_seat_native_create_virtual_device(ClutterSeat * seat,ClutterInputDeviceType device_type)315 meta_seat_native_create_virtual_device (ClutterSeat            *seat,
316                                         ClutterInputDeviceType  device_type)
317 {
318   MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
319   guint slot_base;
320 
321   slot_base = bump_virtual_touch_slot_base (seat_native);
322   g_hash_table_add (seat_native->reserved_virtual_slots,
323                     GUINT_TO_POINTER (slot_base));
324 
325   return g_object_new (META_TYPE_VIRTUAL_INPUT_DEVICE_NATIVE,
326                        "seat", seat,
327                        "slot-base", slot_base,
328                        "device-type", device_type,
329                        NULL);
330 }
331 
332 void
meta_seat_native_release_touch_slots(MetaSeatNative * seat,guint base_slot)333 meta_seat_native_release_touch_slots (MetaSeatNative *seat,
334                                       guint           base_slot)
335 {
336   g_hash_table_remove (seat->reserved_virtual_slots,
337                        GUINT_TO_POINTER (base_slot));
338 }
339 
340 static ClutterVirtualDeviceType
meta_seat_native_get_supported_virtual_device_types(ClutterSeat * seat)341 meta_seat_native_get_supported_virtual_device_types (ClutterSeat *seat)
342 {
343   return (CLUTTER_VIRTUAL_DEVICE_TYPE_KEYBOARD |
344           CLUTTER_VIRTUAL_DEVICE_TYPE_POINTER |
345           CLUTTER_VIRTUAL_DEVICE_TYPE_TOUCHSCREEN);
346 }
347 
348 static void
meta_seat_native_warp_pointer(ClutterSeat * seat,int x,int y)349 meta_seat_native_warp_pointer (ClutterSeat *seat,
350                                int          x,
351                                int          y)
352 {
353   MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
354 
355   meta_seat_impl_warp_pointer (seat_native->impl, x, y);
356 }
357 
358 static gboolean
meta_seat_native_query_state(ClutterSeat * seat,ClutterInputDevice * device,ClutterEventSequence * sequence,graphene_point_t * coords,ClutterModifierType * modifiers)359 meta_seat_native_query_state (ClutterSeat          *seat,
360                               ClutterInputDevice   *device,
361                               ClutterEventSequence *sequence,
362                               graphene_point_t     *coords,
363                               ClutterModifierType  *modifiers)
364 {
365   MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
366 
367   return meta_seat_impl_query_state (seat_native->impl, device, sequence,
368                                      coords, modifiers);
369 }
370 
371 static void
meta_seat_native_class_init(MetaSeatNativeClass * klass)372 meta_seat_native_class_init (MetaSeatNativeClass *klass)
373 {
374   GObjectClass *object_class = G_OBJECT_CLASS (klass);
375   ClutterSeatClass *seat_class = CLUTTER_SEAT_CLASS (klass);
376 
377   object_class->constructed = meta_seat_native_constructed;
378   object_class->set_property = meta_seat_native_set_property;
379   object_class->get_property = meta_seat_native_get_property;
380   object_class->dispose = meta_seat_native_dispose;
381 
382   seat_class->get_pointer = meta_seat_native_get_pointer;
383   seat_class->get_keyboard = meta_seat_native_get_keyboard;
384   seat_class->peek_devices = meta_seat_native_peek_devices;
385   seat_class->bell_notify = meta_seat_native_bell_notify;
386   seat_class->get_keymap = meta_seat_native_get_keymap;
387   seat_class->create_virtual_device = meta_seat_native_create_virtual_device;
388   seat_class->get_supported_virtual_device_types = meta_seat_native_get_supported_virtual_device_types;
389   seat_class->warp_pointer = meta_seat_native_warp_pointer;
390   seat_class->handle_event_post = meta_seat_native_handle_event_post;
391   seat_class->query_state = meta_seat_native_query_state;
392 
393   props[PROP_SEAT_ID] =
394     g_param_spec_string ("seat-id",
395                          "Seat ID",
396                          "Seat ID",
397                          NULL,
398                          G_PARAM_READWRITE |
399                          G_PARAM_CONSTRUCT_ONLY);
400 
401   props[PROP_FLAGS] =
402     g_param_spec_flags ("flags",
403                         "Flags",
404                         "Flags",
405                         META_TYPE_SEAT_NATIVE_FLAG,
406                         META_SEAT_NATIVE_FLAG_NONE,
407                         G_PARAM_READWRITE |
408                         G_PARAM_CONSTRUCT_ONLY);
409 
410   props[PROP_BACKEND] =
411     g_param_spec_object ("backend",
412                          "Backend",
413                          "Backend",
414                          META_TYPE_BACKEND,
415                          G_PARAM_READWRITE |
416                          G_PARAM_CONSTRUCT_ONLY);
417 
418   g_object_class_install_properties (object_class, N_PROPS, props);
419 
420   g_object_class_override_property (object_class, PROP_TOUCH_MODE,
421                                     "touch-mode");
422 }
423 
424 static void
meta_seat_native_init(MetaSeatNative * seat)425 meta_seat_native_init (MetaSeatNative *seat)
426 {
427   seat->reserved_virtual_slots = g_hash_table_new (NULL, NULL);
428 }
429 
430 /**
431  * meta_seat_native_release_devices:
432  *
433  * Releases all the evdev devices that Clutter is currently managing. This api
434  * is typically used when switching away from the Clutter application when
435  * switching tty. The devices can be reclaimed later with a call to
436  * meta_seat_native_reclaim_devices().
437  *
438  * This function should only be called after clutter has been initialized.
439  */
440 void
meta_seat_native_release_devices(MetaSeatNative * seat)441 meta_seat_native_release_devices (MetaSeatNative *seat)
442 {
443   g_return_if_fail (META_IS_SEAT_NATIVE (seat));
444 
445   if (seat->released)
446     {
447       g_warning ("meta_seat_native_release_devices() shouldn't be called "
448                  "multiple times without a corresponding call to "
449                  "meta_seat_native_reclaim_devices() first");
450       return;
451     }
452 
453   meta_seat_impl_release_devices (seat->impl);
454   seat->released = TRUE;
455 }
456 
457 /**
458  * meta_seat_native_reclaim_devices:
459  *
460  * This causes Clutter to re-probe for evdev devices. This is must only be
461  * called after a corresponding call to meta_seat_native_release_devices()
462  * was previously used to release all evdev devices. This API is typically
463  * used when a clutter application using evdev has regained focus due to
464  * switching ttys.
465  *
466  * This function should only be called after clutter has been initialized.
467  */
468 void
meta_seat_native_reclaim_devices(MetaSeatNative * seat)469 meta_seat_native_reclaim_devices (MetaSeatNative *seat)
470 {
471   if (!seat->released)
472     {
473       g_warning ("Spurious call to meta_seat_native_reclaim_devices() without "
474                  "previous call to meta_seat_native_release_devices");
475       return;
476     }
477 
478   meta_seat_impl_reclaim_devices (seat->impl);
479   seat->released = FALSE;
480 }
481 
482 static struct xkb_keymap *
create_keymap(const char * layouts,const char * variants,const char * options)483 create_keymap (const char *layouts,
484                const char *variants,
485                const char *options)
486 {
487   struct xkb_rule_names names;
488   struct xkb_keymap *keymap;
489   struct xkb_context *context;
490 
491   names.rules = DEFAULT_XKB_RULES_FILE;
492   names.model = DEFAULT_XKB_MODEL;
493   names.layout = layouts;
494   names.variant = variants;
495   names.options = options;
496 
497   context = meta_create_xkb_context ();
498   keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
499   xkb_context_unref (context);
500 
501   return keymap;
502 }
503 
504 /**
505  * meta_seat_native_set_keyboard_map: (skip)
506  * @seat: the #ClutterSeat created by the evdev backend
507  * @keymap: the new keymap
508  *
509  * Instructs @evdev to use the specified keyboard map. This will cause
510  * the backend to drop the state and create a new one with the new
511  * map. To avoid state being lost, callers should ensure that no key
512  * is pressed when calling this function.
513  */
514 void
meta_seat_native_set_keyboard_map(MetaSeatNative * seat,const char * layouts,const char * variants,const char * options)515 meta_seat_native_set_keyboard_map (MetaSeatNative *seat,
516                                    const char     *layouts,
517                                    const char     *variants,
518                                    const char     *options)
519 {
520   struct xkb_keymap *keymap, *impl_keymap;
521 
522   keymap = create_keymap (layouts, variants, options);
523   impl_keymap = create_keymap (layouts, variants, options);
524 
525   if (keymap == NULL)
526     {
527       g_warning ("Unable to load configured keymap: rules=%s, model=%s, layout=%s, variant=%s, options=%s",
528                  DEFAULT_XKB_RULES_FILE, DEFAULT_XKB_MODEL, layouts,
529                  variants, options);
530       return;
531     }
532 
533   if (seat->xkb_keymap)
534     xkb_keymap_unref (seat->xkb_keymap);
535   seat->xkb_keymap = keymap;
536 
537   meta_seat_impl_set_keyboard_map (seat->impl, impl_keymap);
538   xkb_keymap_unref (impl_keymap);
539 }
540 
541 /**
542  * meta_seat_native_get_keyboard_map: (skip)
543  * @seat: the #ClutterSeat created by the evdev backend
544  *
545  * Retrieves the #xkb_keymap in use by the evdev backend.
546  *
547  * Return value: the #xkb_keymap.
548  */
549 struct xkb_keymap *
meta_seat_native_get_keyboard_map(MetaSeatNative * seat)550 meta_seat_native_get_keyboard_map (MetaSeatNative *seat)
551 {
552   g_return_val_if_fail (META_IS_SEAT_NATIVE (seat), NULL);
553 
554   return seat->xkb_keymap;
555 }
556 
557 /**
558  * meta_seat_native_set_keyboard_layout_index: (skip)
559  * @seat: the #ClutterSeat created by the evdev backend
560  * @idx: the xkb layout index to set
561  *
562  * Sets the xkb layout index on the backend's #xkb_state .
563  */
564 void
meta_seat_native_set_keyboard_layout_index(MetaSeatNative * seat,xkb_layout_index_t idx)565 meta_seat_native_set_keyboard_layout_index (MetaSeatNative     *seat,
566                                             xkb_layout_index_t  idx)
567 {
568   g_return_if_fail (META_IS_SEAT_NATIVE (seat));
569 
570   seat->xkb_layout_index = idx;
571   meta_seat_impl_set_keyboard_layout_index (seat->impl, idx);
572 }
573 
574 /**
575  * meta_seat_native_get_keyboard_layout_index: (skip)
576  */
577 xkb_layout_index_t
meta_seat_native_get_keyboard_layout_index(MetaSeatNative * seat)578 meta_seat_native_get_keyboard_layout_index (MetaSeatNative *seat)
579 {
580   return seat->xkb_layout_index;
581 }
582 
583 MetaBarrierManagerNative *
meta_seat_native_get_barrier_manager(MetaSeatNative * seat)584 meta_seat_native_get_barrier_manager (MetaSeatNative *seat)
585 {
586   return meta_seat_impl_get_barrier_manager (seat->impl);
587 }
588 
589 MetaBackend *
meta_seat_native_get_backend(MetaSeatNative * seat_native)590 meta_seat_native_get_backend (MetaSeatNative *seat_native)
591 {
592   return seat_native->backend;
593 }
594 
595 void
meta_seat_native_set_pointer_constraint(MetaSeatNative * seat,MetaPointerConstraintImpl * constraint_impl)596 meta_seat_native_set_pointer_constraint (MetaSeatNative            *seat,
597                                          MetaPointerConstraintImpl *constraint_impl)
598 {
599   meta_seat_impl_set_pointer_constraint (seat->impl, constraint_impl);
600 }
601 
602 MetaCursorRenderer *
meta_seat_native_maybe_ensure_cursor_renderer(MetaSeatNative * seat_native,ClutterInputDevice * device)603 meta_seat_native_maybe_ensure_cursor_renderer (MetaSeatNative     *seat_native,
604                                                ClutterInputDevice *device)
605 {
606   if (device == seat_native->core_pointer)
607     {
608       if (!seat_native->cursor_renderer)
609         {
610           MetaCursorRendererNative *cursor_renderer_native;
611 
612           cursor_renderer_native =
613             meta_cursor_renderer_native_new (meta_get_backend (),
614                                              seat_native->core_pointer);
615           seat_native->cursor_renderer =
616             META_CURSOR_RENDERER (cursor_renderer_native);
617         }
618 
619       return seat_native->cursor_renderer;
620     }
621 
622   if (seat_native->tablet_cursors &&
623       clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE)
624     return g_hash_table_lookup (seat_native->tablet_cursors, device);
625 
626   return NULL;
627 }
628 
629 void
meta_seat_native_set_viewports(MetaSeatNative * seat,MetaViewportInfo * viewports)630 meta_seat_native_set_viewports (MetaSeatNative   *seat,
631                                 MetaViewportInfo *viewports)
632 {
633   meta_seat_impl_set_viewports (seat->impl, viewports);
634 }
635