| /* 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 "gdkdevice.h" |
| #include "gdkdeviceprivate.h" |
| #include "gdkintl.h" |
| #include "gdkinternals.h" |
| |
| |
| 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 |
| { |
| GdkDeviceManager *device_manager; |
| GdkDisplay *display; |
| GdkDevice *associated; |
| GdkDeviceType type; |
| GArray *axes; |
| }; |
| |
| static void gdk_device_dispose (GObject *object); |
| static void gdk_device_set_property (GObject *object, |
| guint prop_id, |
| const GValue *value, |
| GParamSpec *pspec); |
| static void gdk_device_get_property (GObject *object, |
| guint prop_id, |
| GValue *value, |
| GParamSpec *pspec); |
| |
| |
| G_DEFINE_ABSTRACT_TYPE (GdkDevice, gdk_device, G_TYPE_OBJECT) |
| |
| enum { |
| PROP_0, |
| PROP_DISPLAY, |
| PROP_DEVICE_MANAGER, |
| PROP_NAME, |
| PROP_ASSOCIATED_DEVICE, |
| PROP_TYPE, |
| PROP_INPUT_SOURCE, |
| PROP_INPUT_MODE, |
| PROP_HAS_CURSOR, |
| PROP_N_AXES |
| }; |
| |
| |
| static void |
| gdk_device_class_init (GdkDeviceClass *klass) |
| { |
| GObjectClass *object_class = G_OBJECT_CLASS (klass); |
| |
| object_class->dispose = gdk_device_dispose; |
| object_class->set_property = gdk_device_set_property; |
| object_class->get_property = gdk_device_get_property; |
| |
| /** |
| * GdkDevice:display: |
| * |
| * The #GdkDisplay the #GdkDevice pertains to. |
| * |
| * Since: 3.0 |
| */ |
| g_object_class_install_property (object_class, |
| PROP_DISPLAY, |
| g_param_spec_object ("display", |
| P_("Device Display"), |
| P_("Display which the device belongs to"), |
| GDK_TYPE_DISPLAY, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_STATIC_STRINGS)); |
| /** |
| * GdkDevice:device-manager: |
| * |
| * The #GdkDeviceManager the #GdkDevice pertains to. |
| * |
| * Since: 3.0 |
| */ |
| g_object_class_install_property (object_class, |
| PROP_DEVICE_MANAGER, |
| g_param_spec_object ("device-manager", |
| P_("Device manager"), |
| P_("Device manager which the device belongs to"), |
| GDK_TYPE_DEVICE_MANAGER, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_STATIC_STRINGS)); |
| /** |
| * GdkDevice:name: |
| * |
| * The device name. |
| * |
| * Since: 3.0 |
| */ |
| g_object_class_install_property (object_class, |
| PROP_NAME, |
| g_param_spec_string ("name", |
| P_("Device name"), |
| P_("Device name"), |
| NULL, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_STATIC_STRINGS)); |
| /** |
| * GdkDevice:type: |
| * |
| * Device role in the device manager. |
| * |
| * Since: 3.0 |
| */ |
| g_object_class_install_property (object_class, |
| PROP_TYPE, |
| g_param_spec_enum ("type", |
| P_("Device type"), |
| P_("Device role in the device manager"), |
| GDK_TYPE_DEVICE_TYPE, |
| GDK_DEVICE_TYPE_MASTER, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_STATIC_STRINGS)); |
| /** |
| * GdkDevice:associated-device: |
| * |
| * Associated pointer or keyboard with this device, if any. Devices of type #GDK_DEVICE_TYPE_MASTER |
| * always come in keyboard/pointer pairs. Other device types will have a %NULL associated device. |
| * |
| * Since: 3.0 |
| */ |
| g_object_class_install_property (object_class, |
| PROP_ASSOCIATED_DEVICE, |
| g_param_spec_object ("associated-device", |
| P_("Associated device"), |
| P_("Associated pointer or keyboard with this device"), |
| GDK_TYPE_DEVICE, |
| G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
| /** |
| * GdkDevice:input-source: |
| * |
| * Source type for the device. |
| * |
| * Since: 3.0 |
| */ |
| g_object_class_install_property (object_class, |
| PROP_INPUT_SOURCE, |
| g_param_spec_enum ("input-source", |
| P_("Input source"), |
| P_("Source type for the device"), |
| GDK_TYPE_INPUT_SOURCE, |
| GDK_SOURCE_MOUSE, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_STATIC_STRINGS)); |
| /** |
| * GdkDevice:input-mode: |
| * |
| * Input mode for the device. |
| * |
| * Since: 3.0 |
| */ |
| g_object_class_install_property (object_class, |
| PROP_INPUT_MODE, |
| g_param_spec_enum ("input-mode", |
| P_("Input mode for the device"), |
| P_("Input mode for the device"), |
| GDK_TYPE_INPUT_MODE, |
| GDK_MODE_DISABLED, |
| G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
| /** |
| * GdkDevice:has-cursor: |
| * |
| * Whether the device is represented by a cursor on the screen. Devices of type |
| * %GDK_DEVICE_TYPE_MASTER will have %TRUE here. |
| * |
| * Since: 3.0 |
| */ |
| g_object_class_install_property (object_class, |
| PROP_HAS_CURSOR, |
| g_param_spec_boolean ("has-cursor", |
| P_("Whether the device has a cursor"), |
| P_("Whether there is a visible cursor following device motion"), |
| FALSE, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
| G_PARAM_STATIC_STRINGS)); |
| /** |
| * GdkDevice:n-axes: |
| * |
| * Number of axes in the device. |
| * |
| * Since: 3.0 |
| */ |
| 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_PARAM_STATIC_STRINGS)); |
| |
| g_type_class_add_private (object_class, sizeof (GdkDevicePrivate)); |
| } |
| |
| static void |
| gdk_device_init (GdkDevice *device) |
| { |
| GdkDevicePrivate *priv; |
| |
| device->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device, |
| GDK_TYPE_DEVICE, |
| GdkDevicePrivate); |
| |
| priv->axes = g_array_new (FALSE, TRUE, sizeof (GdkAxisInfo)); |
| } |
| |
| static void |
| gdk_device_dispose (GObject *object) |
| { |
| GdkDevicePrivate *priv; |
| GdkDevice *device; |
| |
| device = GDK_DEVICE (object); |
| priv = device->priv; |
| |
| if (priv->associated) |
| { |
| _gdk_device_set_associated_device (priv->associated, NULL); |
| g_object_unref (priv->associated); |
| priv->associated = NULL; |
| } |
| |
| if (priv->axes) |
| { |
| g_array_free (priv->axes, TRUE); |
| priv->axes = NULL; |
| } |
| |
| g_free (device->name); |
| g_free (device->keys); |
| g_free (device->axes); |
| |
| device->name = NULL; |
| device->keys = NULL; |
| device->axes = NULL; |
| |
| G_OBJECT_CLASS (gdk_device_parent_class)->dispose (object); |
| } |
| |
| static void |
| gdk_device_set_property (GObject *object, |
| guint prop_id, |
| const GValue *value, |
| GParamSpec *pspec) |
| { |
| GdkDevice *device = GDK_DEVICE (object); |
| GdkDevicePrivate *priv = device->priv; |
| |
| switch (prop_id) |
| { |
| case PROP_DISPLAY: |
| priv->display = g_value_get_object (value); |
| break; |
| case PROP_DEVICE_MANAGER: |
| priv->device_manager = g_value_get_object (value); |
| break; |
| case PROP_NAME: |
| if (device->name) |
| g_free (device->name); |
| |
| device->name = g_value_dup_string (value); |
| break; |
| case PROP_TYPE: |
| priv->type = g_value_get_enum (value); |
| break; |
| case PROP_INPUT_SOURCE: |
| device->source = g_value_get_enum (value); |
| break; |
| case PROP_INPUT_MODE: |
| gdk_device_set_mode (device, g_value_get_enum (value)); |
| break; |
| case PROP_HAS_CURSOR: |
| device->has_cursor = g_value_get_boolean (value); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| gdk_device_get_property (GObject *object, |
| guint prop_id, |
| GValue *value, |
| GParamSpec *pspec) |
| { |
| GdkDevice *device = GDK_DEVICE (object); |
| GdkDevicePrivate *priv = device->priv; |
| |
| switch (prop_id) |
| { |
| case PROP_DISPLAY: |
| g_value_set_object (value, priv->display); |
| break; |
| case PROP_DEVICE_MANAGER: |
| g_value_set_object (value, priv->device_manager); |
| break; |
| case PROP_ASSOCIATED_DEVICE: |
| g_value_set_object (value, priv->associated); |
| break; |
| case PROP_NAME: |
| g_value_set_string (value, |
| device->name); |
| break; |
| case PROP_TYPE: |
| g_value_set_enum (value, priv->type); |
| break; |
| case PROP_INPUT_SOURCE: |
| g_value_set_enum (value, device->source); |
| break; |
| case PROP_INPUT_MODE: |
| g_value_set_enum (value, device->mode); |
| break; |
| case PROP_HAS_CURSOR: |
| 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; |
| } |
| } |
| |
| /** |
| * gdk_device_get_state: |
| * @device: a #GdkDevice. |
| * @window: a #GdkWindow. |
| * @axes: an array of doubles to store the values of the axes of @device in, |
| * or %NULL. |
| * @mask: location to store the modifiers, or %NULL. |
| * |
| * Gets the current state of a device relative to @window. |
| */ |
| void |
| gdk_device_get_state (GdkDevice *device, |
| GdkWindow *window, |
| gdouble *axes, |
| GdkModifierType *mask) |
| { |
| g_return_if_fail (GDK_IS_DEVICE (device)); |
| g_return_if_fail (GDK_IS_WINDOW (window)); |
| |
| if (GDK_DEVICE_GET_CLASS (device)->get_state) |
| GDK_DEVICE_GET_CLASS (device)->get_state (device, window, axes, mask); |
| } |
| |
| /** |
| * gdk_device_get_history: |
| * @device: a #GdkDevice |
| * @window: the window with respect to which which the event coordinates will be reported |
| * @start: starting timestamp for range of events to return |
| * @stop: ending timestamp for the range of events to return |
| * @events: (array length=n_events) (out) (transfer none): location to store a newly-allocated array of #GdkTimeCoord, or %NULL |
| * @n_events: location to store the length of @events, or %NULL |
| * |
| * Obtains the motion history for a device; given a starting and |
| * ending timestamp, return all events in the motion history for |
| * the device in the given range of time. Some windowing systems |
| * do not support motion history, in which case, %FALSE will |
| * be returned. (This is not distinguishable from the case where |
| * motion history is supported and no events were found.) |
| * |
| * Return value: %TRUE if the windowing system supports motion history and |
| * at least one event was found. |
| **/ |
| gboolean |
| gdk_device_get_history (GdkDevice *device, |
| GdkWindow *window, |
| guint32 start, |
| guint32 stop, |
| GdkTimeCoord ***events, |
| guint *n_events) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE); |
| g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); |
| |
| if (n_events) |
| *n_events = 0; |
| |
| if (events) |
| *events = NULL; |
| |
| if (GDK_WINDOW_DESTROYED (window)) |
| return FALSE; |
| |
| if (!GDK_DEVICE_GET_CLASS (device)->get_history) |
| return FALSE; |
| |
| return GDK_DEVICE_GET_CLASS (device)->get_history (device, window, |
| start, stop, |
| events, n_events); |
| } |
| |
| GdkTimeCoord ** |
| _gdk_device_allocate_history (GdkDevice *device, |
| guint n_events) |
| { |
| GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events); |
| gint i; |
| |
| for (i = 0; i < n_events; i++) |
| result[i] = g_malloc (sizeof (GdkTimeCoord) - |
| sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->num_axes)); |
| return result; |
| } |
| |
| /** |
| * gdk_device_free_history: |
| * @events: (inout) (transfer none): an array of #GdkTimeCoord. |
| * @n_events: the length of the array. |
| * |
| * Frees an array of #GdkTimeCoord that was returned by gdk_device_get_history(). |
| */ |
| void |
| gdk_device_free_history (GdkTimeCoord **events, |
| gint n_events) |
| { |
| gint i; |
| |
| for (i = 0; i < n_events; i++) |
| g_free (events[i]); |
| |
| g_free (events); |
| } |
| |
| /** |
| * gdk_device_get_name: |
| * @device: a #GdkDevice |
| * |
| * Determines the name of the device. |
| * |
| * Return value: a name |
| * |
| * Since: 2.20 |
| **/ |
| const gchar * |
| gdk_device_get_name (GdkDevice *device) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); |
| |
| return device->name; |
| } |
| |
| /** |
| * gdk_device_get_has_cursor: |
| * @device: a #GdkDevice |
| * |
| * Determines whether the pointer follows device motion. |
| * |
| * Return value: %TRUE if the pointer follows device motion |
| * |
| * Since: 2.20 |
| **/ |
| gboolean |
| gdk_device_get_has_cursor (GdkDevice *device) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE); |
| |
| return device->has_cursor; |
| } |
| |
| /** |
| * gdk_device_get_source: |
| * @device: a #GdkDevice |
| * |
| * Determines the type of the device. |
| * |
| * Return value: a #GdkInputSource |
| * |
| * Since: 2.20 |
| **/ |
| GdkInputSource |
| gdk_device_get_source (GdkDevice *device) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), 0); |
| |
| return device->source; |
| } |
| |
| /** |
| * gdk_device_set_source: |
| * @device: a #GdkDevice. |
| * @source: the source type. |
| * |
| * Sets the source type for an input device. |
| **/ |
| void |
| gdk_device_set_source (GdkDevice *device, |
| GdkInputSource source) |
| { |
| g_return_if_fail (GDK_IS_DEVICE (device)); |
| |
| device->source = source; |
| } |
| |
| /** |
| * gdk_device_get_mode: |
| * @device: a #GdkDevice |
| * |
| * Determines the mode of the device. |
| * |
| * Return value: a #GdkInputSource |
| * |
| * Since: 2.20 |
| **/ |
| GdkInputMode |
| gdk_device_get_mode (GdkDevice *device) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), 0); |
| |
| return device->mode; |
| } |
| |
| /** |
| * gdk_device_set_mode: |
| * @device: a #GdkDevice. |
| * @mode: the input mode. |
| * |
| * Sets a the mode of an input device. The mode controls if the |
| * device is active and whether the device's range is mapped to the |
| * entire screen or to a single window. |
| * |
| * Returns: %TRUE if the mode was successfully changed. |
| **/ |
| gboolean |
| gdk_device_set_mode (GdkDevice *device, |
| GdkInputMode mode) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE); |
| |
| if (device->mode == mode) |
| return TRUE; |
| |
| if (mode == GDK_MODE_DISABLED && |
| gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER) |
| return FALSE; |
| |
| /* FIXME: setting has_cursor when mode is window? */ |
| |
| device->mode = mode; |
| g_object_notify (G_OBJECT (device), "input-mode"); |
| |
| if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER) |
| _gdk_input_check_extension_events (device); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gdk_device_get_key: |
| * @device: a #GdkDevice. |
| * @index_: the index of the macro button to get. |
| * @keyval: return value for the keyval. |
| * @modifiers: return value for modifiers. |
| * |
| * If @index_ has a valid keyval, this function will return %TRUE |
| * and fill in @keyval and @modifiers with the keyval settings. |
| * |
| * Returns: %TRUE if keyval is set for @index. |
| * |
| * Since: 2.20 |
| **/ |
| gboolean |
| gdk_device_get_key (GdkDevice *device, |
| guint index_, |
| guint *keyval, |
| GdkModifierType *modifiers) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE); |
| g_return_val_if_fail (index_ < device->num_keys, FALSE); |
| |
| if (!device->keys[index_].keyval && |
| !device->keys[index_].modifiers) |
| return FALSE; |
| |
| if (keyval) |
| *keyval = device->keys[index_].keyval; |
| |
| if (modifiers) |
| *modifiers = device->keys[index_].modifiers; |
| |
| return TRUE; |
| } |
| |
| /** |
| * gdk_device_set_key: |
| * @device: a #GdkDevice |
| * @index_: the index of the macro button to set |
| * @keyval: the keyval to generate |
| * @modifiers: the modifiers to set |
| * |
| * Specifies the X key event to generate when a macro button of a device |
| * is pressed. |
| **/ |
| void |
| gdk_device_set_key (GdkDevice *device, |
| guint index_, |
| guint keyval, |
| GdkModifierType modifiers) |
| { |
| g_return_if_fail (GDK_IS_DEVICE (device)); |
| g_return_if_fail (index_ < device->num_keys); |
| |
| device->keys[index_].keyval = keyval; |
| device->keys[index_].modifiers = modifiers; |
| } |
| |
| /** |
| * gdk_device_get_axis_use: |
| * @device: a #GdkDevice. |
| * @index_: the index of the axis. |
| * |
| * Returns the axis use for @index_. |
| * |
| * Returns: a #GdkAxisUse specifying how the axis is used. |
| * |
| * Since: 2.20 |
| **/ |
| GdkAxisUse |
| gdk_device_get_axis_use (GdkDevice *device, |
| guint index_) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_AXIS_IGNORE); |
| g_return_val_if_fail (index_ < device->num_axes, GDK_AXIS_IGNORE); |
| |
| return device->axes[index_].use; |
| } |
| |
| /** |
| * gdk_device_set_axis_use: |
| * @device: a #GdkDevice |
| * @index_: the index of the axis |
| * @use: specifies how the axis is used |
| * |
| * Specifies how an axis of a device is used. |
| **/ |
| void |
| gdk_device_set_axis_use (GdkDevice *device, |
| guint index_, |
| GdkAxisUse use) |
| { |
| GdkDevicePrivate *priv; |
| GdkAxisInfo *info; |
| |
| g_return_if_fail (GDK_IS_DEVICE (device)); |
| g_return_if_fail (index_ < device->num_axes); |
| |
| priv = device->priv; |
| info = &g_array_index (priv->axes, GdkAxisInfo, index_); |
| info->use = use; |
| |
| device->axes[index_].use = use; |
| |
| switch (use) |
| { |
| case GDK_AXIS_X: |
| case GDK_AXIS_Y: |
| device->axes[index_].min = info->min_axis = 0; |
| device->axes[index_].max = info->max_axis = 0; |
| break; |
| case GDK_AXIS_XTILT: |
| case GDK_AXIS_YTILT: |
| device->axes[index_].min = info->min_axis = -1; |
| device->axes[index_].max = info->max_axis = 1; |
| break; |
| default: |
| device->axes[index_].min = info->min_axis = 0; |
| device->axes[index_].max = info->max_axis = 1; |
| break; |
| } |
| } |
| |
| /** |
| * gdk_device_get_display: |
| * @device: a #GdkDevice |
| * |
| * Returns the #GdkDisplay to which @device pertains. |
| * |
| * Returns: a #GdkDisplay. This memory is owned by GTK+, |
| * and must not be freed or unreffed. |
| * |
| * Since: 3.0 |
| **/ |
| GdkDisplay * |
| gdk_device_get_display (GdkDevice *device) |
| { |
| GdkDevicePrivate *priv; |
| |
| g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); |
| |
| priv = device->priv; |
| |
| return priv->display; |
| } |
| |
| /** |
| * gdk_device_get_associated_device: |
| * @device: a #GdkDevice |
| * |
| * Returns the associated device to @device, if @device is of type |
| * %GDK_DEVICE_TYPE_MASTER, it will return the paired pointer or |
| * keyboard. |
| * |
| * If @device is of type %GDK_DEVICE_TYPE_SLAVE, it will return |
| * the master device to which @device is attached to. |
| * |
| * If @device is of type %GDK_DEVICE_TYPE_FLOATING, %NULL will be |
| * returned, as there is no associated device. |
| * |
| * Returns: The associated device, or %NULL |
| * |
| * Since: 3.0 |
| **/ |
| GdkDevice * |
| gdk_device_get_associated_device (GdkDevice *device) |
| { |
| GdkDevicePrivate *priv; |
| |
| g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); |
| |
| priv = device->priv; |
| |
| return priv->associated; |
| } |
| |
| void |
| _gdk_device_set_associated_device (GdkDevice *device, |
| GdkDevice *associated) |
| { |
| GdkDevicePrivate *priv; |
| |
| g_return_if_fail (GDK_IS_DEVICE (device)); |
| g_return_if_fail (GDK_IS_DEVICE (associated)); |
| |
| priv = device->priv; |
| |
| if (priv->associated == associated) |
| return; |
| |
| if (priv->associated) |
| { |
| g_object_unref (priv->associated); |
| priv->associated = NULL; |
| } |
| |
| if (associated) |
| priv->associated = g_object_ref (associated); |
| } |
| |
| /** |
| * gdk_device_get_device_type: |
| * @device: a #GdkDevice |
| * |
| * Returns the device type for @device. |
| * |
| * Returns: the #GdkDeviceType for @device. |
| * |
| * Since: 3.0 |
| **/ |
| GdkDeviceType |
| gdk_device_get_device_type (GdkDevice *device) |
| { |
| GdkDevicePrivate *priv; |
| |
| g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_DEVICE_TYPE_MASTER); |
| |
| priv = device->priv; |
| |
| return priv->type; |
| } |
| |
| /** |
| * gdk_device_get_n_axes: |
| * @device: a #GdkDevice |
| * |
| * Returns the number of axes the device currently has. |
| * |
| * Returns: the number of axes. |
| * |
| * Since: 3.0 |
| **/ |
| guint |
| gdk_device_get_n_axes (GdkDevice *device) |
| { |
| g_return_val_if_fail (GDK_IS_DEVICE (device), 0); |
| |
| return device->num_axes; |
| } |
| |
| /** |
| * gdk_device_list_axes: |
| * @device: a #GdkDevice |
| * |
| * Returns a #GList of #GdkAtom<!-- -->s, containing the labels for |
| * the axes that @device currently has. |
| * |
| * Returns: A #GList of #GdkAtom<!-- -->s, free with g_list_free(). |
| * |
| * Since: 3.0 |
| **/ |
| GList * |
| gdk_device_list_axes (GdkDevice *device) |
| { |
| GdkDevicePrivate *priv; |
| GList *axes = NULL; |
| gint i; |
| |
| priv = device->priv; |
| |
| 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); |
| } |
| |
| /** |
| * gdk_device_get_axis_value: |
| * @device: a #GdkDevice. |
| * @axes: pointer to an array of axes |
| * @axis_label: #GdkAtom with the axis label. |
| * @value: location to store the found value. |
| * |
| * Interprets an array of double as axis values for a given device, |
| * and locates the value in the array for a given axis label, as returned |
| * by gdk_device_list_axes() |
| * |
| * Returns: %TRUE if the given axis use was found, otherwise %FALSE. |
| * |
| * Since: 3.0 |
| **/ |
| 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 = device->priv; |
| |
| 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; |
| } |
| |
| /** |
| * gdk_device_get_axis: |
| * @device: a #GdkDevice |
| * @axes: pointer to an array of axes |
| * @use: the use to look for |
| * @value: location to store the found value. |
| * |
| * Interprets an array of double as axis values for a given device, |
| * and locates the value in the array for a given axis use. |
| * |
| * Return value: %TRUE if the given axis use was found, otherwise %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 = device->priv; |
| |
| 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; |
| } |
| |
| static GdkEventMask |
| get_native_grab_event_mask (GdkEventMask grab_mask) |
| { |
| /* Similar to the above but for pointer events only */ |
| return |
| GDK_POINTER_MOTION_MASK | |
| GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | |
| GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | |
| GDK_SCROLL_MASK | |
| (grab_mask & |
| ~(GDK_POINTER_MOTION_HINT_MASK | |
| GDK_BUTTON_MOTION_MASK | |
| GDK_BUTTON1_MOTION_MASK | |
| GDK_BUTTON2_MOTION_MASK | |
| GDK_BUTTON3_MOTION_MASK)); |
| } |
| |
| /** |
| * gdk_device_grab: |
| * @device: a #GdkDevice |
| * @window: the #GdkWindow which will own the grab (the grab window) |
| * @grab_ownership: specifies the grab ownership. |
| * @owner_events: if %FALSE then all device events are reported with respect to |
| * @window and are only reported if selected by @event_mask. If |
| * %TRUE then pointer events for this application are reported |
| * as normal, but pointer events outside this application are |
| * reported with respect to @window and only if selected by |
| * @event_mask. In either mode, unreported events are discarded. |
| * @event_mask: specifies the event mask, which is used in accordance with |
| * @owner_events. |
| * @cursor: the cursor to display while the grab is active if the device is |
| * a pointer. If this is %NULL then the normal cursors are used for |
| * @window and its descendants, and the cursor for @window is used |
| * elsewhere. |
| * @time_: the timestamp of the event which led to this pointer grab. This |
| * usually comes from the #GdkEvent struct, though %GDK_CURRENT_TIME |
| * can be used if the time isn't known. |
| * |
| * Grabs the device so that all events coming from this device are passed to |
| * this application until the device is ungrabbed with gdk_device_ungrab(), |
| * or the window becomes unviewable. This overrides any previous grab on the device |
| * by this client. |
| * |
| * Device grabs are used for operations which need complete control over the |
| * given device events (either pointer or keyboard). For example in GTK+ this |
| * is used for Drag and Drop operations, popup menus and such. |
| * |
| * Note that if the event mask of an X window has selected both button press |
| * and button release events, then a button press event will cause an automatic |
| * pointer grab until the button is released. X does this automatically since |
| * most applications expect to receive button press and release events in pairs. |
| * It is equivalent to a pointer grab on the window with @owner_events set to |
| * %TRUE. |
| * |
| * If you set up anything at the time you take the grab that needs to be |
| * cleaned up when the grab ends, you should handle the #GdkEventGrabBroken |
| * events that are emitted when the grab ends unvoluntarily. |
| * |
| * Returns: %GDK_GRAB_SUCCESS if the grab was successful. |
| * |
| * Since: 3.0 |
| **/ |
| GdkGrabStatus |
| gdk_device_grab (GdkDevice *device, |
| GdkWindow *window, |
| GdkGrabOwnership grab_ownership, |
| gboolean owner_events, |
| GdkEventMask event_mask, |
| GdkCursor *cursor, |
| guint32 time_) |
| { |
| GdkGrabStatus res; |
| GdkWindow *native; |
| |
| g_return_val_if_fail (GDK_IS_DEVICE (device), 0); |
| g_return_val_if_fail (GDK_IS_WINDOW (window), 0); |
| |
| if (_gdk_native_windows) |
| native = window; |
| else |
| native = gdk_window_get_toplevel (window); |
| |
| while (((GdkWindowObject *) native)->window_type == GDK_WINDOW_OFFSCREEN) |
| { |
| native = gdk_offscreen_window_get_embedder (native); |
| |
| if (native == NULL || |
| (!_gdk_window_has_impl (native) && |
| !gdk_window_is_viewable (native))) |
| return GDK_GRAB_NOT_VIEWABLE; |
| |
| native = gdk_window_get_toplevel (native); |
| } |
| |
| res = _gdk_windowing_device_grab (device, |
| window, |
| native, |
| owner_events, |
| get_native_grab_event_mask (event_mask), |
| NULL, |
| cursor, |
| time_); |
| |
| if (res == GDK_GRAB_SUCCESS) |
| { |
| GdkDisplay *display; |
| gulong serial; |
| |
| display = gdk_drawable_get_display (window); |
| serial = _gdk_windowing_window_get_next_serial (display); |
| |
| _gdk_display_add_device_grab (display, |
| device, |
| window, |
| native, |
| grab_ownership, |
| owner_events, |
| event_mask, |
| serial, |
| time_, |
| FALSE); |
| } |
| |
| return res; |
| } |
| |
| /* Private API */ |
| void |
| _gdk_device_reset_axes (GdkDevice *device) |
| { |
| GdkDevicePrivate *priv; |
| gint i; |
| |
| priv = device->priv; |
| |
| for (i = priv->axes->len - 1; i >= 0; i--) |
| g_array_remove_index (priv->axes, i); |
| |
| g_object_notify (G_OBJECT (device), "n-axes"); |
| |
| /* This is done for backwards compatibility */ |
| g_free (device->axes); |
| device->axes = NULL; |
| } |
| |
| 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; |
| guint pos; |
| |
| priv = device->priv; |
| |
| 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); |
| device->num_axes = priv->axes->len; |
| pos = device->num_axes - 1; |
| |
| /* This is done for backwards compatibility, since the public |
| * struct doesn't actually store the device data. |
| */ |
| device->axes = g_realloc (device->axes, sizeof (GdkDeviceAxis) * priv->axes->len); |
| device->axes[pos].use = axis_info.use; |
| device->axes[pos].min = axis_info.min_axis; |
| device->axes[pos].max = axis_info.max_axis; |
| |
| g_object_notify (G_OBJECT (device), "n-axes"); |
| |
| return pos; |
| } |
| |
| void |
| _gdk_device_set_keys (GdkDevice *device, |
| guint num_keys) |
| { |
| if (device->keys) |
| g_free (device->keys); |
| |
| device->num_keys = num_keys; |
| device->keys = g_new0 (GdkDeviceKey, num_keys); |
| } |
| |
| static 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; |
| } |
| |
| GdkAxisUse |
| _gdk_device_get_axis_use (GdkDevice *device, |
| guint index_) |
| { |
| GdkDevicePrivate *priv; |
| GdkAxisInfo info; |
| |
| priv = device->priv; |
| |
| info = g_array_index (priv->axes, GdkAxisInfo, index_); |
| return info.use; |
| } |
| |
| gboolean |
| _gdk_device_translate_window_coord (GdkDevice *device, |
| GdkWindow *window, |
| guint index_, |
| gdouble value, |
| gdouble *axis_value) |
| { |
| GdkDevicePrivate *priv; |
| GdkAxisInfo axis_info; |
| GdkAxisInfo *axis_info_x, *axis_info_y; |
| gdouble device_width, device_height; |
| gdouble x_offset, y_offset; |
| gdouble x_scale, y_scale; |
| gdouble x_min, y_min; |
| gdouble x_resolution, y_resolution; |
| gdouble device_aspect; |
| gint window_width, window_height; |
| GdkWindowObject *window_private; |
| |
| priv = device->priv; |
| |
| 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) |
| return FALSE; |
| |
| 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_width > 0) |
| x_min = axis_info_x->min_value; |
| else |
| { |
| device_width = gdk_screen_get_width (gdk_drawable_get_screen (window)); |
| x_min = 0; |
| } |
| |
| if (device_height > 0) |
| y_min = axis_info_y->min_value; |
| else |
| { |
| device_height = gdk_screen_get_height (gdk_drawable_get_screen (window)); |
| y_min = 0; |
| } |
| |
| window_private = (GdkWindowObject *) window; |
| gdk_drawable_get_size (window, &window_width, &window_height); |
| |
| 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_value) |
| { |
| if (axis_info.use == GDK_AXIS_X) |
| *axis_value = x_offset + x_scale * (value - x_min); |
| else |
| *axis_value = y_offset + y_scale * (value - y_min); |
| } |
| |
| return TRUE; |
| } |
| |
| gboolean |
| _gdk_device_translate_screen_coord (GdkDevice *device, |
| GdkWindow *window, |
| gint window_root_x, |
| gint window_root_y, |
| guint index_, |
| gdouble value, |
| gdouble *axis_value) |
| { |
| GdkDevicePrivate *priv; |
| GdkAxisInfo axis_info; |
| gdouble axis_width, scale, offset; |
| GdkWindowObject *window_private; |
| |
| if (device->mode != GDK_MODE_SCREEN) |
| return FALSE; |
| |
| priv = device->priv; |
| |
| 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) |
| return FALSE; |
| |
| axis_width = axis_info.max_value - axis_info.min_value; |
| window_private = (GdkWindowObject *) window; |
| |
| if (axis_info.use == GDK_AXIS_X) |
| { |
| if (axis_width > 0) |
| scale = gdk_screen_get_width (gdk_drawable_get_screen (window)) / axis_width; |
| else |
| scale = 1; |
| |
| offset = - window_root_x - window_private->abs_x; |
| } |
| else |
| { |
| if (axis_width > 0) |
| scale = gdk_screen_get_height (gdk_drawable_get_screen (window)) / axis_width; |
| else |
| scale = 1; |
| |
| offset = - window_root_y - window_private->abs_y; |
| } |
| |
| if (axis_value) |
| *axis_value = offset + scale * (value - axis_info.min_value); |
| |
| return TRUE; |
| } |
| |
| gboolean |
| _gdk_device_translate_axis (GdkDevice *device, |
| guint index_, |
| gdouble value, |
| gdouble *axis_value) |
| { |
| GdkDevicePrivate *priv; |
| GdkAxisInfo axis_info; |
| gdouble axis_width, out; |
| |
| priv = device->priv; |
| |
| 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) |
| return FALSE; |
| |
| 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; |
| } |