[mutter/wip/multitouch: 7/8] window: Implement window moving through touch events



commit 1546cba268581d7a4da27eadf7f85c14957a5ad8
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Aug 2 19:29:07 2011 +0200

    window: Implement window moving through touch events
    
    Window moving is triggered by 3-4 simultaneous touch events on
    the window, the hotspot being in the center of the touch area
    bounding rect.

 src/core/display-private.h |    7 ++
 src/core/display.c         |   27 +++++++++
 src/core/window-private.h  |    7 ++
 src/core/window.c          |  137 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 178 insertions(+), 0 deletions(-)
---
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 24711f9..ae83e93 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -59,6 +59,7 @@ typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
 
 typedef struct _MetaGrabInfo MetaGrabInfo;
 typedef struct _MetaFocusInfo MetaFocusInfo;
+typedef struct _MetaTouchInfo MetaTouchInfo;
 
 typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
 				     Window       xwindow,
@@ -147,6 +148,12 @@ struct _MetaFocusInfo
   guint32 last_focus_time;
 };
 
+struct _MetaTouchInfo
+{
+  gdouble root_x;
+  gdouble root_y;
+};
+
 struct _MetaDisplay
 {
   GObject parent_instance;
diff --git a/src/core/display.c b/src/core/display.c
index b349c6f..44d0806 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1761,6 +1761,9 @@ event_callback (XEvent   *event,
       gdouble ev_root_x, ev_root_y;
       MetaDevice *device;
 
+      if (meta_input_event_ignore (display, event))
+        return FALSE;
+
       if (window && !window->override_redirect &&
           ((evtype == KeyPress) || (evtype == ButtonPress)))
         {
@@ -1808,6 +1811,14 @@ event_callback (XEvent   *event,
             filter_out_event = bypass_compositor = TRUE;
           break;
         case ButtonPress:
+          if (window &&
+              meta_input_event_get_touch_id (display, event, NULL))
+            {
+              meta_window_update_touch (window, event);
+              filter_out_event = TRUE;
+              break;
+            }
+
           meta_input_event_get_button (display, event, &n_button);
           meta_input_event_get_state (display, event, &state);
           meta_input_event_get_coordinates (display, event,
@@ -2023,6 +2034,14 @@ event_callback (XEvent   *event,
             }
           break;
         case ButtonRelease:
+          if (window &&
+              meta_input_event_get_touch_id (display, event, NULL))
+            {
+              meta_window_end_touch (window, event);
+              filter_out_event = TRUE;
+              break;
+            }
+
           if (grab_info && grab_info->grab_op == META_GRAB_OP_COMPOSITOR)
             break;
 
@@ -2032,6 +2051,14 @@ event_callback (XEvent   *event,
             meta_window_handle_mouse_grab_op_event (window, event);
           break;
         case MotionNotify:
+          if (window &&
+              meta_input_event_get_touch_id (display, event, NULL))
+            {
+              meta_window_update_touch (window, event);
+              filter_out_event = TRUE;
+              break;
+            }
+
           if (grab_info && grab_info->grab_op == META_GRAB_OP_COMPOSITOR)
             break;
 
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 9a78d45..687c140 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -411,6 +411,8 @@ struct _MetaWindow
 
   /* Focus info if the window is focused, or NULL */
   MetaFocusInfo *cur_focus;
+
+  GHashTable *cur_touches;
 };
 
 struct _MetaWindowClass
@@ -671,4 +673,9 @@ MetaDevice * meta_window_get_client_pointer (MetaWindow *window);
 
 MetaDevice * meta_window_guess_grab_pointer (MetaWindow *window);
 
+gboolean     meta_window_update_touch (MetaWindow *window,
+                                       XEvent     *event);
+void         meta_window_end_touch    (MetaWindow *window,
+                                       XEvent     *event);
+
 #endif
diff --git a/src/core/window.c b/src/core/window.c
index ae84d9d..6dc9fd2 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -200,6 +200,9 @@ meta_window_finalize (GObject *object)
   if (window->menu)
     meta_ui_window_menu_free (window->menu);
 
+  if (window->cur_touches)
+    g_hash_table_destroy (window->cur_touches);
+
   meta_icon_cache_free (&window->icon_cache);
 
   g_free (window->sm_client_id);
@@ -10566,3 +10569,137 @@ meta_window_guess_grab_pointer (MetaWindow *window)
 
   return meta_window_get_client_pointer (window);
 }
+
+typedef struct
+{
+  gdouble top_left_x;
+  gdouble top_left_y;
+  gdouble bottom_right_x;
+  gdouble bottom_right_y;
+} BoundingRectCoords;
+
+static void
+calculate_touch_bounding_rect (gpointer key,
+                               gpointer value,
+                               gpointer user_data)
+{
+  BoundingRectCoords *bounding_rect = user_data;
+  MetaTouchInfo *touch_info = value;
+
+  if (touch_info->root_x < bounding_rect->top_left_x)
+    bounding_rect->top_left_x = touch_info->root_x;
+  if (touch_info->root_x > bounding_rect->bottom_right_x)
+    bounding_rect->bottom_right_x = touch_info->root_x;
+
+  if (touch_info->root_y < bounding_rect->top_left_y)
+    bounding_rect->top_left_y = touch_info->root_y;
+  if (touch_info->root_y > bounding_rect->bottom_right_y)
+    bounding_rect->bottom_right_y = touch_info->root_y;
+}
+
+gboolean
+meta_window_update_touch (MetaWindow *window,
+                          XEvent     *event)
+{
+  gdouble root_x, root_y;
+  MetaTouchInfo *touch_info;
+  gboolean new_touch = FALSE;
+  MetaDevice *device;
+  guint touch_id, n_touches;
+  Time evtime;
+
+  if (!window->cur_touches)
+    window->cur_touches = g_hash_table_new (NULL, NULL);
+
+  meta_input_event_get_touch_id (window->display,
+                                 event, &touch_id);
+
+  touch_info = g_hash_table_lookup (window->cur_touches,
+                                    GUINT_TO_POINTER (touch_id));
+
+  if (!touch_info &&
+      g_hash_table_size (window->cur_touches) == 3)
+    return FALSE;
+
+  meta_input_event_get_coordinates (window->display, event,
+                                    NULL, NULL,
+                                    &root_x, &root_y);
+  evtime = meta_input_event_get_time (window->display, event);
+  device = meta_input_event_get_device (window->display, event);
+
+  if (!touch_info)
+    {
+      touch_info = g_slice_new (MetaTouchInfo);
+      g_hash_table_insert (window->cur_touches,
+                           GUINT_TO_POINTER (touch_id),
+                           touch_info);
+      new_touch = TRUE;
+    }
+
+  touch_info->root_x = root_x;
+  touch_info->root_y = root_y;
+  n_touches = g_hash_table_size (window->cur_touches);
+
+  if (n_touches == 3)
+    {
+      gdouble x, y, width, height;
+      BoundingRectCoords bounding_rect = { DBL_MAX, DBL_MAX,
+                                           DBL_MIN, DBL_MIN };
+
+      g_hash_table_foreach (window->cur_touches,
+                            calculate_touch_bounding_rect,
+                            &bounding_rect);
+
+      /* Get x/y coordinates at the middle of the bounding box,
+       * this will be the hotspot for the window moving operation
+       */
+      width = bounding_rect.bottom_right_x - bounding_rect.top_left_x;
+      height = bounding_rect.bottom_right_y - bounding_rect.top_left_y;
+      x = bounding_rect.top_left_x + (width / 2);
+      y = bounding_rect.top_left_y + (height / 2);
+
+      if (new_touch)
+        {
+          /* Start window move operation with the
+           * bounding rectangle center as the hotspot
+           */
+          meta_display_begin_grab_op (window->display,
+                                      window->screen,
+                                      window,
+                                      device,
+                                      META_GRAB_OP_MOVING,
+                                      TRUE, FALSE,
+                                      1, 0,
+                                      evtime,
+                                      x, y);
+        }
+      else if (window->cur_grab)
+        update_move (window, device, FALSE, x, y);
+    }
+
+  return FALSE;
+}
+
+void
+meta_window_end_touch (MetaWindow *window,
+                       XEvent     *event)
+{
+  guint touch_id;
+  Time evtime;
+
+  meta_input_event_get_touch_id (window->display, event, &touch_id);
+  evtime = meta_input_event_get_time (window->display, event);
+
+  if (!g_hash_table_remove (window->cur_touches,
+                           GUINT_TO_POINTER (touch_id)))
+    return;
+
+  if (g_hash_table_size (window->cur_touches) == 2)
+    {
+      MetaDevice *device;
+
+      device = meta_input_event_get_device (window->display, event);
+      meta_display_end_grab_op (window->display, device, evtime);
+    }
+}
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]