[gtk+/gestures] paned: Use GtkGesture to handle handle dragging
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gestures] paned: Use GtkGesture to handle handle dragging
- Date: Mon, 19 May 2014 19:19:19 +0000 (UTC)
commit 3b8b76be89d5567c6bc85fca68cf4ac018a53e64
Author: Carlos Garnacho <carlosg gnome org>
Date: Mon May 19 19:58:54 2014 +0200
paned: Use GtkGesture to handle handle dragging
Dragging is all handled by a GtkGesturePan now, matching the
paned orientation.
On touch events, a wider area is listened for, so touch events
don't need to be as accurate to initiate dragging, if no dragging
is truly initiated in this case, events are just forwarded for
child widgets to handle.
gtk/gtkpaned.c | 287 ++++++++++++++++++++++++++------------------------------
1 files changed, 134 insertions(+), 153 deletions(-)
---
diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c
index 6a0b6e5..fe28801 100644
--- a/gtk/gtkpaned.c
+++ b/gtk/gtkpaned.c
@@ -110,10 +110,11 @@ struct _GtkPanedPrivate
GtkOrientation orientation;
GdkCursorType cursor_type;
- GdkDevice *grab_device;
GdkRectangle handle_pos;
GdkWindow *handle;
+ GtkGesture *pan_gesture;
+
gint child1_size;
gint drag_pos;
gint last_allocation;
@@ -121,16 +122,14 @@ struct _GtkPanedPrivate
gint min_position;
gint original_position;
- guint32 grab_time;
-
guint handle_prelit : 1;
- guint in_drag : 1;
guint in_recursion : 1;
guint child1_resize : 1;
guint child1_shrink : 1;
guint child2_resize : 1;
guint child2_shrink : 1;
guint position_set : 1;
+ guint panning : 1;
};
enum {
@@ -209,16 +208,8 @@ static gboolean gtk_paned_enter (GtkWidget *widget,
GdkEventCrossing *event);
static gboolean gtk_paned_leave (GtkWidget *widget,
GdkEventCrossing *event);
-static gboolean gtk_paned_button_press (GtkWidget *widget,
- GdkEventButton *event);
-static gboolean gtk_paned_button_release (GtkWidget *widget,
- GdkEventButton *event);
-static gboolean gtk_paned_motion (GtkWidget *widget,
- GdkEventMotion *event);
static gboolean gtk_paned_focus (GtkWidget *widget,
GtkDirectionType direction);
-static gboolean gtk_paned_grab_broken (GtkWidget *widget,
- GdkEventGrabBroken *event);
static void gtk_paned_add (GtkContainer *container,
GtkWidget *widget);
static void gtk_paned_remove (GtkContainer *container,
@@ -252,9 +243,10 @@ static gboolean gtk_paned_cancel_position (GtkPaned *paned);
static gboolean gtk_paned_toggle_handle_focus (GtkPaned *paned);
static GType gtk_paned_child_type (GtkContainer *container);
-static void gtk_paned_grab_notify (GtkWidget *widget,
- gboolean was_grabbed);
+static void update_drag (GtkPaned *paned,
+ int xpos,
+ int ypos);
G_DEFINE_TYPE_WITH_CODE (GtkPaned, gtk_paned, GTK_TYPE_CONTAINER,
G_ADD_PRIVATE (GtkPaned)
@@ -316,11 +308,6 @@ gtk_paned_class_init (GtkPanedClass *class)
widget_class->focus = gtk_paned_focus;
widget_class->enter_notify_event = gtk_paned_enter;
widget_class->leave_notify_event = gtk_paned_leave;
- widget_class->button_press_event = gtk_paned_button_press;
- widget_class->button_release_event = gtk_paned_button_release;
- widget_class->motion_notify_event = gtk_paned_motion;
- widget_class->grab_broken_event = gtk_paned_grab_broken;
- widget_class->grab_notify = gtk_paned_grab_notify;
widget_class->state_flags_changed = gtk_paned_state_flags_changed;
container_class->add = gtk_paned_add;
@@ -667,10 +654,106 @@ gtk_paned_child_type (GtkContainer *container)
return G_TYPE_NONE;
}
+static gboolean
+initiates_touch_drag (GtkPaned *paned,
+ gdouble start_x,
+ gdouble start_y)
+{
+ gint handle_size, handle_pos, drag_pos;
+ GtkPanedPrivate *priv = paned->priv;
+ GtkAllocation allocation;
+
+#define TOUCH_EXTRA_AREA_WIDTH 50
+ gtk_widget_get_allocation (GTK_WIDGET (paned), &allocation);
+ gtk_widget_style_get (GTK_WIDGET (paned), "handle-size", &handle_size, NULL);
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ handle_pos = priv->handle_pos.x - allocation.x;
+ drag_pos = start_x;
+ }
+ else
+ {
+ handle_pos = priv->handle_pos.y - allocation.y;
+ drag_pos = start_y;
+ }
+
+ if (drag_pos < handle_pos - TOUCH_EXTRA_AREA_WIDTH ||
+ drag_pos > handle_pos + handle_size + TOUCH_EXTRA_AREA_WIDTH)
+ return FALSE;
+
+#undef TOUCH_EXTRA_AREA_WIDTH
+
+ return TRUE;
+}
+
+static void
+pan_gesture_drag_begin_cb (GtkGestureDrag *gesture,
+ gdouble start_x,
+ gdouble start_y,
+ GtkPaned *paned)
+{
+ GtkPanedPrivate *priv = paned->priv;
+ GdkEventSequence *sequence;
+ GtkAllocation allocation;
+ const GdkEvent *event;
+
+ sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+ event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+ gtk_widget_get_allocation (GTK_WIDGET (paned), &allocation);
+ paned->priv->panning = FALSE;
+
+ if (event->any.window == priv->handle ||
+ (event->type == GDK_TOUCH_BEGIN &&
+ initiates_touch_drag (paned, start_x, start_y)))
+ {
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ priv->drag_pos = start_x - (priv->handle_pos.x - allocation.x);
+ else
+ priv->drag_pos = start_y - (priv->handle_pos.y - allocation.y);
+
+ gtk_gesture_set_state (GTK_GESTURE (gesture),
+ GTK_EVENT_SEQUENCE_CLAIMED);
+ }
+ else
+ {
+ gtk_gesture_set_state (GTK_GESTURE (gesture),
+ GTK_EVENT_SEQUENCE_DENIED);
+ }
+}
+
+static void
+pan_gesture_pan_cb (GtkGesturePan *gesture,
+ GtkPanDirection direction,
+ gdouble offset,
+ GtkPaned *paned)
+{
+ gdouble start_x, start_y, offset_x, offset_y;
+
+ paned->priv->panning = TRUE;
+
+ gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (gesture),
+ &start_x, &start_y);
+ gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (gesture),
+ &offset_x, &offset_y);
+ update_drag (paned, start_x + offset_x, start_y + offset_y);
+}
+
+static void
+pan_gesture_drag_end_cb (GtkGestureDrag *gesture,
+ gdouble offset_x,
+ gdouble offset_y,
+ GtkPaned *paned)
+{
+ if (!paned->priv->panning)
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
+}
+
static void
gtk_paned_init (GtkPaned *paned)
{
GtkPanedPrivate *priv;
+ GtkGesture *gesture;
gtk_widget_set_has_window (GTK_WIDGET (paned), FALSE);
gtk_widget_set_can_focus (GTK_WIDGET (paned), TRUE);
@@ -694,7 +777,6 @@ gtk_paned_init (GtkPaned *paned)
priv->handle_pos.height = 5;
priv->position_set = FALSE;
priv->last_allocation = -1;
- priv->in_drag = FALSE;
priv->last_child1_focus = NULL;
priv->last_child2_focus = NULL;
@@ -705,7 +787,17 @@ gtk_paned_init (GtkPaned *paned)
priv->handle_pos.x = -1;
priv->handle_pos.y = -1;
- priv->drag_pos = -1;
+ gesture = gtk_gesture_pan_new (GTK_WIDGET (paned),
+ GTK_PAN_ORIENTATION_HORIZONTAL);
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
+ g_signal_connect (gesture, "drag-begin",
+ G_CALLBACK (pan_gesture_drag_begin_cb), paned);
+ g_signal_connect (gesture, "pan",
+ G_CALLBACK (pan_gesture_pan_cb), paned);
+ g_signal_connect (gesture, "drag-end",
+ G_CALLBACK (pan_gesture_drag_end_cb), paned);
+ gtk_gesture_attach (gesture, GTK_PHASE_CAPTURE);
+ priv->pan_gesture = gesture;
}
static void
@@ -724,9 +816,17 @@ gtk_paned_set_property (GObject *object,
_gtk_orientable_set_style_classes (GTK_ORIENTABLE (paned));
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- priv->cursor_type = GDK_SB_H_DOUBLE_ARROW;
+ {
+ priv->cursor_type = GDK_SB_H_DOUBLE_ARROW;
+ gtk_gesture_pan_set_orientation (GTK_GESTURE_PAN (priv->pan_gesture),
+ GTK_PAN_ORIENTATION_HORIZONTAL);
+ }
else
- priv->cursor_type = GDK_SB_V_DOUBLE_ARROW;
+ {
+ priv->cursor_type = GDK_SB_V_DOUBLE_ARROW;
+ gtk_gesture_pan_set_orientation (GTK_GESTURE_PAN (priv->pan_gesture),
+ GTK_PAN_ORIENTATION_VERTICAL);
+ }
/* state_flags_changed updates the cursor */
gtk_paned_state_flags_changed (GTK_WIDGET (paned), 0);
@@ -866,6 +966,9 @@ gtk_paned_finalize (GObject *object)
gtk_paned_set_saved_focus (paned, NULL);
gtk_paned_set_first_paned (paned, NULL);
+ gtk_gesture_detach (paned->priv->pan_gesture);
+ g_clear_object (&paned->priv->pan_gesture);
+
G_OBJECT_CLASS (gtk_paned_parent_class)->finalize (object);
}
@@ -1634,10 +1737,9 @@ is_rtl (GtkPaned *paned)
}
static void
-update_drag (GtkPaned *paned,
- /* relative to priv->handle */
- int xpos,
- int ypos)
+update_drag (GtkPaned *paned,
+ int xpos,
+ int ypos)
{
GtkPanedPrivate *priv = paned->priv;
GtkAllocation allocation;
@@ -1650,13 +1752,9 @@ update_drag (GtkPaned *paned,
gdk_window_get_position (priv->handle, &x, &y);
gtk_widget_get_allocation (widget, &allocation);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- pos = xpos + x - allocation.x;
- }
+ pos = xpos;
else
- {
- pos = ypos + y - allocation.y;
- }
+ pos = ypos;
pos -= priv->drag_pos;
@@ -1686,9 +1784,7 @@ gtk_paned_enter (GtkWidget *widget,
GtkPaned *paned = GTK_PANED (widget);
GtkPanedPrivate *priv = paned->priv;
- if (priv->in_drag)
- update_drag (paned, event->x, event->y);
- else
+ if (!gtk_gesture_is_active (priv->pan_gesture))
{
priv->handle_prelit = TRUE;
gtk_widget_queue_draw_area (widget,
@@ -1708,9 +1804,7 @@ gtk_paned_leave (GtkWidget *widget,
GtkPaned *paned = GTK_PANED (widget);
GtkPanedPrivate *priv = paned->priv;
- if (priv->in_drag)
- update_drag (paned, event->x, event->y);
- else
+ if (!gtk_gesture_is_active (priv->pan_gesture))
{
priv->handle_prelit = FALSE;
gtk_widget_queue_draw_area (widget,
@@ -1741,86 +1835,6 @@ gtk_paned_focus (GtkWidget *widget,
return retval;
}
-static gboolean
-gtk_paned_button_press (GtkWidget *widget,
- GdkEventButton *event)
-{
- GtkPaned *paned = GTK_PANED (widget);
- GtkPanedPrivate *priv = paned->priv;
-
- if (!priv->in_drag &&
- (event->window == priv->handle) && (event->button == GDK_BUTTON_PRIMARY))
- {
- /* We need a server grab here, not gtk_grab_add(), since
- * we don't want to pass events on to the widget's children */
- if (gdk_device_grab (event->device,
- priv->handle,
- GDK_OWNERSHIP_WINDOW, FALSE,
- GDK_BUTTON1_MOTION_MASK
- | GDK_BUTTON_RELEASE_MASK
- | GDK_ENTER_NOTIFY_MASK
- | GDK_LEAVE_NOTIFY_MASK,
- NULL, event->time) != GDK_GRAB_SUCCESS)
- return FALSE;
-
- priv->in_drag = TRUE;
- priv->grab_time = event->time;
- priv->grab_device = event->device;
-
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- priv->drag_pos = event->x;
- else
- priv->drag_pos = event->y;
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-gtk_paned_grab_broken (GtkWidget *widget,
- GdkEventGrabBroken *event)
-{
- GtkPaned *paned = GTK_PANED (widget);
- GtkPanedPrivate *priv = paned->priv;
-
- priv->in_drag = FALSE;
- priv->drag_pos = -1;
- priv->position_set = TRUE;
-
- return TRUE;
-}
-
-static void
-stop_drag (GtkPaned *paned)
-{
- GtkPanedPrivate *priv = paned->priv;
-
- priv->in_drag = FALSE;
- priv->drag_pos = -1;
- priv->position_set = TRUE;
-
- gdk_device_ungrab (priv->grab_device,
- priv->grab_time);
- priv->grab_device = NULL;
-}
-
-static void
-gtk_paned_grab_notify (GtkWidget *widget,
- gboolean was_grabbed)
-{
- GtkPaned *paned = GTK_PANED (widget);
- GtkPanedPrivate *priv = paned->priv;
- GdkDevice *grab_device;
-
- grab_device = priv->grab_device;
-
- if (priv->in_drag && grab_device &&
- gtk_widget_device_is_shadowed (widget, grab_device))
- stop_drag (paned);
-}
-
static void
gtk_paned_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state)
@@ -1844,39 +1858,6 @@ gtk_paned_state_flags_changed (GtkWidget *widget,
}
}
-static gboolean
-gtk_paned_button_release (GtkWidget *widget,
- GdkEventButton *event)
-{
- GtkPaned *paned = GTK_PANED (widget);
- GtkPanedPrivate *priv = paned->priv;
-
- if (priv->in_drag && (event->button == GDK_BUTTON_PRIMARY))
- {
- stop_drag (paned);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-gtk_paned_motion (GtkWidget *widget,
- GdkEventMotion *event)
-{
- GtkPaned *paned = GTK_PANED (widget);
- GtkPanedPrivate *priv = paned->priv;
-
- if (priv->in_drag)
- {
- update_drag (paned, event->x, event->y);
- return TRUE;
- }
-
- return FALSE;
-}
-
/**
* gtk_paned_new:
* @orientation: the paned’s orientation.
@@ -2848,4 +2829,4 @@ gtk_paned_get_handle_window (GtkPaned *paned)
g_return_val_if_fail (GTK_IS_PANED (paned), NULL);
return paned->priv->handle;
-}
\ No newline at end of file
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]