]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkdevice-xi2.c
Require XInput2.h in X11 backend
[~andy/gtk] / gdk / x11 / gdkdevice-xi2.c
index 6c9b5283174db30e576bfa244a7843f6b402e59c..4426a0e6392ac84bf660312a50ee0d5645133bbc 100644 (file)
  * 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.
+ * 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>
 
+
+typedef struct _ScrollValuator ScrollValuator;
+
+struct _ScrollValuator
+{
+  guint n_valuator       : 4;
+  guint direction        : 4;
+  guint last_value_valid : 1;
+  gdouble last_value;
+};
+
+struct _GdkX11DeviceXI2
+{
+  GdkDevice parent_instance;
+
+  gint device_id;
+  GArray *scroll_valuators;
+};
+
+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,
@@ -77,8 +107,6 @@ static void  gdk_x11_device_xi2_select_window_events (GdkDevice    *device,
                                                       GdkEventMask  event_mask);
 
 
-G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
-
 enum {
   PROP_0,
   PROP_DEVICE_ID
@@ -90,6 +118,7 @@ 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;
 
@@ -114,6 +143,17 @@ gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
 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_OBJECT_CLASS (gdk_x11_device_xi2_parent_class)->finalize (object);
 }
 
 static void
@@ -161,18 +201,21 @@ gdk_x11_device_xi2_get_state (GdkDevice       *device,
                               GdkModifierType *mask)
 {
   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
-  GdkDisplay *display;
-  XIDeviceInfo *info;
-  gint i, j, ndevices;
-
-  display = gdk_device_get_display (device);
 
   if (axes)
     {
-      info = XIQueryDevice(GDK_DISPLAY_XDISPLAY (display),
-                           device_xi2->device_id, &ndevices);
+      GdkDisplay *display;
+      XIDeviceInfo *info;
+      gint i, j, ndevices;
+
+      display = gdk_device_get_display (device);
 
-      for (i = 0, j = 0; i < info->num_classes; i++)
+      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;
@@ -182,7 +225,7 @@ gdk_x11_device_xi2_get_state (GdkDevice       *device,
             continue;
 
           value = ((XIValuatorClassInfo *) class_info)->value;
-          use = _gdk_device_get_axis_use (device, j);
+          use = gdk_device_get_axis_use (device, j);
 
           switch (use)
             {
@@ -211,7 +254,8 @@ gdk_x11_device_xi2_get_state (GdkDevice       *device,
           j++;
         }
 
-      XIFreeDeviceInfo (info);
+      if (info)
+        XIFreeDeviceInfo (info);
     }
 
   if (mask)
@@ -345,7 +389,9 @@ gdk_x11_device_xi2_query_state (GdkDevice        *device,
     *win_y = (gint) xwin_y;
 
   if (mask)
-    *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state);
+    *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
+
+  free (button_state.mask);
 
   return TRUE;
 }
@@ -360,6 +406,7 @@ gdk_x11_device_xi2_grab (GdkDevice    *device,
                          guint32       time_)
 {
   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
+  GdkX11DeviceManagerXI2 *device_manager_xi2;
   GdkDisplay *display;
   XIEventMask mask;
   Window xwindow;
@@ -367,6 +414,7 @@ gdk_x11_device_xi2_grab (GdkDevice    *device,
   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 */
 
@@ -381,7 +429,9 @@ gdk_x11_device_xi2_grab (GdkDevice    *device,
     }
 
   mask.deviceid = device_xi2->device_id;
-  mask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
+  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)
@@ -434,7 +484,7 @@ gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
   GdkWindow *window;
   Window xwindow, root, child, last = None;
   gdouble xroot_x, xroot_y, xwin_x, xwin_y;
-  XIButtonState button_state;
+  XIButtonState button_state = { 0 };
   XIModifierState mod_state;
   XIGroupState group_state;
 
@@ -486,6 +536,10 @@ gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
             {
               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,
@@ -510,6 +564,8 @@ gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
                   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);
@@ -543,6 +599,8 @@ gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
   while (xwindow)
     {
       last = xwindow;
+      free (button_state.mask);
+
       gdk_x11_display_error_trap_push (display);
       XIQueryPointer (xdisplay,
                       device_xi2->device_id,
@@ -576,7 +634,9 @@ gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
     *win_y = (window) ? (gint) xwin_y : -1;
 
   if (mask)
-    *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state);
+    *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
+
+  free (button_state.mask);
 
   return window;
 }
@@ -587,10 +647,17 @@ gdk_x11_device_xi2_select_window_events (GdkDevice    *device,
                                          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 (event_mask, &evmask.mask_len);
+  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),
@@ -600,10 +667,14 @@ gdk_x11_device_xi2_select_window_events (GdkDevice    *device,
 }
 
 guchar *
-_gdk_x11_device_xi2_translate_event_mask (GdkEventMask  event_mask,
-                                          gint         *len)
+_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);
@@ -652,17 +723,29 @@ _gdk_x11_device_xi2_translate_event_mask (GdkEventMask  event_mask,
       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)
+                                     XIButtonState   *buttons_state,
+                                     XIGroupState    *group_state)
 {
   guint state = 0;
 
   if (mods_state)
-    state = (guint) mods_state->effective;
+    state = (guint) mods_state->base | mods_state->latched | mods_state->locked;
 
   if (buttons_state)
     {
@@ -699,5 +782,102 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
         }
     }
 
+  if (group_state)
+    {
+      gint group;
+
+      group = group_state->base | group_state->latched | group_state->locked;
+
+      /* FIXME: do we need the XKB complications for this ? */
+      group = CLAMP(group, 0, 3);
+
+      state |= group << 13;
+    }
+
   return state;
 }
+
+void
+_gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2    *device,
+                                         guint               n_valuator,
+                                         GdkScrollDirection  direction)
+{
+  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;
+
+  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->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;
+    }
+}
+
+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;
+}