gtk2/gdk/x11/gdkdevice-xi2.c
Carlos Garnacho 4cae9bdd05 x11: Store last axes from device
And use these for the missing axes if the valuator mask is incomplete.
This used to work fine on tablets because the Wacom driver ensures all
valuators are sent, which is not true if using the evdev driver.

https://bugzilla.gnome.org/show_bug.cgi?id=703610
2015-03-02 18:57:04 +01:00

922 lines
29 KiB
C

/* 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkx11device-xi2.h"
#include "gdkdeviceprivate.h"
#include "gdkintl.h"
#include "gdkasync.h"
#include "gdkprivate-x11.h"
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XInput2.h>
#include <math.h>
/* for the use of round() */
#include "fallback-c89.c"
typedef struct _ScrollValuator ScrollValuator;
struct _ScrollValuator
{
guint n_valuator : 4;
guint direction : 4;
guint last_value_valid : 1;
gdouble last_value;
gdouble increment;
};
struct _GdkX11DeviceXI2
{
GdkDevice parent_instance;
gint device_id;
GArray *scroll_valuators;
gdouble *last_axes;
};
struct _GdkX11DeviceXI2Class
{
GdkDeviceClass parent_class;
};
G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
static void gdk_x11_device_xi2_finalize (GObject *object);
static void gdk_x11_device_xi2_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void gdk_x11_device_xi2_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gdk_x11_device_xi2_get_state (GdkDevice *device,
GdkWindow *window,
gdouble *axes,
GdkModifierType *mask);
static void gdk_x11_device_xi2_set_window_cursor (GdkDevice *device,
GdkWindow *window,
GdkCursor *cursor);
static void gdk_x11_device_xi2_warp (GdkDevice *device,
GdkScreen *screen,
gdouble x,
gdouble y);
static void gdk_x11_device_xi2_query_state (GdkDevice *device,
GdkWindow *window,
GdkWindow **root_window,
GdkWindow **child_window,
gdouble *root_x,
gdouble *root_y,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask);
static GdkGrabStatus gdk_x11_device_xi2_grab (GdkDevice *device,
GdkWindow *window,
gboolean owner_events,
GdkEventMask event_mask,
GdkWindow *confine_to,
GdkCursor *cursor,
guint32 time_);
static void gdk_x11_device_xi2_ungrab (GdkDevice *device,
guint32 time_);
static GdkWindow * gdk_x11_device_xi2_window_at_position (GdkDevice *device,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask,
gboolean get_toplevel);
static void gdk_x11_device_xi2_select_window_events (GdkDevice *device,
GdkWindow *window,
GdkEventMask event_mask);
enum {
PROP_0,
PROP_DEVICE_ID
};
static void
gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
object_class->finalize = gdk_x11_device_xi2_finalize;
object_class->get_property = gdk_x11_device_xi2_get_property;
object_class->set_property = gdk_x11_device_xi2_set_property;
device_class->get_state = gdk_x11_device_xi2_get_state;
device_class->set_window_cursor = gdk_x11_device_xi2_set_window_cursor;
device_class->warp = gdk_x11_device_xi2_warp;
device_class->query_state = gdk_x11_device_xi2_query_state;
device_class->grab = gdk_x11_device_xi2_grab;
device_class->ungrab = gdk_x11_device_xi2_ungrab;
device_class->window_at_position = gdk_x11_device_xi2_window_at_position;
device_class->select_window_events = gdk_x11_device_xi2_select_window_events;
g_object_class_install_property (object_class,
PROP_DEVICE_ID,
g_param_spec_int ("device-id",
P_("Device ID"),
P_("Device identifier"),
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
gdk_x11_device_xi2_init (GdkX11DeviceXI2 *device)
{
device->scroll_valuators = g_array_new (FALSE, FALSE, sizeof (ScrollValuator));
}
static void
gdk_x11_device_xi2_finalize (GObject *object)
{
GdkX11DeviceXI2 *device = GDK_X11_DEVICE_XI2 (object);
g_array_free (device->scroll_valuators, TRUE);
g_free (device->last_axes);
G_OBJECT_CLASS (gdk_x11_device_xi2_parent_class)->finalize (object);
}
static void
gdk_x11_device_xi2_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
switch (prop_id)
{
case PROP_DEVICE_ID:
g_value_set_int (value, device_xi2->device_id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdk_x11_device_xi2_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
switch (prop_id)
{
case PROP_DEVICE_ID:
device_xi2->device_id = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdk_x11_device_xi2_get_state (GdkDevice *device,
GdkWindow *window,
gdouble *axes,
GdkModifierType *mask)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
if (axes)
{
GdkDisplay *display;
XIDeviceInfo *info;
gint i, j, ndevices;
display = gdk_device_get_display (device);
gdk_x11_display_error_trap_push (display);
info = XIQueryDevice (GDK_DISPLAY_XDISPLAY (display),
device_xi2->device_id, &ndevices);
gdk_x11_display_error_trap_pop_ignored (display);
for (i = 0, j = 0; info && i < info->num_classes; i++)
{
XIAnyClassInfo *class_info = info->classes[i];
GdkAxisUse use;
gdouble value;
if (class_info->type != XIValuatorClass)
continue;
value = ((XIValuatorClassInfo *) class_info)->value;
use = gdk_device_get_axis_use (device, j);
switch (use)
{
case GDK_AXIS_X:
case GDK_AXIS_Y:
case GDK_AXIS_IGNORE:
if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
_gdk_device_translate_window_coord (device, window, j, value, &axes[j]);
else
{
gint root_x, root_y;
/* FIXME: Maybe root coords chaching should happen here */
gdk_window_get_origin (window, &root_x, &root_y);
_gdk_device_translate_screen_coord (device, window,
root_x, root_y,
j, value,
&axes[j]);
}
break;
default:
_gdk_device_translate_axis (device, j, value, &axes[j]);
break;
}
j++;
}
if (info)
XIFreeDeviceInfo (info);
}
if (mask)
gdk_x11_device_xi2_query_state (device, window,
NULL, NULL,
NULL, NULL,
NULL, NULL,
mask);
}
static void
gdk_x11_device_xi2_set_window_cursor (GdkDevice *device,
GdkWindow *window,
GdkCursor *cursor)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
/* Non-master devices don't have a cursor */
if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
return;
if (cursor)
XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
device_xi2->device_id,
GDK_WINDOW_XID (window),
gdk_x11_cursor_get_xcursor (cursor));
else
XIUndefineCursor (GDK_WINDOW_XDISPLAY (window),
device_xi2->device_id,
GDK_WINDOW_XID (window));
}
static void
gdk_x11_device_xi2_warp (GdkDevice *device,
GdkScreen *screen,
gdouble x,
gdouble y)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
Window dest;
dest = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
device_xi2->device_id,
None, dest,
0, 0, 0, 0,
round (x * GDK_X11_SCREEN(screen)->window_scale),
round (y * GDK_X11_SCREEN(screen)->window_scale));
}
static void
gdk_x11_device_xi2_query_state (GdkDevice *device,
GdkWindow *window,
GdkWindow **root_window,
GdkWindow **child_window,
gdouble *root_x,
gdouble *root_y,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask)
{
GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
GdkDisplay *display;
GdkScreen *default_screen;
Window xroot_window, xchild_window;
gdouble xroot_x, xroot_y, xwin_x, xwin_y;
XIButtonState button_state;
XIModifierState mod_state;
XIGroupState group_state;
display = gdk_window_get_display (window);
default_screen = gdk_display_get_default_screen (display);
if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_SLAVE)
{
GdkDevice *master = gdk_device_get_associated_device (device);
if (master)
_gdk_device_query_state (master, window, root_window, child_window,
root_x, root_y, win_x, win_y, mask);
return;
}
if (!GDK_X11_DISPLAY (display)->trusted_client ||
!XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
device_xi2->device_id,
GDK_WINDOW_XID (window),
&xroot_window,
&xchild_window,
&xroot_x, &xroot_y,
&xwin_x, &xwin_y,
&button_state,
&mod_state,
&group_state))
{
XSetWindowAttributes attributes;
Display *xdisplay;
Window xwindow, w;
/* FIXME: untrusted clients not multidevice-safe */
xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
xwindow = GDK_SCREEN_XROOTWIN (default_screen);
w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
CopyFromParent, InputOnly, CopyFromParent,
0, &attributes);
XIQueryPointer (xdisplay, device_xi2->device_id,
w,
&xroot_window,
&xchild_window,
&xroot_x, &xroot_y,
&xwin_x, &xwin_y,
&button_state,
&mod_state,
&group_state);
XDestroyWindow (xdisplay, w);
}
if (root_window)
*root_window = gdk_x11_window_lookup_for_display (display, xroot_window);
if (child_window)
*child_window = gdk_x11_window_lookup_for_display (display, xchild_window);
if (root_x)
*root_x = xroot_x / impl->window_scale;
if (root_y)
*root_y = xroot_y / impl->window_scale;
if (win_x)
*win_x = xwin_x / impl->window_scale;
if (win_y)
*win_y = xwin_y / impl->window_scale;
if (mask)
*mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
free (button_state.mask);
}
static GdkGrabStatus
gdk_x11_device_xi2_grab (GdkDevice *device,
GdkWindow *window,
gboolean owner_events,
GdkEventMask event_mask,
GdkWindow *confine_to,
GdkCursor *cursor,
guint32 time_)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
GdkX11DeviceManagerXI2 *device_manager_xi2;
GdkDisplay *display;
XIEventMask mask;
Window xwindow;
Cursor xcursor;
gint status;
display = gdk_device_get_display (device);
device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
/* FIXME: confine_to is actually unused */
xwindow = GDK_WINDOW_XID (window);
if (!cursor)
xcursor = None;
else
{
_gdk_x11_cursor_update_theme (cursor);
xcursor = gdk_x11_cursor_get_xcursor (cursor);
}
mask.deviceid = device_xi2->device_id;
mask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
event_mask,
&mask.mask_len);
#ifdef G_ENABLE_DEBUG
if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
status = GrabSuccess;
else
#endif
status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
device_xi2->device_id,
xwindow,
time_,
xcursor,
GrabModeAsync, GrabModeAsync,
owner_events,
&mask);
g_free (mask.mask);
_gdk_x11_display_update_grab_info (display, device, status);
return _gdk_x11_convert_grab_status (status);
}
static void
gdk_x11_device_xi2_ungrab (GdkDevice *device,
guint32 time_)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
GdkDisplay *display;
gulong serial;
display = gdk_device_get_display (device);
serial = NextRequest (GDK_DISPLAY_XDISPLAY (display));
XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display), device_xi2->device_id, time_);
_gdk_x11_display_update_grab_info_ungrab (display, device, time_, serial);
}
static GdkWindow *
gdk_x11_device_xi2_window_at_position (GdkDevice *device,
gdouble *win_x,
gdouble *win_y,
GdkModifierType *mask,
gboolean get_toplevel)
{
GdkWindowImplX11 *impl;
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
GdkDisplay *display;
GdkScreen *screen;
Display *xdisplay;
GdkWindow *window;
Window xwindow, root, child, last = None;
gdouble xroot_x, xroot_y, xwin_x, xwin_y;
XIButtonState button_state = { 0 };
XIModifierState mod_state;
XIGroupState group_state;
display = gdk_device_get_display (device);
screen = gdk_display_get_default_screen (display);
/* This function really only works if the mouse pointer is held still
* during its operation. If it moves from one leaf window to another
* than we'll end up with inaccurate values for win_x, win_y
* and the result.
*/
gdk_x11_display_grab (display);
xdisplay = GDK_SCREEN_XDISPLAY (screen);
xwindow = GDK_SCREEN_XROOTWIN (screen);
if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
{
XIQueryPointer (xdisplay,
device_xi2->device_id,
xwindow,
&root, &child,
&xroot_x, &xroot_y,
&xwin_x, &xwin_y,
&button_state,
&mod_state,
&group_state);
if (root == xwindow)
xwindow = child;
else
xwindow = root;
}
else
{
gint width, height;
GList *toplevels, *list;
Window pointer_window, root, child;
/* FIXME: untrusted clients case not multidevice-safe */
pointer_window = None;
screen = gdk_display_get_screen (display, 0);
toplevels = gdk_screen_get_toplevel_windows (screen);
for (list = toplevels; list != NULL; list = g_list_next (list))
{
window = GDK_WINDOW (list->data);
xwindow = GDK_WINDOW_XID (window);
/* Free previous button mask, if any */
g_free (button_state.mask);
gdk_x11_display_error_trap_push (display);
XIQueryPointer (xdisplay,
device_xi2->device_id,
xwindow,
&root, &child,
&xroot_x, &xroot_y,
&xwin_x, &xwin_y,
&button_state,
&mod_state,
&group_state);
if (gdk_x11_display_error_trap_pop (display))
continue;
if (child != None)
{
pointer_window = child;
break;
}
gdk_window_get_geometry (window, NULL, NULL, &width, &height);
if (xwin_x >= 0 && xwin_y >= 0 && xwin_x < width && xwin_y < height)
{
/* A childless toplevel, or below another window? */
XSetWindowAttributes attributes;
Window w;
free (button_state.mask);
w = XCreateWindow (xdisplay, xwindow, (int)xwin_x, (int)xwin_y, 1, 1, 0,
CopyFromParent, InputOnly, CopyFromParent,
0, &attributes);
XMapWindow (xdisplay, w);
XIQueryPointer (xdisplay,
device_xi2->device_id,
xwindow,
&root, &child,
&xroot_x, &xroot_y,
&xwin_x, &xwin_y,
&button_state,
&mod_state,
&group_state);
XDestroyWindow (xdisplay, w);
if (child == w)
{
pointer_window = xwindow;
break;
}
}
g_list_free (toplevels);
if (pointer_window != None)
break;
}
xwindow = pointer_window;
}
while (xwindow)
{
last = xwindow;
free (button_state.mask);
gdk_x11_display_error_trap_push (display);
XIQueryPointer (xdisplay,
device_xi2->device_id,
xwindow,
&root, &xwindow,
&xroot_x, &xroot_y,
&xwin_x, &xwin_y,
&button_state,
&mod_state,
&group_state);
if (gdk_x11_display_error_trap_pop (display))
break;
if (get_toplevel && last != root &&
(window = gdk_x11_window_lookup_for_display (display, last)) != NULL &&
GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
{
xwindow = last;
break;
}
}
gdk_x11_display_ungrab (display);
window = gdk_x11_window_lookup_for_display (display, last);
impl = NULL;
if (window)
impl = GDK_WINDOW_IMPL_X11 (window->impl);
if (win_x)
*win_x = (window) ? (xwin_x / impl->window_scale) : -1;
if (win_y)
*win_y = (window) ? (xwin_y / impl->window_scale) : -1;
if (mask)
*mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
free (button_state.mask);
return window;
}
static void
gdk_x11_device_xi2_select_window_events (GdkDevice *device,
GdkWindow *window,
GdkEventMask event_mask)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
GdkX11DeviceManagerXI2 *device_manager_xi2;
GdkDisplay *display;
XIEventMask evmask;
display = gdk_device_get_display (device);
device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
evmask.deviceid = device_xi2->device_id;
evmask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
event_mask,
&evmask.mask_len);
XISelectEvents (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
&evmask, 1);
g_free (evmask.mask);
}
guchar *
_gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
GdkEventMask event_mask,
gint *len)
{
guchar *mask;
gint minor;
g_object_get (device_manager_xi2, "minor", &minor, NULL);
*len = XIMaskLen (XI_LASTEVENT);
mask = g_new0 (guchar, *len);
if (event_mask & GDK_POINTER_MOTION_MASK ||
event_mask & GDK_POINTER_MOTION_HINT_MASK)
XISetMask (mask, XI_Motion);
if (event_mask & GDK_BUTTON_MOTION_MASK ||
event_mask & GDK_BUTTON1_MOTION_MASK ||
event_mask & GDK_BUTTON2_MOTION_MASK ||
event_mask & GDK_BUTTON3_MOTION_MASK)
{
XISetMask (mask, XI_ButtonPress);
XISetMask (mask, XI_ButtonRelease);
XISetMask (mask, XI_Motion);
}
if (event_mask & GDK_SCROLL_MASK)
{
XISetMask (mask, XI_ButtonPress);
XISetMask (mask, XI_ButtonRelease);
}
if (event_mask & GDK_BUTTON_PRESS_MASK)
XISetMask (mask, XI_ButtonPress);
if (event_mask & GDK_BUTTON_RELEASE_MASK)
XISetMask (mask, XI_ButtonRelease);
if (event_mask & GDK_KEY_PRESS_MASK)
XISetMask (mask, XI_KeyPress);
if (event_mask & GDK_KEY_RELEASE_MASK)
XISetMask (mask, XI_KeyRelease);
if (event_mask & GDK_ENTER_NOTIFY_MASK)
XISetMask (mask, XI_Enter);
if (event_mask & GDK_LEAVE_NOTIFY_MASK)
XISetMask (mask, XI_Leave);
if (event_mask & GDK_FOCUS_CHANGE_MASK)
{
XISetMask (mask, XI_FocusIn);
XISetMask (mask, XI_FocusOut);
}
#ifdef XINPUT_2_2
/* XInput 2.2 includes multitouch support */
if (minor >= 2 &&
event_mask & GDK_TOUCH_MASK)
{
XISetMask (mask, XI_TouchBegin);
XISetMask (mask, XI_TouchUpdate);
XISetMask (mask, XI_TouchEnd);
}
#endif /* XINPUT_2_2 */
return mask;
}
guint
_gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
XIButtonState *buttons_state,
XIGroupState *group_state)
{
guint state = 0;
if (mods_state)
state = mods_state->effective;
if (buttons_state)
{
gint len, i;
/* We're only interested in the first 5 buttons */
len = MIN (5, buttons_state->mask_len * 8);
for (i = 0; i < len; i++)
{
if (!XIMaskIsSet (buttons_state->mask, i))
continue;
switch (i)
{
case 1:
state |= GDK_BUTTON1_MASK;
break;
case 2:
state |= GDK_BUTTON2_MASK;
break;
case 3:
state |= GDK_BUTTON3_MASK;
break;
case 4:
state |= GDK_BUTTON4_MASK;
break;
case 5:
state |= GDK_BUTTON5_MASK;
break;
default:
break;
}
}
}
if (group_state)
state |= (group_state->effective) << 13;
return state;
}
void
_gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2 *device,
guint n_valuator,
GdkScrollDirection direction,
gdouble increment)
{
ScrollValuator scroll;
g_return_if_fail (GDK_IS_X11_DEVICE_XI2 (device));
g_return_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)));
scroll.n_valuator = n_valuator;
scroll.direction = direction;
scroll.last_value_valid = FALSE;
scroll.increment = increment;
g_array_append_val (device->scroll_valuators, scroll);
}
gboolean
_gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2 *device,
guint n_valuator,
gdouble valuator_value,
GdkScrollDirection *direction_ret,
gdouble *delta_ret)
{
guint i;
g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), FALSE);
g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), FALSE);
for (i = 0; i < device->scroll_valuators->len; i++)
{
ScrollValuator *scroll;
scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
if (scroll->n_valuator == n_valuator)
{
if (direction_ret)
*direction_ret = scroll->direction;
if (delta_ret)
*delta_ret = 0;
if (scroll->last_value_valid)
{
if (delta_ret)
*delta_ret = (valuator_value - scroll->last_value) / scroll->increment;
scroll->last_value = valuator_value;
}
else
{
scroll->last_value = valuator_value;
scroll->last_value_valid = TRUE;
}
return TRUE;
}
}
return FALSE;
}
void
_gdk_device_xi2_reset_scroll_valuators (GdkX11DeviceXI2 *device)
{
guint i;
for (i = 0; i < device->scroll_valuators->len; i++)
{
ScrollValuator *scroll;
scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
scroll->last_value_valid = FALSE;
}
}
void
_gdk_device_xi2_unset_scroll_valuators (GdkX11DeviceXI2 *device)
{
if (device->scroll_valuators->len > 0)
g_array_remove_range (device->scroll_valuators, 0,
device->scroll_valuators->len);
}
gint
_gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device)
{
g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), 0);
return device->device_id;
}
gdouble
gdk_x11_device_xi2_get_last_axis_value (GdkX11DeviceXI2 *device,
gint n_axis)
{
if (n_axis >= gdk_device_get_n_axes (GDK_DEVICE (device)))
return 0;
if (!device->last_axes)
return 0;
return device->last_axes[n_axis];
}
void
gdk_x11_device_xi2_store_axes (GdkX11DeviceXI2 *device,
gdouble *axes,
gint n_axes)
{
g_free (device->last_axes);
if (axes && n_axes)
device->last_axes = g_memdup (axes, sizeof (gdouble) * n_axes);
else
device->last_axes = NULL;
}