227 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* GTK - The GIMP Toolkit
 | 
						|
 * Copyright (C) 2012 Red Hat, Inc.
 | 
						|
 *
 | 
						|
 * 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 "gdk.h"
 | 
						|
#include "gtkpressandholdprivate.h"
 | 
						|
#include "gtkintl.h"
 | 
						|
#include "gtkprivate.h"
 | 
						|
 | 
						|
struct _GtkPressAndHoldPrivate
 | 
						|
{
 | 
						|
  gint hold_time;
 | 
						|
  gint drag_threshold;
 | 
						|
 | 
						|
  GdkEventSequence *sequence;
 | 
						|
  guint timeout;
 | 
						|
  gint start_x;
 | 
						|
  gint start_y;
 | 
						|
  gint x;
 | 
						|
  gint y;
 | 
						|
};
 | 
						|
 | 
						|
enum
 | 
						|
{
 | 
						|
  PROP_ZERO,
 | 
						|
  PROP_HOLD_TIME,
 | 
						|
  PROP_DRAG_THRESHOLD
 | 
						|
};
 | 
						|
 | 
						|
enum
 | 
						|
{
 | 
						|
  HOLD,
 | 
						|
  TAP,
 | 
						|
  LAST_SIGNAL
 | 
						|
};
 | 
						|
 | 
						|
static guint signals[LAST_SIGNAL];
 | 
						|
 | 
						|
G_DEFINE_TYPE (GtkPressAndHold, gtk_press_and_hold, G_TYPE_OBJECT)
 | 
						|
 | 
						|
static void
 | 
						|
gtk_press_and_hold_init (GtkPressAndHold *pah)
 | 
						|
{
 | 
						|
  pah->priv = G_TYPE_INSTANCE_GET_PRIVATE (pah,
 | 
						|
                                           GTK_TYPE_PRESS_AND_HOLD,
 | 
						|
                                           GtkPressAndHoldPrivate);
 | 
						|
 | 
						|
  pah->priv->hold_time = 1000;
 | 
						|
  pah->priv->drag_threshold = 8;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
press_and_hold_finalize (GObject *object)
 | 
						|
{
 | 
						|
  GtkPressAndHold *pah = GTK_PRESS_AND_HOLD (object);
 | 
						|
 | 
						|
  if (pah->priv->timeout)
 | 
						|
    g_source_remove (pah->priv->timeout);
 | 
						|
 | 
						|
  G_OBJECT_CLASS (gtk_press_and_hold_parent_class)->finalize (object);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
press_and_hold_get_property (GObject    *object,
 | 
						|
                             guint       prop_id,
 | 
						|
                             GValue     *value,
 | 
						|
                             GParamSpec *pspec)
 | 
						|
{
 | 
						|
  GtkPressAndHold *pah = GTK_PRESS_AND_HOLD (object);
 | 
						|
 | 
						|
  switch (prop_id)
 | 
						|
    {
 | 
						|
    case PROP_HOLD_TIME:
 | 
						|
      g_value_set_int (value, pah->priv->hold_time);
 | 
						|
      break;
 | 
						|
    case PROP_DRAG_THRESHOLD:
 | 
						|
      g_value_set_int (value, pah->priv->drag_threshold);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
press_and_hold_set_property (GObject      *object,
 | 
						|
                             guint         prop_id,
 | 
						|
                             const GValue *value,
 | 
						|
                             GParamSpec   *pspec)
 | 
						|
{
 | 
						|
  GtkPressAndHold *pah = GTK_PRESS_AND_HOLD (object);
 | 
						|
 | 
						|
  switch (prop_id)
 | 
						|
    {
 | 
						|
    case PROP_HOLD_TIME:
 | 
						|
      pah->priv->hold_time = g_value_get_int (value);
 | 
						|
      break;
 | 
						|
    case PROP_DRAG_THRESHOLD:
 | 
						|
      pah->priv->hold_time = g_value_get_int (value);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_press_and_hold_class_init (GtkPressAndHoldClass *class)
 | 
						|
{
 | 
						|
  GObjectClass *object_class = (GObjectClass *)class;
 | 
						|
 | 
						|
  object_class->get_property = press_and_hold_get_property;
 | 
						|
  object_class->set_property = press_and_hold_set_property;
 | 
						|
  object_class->finalize = press_and_hold_finalize;
 | 
						|
 | 
						|
  signals[HOLD] =
 | 
						|
    g_signal_new ("hold",
 | 
						|
                  GTK_TYPE_PRESS_AND_HOLD,
 | 
						|
                  G_SIGNAL_RUN_FIRST,
 | 
						|
                  G_STRUCT_OFFSET (GtkPressAndHoldClass, hold),
 | 
						|
                  NULL, NULL, NULL,
 | 
						|
                  G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
 | 
						|
 | 
						|
  signals[TAP] =
 | 
						|
    g_signal_new ("tap",
 | 
						|
                  GTK_TYPE_PRESS_AND_HOLD,
 | 
						|
                  G_SIGNAL_RUN_FIRST,
 | 
						|
                  G_STRUCT_OFFSET (GtkPressAndHoldClass, tap),
 | 
						|
                  NULL, NULL, NULL,
 | 
						|
                  G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_HOLD_TIME,
 | 
						|
      g_param_spec_int ("hold-time", P_("Hold Time"), P_("Hold Time (in milliseconds)"),
 | 
						|
                        0, G_MAXINT, 1000, GTK_PARAM_READWRITE));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_DRAG_THRESHOLD,
 | 
						|
      g_param_spec_int ("drag-threshold", P_("Drag Threshold"), P_("Drag Threshold (in pixels)"),
 | 
						|
                        1, G_MAXINT, 8, GTK_PARAM_READWRITE));
 | 
						|
 | 
						|
  g_type_class_add_private (object_class, sizeof (GtkPressAndHoldPrivate));
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
press_and_hold_cancel (GtkPressAndHold *pah)
 | 
						|
{
 | 
						|
  GtkPressAndHoldPrivate *priv = pah->priv;
 | 
						|
 | 
						|
  if (priv->timeout)
 | 
						|
    g_source_remove (priv->timeout);
 | 
						|
 | 
						|
  priv->timeout = 0;
 | 
						|
  priv->sequence = NULL;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
hold_action (gpointer data)
 | 
						|
{
 | 
						|
  GtkPressAndHold *pah = data;
 | 
						|
  GtkPressAndHoldPrivate *priv = pah->priv;
 | 
						|
 | 
						|
  press_and_hold_cancel (pah);
 | 
						|
 | 
						|
  g_signal_emit (pah, signals[HOLD], 0, priv->x, priv->y);
 | 
						|
 | 
						|
  return G_SOURCE_REMOVE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gtk_press_and_hold_process_event (GtkPressAndHold *pah,
 | 
						|
                                  GdkEvent        *event)
 | 
						|
{
 | 
						|
  GtkPressAndHoldPrivate *priv = pah->priv;
 | 
						|
 | 
						|
  /* We're already tracking a different touch, ignore */
 | 
						|
  if ((event->type == GDK_TOUCH_BEGIN && priv->sequence != NULL) ||
 | 
						|
      (event->type != GDK_TOUCH_BEGIN && priv->sequence != event->touch.sequence))
 | 
						|
    return;
 | 
						|
 | 
						|
  priv->x = event->touch.x;
 | 
						|
  priv->y = event->touch.y;
 | 
						|
 | 
						|
  if (event->type == GDK_TOUCH_BEGIN)
 | 
						|
    {
 | 
						|
      priv->sequence = event->touch.sequence;
 | 
						|
      priv->start_x = priv->x;
 | 
						|
      priv->start_y = priv->y;
 | 
						|
      priv->timeout =
 | 
						|
          gdk_threads_add_timeout (priv->hold_time, hold_action, pah);
 | 
						|
    }
 | 
						|
  else if (event->type == GDK_TOUCH_UPDATE)
 | 
						|
    {
 | 
						|
      if (ABS (priv->x - priv->start_x) > priv->drag_threshold ||
 | 
						|
          ABS (priv->y - priv->start_y) > priv->drag_threshold)
 | 
						|
        press_and_hold_cancel (pah);
 | 
						|
    }
 | 
						|
  else if (event->type == GDK_TOUCH_END)
 | 
						|
    {
 | 
						|
      press_and_hold_cancel (pah);
 | 
						|
      g_signal_emit (pah, signals[TAP], 0, priv->x, priv->y);
 | 
						|
    }
 | 
						|
  else if (event->type == GDK_TOUCH_CANCEL)
 | 
						|
    {
 | 
						|
      press_and_hold_cancel (pah);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
GtkPressAndHold *
 | 
						|
gtk_press_and_hold_new (void)
 | 
						|
{
 | 
						|
  return (GtkPressAndHold *) g_object_new (GTK_TYPE_PRESS_AND_HOLD, NULL);
 | 
						|
}
 |