summaryrefslogtreecommitdiff
path: root/gdk/x11/gdkdevice-xi.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2010-05-25 18:38:44 -0400
committerMatthias Clasen <mclasen@redhat.com>2010-05-25 18:38:44 -0400
commitbd4609b14042a91646cd9057764eecfbc6faf42b (patch)
tree8721405d2b45a998f87cccc672b4070780907fb8 /gdk/x11/gdkdevice-xi.c
parenta538f639b69a39d7bb85b39af2dfd296d28fc0aa (diff)
downloadgtk+-bd4609b14042a91646cd9057764eecfbc6faf42b.tar.gz
Merge the xi2-for-master branch
Diffstat (limited to 'gdk/x11/gdkdevice-xi.c')
-rw-r--r--gdk/x11/gdkdevice-xi.c624
1 files changed, 624 insertions, 0 deletions
diff --git a/gdk/x11/gdkdevice-xi.c b/gdk/x11/gdkdevice-xi.c
new file mode 100644
index 0000000000..b82ff18002
--- /dev/null
+++ b/gdk/x11/gdkdevice-xi.c
@@ -0,0 +1,624 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <gdk/gdkwindow.h>
+#include "gdkdeviceprivate.h"
+#include "gdkdevice-xi.h"
+#include "gdkprivate-x11.h"
+#include "gdkintl.h"
+#include "gdkx.h"
+
+#define MAX_DEVICE_CLASSES 13
+
+static GQuark quark_window_input_info = 0;
+
+typedef struct
+{
+ gdouble root_x;
+ gdouble root_y;
+} GdkWindowInputInfo;
+
+static void gdk_device_xi_constructed (GObject *object);
+static void gdk_device_xi_dispose (GObject *object);
+
+static void gdk_device_xi_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdk_device_xi_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static gboolean gdk_device_xi_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events);
+
+static void gdk_device_xi_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask);
+static void gdk_device_xi_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor);
+static void gdk_device_xi_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y);
+static gboolean gdk_device_xi_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask);
+static GdkGrabStatus gdk_device_xi_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_);
+static void gdk_device_xi_ungrab (GdkDevice *device,
+ guint32 time_);
+
+static GdkWindow* gdk_device_xi_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel);
+
+static void gdk_device_xi_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask mask);
+
+
+G_DEFINE_TYPE (GdkDeviceXI, gdk_device_xi, GDK_TYPE_DEVICE)
+
+enum {
+ PROP_0,
+ PROP_DEVICE_ID
+};
+
+static void
+gdk_device_xi_class_init (GdkDeviceXIClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+ quark_window_input_info = g_quark_from_static_string ("gdk-window-input-info");
+
+ object_class->constructed = gdk_device_xi_constructed;
+ object_class->set_property = gdk_device_xi_set_property;
+ object_class->get_property = gdk_device_xi_get_property;
+ object_class->dispose = gdk_device_xi_dispose;
+
+ device_class->get_history = gdk_device_xi_get_history;
+ device_class->get_state = gdk_device_xi_get_state;
+ device_class->set_window_cursor = gdk_device_xi_set_window_cursor;
+ device_class->warp = gdk_device_xi_warp;
+ device_class->query_state = gdk_device_xi_query_state;
+ device_class->grab = gdk_device_xi_grab;
+ device_class->ungrab = gdk_device_xi_ungrab;
+ device_class->window_at_position = gdk_device_xi_window_at_position;
+ device_class->select_window_events = gdk_device_xi_select_window_events;
+
+ g_object_class_install_property (object_class,
+ PROP_DEVICE_ID,
+ g_param_spec_int ("device-id",
+ P_("Device ID"),
+ P_("Device ID"),
+ 0, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gdk_device_xi_init (GdkDeviceXI *device)
+{
+}
+
+static void
+gdk_device_xi_constructed (GObject *object)
+{
+ GdkDeviceXI *device;
+ GdkDisplay *display;
+
+ device = GDK_DEVICE_XI (object);
+ display = gdk_device_get_display (GDK_DEVICE (object));
+
+ gdk_error_trap_push ();
+ device->xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (display),
+ device->device_id);
+
+ if (gdk_error_trap_pop ())
+ g_warning ("Device %s can't be opened", GDK_DEVICE (device)->name);
+
+ if (G_OBJECT_CLASS (gdk_device_xi_parent_class)->constructed)
+ G_OBJECT_CLASS (gdk_device_xi_parent_class)->constructed (object);
+}
+
+static void
+gdk_device_xi_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceXI *device = GDK_DEVICE_XI (object);
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE_ID:
+ device->device_id = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_xi_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkDeviceXI *device = GDK_DEVICE_XI (object);
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE_ID:
+ g_value_set_int (value, device->device_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_device_xi_dispose (GObject *object)
+{
+ GdkDeviceXI *device_xi;
+ GdkDisplay *display;
+
+ device_xi = GDK_DEVICE_XI (object);
+ display = gdk_device_get_display (GDK_DEVICE (device_xi));
+
+ if (device_xi->xdevice)
+ {
+ XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device_xi->xdevice);
+ device_xi->xdevice = NULL;
+ }
+
+ if (device_xi->axis_data)
+ {
+ g_free (device_xi->axis_data);
+ device_xi->axis_data = NULL;
+ }
+
+ G_OBJECT_CLASS (gdk_device_xi_parent_class)->dispose (object);
+}
+
+static gboolean
+gdk_device_xi_get_history (GdkDevice *device,
+ GdkWindow *window,
+ guint32 start,
+ guint32 stop,
+ GdkTimeCoord ***events,
+ guint *n_events)
+{
+ GdkTimeCoord **coords;
+ XDeviceTimeCoord *device_coords;
+ GdkWindow *impl_window;
+ GdkDeviceXI *device_xi;
+ gint n_events_return;
+ gint mode_return;
+ gint axis_count_return;
+ gint i;
+
+ device_xi = GDK_DEVICE_XI (device);
+ impl_window = _gdk_window_get_impl_window (window);
+
+ device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (impl_window),
+ device_xi->xdevice,
+ start, stop,
+ &n_events_return,
+ &mode_return,
+ &axis_count_return);
+
+ if (!device_coords)
+ return FALSE;
+
+ *n_events = (guint) n_events_return;
+ coords = _gdk_device_allocate_history (device, *n_events);
+
+ for (i = 0; i < *n_events; i++)
+ {
+ coords[i]->time = device_coords[i].time;
+ gdk_device_xi_translate_axes (device, window,
+ device_coords[i].data,
+ coords[i]->axes,
+ NULL, NULL);
+ }
+
+ XFreeDeviceMotionEvents (device_coords);
+
+ *events = coords;
+
+ return TRUE;
+}
+
+static void
+gdk_device_xi_get_state (GdkDevice *device,
+ GdkWindow *window,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ GdkDeviceXI *device_xi;
+ XDeviceState *state;
+ XInputClass *input_class;
+ gint i;
+
+ if (mask)
+ gdk_window_get_pointer (window, NULL, NULL, mask);
+
+ device_xi = GDK_DEVICE_XI (device);
+ state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
+ device_xi->xdevice);
+ input_class = state->data;
+
+ for (i = 0; i < state->num_classes; i++)
+ {
+ switch (input_class->class)
+ {
+ case ValuatorClass:
+ if (axes)
+ gdk_device_xi_translate_axes (device, window,
+ ((XValuatorState *) input_class)->valuators,
+ axes, NULL, NULL);
+ break;
+
+ case ButtonClass:
+ if (mask)
+ {
+ *mask &= 0xFF;
+ if (((XButtonState *)input_class)->num_buttons > 0)
+ *mask |= ((XButtonState *)input_class)->buttons[0] << 7;
+ /* GDK_BUTTON1_MASK = 1 << 8, and button n is stored
+ * in bit 1<<(n%8) in byte n/8. n = 1,2,... */
+ }
+ break;
+ }
+
+ input_class = (XInputClass *)(((char *)input_class)+input_class->length);
+ }
+
+ XFreeDeviceState (state);
+}
+
+static void
+gdk_device_xi_set_window_cursor (GdkDevice *device,
+ GdkWindow *window,
+ GdkCursor *cursor)
+{
+}
+
+static void
+gdk_device_xi_warp (GdkDevice *device,
+ GdkScreen *screen,
+ gint x,
+ gint y)
+{
+}
+
+static void
+find_events (GdkDevice *device,
+ GdkEventMask mask,
+ XEventClass *classes,
+ int *num_classes)
+{
+ GdkDeviceXI *device_xi;
+ XEventClass class;
+ gint i;
+
+ device_xi = GDK_DEVICE_XI (device);
+ i = 0;
+
+ if (mask & GDK_BUTTON_PRESS_MASK)
+ {
+ DeviceButtonPress (device_xi->xdevice, device_xi->button_press_type, class);
+ if (class != 0)
+ classes[i++] = class;
+
+ DeviceButtonPressGrab (device_xi->xdevice, 0, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_BUTTON_RELEASE_MASK)
+ {
+ DeviceButtonRelease (device_xi->xdevice, device_xi->button_release_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & (GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_MOTION_MASK))
+ {
+ /* Make sure device->motionnotify_type is set */
+ DeviceMotionNotify (device_xi->xdevice, device_xi->motion_notify_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ DeviceStateNotify (device_xi->xdevice, device_xi->state_notify_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_KEY_PRESS_MASK)
+ {
+ DeviceKeyPress (device_xi->xdevice, device_xi->key_press_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_KEY_RELEASE_MASK)
+ {
+ DeviceKeyRelease (device_xi->xdevice, device_xi->key_release_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_PROXIMITY_IN_MASK)
+ {
+ ProximityIn (device_xi->xdevice, device_xi->proximity_in_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ if (mask & GDK_PROXIMITY_OUT_MASK)
+ {
+ ProximityOut (device_xi->xdevice, device_xi->proximity_out_type, class);
+ if (class != 0)
+ classes[i++] = class;
+ }
+
+ *num_classes = i;
+}
+
+static gboolean
+gdk_device_xi_query_state (GdkDevice *device,
+ GdkWindow *window,
+ GdkWindow **root_window,
+ GdkWindow **child_window,
+ gint *root_x,
+ gint *root_y,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask)
+{
+ return FALSE;
+}
+
+static GdkGrabStatus
+gdk_device_xi_grab (GdkDevice *device,
+ GdkWindow *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow *confine_to,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ XEventClass event_classes[MAX_DEVICE_CLASSES];
+ gint status, num_classes;
+ GdkDeviceXI *device_xi;
+
+ device_xi = GDK_DEVICE_XI (device);
+ find_events (device, event_mask, event_classes, &num_classes);
+
+ status = XGrabDevice (GDK_WINDOW_XDISPLAY (window),
+ device_xi->xdevice,
+ GDK_WINDOW_XWINDOW (window),
+ owner_events,
+ num_classes, event_classes,
+ GrabModeAsync, GrabModeAsync,
+ time_);
+
+ return _gdk_x11_convert_grab_status (status);
+}
+
+static void
+gdk_device_xi_ungrab (GdkDevice *device,
+ guint32 time_)
+{
+ GdkDisplay *display;
+ GdkDeviceXI *device_xi;
+
+ device_xi = GDK_DEVICE_XI (device);
+ display = gdk_device_get_display (device);
+
+ XUngrabDevice (GDK_DISPLAY_XDISPLAY (device),
+ device_xi->xdevice,
+ time_);
+}
+
+static GdkWindow*
+gdk_device_xi_window_at_position (GdkDevice *device,
+ gint *win_x,
+ gint *win_y,
+ GdkModifierType *mask,
+ gboolean get_toplevel)
+{
+ return NULL;
+}
+static void
+gdk_device_xi_select_window_events (GdkDevice *device,
+ GdkWindow *window,
+ GdkEventMask event_mask)
+{
+ XEventClass event_classes[MAX_DEVICE_CLASSES];
+ GdkDeviceXI *device_xi;
+ gint num_classes;
+
+ event_mask |= (GDK_PROXIMITY_IN_MASK |
+ GDK_PROXIMITY_OUT_MASK);
+
+ device_xi = GDK_DEVICE_XI (device);
+ find_events (device, event_mask, event_classes, &num_classes);
+
+ XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XWINDOW (window),
+ event_classes, num_classes);
+
+ if (event_mask)
+ {
+ GdkWindowInputInfo *info;
+
+ info = g_new0 (GdkWindowInputInfo, 1);
+ g_object_set_qdata_full (G_OBJECT (window),
+ quark_window_input_info,
+ info,
+ (GDestroyNotify) g_free);
+ }
+ else
+ g_object_set_qdata (G_OBJECT (window),
+ quark_window_input_info,
+ NULL);
+}
+
+void
+gdk_device_xi_update_window_info (GdkWindow *window)
+{
+ GdkWindowInputInfo *info;
+ gint root_x, root_y;
+
+ info = g_object_get_qdata (G_OBJECT (window),
+ quark_window_input_info);
+
+ if (!info)
+ return;
+
+ gdk_window_get_origin (window, &root_x, &root_y);
+ info->root_x = (gdouble) root_x;
+ info->root_y = (gdouble) root_y;
+}
+
+static gboolean
+gdk_device_xi_get_window_info (GdkWindow *window,
+ gdouble *root_x,
+ gdouble *root_y)
+{
+ GdkWindowInputInfo *info;
+
+ info = g_object_get_qdata (G_OBJECT (window),
+ quark_window_input_info);
+
+ if (!info)
+ return FALSE;
+
+ *root_x = info->root_x;
+ *root_y = info->root_y;
+
+ return TRUE;
+}
+
+void
+gdk_device_xi_update_axes (GdkDevice *device,
+ gint axes_count,
+ gint first_axis,
+ gint *axis_data)
+{
+ GdkDeviceXI *device_xi;
+ int i;
+
+ device_xi = GDK_DEVICE_XI (device);
+ g_return_if_fail (first_axis >= 0 && first_axis + axes_count <= device->num_axes);
+
+ if (!device_xi->axis_data)
+ device_xi->axis_data = g_new0 (gint, device->num_axes);
+
+ for (i = 0; i < axes_count; i++)
+ device_xi->axis_data[first_axis + i] = axis_data[i];
+}
+
+void
+gdk_device_xi_translate_axes (GdkDevice *device,
+ GdkWindow *window,
+ gint *axis_data,
+ gdouble *axes,
+ gdouble *x,
+ gdouble *y)
+{
+ GdkDeviceXI *device_xi;
+ GdkWindow *impl_window;
+ gdouble root_x, root_y;
+ gdouble temp_x, temp_y;
+ gint i;
+
+ device_xi = GDK_DEVICE_XI (device);
+ impl_window = _gdk_window_get_impl_window (window);
+ temp_x = temp_y = 0;
+
+ if (!gdk_device_xi_get_window_info (impl_window, &root_x, &root_y))
+ return;
+
+ for (i = 0; i < device->num_axes; i++)
+ {
+ GdkAxisUse use;
+
+ use = _gdk_device_get_axis_use (device, i);
+
+ switch (use)
+ {
+ case GDK_AXIS_X:
+ case GDK_AXIS_Y:
+ if (device->mode == GDK_MODE_WINDOW)
+ _gdk_device_translate_window_coord (device, window,
+ i, axis_data[i],
+ &axes[i]);
+ else
+ _gdk_device_translate_screen_coord (device, window,
+ root_x, root_y,
+ i, axis_data[i],
+ &axes[i]);
+ if (use == GDK_AXIS_X)
+ temp_x = axes[i];
+ else if (use == GDK_AXIS_Y)
+ temp_y = axes[i];
+
+ break;
+ default:
+ _gdk_device_translate_axis (device, i, axis_data[i], &axes[i]);
+ break;
+ }
+ }
+
+ if (x)
+ *x = temp_x;
+
+ if (y)
+ *y = temp_y;
+}