diff --git a/gdk/Makefile.am b/gdk/Makefile.am index f3ce6b9441..bb0007afa8 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -114,6 +114,7 @@ gdk_private_headers = \ gdkglcontextprivate.h \ gdkscreenprivate.h \ gdkseatprivate.h \ + gdkseatdefaultprivate.h \ gdkinternals.h \ gdkintl.h \ gdkkeysprivate.h \ @@ -153,6 +154,7 @@ gdk_c_sources = \ gdkrgba.c \ gdkscreen.c \ gdkseat.c \ + gdkseatdefault.c \ gdkselection.c \ gdkvisual.c \ gdkwindow.c \ diff --git a/gdk/gdkseatdefault.c b/gdk/gdkseatdefault.c new file mode 100644 index 0000000000..9b517690cd --- /dev/null +++ b/gdk/gdkseatdefault.c @@ -0,0 +1,341 @@ +/* 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 . + * + * Author: Carlos Garnacho + */ + +#include "gdkseatdefaultprivate.h" +#include "gdkdeviceprivate.h" + +typedef struct _GdkSeatDefaultPrivate GdkSeatDefaultPrivate; + +struct _GdkSeatDefaultPrivate +{ + GdkDevice *master_pointer; + GdkDevice *master_keyboard; + GList *slave_pointers; + GList *slave_keyboards; +}; + +#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) +{ + /* FIXME */ + return GDK_SEAT_CAPABILITY_NONE; +} + +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\n", 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; + } + + gdk_seat_device_added (GDK_SEAT (seat), device); +} + +void +gdk_seat_default_remove_slave (GdkSeatDefault *seat, + GdkDevice *device) +{ + GdkSeatDefaultPrivate *priv; + + 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); + 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); + gdk_seat_device_removed (GDK_SEAT (seat), device); + } +} diff --git a/gdk/gdkseatdefaultprivate.h b/gdk/gdkseatdefaultprivate.h new file mode 100644 index 0000000000..727bcc1b1e --- /dev/null +++ b/gdk/gdkseatdefaultprivate.h @@ -0,0 +1,56 @@ +/* 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 . + * + * Author: Carlos Garnacho + */ + +#ifndef __GDK_SEAT_DEFAULT_PRIVATE_H__ +#define __GDK_SEAT_DEFAULT_PRIVATE_H__ + +#include "gdkseat.h" +#include "gdkseatprivate.h" + +#define GDK_TYPE_SEAT_DEFAULT (gdk_seat_default_get_type ()) +#define GDK_SEAT_DEFAULT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_SEAT_DEFAULT, GdkSeatDefault)) +#define GDK_IS_SEAT_DEFAULT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_SEAT_DEFAULT)) +#define GDK_SEAT_DEFAULT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_SEAT_DEFAULT, GdkSeatDefaultClass)) +#define GDK_IS_SEAT_DEFAULT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_SEAT_DEFAULT)) +#define GDK_SEAT_DEFAULT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_SEAT_DEFAULT, GdkSeatDefaultClass)) + +typedef struct _GdkSeatDefault GdkSeatDefault; +typedef struct _GdkSeatDefaultClass GdkSeatDefaultClass; + +struct _GdkSeatDefault +{ + GdkSeat parent_instance; +}; + +struct _GdkSeatDefaultClass +{ + GdkSeatClass parent_class; +}; + +GType gdk_seat_default_get_type (void) G_GNUC_CONST; + +GdkSeat * gdk_seat_default_new_for_master_pair (GdkDevice *pointer, + GdkDevice *keyboard); + +void gdk_seat_default_add_slave (GdkSeatDefault *seat, + GdkDevice *device); +void gdk_seat_default_remove_slave (GdkSeatDefault *seat, + GdkDevice *device); + +#endif /* __GDK_SEAT_DEFAULT_PRIVATE_H__ */