449 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			449 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GDK - The GIMP Drawing Kit
 | |
|  * Copyright (C) 2015 Red Hat
 | |
|  *
 | |
|  * 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: Carlos Garnacho <carlosg@gnome.org>
 | |
|  */
 | |
| 
 | |
| #include "gdkseatdefaultprivate.h"
 | |
| #include "gdkdevicetoolprivate.h"
 | |
| 
 | |
| typedef struct _GdkSeatDefaultPrivate GdkSeatDefaultPrivate;
 | |
| 
 | |
| struct _GdkSeatDefaultPrivate
 | |
| {
 | |
|   GdkDevice *master_pointer;
 | |
|   GdkDevice *master_keyboard;
 | |
|   GList *slave_pointers;
 | |
|   GList *slave_keyboards;
 | |
|   GdkSeatCapabilities capabilities;
 | |
| 
 | |
|   GPtrArray *tools;
 | |
| };
 | |
| 
 | |
| #define KEYBOARD_EVENTS (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |    \
 | |
|                          GDK_FOCUS_CHANGE_MASK)
 | |
| #define TOUCH_EVENTS    (GDK_TOUCH_MASK)
 | |
| #define POINTER_EVENTS  (GDK_POINTER_MOTION_MASK |                      \
 | |
|                          GDK_BUTTON_PRESS_MASK |                        \
 | |
|                          GDK_BUTTON_RELEASE_MASK |                      \
 | |
|                          GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK |     \
 | |
|                          GDK_ENTER_NOTIFY_MASK |                        \
 | |
|                          GDK_LEAVE_NOTIFY_MASK |                        \
 | |
|                          GDK_PROXIMITY_IN_MASK |                        \
 | |
|                          GDK_PROXIMITY_OUT_MASK |                       \
 | |
|                          GDK_TOUCHPAD_GESTURE_MASK)
 | |
| 
 | |
| G_DEFINE_TYPE_WITH_PRIVATE (GdkSeatDefault, gdk_seat_default, GDK_TYPE_SEAT)
 | |
| 
 | |
| static void
 | |
| gdk_seat_dispose (GObject *object)
 | |
| {
 | |
|   GdkSeatDefault *seat = GDK_SEAT_DEFAULT (object);
 | |
|   GdkSeatDefaultPrivate *priv = gdk_seat_default_get_instance_private (seat);
 | |
|   GList *l;
 | |
| 
 | |
|   if (priv->master_pointer)
 | |
|     {
 | |
|       gdk_seat_device_removed (GDK_SEAT (seat), priv->master_pointer);
 | |
|       g_clear_object (&priv->master_pointer);
 | |
|     }
 | |
| 
 | |
|   if (priv->master_keyboard)
 | |
|     {
 | |
|       gdk_seat_device_removed (GDK_SEAT (seat), priv->master_keyboard);
 | |
|       g_clear_object (&priv->master_pointer);
 | |
|     }
 | |
| 
 | |
|   for (l = priv->slave_pointers; l; l = l->next)
 | |
|     {
 | |
|       gdk_seat_device_removed (GDK_SEAT (seat), l->data);
 | |
|       g_object_unref (l->data);
 | |
|     }
 | |
| 
 | |
|   for (l = priv->slave_keyboards; l; l = l->next)
 | |
|     {
 | |
|       gdk_seat_device_removed (GDK_SEAT (seat), l->data);
 | |
|       g_object_unref (l->data);
 | |
|     }
 | |
| 
 | |
|   if (priv->tools)
 | |
|     {
 | |
|       g_ptr_array_unref (priv->tools);
 | |
|       priv->tools = NULL;
 | |
|     }
 | |
| 
 | |
|   g_list_free (priv->slave_pointers);
 | |
|   g_list_free (priv->slave_keyboards);
 | |
|   priv->slave_pointers = NULL;
 | |
|   priv->slave_keyboards = NULL;
 | |
| 
 | |
|   G_OBJECT_CLASS (gdk_seat_default_parent_class)->dispose (object);
 | |
| }
 | |
| 
 | |
| static GdkSeatCapabilities
 | |
| gdk_seat_default_get_capabilities (GdkSeat *seat)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
 | |
| 
 | |
|   return priv->capabilities;
 | |
| }
 | |
| 
 | |
| static GdkGrabStatus
 | |
| gdk_seat_default_grab (GdkSeat                *seat,
 | |
|                        GdkWindow              *window,
 | |
|                        GdkSeatCapabilities     capabilities,
 | |
|                        gboolean                owner_events,
 | |
|                        GdkCursor              *cursor,
 | |
|                        const GdkEvent         *event,
 | |
|                        GdkSeatGrabPrepareFunc  prepare_func,
 | |
|                        gpointer                prepare_func_data)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
|   guint32 evtime = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME;
 | |
|   GdkGrabStatus status = GDK_GRAB_SUCCESS;
 | |
|   gboolean was_visible;
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
 | |
|   was_visible = gdk_window_is_visible (window);
 | |
| 
 | |
|   if (prepare_func)
 | |
|     (prepare_func) (seat, window, prepare_func_data);
 | |
| 
 | |
|   if (!gdk_window_is_visible (window))
 | |
|     {
 | |
|       g_critical ("Window %p has not been made visible in GdkSeatGrabPrepareFunc",
 | |
|                   window);
 | |
|       return GDK_GRAB_NOT_VIEWABLE;
 | |
|     }
 | |
| 
 | |
|   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
 | |
| 
 | |
|   if (capabilities & GDK_SEAT_CAPABILITY_ALL_POINTING)
 | |
|     {
 | |
|       /* ALL_POINTING spans 3 capabilities; get the mask for the ones we have */
 | |
|       GdkEventMask pointer_evmask = 0;
 | |
| 
 | |
|       /* We let tablet styli take over the pointer cursor */
 | |
|       if (capabilities & (GDK_SEAT_CAPABILITY_POINTER |
 | |
|                           GDK_SEAT_CAPABILITY_TABLET_STYLUS))
 | |
|         {
 | |
|           pointer_evmask |= POINTER_EVENTS;
 | |
|         }
 | |
| 
 | |
|       if (capabilities & GDK_SEAT_CAPABILITY_TOUCH)
 | |
|         pointer_evmask |= TOUCH_EVENTS;
 | |
| 
 | |
|       status = gdk_device_grab (priv->master_pointer, window,
 | |
|                                 GDK_OWNERSHIP_NONE, owner_events,
 | |
|                                 pointer_evmask, cursor,
 | |
|                                 evtime);
 | |
|     }
 | |
| 
 | |
|   if (status == GDK_GRAB_SUCCESS &&
 | |
|       capabilities & GDK_SEAT_CAPABILITY_KEYBOARD)
 | |
|     {
 | |
|       status = gdk_device_grab (priv->master_keyboard, window,
 | |
|                                 GDK_OWNERSHIP_NONE, owner_events,
 | |
|                                 KEYBOARD_EVENTS, cursor,
 | |
|                                 evtime);
 | |
| 
 | |
|       if (status != GDK_GRAB_SUCCESS)
 | |
|         {
 | |
|           if (capabilities & ~GDK_SEAT_CAPABILITY_KEYBOARD)
 | |
|             gdk_device_ungrab (priv->master_pointer, evtime);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   if (status != GDK_GRAB_SUCCESS && !was_visible)
 | |
|     gdk_window_hide (window);
 | |
| 
 | |
|   G_GNUC_END_IGNORE_DEPRECATIONS;
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_seat_default_ungrab (GdkSeat *seat)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
 | |
| 
 | |
|   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
 | |
|   gdk_device_ungrab (priv->master_pointer, GDK_CURRENT_TIME);
 | |
|   gdk_device_ungrab (priv->master_keyboard, GDK_CURRENT_TIME);
 | |
|   G_GNUC_END_IGNORE_DEPRECATIONS;
 | |
| }
 | |
| 
 | |
| static GdkDevice *
 | |
| gdk_seat_default_get_master (GdkSeat             *seat,
 | |
|                              GdkSeatCapabilities  capability)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
 | |
| 
 | |
|   /* There must be only one flag set */
 | |
|   switch (capability)
 | |
|     {
 | |
|     case GDK_SEAT_CAPABILITY_POINTER:
 | |
|     case GDK_SEAT_CAPABILITY_TOUCH:
 | |
|       return priv->master_pointer;
 | |
|     case GDK_SEAT_CAPABILITY_KEYBOARD:
 | |
|       return priv->master_keyboard;
 | |
|     default:
 | |
|       g_warning ("Unhandled capability %x", capability);
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static GdkSeatCapabilities
 | |
| device_get_capability (GdkDevice *device)
 | |
| {
 | |
|   GdkInputSource source;
 | |
| 
 | |
|   source = gdk_device_get_source (device);
 | |
| 
 | |
|   switch (source)
 | |
|     {
 | |
|     case GDK_SOURCE_KEYBOARD:
 | |
|       return GDK_SEAT_CAPABILITY_KEYBOARD;
 | |
|     case GDK_SOURCE_TOUCHSCREEN:
 | |
|       return GDK_SEAT_CAPABILITY_TOUCH;
 | |
|     case GDK_SOURCE_MOUSE:
 | |
|     case GDK_SOURCE_TOUCHPAD:
 | |
|     default:
 | |
|       return GDK_SEAT_CAPABILITY_POINTER;
 | |
|     }
 | |
| 
 | |
|   return GDK_SEAT_CAPABILITY_NONE;
 | |
| }
 | |
| 
 | |
| static GList *
 | |
| append_filtered (GList               *list,
 | |
|                  GList               *devices,
 | |
|                  GdkSeatCapabilities  capabilities)
 | |
| {
 | |
|   GList *l;
 | |
| 
 | |
|   for (l = devices; l; l = l->next)
 | |
|     {
 | |
|       GdkSeatCapabilities device_cap;
 | |
| 
 | |
|       device_cap = device_get_capability (l->data);
 | |
| 
 | |
|       if ((device_cap & capabilities) != 0)
 | |
|         list = g_list_prepend (list, l->data);
 | |
|     }
 | |
| 
 | |
|   return list;
 | |
| }
 | |
| 
 | |
| static GList *
 | |
| gdk_seat_default_get_slaves (GdkSeat             *seat,
 | |
|                              GdkSeatCapabilities  capabilities)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
|   GList *devices = NULL;
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
 | |
| 
 | |
|   if (capabilities & (GDK_SEAT_CAPABILITY_POINTER | GDK_SEAT_CAPABILITY_TOUCH))
 | |
|     devices = append_filtered (devices, priv->slave_pointers, capabilities);
 | |
| 
 | |
|   if (capabilities & GDK_SEAT_CAPABILITY_KEYBOARD)
 | |
|     devices = append_filtered (devices, priv->slave_keyboards, capabilities);
 | |
| 
 | |
|   return devices;
 | |
| }
 | |
| 
 | |
| static GdkDeviceTool *
 | |
| gdk_seat_default_get_tool (GdkSeat *seat,
 | |
|                            guint64  serial,
 | |
|                            guint64  hw_id)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
|   GdkDeviceTool *tool;
 | |
|   guint i;
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
 | |
| 
 | |
|   if (!priv->tools)
 | |
|     return NULL;
 | |
| 
 | |
|   for (i = 0; i < priv->tools->len; i++)
 | |
|     {
 | |
|       tool = g_ptr_array_index (priv->tools, i);
 | |
| 
 | |
|       if (tool->serial == serial && tool->hw_id == hw_id)
 | |
|         return tool;
 | |
|     }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_seat_default_class_init (GdkSeatDefaultClass *klass)
 | |
| {
 | |
|   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | |
|   GdkSeatClass *seat_class = GDK_SEAT_CLASS (klass);
 | |
| 
 | |
|   object_class->dispose = gdk_seat_dispose;
 | |
| 
 | |
|   seat_class->get_capabilities = gdk_seat_default_get_capabilities;
 | |
| 
 | |
|   seat_class->grab = gdk_seat_default_grab;
 | |
|   seat_class->ungrab = gdk_seat_default_ungrab;
 | |
| 
 | |
|   seat_class->get_master = gdk_seat_default_get_master;
 | |
|   seat_class->get_slaves = gdk_seat_default_get_slaves;
 | |
| 
 | |
|   seat_class->get_tool = gdk_seat_default_get_tool;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_seat_default_init (GdkSeatDefault *seat)
 | |
| {
 | |
| }
 | |
| 
 | |
| GdkSeat *
 | |
| gdk_seat_default_new_for_master_pair (GdkDevice *pointer,
 | |
|                                       GdkDevice *keyboard)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
|   GdkDisplay *display;
 | |
|   GdkSeat *seat;
 | |
| 
 | |
|   display = gdk_device_get_display (pointer);
 | |
| 
 | |
|   seat = g_object_new (GDK_TYPE_SEAT_DEFAULT,
 | |
|                        "display", display,
 | |
|                        NULL);
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
 | |
|   priv->master_pointer = g_object_ref (pointer);
 | |
|   priv->master_keyboard = g_object_ref (keyboard);
 | |
| 
 | |
|   gdk_seat_device_added (seat, priv->master_pointer);
 | |
|   gdk_seat_device_added (seat, priv->master_keyboard);
 | |
| 
 | |
|   return seat;
 | |
| }
 | |
| 
 | |
| void
 | |
| gdk_seat_default_add_slave (GdkSeatDefault *seat,
 | |
|                             GdkDevice      *device)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
|   GdkSeatCapabilities capability;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_SEAT_DEFAULT (seat));
 | |
|   g_return_if_fail (GDK_IS_DEVICE (device));
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (seat);
 | |
|   capability = device_get_capability (device);
 | |
| 
 | |
|   if (capability & (GDK_SEAT_CAPABILITY_POINTER | GDK_SEAT_CAPABILITY_TOUCH))
 | |
|     priv->slave_pointers = g_list_prepend (priv->slave_pointers, g_object_ref (device));
 | |
|   else if (capability & GDK_SEAT_CAPABILITY_KEYBOARD)
 | |
|     priv->slave_keyboards = g_list_prepend (priv->slave_keyboards, g_object_ref (device));
 | |
|   else
 | |
|     {
 | |
|       g_critical ("Unhandled capability %x for device '%s'",
 | |
|                   capability, gdk_device_get_name (device));
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   priv->capabilities |= capability;
 | |
| 
 | |
|   gdk_seat_device_added (GDK_SEAT (seat), device);
 | |
| }
 | |
| 
 | |
| void
 | |
| gdk_seat_default_remove_slave (GdkSeatDefault *seat,
 | |
|                                GdkDevice      *device)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
|   GList *l;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_SEAT_DEFAULT (seat));
 | |
|   g_return_if_fail (GDK_IS_DEVICE (device));
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (seat);
 | |
| 
 | |
|   if (g_list_find (priv->slave_pointers, device))
 | |
|     {
 | |
|       priv->slave_pointers = g_list_remove (priv->slave_pointers, device);
 | |
| 
 | |
|       priv->capabilities &= ~(GDK_SEAT_CAPABILITY_POINTER | GDK_SEAT_CAPABILITY_TOUCH);
 | |
|       for (l = priv->slave_pointers; l; l = l->next)
 | |
|         priv->capabilities |= device_get_capability (GDK_DEVICE (l->data));
 | |
| 
 | |
|       gdk_seat_device_removed (GDK_SEAT (seat), device);
 | |
|       g_object_unref (device);
 | |
|     }
 | |
|   else if (g_list_find (priv->slave_keyboards, device))
 | |
|     {
 | |
|       priv->slave_keyboards = g_list_remove (priv->slave_keyboards, device);
 | |
| 
 | |
|       if (priv->slave_keyboards == NULL)
 | |
|         priv->capabilities &= ~GDK_SEAT_CAPABILITY_KEYBOARD;
 | |
| 
 | |
|       gdk_seat_device_removed (GDK_SEAT (seat), device);
 | |
|       g_object_unref (device);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| gdk_seat_default_add_tool (GdkSeatDefault *seat,
 | |
|                            GdkDeviceTool  *tool)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_SEAT_DEFAULT (seat));
 | |
|   g_return_if_fail (tool != NULL);
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (seat);
 | |
| 
 | |
|   if (!priv->tools)
 | |
|     priv->tools = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
 | |
| 
 | |
|   g_ptr_array_add (priv->tools, g_object_ref (tool));
 | |
|   g_signal_emit_by_name (seat, "tool-added", tool);
 | |
| }
 | |
| 
 | |
| void
 | |
| gdk_seat_default_remove_tool (GdkSeatDefault *seat,
 | |
|                               GdkDeviceTool  *tool)
 | |
| {
 | |
|   GdkSeatDefaultPrivate *priv;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_SEAT_DEFAULT (seat));
 | |
|   g_return_if_fail (tool != NULL);
 | |
| 
 | |
|   priv = gdk_seat_default_get_instance_private (seat);
 | |
| 
 | |
|   if (tool != gdk_seat_get_tool (GDK_SEAT (seat), tool->serial, tool->hw_id))
 | |
|     return;
 | |
| 
 | |
|   g_signal_emit_by_name (seat, "tool-removed", tool);
 | |
|   g_ptr_array_remove (priv->tools, tool);
 | |
| }
 | 
