358 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			358 lines
		
	
	
		
			10 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 "gdkdeviceprivate.h"
 | 
						|
 | 
						|
typedef struct _GdkSeatDefaultPrivate GdkSeatDefaultPrivate;
 | 
						|
 | 
						|
struct _GdkSeatDefaultPrivate
 | 
						|
{
 | 
						|
  GdkDevice *master_pointer;
 | 
						|
  GdkDevice *master_keyboard;
 | 
						|
  GList *slave_pointers;
 | 
						|
  GList *slave_keyboards;
 | 
						|
  GdkSeatCapabilities capabilities;
 | 
						|
};
 | 
						|
 | 
						|
#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)
 | 
						|
 | 
						|
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);
 | 
						|
    }
 | 
						|
 | 
						|
  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;
 | 
						|
 | 
						|
  priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
 | 
						|
 | 
						|
  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)
 | 
						|
    {
 | 
						|
      status = gdk_device_grab (priv->master_pointer, window,
 | 
						|
                                GDK_OWNERSHIP_NONE, owner_events,
 | 
						|
                                POINTER_EVENTS, 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);
 | 
						|
          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 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;
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
    }
 | 
						|
  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);
 | 
						|
    }
 | 
						|
}
 |