summaryrefslogtreecommitdiff
path: root/gtk/gtkpaned.c
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2014-05-19 19:58:54 +0200
committerCarlos Garnacho <carlosg@gnome.org>2014-05-23 19:54:32 +0200
commit681164564e2a681f1d157a47c67e2fa975de6b4f (patch)
tree392369877eb985c489ef6973bd500ea7c81e6cc3 /gtk/gtkpaned.c
parent8f20780fb936ced3d4a886d862dfe165798b43bb (diff)
downloadgtk+-681164564e2a681f1d157a47c67e2fa975de6b4f.tar.gz
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.
Diffstat (limited to 'gtk/gtkpaned.c')
-rw-r--r--gtk/gtkpaned.c287
1 files changed, 134 insertions, 153 deletions
diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c
index 6a0b6e5bc1..fe28801691 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
+}