[gtk+/events-refactor: 736/1085] Add/Improve API for handling devices' axes.
- From: Carlos Garnacho <carlosg src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gtk+/events-refactor: 736/1085] Add/Improve API for handling devices' axes.
- Date: Tue, 29 Sep 2009 10:47:26 +0000 (UTC)
commit be3721119fea12d0a16ec49be142ed2fd6c0ee4c
Author: Carlos Garnacho <carlos lanedo com>
Date: Sat Aug 15 17:13:44 2009 +0200
Add/Improve API for handling devices' axes.
gdk/gdkdevice.c | 325 +++++++++++++++++++++++++++++++++++++++++++++---
gdk/gdkdeviceprivate.h | 23 +++-
2 files changed, 327 insertions(+), 21 deletions(-)
---
diff --git a/gdk/gdkdevice.c b/gdk/gdkdevice.c
index 1051914..ca02952 100644
--- a/gdk/gdkdevice.c
+++ b/gdk/gdkdevice.c
@@ -26,10 +26,25 @@
#define GDK_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDK_TYPE_DEVICE, GdkDevicePrivate))
typedef struct _GdkDevicePrivate GdkDevicePrivate;
+typedef struct _GdkAxisInfo GdkAxisInfo;
+
+struct _GdkAxisInfo
+{
+ GdkAtom label;
+ GdkAxisUse use;
+
+ gdouble min_axis;
+ gdouble max_axis;
+
+ gdouble min_value;
+ gdouble max_value;
+ gdouble resolution;
+};
struct _GdkDevicePrivate
{
GdkDisplay *display;
+ GArray *axes;
};
static void gdk_device_set_property (GObject *object,
@@ -51,6 +66,7 @@ enum {
PROP_INPUT_SOURCE,
PROP_INPUT_MODE,
PROP_HAS_CURSOR,
+ PROP_N_AXES
};
@@ -99,6 +115,13 @@ gdk_device_class_init (GdkDeviceClass *klass)
P_("Whether there is a visible cursor following device motion"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_N_AXES,
+ g_param_spec_uint ("n-axes",
+ P_("Number of axes in the device"),
+ P_("Number of axes in the device"),
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE));
g_type_class_add_private (object_class, sizeof (GdkDevicePrivate));
}
@@ -106,6 +129,10 @@ gdk_device_class_init (GdkDeviceClass *klass)
static void
gdk_device_init (GdkDevice *device)
{
+ GdkDevicePrivate *priv;
+
+ priv = GDK_DEVICE_GET_PRIVATE (device);
+ priv->axes = g_array_new (FALSE, TRUE, sizeof (GdkAxisInfo));
}
static void
@@ -171,6 +198,9 @@ gdk_device_get_property (GObject *object,
g_value_set_boolean (value,
device->has_cursor);
break;
+ case PROP_N_AXES:
+ g_value_set_uint (value, priv->axes->len);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -221,22 +251,6 @@ gdk_device_free_history (GdkTimeCoord **events,
g_free (events);
}
-gboolean
-gdk_device_get_axis (GdkDevice *device,
- gdouble *axes,
- GdkAxisUse use,
- gdouble *value)
-{
- g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (axes != NULL, FALSE);
- g_return_val_if_fail (value != NULL, FALSE);
-
- if (!GDK_DEVICE_GET_CLASS (device)->get_axis)
- return FALSE;
-
- return GDK_DEVICE_GET_CLASS (device)->get_axis (device, axes, use, value);
-}
-
void
gdk_device_set_source (GdkDevice *device,
GdkInputSource source)
@@ -312,5 +326,284 @@ gdk_device_get_display (GdkDevice *device)
return priv->display;
}
+GList *
+gdk_device_list_axes (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+ GList *axes = NULL;
+ gint i;
+
+ priv = GDK_DEVICE_GET_PRIVATE (device);
+
+ for (i = 0; i < priv->axes->len; i++)
+ {
+ GdkAxisInfo axis_info;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
+ axes = g_list_prepend (axes, GDK_ATOM_TO_POINTER (axis_info.label));
+ }
+
+ return g_list_reverse (axes);
+}
+
+gboolean
+gdk_device_get_axis_value (GdkDevice *device,
+ gdouble *axes,
+ GdkAtom axis_label,
+ gdouble *value)
+{
+ GdkDevicePrivate *priv;
+ gint i;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+ if (axes == NULL)
+ return FALSE;
+
+ priv = GDK_DEVICE_GET_PRIVATE (device);
+
+ for (i = 0; i < priv->axes->len; i++)
+ {
+ GdkAxisInfo axis_info;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
+
+ if (axis_info.label != axis_label)
+ continue;
+
+ if (value)
+ *value = axes[i];
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+gdk_device_get_axis (GdkDevice *device,
+ gdouble *axes,
+ GdkAxisUse use,
+ gdouble *value)
+{
+ GdkDevicePrivate *priv;
+ gint i;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+ if (axes == NULL)
+ return FALSE;
+
+ priv = GDK_DEVICE_GET_PRIVATE (device);
+
+ g_return_val_if_fail (priv->axes != NULL, FALSE);
+
+ for (i = 0; i < priv->axes->len; i++)
+ {
+ GdkAxisInfo axis_info;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, i);
+
+ if (axis_info.use != use)
+ continue;
+
+ if (value)
+ *value = axes[i];
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Private API */
+void
+_gdk_device_reset_axes (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+ guint i;
+
+ priv = GDK_DEVICE_GET_PRIVATE (device);
+
+ for (i = priv->axes->len - 1; i >= 0; i--)
+ g_array_remove_index (priv->axes, i);
+}
+
+guint
+_gdk_device_add_axis (GdkDevice *device,
+ GdkAtom label_atom,
+ GdkAxisUse use,
+ gdouble min_value,
+ gdouble max_value,
+ gdouble resolution)
+{
+ GdkDevicePrivate *priv;
+ GdkAxisInfo axis_info;
+
+ priv = GDK_DEVICE_GET_PRIVATE (device);
+
+ axis_info.use = use;
+ axis_info.label = label_atom;
+ axis_info.min_value = min_value;
+ axis_info.max_value = max_value;
+ axis_info.resolution = resolution;
+
+ switch (use)
+ {
+ case GDK_AXIS_X:
+ case GDK_AXIS_Y:
+ axis_info.min_axis = 0.;
+ axis_info.max_axis = 0.;
+ break;
+ case GDK_AXIS_XTILT:
+ case GDK_AXIS_YTILT:
+ axis_info.min_axis = -1.;
+ axis_info.max_axis = 1.;
+ break;
+ default:
+ axis_info.min_axis = 0.;
+ axis_info.max_axis = 1.;
+ break;
+ }
+
+ priv->axes = g_array_append_val (priv->axes, axis_info);
+
+ return priv->axes->len - 1;
+}
+
+GdkAxisInfo *
+find_axis_info (GArray *array,
+ GdkAxisUse use)
+{
+ GdkAxisInfo *info;
+ gint i;
+
+ for (i = 0; i < GDK_AXIS_LAST; i++)
+ {
+ info = &g_array_index (array, GdkAxisInfo, i);
+
+ if (info->use == use)
+ return info;
+ }
+
+ return NULL;
+}
+
+gboolean
+_gdk_device_translate_axis (GdkDevice *device,
+ gdouble window_width,
+ gdouble window_height,
+ gdouble window_x,
+ gdouble window_y,
+ guint index,
+ gdouble value,
+ gdouble *axis_value)
+{
+ GdkDevicePrivate *priv;
+ GdkAxisInfo axis_info;
+ gdouble out = 0;
+
+ priv = GDK_DEVICE_GET_PRIVATE (device);
+
+ if (index >= priv->axes->len)
+ return FALSE;
+
+ axis_info = g_array_index (priv->axes, GdkAxisInfo, index);
+
+ if (axis_info.use == GDK_AXIS_X ||
+ axis_info.use == GDK_AXIS_Y)
+ {
+ GdkAxisInfo *axis_info_x, *axis_info_y;
+ gdouble device_width, device_height;
+ gdouble x_offset, y_offset;
+ gdouble x_scale, y_scale;
+
+ if (axis_info.use == GDK_AXIS_X)
+ {
+ axis_info_x = &axis_info;
+ axis_info_y = find_axis_info (priv->axes, GDK_AXIS_Y);
+ }
+ else
+ {
+ axis_info_x = find_axis_info (priv->axes, GDK_AXIS_X);
+ axis_info_y = &axis_info;
+ }
+
+ device_width = axis_info_x->max_value - axis_info_x->min_value;
+ device_height = axis_info_y->max_value - axis_info_y->min_value;
+
+ if (device->mode == GDK_MODE_SCREEN)
+ {
+ if (axis_info.use == GDK_AXIS_X)
+ out = window_x;
+ else
+ out = window_y;
+ }
+ else /* GDK_MODE_WINDOW */
+ {
+ gdouble x_resolution, y_resolution, device_aspect;
+
+ x_resolution = axis_info_x->resolution;
+ y_resolution = axis_info_y->resolution;
+
+ /*
+ * Some drivers incorrectly report the resolution of the device
+ * as zero (in partiular linuxwacom < 0.5.3 with usb tablets).
+ * This causes the device_aspect to become NaN and totally
+ * breaks windowed mode. If this is the case, the best we can
+ * do is to assume the resolution is non-zero is equal in both
+ * directions (which is true for many devices). The absolute
+ * value of the resolution doesn't matter since we only use the
+ * ratio.
+ */
+ if (x_resolution == 0 || y_resolution == 0)
+ {
+ x_resolution = 1;
+ y_resolution = 1;
+ }
+
+ device_aspect = (device_height * y_resolution) /
+ (device_width * x_resolution);
+
+ if (device_aspect * window_width >= window_height)
+ {
+ /* device taller than window */
+ x_scale = window_width / device_width;
+ y_scale = (x_scale * x_resolution) / y_resolution;
+
+ x_offset = 0;
+ y_offset = - (device_height * y_scale - window_height) / 2;
+ }
+ else
+ {
+ /* window taller than device */
+ y_scale = window_height / device_height;
+ x_scale = (y_scale * y_resolution) / x_resolution;
+
+ y_offset = 0;
+ x_offset = - (device_width * x_scale - window_width) / 2;
+ }
+
+ if (axis_info.use == GDK_AXIS_X)
+ out = x_offset + x_scale * (value - axis_info.min_value);
+ else
+ out = y_offset + y_scale * (value - axis_info.min_value);
+ }
+ }
+ else
+ {
+ gdouble axis_width;
+
+ axis_width = axis_info.max_value - axis_info.min_value;
+ out = (axis_info.max_axis * (value - axis_info.min_value) +
+ axis_info.min_axis * (axis_info.max_value - value)) / axis_width;
+ }
+
+ if (axis_value)
+ *axis_value = out;
+
+ return TRUE;
+}
+
#define __GDK_DEVICE_C__
#include "gdkaliasdef.c"
diff --git a/gdk/gdkdeviceprivate.h b/gdk/gdkdeviceprivate.h
index d1ce69b..ca6bd21 100644
--- a/gdk/gdkdeviceprivate.h
+++ b/gdk/gdkdeviceprivate.h
@@ -50,11 +50,6 @@ struct _GdkDeviceClass
gdouble *axes,
GdkModifierType *mask);
- gboolean (* get_axis) (GdkDevice *device,
- gdouble *axes,
- GdkAxisUse use,
- gdouble *value);
-
void (* set_window_cursor) (GdkDevice *device,
GdkWindow *window,
GdkCursor *cursor);
@@ -65,6 +60,24 @@ struct _GdkDeviceClass
gint y);
};
+
+void _gdk_device_reset_axes (GdkDevice *device);
+guint _gdk_device_add_axis (GdkDevice *device,
+ GdkAtom label_atom,
+ GdkAxisUse use,
+ gdouble min_value,
+ gdouble max_value,
+ gdouble resolution);
+
+gboolean _gdk_device_translate_axis (GdkDevice *device,
+ gdouble window_width,
+ gdouble window_height,
+ gdouble window_x,
+ gdouble window_y,
+ guint index,
+ gdouble value,
+ gdouble *axis_value);
+
G_END_DECLS
#endif /* __GDK_DEVICE_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]