[gtk+/gestures: 54/92] window: Use gestures for window moving/resizing
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gestures: 54/92] window: Use gestures for window moving/resizing
- Date: Tue, 8 Apr 2014 19:44:57 +0000 (UTC)
commit 825b33a7aeb25d258fc0e906bc2d66c58de63fb2
Author: Carlos Garnacho <carlosg gnome org>
Date: Fri Mar 28 15:44:11 2014 +0100
window: Use gestures for window moving/resizing
A multipress gesture is used to control all this, replacing
single/double click custom code, and triggering window dragging
when the multipress is stopped, yet active (ie. the sequence remains
pressed).
gtk/gtkmain.c | 6 -
gtk/gtkwindow.c | 375 ++++++++++++++++++++-----------------------------------
2 files changed, 133 insertions(+), 248 deletions(-)
---
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 4701435..657aab0 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1545,12 +1545,6 @@ gtk_main_do_event (GdkEvent *event)
event_widget = gtk_get_event_widget (event);
}
- if (GTK_IS_WINDOW (event_widget))
- {
- if (_gtk_window_check_handle_wm_event (event))
- return;
- }
-
window_group = gtk_main_get_window_group (event_widget);
device = gdk_event_get_device (event);
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index d791186..77d1d6c 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -232,9 +232,7 @@ struct _GtkWindowPrivate
guint drag_possible : 1;
- gint button_press_x;
- gint button_press_y;
- guint32 button_press_time;
+ GtkGesture *multipress_gesture;
};
enum {
@@ -403,12 +401,6 @@ static gint gtk_window_key_press_event (GtkWidget *widget,
GdkEventKey *event);
static gint gtk_window_key_release_event (GtkWidget *widget,
GdkEventKey *event);
-static gint gtk_window_button_press_event (GtkWidget *widget,
- GdkEventButton *event);
-static gint gtk_window_button_release_event (GtkWidget *widget,
- GdkEventButton *event);
-static gint gtk_window_motion_notify_event (GtkWidget *widget,
- GdkEventMotion *event);
static gint gtk_window_focus_in_event (GtkWidget *widget,
GdkEventFocus *event);
static gint gtk_window_focus_out_event (GtkWidget *widget,
@@ -578,6 +570,11 @@ static void unset_titlebar (GtkWindow *window);
static void on_titlebar_title_notify (GtkHeaderBar *titlebar,
GParamSpec *pspec,
GtkWindow *self);
+static GtkWindowRegion get_active_region_type (GtkWindow *window,
+ GdkEventAny *event,
+ gint x,
+ gint y);
+
G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
G_ADD_PRIVATE (GtkWindow)
@@ -683,9 +680,6 @@ gtk_window_class_init (GtkWindowClass *klass)
widget_class->key_press_event = gtk_window_key_press_event;
widget_class->key_release_event = gtk_window_key_release_event;
widget_class->focus_in_event = gtk_window_focus_in_event;
- widget_class->button_press_event = gtk_window_button_press_event;
- widget_class->button_release_event = gtk_window_button_release_event;
- widget_class->motion_notify_event = gtk_window_motion_notify_event;
widget_class->focus_out_event = gtk_window_focus_out_event;
widget_class->focus = gtk_window_focus;
widget_class->move_focus = gtk_window_move_focus;
@@ -1352,6 +1346,124 @@ popover_destroy (GtkWindowPopover *popover)
}
static void
+multipress_gesture_pressed_cb (GtkGestureMultiPress *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ GtkWindow *window)
+{
+ GtkWidget *event_widget, *widget;
+ gboolean window_drag = FALSE;
+ GdkEventSequence *sequence;
+ GtkWindowRegion region;
+ GtkWindowPrivate *priv;
+ const GdkEvent *event;
+ guint button;
+
+ widget = GTK_WIDGET (window);
+ priv = gtk_window_get_instance_private (window);
+ sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+ button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+
+ event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+
+ region = get_active_region_type (window, (GdkEventAny*) event, x, y);
+ priv->drag_possible = FALSE;
+
+ if (button == GDK_BUTTON_SECONDARY && region == GTK_WINDOW_REGION_TITLE)
+ {
+ gtk_window_do_popup (window, (GdkEventButton*) event);
+ gtk_widget_set_sequence_state (widget, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
+ return;
+ }
+ else if (button == GDK_BUTTON_MIDDLE && region == GTK_WINDOW_REGION_TITLE)
+ {
+ gdk_window_lower (gtk_widget_get_window (GTK_WIDGET (window)));
+ gtk_widget_set_sequence_state (widget, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
+ return;
+ }
+ else if (button != GDK_BUTTON_PRIMARY)
+ return;
+
+ event_widget = gtk_get_event_widget ((GdkEvent*) event);
+
+ switch (region)
+ {
+ case GTK_WINDOW_REGION_CONTENT:
+ if (event_widget != widget)
+ gtk_widget_style_get (event_widget, "window-dragging",
+ &window_drag, NULL);
+ /* fall thru */
+ case GTK_WINDOW_REGION_TITLE:
+ if (!window_drag && event_widget != widget)
+ {
+ gtk_widget_set_sequence_state (widget, sequence,
+ GTK_EVENT_SEQUENCE_DENIED);
+ return;
+ }
+
+ if (n_press == 2)
+ _gtk_window_toggle_maximized (window);
+ /* fall thru */
+ case GTK_WINDOW_REGION_EDGE:
+ if (n_press == 1)
+ priv->drag_possible = TRUE;
+ break;
+ default:
+ if (!priv->maximized)
+ {
+ gdouble x_root, y_root;
+
+ gdk_event_get_root_coords (event, &x_root, &y_root);
+ gdk_window_begin_resize_drag_for_device (gtk_widget_get_window (widget),
+ (GdkWindowEdge) region,
+ gdk_event_get_device ((GdkEvent *) event),
+ GDK_BUTTON_PRIMARY,
+ x_root, y_root,
+ gdk_event_get_time (event));
+ }
+ break;
+ }
+
+ gtk_widget_set_sequence_state (widget, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
+static void
+multipress_gesture_stopped_cb (GtkGestureMultiPress *gesture,
+ GtkWindow *window)
+{
+ GdkEventSequence *sequence;
+ GtkWindowPrivate *priv;
+ const GdkEvent *event;
+ gdouble x, y;
+
+ if (!gtk_gesture_is_active (GTK_GESTURE (gesture)))
+ return;
+
+ /* The gesture is active, but stopped, so a too long
+ * press happened, or one drifting out of the threshold
+ */
+ priv = gtk_window_get_instance_private (window);
+ sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+ event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+ gtk_gesture_get_point (GTK_GESTURE (gesture), sequence, &x, &y);
+
+ if (priv->drag_possible)
+ {
+ gdouble x_root, y_root;
+
+ gdk_event_get_root_coords (event, &x_root, &y_root);
+ gdk_window_begin_move_drag_for_device (gtk_widget_get_window (GTK_WIDGET (window)),
+ gdk_event_get_device ((GdkEvent*) event),
+ GDK_BUTTON_PRIMARY,
+ x_root, y_root,
+ gdk_event_get_time (event));
+ }
+
+ priv->drag_possible = FALSE;
+}
+
+static void
gtk_window_init (GtkWindow *window)
{
GtkStyleContext *context;
@@ -1420,6 +1532,15 @@ gtk_window_init (GtkWindow *window)
gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
priv->scale = gtk_widget_get_scale_factor (widget);
+
+ priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (window));
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->multipress_gesture), FALSE);
+ g_signal_connect (priv->multipress_gesture, "pressed",
+ G_CALLBACK (multipress_gesture_pressed_cb), window);
+ g_signal_connect (priv->multipress_gesture, "stopped",
+ G_CALLBACK (multipress_gesture_stopped_cb), window);
+ gtk_widget_add_gesture (GTK_WIDGET (window), priv->multipress_gesture,
+ GTK_PHASE_CAPTURE);
}
static void
@@ -7696,236 +7817,6 @@ get_active_region_type (GtkWindow *window, GdkEventAny *event, gint x, gint y)
return GTK_WINDOW_REGION_CONTENT;
}
-static inline gboolean
-in_double_click_range (GtkWidget *widget,
- GdkEventButton *event)
-{
- GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
- gint double_click_time;
- gint double_click_distance;
-
- g_object_get (gtk_widget_get_settings (widget),
- "gtk-double-click-time", &double_click_time,
- "gtk-double-click-distance", &double_click_distance,
- NULL);
-
- if (event->time < priv->button_press_time + double_click_time &&
- ABS (event->x_root - priv->button_press_x) <= double_click_distance &&
- ABS (event->y_root - priv->button_press_y) <= double_click_distance)
- return TRUE;
-
- return FALSE;
-}
-
-static gint
-gtk_window_motion_notify_event (GtkWidget *widget,
- GdkEventMotion *event)
-{
- GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
- GtkWidget *src;
- gboolean window_drag;
- gint x, y;
- GtkWindowRegion region;
-
- if (!priv->drag_possible)
- return FALSE;
-
- gdk_window_get_user_data (event->window, (gpointer *)&src);
- if (src && src != widget)
- {
- gtk_widget_style_get (GTK_WIDGET (src),
- "window-dragging", &window_drag,
- NULL);
- gtk_widget_translate_coordinates (src, widget, event->x, event->y, &x, &y);
- }
- else
- {
- x = event->x;
- y = event->y;
- }
-
- region = get_active_region_type (GTK_WINDOW (widget), (GdkEventAny*)event, x, y);
- if (region == GTK_WINDOW_REGION_CONTENT)
- {
- if (!window_drag)
- {
- priv->drag_possible = FALSE;
- return FALSE;
- }
- }
-
- if (!in_double_click_range (widget, (GdkEventButton *)event))
- {
- gdk_window_begin_move_drag_for_device (gtk_widget_get_window (widget),
- gdk_event_get_device ((GdkEvent *)event),
- GDK_BUTTON_PRIMARY,
- event->x_root,
- event->y_root,
- event->time);
- priv->drag_possible = FALSE;
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gint
-gtk_window_button_release_event (GtkWidget *widget,
- GdkEventButton *event)
-{
- GtkWindow *window = GTK_WINDOW (widget);
- GtkWindowPrivate *priv = window->priv;
-
- priv->drag_possible = FALSE;
-
- return FALSE;
-}
-
-static gint
-gtk_window_button_press_event (GtkWidget *widget,
- GdkEventButton *event)
-{
- GtkWindow *window = GTK_WINDOW (widget);
- GtkWindowPrivate *priv = window->priv;
- GdkWindowEdge edge;
- GdkWindow *gdk_window;
- gint x, y;
- GtkWidget *src;
- GtkWindowRegion region;
- gboolean window_drag = FALSE;
-
- gdk_window = gtk_widget_get_window (widget);
-
- /* We do our own double-click detection, so we ignore
- * GDK_2BUTTON_PRESS and GDK_3BUTTON_PRESS events
- */
- if (event->type != GDK_BUTTON_PRESS)
- return FALSE;
-
- if (priv->fullscreen)
- return FALSE;
-
- if (event->window == priv->grip_window)
- {
- if (get_drag_edge (widget, &edge))
- gdk_window_begin_resize_drag_for_device (gdk_window,
- edge,
- gdk_event_get_device ((GdkEvent *) event),
- event->button,
- event->x_root,
- event->y_root,
- event->time);
-
- return TRUE;
- }
-
- gdk_window_get_user_data (event->window, (gpointer *)&src);
- if (src && src != widget)
- {
- gtk_widget_style_get (GTK_WIDGET (src),
- "window-dragging", &window_drag,
- NULL);
- gtk_widget_translate_coordinates (src, widget, event->x, event->y, &x, &y);
- }
- else
- {
- x = event->x;
- y = event->y;
- }
-
- region = get_active_region_type (window, (GdkEventAny*)event, x, y);
-
- if (event->button == GDK_BUTTON_PRIMARY)
- {
- if (in_double_click_range (widget, event))
- {
- switch (region)
- {
- case GTK_WINDOW_REGION_CONTENT:
- if (!window_drag) /* do nothing */
- break;
- /* fall thru */
- case GTK_WINDOW_REGION_TITLE:
- _gtk_window_toggle_maximized (window);
- return TRUE;
- default:
- break;
- }
- }
- else
- {
- switch (region)
- {
- case GTK_WINDOW_REGION_CONTENT:
- if (!window_drag)
- break;
- /* fall thru */
-
- case GTK_WINDOW_REGION_TITLE:
- case GTK_WINDOW_REGION_EDGE:
- priv->drag_possible = TRUE;
- priv->button_press_x = event->x_root;
- priv->button_press_y = event->y_root;
- priv->button_press_time = event->time;
- return TRUE;
-
- default:
- if (!priv->maximized)
- {
- gdk_window_begin_resize_drag_for_device (gdk_window,
- (GdkWindowEdge)region,
- gdk_event_get_device ((GdkEvent *) event),
- event->button,
- event->x_root,
- event->y_root,
- event->time);
- return TRUE;
- }
- break;
- }
- }
- }
- else if (event->button == GDK_BUTTON_SECONDARY)
- {
- if (region == GTK_WINDOW_REGION_TITLE)
- {
- gtk_window_do_popup (window, event);
- return TRUE;
- }
- }
- else if (event->button == GDK_BUTTON_MIDDLE)
- {
- if (region == GTK_WINDOW_REGION_TITLE)
- {
- gdk_window_lower (gdk_window);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-gboolean
-_gtk_window_check_handle_wm_event (GdkEvent *event)
-{
- GtkWidget *widget;
-
- widget = gtk_get_event_widget (event);
-
- if (!GTK_IS_WINDOW (widget))
- return FALSE;
-
- if (event->type == GDK_BUTTON_PRESS ||
- event->type == GDK_2BUTTON_PRESS)
- return gtk_window_button_press_event (widget, &event->button);
- else if (event->type == GDK_BUTTON_RELEASE)
- return gtk_window_button_release_event (widget, &event->button);
- else if (event->type == GDK_MOTION_NOTIFY)
- return gtk_window_motion_notify_event (widget, &event->motion);
- else
- return FALSE;
-}
-
static void
gtk_window_real_activate_default (GtkWindow *window)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]