[gtk+] Break out press-and-hold code as its own object
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Break out press-and-hold code as its own object
- Date: Sun, 4 Mar 2012 05:28:55 +0000 (UTC)
commit 912ad3b6989c9206fea95afe9a0fd03f8413db08
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Mar 3 23:42:54 2012 -0500
Break out press-and-hold code as its own object
https://bugzilla.gnome.org/show_bug.cgi?id=671057
gtk/Makefile.am | 2 +
gtk/gtkcolorplane.c | 58 +++++++++++
gtk/gtkcolorswatch.c | 95 ++++++------------
gtk/gtkpressandhold.c | 226 ++++++++++++++++++++++++++++++++++++++++++
gtk/gtkpressandholdprivate.h | 68 +++++++++++++
5 files changed, 383 insertions(+), 66 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 9f4f818..bb60b3d 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -470,6 +470,7 @@ gtk_private_h_sources = \
gtkorientableprivate.h \
gtkpango.h \
gtkpathbar.h \
+ gtkpressandholdprivate.h \
gtkprintoperation-private.h \
gtkprintutils.h \
gtkprivate.h \
@@ -707,6 +708,7 @@ gtk_base_c_sources = \
gtkpango.c \
gtkpapersize.c \
gtkpathbar.c \
+ gtkpressandhold.c \
gtkprintcontext.c \
gtkprintoperation.c \
gtkprintoperationpreview.c \
diff --git a/gtk/gtkcolorplane.c b/gtk/gtkcolorplane.c
index c8b2d71..c1ca898 100644
--- a/gtk/gtkcolorplane.c
+++ b/gtk/gtkcolorplane.c
@@ -22,6 +22,7 @@
#include "gtkaccessible.h"
#include "gtkadjustment.h"
#include "gtkcolorutils.h"
+#include "gtkpressandholdprivate.h"
#include "gtkintl.h"
struct _GtkColorPlanePrivate
@@ -32,6 +33,8 @@ struct _GtkColorPlanePrivate
cairo_surface_t *surface;
gboolean in_drag;
+
+ GtkPressAndHold *press_and_hold;
};
G_DEFINE_TYPE (GtkColorPlane, gtk_color_plane, GTK_TYPE_DRAWING_AREA)
@@ -286,6 +289,58 @@ plane_motion_notify (GtkWidget *widget,
}
static void
+hold_action (GtkPressAndHold *pah,
+ gint x,
+ gint y,
+ GtkColorPlane *plane)
+{
+ gboolean handled;
+
+ g_signal_emit_by_name (plane, "popup-menu", &handled);
+}
+
+static void
+tap_action (GtkPressAndHold *pah,
+ gint x,
+ gint y,
+ GtkColorPlane *plane)
+{
+ update_color (plane, x, y);
+}
+
+static gboolean
+plane_touch (GtkWidget *widget,
+ GdkEventTouch *event)
+{
+ GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
+
+ if (!plane->priv->press_and_hold)
+ {
+ gint drag_threshold;
+
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-dnd-drag-threshold", &drag_threshold,
+ NULL);
+
+ plane->priv->press_and_hold = gtk_press_and_hold_new ();
+
+ g_object_set (plane->priv->press_and_hold,
+ "drag-threshold", drag_threshold,
+ "hold-time", 1000,
+ NULL);
+
+ g_signal_connect (plane->priv->press_and_hold, "hold",
+ G_CALLBACK (hold_action), plane);
+ g_signal_connect (plane->priv->press_and_hold, "tap",
+ G_CALLBACK (tap_action), plane);
+ }
+
+ gtk_press_and_hold_process_event (plane->priv->press_and_hold, (GdkEvent *)event);
+
+ return TRUE;
+}
+
+static void
sv_move (GtkColorPlane *plane,
gdouble ds,
gdouble dv)
@@ -406,6 +461,8 @@ plane_finalize (GObject *object)
g_clear_object (&plane->priv->s_adj);
g_clear_object (&plane->priv->v_adj);
+ g_clear_object (&plane->priv->press_and_hold);
+
G_OBJECT_CLASS (gtk_color_plane_parent_class)->finalize (object);
}
@@ -424,6 +481,7 @@ gtk_color_plane_class_init (GtkColorPlaneClass *class)
widget_class->motion_notify_event = plane_motion_notify;
widget_class->grab_broken_event = plane_grab_broken;
widget_class->key_press_event = plane_key_press;
+ widget_class->touch_event= plane_touch;
g_type_class_add_private (class, sizeof (GtkColorPlanePrivate));
}
diff --git a/gtk/gtkcolorswatch.c b/gtk/gtkcolorswatch.c
index c75ef2d..810112d 100644
--- a/gtk/gtkcolorswatch.c
+++ b/gtk/gtkcolorswatch.c
@@ -28,20 +28,12 @@
#include "gtkmenu.h"
#include "gtkmenuitem.h"
#include "gtkmenushell.h"
+#include "gtkpressandholdprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "a11y/gtkcolorswatchaccessible.h"
-typedef struct {
- GtkWidget *widget;
-
- GdkEventSequence *sequence;
- guint press_and_hold_id;
- gint start_x;
- gint start_y;
-} GtkPressAndHoldData;
-
struct _GtkColorSwatchPrivate
{
GdkRGBA color;
@@ -54,7 +46,7 @@ struct _GtkColorSwatchPrivate
GdkWindow *event_window;
- GtkPressAndHoldData *press_and_hold;
+ GtkPressAndHold *press_and_hold;
};
enum
@@ -531,80 +523,52 @@ swatch_button_release (GtkWidget *widget,
}
static void
-swatch_press_and_hold_cancel (GtkWidget *widget,
- GtkPressAndHoldData *data)
+hold_action (GtkPressAndHold *pah,
+ gint x,
+ gint y,
+ GtkColorSwatch *swatch)
{
- if (data->press_and_hold_id)
- {
- g_source_remove (data->press_and_hold_id);
- data->press_and_hold_id = 0;
- }
-
- data->sequence = NULL;
+ emit_customize (swatch);
}
static void
-swatch_press_and_hold_free (GtkPressAndHoldData *data)
+tap_action (GtkPressAndHold *pah,
+ gint x,
+ gint y,
+ GtkColorSwatch *swatch)
{
- swatch_press_and_hold_cancel (data->widget, data);
- g_slice_free (GtkPressAndHoldData, data);
-}
-
-static gboolean
-swatch_press_and_hold_action (gpointer data)
-{
- GtkPressAndHoldData *pah = data;
-
- emit_customize (GTK_COLOR_SWATCH (pah->widget));
- swatch_press_and_hold_cancel (pah->widget, pah);
-
- return G_SOURCE_REMOVE;
+ swatch_primary_action (swatch);
}
-
static gboolean
swatch_touch (GtkWidget *widget,
GdkEventTouch *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
- GtkPressAndHoldData *data;
if (!swatch->priv->press_and_hold)
- swatch->priv->press_and_hold = g_slice_new0 (GtkPressAndHoldData);
+ {
+ gint drag_threshold;
- data = swatch->priv->press_and_hold;
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-dnd-drag-threshold", &drag_threshold,
+ NULL);
- /* We're already tracking a different touch, ignore */
- if (data->sequence != NULL && data->sequence != event->sequence)
- return TRUE;
+ swatch->priv->press_and_hold = gtk_press_and_hold_new ();
- if (event->type == GDK_TOUCH_BEGIN)
- {
- data->widget = widget;
- data->sequence = event->sequence;
- data->start_x = event->x;
- data->start_y = event->y;
+ g_object_set (swatch->priv->press_and_hold,
+ "drag-threshold", drag_threshold,
+ "hold-time", 1000,
+ NULL);
- data->press_and_hold_id =
- gdk_threads_add_timeout (1000, swatch_press_and_hold_action, data);
- }
- else if (event->type == GDK_TOUCH_UPDATE)
- {
- if (gtk_drag_check_threshold (widget,
- data->start_x, data->start_y,
- event->x, event->y))
- swatch_press_and_hold_cancel (widget, data);
- }
- else if (event->type == GDK_TOUCH_END)
- {
- swatch_press_and_hold_cancel (widget, data);
- swatch_primary_action (swatch);
- }
- else if (event->type == GDK_TOUCH_CANCEL)
- {
- swatch_press_and_hold_cancel (widget, data);
+ g_signal_connect (swatch->priv->press_and_hold, "hold",
+ G_CALLBACK (hold_action), swatch);
+ g_signal_connect (swatch->priv->press_and_hold, "tap",
+ G_CALLBACK (tap_action), swatch);
}
+ gtk_press_and_hold_process_event (swatch->priv->press_and_hold, (GdkEvent *)event);
+
return TRUE;
}
@@ -759,8 +723,7 @@ swatch_finalize (GObject *object)
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
g_free (swatch->priv->icon);
- if (swatch->priv->press_and_hold)
- swatch_press_and_hold_free (swatch->priv->press_and_hold);
+ g_clear_object (&swatch->priv->press_and_hold);
G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
}
diff --git a/gtk/gtkpressandhold.c b/gtk/gtkpressandhold.c
new file mode 100644
index 0000000..aed0095
--- /dev/null
+++ b/gtk/gtkpressandhold.c
@@ -0,0 +1,226 @@
+/* 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 (priv->sequence != NULL && 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);
+}
diff --git a/gtk/gtkpressandholdprivate.h b/gtk/gtkpressandholdprivate.h
new file mode 100644
index 0000000..ccccca2
--- /dev/null
+++ b/gtk/gtkpressandholdprivate.h
@@ -0,0 +1,68 @@
+/* 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/>.
+ */
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_PRESS_AND_HOLD_H__
+#define __GTK_PRESS_AND_HOLD_H__
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRESS_AND_HOLD (gtk_press_and_hold_get_type ())
+#define GTK_PRESS_AND_HOLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRESS_AND_HOLD, GtkPressAndHold))
+#define GTK_PRESS_AND_HOLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRESS_AND_HOLD, GtkPressAndHoldClass))
+#define GTK_IS_PRESS_AND_HOLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRESS_AND_HOLD))
+#define GTK_IS_PRESS_AND_HOLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRESS_AND_HOLD))
+#define GTK_PRESS_AND_HOLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRESS_AND_HOLD, GtkPressAndHoldClass))
+
+
+typedef struct _GtkPressAndHold GtkPressAndHold;
+typedef struct _GtkPressAndHoldClass GtkPressAndHoldClass;
+typedef struct _GtkPressAndHoldPrivate GtkPressAndHoldPrivate;
+
+struct _GtkPressAndHold
+{
+ GObject parent;
+
+ /*< private >*/
+ GtkPressAndHoldPrivate *priv;
+};
+
+struct _GtkPressAndHoldClass
+{
+ GObjectClass parent_class;
+
+ void ( * hold) (GtkPressAndHold *pah, gint x, gint y);
+ void ( * tap) (GtkPressAndHold *pah, gint x, gint y);
+};
+
+
+G_GNUC_INTERNAL
+GType gtk_press_and_hold_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GtkPressAndHold * gtk_press_and_hold_new (void);
+
+G_GNUC_INTERNAL
+void gtk_press_and_hold_process_event (GtkPressAndHold *pah,
+ GdkEvent *event);
+
+G_END_DECLS
+
+#endif /* __GTK_PRESS_AND_HOLD_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]