Merge branch 'gestures'

This commit is contained in:
Carlos Garnacho 2014-05-23 19:58:46 +02:00
commit bd35df05a5
79 changed files with 9102 additions and 2498 deletions

View File

@ -24,6 +24,7 @@ demos = \
entry_completion.c \
event_axes.c \
expander.c \
gestures.c \
headerbar.c \
hypertext.c \
iconview.c \

View File

@ -42,7 +42,7 @@ response_cb (GtkDialog *dialog,
gtk_widget_override_background_color (da, 0, &color);
}
gtk_widget_hide (GTK_WIDGET (dialog));
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void

View File

@ -94,6 +94,7 @@
<file>event_axes.c</file>
<file>expander.c</file>
<file>flowbox.c</file>
<file>gestures.c</file>
<file>headerbar.c</file>
<file>hypertext.c</file>
<file>iconview.c</file>

195
demos/gtk-demo/gestures.c Normal file
View File

@ -0,0 +1,195 @@
/* Gestures
*
* Perform gestures on touchscreens and other input devices. This
* demo reacts to long presses and swipes from all devices, plus
* multi-touch rotate and zoom gestures.
*/
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
static GtkGesture *rotate = NULL;
static GtkGesture *zoom = NULL;
static gdouble swipe_x = 0;
static gdouble swipe_y = 0;
static gboolean long_pressed = FALSE;
static void
swipe_gesture_swept (GtkGestureSwipe *gesture,
gdouble velocity_x,
gdouble velocity_y,
GtkWidget *widget)
{
swipe_x = velocity_x / 10;
swipe_y = velocity_y / 10;
gtk_widget_queue_draw (widget);
}
static void
long_press_gesture_pressed (GtkGestureLongPress *gesture,
gdouble x,
gdouble y,
GtkWidget *widget)
{
long_pressed = TRUE;
gtk_widget_queue_draw (widget);
}
static void
long_press_gesture_end (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkWidget *widget)
{
long_pressed = FALSE;
gtk_widget_queue_draw (widget);
}
static void
rotation_angle_changed (GtkGestureRotate *gesture,
gdouble angle,
gdouble delta,
GtkWidget *widget)
{
gtk_widget_queue_draw (widget);
}
static void
zoom_scale_changed (GtkGestureZoom *gesture,
gdouble scale,
GtkWidget *widget)
{
gtk_widget_queue_draw (widget);
}
static gboolean
drawing_area_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
if (swipe_x != 0 || swipe_y != 0)
{
cairo_save (cr);
cairo_set_line_width (cr, 6);
cairo_move_to (cr, allocation.width / 2,
allocation.height / 2);
cairo_rel_line_to (cr, swipe_x, swipe_y);
cairo_set_source_rgba (cr, 1, 0, 0, 0.5);
cairo_stroke (cr);
cairo_restore (cr);
}
if (gtk_gesture_is_recognized (rotate) || gtk_gesture_is_recognized (zoom))
{
cairo_pattern_t *pat;
cairo_matrix_t matrix;
gdouble angle, scale;
cairo_matrix_init_translate (&matrix,
allocation.width / 2,
allocation.height / 2);
cairo_save (cr);
if (gtk_gesture_rotate_get_angle_delta (GTK_GESTURE_ROTATE (rotate), &angle))
cairo_matrix_rotate (&matrix, angle);
if (gtk_gesture_zoom_get_scale_delta (GTK_GESTURE_ZOOM (zoom), &scale))
cairo_matrix_scale (&matrix, scale, scale);
cairo_set_matrix (cr, &matrix);
cairo_rectangle (cr, -100, -100, 200, 200);
pat = cairo_pattern_create_linear (-100, 0, 200, 0);
cairo_pattern_add_color_stop_rgb (pat, 0, 0, 0, 1);
cairo_pattern_add_color_stop_rgb (pat, 1, 1, 0, 0);
cairo_set_source (cr, pat);
cairo_fill (cr);
cairo_restore (cr);
cairo_pattern_destroy (pat);
}
if (long_pressed)
{
cairo_save (cr);
cairo_arc (cr, allocation.width / 2,
allocation.height / 2,
50, 0, 2 * G_PI);
cairo_set_source_rgba (cr, 0, 1, 0, 0.5);
cairo_stroke (cr);
cairo_restore (cr);
}
return TRUE;
}
GtkWidget *
do_gestures (GtkWidget *do_widget)
{
GtkWidget *drawing_area;
GtkGesture *gesture;
if (!window)
{
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
gtk_window_set_title (GTK_WINDOW (window), "Gestures demo");
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
drawing_area = gtk_drawing_area_new ();
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_add_events (drawing_area,
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK | GDK_TOUCH_MASK);
g_signal_connect (drawing_area, "draw",
G_CALLBACK (drawing_area_draw), NULL);
/* Swipe */
gesture = gtk_gesture_swipe_new (drawing_area);
g_signal_connect (gesture, "swipe",
G_CALLBACK (swipe_gesture_swept), drawing_area);
gtk_gesture_attach (gesture, GTK_PHASE_BUBBLE);
g_object_unref (gesture);
/* Long press */
gesture = gtk_gesture_long_press_new (drawing_area);
g_signal_connect (gesture, "pressed",
G_CALLBACK (long_press_gesture_pressed), drawing_area);
g_signal_connect (gesture, "end",
G_CALLBACK (long_press_gesture_end), drawing_area);
gtk_gesture_attach (gesture, GTK_PHASE_BUBBLE);
g_object_unref (gesture);
/* Rotate */
rotate = gesture = gtk_gesture_rotate_new (drawing_area);
g_signal_connect (gesture, "angle-changed",
G_CALLBACK (rotation_angle_changed), drawing_area);
gtk_gesture_attach (gesture, GTK_PHASE_BUBBLE);
g_object_unref (gesture);
/* Zoom */
zoom = gesture = gtk_gesture_zoom_new (drawing_area);
g_signal_connect (gesture, "scale-changed",
G_CALLBACK (zoom_scale_changed), drawing_area);
gtk_gesture_attach (gesture, GTK_PHASE_BUBBLE);
g_object_unref (gesture);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show_all (window);
else
{
gtk_widget_destroy (window);
window = NULL;
}
return window;
}

View File

@ -287,6 +287,20 @@
<xi:include href="xml/gtkappchooserwidget.xml" />
</chapter>
<chapter id="Gestures">
<title>Gestures</title>
<xi:include href="xml/gtkeventcontroller.xml" />
<xi:include href="xml/gtkgesture.xml" />
<xi:include href="xml/gtkgesturesingle.xml" />
<xi:include href="xml/gtkgesturedrag.xml" />
<xi:include href="xml/gtkgesturelongpress.xml" />
<xi:include href="xml/gtkgesturemultipress.xml" />
<xi:include href="xml/gtkgesturepan.xml" />
<xi:include href="xml/gtkgestureswipe.xml" />
<xi:include href="xml/gtkgesturerotate.xml" />
<xi:include href="xml/gtkgesturezoom.xml" />
</chapter>
<chapter id="DeprecatedObjects">
<title>Deprecated</title>
<xi:include href="xml/gtksymboliccolor.xml" />

View File

@ -7891,3 +7891,231 @@ gtk_popover_get_position
gtk_popover_set_modal
gtk_popover_get_modal
</SECTION>
<SECTION>
<FILE>gtkeventcontroller</FILE>
<TITLE>GtkEventController</TITLE>
GtkEventController
gtk_event_controller_handle_event
gtk_event_controller_get_event_mask
gtk_event_controller_set_event_mask
gtk_event_controller_get_widget
gtk_event_controller_reset
<SUBSECTION Standard>
GTK_TYPE_EVENT_CONTROLLER
GTK_EVENT_CONTROLLER
GTK_EVENT_CONTROLLER_CLASS
GTK_IS_EVENT_CONTROLLER
GTK_EVENT_CONTROLLER_GET_CLASS
<SUBSECTION Private>
GtkEventControllerPriv
gtk_event_controller_get_type
</SECTION>
<SECTION>
<FILE>gtkgesture</FILE>
<TITLE>GtkGesture</TITLE>
GtkGesture
gtk_gesture_get_device
gtk_gesture_get_window
gtk_gesture_set_window
gtk_gesture_is_active
gtk_gesture_is_recognized
GtkEventSequenceState
gtk_gesture_get_sequence_state
gtk_gesture_set_sequence_state
gtk_gesture_set_state
gtk_gesture_get_sequences
gtk_gesture_handles_sequence
GtkPropagationPhase
gtk_gesture_attach
gtk_gesture_detach
<SUBSECTION>
gtk_gesture_get_last_updated_sequence
gtk_gesture_get_last_event
gtk_gesture_get_point
gtk_gesture_get_bounding_box
gtk_gesture_get_bounding_box_center
<SUBSECTION>
gtk_gesture_group
gtk_gesture_ungroup
gtk_gesture_get_group
gtk_gesture_is_grouped_with
<SUBSECTION Standard>
GTK_TYPE_GESTURE
GTK_GESTURE
GTK_GESTURE_CLASS
GTK_IS_GESTURE
GTK_IS_GESTURE_CLASS
GTK_GESTURE_GET_CLASS
<SUBSECTION Private>
gtk_gesture_get_type
</SECTION>
<SECTION>
<FILE>gtkgesturesingle</FILE>
<TITLE>GtkGestureSingle</TITLE>
GtkGestureSingle
gtk_gesture_single_get_exclusive
gtk_gesture_single_set_exclusive
gtk_gesture_single_get_touch_only
gtk_gesture_single_set_touch_only
gtk_gesture_single_get_button
gtk_gesture_single_set_button
gtk_gesture_single_get_current_button
gtk_gesture_single_get_current_sequence
<SUBSECTION Standard>
GTK_TYPE_GESTURE_SINGLE
GTK_GESTURE_SINGLE
GTK_GESTURE_SINGLE_CLASS
GTK_IS_GESTURE_SINGLE
GTK_IS_GESTURE_SINGLE_CLASS
GTK_GESTURE_SINGLE_GET_CLASS
<SUBSECTION Private>
gtk_gesture_single_get_type
</SECTION>
<SECTION>
<FILE>gtkgesturedrag</FILE>
<TITLE>GtkGestureDrag</TITLE>
GtkGestureDrag
gtk_gesture_drag_new
gtk_gesture_drag_get_start_point
gtk_gesture_drag_get_offset
<SUBSECTION Standard>
GTK_TYPE_GESTURE_DRAG
GTK_GESTURE_DRAG
GTK_GESTURE_DRAG_CLASS
GTK_IS_GESTURE_DRAG
GTK_IS_GESTURE_DRAG_CLASS
GTK_GESTURE_DRAG_GET_CLASS
<SUBSECTION Private>
gtk_gesture_drag_get_type
</SECTION>
<SECTION>
<FILE>gtkgesturelongpress</FILE>
<TITLE>GtkGestureLongPress</TITLE>
GtkGestureLongPress
gtk_gesture_long_press_new
<SUBSECTION Standard>
GTK_TYPE_GESTURE_LONG_PRESS
GTK_GESTURE_LONG_PRESS
GTK_GESTURE_LONG_PRESS_CLASS
GTK_IS_GESTURE_LONG_PRESS
GTK_IS_GESTURE_LONG_PRESS_CLASS
GTK_GESTURE_LONG_PRESS_GET_CLASS
<SUBSECTION Private>
gtk_gesture_long_press_get_type
</SECTION>
<SECTION>
<FILE>gtkgesturemultipress</FILE>
<TITLE>GtkGestureMultiPress</TITLE>
GtkGestureMultiPress
gtk_gesture_multi_press_new
gtk_gesture_multi_press_set_area
gtk_gesture_multi_press_get_area
<SUBSECTION Standard>
GTK_TYPE_GESTURE_MULTI_PRESS
GTK_GESTURE_MULTI_PRESS
GTK_GESTURE_MULTI_PRESS_CLASS
GTK_IS_GESTURE_MULTI_PRESS
GTK_IS_GESTURE_MULTI_PRESS_CLASS
GTK_GESTURE_MULTI_PRESS_GET_CLASS
<SUBSECTION Private>
gtk_gesture_multi_press_get_type
</SECTION>
<SECTION>
<FILE>gtkgesturepan</FILE>
<TITLE>GtkGesturePan</TITLE>
GtkGesturePan
GtkPanDirection
GtkPanOrientation
gtk_gesture_pan_new
gtk_gesture_pan_get_orientation
gtk_gesture_pan_set_orientation
<SUBSECTION Standard>
GTK_TYPE_GESTURE_PAN
GTK_GESTURE_PAN
GTK_GESTURE_PAN_CLASS
GTK_IS_GESTURE_PAN
GTK_IS_GESTURE_PAN_CLASS
GTK_GESTURE_PAN_GET_CLASS
<SUBSECTION Private>
gtk_gesture_pan_get_type
</SECTION>
<SECTION>
<FILE>gtkgestureswipe</FILE>
<TITLE>GtkGestureSwipe</TITLE>
GtkGestureSwipe
gtk_gesture_swipe_new
gtk_gesture_swipe_get_velocity
<SUBSECTION Standard>
GTK_TYPE_GESTURE_SWIPE
GTK_GESTURE_SWIPE
GTK_GESTURE_SWIPE_CLASS
GTK_IS_GESTURE_SWIPE
GTK_IS_GESTURE_SWIPE_CLASS
GTK_GESTURE_SWIPE_GET_CLASS
<SUBSECTION Private>
gtk_gesture_swipe_get_type
</SECTION>
<SECTION>
<FILE>gtkgesturerotate</FILE>
<TITLE>GtkGestureRotate</TITLE>
GtkGestureRotate
gtk_gesture_rotate_new
gtk_gesture_rotate_get_angle_delta
<SUBSECTION Standard>
GTK_TYPE_GESTURE_ROTATE
GTK_GESTURE_ROTATE
GTK_GESTURE_ROTATE_CLASS
GTK_IS_GESTURE_ROTATE
GTK_IS_GESTURE_ROTATE_CLASS
GTK_GESTURE_ROTATE_GET_CLASS
<SUBSECTION Private>
gtk_gesture_rotate_get_type
</SECTION>
<SECTION>
<FILE>gtkgesturezoom</FILE>
<TITLE>GtkGestureZoom</TITLE>
GtkGestureZoom
gtk_gesture_zoom_new
gtk_gesture_zoom_get_scale_delta
<SUBSECTION Standard>
GTK_TYPE_GESTURE_ZOOM
GTK_GESTURE_ZOOM
GTK_GESTURE_ZOOM_CLASS
GTK_IS_GESTURE_ZOOM
GTK_IS_GESTURE_ZOOM_CLASS
GTK_GESTURE_ZOOM_GET_CLASS
<SUBSECTION Private>
gtk_gesture_zoom_get_type
</SECTION>

View File

@ -63,6 +63,7 @@ gtk_entry_buffer_get_type
gtk_entry_completion_get_type
gtk_entry_get_type
gtk_event_box_get_type
gtk_event_controller_get_type
gtk_expander_get_type
gtk_file_chooser_button_get_type
gtk_file_chooser_dialog_get_type
@ -79,6 +80,15 @@ gtk_font_chooser_widget_get_type
gtk_font_selection_dialog_get_type
gtk_font_selection_get_type
gtk_frame_get_type
gtk_gesture_get_type
gtk_gesture_drag_get_type
gtk_gesture_long_press_get_type
gtk_gesture_multi_press_get_type
gtk_gesture_pan_get_type
gtk_gesture_rotate_get_type
gtk_gesture_single_get_type
gtk_gesture_swipe_get_type
gtk_gesture_zoom_get_type
gtk_grid_get_type
gtk_handle_box_get_type
gtk_hbox_get_type

View File

@ -1952,7 +1952,7 @@ gdk_event_get_screen (const GdkEvent *event)
* %GDK_TOUCH_END or %GDK_TOUCH_CANCEL, returns the #GdkEventSequence
* to which the event belongs. Otherwise, return %NULL.
*
* Returns: the event sequence that the event belongs to
* Returns: (transfer none): the event sequence that the event belongs to
*
* Since: 3.4
*/
@ -2209,6 +2209,22 @@ G_DEFINE_BOXED_TYPE (GdkEvent, gdk_event,
gdk_event_copy,
gdk_event_free)
static GdkEventSequence *
gdk_event_sequence_copy (GdkEventSequence *sequence)
{
return sequence;
}
static void
gdk_event_sequence_free (GdkEventSequence *sequence)
{
/* Nothing to free here */
}
G_DEFINE_BOXED_TYPE (GdkEventSequence, gdk_event_sequence,
gdk_event_sequence_copy,
gdk_event_sequence_free)
/**
* gdk_setting_get:
* @name: the name of the setting.

View File

@ -50,6 +50,7 @@ G_BEGIN_DECLS
#define GDK_TYPE_EVENT (gdk_event_get_type ())
#define GDK_TYPE_EVENT_SEQUENCE (gdk_event_sequence_get_type ())
/**
* GDK_PRIORITY_EVENTS:
@ -1193,6 +1194,9 @@ union _GdkEvent
GDK_AVAILABLE_IN_ALL
GType gdk_event_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GType gdk_event_sequence_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
gboolean gdk_events_pending (void);
GDK_AVAILABLE_IN_ALL

View File

@ -6891,6 +6891,7 @@ update_cursor (GdkDisplay *display,
/* Find the first window with the cursor actually set, as
the cursor is inherited from the parent */
while (cursor_window->cursor == NULL &&
!g_hash_table_contains (cursor_window->device_cursor, device) &&
(parent = get_event_parent (cursor_window)) != NULL &&
parent->window_type != GDK_WINDOW_ROOT)
cursor_window = parent;

View File

@ -266,6 +266,7 @@ gtk_public_h_sources = \
gtkentrycompletion.h \
gtkenums.h \
gtkeventbox.h \
gtkeventcontroller.h \
gtkexpander.h \
gtkfilechooser.h \
gtkfilechooserbutton.h \
@ -279,6 +280,15 @@ gtk_public_h_sources = \
gtkfontchooserdialog.h \
gtkfontchooserwidget.h \
gtkframe.h \
gtkgesture.h \
gtkgesturedrag.h \
gtkgesturelongpress.h \
gtkgesturemultipress.h \
gtkgesturepan.h \
gtkgesturerotate.h \
gtkgesturesingle.h \
gtkgestureswipe.h \
gtkgesturezoom.h \
gtkgrid.h \
gtkheaderbar.h \
gtkicontheme.h \
@ -493,6 +503,7 @@ gtk_private_h_sources = \
gtkcustompaperunixdialog.h \
gtkdialogprivate.h \
gtkentryprivate.h \
gtkeventcontrollerprivate.h \
gtkfilechooserembed.h \
gtkfilechooserentry.h \
gtkfilechooserprivate.h \
@ -501,6 +512,14 @@ gtk_private_h_sources = \
gtkfilesystemmodel.h \
gtkfontchooserprivate.h \
gtkfontchooserutils.h \
gtkgestureprivate.h \
gtkgesturedragprivate.h \
gtkgesturelongpressprivate.h \
gtkgesturemultipressprivate.h \
gtkgesturepanprivate.h \
gtkgesturerotateprivate.h \
gtkgestureswipeprivate.h \
gtkgesturezoomprivate.h \
gtkheaderbarprivate.h \
gtkhslaprivate.h \
gtkiconcache.h \
@ -530,7 +549,6 @@ gtk_private_h_sources = \
gtkorientableprivate.h \
gtkpango.h \
gtkpathbar.h \
gtkpressandholdprivate.h \
gtkprintoperation-private.h \
gtkprintutils.h \
gtkprivate.h \
@ -750,6 +768,7 @@ gtk_base_c_sources = \
gtkentrybuffer.c \
gtkentrycompletion.c \
gtkeventbox.c \
gtkeventcontroller.c \
gtkexpander.c \
gtkfilechooser.c \
gtkfilechooserbutton.c \
@ -770,6 +789,15 @@ gtk_base_c_sources = \
gtkfontchooserwidget.c \
gtkframe.c \
gtkgladecatalog.c \
gtkgesture.c \
gtkgesturedrag.c \
gtkgesturelongpress.c \
gtkgesturemultipress.c \
gtkgesturepan.c \
gtkgesturerotate.c \
gtkgesturesingle.c \
gtkgestureswipe.c \
gtkgesturezoom.c \
gtkgrid.c \
gtkheaderbar.c \
gtkhsla.c \
@ -822,7 +850,6 @@ gtk_base_c_sources = \
gtkpapersize.c \
gtkpathbar.c \
gtkplacessidebar.c \
gtkpressandhold.c \
gtkprintcontext.c \
gtkprintoperation.c \
gtkprintoperationpreview.c \

View File

@ -92,6 +92,7 @@
#include <gtk/gtkentrycompletion.h>
#include <gtk/gtkenums.h>
#include <gtk/gtkeventbox.h>
#include <gtk/gtkeventcontroller.h>
#include <gtk/gtkexpander.h>
#include <gtk/gtkfixed.h>
#include <gtk/gtkfilechooser.h>
@ -105,6 +106,15 @@
#include <gtk/gtkfontchooserdialog.h>
#include <gtk/gtkfontchooserwidget.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkgesture.h>
#include <gtk/gtkgesturedrag.h>
#include <gtk/gtkgesturelongpress.h>
#include <gtk/gtkgesturemultipress.h>
#include <gtk/gtkgesturepan.h>
#include <gtk/gtkgesturerotate.h>
#include <gtk/gtkgesturesingle.h>
#include <gtk/gtkgestureswipe.h>
#include <gtk/gtkgesturezoom.h>
#include <gtk/gtkgrid.h>
#include <gtk/gtkheaderbar.h>
#include <gtk/gtkicontheme.h>

View File

@ -119,12 +119,6 @@ static void gtk_button_style_updated (GtkWidget * widget);
static void gtk_button_size_allocate (GtkWidget * widget,
GtkAllocation * allocation);
static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
static gint gtk_button_button_press (GtkWidget * widget,
GdkEventButton * event);
static gint gtk_button_button_release (GtkWidget * widget,
GdkEventButton * event);
static gboolean gtk_button_touch (GtkWidget *widget,
GdkEventTouch *event);
static gint gtk_button_grab_broken (GtkWidget * widget,
GdkEventGrabBroken * event);
static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
@ -225,9 +219,6 @@ gtk_button_class_init (GtkButtonClass *klass)
widget_class->style_updated = gtk_button_style_updated;
widget_class->size_allocate = gtk_button_size_allocate;
widget_class->draw = gtk_button_draw;
widget_class->button_press_event = gtk_button_button_press;
widget_class->button_release_event = gtk_button_button_release;
widget_class->touch_event = gtk_button_touch;
widget_class->grab_broken_event = gtk_button_grab_broken;
widget_class->key_release_event = gtk_button_key_release;
widget_class->enter_notify_event = gtk_button_enter_notify;
@ -593,6 +584,34 @@ gtk_button_class_init (GtkButtonClass *klass)
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_BUTTON_ACCESSIBLE);
}
static void
multipress_pressed_cb (GtkGestureMultiPress *gesture,
guint n_press,
gdouble x,
gdouble y,
GtkWidget *widget)
{
GtkButton *button = GTK_BUTTON (widget);
GtkButtonPrivate *priv = button->priv;
if (priv->focus_on_click && !gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
g_signal_emit (button, button_signals[PRESSED], 0);
}
static void
multipress_released_cb (GtkGestureMultiPress *gesture,
guint n_press,
gdouble x,
gdouble y,
GtkWidget *widget)
{
GtkButton *button = GTK_BUTTON (widget);
g_signal_emit (button, button_signals[RELEASED], 0);
}
static void
gtk_button_init (GtkButton *button)
{
@ -627,6 +646,14 @@ gtk_button_init (GtkButton *button)
context = gtk_widget_get_style_context (GTK_WIDGET (button));
gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
priv->gesture = gtk_gesture_multi_press_new (GTK_WIDGET (button));
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->gesture), FALSE);
gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (priv->gesture), TRUE);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->gesture), GDK_BUTTON_PRIMARY);
g_signal_connect (priv->gesture, "pressed", G_CALLBACK (multipress_pressed_cb), button);
g_signal_connect (priv->gesture, "released", G_CALLBACK (multipress_released_cb), button);
gtk_gesture_attach (priv->gesture, GTK_PHASE_TARGET);
}
static void
@ -641,6 +668,13 @@ gtk_button_destroy (GtkWidget *widget)
priv->label_text = NULL;
}
if (priv->gesture)
{
gtk_gesture_detach (priv->gesture);
g_object_unref (priv->gesture);
priv->gesture = NULL;
}
GTK_WIDGET_CLASS (gtk_button_parent_class)->destroy (widget);
}
@ -1849,75 +1883,6 @@ gtk_button_draw (GtkWidget *widget,
return FALSE;
}
static gboolean
gtk_button_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkButton *button;
GtkButtonPrivate *priv;
if (event->type == GDK_BUTTON_PRESS)
{
button = GTK_BUTTON (widget);
priv = button->priv;
if (priv->focus_on_click && !gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
if (event->button == GDK_BUTTON_PRIMARY)
{
g_signal_emit (button, button_signals[PRESSED], 0);
return GDK_EVENT_STOP;
}
}
else if (event->type == GDK_2BUTTON_PRESS)
{
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
static gboolean
gtk_button_button_release (GtkWidget *widget,
GdkEventButton *event)
{
GtkButton *button;
if (event->button == GDK_BUTTON_PRIMARY)
{
button = GTK_BUTTON (widget);
g_signal_emit (button, button_signals[RELEASED], 0);
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
static gboolean
gtk_button_touch (GtkWidget *widget,
GdkEventTouch *event)
{
GtkButton *button = GTK_BUTTON (widget);
GtkButtonPrivate *priv = button->priv;
if (event->type == GDK_TOUCH_BEGIN)
{
if (priv->focus_on_click && !gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
g_signal_emit (button, button_signals[PRESSED], 0);
return GDK_EVENT_STOP;
}
else if (event->type == GDK_TOUCH_END)
{
g_signal_emit (button, button_signals[RELEASED], 0);
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
static void
gtk_button_do_release (GtkButton *button,
gboolean emit_clicked)

View File

@ -20,6 +20,7 @@
#define __GTK_BUTTON_PRIVATE_H__
#include "gtkactionhelper.h"
#include "gtkgesturesingle.h"
#include "deprecated/gtkaction.h"
G_BEGIN_DECLS
@ -36,6 +37,8 @@ struct _GtkButtonPrivate
gchar *label_text;
GtkGesture *gesture;
gfloat xalign;
gfloat yalign;

View File

@ -511,7 +511,6 @@ grab_key_callback (GtkWidget *widget,
edited = TRUE;
out:
gtk_device_grab_remove (priv->grab_widget, priv->grab_pointer);
gdk_device_ungrab (priv->grab_keyboard, event->time);
gdk_device_ungrab (priv->grab_pointer, event->time);
@ -541,7 +540,6 @@ ungrab_stuff (GtkWidget *widget,
{
GtkCellRendererAccelPrivate *priv = accel->priv;
gtk_device_grab_remove (priv->grab_widget, priv->grab_pointer);
gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
@ -749,8 +747,6 @@ gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
gtk_widget_show_all (priv->edit_widget);
gtk_device_grab_add (priv->grab_widget, pointer, TRUE);
g_signal_connect (priv->edit_widget, "unrealize",
G_CALLBACK (ungrab_stuff), accel);

View File

@ -19,10 +19,11 @@
#include "gtkcolorplaneprivate.h"
#include "gtkgesturedrag.h"
#include "gtkgesturelongpress.h"
#include "gtkaccessible.h"
#include "gtkadjustment.h"
#include "gtkcolorutils.h"
#include "gtkpressandholdprivate.h"
#include "gtkintl.h"
struct _GtkColorPlanePrivate
@ -32,9 +33,9 @@ struct _GtkColorPlanePrivate
GtkAdjustment *v_adj;
cairo_surface_t *surface;
gboolean in_drag;
GtkPressAndHold *press_and_hold;
GtkGesture *drag_gesture;
GtkGesture *long_press_gesture;
};
enum {
@ -180,32 +181,27 @@ plane_configure (GtkWidget *widget,
}
static void
set_cross_grab (GtkWidget *widget,
GdkDevice *device,
guint32 time)
set_cross_cursor (GtkWidget *widget,
gboolean enabled)
{
GdkCursor *cursor;
GdkCursor *cursor = NULL;
GdkWindow *window;
GdkDevice *device;
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (widget)),
GDK_CROSSHAIR);
gdk_device_grab (device,
gtk_widget_get_window (widget),
GDK_OWNERSHIP_NONE,
FALSE,
GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
| GDK_BUTTON_RELEASE_MASK,
cursor,
time);
g_object_unref (cursor);
}
window = gtk_widget_get_window (widget);
device = gtk_gesture_get_device (GTK_COLOR_PLANE (widget)->priv->drag_gesture);
static gboolean
plane_grab_broken (GtkWidget *widget,
GdkEventGrabBroken *event)
{
GTK_COLOR_PLANE (widget)->priv->in_drag = FALSE;
return TRUE;
if (!window || !device)
return;
if (enabled)
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (widget)),
GDK_CROSSHAIR);
gdk_window_set_device_cursor (window, device, cursor);
if (cursor)
g_object_unref (cursor);
}
static void
@ -237,106 +233,17 @@ update_color (GtkColorPlane *plane,
gtk_widget_queue_draw (widget);
}
static gboolean
plane_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
if (event->button == GDK_BUTTON_SECONDARY)
{
gboolean handled;
g_signal_emit_by_name (widget, "popup-menu", &handled);
return TRUE;
}
if (plane->priv->in_drag || event->button != GDK_BUTTON_PRIMARY)
return FALSE;
plane->priv->in_drag = TRUE;
set_cross_grab (widget, gdk_event_get_device ((GdkEvent*)event), event->time);
update_color (plane, event->x, event->y);
gtk_widget_grab_focus (widget);
return TRUE;
}
static gboolean
plane_button_release (GtkWidget *widget,
GdkEventButton *event)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
if (!plane->priv->in_drag || event->button != GDK_BUTTON_PRIMARY)
return FALSE;
plane->priv->in_drag = FALSE;
update_color (plane, event->x, event->y);
gdk_device_ungrab (gdk_event_get_device ((GdkEvent *) event), event->time);
return TRUE;
}
static gboolean
plane_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
if (!plane->priv->in_drag)
return FALSE;
gdk_event_request_motions (event);
update_color (plane, event->x, event->y);
return TRUE;
}
static void
hold_action (GtkPressAndHold *pah,
gint x,
gint y,
GtkColorPlane *plane)
hold_action (GtkGestureLongPress *gesture,
gdouble x,
gdouble y,
GtkColorPlane *plane)
{
gboolean handled;
g_signal_emit_by_name (plane, "popup-menu", &handled);
}
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);
}
gtk_press_and_hold_process_event (plane->priv->press_and_hold, (GdkEvent *)event);
update_color (plane, event->x, event->y);
return TRUE;
}
static void
sv_move (GtkColorPlane *plane,
gdouble ds,
@ -423,6 +330,57 @@ plane_key_press (GtkWidget *widget,
return TRUE;
}
static void
plane_drag_gesture_begin (GtkGestureDrag *gesture,
gdouble start_x,
gdouble start_y,
GtkColorPlane *plane)
{
guint button;
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
if (button == GDK_BUTTON_SECONDARY)
{
gboolean handled;
g_signal_emit_by_name (plane, "popup-menu", &handled);
}
if (button != GDK_BUTTON_PRIMARY)
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
return;
}
set_cross_cursor (GTK_WIDGET (plane), TRUE);
update_color (plane, start_x, start_y);
gtk_widget_grab_focus (GTK_WIDGET (plane));
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
}
static void
plane_drag_gesture_update (GtkGestureDrag *gesture,
gdouble offset_x,
gdouble offset_y,
GtkColorPlane *plane)
{
gdouble start_x, start_y;
gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (gesture),
&start_x, &start_y);
update_color (plane, start_x + offset_x, start_y + offset_y);
}
static void
plane_drag_gesture_end (GtkGestureDrag *gesture,
gdouble offset_x,
gdouble offset_y,
GtkColorPlane *plane)
{
set_cross_cursor (GTK_WIDGET (plane), FALSE);
}
static void
gtk_color_plane_init (GtkColorPlane *plane)
{
@ -443,6 +401,22 @@ gtk_color_plane_init (GtkColorPlane *plane)
atk_object_set_name (atk_obj, _("Color Plane"));
atk_object_set_role (atk_obj, ATK_ROLE_COLOR_CHOOSER);
}
plane->priv->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (plane));
g_signal_connect (plane->priv->drag_gesture, "drag-begin",
G_CALLBACK (plane_drag_gesture_begin), plane);
g_signal_connect (plane->priv->drag_gesture, "drag-update",
G_CALLBACK (plane_drag_gesture_update), plane);
g_signal_connect (plane->priv->drag_gesture, "drag-end",
G_CALLBACK (plane_drag_gesture_end), plane);
gtk_gesture_attach (plane->priv->drag_gesture, GTK_PHASE_TARGET);
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (plane->priv->drag_gesture),
FALSE);
plane->priv->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (plane));
g_signal_connect (plane->priv->long_press_gesture, "pressed",
G_CALLBACK (hold_action), plane);
gtk_gesture_attach (plane->priv->long_press_gesture, GTK_PHASE_TARGET);
}
static void
@ -457,7 +431,11 @@ 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);
gtk_gesture_detach (plane->priv->drag_gesture);
g_clear_object (&plane->priv->drag_gesture);
gtk_gesture_detach (plane->priv->long_press_gesture);
g_clear_object (&plane->priv->long_press_gesture);
G_OBJECT_CLASS (gtk_color_plane_parent_class)->finalize (object);
}
@ -517,12 +495,7 @@ gtk_color_plane_class_init (GtkColorPlaneClass *class)
widget_class->draw = plane_draw;
widget_class->configure_event = plane_configure;
widget_class->button_press_event = plane_button_press;
widget_class->button_release_event = plane_button_release;
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_object_class_install_property (object_class,
PROP_H_ADJUSTMENT,

View File

@ -20,11 +20,11 @@
#include "gtkcolorscaleprivate.h"
#include "gtkcolorchooserprivate.h"
#include "gtkgesturelongpress.h"
#include "gtkcolorutils.h"
#include "gtkorientable.h"
#include "gtkstylecontext.h"
#include "gtkaccessible.h"
#include "gtkpressandholdprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
@ -37,7 +37,7 @@ struct _GtkColorScalePrivate
GdkRGBA color;
GtkColorScaleType type;
GtkPressAndHold *press_and_hold;
GtkGesture *long_press_gesture;
};
enum
@ -46,6 +46,11 @@ enum
PROP_SCALE_TYPE
};
static void hold_action (GtkGestureLongPress *gesture,
gdouble x,
gdouble y,
GtkColorScale *scale);
G_DEFINE_TYPE_WITH_PRIVATE (GtkColorScale, gtk_color_scale, GTK_TYPE_SCALE)
static void
@ -249,6 +254,11 @@ gtk_color_scale_init (GtkColorScale *scale)
scale->priv = gtk_color_scale_get_instance_private (scale);
gtk_widget_add_events (GTK_WIDGET (scale), GDK_TOUCH_MASK);
scale->priv->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (scale));
g_signal_connect (scale->priv->long_press_gesture, "pressed",
G_CALLBACK (hold_action), scale);
gtk_gesture_attach (scale->priv->long_press_gesture, GTK_PHASE_BUBBLE);
}
static void
@ -259,7 +269,8 @@ scale_finalize (GObject *object)
if (scale->priv->surface)
cairo_surface_destroy (scale->priv->surface);
g_clear_object (&scale->priv->press_and_hold);
gtk_gesture_detach (scale->priv->long_press_gesture);
g_clear_object (&scale->priv->long_press_gesture);
G_OBJECT_CLASS (gtk_color_scale_parent_class)->finalize (object);
}
@ -322,47 +333,16 @@ scale_set_property (GObject *object,
}
static void
hold_action (GtkPressAndHold *pah,
gint x,
gint y,
GtkColorScale *scale)
hold_action (GtkGestureLongPress *gesture,
gdouble x,
gdouble y,
GtkColorScale *scale)
{
gboolean handled;
g_signal_emit_by_name (scale, "popup-menu", &handled);
}
static gboolean
scale_touch (GtkWidget *widget,
GdkEventTouch *event)
{
GtkColorScale *scale = GTK_COLOR_SCALE (widget);
if (!scale->priv->press_and_hold)
{
gint drag_threshold;
g_object_get (gtk_widget_get_settings (widget),
"gtk-dnd-drag-threshold", &drag_threshold,
NULL);
scale->priv->press_and_hold = gtk_press_and_hold_new ();
g_object_set (scale->priv->press_and_hold,
"drag-threshold", drag_threshold,
"hold-time", 1000,
NULL);
g_signal_connect (scale->priv->press_and_hold, "hold",
G_CALLBACK (hold_action), scale);
}
gtk_press_and_hold_process_event (scale->priv->press_and_hold, (GdkEvent *)event);
return GTK_WIDGET_CLASS (gtk_color_scale_parent_class)->touch_event (widget, event);
}
static void
gtk_color_scale_class_init (GtkColorScaleClass *class)
{
@ -374,7 +354,6 @@ gtk_color_scale_class_init (GtkColorScaleClass *class)
object_class->set_property = scale_set_property;
widget_class->draw = scale_draw;
widget_class->touch_event = scale_touch;
g_object_class_install_property (object_class, PROP_SCALE_TYPE,
g_param_spec_int ("scale-type", P_("Scale type"), P_("Scale type"),

View File

@ -28,7 +28,6 @@
#include "gtkmenu.h"
#include "gtkmenuitem.h"
#include "gtkmenushell.h"
#include "gtkpressandholdprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "a11y/gtkcolorswatchaccessibleprivate.h"
@ -46,7 +45,8 @@ struct _GtkColorSwatchPrivate
GdkWindow *event_window;
GtkPressAndHold *press_and_hold;
GtkGesture *long_press_gesture;
GtkGesture *multipress_gesture;
};
enum
@ -65,6 +65,16 @@ enum
static guint signals[LAST_SIGNAL];
static void hold_action (GtkGestureLongPress *gesture,
gdouble x,
gdouble y,
GtkColorSwatch *swatch);
static void tap_action (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y,
GtkColorSwatch *swatch);
G_DEFINE_TYPE_WITH_PRIVATE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET)
static void
@ -76,6 +86,17 @@ gtk_color_swatch_init (GtkColorSwatch *swatch)
gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE);
gtk_widget_set_has_window (GTK_WIDGET (swatch), FALSE);
swatch->priv->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (swatch));
g_signal_connect (swatch->priv->long_press_gesture, "pressed",
G_CALLBACK (hold_action), swatch);
gtk_gesture_attach (swatch->priv->long_press_gesture, GTK_PHASE_TARGET);
swatch->priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (swatch));
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (swatch->priv->multipress_gesture), FALSE);
g_signal_connect (swatch->priv->multipress_gesture, "pressed",
G_CALLBACK (tap_action), swatch);
gtk_gesture_attach (swatch->priv->multipress_gesture, GTK_PHASE_TARGET);
}
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
@ -435,7 +456,8 @@ popup_position_func (GtkMenu *menu,
static void
do_popup (GtkWidget *swatch,
GdkEventButton *event)
gint button,
gint time)
{
GtkWidget *menu;
GtkWidget *item;
@ -454,41 +476,13 @@ do_popup (GtkWidget *swatch,
gtk_widget_show_all (item);
if (event)
if (button != 0)
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
NULL, NULL, event->button, event->time);
NULL, NULL, button, time);
else
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
popup_position_func, swatch,
0, gtk_get_current_event_time ());
}
static gboolean
swatch_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
gtk_widget_grab_focus (widget);
if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
swatch->priv->has_color)
{
do_popup (widget, event);
return TRUE;
}
else if (event->type == GDK_2BUTTON_PRESS &&
event->button == GDK_BUTTON_PRIMARY)
{
g_signal_emit (swatch, signals[ACTIVATE], 0);
return TRUE;
}
else if (event->button == GDK_BUTTON_PRIMARY)
{
return TRUE;
}
return FALSE;
button, time);
}
static gboolean
@ -513,67 +507,39 @@ swatch_primary_action (GtkColorSwatch *swatch)
return FALSE;
}
static gboolean
swatch_button_release (GtkWidget *widget,
GdkEventButton *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
if (event->button == GDK_BUTTON_PRIMARY &&
swatch->priv->contains_pointer)
return swatch_primary_action (swatch);
return FALSE;
}
static void
hold_action (GtkPressAndHold *pah,
gint x,
gint y,
GtkColorSwatch *swatch)
hold_action (GtkGestureLongPress *gesture,
gdouble x,
gdouble y,
GtkColorSwatch *swatch)
{
emit_customize (swatch);
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
}
static void
tap_action (GtkPressAndHold *pah,
gint x,
gint y,
GtkColorSwatch *swatch)
tap_action (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y,
GtkColorSwatch *swatch)
{
swatch_primary_action (swatch);
}
guint button;
static gboolean
swatch_touch (GtkWidget *widget,
GdkEventTouch *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
if (!swatch->priv->press_and_hold)
if (button == GDK_BUTTON_PRIMARY)
{
gint drag_threshold;
g_object_get (gtk_widget_get_settings (widget),
"gtk-dnd-drag-threshold", &drag_threshold,
NULL);
swatch->priv->press_and_hold = gtk_press_and_hold_new ();
g_object_set (swatch->priv->press_and_hold,
"drag-threshold", drag_threshold,
"hold-time", 1000,
NULL);
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);
if (n_press == 1)
swatch_primary_action (swatch);
else if (n_press > 1)
g_signal_emit (swatch, signals[ACTIVATE], 0);
}
else if (button == GDK_BUTTON_SECONDARY)
{
if (swatch->priv->has_color)
do_popup (GTK_WIDGET (swatch), button, gtk_get_current_event_time ());
}
gtk_press_and_hold_process_event (swatch->priv->press_and_hold, (GdkEvent *)event);
return TRUE;
}
static void
@ -669,7 +635,7 @@ swatch_size_allocate (GtkWidget *widget,
static gboolean
swatch_popup_menu (GtkWidget *swatch)
{
do_popup (swatch, NULL);
do_popup (swatch, 0, gtk_get_current_event_time ());
return TRUE;
}
@ -727,7 +693,12 @@ swatch_finalize (GObject *object)
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
g_free (swatch->priv->icon);
g_clear_object (&swatch->priv->press_and_hold);
gtk_gesture_detach (swatch->priv->long_press_gesture);
g_object_unref (swatch->priv->long_press_gesture);
gtk_gesture_detach (swatch->priv->multipress_gesture);
g_object_unref (swatch->priv->multipress_gesture);
G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
}
@ -750,8 +721,6 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class)
widget_class->drag_data_received = swatch_drag_data_received;
widget_class->key_press_event = swatch_key_press;
widget_class->popup_menu = swatch_popup_menu;
widget_class->button_press_event = swatch_button_press;
widget_class->button_release_event = swatch_button_release;
widget_class->enter_notify_event = swatch_enter_notify;
widget_class->leave_notify_event = swatch_leave_notify;
widget_class->realize = swatch_realize;
@ -759,7 +728,6 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class)
widget_class->map = swatch_map;
widget_class->unmap = swatch_unmap;
widget_class->size_allocate = swatch_size_allocate;
widget_class->touch_event = swatch_touch;
signals[ACTIVATE] =
g_signal_new ("activate",

View File

@ -2473,7 +2473,6 @@ gtk_combo_box_popup_for_device (GtkComboBox *combo_box,
return;
}
gtk_device_grab_add (priv->popup_window, pointer, TRUE);
priv->grab_pointer = pointer;
priv->grab_keyboard = keyboard;
@ -2551,7 +2550,6 @@ gtk_combo_box_popdown (GtkComboBox *combo_box)
gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
gtk_device_grab_remove (priv->popup_window, priv->grab_pointer);
gtk_widget_hide (priv->popup_window);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
FALSE);

View File

@ -90,6 +90,7 @@ struct _GtkDragSourceSite
GdkDragAction actions; /* Possible actions */
GtkIconHelper *icon_helper;
GtkGesture *drag_gesture;
/* Stored button press information to detect drag beginning */
gint state;
@ -180,7 +181,7 @@ enum {
};
/* Forward declarations */
static void gtk_drag_get_event_actions (GdkEvent *event,
static void gtk_drag_get_event_actions (const GdkEvent *event,
gint button,
GdkDragAction actions,
GdkDragAction *suggested_action,
@ -265,7 +266,7 @@ static void gtk_drag_update (GtkDragSourceInfo *info,
GdkScreen *screen,
gint x_root,
gint y_root,
GdkEvent *event);
const GdkEvent *event);
static gboolean gtk_drag_motion_cb (GtkWidget *widget,
GdkEventMotion *event,
gpointer data);
@ -696,8 +697,8 @@ gtk_drag_get_event_time (GdkEvent *event)
}
static void
gtk_drag_get_event_actions (GdkEvent *event,
gint button,
gtk_drag_get_event_actions (const GdkEvent *event,
gint button,
GdkDragAction actions,
GdkDragAction *suggested_action,
GdkDragAction *possible_actions)
@ -2472,7 +2473,7 @@ gtk_drag_begin_internal (GtkWidget *widget,
GtkTargetList *target_list,
GdkDragAction actions,
gint button,
GdkEvent *event,
const GdkEvent *event,
int x,
int y)
{
@ -2797,7 +2798,11 @@ gtk_drag_source_set (GtkWidget *widget,
{
site = g_slice_new0 (GtkDragSourceSite);
site->icon_helper = _gtk_icon_helper_new ();
site->drag_gesture = gtk_gesture_drag_new (widget);
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (site->drag_gesture),
FALSE);
gtk_gesture_attach (site->drag_gesture, GTK_PHASE_NONE);
g_signal_connect (widget, "button-press-event",
G_CALLBACK (gtk_drag_source_event_cb),
site);
@ -2807,7 +2812,6 @@ gtk_drag_source_set (GtkWidget *widget,
g_signal_connect (widget, "motion-notify-event",
G_CALLBACK (gtk_drag_source_event_cb),
site);
g_object_set_data_full (G_OBJECT (widget),
I_("gtk-site-data"),
site, gtk_drag_source_site_destroy);
@ -2838,8 +2842,9 @@ gtk_drag_source_unset (GtkWidget *widget)
if (site)
{
g_signal_handlers_disconnect_by_func (widget,
gtk_drag_source_event_cb,
site);
gtk_drag_source_event_cb,
site);
gtk_gesture_detach (site->drag_gesture);
g_object_set_data (G_OBJECT (widget), I_("gtk-site-data"), NULL);
}
}
@ -3899,58 +3904,38 @@ gtk_drag_source_event_cb (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
GtkDragSourceSite *site;
gboolean retval = FALSE;
site = (GtkDragSourceSite *)data;
gdouble start_x, start_y, offset_x, offset_y;
GtkDragSourceSite *site = data;
switch (event->type)
gtk_event_controller_handle_event (GTK_EVENT_CONTROLLER (site->drag_gesture), event);
if (gtk_gesture_is_recognized (site->drag_gesture))
{
case GDK_BUTTON_PRESS:
if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
{
site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
site->x = event->button.x;
site->y = event->button.y;
}
break;
case GDK_BUTTON_RELEASE:
if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
break;
case GDK_MOTION_NOTIFY:
if (site->state & event->motion.state & site->start_button_mask)
{
/* FIXME: This is really broken and can leave us
* with a stuck grab
*/
int i;
for (i=1; i<6; i++)
{
if (site->state & event->motion.state &
GDK_BUTTON1_MASK << (i - 1))
break;
}
gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (site->drag_gesture),
&start_x, &start_y);
gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (site->drag_gesture),
&offset_x, &offset_y);
if (gtk_drag_check_threshold (widget, site->x, site->y,
event->motion.x, event->motion.y))
{
site->state = 0;
gtk_drag_begin_internal (widget, site, site->target_list,
site->actions, i, event,
site->x, site->y);
if (gtk_drag_check_threshold (widget, start_x, start_y,
start_x + offset_x, start_y + offset_y))
{
GdkEventSequence *sequence;
const GdkEvent *event;
guint button;
retval = TRUE;
}
}
break;
default: /* hit for 2/3BUTTON_PRESS */
break;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (site->drag_gesture));
event = gtk_gesture_get_last_event (site->drag_gesture, sequence);
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (site->drag_gesture));
gtk_event_controller_reset (GTK_EVENT_CONTROLLER (site->drag_gesture));
gtk_drag_begin_internal (widget, site, site->target_list,
site->actions, button, event,
start_x, start_y);
return TRUE;
}
}
return retval;
return FALSE;
}
static void
@ -3962,6 +3947,7 @@ gtk_drag_source_site_destroy (gpointer data)
gtk_target_list_unref (site->target_list);
g_clear_object (&site->icon_helper);
g_clear_object (&site->drag_gesture);
g_slice_free (GtkDragSourceSite, site);
}
@ -4223,7 +4209,7 @@ gtk_drag_update (GtkDragSourceInfo *info,
GdkScreen *screen,
gint x_root,
gint y_root,
GdkEvent *event)
const GdkEvent *event)
{
info->cur_screen = screen;
info->cur_x = x_root;

File diff suppressed because it is too large Load Diff

View File

@ -1049,4 +1049,84 @@ typedef enum
GTK_INPUT_HINT_INHIBIT_OSK = 1 << 7
} GtkInputHints;
/**
* GtkPropagationPhase:
* @GTK_PHASE_NONE: Events are not delivered automatically. Those can be
* manually fed through gtk_event_controller_handle_event(). This should
* only be used when full control about when, or whether the controller
* handles the event is needed.
* @GTK_PHASE_CAPTURE: Events are delivered in the capture phase. The
* capture phase happens before the bubble phase, runs from the toplevel down
* to the event widget. This option should only be used on containers that
* might possibly handle events before their children do.
* @GTK_PHASE_BUBBLE: Events are delivered in the bubble phase. The bubble
* phase happens after the capture phase, and before the default handlers
* are run. This phase runs from the event widget, up to the toplevel.
* @GTK_PHASE_TARGET: Events are delivered in the default widget event handlers,
* note that widget implementations must chain up on button, motion, touch and
* grab broken handlers for controllers in this phase to be run.
*
* Describes the stage at which events are fed into a #GtkEventController.
*
* Since: 3.14
*/
typedef enum
{
GTK_PHASE_NONE,
GTK_PHASE_CAPTURE,
GTK_PHASE_BUBBLE,
GTK_PHASE_TARGET
} GtkPropagationPhase;
/**
* GtkEventSequenceState:
* @GTK_EVENT_SEQUENCE_NONE: The sequence is handled, but not grabbed.
* @GTK_EVENT_SEQUENCE_CLAIMED: The sequence is handled and grabbed.
* @GTK_EVENT_SEQUENCE_DENIED: The sequence is denied.
*
* Describes the state of a #GdkEventSequence in a #GtkGesture.
*
* Since: 3.14
*/
typedef enum
{
GTK_EVENT_SEQUENCE_NONE,
GTK_EVENT_SEQUENCE_CLAIMED,
GTK_EVENT_SEQUENCE_DENIED
} GtkEventSequenceState;
/**
* GtkPanDirection:
* @GTK_PAN_DIRECTION_LEFT: panned towards the left
* @GTK_PAN_DIRECTION_RIGHT: panned towards the right
* @GTK_PAN_DIRECTION_UP: panned upwards
* @GTK_PAN_DIRECTION_DOWN: panned downwards
*
* Describes the panning direction of a #GtkGesturePan
*
* Since: 3.14
*/
typedef enum
{
GTK_PAN_DIRECTION_LEFT,
GTK_PAN_DIRECTION_RIGHT,
GTK_PAN_DIRECTION_UP,
GTK_PAN_DIRECTION_DOWN
} GtkPanDirection;
/**
* GtkPanOrientation:
* @GTK_PAN_ORIENTATION_VERTICAL: vertical panning allowed
* @GTK_PAN_ORIENTATION_HORIZONTAL: horizontal panning allowed
*
* Describes the panning axis of a #GtkGesturePan
*
* Since: 3.14
*/
typedef enum
{
GTK_PAN_ORIENTATION_VERTICAL,
GTK_PAN_ORIENTATION_HORIZONTAL
} GtkPanOrientation;
#endif /* __GTK_ENUMS_H__ */

314
gtk/gtkeventcontroller.c Normal file
View File

@ -0,0 +1,314 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkeventcontroller
* @Short_description: Self-contained handler of series of events
* @Title: GtkEventController
* @See_also: #GtkGesture
*
* #GtkEventController is a base, low-level implementation for event
* controllers. Those react to a series of #GdkEvents, and possibly trigger
* actions as a consequence of those.
*/
#include "config.h"
#include "gtkeventcontroller.h"
#include "gtkeventcontrollerprivate.h"
#include "gtktypebuiltins.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtkintl.h"
typedef struct _GtkEventControllerPrivate GtkEventControllerPrivate;
enum {
PROP_WIDGET = 1,
PROP_EVENT_MASK
};
enum {
HANDLE_EVENT,
RESET,
N_SIGNALS
};
struct _GtkEventControllerPrivate
{
GtkWidget *widget;
guint evmask;
};
guint signals[N_SIGNALS] = { 0 };
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkEventController, gtk_event_controller, G_TYPE_OBJECT)
static gboolean
gtk_event_controller_handle_event_default (GtkEventController *controller,
const GdkEvent *event)
{
return FALSE;
}
static void
gtk_event_controller_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkEventControllerPrivate *priv;
priv = gtk_event_controller_get_instance_private (GTK_EVENT_CONTROLLER (object));
switch (prop_id)
{
case PROP_WIDGET:
priv->widget = g_value_get_object (value);
break;
case PROP_EVENT_MASK:
priv->evmask = g_value_get_flags (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_event_controller_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkEventControllerPrivate *priv;
priv = gtk_event_controller_get_instance_private (GTK_EVENT_CONTROLLER (object));
switch (prop_id)
{
case PROP_WIDGET:
g_value_set_object (value, priv->widget);
break;
case PROP_EVENT_MASK:
g_value_set_flags (value, priv->evmask);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_event_controller_class_init (GtkEventControllerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
klass->handle_event = gtk_event_controller_handle_event_default;
object_class->set_property = gtk_event_controller_set_property;
object_class->get_property = gtk_event_controller_get_property;
/**
* GtkEventController:widget:
*
* The widget receiving the #GdkEvents that the controller will handle.
*
* Since: 3.14
*/
g_object_class_install_property (object_class,
PROP_WIDGET,
g_param_spec_object ("widget",
P_("Widget"),
P_("Widget the gesture relates to"),
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
/**
* GtkEventController:event-mask:
*
* Set of events that the controller handles.
*
* Since: 3.14
*/
g_object_class_install_property (object_class,
PROP_EVENT_MASK,
g_param_spec_flags ("event-mask",
P_("Event mask"),
P_("Event mask the controller handles"),
GDK_TYPE_EVENT_MASK, 0,
GTK_PARAM_READWRITE));
/**
* GtkEventController::handle-event:
* @controller: the object which receives the signal
* @event: the event to handle
*
* This signal is emitted on @controller whenever an event is to be handled.
*
* Return value: %TRUE to propagate further emission if the event was handled,
* %FALSE otherwise
*
* Since: 3.14
*/
signals[HANDLE_EVENT] =
g_signal_new ("handle-event",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkEventControllerClass, handle_event),
g_signal_accumulator_true_handled, NULL, NULL,
G_TYPE_BOOLEAN, 1,
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* GtkEventController::reset:
* @controller: the object which receives the signal
*
* This signal is emitted on @controller whenever it needs to be reset. When
* this happens controllers must forget any recorded state.
*
* Since: 3.14
*/
signals[RESET] =
g_signal_new ("reset",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkEventControllerClass, reset),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
gtk_event_controller_init (GtkEventController *controller)
{
}
/**
* gtk_event_controller_handle_event:
* @controller: a #GtkEventController
* @event: a #GdkEvent
*
* Feeds an events into @controller, so it can be interpreted
* and the controller actions triggered.
*
* Returns: %TRUE if the event was potentially useful to trigger the
* controller action
*
* Since: 3.14
**/
gboolean
gtk_event_controller_handle_event (GtkEventController *controller,
const GdkEvent *event)
{
gboolean retval = FALSE;
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_signal_emit (controller, signals[HANDLE_EVENT], 0, event, &retval);
return retval;
}
/**
* gtk_event_controller_set_event_mask:
* @controller: a #GtkEventController
* @event_mask: mask for the events the controller handles
*
* Sets the event mask that the controller handles. This is only
* meant for #GtkEventController implementations and should not be
* called in applications.
*
* Since: 3.14
**/
void
gtk_event_controller_set_event_mask (GtkEventController *controller,
GdkEventMask event_mask)
{
GtkEventControllerPrivate *priv;
g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
priv = gtk_event_controller_get_instance_private (controller);
if (priv->evmask == event_mask)
return;
priv->evmask = event_mask;
g_object_notify (G_OBJECT (controller), "event-mask");
}
/**
* gtk_event_controller_get_event_mask:
* @controller: a #GtkEventController
*
* Returns the event mask necessary for the events handled by @controller.
*
* Returns: the controller event mask
*
* Since: 3.14
**/
GdkEventMask
gtk_event_controller_get_event_mask (GtkEventController *controller)
{
GtkEventControllerPrivate *priv;
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), 0);
priv = gtk_event_controller_get_instance_private (controller);
return priv->evmask;
}
/**
* gtk_event_controller_get_widget:
* @controller: a #GtkEventController
*
* Returns the #GtkWidget this controller relates to.
*
* Returns: (transfer none): a #GtkWidget
*
* Since: 3.14
**/
GtkWidget *
gtk_event_controller_get_widget (GtkEventController *controller)
{
GtkEventControllerPrivate *priv;
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), 0);
priv = gtk_event_controller_get_instance_private (controller);
return priv->widget;
}
/**
* gtk_event_controller_reset:
* @controller: a #GtkEventController
*
* Resets the @controller to a clean state. Every interaction
* the controller did through #GtkEventController::handle-event
* will be dropped at this point.
*
* Since: 3.14
**/
void
gtk_event_controller_reset (GtkEventController *controller)
{
g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
g_signal_emit (controller, signals[RESET], 0);
}

64
gtk/gtkeventcontroller.h Normal file
View File

@ -0,0 +1,64 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_EVENT_CONTROLLER_H__
#define __GTK_EVENT_CONTROLLER_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
typedef struct _GtkEventController GtkEventController;
typedef struct _GtkEventControllerClass GtkEventControllerClass;
#include <gdk/gdk.h>
#include <gtk/gtktypes.h>
#include <gtk/gtkenums.h>
G_BEGIN_DECLS
#define GTK_TYPE_EVENT_CONTROLLER (gtk_event_controller_get_type ())
#define GTK_EVENT_CONTROLLER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_EVENT_CONTROLLER, GtkEventController))
#define GTK_EVENT_CONTROLLER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_EVENT_CONTROLLER, GtkEventControllerClass))
#define GTK_IS_EVENT_CONTROLLER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_EVENT_CONTROLLER))
#define GTK_IS_EVENT_CONTROLLER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_EVENT_CONTROLLER))
#define GTK_EVENT_CONTROLLER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_EVENT_CONTROLLER, GtkEventControllerClass))
GDK_AVAILABLE_IN_3_14
GType gtk_event_controller_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GtkWidget * gtk_event_controller_get_widget (GtkEventController *controller);
GDK_AVAILABLE_IN_3_14
void gtk_event_controller_set_event_mask (GtkEventController *controller,
GdkEventMask event_mask);
GDK_AVAILABLE_IN_3_14
GdkEventMask gtk_event_controller_get_event_mask (GtkEventController *controller);
GDK_AVAILABLE_IN_3_14
gboolean gtk_event_controller_handle_event (GtkEventController *controller,
const GdkEvent *event);
GDK_AVAILABLE_IN_3_14
void gtk_event_controller_reset (GtkEventController *controller);
G_END_DECLS
#endif /* __GTK_EVENT_CONTROLLER_H__ */

View File

@ -0,0 +1,42 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_EVENT_CONTROLLER_PRIVATE_H__
#define __GTK_EVENT_CONTROLLER_PRIVATE_H__
#include "gtkeventcontroller.h"
struct _GtkEventController
{
GObject parent_instance;
};
struct _GtkEventControllerClass
{
GObjectClass parent_class;
gboolean (* handle_event) (GtkEventController *controller,
const GdkEvent *event);
void (* reset) (GtkEventController *controller);
/*<private>*/
gpointer padding[10];
};
#endif /* __GTK_EVENT_CONTROLLER_PRIVATE_H__ */

1596
gtk/gtkgesture.c Normal file

File diff suppressed because it is too large Load Diff

120
gtk/gtkgesture.h Normal file
View File

@ -0,0 +1,120 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_H__
#define __GTK_GESTURE_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkeventcontroller.h>
#include <gtk/gtkenums.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE (gtk_gesture_get_type ())
#define GTK_GESTURE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE, GtkGesture))
#define GTK_GESTURE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE, GtkGestureClass))
#define GTK_IS_GESTURE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE))
#define GTK_IS_GESTURE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE))
#define GTK_GESTURE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE, GtkGestureClass))
typedef struct _GtkGesture GtkGesture;
typedef struct _GtkGestureClass GtkGestureClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GdkDevice * gtk_gesture_get_device (GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_set_state (GtkGesture *gesture,
GtkEventSequenceState state);
GDK_AVAILABLE_IN_3_14
GtkEventSequenceState
gtk_gesture_get_sequence_state (GtkGesture *gesture,
GdkEventSequence *sequence);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_set_sequence_state (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkEventSequenceState state);
GDK_AVAILABLE_IN_3_14
GList * gtk_gesture_get_sequences (GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
GdkEventSequence * gtk_gesture_get_last_updated_sequence
(GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_handles_sequence (GtkGesture *gesture,
GdkEventSequence *sequence);
GDK_AVAILABLE_IN_3_14
const GdkEvent *
gtk_gesture_get_last_event (GtkGesture *gesture,
GdkEventSequence *sequence);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_get_point (GtkGesture *gesture,
GdkEventSequence *sequence,
gdouble *x,
gdouble *y);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_get_bounding_box (GtkGesture *gesture,
GdkRectangle *rect);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_get_bounding_box_center
(GtkGesture *gesture,
gdouble *x,
gdouble *y);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_is_active (GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_is_recognized (GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
GdkWindow * gtk_gesture_get_window (GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_set_window (GtkGesture *gesture,
GdkWindow *window);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_group (GtkGesture *group_gesture,
GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_ungroup (GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
GList * gtk_gesture_get_group (GtkGesture *gesture);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_is_grouped_with (GtkGesture *gesture,
GtkGesture *other);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_attach (GtkGesture *gesture,
GtkPropagationPhase phase);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_detach (GtkGesture *gesture);
G_END_DECLS
#endif /* __GTK_GESTURE_H__ */

272
gtk/gtkgesturedrag.c Normal file
View File

@ -0,0 +1,272 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkgesturedrag
* @Short_description: Drag gesture
* @Title: GtkGestureDrag
* @See_also: #GtkGestureSwipe
*
* #GtkGestureDrag is a #GtkGesture implementation that recognizes drag
* operations. The drag operation itself can be tracked throught the
* #GtkGestureDrag:drag-begin, #GtkGestureDrag:drag-update and
* #GtkGestureDrag:drag-end signals, or the relevant coordinates be
* extracted through gtk_gesture_drag_get_offset() and
* gtk_gesture_drag_get_start_point().
*/
#include "config.h"
#include "gtkgesturedrag.h"
#include "gtkgesturedragprivate.h"
typedef struct _GtkGestureDragPrivate GtkGestureDragPrivate;
typedef struct _EventData EventData;
struct _GtkGestureDragPrivate
{
gdouble start_x;
gdouble start_y;
gdouble last_x;
gdouble last_y;
};
enum {
DRAG_BEGIN,
DRAG_UPDATE,
DRAG_END,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureDrag, gtk_gesture_drag, GTK_TYPE_GESTURE_SINGLE)
static void
gtk_gesture_drag_begin (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureDragPrivate *priv;
GdkEventSequence *current;
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
gtk_gesture_get_point (gesture, current, &priv->start_x, &priv->start_y);
priv->last_x = priv->start_x;
priv->last_y = priv->start_y;
g_signal_emit (gesture, signals[DRAG_BEGIN], 0, priv->start_x, priv->start_y);
}
static void
gtk_gesture_drag_update (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureDragPrivate *priv;
gdouble x, y;
priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
gtk_gesture_get_point (gesture, sequence, &priv->last_x, &priv->last_y);
x = priv->last_x - priv->start_x;
y = priv->last_y - priv->start_y;
g_signal_emit (gesture, signals[DRAG_UPDATE], 0, x, y);
}
static void
gtk_gesture_drag_end (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureDragPrivate *priv;
GdkEventSequence *current;
gdouble x, y;
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
gtk_gesture_get_point (gesture, current, &priv->last_x, &priv->last_y);
x = priv->last_x - priv->start_x;
y = priv->last_y - priv->start_y;
g_signal_emit (gesture, signals[DRAG_END], 0, x, y);
}
static void
gtk_gesture_drag_class_init (GtkGestureDragClass *klass)
{
GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass);
gesture_class->begin = gtk_gesture_drag_begin;
gesture_class->update = gtk_gesture_drag_update;
gesture_class->end = gtk_gesture_drag_end;
/**
* GtkGestureDrag::drag-begin:
* @gesture: the object which received the signal
* @start_x: X coordinate, relative to the widget allocation
* @start_y: Y coordinate, relative to the widget allocation
*
* This signal is emitted whenever dragging starts.
*
* Since: 3.14
*/
signals[DRAG_BEGIN] =
g_signal_new ("drag-begin",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureDragClass, drag_begin),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
/**
* GtkGestureDrag::drag-update:
* @gesture: the object which received the signal
* @offset_x: X offset, relative to the start point
* @offset_y: Y offset, relative to the start point
*
* This signal is emitted whenever the dragging point moves.
*
* Since: 3.14
*/
signals[DRAG_UPDATE] =
g_signal_new ("drag-update",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureDragClass, drag_update),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
/**
* GtkGestureDrag::drag-end:
* @gesture: the object which received the signal
* @offset_x: X offset, relative to the start point
* @offset_y: Y offset, relative to the start point
*
* This signal is emitted whenever the dragging is finished.
*
* Since: 3.14
*/
signals[DRAG_END] =
g_signal_new ("drag-end",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureDragClass, drag_end),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
}
static void
gtk_gesture_drag_init (GtkGestureDrag *gesture)
{
}
/**
* gtk_gesture_drag_new:
* @widget: a #GtkWidget
*
* Returns a newly created #GtkGesture that recognizes drags.
*
* Returns: a newly created #GtkGestureDrag
*
* Since: 3.14
**/
GtkGesture *
gtk_gesture_drag_new (GtkWidget *widget)
{
return g_object_new (GTK_TYPE_GESTURE_DRAG,
"widget", widget,
NULL);
}
/**
* gtk_gesture_drag_get_start_point:
* @gesture: a #GtkGesture
* @x: X coordinate for the drag start point
* @y: Y coordinate for the drag start point
*
* If the @gesture is active, this function returns %TRUE
* and fills in @x and @y with the drag start coordinates,
* in window-relative coordinates.
*
* Returns: %TRUE if the gesture is active
*
* Since: 3.14
**/
gboolean
gtk_gesture_drag_get_start_point (GtkGestureDrag *gesture,
gdouble *x,
gdouble *y)
{
GtkGestureDragPrivate *priv;
GdkEventSequence *sequence;
g_return_val_if_fail (GTK_IS_GESTURE_DRAG (gesture), FALSE);
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
return FALSE;
priv = gtk_gesture_drag_get_instance_private (gesture);
if (x)
*x = priv->start_x;
if (y)
*y = priv->start_y;
return TRUE;
}
/**
* gtk_gesture_drag_get_offset:
* @gesture: a #GtkGesture
* @x: X offset for the current point
* @y: Y offset for the current point
*
* If the @gesture is active, this function returns %TRUE and
* fills in @x and @y with the coordinates of the current point,
* as an offset to the starting drag point.
*
* Returns: %TRUE if the gesture is active
*
* Since: 3.14
**/
gboolean
gtk_gesture_drag_get_offset (GtkGestureDrag *gesture,
gdouble *x,
gdouble *y)
{
GtkGestureDragPrivate *priv;
GdkEventSequence *sequence;
g_return_val_if_fail (GTK_IS_GESTURE_DRAG (gesture), FALSE);
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
return FALSE;
priv = gtk_gesture_drag_get_instance_private (gesture);
if (x)
*x = priv->last_x - priv->start_x;
if (y)
*y = priv->last_y - priv->start_y;
return TRUE;
}

58
gtk/gtkgesturedrag.h Normal file
View File

@ -0,0 +1,58 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_DRAG_H__
#define __GTK_GESTURE_DRAG_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkwidget.h>
#include <gtk/gtkgesturesingle.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_DRAG (gtk_gesture_drag_get_type ())
#define GTK_GESTURE_DRAG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_DRAG, GtkGestureDrag))
#define GTK_GESTURE_DRAG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_DRAG, GtkGestureDragClass))
#define GTK_IS_GESTURE_DRAG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_DRAG))
#define GTK_IS_GESTURE_DRAG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_DRAG))
#define GTK_GESTURE_DRAG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_DRAG, GtkGestureDragClass))
typedef struct _GtkGestureDrag GtkGestureDrag;
typedef struct _GtkGestureDragClass GtkGestureDragClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_drag_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GtkGesture * gtk_gesture_drag_new (GtkWidget *widget);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_drag_get_start_point (GtkGestureDrag *gesture,
gdouble *x,
gdouble *y);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_drag_get_offset (GtkGestureDrag *gesture,
gdouble *x,
gdouble *y);
G_END_DECLS
#endif /* __GTK_GESTURE_DRAG_H__ */

View File

@ -0,0 +1,47 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_DRAG_PRIVATE_H__
#define __GTK_GESTURE_DRAG_PRIVATE_H__
#include "gtkgesturesingleprivate.h"
#include "gtkgesturedrag.h"
struct _GtkGestureDrag
{
GtkGestureSingle parent_instance;
};
struct _GtkGestureDragClass
{
GtkGestureSingleClass parent_class;
void (* drag_begin) (GtkGestureDrag *gesture,
gdouble start_x,
gdouble start_y);
void (* drag_update) (GtkGestureDrag *gesture,
gdouble offset_x,
gdouble offset_y);
void (* drag_end) (GtkGestureDrag *gesture,
gdouble offset_x,
gdouble offset_y);
/*<private>*/
gpointer padding[10];
};
#endif /* __GTK_GESTURE_DRAG_PRIVATE_H__ */

268
gtk/gtkgesturelongpress.c Normal file
View File

@ -0,0 +1,268 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkgesturelongpress
* @Short_description: "Press and Hold" gesture
* @Title: GtkGestureLongPress
*
* #GtkGestureLongPress is a #GtkGesture implementation able to recognize
* long presses, triggering the #GtkGestureLongPress::pressed after the
* timeout is exceeded.
*
* If the touchpoint is lifted before the timeout passes, or if it drifts
* too far of the initial press point, the #GtkGestureLongPress::cancelled
* signal will be emitted.
*/
#include "config.h"
#include "gtkgesturelongpress.h"
#include "gtkgesturelongpressprivate.h"
#include "gtkgestureprivate.h"
#include "gtkmarshalers.h"
#include "gtkdnd.h"
#include "gtkprivate.h"
#include "gtkintl.h"
typedef struct _GtkGestureLongPressPrivate GtkGestureLongPressPrivate;
enum {
PRESSED,
CANCELLED,
N_SIGNALS
};
struct _GtkGestureLongPressPrivate
{
gdouble initial_x;
gdouble initial_y;
guint timeout_id;
guint delay;
guint cancelled : 1;
guint triggered : 1;
};
static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureLongPress, gtk_gesture_long_press, GTK_TYPE_GESTURE_SINGLE)
static void
gtk_gesture_long_press_init (GtkGestureLongPress *gesture)
{
}
static gboolean
gtk_gesture_long_press_check (GtkGesture *gesture)
{
GtkGestureLongPressPrivate *priv;
priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (gesture));
if (priv->cancelled)
return FALSE;
return GTK_GESTURE_CLASS (gtk_gesture_long_press_parent_class)->check (gesture);
}
static gboolean
_gtk_gesture_long_press_timeout (gpointer user_data)
{
GtkGestureLongPress *gesture = user_data;
GtkGestureLongPressPrivate *priv;
GdkEventSequence *sequence;
gdouble x, y;
priv = gtk_gesture_long_press_get_instance_private (gesture);
sequence = gtk_gesture_get_last_updated_sequence (GTK_GESTURE (gesture));
gtk_gesture_get_point (GTK_GESTURE (gesture), sequence, &x, &y);
priv->timeout_id = 0;
priv->triggered = TRUE;
g_signal_emit (gesture, signals[PRESSED], 0, x, y);
return FALSE;
}
static void
gtk_gesture_long_press_begin (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureLongPressPrivate *priv;
const GdkEvent *event;
GtkWidget *widget;
gint delay;
priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (gesture));
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
event = gtk_gesture_get_last_event (gesture, sequence);
if (!event ||
(event->type != GDK_BUTTON_PRESS &&
event->type != GDK_TOUCH_BEGIN))
return;
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
g_object_get (gtk_widget_get_settings (widget),
"gtk-long-press-time", &delay, NULL);
gtk_gesture_get_point (gesture, sequence,
&priv->initial_x, &priv->initial_y);
priv->timeout_id =
gdk_threads_add_timeout (delay,
_gtk_gesture_long_press_timeout,
gesture);
}
static void
gtk_gesture_long_press_update (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureLongPressPrivate *priv;
GtkWidget *widget;
gdouble x, y;
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (gesture));
gtk_gesture_get_point (gesture, sequence, &x, &y);
if (gtk_drag_check_threshold (widget, priv->initial_x, priv->initial_y, x, y))
{
if (priv->timeout_id)
{
g_source_remove (priv->timeout_id);
priv->timeout_id = 0;
g_signal_emit (gesture, signals[CANCELLED], 0);
}
priv->cancelled = TRUE;
_gtk_gesture_check (gesture);
}
}
static void
gtk_gesture_long_press_end (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureLongPressPrivate *priv;
priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (gesture));
if (priv->timeout_id)
{
g_source_remove (priv->timeout_id);
priv->timeout_id = 0;
g_signal_emit (gesture, signals[CANCELLED], 0);
}
priv->cancelled = priv->triggered = FALSE;
}
static void
gtk_gesture_long_press_sequence_state_changed (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkEventSequenceState state)
{
if (state == GTK_EVENT_SEQUENCE_DENIED)
gtk_gesture_long_press_end (gesture, sequence);
}
static void
gtk_gesture_long_press_finalize (GObject *object)
{
GtkGestureLongPressPrivate *priv;
priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (object));
if (priv->timeout_id)
g_source_remove (priv->timeout_id);
G_OBJECT_CLASS (gtk_gesture_long_press_parent_class)->finalize (object);
}
static void
gtk_gesture_long_press_class_init (GtkGestureLongPressClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass);
object_class->finalize = gtk_gesture_long_press_finalize;
gesture_class->check = gtk_gesture_long_press_check;
gesture_class->begin = gtk_gesture_long_press_begin;
gesture_class->update = gtk_gesture_long_press_update;
gesture_class->end = gtk_gesture_long_press_end;
gesture_class->cancel = gtk_gesture_long_press_end;
gesture_class->sequence_state_changed =
gtk_gesture_long_press_sequence_state_changed;
/**
* GtkGestureLongPress::pressed:
* @gesture: the object which received the signal
* @x: the X coordinate where the press happened, relative to the widget allocation
* @y: the Y coordinate where the press happened, relative to the widget allocation
*
* This signal is emitted whenever a press goes unmoved/unreleased longer than
* what the GTK+ defaults tell.
*
* Since: 3.14
*/
signals[PRESSED] =
g_signal_new ("pressed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureLongPressClass, pressed),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
/**
* GtkGestureLongPress::cancelled:
* @gesture: the object which received the signal
*
* This signal is emitted whenever a press moved too far, or was released
* before #GtkGestureLongPress:pressed happened.
*
* Since: 3.14
*/
signals[CANCELLED] =
g_signal_new ("cancelled",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureLongPressClass, cancelled),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
/**
* gtk_gesture_long_press_new:
* @widget: a #GtkWidget
*
* Returns a newly created #GtkGesture that recognizes long presses.
*
* Returns: a newly created #GtkGestureLongPress
*
* Since: 3.14
**/
GtkGesture *
gtk_gesture_long_press_new (GtkWidget *widget)
{
return g_object_new (GTK_TYPE_GESTURE_LONG_PRESS,
"widget", widget,
NULL);
}

49
gtk/gtkgesturelongpress.h Normal file
View File

@ -0,0 +1,49 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_LONG_PRESS_H__
#define __GTK_GESTURE_LONG_PRESS_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkgesturesingle.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_LONG_PRESS (gtk_gesture_long_press_get_type ())
#define GTK_GESTURE_LONG_PRESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_LONG_PRESS, GtkGestureLongPress))
#define GTK_GESTURE_LONG_PRESS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_LONG_PRESS, GtkGestureLongPressClass))
#define GTK_IS_GESTURE_LONG_PRESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_LONG_PRESS))
#define GTK_IS_GESTURE_LONG_PRESS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_LONG_PRESS))
#define GTK_GESTURE_LONG_PRESS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_LONG_PRESS, GtkGestureLongPressClass))
typedef struct _GtkGestureLongPress GtkGestureLongPress;
typedef struct _GtkGestureLongPressClass GtkGestureLongPressClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_long_press_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GtkGesture * gtk_gesture_long_press_new (GtkWidget *widget);
G_END_DECLS
#endif /* __GTK_GESTURE_LONG_PRESS_H__ */

View File

@ -0,0 +1,44 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_LONG_PRESS_PRIVATE_H__
#define __GTK_GESTURE_LONG_PRESS_PRIVATE_H__
#include "gtkgesturesingleprivate.h"
#include "gtkgesturelongpress.h"
struct _GtkGestureLongPress
{
GtkGestureSingle parent_instance;
};
struct _GtkGestureLongPressClass
{
GtkGestureSingleClass parent_class;
void (* pressed) (GtkGestureLongPress *gesture,
gdouble x,
gdouble y);
void (* cancelled) (GtkGestureLongPress *gesture);
/*< private >*/
gpointer padding[10];
};
#endif /* __GTK_GESTURE_LONG_PRESS_PRIVATE_H__ */

465
gtk/gtkgesturemultipress.c Normal file
View File

@ -0,0 +1,465 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkgesturemultipress
* @Short_description: Multipress gesture
* @Title: GtkGestureMultiPress
*
* #GtkGestureMultiPress is a #GtkGesture implementation able to recognize
* multiple clicks on a nearby zone, which can be listened for through the
* #GtkGestureMultiPress::pressed signal. Whenever time or distance between
* clicks exceed the GTK+ defaults, #GtkGestureMultiPress::stopped is emitted,
* and the click counter is reset.
*
* Callers may also restrict the area that is considered valid for a >1
* touch/button press through gtk_gesture_multi_press_set_area(), so any
* click happening outside that area is considered to be a first click of
* its own.
*/
#include "config.h"
#include "gtkgestureprivate.h"
#include "gtkgesturemultipress.h"
#include "gtkgesturemultipressprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
typedef struct _GtkGestureMultiPressPrivate GtkGestureMultiPressPrivate;
struct _GtkGestureMultiPressPrivate
{
GdkRectangle rect;
gdouble initial_press_x;
gdouble initial_press_y;
guint double_click_timeout_id;
guint n_presses;
guint n_release;
guint current_button;
guint rect_is_set : 1;
};
enum {
PRESSED,
RELEASED,
STOPPED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureMultiPress, gtk_gesture_multi_press, GTK_TYPE_GESTURE_SINGLE)
static void
gtk_gesture_multi_press_finalize (GObject *object)
{
GtkGestureMultiPressPrivate *priv;
GtkGestureMultiPress *gesture;
gesture = GTK_GESTURE_MULTI_PRESS (object);
priv = gtk_gesture_multi_press_get_instance_private (gesture);
if (priv->double_click_timeout_id)
{
g_source_remove (priv->double_click_timeout_id);
priv->double_click_timeout_id = 0;
}
G_OBJECT_CLASS (gtk_gesture_multi_press_parent_class)->finalize (object);
}
static gboolean
gtk_gesture_multi_press_check (GtkGesture *gesture)
{
GtkGestureMultiPress *multi_press;
GtkGestureMultiPressPrivate *priv;
GList *sequences;
gboolean active;
multi_press = GTK_GESTURE_MULTI_PRESS (gesture);
priv = gtk_gesture_multi_press_get_instance_private (multi_press);
sequences = gtk_gesture_get_sequences (gesture);
active = g_list_length (sequences) == 1 || priv->double_click_timeout_id;
g_list_free (sequences);
return active;
}
static void
_gtk_gesture_multi_press_stop (GtkGestureMultiPress *gesture)
{
GtkGestureMultiPressPrivate *priv;
priv = gtk_gesture_multi_press_get_instance_private (gesture);
if (priv->n_presses == 0)
return;
priv->current_button = 0;
priv->n_presses = 0;
g_signal_emit (gesture, signals[STOPPED], 0);
_gtk_gesture_check (GTK_GESTURE (gesture));
}
static gboolean
_double_click_timeout_cb (gpointer user_data)
{
GtkGestureMultiPress *gesture = user_data;
GtkGestureMultiPressPrivate *priv;
priv = gtk_gesture_multi_press_get_instance_private (gesture);
priv->double_click_timeout_id = 0;
_gtk_gesture_multi_press_stop (gesture);
return FALSE;
}
static void
_gtk_gesture_multi_press_update_timeout (GtkGestureMultiPress *gesture)
{
GtkGestureMultiPressPrivate *priv;
guint double_click_time;
GtkSettings *settings;
GtkWidget *widget;
priv = gtk_gesture_multi_press_get_instance_private (gesture);
if (priv->double_click_timeout_id)
g_source_remove (priv->double_click_timeout_id);
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
settings = gtk_widget_get_settings (widget);
g_object_get (settings, "gtk-double-click-time", &double_click_time, NULL);
priv->double_click_timeout_id =
gdk_threads_add_timeout (double_click_time,
_double_click_timeout_cb,
gesture);
}
static gboolean
_gtk_gesture_multi_press_check_within_threshold (GtkGestureMultiPress *gesture,
gdouble x,
gdouble y)
{
GtkGestureMultiPressPrivate *priv;
guint double_click_distance;
GtkSettings *settings;
GtkWidget *widget;
priv = gtk_gesture_multi_press_get_instance_private (gesture);
if (priv->n_presses == 0)
return TRUE;
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
settings = gtk_widget_get_settings (widget);
g_object_get (settings,
"gtk-double-click-distance", &double_click_distance,
NULL);
if (ABS (priv->initial_press_x - x) < double_click_distance &&
ABS (priv->initial_press_y - y) < double_click_distance)
{
if (!priv->rect_is_set ||
(x >= priv->rect.x && x < priv->rect.x + priv->rect.width &&
y >= priv->rect.y && y < priv->rect.y + priv->rect.height))
return TRUE;
}
return FALSE;
}
static void
gtk_gesture_multi_press_begin (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureMultiPress *multi_press;
GtkGestureMultiPressPrivate *priv;
guint n_presses, button = 1;
GdkEventSequence *current;
const GdkEvent *event;
gdouble x, y;
if (!gtk_gesture_handles_sequence (gesture, sequence))
return;
multi_press = GTK_GESTURE_MULTI_PRESS (gesture);
priv = gtk_gesture_multi_press_get_instance_private (multi_press);
event = gtk_gesture_get_last_event (gesture, sequence);
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (event->type == GDK_BUTTON_PRESS)
button = event->button.button;
else if (event->type == GDK_TOUCH_BEGIN)
button = 1;
else
return;
/* Reset the gesture if the button number changes mid-recognition */
if (priv->n_presses > 0 &&
priv->current_button != button)
_gtk_gesture_multi_press_stop (multi_press);
priv->current_button = button;
_gtk_gesture_multi_press_update_timeout (multi_press);
gtk_gesture_get_point (gesture, current, &x, &y);
if (!_gtk_gesture_multi_press_check_within_threshold (multi_press, x, y))
_gtk_gesture_multi_press_stop (multi_press);
/* Increment later the real counter, just if the gesture is
* reset on the pressed handler */
n_presses = priv->n_release = priv->n_presses + 1;
g_signal_emit (gesture, signals[PRESSED], 0, n_presses, x, y);
if (priv->n_presses == 0)
{
priv->initial_press_x = x;
priv->initial_press_y = y;
}
priv->n_presses++;
}
static void
gtk_gesture_multi_press_update (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureMultiPress *multi_press;
GdkEventSequence *current;
gdouble x, y;
multi_press = GTK_GESTURE_MULTI_PRESS (gesture);
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
gtk_gesture_get_point (gesture, current, &x, &y);
if (!_gtk_gesture_multi_press_check_within_threshold (multi_press, x, y))
_gtk_gesture_multi_press_stop (multi_press);
}
static void
gtk_gesture_multi_press_end (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureMultiPress *multi_press;
GtkGestureMultiPressPrivate *priv;
GdkEventSequence *current;
gdouble x, y;
multi_press = GTK_GESTURE_MULTI_PRESS (gesture);
priv = gtk_gesture_multi_press_get_instance_private (multi_press);
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
gtk_gesture_get_point (gesture, current, &x, &y);
g_signal_emit (gesture, signals[RELEASED], 0, priv->n_release, x, y);
priv->n_release = 0;
}
static void
gtk_gesture_multi_press_cancel (GtkGesture *gesture,
GdkEventSequence *sequence)
{
_gtk_gesture_multi_press_stop (GTK_GESTURE_MULTI_PRESS (gesture));
}
static void
gtk_gesture_multi_press_reset (GtkEventController *controller)
{
_gtk_gesture_multi_press_stop (GTK_GESTURE_MULTI_PRESS (controller));
GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_multi_press_parent_class)->reset (controller);
}
static void
gtk_gesture_multi_press_class_init (GtkGestureMultiPressClass *klass)
{
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass);
object_class->finalize = gtk_gesture_multi_press_finalize;
gesture_class->check = gtk_gesture_multi_press_check;
gesture_class->begin = gtk_gesture_multi_press_begin;
gesture_class->update = gtk_gesture_multi_press_update;
gesture_class->end = gtk_gesture_multi_press_end;
gesture_class->cancel = gtk_gesture_multi_press_cancel;
controller_class->reset = gtk_gesture_multi_press_reset;
/**
* GtkGestureMultiPress::pressed:
* @gesture: the object which received the signal
* @n_press: how many touch/button presses happened with this one
* @x: The X coordinate, in widget allocation coordinates
* @y: The Y coordinate, in widget allocation coordinates
*
* This signal is emitted whenever a button or touch press happens.
*
* Since: 3.14
*/
signals[PRESSED] =
g_signal_new ("pressed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureMultiPressClass, pressed),
NULL, NULL, NULL,
G_TYPE_NONE, 3, G_TYPE_INT,
G_TYPE_DOUBLE, G_TYPE_DOUBLE);
/**
* GtkGestureMultiPress::released:
* @gesture: the object which received the signal
* @n_press: number of press that is paired with this release
* @x: The X coordinate, in widget allocation coordinates
* @y: The Y coordinate, in widget allocation coordinates
*
* This signal is emitted when a button or touch is released. @n_press
* will report the number of press that is paired to this event, note
* that #GtkGestureMultiPress::stopped may have been emitted between the
* press and its release, @n_press will only start over at the next press.
*
* Since: 3.14
*/
signals[RELEASED] =
g_signal_new ("released",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureMultiPressClass, released),
NULL, NULL, NULL,
G_TYPE_NONE, 3, G_TYPE_INT,
G_TYPE_DOUBLE, G_TYPE_DOUBLE);
/**
* GtkGestureMultiPress::stopped:
* @gesture: the object which received the signal
*
* This signal is emitted whenever any time/distance threshold has
* been exceeded.
*
* Since: 3.14
*/
signals[STOPPED] =
g_signal_new ("stopped",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureMultiPressClass, stopped),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
gtk_gesture_multi_press_init (GtkGestureMultiPress *gesture)
{
}
/**
* gtk_gesture_multi_press_new:
* @widget: a #GtkWidget
*
* Returns a newly created #GtkGesture that recognizes single and multiple
* presses.
*
* Returns: a newly created #GtkGestureMultiPress
*
* Since: 3.14
**/
GtkGesture *
gtk_gesture_multi_press_new (GtkWidget *widget)
{
return g_object_new (GTK_TYPE_GESTURE_MULTI_PRESS,
"widget", widget,
NULL);
}
/**
* gtk_gesture_multi_press_set_area:
* @gesture: a #GtkGesture
* @rect: (allow-none): rectangle to receive coordinates on
*
* If @rect is non-%NULL, the press area will be checked to be
* confined within the rectangle, otherwise the button count
* will be reset so the press is seen as being the first one.
* If @rect is #NULL, the area will be reset to an unrestricted
* state.
*
* Note: The rectangle is only used to determine whether any
* non-first click falls within the expected area. This is not
* akin to an input shape.
*
* Since: 3.14
**/
void
gtk_gesture_multi_press_set_area (GtkGestureMultiPress *gesture,
const GdkRectangle *rect)
{
GtkGestureMultiPressPrivate *priv;
g_return_if_fail (GTK_IS_GESTURE_MULTI_PRESS (gesture));
g_return_if_fail (rect != NULL);
priv = gtk_gesture_multi_press_get_instance_private (gesture);
if (!rect)
priv->rect_is_set = FALSE;
else
{
priv->rect_is_set = TRUE;
priv->rect = *rect;
}
}
/**
* gtk_gesture_multi_press_get_area:
* @gesture: a #GtkGestureMultiPress
* @rect: (out): return location for the press area
*
* If an area was set through gtk_gesture_multi_press_set_area(),
* this function will return %TRUE and fill in @rect with the
* press area. See gtk_gesture_multi_press_set_area() for more
* details on what the press area represents.
*
* Returns: %TRUE if @rect was filled with the press area
*
* Since: 3.14
**/
gboolean
gtk_gesture_multi_press_get_area (GtkGestureMultiPress *gesture,
GdkRectangle *rect)
{
GtkGestureMultiPressPrivate *priv;
g_return_val_if_fail (GTK_IS_GESTURE_MULTI_PRESS (gesture), FALSE);
priv = gtk_gesture_multi_press_get_instance_private (gesture);
if (rect)
{
if (priv->rect_is_set)
*rect = priv->rect;
else
{
rect->x = rect->y = G_MININT;
rect->width = rect->height = G_MAXINT;
}
}
return priv->rect_is_set;
}

View File

@ -0,0 +1,56 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_MULTI_PRESS_H__
#define __GTK_GESTURE_MULTI_PRESS_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkwidget.h>
#include <gtk/gtkgesturesingle.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_MULTI_PRESS (gtk_gesture_multi_press_get_type ())
#define GTK_GESTURE_MULTI_PRESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_MULTI_PRESS, GtkGestureMultiPress))
#define GTK_GESTURE_MULTI_PRESS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_MULTI_PRESS, GtkGestureMultiPressClass))
#define GTK_IS_GESTURE_MULTI_PRESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_MULTI_PRESS))
#define GTK_IS_GESTURE_MULTI_PRESS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_MULTI_PRESS))
#define GTK_GESTURE_MULTI_PRESS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_MULTI_PRESS, GtkGestureMultiPressClass))
typedef struct _GtkGestureMultiPress GtkGestureMultiPress;
typedef struct _GtkGestureMultiPressClass GtkGestureMultiPressClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_multi_press_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GtkGesture * gtk_gesture_multi_press_new (GtkWidget *widget);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_multi_press_set_area (GtkGestureMultiPress *gesture,
const GdkRectangle *rect);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_multi_press_get_area (GtkGestureMultiPress *gesture,
GdkRectangle *rect);
G_END_DECLS
#endif /* __GTK_GESTURE_MULTI_PRESS_H__ */

View File

@ -0,0 +1,48 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_MULTI_PRESS_PRIVATE_H__
#define __GTK_GESTURE_MULTI_PRESS_PRIVATE_H__
#include "gtkgesturesingleprivate.h"
#include "gtkgesturemultipress.h"
struct _GtkGestureMultiPress
{
GtkGestureSingle parent_instance;
};
struct _GtkGestureMultiPressClass
{
GtkGestureSingleClass parent_class;
void (* pressed) (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y);
void (* released) (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y);
void (* stopped) (GtkGestureMultiPress *gesture);
/*<private>*/
gpointer padding[10];
};
#endif /* __GTK_GESTURE_MULTI_PRESS_PRIVATE_H__ */

343
gtk/gtkgesturepan.c Normal file
View File

@ -0,0 +1,343 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkgesturepan
* @Short_description: Pan gesture
* @Title: GtkGesturePan
*
* #GtkGesturePan is a #GtkGesture implementation able to recognize
* pan gestures, those are drags that are locked to happen along one
* axis. The axis that a #GtkGesturePan handles is defined at
* construct time, and can be changed through
* gtk_gesture_pan_set_orientation().
*
* When the gesture starts to be recognized, #GtkGesturePan will
* attempt to determine as early as possible whether the sequence
* is moving in the expected direction, and denying the sequence if
* this does not happen.
*
* Once a panning gesture along the expected axis is recognized,
* the #GtkGesturePan::pan signal will be emitted as input events
* are received, containing the offset in the given axis.
*/
#include "config.h"
#include "gtkgesturepan.h"
#include "gtkgesturepanprivate.h"
#include "gtktypebuiltins.h"
#include "gtkprivate.h"
#include "gtkintl.h"
typedef struct _GtkGesturePanPrivate GtkGesturePanPrivate;
struct _GtkGesturePanPrivate
{
guint orientation : 2;
guint panning : 1;
};
enum {
PROP_ORIENTATION = 1
};
enum {
PAN,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkGesturePan, gtk_gesture_pan, GTK_TYPE_GESTURE_DRAG)
static void
gtk_gesture_pan_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkGesturePanPrivate *priv;
priv = gtk_gesture_pan_get_instance_private (GTK_GESTURE_PAN (object));
switch (prop_id)
{
case PROP_ORIENTATION:
g_value_set_enum (value, priv->orientation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_gesture_pan_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_ORIENTATION:
gtk_gesture_pan_set_orientation (GTK_GESTURE_PAN (object),
g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
direction_from_offset (gdouble offset_x,
gdouble offset_y,
GtkPanOrientation orientation,
GtkPanDirection *direction)
{
if (orientation == GTK_PAN_ORIENTATION_HORIZONTAL)
{
if (offset_x > 0)
*direction = GTK_PAN_DIRECTION_RIGHT;
else
*direction = GTK_PAN_DIRECTION_LEFT;
}
else if (orientation == GTK_PAN_ORIENTATION_VERTICAL)
{
if (offset_y > 0)
*direction = GTK_PAN_DIRECTION_DOWN;
else
*direction = GTK_PAN_DIRECTION_UP;
}
else
g_assert_not_reached ();
}
static gboolean
guess_direction (GtkGesturePan *gesture,
gdouble offset_x,
gdouble offset_y,
GtkPanDirection *direction)
{
gdouble abs_x, abs_y;
abs_x = ABS (offset_x);
abs_y = ABS (offset_y);
#define FACTOR 2
if (abs_x > abs_y * FACTOR)
direction_from_offset (offset_x, offset_y,
GTK_PAN_ORIENTATION_HORIZONTAL, direction);
else if (abs_y > abs_x * FACTOR)
direction_from_offset (offset_x, offset_y,
GTK_PAN_ORIENTATION_VERTICAL, direction);
else
return FALSE;
return TRUE;
#undef FACTOR
}
static gboolean
check_orientation_matches (GtkGesturePan *gesture,
GtkPanDirection direction)
{
GtkGesturePanPrivate *priv = gtk_gesture_pan_get_instance_private (gesture);
return (((direction == GTK_PAN_DIRECTION_LEFT ||
direction == GTK_PAN_DIRECTION_RIGHT) &&
priv->orientation == GTK_PAN_ORIENTATION_HORIZONTAL) ||
((direction == GTK_PAN_DIRECTION_UP ||
direction == GTK_PAN_DIRECTION_DOWN) &&
priv->orientation == GTK_PAN_ORIENTATION_VERTICAL));
}
static void
gtk_gesture_pan_drag_update (GtkGestureDrag *gesture,
gdouble offset_x,
gdouble offset_y)
{
GtkGesturePanPrivate *priv;
GtkPanDirection direction;
GtkGesturePan *pan;
gdouble offset;
pan = GTK_GESTURE_PAN (gesture);
priv = gtk_gesture_pan_get_instance_private (pan);
if (!priv->panning)
{
if (!guess_direction (pan, offset_x, offset_y, &direction))
return;
if (!check_orientation_matches (pan, direction))
{
gtk_gesture_set_state (GTK_GESTURE (gesture),
GTK_EVENT_SEQUENCE_DENIED);
return;
}
priv->panning = TRUE;
}
else
direction_from_offset (offset_x, offset_y, priv->orientation, &direction);
offset = (priv->orientation == GTK_PAN_ORIENTATION_VERTICAL) ?
ABS (offset_y) : ABS (offset_x);
g_signal_emit (gesture, signals[PAN], 0, direction, offset);
}
static void
gtk_gesture_pan_drag_end (GtkGestureDrag *gesture,
gdouble offset_x,
gdouble offset_y)
{
GtkGesturePanPrivate *priv;
priv = gtk_gesture_pan_get_instance_private (GTK_GESTURE_PAN (gesture));
priv->panning = FALSE;
}
static void
gtk_gesture_pan_class_init (GtkGesturePanClass *klass)
{
GtkGestureDragClass *drag_gesture_class = GTK_GESTURE_DRAG_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gtk_gesture_pan_get_property;
object_class->set_property = gtk_gesture_pan_set_property;
drag_gesture_class->drag_update = gtk_gesture_pan_drag_update;
drag_gesture_class->drag_end = gtk_gesture_pan_drag_end;
/**
* GtkGesturePan:orientation:
*
* The expected orientation of pan gestures.
*
* Since: 3.14
*/
g_object_class_install_property (object_class,
PROP_ORIENTATION,
g_param_spec_enum ("orientation",
P_("Orientation"),
P_("Allowed orientations"),
GTK_TYPE_PAN_ORIENTATION,
GTK_PAN_ORIENTATION_HORIZONTAL,
GTK_PARAM_READWRITE));
/**
* GtkGesturePan::pan:
* @gesture: The object which received the signal
* @direction: current direction of the pan gesture
* @offset: Offset along the gesture orientation
*
* This signal is emitted once a panning gesture along the
* expected axis is detected.
*
* Since: 3.14
*/
signals[PAN] =
g_signal_new ("pan",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGesturePanClass, pan),
NULL, NULL, NULL,
G_TYPE_NONE, 2, GTK_TYPE_PAN_DIRECTION,
G_TYPE_DOUBLE);
}
static void
gtk_gesture_pan_init (GtkGesturePan *gesture)
{
GtkGesturePanPrivate *priv;
priv = gtk_gesture_pan_get_instance_private (gesture);
priv->orientation = GTK_PAN_ORIENTATION_HORIZONTAL;
}
/**
* gtk_gesture_pan_new:
* @widget: a #GtkWidget
* @orientation: expected orientation
*
* Returns a newly created #GtkGesture that recognizes pan gestures.
*
* Returns: a newly created #GtkGesturePan
*
* Since: 3.14
**/
GtkGesture *
gtk_gesture_pan_new (GtkWidget *widget,
GtkPanOrientation orientation)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
return g_object_new (GTK_TYPE_GESTURE_PAN,
"widget", widget,
"orientation", orientation,
NULL);
}
/**
* gtk_gesture_pan_get_orientation:
* @gesture: A #GtkGesturePan
*
* Returns the orientation of the pan gestures that this @gesture expects.
*
* Return value: the expected orientation for pan gestures
*
* Since: 3.14
*/
GtkPanOrientation
gtk_gesture_pan_get_orientation (GtkGesturePan *gesture)
{
GtkGesturePanPrivate *priv;
g_return_val_if_fail (GTK_IS_GESTURE_PAN (gesture), 0);
priv = gtk_gesture_pan_get_instance_private (gesture);
return priv->orientation;
}
/**
* gtk_gesture_pan_set_orientation:
* @gesture: A #GtkGesturePan
* @orientation: expected orientation
*
* Sets the orientation to be expected on pan gestures.
*
* Since: 3.14
*/
void
gtk_gesture_pan_set_orientation (GtkGesturePan *gesture,
GtkPanOrientation orientation)
{
GtkGesturePanPrivate *priv;
g_return_if_fail (GTK_IS_GESTURE_PAN (gesture));
g_return_if_fail (orientation == GTK_PAN_ORIENTATION_HORIZONTAL ||
orientation == GTK_PAN_ORIENTATION_VERTICAL);
priv = gtk_gesture_pan_get_instance_private (gesture);
if (priv->orientation == orientation)
return;
priv->orientation = orientation;
g_object_notify (G_OBJECT (gesture), "orientation");
}

58
gtk/gtkgesturepan.h Normal file
View File

@ -0,0 +1,58 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_PAN_H__
#define __GTK_GESTURE_PAN_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkenums.h>
#include <gtk/gtkgesturedrag.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_PAN (gtk_gesture_pan_get_type ())
#define GTK_GESTURE_PAN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_PAN, GtkGesturePan))
#define GTK_GESTURE_PAN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_PAN, GtkGesturePanClass))
#define GTK_IS_GESTURE_PAN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_PAN))
#define GTK_IS_GESTURE_PAN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_PAN))
#define GTK_GESTURE_PAN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_PAN, GtkGesturePanClass))
typedef struct _GtkGesturePan GtkGesturePan;
typedef struct _GtkGesturePanClass GtkGesturePanClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_pan_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GtkGesture * gtk_gesture_pan_new (GtkWidget *widget,
GtkPanOrientation orientation);
GDK_AVAILABLE_IN_3_14
GtkPanOrientation gtk_gesture_pan_get_orientation (GtkGesturePan *gesture);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_pan_set_orientation (GtkGesturePan *gesture,
GtkPanOrientation orientation);
G_END_DECLS
#endif /* __GTK_GESTURE_PAN_H__ */

View File

@ -0,0 +1,42 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_PAN_PRIVATE_H__
#define __GTK_GESTURE_PAN_PRIVATE_H__
#include "gtkgesturedragprivate.h"
#include "gtkgesturepan.h"
struct _GtkGesturePan
{
GtkGestureDrag parent_instance;
};
struct _GtkGesturePanClass
{
GtkGestureDragClass parent_class;
void (* pan) (GtkGesturePan *gesture,
GtkPanDirection direction,
gdouble offset);
/*< private >*/
gpointer padding[10];
};
#endif /* __GTK_GESTURE_PAN_PRIVATE_H__ */

75
gtk/gtkgestureprivate.h Normal file
View File

@ -0,0 +1,75 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_PRIVATE_H__
#define __GTK_GESTURE_PRIVATE_H__
#include "gtkeventcontrollerprivate.h"
#include "gtkgesture.h"
struct _GtkGesture
{
GtkEventController parent_instance;
};
struct _GtkGestureClass
{
GtkEventControllerClass parent_class;
gboolean (* check) (GtkGesture *gesture);
void (* begin) (GtkGesture *gesture,
GdkEventSequence *sequence);
void (* update) (GtkGesture *gesture,
GdkEventSequence *sequence);
void (* end) (GtkGesture *gesture,
GdkEventSequence *sequence);
void (* cancel) (GtkGesture *gesture,
GdkEventSequence *sequence);
void (* sequence_state_changed) (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkEventSequenceState state);
/*< private >*/
gpointer padding[10];
};
G_BEGIN_DECLS
gboolean _gtk_gesture_check (GtkGesture *gesture);
gboolean _gtk_gesture_handled_sequence_press (GtkGesture *gesture,
GdkEventSequence *sequence);
gboolean _gtk_gesture_get_pointer_emulating_sequence
(GtkGesture *gesture,
GdkEventSequence **sequence);
gboolean _gtk_gesture_cancel_sequence (GtkGesture *gesture,
GdkEventSequence *sequence);
gboolean _gtk_gesture_get_last_update_time (GtkGesture *gesture,
GdkEventSequence *sequence,
guint32 *evtime);
G_END_DECLS
#endif /* __GTK_GESTURE_PRIVATE_H__ */

227
gtk/gtkgesturerotate.c Normal file
View File

@ -0,0 +1,227 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkgesturerotate
* @Short_description: Rotate gesture
* @Title: GtkGestureRotate
* @See_also: #GtkGestureZoom
*
* #GtkGestureRotate is a #GtkGesture implementation able to recognize
* 2-finger rotations, whenever the angle between both handled sequences
* changes, the #GtkGestureRotate::angle-changed signal is emitted.
*/
#include "config.h"
#include <math.h>
#include "gtkgesturerotate.h"
#include "gtkgesturerotateprivate.h"
#include "gtkmarshalers.h"
typedef struct _GtkGestureRotatePrivate GtkGestureRotatePrivate;
enum {
ANGLE_CHANGED,
LAST_SIGNAL
};
struct _GtkGestureRotatePrivate
{
gdouble initial_angle;
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureRotate, gtk_gesture_rotate, GTK_TYPE_GESTURE)
static void
gtk_gesture_rotate_init (GtkGestureRotate *gesture)
{
}
static GObject *
gtk_gesture_rotate_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *object;
object = G_OBJECT_CLASS (gtk_gesture_rotate_parent_class)->constructor (type,
n_construct_properties,
construct_properties);
g_object_set (object, "n-points", 2, NULL);
return object;
}
static gboolean
_gtk_gesture_rotate_get_angle (GtkGestureRotate *rotate,
gdouble *angle)
{
gdouble x1, y1, x2, y2;
GtkGesture *gesture;
gdouble dx, dy;
GList *sequences;
gesture = GTK_GESTURE (rotate);
if (!gtk_gesture_is_recognized (gesture))
return FALSE;
sequences = gtk_gesture_get_sequences (gesture);
g_assert (sequences && sequences->next);
gtk_gesture_get_point (gesture, sequences->data, &x1, &y1);
gtk_gesture_get_point (gesture, sequences->next->data, &x2, &y2);
g_list_free (sequences);
dx = x1 - x2;
dy = y1 - y2;
*angle = atan2 (dx, dy);
/* Invert angle */
*angle = (2 * G_PI) - *angle;
/* And constraint it to 0°-360° */
*angle = fmod (*angle, 2 * G_PI);
return TRUE;
}
static gboolean
_gtk_gesture_rotate_check_emit (GtkGestureRotate *gesture)
{
GtkGestureRotatePrivate *priv;
gdouble angle, delta;
if (!_gtk_gesture_rotate_get_angle (gesture, &angle))
return FALSE;
priv = gtk_gesture_rotate_get_instance_private (gesture);
delta = angle - priv->initial_angle;
if (delta < 0)
delta += 2 * G_PI;
g_signal_emit (gesture, signals[ANGLE_CHANGED], 0, angle, delta);
return TRUE;
}
static void
gtk_gesture_rotate_begin (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureRotate *rotate = GTK_GESTURE_ROTATE (gesture);
GtkGestureRotatePrivate *priv;
priv = gtk_gesture_rotate_get_instance_private (rotate);
_gtk_gesture_rotate_get_angle (rotate, &priv->initial_angle);
}
static void
gtk_gesture_rotate_update (GtkGesture *gesture,
GdkEventSequence *sequence)
{
_gtk_gesture_rotate_check_emit (GTK_GESTURE_ROTATE (gesture));
}
static void
gtk_gesture_rotate_class_init (GtkGestureRotateClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass);
object_class->constructor = gtk_gesture_rotate_constructor;
gesture_class->begin = gtk_gesture_rotate_begin;
gesture_class->update = gtk_gesture_rotate_update;
/**
* GtkGestureRotate::angle-changed:
* @gesture: the object on which the signal is emitted
* @angle: Current angle in radians
* @angle_delta: Difference with the starting angle, in radians
*
* This signal is emitted when the angle between both tracked points
* changes.
*
* Since: 3.14
*/
signals[ANGLE_CHANGED] =
g_signal_new ("angle-changed",
GTK_TYPE_GESTURE_ROTATE,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkGestureRotateClass, angle_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
}
/**
* gtk_gesture_rotate_new:
* @widget: a #GtkWidget
*
* Returns a newly created #GtkGesture that recognizes 2-touch
* rotation gestures.
*
* Returns: a newly created #GtkGestureRotate
*
* Since: 3.14
**/
GtkGesture *
gtk_gesture_rotate_new (GtkWidget *widget)
{
return g_object_new (GTK_TYPE_GESTURE_ROTATE,
"widget", widget,
NULL);
}
/**
* gtk_gesture_rotate_get_angle_delta:
* @gesture: a #GtkGestureRotate
* @delta: (out) (transfer none): angle delta
*
* If @gesture is active, this function returns %TRUE and fills
* in @delta with the angle difference in radians since the
* gesture was first recognized.
*
* Returns: %TRUE if @controller is recognizing a rotate gesture
*
* Since: 3.14
**/
gboolean
gtk_gesture_rotate_get_angle_delta (GtkGestureRotate *gesture,
gdouble *delta)
{
GtkGestureRotatePrivate *priv;
gdouble angle;
g_return_val_if_fail (GTK_IS_GESTURE_ROTATE (gesture), FALSE);
if (!_gtk_gesture_rotate_get_angle (gesture, &angle))
return FALSE;
priv = gtk_gesture_rotate_get_instance_private (gesture);
if (delta)
*delta = angle - priv->initial_angle;
return TRUE;
}

54
gtk/gtkgesturerotate.h Normal file
View File

@ -0,0 +1,54 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_ROTATE_H__
#define __GTK_GESTURE_ROTATE_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkwidget.h>
#include <gtk/gtkgesture.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_ROTATE (gtk_gesture_rotate_get_type ())
#define GTK_GESTURE_ROTATE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_ROTATE, GtkGestureRotate))
#define GTK_GESTURE_ROTATE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_ROTATE, GtkGestureRotateClass))
#define GTK_IS_GESTURE_ROTATE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_ROTATE))
#define GTK_IS_GESTURE_ROTATE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_ROTATE))
#define GTK_GESTURE_ROTATE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_ROTATE, GtkGestureRotateClass))
typedef struct _GtkGestureRotate GtkGestureRotate;
typedef struct _GtkGestureRotateClass GtkGestureRotateClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_rotate_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GtkGesture * gtk_gesture_rotate_new (GtkWidget *widget);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_rotate_get_angle_delta (GtkGestureRotate *gesture,
gdouble *delta);
G_END_DECLS
#endif /* __GTK_GESTURE_ROTATE_H__ */

View File

@ -0,0 +1,42 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_ROTATE_PRIVATE_H__
#define __GTK_GESTURE_ROTATE_PRIVATE_H__
#include "gtkgestureprivate.h"
#include "gtkgesturerotate.h"
struct _GtkGestureRotate
{
GtkGesture parent_instance;
};
struct _GtkGestureRotateClass
{
GtkGestureClass parent_class;
void (* angle_changed) (GtkGestureRotate *gesture,
gdouble angle,
gdouble delta);
/*< private >*/
gpointer padding[10];
};
#endif /* __GTK_GESTURE_ROTATE_PRIVATE_H__ */

504
gtk/gtkgesturesingle.c Normal file
View File

@ -0,0 +1,504 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkgesturesingle
* @Short_description: Base class for for mouse/single-touch gestures
* @Title: GtkGestureSingle
*
* #GtkGestureSingle is a subclass of #GtkGesture, optimized (although
* not restricted) for dealing with mouse and single-touch gestures. Under
* interaction, these gestures stick to the first interacting sequence, which
* is accessible through gtk_gesture_single_get_current_sequence() while the
* gesture is being interacted with.
*
* By default gestures only react to touch events, gtk_gesture_single_set_touch_only()
* can be used to change this default behavior. Callers may also specify
* a mouse button number to interact with through gtk_gesture_single_set_button().
*/
#include "config.h"
#include "gtkgesturesingle.h"
#include "gtkgesturesingleprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
typedef struct _GtkGestureSinglePrivate GtkGestureSinglePrivate;
struct _GtkGestureSinglePrivate
{
GdkEventSequence *current_sequence;
guint button;
guint current_button;
guint touch_only : 1;
guint exclusive : 1;
};
enum {
PROP_TOUCH_ONLY = 1,
PROP_EXCLUSIVE,
PROP_BUTTON
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureSingle, gtk_gesture_single,
GTK_TYPE_GESTURE)
static void
gtk_gesture_single_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkGestureSinglePrivate *priv;
priv = gtk_gesture_single_get_instance_private (GTK_GESTURE_SINGLE (object));
switch (prop_id)
{
case PROP_TOUCH_ONLY:
g_value_set_boolean (value, priv->touch_only);
break;
case PROP_EXCLUSIVE:
g_value_set_boolean (value, priv->exclusive);
break;
case PROP_BUTTON:
g_value_set_uint (value, priv->button);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_gesture_single_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_TOUCH_ONLY:
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (object),
g_value_get_boolean (value));
break;
case PROP_EXCLUSIVE:
gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (object),
g_value_get_boolean (value));
break;
case PROP_BUTTON:
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (object),
g_value_get_uint (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_gesture_single_reset (GtkEventController *controller)
{
GtkGestureSinglePrivate *priv;
priv = gtk_gesture_single_get_instance_private (GTK_GESTURE_SINGLE (controller));
priv->current_button = 0;
GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_single_parent_class)->reset (controller);
}
static gboolean
gtk_gesture_single_handle_event (GtkEventController *controller,
const GdkEvent *event)
{
GdkEventSequence *sequence = NULL;
GtkGestureSinglePrivate *priv;
GdkDevice *source_device;
GdkInputSource source;
guint button = 0, i;
source_device = gdk_event_get_source_device (event);
if (!source_device)
return FALSE;
priv = gtk_gesture_single_get_instance_private (GTK_GESTURE_SINGLE (controller));
source = gdk_device_get_source (source_device);
switch (event->type)
{
case GDK_TOUCH_BEGIN:
case GDK_TOUCH_END:
case GDK_TOUCH_UPDATE:
if (priv->exclusive && !event->touch.emulating_pointer)
return FALSE;
sequence = event->touch.sequence;
button = 1;
break;
case GDK_BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
if (priv->touch_only && source != GDK_SOURCE_TOUCHSCREEN)
return FALSE;
button = event->button.button;
break;
case GDK_MOTION_NOTIFY:
if (priv->touch_only && source != GDK_SOURCE_TOUCHSCREEN)
return FALSE;
if (priv->current_button > 0 && priv->current_button <= 5 &&
(event->motion.state & (GDK_BUTTON1_MASK << (priv->current_button - 1))))
button = priv->current_button;
else if (priv->current_button == 0)
{
/* No current button, find out from the mask */
for (i = 0; i < 3; i++)
{
if ((event->motion.state & (GDK_BUTTON1_MASK << i)) == 0)
continue;
button = i + 1;
break;
}
}
break;
case GDK_TOUCH_CANCEL:
case GDK_GRAB_BROKEN:
return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_single_parent_class)->handle_event (controller,
event);
break;
default:
return FALSE;
}
if (button == 0 ||
(priv->button != 0 && priv->button != button) ||
(priv->current_button != 0 && priv->current_button != button))
{
if (gtk_gesture_is_active (GTK_GESTURE (controller)))
gtk_event_controller_reset (controller);
return FALSE;
}
if (event->type == GDK_BUTTON_PRESS || event->type == GDK_TOUCH_BEGIN ||
event->type == GDK_MOTION_NOTIFY || event->type == GDK_TOUCH_UPDATE)
{
if (!gtk_gesture_is_active (GTK_GESTURE (controller)))
priv->current_sequence = sequence;
priv->current_button = button;
}
else if (sequence == priv->current_sequence &&
(event->type == GDK_BUTTON_RELEASE || event->type == GDK_TOUCH_END))
priv->current_button = 0;
return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_single_parent_class)->handle_event (controller, event);
}
static void
gtk_gesture_single_class_init (GtkGestureSingleClass *klass)
{
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gtk_gesture_single_get_property;
object_class->set_property = gtk_gesture_single_set_property;
controller_class->reset = gtk_gesture_single_reset;
controller_class->handle_event = gtk_gesture_single_handle_event;
/**
* GtkGestureSingle:touch-only:
*
* Whether the gesture handles only touch events.
*
* Since: 3.14
*/
g_object_class_install_property (object_class,
PROP_TOUCH_ONLY,
g_param_spec_boolean ("touch-only",
P_("Handle only touch events"),
P_("Whether the gesture handles"
" only touch events"),
TRUE,
GTK_PARAM_READWRITE));
/**
* GtkGestureSingle:exclusive:
*
* Whether the gesture is exclusive. Exclusive gestures only listen to pointer
* and pointer emulated events.
*
* Since: 3.14
*/
g_object_class_install_property (object_class,
PROP_EXCLUSIVE,
g_param_spec_boolean ("exclusive",
P_("Whether the gesture is exclusive"),
P_("Whether the gesture is exclusive"),
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkGestureSingle:button:
*
* Mouse button number to listen to, or 0 to listen for any button.
*
* Since: 3.14
*/
g_object_class_install_property (object_class,
PROP_BUTTON,
g_param_spec_uint ("button",
P_("Button number"),
P_("Button number to listen to"),
0, G_MAXUINT, 0,
GTK_PARAM_READWRITE));
}
static void
_gtk_gesture_single_update_evmask (GtkGestureSingle *gesture)
{
GtkGestureSinglePrivate *priv;
GdkEventMask evmask;
priv = gtk_gesture_single_get_instance_private (gesture);
evmask = GDK_TOUCH_MASK;
if (!priv->touch_only)
evmask |= GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_MOTION_MASK;
gtk_event_controller_set_event_mask (GTK_EVENT_CONTROLLER (gesture), evmask);
}
static void
gtk_gesture_single_init (GtkGestureSingle *gesture)
{
GtkGestureSinglePrivate *priv;
priv = gtk_gesture_single_get_instance_private (gesture);
if (g_getenv ("GTK_TEST_TOUCHSCREEN"))
priv->touch_only = FALSE;
else
priv->touch_only = TRUE;
_gtk_gesture_single_update_evmask (gesture);
}
/**
* gtk_gesture_single_get_touch_only:
* @gesture: a #GtkGestureSingle
*
* Returns %TRUE if the gesture is only triggered by touch events.
*
* Returns: %TRUE if the gesture only handles touch events
*
* Since: 3.14
**/
gboolean
gtk_gesture_single_get_touch_only (GtkGestureSingle *gesture)
{
GtkGestureSinglePrivate *priv;
g_return_val_if_fail (GTK_IS_GESTURE_SINGLE (gesture), FALSE);
priv = gtk_gesture_single_get_instance_private (gesture);
return priv->touch_only;
}
/**
* gtk_gesture_single_set_touch_only:
* @gesture: a #GtkGestureSingle
* @touch_only: whether @gesture handles only touch events
*
* If @touch_only is %TRUE, @gesture will only handle events of type
* #GDK_TOUCH_BEGIN, #GDK_TOUCH_UPDATE or #GDK_TOUCH_END. If %FALSE,
* mouse events will be handled too.
*
* Since: 3.14
**/
void
gtk_gesture_single_set_touch_only (GtkGestureSingle *gesture,
gboolean touch_only)
{
GtkGestureSinglePrivate *priv;
g_return_if_fail (GTK_IS_GESTURE_SINGLE (gesture));
touch_only = touch_only != FALSE;
priv = gtk_gesture_single_get_instance_private (gesture);
if (priv->touch_only == touch_only)
return;
priv->touch_only = touch_only;
_gtk_gesture_single_update_evmask (gesture);
g_object_notify (G_OBJECT (gesture), "touch-only");
}
/**
* gtk_gesture_single_get_exclusive:
* @gesture: a #GtkGestureSingle
*
* Gets whether a gesture is exclusive. For more information, see
* gtk_gesture_single_set_exclusive().
*
* Returns: Whether the gesture is exclusive
*
* Since: 3.14
**/
gboolean
gtk_gesture_single_get_exclusive (GtkGestureSingle *gesture)
{
GtkGestureSinglePrivate *priv;
g_return_val_if_fail (GTK_IS_GESTURE_SINGLE (gesture), FALSE);
priv = gtk_gesture_single_get_instance_private (gesture);
return priv->exclusive;
}
/**
* gtk_gesture_single_set_exclusive:
* @gesture: a #GtkGestureSingle
* @exclusive: %TRUE to make @gesture exclusive
*
* Sets whether @gesture is exclusive. An exclusive gesture will
* only handle pointer and "pointer emulated" touch events, so at
* any given time, there is only one sequence able to interact with
* those.
*
* Since: 3.14
**/
void
gtk_gesture_single_set_exclusive (GtkGestureSingle *gesture,
gboolean exclusive)
{
GtkGestureSinglePrivate *priv;
g_return_if_fail (GTK_IS_GESTURE_SINGLE (gesture));
exclusive = exclusive != FALSE;
priv = gtk_gesture_single_get_instance_private (gesture);
if (priv->exclusive == exclusive)
return;
priv->exclusive = exclusive;
_gtk_gesture_single_update_evmask (gesture);
g_object_notify (G_OBJECT (gesture), "exclusive");
}
/**
* gtk_gesture_single_get_button:
* @gesture: a #GtkGestureSingle
*
* Returns the button number @gesture listens for, or 0 if @gesture
* reacts to any button press.
*
* Returns: The button number, or 0 for any button
*
* Since: 3.14
**/
guint
gtk_gesture_single_get_button (GtkGestureSingle *gesture)
{
GtkGestureSinglePrivate *priv;
g_return_val_if_fail (GTK_IS_GESTURE_SINGLE (gesture), 0);
priv = gtk_gesture_single_get_instance_private (gesture);
return priv->button;
}
/**
* gtk_gesture_single_set_button:
* @gesture: a #GtkGestureSingle
* @button: button number to listen to, or 0 for any button
*
* Sets the button number @gesture listens to. If non-0, every
* button press from a different button number will be ignored.
* Touch events implicitly match with button 1.
*
* Since: 3.14
**/
void
gtk_gesture_single_set_button (GtkGestureSingle *gesture,
guint button)
{
GtkGestureSinglePrivate *priv;
g_return_if_fail (GTK_IS_GESTURE_SINGLE (gesture));
priv = gtk_gesture_single_get_instance_private (gesture);
if (priv->button == button)
return;
priv->button = button;
g_object_notify (G_OBJECT (gesture), "button");
}
/**
* gtk_gesture_single_get_current_button:
* @gesture: a #GtkGestureSingle
*
* Returns the button number currently interacting with @gesture, or 0 if there
* is none.
*
* Returns: The current button number
*
* Since: 3.14
**/
guint
gtk_gesture_single_get_current_button (GtkGestureSingle *gesture)
{
GtkGestureSinglePrivate *priv;
g_return_val_if_fail (GTK_IS_GESTURE_SINGLE (gesture), 0);
priv = gtk_gesture_single_get_instance_private (gesture);
return priv->current_button;
}
/**
* gtk_gesture_single_get_current_sequence:
* @gesture: a #GtkGestureSingle
*
* Returns the event sequence currently interacting with @gesture.
* This is only meaningful if gtk_gesture_is_active() returns %TRUE.
*
* Returns: the current sequence
*
* Since: 3.14
**/
GdkEventSequence *
gtk_gesture_single_get_current_sequence (GtkGestureSingle *gesture)
{
GtkGestureSinglePrivate *priv;
g_return_val_if_fail (GTK_IS_GESTURE_SINGLE (gesture), NULL);
priv = gtk_gesture_single_get_instance_private (gesture);
return priv->current_sequence;
}

75
gtk/gtkgesturesingle.h Normal file
View File

@ -0,0 +1,75 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_SINGLE_H__
#define __GTK_GESTURE_SINGLE_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkgesture.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_SINGLE (gtk_gesture_single_get_type ())
#define GTK_GESTURE_SINGLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_SINGLE, GtkGestureSingle))
#define GTK_GESTURE_SINGLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_SINGLE, GtkGestureSingleClass))
#define GTK_IS_GESTURE_SINGLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_SINGLE))
#define GTK_IS_GESTURE_SINGLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_SINGLE))
#define GTK_GESTURE_SINGLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_SINGLE, GtkGestureSingleClass))
typedef struct _GtkGestureSingle GtkGestureSingle;
typedef struct _GtkGestureSingleClass GtkGestureSingleClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_single_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_single_get_touch_only (GtkGestureSingle *gesture);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_single_set_touch_only (GtkGestureSingle *gesture,
gboolean touch_only);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_single_get_exclusive (GtkGestureSingle *gesture);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_single_set_exclusive (GtkGestureSingle *gesture,
gboolean exclusive);
GDK_AVAILABLE_IN_3_14
guint gtk_gesture_single_get_button (GtkGestureSingle *gesture);
GDK_AVAILABLE_IN_3_14
void gtk_gesture_single_set_button (GtkGestureSingle *gesture,
guint button);
GDK_AVAILABLE_IN_3_14
guint gtk_gesture_single_get_current_button
(GtkGestureSingle *gesture);
GDK_AVAILABLE_IN_3_14
GdkEventSequence * gtk_gesture_single_get_current_sequence
(GtkGestureSingle *gesture);
G_END_DECLS
#endif /* __GTK_GESTURE_SINGLE_H__ */

View File

@ -0,0 +1,40 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_SINGLE_PRIVATE_H__
#define __GTK_GESTURE_SINGLE_PRIVATE_H__
#include "gtkgestureprivate.h"
#include "gtkgesturesingle.h"
struct _GtkGestureSingle
{
GtkGesture parent_instance;
};
struct _GtkGestureSingleClass
{
GtkGestureClass parent_class;
/*< private >*/
gpointer padding[10];
};
#endif /* __GTK_GESTURE_SINGLE_PRIVATE_H__ */

279
gtk/gtkgestureswipe.c Normal file
View File

@ -0,0 +1,279 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkgestureswipe
* @Short_description: Swipe gesture
* @Title: GtkGestureSwipe
*
* #GtkGestureSwipe is a #GtkGesture implementation able to recognize
* swipes, after a press/move/.../move/release sequence happens, the
* #GtkGestureSwipe::swipe signal will be emitted, providing the velocity
* and directionality of the sequence at the time it was lifted.
*
* If the velocity is desired in intermediate points,
* gtk_gesture_swipe_get_velocity() can be called on eg. a
* #GtkGesture::update handler.
*
* All velocities are reported in pixels/sec units.
*/
#include "config.h"
#include "gtkgestureswipe.h"
#include "gtkgestureswipeprivate.h"
#include "gtkgestureprivate.h"
#include "gtkmarshalers.h"
#define CAPTURE_THRESHOLD_MS 150
typedef struct _GtkGestureSwipePrivate GtkGestureSwipePrivate;
typedef struct _EventData EventData;
struct _EventData
{
guint32 evtime;
GdkPoint point;
};
struct _GtkGestureSwipePrivate
{
GArray *events;
};
enum {
SWIPE,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureSwipe, gtk_gesture_swipe, GTK_TYPE_GESTURE_SINGLE)
static void
gtk_gesture_swipe_finalize (GObject *object)
{
GtkGestureSwipePrivate *priv;
priv = gtk_gesture_swipe_get_instance_private (GTK_GESTURE_SWIPE (object));
g_array_free (priv->events, TRUE);
G_OBJECT_CLASS (gtk_gesture_swipe_parent_class)->finalize (object);
}
static void
_gtk_gesture_swipe_clear_backlog (GtkGestureSwipe *gesture,
guint32 evtime)
{
GtkGestureSwipePrivate *priv;
gint i, length = 0;
priv = gtk_gesture_swipe_get_instance_private (gesture);
for (i = 0; i < (gint) priv->events->len; i++)
{
EventData *data;
data = &g_array_index (priv->events, EventData, i);
if (data->evtime >= evtime - CAPTURE_THRESHOLD_MS)
{
length = i - 1;
break;
}
}
if (length > 0)
g_array_remove_range (priv->events, 0, length);
}
static void
gtk_gesture_swipe_update (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureSwipe *swipe = GTK_GESTURE_SWIPE (gesture);
GtkGestureSwipePrivate *priv;
EventData new;
gdouble x, y;
priv = gtk_gesture_swipe_get_instance_private (swipe);
_gtk_gesture_get_last_update_time (gesture, sequence, &new.evtime);
gtk_gesture_get_point (gesture, sequence, &x, &y);
new.point.x = x;
new.point.y = y;
_gtk_gesture_swipe_clear_backlog (swipe, new.evtime);
g_array_append_val (priv->events, new);
}
static void
_gtk_gesture_swipe_calculate_velocity (GtkGestureSwipe *gesture,
gdouble *velocity_x,
gdouble *velocity_y)
{
GtkGestureSwipePrivate *priv;
GdkEventSequence *sequence;
guint32 evtime, diff_time;
EventData *start, *end;
gdouble diff_x, diff_y;
priv = gtk_gesture_swipe_get_instance_private (gesture);
*velocity_x = *velocity_y = 0;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
_gtk_gesture_get_last_update_time (GTK_GESTURE (gesture), sequence, &evtime);
_gtk_gesture_swipe_clear_backlog (gesture, evtime);
if (priv->events->len == 0)
return;
start = &g_array_index (priv->events, EventData, 0);
end = &g_array_index (priv->events, EventData, priv->events->len - 1);
diff_time = end->evtime - start->evtime;
diff_x = end->point.x - start->point.x;
diff_y = end->point.y - start->point.y;
if (diff_time == 0)
return;
/* Velocity in pixels/sec */
*velocity_x = diff_x * 1000 / diff_time;
*velocity_y = diff_y * 1000 / diff_time;
}
static void
gtk_gesture_swipe_end (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureSwipe *swipe = GTK_GESTURE_SWIPE (gesture);
GtkGestureSwipePrivate *priv;
gdouble velocity_x, velocity_y;
GdkEventSequence *seq;
seq = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (gtk_gesture_get_sequence_state (gesture, seq) == GTK_EVENT_SEQUENCE_DENIED)
return;
if (gtk_gesture_is_active (gesture))
return;
priv = gtk_gesture_swipe_get_instance_private (swipe);
_gtk_gesture_swipe_calculate_velocity (swipe, &velocity_x, &velocity_y);
g_signal_emit (gesture, signals[SWIPE], 0, velocity_x, velocity_y);
if (priv->events->len > 0)
g_array_remove_range (priv->events, 0, priv->events->len);
}
static void
gtk_gesture_swipe_class_init (GtkGestureSwipeClass *klass)
{
GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_gesture_swipe_finalize;
gesture_class->update = gtk_gesture_swipe_update;
gesture_class->end = gtk_gesture_swipe_end;
/**
* GtkGestureSwipe::swipe:
* @gesture: object which received the signal
* @velocity_x: velocity in the X axis, in pixels/sec
* @velocity_y: velocity in the Y axis, in pixels/sec
*
* This signal is emitted when the recognized gesture is finished, velocity
* and direction are a product of previously recorded events.
*
* Since: 3.14
*/
signals[SWIPE] =
g_signal_new ("swipe",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkGestureSwipeClass, swipe),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
}
static void
gtk_gesture_swipe_init (GtkGestureSwipe *gesture)
{
GtkGestureSwipePrivate *priv;
priv = gtk_gesture_swipe_get_instance_private (gesture);
priv->events = g_array_new (FALSE, FALSE, sizeof (EventData));
}
/**
* gtk_gesture_swipe_new:
* @widget: a #GtkWidget
*
* Returns a newly created #GtkGesture that recognizes swipes.
*
* Returns: a newly created #GtkGestureSwipe
*
* Since: 3.14
**/
GtkGesture *
gtk_gesture_swipe_new (GtkWidget *widget)
{
return g_object_new (GTK_TYPE_GESTURE_SWIPE,
"widget", widget,
NULL);
}
/**
* gtk_gesture_swipe_get_velocity:
* @gesture: a #GtkGestureSwipe
* @velocity_x: (out): return value for the velocity in the X axis, in pixels/sec
* @velocity_y: (out): return value for the velocity in the Y axis, in pixels/sec
*
* If the gesture is recognized, this function returns %TRUE and fill in
* @velocity_x and @velocity_y with the recorded velocity, as per the
* last event(s) processed.
*
* Returns: whether velocity could be calculated
*
* Since: 3.14
**/
gboolean
gtk_gesture_swipe_get_velocity (GtkGestureSwipe *gesture,
gdouble *velocity_x,
gdouble *velocity_y)
{
gdouble vel_x, vel_y;
g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
if (!gtk_gesture_is_recognized (GTK_GESTURE (gesture)))
return FALSE;
_gtk_gesture_swipe_calculate_velocity (gesture, &vel_x, &vel_y);
if (velocity_x)
*velocity_x = vel_x;
if (velocity_y)
*velocity_y = vel_y;
return TRUE;
}

55
gtk/gtkgestureswipe.h Normal file
View File

@ -0,0 +1,55 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_SWIPE_H__
#define __GTK_GESTURE_SWIPE_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkwidget.h>
#include <gtk/gtkgesturesingle.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_SWIPE (gtk_gesture_swipe_get_type ())
#define GTK_GESTURE_SWIPE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_SWIPE, GtkGestureSwipe))
#define GTK_GESTURE_SWIPE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_SWIPE, GtkGestureSwipeClass))
#define GTK_IS_GESTURE_SWIPE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_SWIPE))
#define GTK_IS_GESTURE_SWIPE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_SWIPE))
#define GTK_GESTURE_SWIPE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_SWIPE, GtkGestureSwipeClass))
typedef struct _GtkGestureSwipe GtkGestureSwipe;
typedef struct _GtkGestureSwipeClass GtkGestureSwipeClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_swipe_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GtkGesture * gtk_gesture_swipe_new (GtkWidget *widget);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_swipe_get_velocity (GtkGestureSwipe *gesture,
gdouble *velocity_x,
gdouble *velocity_y);
G_END_DECLS
#endif /* __GTK_GESTURE_SWIPE_H__ */

View File

@ -0,0 +1,43 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_SWIPE_PRIVATE_H__
#define __GTK_GESTURE_SWIPE_PRIVATE_H__
#include "gtkgesturesingleprivate.h"
#include "gtkgestureswipe.h"
struct _GtkGestureSwipe
{
GtkGestureSingle parent_instance;
};
struct _GtkGestureSwipeClass
{
GtkGestureSingleClass parent_class;
void (* swipe) (GtkGestureSwipe *gesture,
gdouble velocity_x,
gdouble velocity_y);
/*< private >*/
gpointer padding[10];
};
#endif /* __GTK_GESTURE_SWIPE_PRIVATE_H__ */

220
gtk/gtkgesturezoom.c Normal file
View File

@ -0,0 +1,220 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:gtkgesturezoom
* @Short_description: Zoom gesture
* @Title: GtkGestureZoom
* @See_also: #GtkGestureRotate
*
* #GtkGestureZoom is a #GtkGesture implementation able to recognize
* pinch/zoom gestures, whenever the distance between both tracked
* sequences changes, the #GtkGestureZoom::scale-changed signal is
* emitted to report the scale factor.
*/
#include "config.h"
#include <math.h>
#include "gtkgesturezoom.h"
#include "gtkgesturezoomprivate.h"
typedef struct _GtkGestureZoomPrivate GtkGestureZoomPrivate;
enum {
SCALE_CHANGED,
LAST_SIGNAL
};
struct _GtkGestureZoomPrivate
{
gdouble initial_distance;
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureZoom, gtk_gesture_zoom, GTK_TYPE_GESTURE)
static void
gtk_gesture_zoom_init (GtkGestureZoom *gesture)
{
}
static GObject *
gtk_gesture_zoom_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *object;
object = G_OBJECT_CLASS (gtk_gesture_zoom_parent_class)->constructor (type,
n_construct_properties,
construct_properties);
g_object_set (object, "n-points", 2, NULL);
return object;
}
static gboolean
_gtk_gesture_zoom_get_distance (GtkGestureZoom *zoom,
gdouble *distance)
{
gdouble x1, y1, x2, y2;
GtkGesture *gesture;
GList *sequences;
gdouble dx, dy;
gesture = GTK_GESTURE (zoom);
if (!gtk_gesture_is_recognized (gesture))
return FALSE;
sequences = gtk_gesture_get_sequences (gesture);
g_assert (sequences && sequences->next);
gtk_gesture_get_point (gesture, sequences->data, &x1, &y1);
gtk_gesture_get_point (gesture, sequences->next->data, &x2, &y2);
g_list_free (sequences);
dx = x1 - x2;
dy = y1 - y2;;
*distance = sqrt ((dx * dx) + (dy * dy));
return TRUE;
}
static gboolean
_gtk_gesture_zoom_check_emit (GtkGestureZoom *gesture)
{
GtkGestureZoomPrivate *priv;
gdouble distance, zoom;
if (!_gtk_gesture_zoom_get_distance (gesture, &distance))
return FALSE;
priv = gtk_gesture_zoom_get_instance_private (gesture);
if (distance == 0 || priv->initial_distance == 0)
return FALSE;
zoom = distance / priv->initial_distance;
g_signal_emit (gesture, signals[SCALE_CHANGED], 0, zoom);
return TRUE;
}
static void
gtk_gesture_zoom_begin (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureZoom *zoom = GTK_GESTURE_ZOOM (gesture);
GtkGestureZoomPrivate *priv;
priv = gtk_gesture_zoom_get_instance_private (zoom);
_gtk_gesture_zoom_get_distance (zoom, &priv->initial_distance);
}
static void
gtk_gesture_zoom_update (GtkGesture *gesture,
GdkEventSequence *sequence)
{
_gtk_gesture_zoom_check_emit (GTK_GESTURE_ZOOM (gesture));
}
static void
gtk_gesture_zoom_class_init (GtkGestureZoomClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass);
object_class->constructor = gtk_gesture_zoom_constructor;
gesture_class->begin = gtk_gesture_zoom_begin;
gesture_class->update = gtk_gesture_zoom_update;
/**
* GtkGestureZoom::scale-changed:
* @controller: the object on which the signal is emitted
* @scale: Scale delta, taking the initial state as 1:1
*
* This signal is emitted whenever the distance between both tracked
* sequences changes.
*
* Since: 3.14
*/
signals[SCALE_CHANGED] =
g_signal_new ("scale-changed",
GTK_TYPE_GESTURE_ZOOM,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkGestureZoomClass, scale_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_DOUBLE);
}
/**
* gtk_gesture_zoom_new:
* @widget: a #GtkWidget
*
* Returns a newly created #GtkGesture that recognizes zoom
* in/out gestures (usually known as pinch/zoom).
*
* Returns: a newly created #GtkGestureZoom
*
* Since: 3.14
**/
GtkGesture *
gtk_gesture_zoom_new (GtkWidget *widget)
{
return g_object_new (GTK_TYPE_GESTURE_ZOOM,
"widget", widget,
NULL);
}
/**
* gtk_gesture_zoom_get_scale_delta:
* @gesture: a #GtkGestureZoom
* @scale: (out) (transfer none): zoom delta
*
* If @controller is active, this function returns %TRUE and fills
* in @scale with the zooming difference since the gesture was
* recognized (hence the starting point is considered 1:1).
*
* Returns: %TRUE if @controller is recognizing a zoom gesture
*
* Since: 3.14
**/
gboolean
gtk_gesture_zoom_get_scale_delta (GtkGestureZoom *gesture,
gdouble *scale)
{
GtkGestureZoomPrivate *priv;
gdouble distance;
g_return_val_if_fail (GTK_IS_GESTURE_ZOOM (gesture), FALSE);
if (!_gtk_gesture_zoom_get_distance (gesture, &distance))
return FALSE;
priv = gtk_gesture_zoom_get_instance_private (gesture);
if (scale)
*scale = distance / priv->initial_distance;
return TRUE;
}

54
gtk/gtkgesturezoom.h Normal file
View File

@ -0,0 +1,54 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_ZOOM_H__
#define __GTK_GESTURE_ZOOM_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkgesture.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_ZOOM (gtk_gesture_zoom_get_type ())
#define GTK_GESTURE_ZOOM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_ZOOM, GtkGestureZoom))
#define GTK_GESTURE_ZOOM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_ZOOM, GtkGestureZoomClass))
#define GTK_IS_GESTURE_ZOOM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_ZOOM))
#define GTK_IS_GESTURE_ZOOM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_ZOOM))
#define GTK_GESTURE_ZOOM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_ZOOM, GtkGestureZoomClass))
typedef struct _GtkGestureZoom GtkGestureZoom;
typedef struct _GtkGestureZoomClass GtkGestureZoomClass;
GDK_AVAILABLE_IN_3_14
GType gtk_gesture_zoom_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GtkGesture * gtk_gesture_zoom_new (GtkWidget *widget);
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_zoom_get_scale_delta (GtkGestureZoom *gesture,
gdouble *scale);
G_END_DECLS
#endif /* __GTK_GESTURE_ZOOM_H__ */

View File

@ -0,0 +1,41 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012, One Laptop Per Child.
* Copyright (C) 2014, 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/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_GESTURE_ZOOM_PRIVATE_H__
#define __GTK_GESTURE_ZOOM_PRIVATE_H__
#include "gtkgestureprivate.h"
#include "gtkgesturezoom.h"
struct _GtkGestureZoom
{
GtkGesture parent_instance;
};
struct _GtkGestureZoomClass
{
GtkGestureClass parent_class;
void (* scale_changed) (GtkGestureZoom *gesture,
gdouble scale);
/*< private >*/
gpointer padding[10];
};
#endif /* __GTK_GESTURE_ZOOM_PRIVATE_H__ */

View File

@ -2595,8 +2595,6 @@ gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
icon_view->priv->doing_rubberband = TRUE;
icon_view->priv->rubberband_device = device;
gtk_device_grab_add (GTK_WIDGET (icon_view), device, TRUE);
}
static void
@ -2605,9 +2603,6 @@ gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
if (!icon_view->priv->doing_rubberband)
return;
gtk_device_grab_remove (GTK_WIDGET (icon_view),
icon_view->priv->rubberband_device);
icon_view->priv->doing_rubberband = FALSE;
icon_view->priv->rubberband_device = NULL;

View File

@ -52,6 +52,7 @@ OBJECT:VOID
STRING:DOUBLE
STRING:STRING
VOID:DOUBLE
VOID:DOUBLE,DOUBLE
VOID:BOOLEAN
VOID:BOOLEAN,BOOLEAN,BOOLEAN
VOID:BOXED

View File

@ -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,111 @@ 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;
GdkDevice *device;
gboolean is_touch;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
device = gdk_event_get_source_device (event);
gtk_widget_get_allocation (GTK_WIDGET (paned), &allocation);
paned->priv->panning = FALSE;
is_touch = (event->type == GDK_TOUCH_BEGIN ||
gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN);
if (event->any.window == priv->handle ||
(is_touch && 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 +782,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 +792,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 +821,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 +971,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 +1742,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 +1757,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 +1789,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 +1809,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 +1840,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 +1863,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 paneds orientation.
@ -2848,4 +2834,4 @@ gtk_paned_get_handle_window (GtkPaned *paned)
g_return_val_if_fail (GTK_IS_PANED (paned), NULL);
return paned->priv->handle;
}
}

View File

@ -235,6 +235,8 @@ gtk_popover_dispose (GObject *object)
GtkPopover *popover = GTK_POPOVER (object);
GtkPopoverPrivate *priv = popover->priv;
gtk_widget_set_visible (GTK_WIDGET (object), FALSE);
if (priv->window)
_gtk_window_remove_popover (priv->window, GTK_WIDGET (object));
@ -249,7 +251,6 @@ gtk_popover_dispose (GObject *object)
priv->prev_focus_widget = NULL;
}
gtk_widget_set_visible (GTK_WIDGET (object), FALSE);
G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);
}

View File

@ -1,257 +0,0 @@
/* 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;
GdkDevice *device;
guint button;
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_WITH_PRIVATE (GtkPressAndHold, gtk_press_and_hold, G_TYPE_OBJECT)
static void
gtk_press_and_hold_init (GtkPressAndHold *pah)
{
pah->priv = gtk_press_and_hold_get_instance_private (pah);
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));
}
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;
priv->device = NULL;
priv->button = 0;
}
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 input, ignore */
if ((event->type == GDK_TOUCH_BEGIN && priv->sequence != NULL) ||
(event->type == GDK_BUTTON_PRESS && priv->device != NULL) ||
(event->type == GDK_TOUCH_UPDATE && priv->sequence != event->touch.sequence) ||
(event->type == GDK_TOUCH_END && priv->sequence != event->touch.sequence) ||
(event->type == GDK_TOUCH_CANCEL && priv->sequence != event->touch.sequence) ||
(event->type == GDK_BUTTON_RELEASE && priv->device != event->button.device) ||
(event->type == GDK_BUTTON_RELEASE && priv->button != event->button.button) ||
(event->type == GDK_MOTION_NOTIFY && priv->device != event->motion.device))
return;
if (event->type == GDK_TOUCH_BEGIN)
{
priv->sequence = event->touch.sequence;
priv->x = event->touch.x;
priv->y = event->touch.y;
priv->start_x = priv->x;
priv->start_y = priv->y;
priv->timeout =
gdk_threads_add_timeout (priv->hold_time, hold_action, pah);
g_source_set_name_by_id (priv->timeout, "[gtk+] hold_action");
}
else if (event->type == GDK_TOUCH_UPDATE)
{
priv->x = event->touch.x;
priv->y = event->touch.y;
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);
}
else if (event->type == GDK_BUTTON_PRESS)
{
priv->device = event->button.device;
priv->button = event->button.button;
priv->x = event->button.x;
priv->y = event->button.y;
priv->start_x = priv->x;
priv->start_y = priv->y;
priv->timeout =
gdk_threads_add_timeout (priv->hold_time, hold_action, pah);
g_source_set_name_by_id (priv->timeout, "[gtk+] hold_action");
}
else if (event->type == GDK_BUTTON_RELEASE)
{
press_and_hold_cancel (pah);
}
else if (event->type == GDK_MOTION_NOTIFY)
{
priv->x = event->motion.x;
priv->y = event->motion.y;
if (ABS (priv->x - priv->start_x) > priv->drag_threshold ||
ABS (priv->y - priv->start_y) > priv->drag_threshold)
press_and_hold_cancel (pah);
}
}
GtkPressAndHold *
gtk_press_and_hold_new (void)
{
return (GtkPressAndHold *) g_object_new (GTK_TYPE_PRESS_AND_HOLD, NULL);
}

View File

@ -1,63 +0,0 @@
/* 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/>.
*/
#ifndef __GTK_PRESS_AND_HOLD_H__
#define __GTK_PRESS_AND_HOLD_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
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);
};
GType gtk_press_and_hold_get_type (void) G_GNUC_CONST;
GtkPressAndHold * gtk_press_and_hold_new (void);
void gtk_press_and_hold_process_event (GtkPressAndHold *pah,
GdkEvent *event);
G_END_DECLS
#endif /* __GTK_PRESS_AND_HOLD_H__ */

View File

@ -37,7 +37,6 @@
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkorientableprivate.h"
#include "gtkpressandholdprivate.h"
#include "gtkprivate.h"
#include "gtkscale.h"
#include "gtkscrollbar.h"
@ -148,7 +147,7 @@ struct _GtkRangePrivate
/* Whether we're doing fine adjustment */
guint zoom : 1;
guint zoom_set : 1;
GtkPressAndHold *press_and_hold;
GtkGesture *long_press_gesture;
GtkScrollType autoscroll_mode;
guint autoscroll_id;
@ -1506,7 +1505,11 @@ gtk_range_destroy (GtkWidget *widget)
gtk_range_remove_step_timer (range);
g_clear_object (&priv->press_and_hold);
if (priv->long_press_gesture)
{
gtk_gesture_detach (priv->long_press_gesture);
g_clear_object (&priv->long_press_gesture);
}
if (priv->adjustment)
{
@ -2365,7 +2368,10 @@ update_zoom_set (GtkRange *range,
gboolean zoom_set)
{
if (zoom_set)
g_clear_object (&range->priv->press_and_hold);
{
gtk_gesture_detach (range->priv->long_press_gesture);
g_clear_object (&range->priv->long_press_gesture);
}
range->priv->zoom_set = zoom_set;
}
@ -2537,10 +2543,10 @@ gtk_range_key_press (GtkWidget *widget,
}
static void
hold_action (GtkPressAndHold *pah,
gint x,
gint y,
GtkRange *range)
hold_action (GtkGestureLongPress *gesture,
gdouble x,
gdouble y,
GtkRange *range)
{
update_zoom_state (range, TRUE);
update_zoom_set (range, TRUE);
@ -2698,25 +2704,21 @@ gtk_range_button_press (GtkWidget *widget,
}
else
{
if (!priv->press_and_hold)
if (!priv->long_press_gesture)
{
gint drag_threshold;
priv->long_press_gesture =
gtk_gesture_long_press_new (widget);
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->long_press_gesture),
FALSE);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->long_press_gesture), 1);
gtk_gesture_attach (priv->long_press_gesture, GTK_PHASE_NONE);
g_object_get (gtk_widget_get_settings (widget),
"gtk-dnd-drag-threshold", &drag_threshold,
NULL);
priv->press_and_hold = gtk_press_and_hold_new ();
g_object_set (priv->press_and_hold,
"drag-threshold", drag_threshold,
"hold-time", ZOOM_HOLD_TIME,
NULL);
g_signal_connect (priv->press_and_hold, "hold",
g_signal_connect (priv->long_press_gesture, "pressed",
G_CALLBACK (hold_action), range);
}
gtk_press_and_hold_process_event (priv->press_and_hold, (GdkEvent *)event);
gtk_event_controller_handle_event (GTK_EVENT_CONTROLLER (priv->long_press_gesture),
(const GdkEvent*) event);
}
}
@ -2929,8 +2931,9 @@ gtk_range_button_release (GtkWidget *widget,
{
if (priv->grab_location == MOUSE_SLIDER)
{
if (priv->press_and_hold)
gtk_press_and_hold_process_event (priv->press_and_hold, (GdkEvent *)event);
if (priv->long_press_gesture)
gtk_event_controller_handle_event (GTK_EVENT_CONTROLLER (priv->long_press_gesture),
(const GdkEvent*) event);
}
stop_scrolling (range);
@ -3071,8 +3074,9 @@ gtk_range_motion_notify (GtkWidget *widget,
if (priv->grab_location == MOUSE_SLIDER)
{
if (!priv->zoom_set && priv->press_and_hold != NULL)
gtk_press_and_hold_process_event (priv->press_and_hold, (GdkEvent *)event);
if (!priv->zoom_set && priv->long_press_gesture != NULL)
gtk_event_controller_handle_event (GTK_EVENT_CONTROLLER (priv->long_press_gesture),
(const GdkEvent*) event);
update_autoscroll_mode (range);
if (priv->autoscroll_mode == GTK_SCROLL_NONE)

View File

@ -130,7 +130,6 @@
#define MAX_OVERSHOOT_DISTANCE 50
#define FRICTION_DECELERATION 0.003
#define OVERSHOOT_INVERSE_ACCELERATION 0.003
#define RELEASE_EVENT_TIMEOUT 1000
struct _GtkScrolledWindowPrivate
{
@ -150,24 +149,24 @@ struct _GtkScrolledWindowPrivate
gint min_content_height;
/* Kinetic scrolling */
GdkEvent *button_press_event;
GtkGesture *long_press_gesture;
GtkGesture *swipe_gesture;
/* These two gestures are mutually exclusive */
GtkGesture *drag_gesture;
GtkGesture *pan_gesture;
gdouble drag_start_x;
gdouble drag_start_y;
GdkWindow *overshoot_window;
GdkDevice *drag_device;
guint kinetic_scrolling : 1;
guint capture_button_press : 1;
guint in_drag : 1;
guint last_button_event_valid : 1;
guint release_timeout_id;
guint deceleration_id;
gdouble last_button_event_x_root;
gdouble last_button_event_y_root;
gdouble last_motion_event_x_root;
gdouble last_motion_event_y_root;
guint32 last_motion_event_time;
gdouble x_velocity;
gdouble y_velocity;
@ -224,8 +223,6 @@ static void gtk_scrolled_window_size_allocate (GtkWidget *widge
GtkAllocation *allocation);
static gboolean gtk_scrolled_window_scroll_event (GtkWidget *widget,
GdkEventScroll *event);
static gboolean gtk_scrolled_window_captured_event (GtkWidget *widget,
GdkEvent *event);
static gboolean gtk_scrolled_window_focus (GtkWidget *widget,
GtkDirectionType direction);
static void gtk_scrolled_window_add (GtkContainer *container,
@ -280,6 +277,13 @@ static gboolean _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindo
static void gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window);
static gboolean _gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_window,
gint *overshoot_x,
gint *overshoot_y);
static void _gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_window);
static void gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window);
static guint signals[LAST_SIGNAL] = {0};
G_DEFINE_TYPE_WITH_PRIVATE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
@ -562,16 +566,196 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCROLLED_WINDOW_ACCESSIBLE);
}
static void
scrolled_window_drag_begin_cb (GtkScrolledWindow *scrolled_window,
gdouble start_x,
gdouble start_y,
GtkGesture *gesture)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
GtkEventSequenceState state;
GdkEventSequence *sequence;
priv->in_drag = FALSE;
priv->drag_start_x = priv->unclamped_hadj_value;
priv->drag_start_y = priv->unclamped_vadj_value;
gtk_scrolled_window_cancel_deceleration (scrolled_window);
if (!priv->hscrollbar_visible && !priv->vscrollbar_visible)
state = GTK_EVENT_SEQUENCE_DENIED;
else if (priv->capture_button_press)
state = GTK_EVENT_SEQUENCE_CLAIMED;
else
return;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
gtk_gesture_set_sequence_state (gesture, sequence, state);
}
static void
scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
gdouble offset_x,
gdouble offset_y,
GtkGesture *gesture)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
gint old_overshoot_x, old_overshoot_y;
gint new_overshoot_x, new_overshoot_y;
GtkAdjustment *hadjustment;
GtkAdjustment *vadjustment;
gdouble dx, dy;
if (!priv->capture_button_press)
{
GdkEventSequence *sequence;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
gtk_gesture_set_sequence_state (gesture, sequence,
GTK_EVENT_SEQUENCE_CLAIMED);
}
_gtk_scrolled_window_get_overshoot (scrolled_window,
&old_overshoot_x, &old_overshoot_y);
hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
if (hadjustment && priv->hscrollbar_visible)
{
dx = priv->drag_start_x - offset_x;
_gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment,
dx, TRUE, FALSE);
}
vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
if (vadjustment && priv->vscrollbar_visible)
{
dy = priv->drag_start_y - offset_y;
_gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment,
dy, TRUE, FALSE);
}
_gtk_scrolled_window_get_overshoot (scrolled_window,
&new_overshoot_x, &new_overshoot_y);
if (old_overshoot_x != new_overshoot_x ||
old_overshoot_y != new_overshoot_y)
{
if (new_overshoot_x >= 0 || new_overshoot_y >= 0)
{
/* We need to reallocate the widget to have it at
* negative offset, so there's a "gravity" on the
* bottom/right corner
*/
gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
}
else if (new_overshoot_x < 0 || new_overshoot_y < 0)
_gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
}
}
static void
scrolled_window_drag_end_cb (GtkScrolledWindow *scrolled_window,
GdkEventSequence *sequence,
GtkGesture *gesture)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
if (!priv->in_drag || !gtk_gesture_handles_sequence (gesture, sequence))
gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);
}
static void
scrolled_window_swipe_cb (GtkScrolledWindow *scrolled_window,
gdouble x_velocity,
gdouble y_velocity)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
gboolean overshoot;
overshoot = _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL);
priv->x_velocity = -x_velocity / 1000;
priv->y_velocity = -y_velocity / 1000;
/* Zero out vector components without a visible scrollbar */
if (!priv->hscrollbar_visible)
priv->x_velocity = 0;
if (!priv->vscrollbar_visible)
priv->y_velocity = 0;
if (priv->x_velocity != 0 || priv->y_velocity != 0 || overshoot)
{
gtk_scrolled_window_start_deceleration (scrolled_window);
priv->x_velocity = priv->y_velocity = 0;
}
}
static void
scrolled_window_long_press_cb (GtkScrolledWindow *scrolled_window,
gdouble x,
gdouble y,
GtkGesture *gesture)
{
GdkEventSequence *sequence;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
gtk_gesture_set_sequence_state (gesture, sequence,
GTK_EVENT_SEQUENCE_DENIED);
}
static void
scrolled_window_long_press_cancelled_cb (GtkScrolledWindow *scrolled_window,
GtkGesture *gesture)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
GdkEventSequence *sequence;
const GdkEvent *event;
sequence = gtk_gesture_get_last_updated_sequence (gesture);
event = gtk_gesture_get_last_event (gesture, sequence);
if (event->type == GDK_TOUCH_BEGIN ||
event->type == GDK_BUTTON_PRESS)
gtk_gesture_set_sequence_state (gesture, sequence,
GTK_EVENT_SEQUENCE_DENIED);
else if (event->type != GDK_TOUCH_END &&
event->type != GDK_BUTTON_RELEASE)
priv->in_drag = TRUE;
}
static void
gtk_scrolled_window_check_attach_pan_gesture (GtkScrolledWindow *sw)
{
GtkScrolledWindowPrivate *priv = sw->priv;
if (priv->kinetic_scrolling &&
((priv->hscrollbar_visible && !priv->vscrollbar_visible) ||
(!priv->hscrollbar_visible && priv->vscrollbar_visible)))
{
GtkPanOrientation orientation;
if (priv->hscrollbar_visible)
orientation = GTK_PAN_ORIENTATION_HORIZONTAL;
else
orientation = GTK_PAN_ORIENTATION_VERTICAL;
gtk_gesture_pan_set_orientation (GTK_GESTURE_PAN (priv->pan_gesture),
orientation);
gtk_gesture_attach (priv->pan_gesture, GTK_PHASE_CAPTURE);
}
else
gtk_gesture_detach (priv->pan_gesture);
}
static void
gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
{
GtkWidget *widget = GTK_WIDGET (scrolled_window);
GtkScrolledWindowPrivate *priv;
scrolled_window->priv = priv =
gtk_scrolled_window_get_instance_private (scrolled_window);
gtk_widget_set_has_window (GTK_WIDGET (scrolled_window), FALSE);
gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
gtk_widget_set_has_window (widget, FALSE);
gtk_widget_set_can_focus (widget, TRUE);
/* Instantiated by gtk_scrolled_window_set_[hv]adjustment
* which are both construct properties
@ -587,6 +771,38 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
priv->min_content_width = -1;
priv->min_content_height = -1;
priv->drag_gesture = gtk_gesture_drag_new (widget);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->drag_gesture), 1);
g_signal_connect_swapped (priv->drag_gesture, "drag-begin",
G_CALLBACK (scrolled_window_drag_begin_cb),
scrolled_window);
g_signal_connect_swapped (priv->drag_gesture, "drag-update",
G_CALLBACK (scrolled_window_drag_update_cb),
scrolled_window);
g_signal_connect_swapped (priv->drag_gesture, "end",
G_CALLBACK (scrolled_window_drag_end_cb),
scrolled_window);
priv->pan_gesture = gtk_gesture_pan_new (widget, GTK_PAN_ORIENTATION_VERTICAL);
gtk_gesture_group (priv->pan_gesture, priv->drag_gesture);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->pan_gesture), 1);
priv->swipe_gesture = gtk_gesture_swipe_new (widget);
gtk_gesture_group (priv->swipe_gesture, priv->drag_gesture);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->swipe_gesture), 1);
g_signal_connect_swapped (priv->swipe_gesture, "swipe",
G_CALLBACK (scrolled_window_swipe_cb),
scrolled_window);
priv->long_press_gesture = gtk_gesture_long_press_new (widget);
gtk_gesture_group (priv->long_press_gesture, priv->drag_gesture);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->long_press_gesture), 1);
g_signal_connect_swapped (priv->long_press_gesture, "pressed",
G_CALLBACK (scrolled_window_long_press_cb),
scrolled_window);
g_signal_connect_swapped (priv->long_press_gesture, "cancelled",
G_CALLBACK (scrolled_window_long_press_cancelled_cb),
scrolled_window);
gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
}
@ -1060,24 +1276,21 @@ gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
return;
priv->kinetic_scrolling = kinetic_scrolling;
gtk_scrolled_window_check_attach_pan_gesture (scrolled_window);
if (priv->kinetic_scrolling)
{
_gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window),
gtk_scrolled_window_captured_event);
gtk_gesture_attach (priv->drag_gesture, GTK_PHASE_CAPTURE);
gtk_gesture_attach (priv->swipe_gesture, GTK_PHASE_CAPTURE);
gtk_gesture_attach (priv->long_press_gesture, GTK_PHASE_CAPTURE);
}
else
{
_gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window), NULL);
if (priv->release_timeout_id)
{
g_source_remove (priv->release_timeout_id);
priv->release_timeout_id = 0;
}
if (priv->deceleration_id)
{
gtk_widget_remove_tick_callback (GTK_WIDGET (scrolled_window), priv->deceleration_id);
priv->deceleration_id = 0;
}
gtk_gesture_detach (priv->drag_gesture);
gtk_gesture_detach (priv->swipe_gesture);
gtk_gesture_detach (priv->long_press_gesture);
gtk_scrolled_window_cancel_deceleration (scrolled_window);
}
g_object_notify (G_OBJECT (scrolled_window), "kinetic-scrolling");
}
@ -1175,22 +1388,15 @@ gtk_scrolled_window_destroy (GtkWidget *widget)
priv->vscrollbar = NULL;
}
if (priv->release_timeout_id)
{
g_source_remove (priv->release_timeout_id);
priv->release_timeout_id = 0;
}
if (priv->deceleration_id)
{
gtk_widget_remove_tick_callback (widget, priv->deceleration_id);
priv->deceleration_id = 0;
}
if (priv->button_press_event)
{
gdk_event_free (priv->button_press_event);
priv->button_press_event = NULL;
}
g_clear_object (&priv->drag_gesture);
g_clear_object (&priv->swipe_gesture);
g_clear_object (&priv->long_press_gesture);
GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->destroy (widget);
}
@ -2116,6 +2322,7 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
}
_gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
gtk_scrolled_window_check_attach_pan_gesture (scrolled_window);
}
static gboolean
@ -2414,388 +2621,6 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
(GDestroyNotify) g_free);
}
static gboolean
gtk_scrolled_window_release_captured_event (GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
/* Cancel the scrolling and send the button press
* event to the child widget
*/
if (!priv->button_press_event)
return FALSE;
if (priv->drag_device)
{
gtk_device_grab_remove (GTK_WIDGET (scrolled_window), priv->drag_device);
priv->drag_device = NULL;
}
if (priv->capture_button_press)
{
GtkWidget *event_widget;
event_widget = gtk_get_event_widget (priv->button_press_event);
if (!_gtk_propagate_captured_event (event_widget,
priv->button_press_event,
gtk_bin_get_child (GTK_BIN (scrolled_window))))
gtk_propagate_event (event_widget, priv->button_press_event);
gdk_event_free (priv->button_press_event);
priv->button_press_event = NULL;
}
if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
gtk_scrolled_window_start_deceleration (scrolled_window);
return FALSE;
}
static gboolean
gtk_scrolled_window_calculate_velocity (GtkScrolledWindow *scrolled_window,
GdkEvent *event)
{
GtkScrolledWindowPrivate *priv;
gdouble x_root, y_root;
guint32 _time;
#define STILL_THRESHOLD 40
if (!gdk_event_get_root_coords (event, &x_root, &y_root))
return FALSE;
priv = scrolled_window->priv;
_time = gdk_event_get_time (event);
if (priv->last_motion_event_x_root != x_root ||
priv->last_motion_event_y_root != y_root ||
ABS (_time - priv->last_motion_event_time) > STILL_THRESHOLD)
{
priv->x_velocity = (priv->last_motion_event_x_root - x_root) /
(gdouble) (_time - priv->last_motion_event_time);
priv->y_velocity = (priv->last_motion_event_y_root - y_root) /
(gdouble) (_time - priv->last_motion_event_time);
}
priv->last_motion_event_x_root = x_root;
priv->last_motion_event_y_root = y_root;
priv->last_motion_event_time = _time;
#undef STILL_THRESHOLD
return TRUE;
}
static gboolean
gtk_scrolled_window_captured_button_release (GtkWidget *widget,
GdkEvent *event)
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
GtkWidget *child;
gboolean overshoot;
guint button;
gdouble x_root, y_root;
if (gdk_event_get_button (event, &button) && button != 1)
return FALSE;
child = gtk_bin_get_child (GTK_BIN (widget));
if (!child)
return FALSE;
gtk_device_grab_remove (widget, priv->drag_device);
priv->drag_device = NULL;
if (priv->release_timeout_id)
{
g_source_remove (priv->release_timeout_id);
priv->release_timeout_id = 0;
}
overshoot = _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL);
if (priv->in_drag)
gdk_device_ungrab (gdk_event_get_device (event), gdk_event_get_time (event));
else
{
/* There hasn't been scrolling at all, so just let the
* child widget handle the button press normally
*/
gtk_scrolled_window_release_captured_event (scrolled_window);
if (!overshoot)
return FALSE;
}
priv->in_drag = FALSE;
if (priv->button_press_event)
{
gdk_event_free (priv->button_press_event);
priv->button_press_event = NULL;
}
gtk_scrolled_window_calculate_velocity (scrolled_window, event);
/* Zero out vector components without a visible scrollbar */
if (!priv->hscrollbar_visible)
priv->x_velocity = 0;
if (!priv->vscrollbar_visible)
priv->y_velocity = 0;
if (priv->x_velocity != 0 || priv->y_velocity != 0 || overshoot)
{
gtk_scrolled_window_start_deceleration (scrolled_window);
priv->x_velocity = priv->y_velocity = 0;
priv->last_button_event_valid = FALSE;
}
else
{
gdk_event_get_root_coords (event, &x_root, &y_root);
priv->last_button_event_x_root = x_root;
priv->last_button_event_y_root = y_root;
priv->last_button_event_valid = TRUE;
}
if (priv->capture_button_press)
return TRUE;
else
return FALSE;
}
static gboolean
gtk_scrolled_window_captured_motion_notify (GtkWidget *widget,
GdkEvent *event)
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
gint old_overshoot_x, old_overshoot_y;
gint new_overshoot_x, new_overshoot_y;
GtkWidget *child;
GtkAdjustment *hadjustment;
GtkAdjustment *vadjustment;
gdouble dx, dy;
GdkModifierType state;
gdouble x_root, y_root;
gdk_event_get_state (event, &state);
if (!(state & GDK_BUTTON1_MASK))
return FALSE;
child = gtk_bin_get_child (GTK_BIN (widget));
if (!child)
return FALSE;
/* Check if we've passed the drag threshold */
gdk_event_get_root_coords (event, &x_root, &y_root);
if (!priv->in_drag)
{
if (gtk_drag_check_threshold (widget,
priv->last_button_event_x_root,
priv->last_button_event_y_root,
x_root, y_root))
{
if (priv->release_timeout_id)
{
g_source_remove (priv->release_timeout_id);
priv->release_timeout_id = 0;
}
priv->last_button_event_valid = FALSE;
priv->in_drag = TRUE;
}
else
return TRUE;
}
gdk_device_grab (priv->drag_device,
gtk_widget_get_window (widget),
GDK_OWNERSHIP_WINDOW,
TRUE,
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK,
NULL,
gdk_event_get_time (event));
priv->last_button_event_valid = FALSE;
if (priv->button_press_event)
{
gdk_event_free (priv->button_press_event);
priv->button_press_event = NULL;
}
_gtk_scrolled_window_get_overshoot (scrolled_window,
&old_overshoot_x, &old_overshoot_y);
hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
if (hadjustment && priv->hscrollbar_visible)
{
dx = (priv->last_motion_event_x_root - x_root) + priv->unclamped_hadj_value;
_gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment,
dx, TRUE, FALSE);
}
vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
if (vadjustment && priv->vscrollbar_visible)
{
dy = (priv->last_motion_event_y_root - y_root) + priv->unclamped_vadj_value;
_gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment,
dy, TRUE, FALSE);
}
_gtk_scrolled_window_get_overshoot (scrolled_window,
&new_overshoot_x, &new_overshoot_y);
if (old_overshoot_x != new_overshoot_x ||
old_overshoot_y != new_overshoot_y)
{
if (new_overshoot_x >= 0 || new_overshoot_y >= 0)
{
/* We need to reallocate the widget to have it at
* negative offset, so there's a "gravity" on the
* bottom/right corner
*/
gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
}
else if (new_overshoot_x < 0 || new_overshoot_y < 0)
_gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
}
gtk_scrolled_window_calculate_velocity (scrolled_window, event);
return TRUE;
}
static gboolean
gtk_scrolled_window_captured_button_press (GtkWidget *widget,
GdkEvent *event)
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
GtkWidget *child;
GtkWidget *event_widget;
GdkDevice *source_device;
GdkInputSource source;
gdouble x_root, y_root;
guint button;
/* If scrollbars are not visible, we don't do kinetic scrolling */
if (!priv->vscrollbar_visible && !priv->hscrollbar_visible)
return FALSE;
source_device = gdk_event_get_source_device (event);
source = gdk_device_get_source (source_device);
if (source != GDK_SOURCE_TOUCHSCREEN)
return FALSE;
event_widget = gtk_get_event_widget (event);
/* If there's another scrolled window between the widget
* receiving the event and this capturing scrolled window,
* let it handle the events.
*/
if (widget != gtk_widget_get_ancestor (event_widget, GTK_TYPE_SCROLLED_WINDOW))
return FALSE;
/* Check whether the button press is close to the previous one,
* take that as a shortcut to get the child widget handle events
*/
gdk_event_get_root_coords (event, &x_root, &y_root);
if (priv->last_button_event_valid &&
ABS (x_root - priv->last_button_event_x_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD &&
ABS (y_root - priv->last_button_event_y_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD)
{
priv->last_button_event_valid = FALSE;
return FALSE;
}
priv->last_button_event_x_root = priv->last_motion_event_x_root = x_root;
priv->last_button_event_y_root = priv->last_motion_event_y_root = y_root;
priv->last_motion_event_time = gdk_event_get_time (event);
priv->last_button_event_valid = TRUE;
if (gdk_event_get_button (event, &button) && button != 1)
return FALSE;
child = gtk_bin_get_child (GTK_BIN (widget));
if (!child)
return FALSE;
if (priv->hscrollbar == event_widget || priv->vscrollbar == event_widget)
return FALSE;
priv->drag_device = gdk_event_get_device (event);
gtk_device_grab_add (widget, priv->drag_device, TRUE);
gtk_scrolled_window_cancel_deceleration (scrolled_window);
/* Only set the timeout if we're going to store an event */
if (priv->capture_button_press)
{
priv->release_timeout_id =
gdk_threads_add_timeout (RELEASE_EVENT_TIMEOUT,
(GSourceFunc) gtk_scrolled_window_release_captured_event,
scrolled_window);
g_source_set_name_by_id (priv->release_timeout_id, "[gtk+] gtk_scrolled_window_release_captured_event");
}
priv->in_drag = FALSE;
if (priv->capture_button_press)
{
/* Store the button press event in
* case we need to propagate it later
*/
priv->button_press_event = gdk_event_copy (event);
return TRUE;
}
else
return FALSE;
}
static gboolean
gtk_scrolled_window_captured_event (GtkWidget *widget,
GdkEvent *event)
{
gboolean retval = FALSE;
GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW (widget)->priv;
if (gdk_window_get_window_type (event->any.window) == GDK_WINDOW_TEMP)
return FALSE;
switch (event->type)
{
case GDK_TOUCH_BEGIN:
case GDK_BUTTON_PRESS:
retval = gtk_scrolled_window_captured_button_press (widget, event);
break;
case GDK_TOUCH_END:
case GDK_BUTTON_RELEASE:
if (priv->drag_device)
retval = gtk_scrolled_window_captured_button_release (widget, event);
else
priv->last_button_event_valid = FALSE;
break;
case GDK_TOUCH_UPDATE:
case GDK_MOTION_NOTIFY:
if (priv->drag_device)
retval = gtk_scrolled_window_captured_motion_notify (widget, event);
break;
case GDK_LEAVE_NOTIFY:
case GDK_ENTER_NOTIFY:
if (priv->in_drag &&
event->crossing.mode != GDK_CROSSING_GRAB)
retval = TRUE;
break;
default:
break;
}
return retval;
}
static gboolean
gtk_scrolled_window_focus (GtkWidget *widget,
GtkDirectionType direction)
@ -3335,20 +3160,11 @@ gtk_scrolled_window_grab_notify (GtkWidget *widget,
gdk_device_ungrab (priv->drag_device,
gtk_get_current_event_time ());
priv->drag_device = NULL;
priv->in_drag = FALSE;
if (priv->release_timeout_id)
{
g_source_remove (priv->release_timeout_id);
priv->release_timeout_id = 0;
}
if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
gtk_scrolled_window_start_deceleration (scrolled_window);
else
gtk_scrolled_window_cancel_deceleration (scrolled_window);
priv->last_button_event_valid = FALSE;
}
}

View File

@ -219,7 +219,8 @@ enum {
PROP_DECORATION_LAYOUT,
PROP_DIALOGS_USE_HEADER,
PROP_ENABLE_PRIMARY_PASTE,
PROP_RECENT_FILES_ENABLED
PROP_RECENT_FILES_ENABLED,
PROP_LONG_PRESS_TIME
};
/* --- prototypes --- */
@ -1635,6 +1636,22 @@ gtk_settings_class_init (GtkSettingsClass *class)
GTK_PARAM_READWRITE),
NULL);
g_assert (result == PROP_RECENT_FILES_ENABLED);
/**
* GtkSettings:gtk-long-press-time:
*
* The time for a button or touch press to be considered a "long press".
*
* Since: 3.14
*/
result = settings_install_property_parser (class,
g_param_spec_uint ("gtk-long-press-time",
P_("Long press time"),
P_("Time for a button/touch press to be considered a long press (in milliseconds)"),
0, G_MAXINT, 500,
GTK_PARAM_READWRITE),
NULL);
g_assert (result == PROP_LONG_PRESS_TIME);
}
static void

View File

@ -166,6 +166,8 @@ struct _GtkSpinButtonPrivate
GtkOrientation orientation;
GtkGesture *swipe_gesture;
guint button : 2;
guint digits : 10;
guint need_timer : 1;
@ -641,6 +643,36 @@ gtk_spin_button_get_property (GObject *object,
}
}
static void
swipe_gesture_begin (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkSpinButton *spin_button)
{
GdkEventSequence *current;
const GdkEvent *event;
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
event = gtk_gesture_get_last_event (gesture, current);
if (event->any.window == spin_button->priv->up_panel ||
event->any.window == spin_button->priv->down_panel)
gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);
gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_CLAIMED);
gtk_widget_grab_focus (GTK_WIDGET (spin_button));
}
static void
swipe_gesture_update (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkSpinButton *spin_button)
{
gdouble vel_y;
gtk_gesture_swipe_get_velocity (GTK_GESTURE_SWIPE (gesture), NULL, &vel_y);
gtk_spin_button_real_spin (spin_button, -vel_y / 20);
}
static void
gtk_spin_button_init (GtkSpinButton *spin_button)
{
@ -676,6 +708,13 @@ gtk_spin_button_init (GtkSpinButton *spin_button)
gtk_style_context_add_class (context, GTK_STYLE_CLASS_SPINBUTTON);
gtk_widget_add_events (GTK_WIDGET (spin_button), GDK_SCROLL_MASK);
priv->swipe_gesture = gtk_gesture_swipe_new (GTK_WIDGET (spin_button));
gtk_gesture_attach (priv->swipe_gesture, GTK_PHASE_CAPTURE);
g_signal_connect (priv->swipe_gesture, "begin",
G_CALLBACK (swipe_gesture_begin), spin_button);
g_signal_connect (priv->swipe_gesture, "update",
G_CALLBACK (swipe_gesture_update), spin_button);
}
static void
@ -692,6 +731,9 @@ gtk_spin_button_finalize (GObject *object)
if (priv->up_panel_context)
g_object_unref (priv->up_panel_context);
gtk_gesture_detach (priv->swipe_gesture);
g_object_unref (priv->swipe_gesture);
G_OBJECT_CLASS (gtk_spin_button_parent_class)->finalize (object);
}
@ -1487,7 +1529,9 @@ gtk_spin_button_button_press (GtkWidget *widget,
return TRUE;
}
else
return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->button_press_event (widget, event);
{
return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->button_press_event (widget, event);
}
}
return FALSE;
}
@ -1529,7 +1573,9 @@ gtk_spin_button_button_release (GtkWidget *widget,
return TRUE;
}
else
return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->button_release_event (widget, event);
{
return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->button_release_event (widget, event);
}
}
static gint
@ -1553,6 +1599,9 @@ gtk_spin_button_motion_notify (GtkWidget *widget,
return FALSE;
}
if (gtk_gesture_is_recognized (priv->swipe_gesture))
return TRUE;
return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->motion_notify_event (widget, event);
}

View File

@ -62,6 +62,9 @@ struct _GtkSwitchPrivate
GtkAction *action;
GtkActionHelper *action_helper;
GtkGesture *pan_gesture;
GtkGesture *multipress_gesture;
gint handle_x;
gint offset;
gint drag_start;
@ -69,8 +72,6 @@ struct _GtkSwitchPrivate
guint state : 1;
guint is_active : 1;
guint is_dragging : 1;
guint in_press : 1;
guint in_switch : 1;
guint use_action_appearance : 1;
};
@ -110,171 +111,131 @@ G_DEFINE_TYPE_WITH_CODE (GtkSwitch, gtk_switch, GTK_TYPE_WIDGET,
gtk_switch_activatable_interface_init));
G_GNUC_END_IGNORE_DEPRECATIONS;
static gboolean
gtk_switch_button_press (GtkWidget *widget,
GdkEventButton *event)
static void
gtk_switch_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y,
GtkSwitch *sw)
{
GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
GtkSwitchPrivate *priv = sw->priv;
GtkAllocation allocation;
/* Don't handle extra mouse buttons events, let them bubble up */
if (event->button > 5)
return GDK_EVENT_PROPAGATE;
gtk_widget_get_allocation (widget, &allocation);
gtk_widget_get_allocation (GTK_WIDGET (sw), &allocation);
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
if (priv->is_active)
{
/* if the event occurred in the "off" area, then this
* is a direct toggle
*/
if (event->x <= allocation.width / 2)
{
priv->in_press = TRUE;
return GDK_EVENT_STOP;
}
priv->offset = event->x - allocation.width / 2;
}
priv->offset = allocation.width / 2;
else
{
/* if the event occurred in the "on" area, then this
* is a direct toggle
*/
if (event->x >= allocation.width / 2)
{
priv->in_press = TRUE;
return GDK_EVENT_STOP;
}
priv->offset = 0;
priv->offset = event->x;
}
priv->drag_start = event->x;
g_object_get (gtk_widget_get_settings (widget),
"gtk-dnd-drag-threshold", &priv->drag_threshold,
NULL);
return GDK_EVENT_STOP;
/* If the press didn't happen in the draggable handle,
* cancel the pan gesture right away
*/
if ((priv->is_active && x <= allocation.width / 2) ||
(!priv->is_active && x > allocation.width / 2))
gtk_gesture_set_state (priv->pan_gesture, GTK_EVENT_SEQUENCE_DENIED);
}
static gboolean
gtk_switch_motion (GtkWidget *widget,
GdkEventMotion *event)
static void
gtk_switch_multipress_gesture_released (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y,
GtkSwitch *sw)
{
GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
/* if this is a direct toggle we don't handle motion */
if (priv->in_press)
return GDK_EVENT_PROPAGATE;
if (ABS (event->x - priv->drag_start) < priv->drag_threshold)
return GDK_EVENT_STOP;
if (event->state & GDK_BUTTON1_MASK)
{
gint position = event->x - priv->offset;
GtkAllocation allocation;
GtkStyleContext *context;
GtkStateFlags state;
GtkBorder padding;
gint width;
context = gtk_widget_get_style_context (widget);
state = gtk_widget_get_state_flags (widget);
gtk_style_context_save (context);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER);
gtk_style_context_get_padding (context, state, &padding);
gtk_style_context_restore (context);
gtk_widget_get_allocation (widget, &allocation);
width = allocation.width;
/* constrain the handle within the trough width */
if (position > (width / 2) - padding.right)
priv->handle_x = width / 2 - padding.right;
else if (position < padding.left)
priv->handle_x = 0;
else
priv->handle_x = position;
priv->is_dragging = TRUE;
/* we need to redraw the handle */
gtk_widget_queue_draw (widget);
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
static gboolean
gtk_switch_button_release (GtkWidget *widget,
GdkEventButton *event)
{
GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
GtkSwitchPrivate *priv = sw->priv;
GdkEventSequence *sequence;
GtkAllocation allocation;
/* Don't handle extra mouse buttons events, let them bubble up */
if (event->button > 5)
return GDK_EVENT_PROPAGATE;
gtk_widget_get_allocation (GTK_WIDGET (sw), &allocation);
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (priv->in_switch &&
gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
gtk_switch_set_active (sw, !priv->is_active);
}
static void
gtk_switch_pan_gesture_pan (GtkGesturePan *gesture,
GtkPanDirection direction,
gdouble offset,
GtkSwitch *sw)
{
GtkWidget *widget = GTK_WIDGET (sw);
GtkSwitchPrivate *priv = sw->priv;
GtkAllocation allocation;
GtkStyleContext *context;
GtkStateFlags state;
GtkBorder padding;
gint width, position;
if (direction == GTK_PAN_DIRECTION_LEFT)
offset = -offset;
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
position = priv->offset + offset;
context = gtk_widget_get_style_context (widget);
state = gtk_widget_get_state_flags (widget);
gtk_style_context_save (context);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER);
gtk_style_context_get_padding (context, state, &padding);
gtk_style_context_restore (context);
gtk_widget_get_allocation (widget, &allocation);
/* dragged toggles have a "soft" grab, so we don't care whether we
* are in the switch or not when the button is released; we do care
* for direct toggles, instead
*/
if (!priv->is_dragging && !priv->in_switch)
return GDK_EVENT_PROPAGATE;
width = allocation.width;
/* direct toggle */
if (priv->in_press)
/* constrain the handle within the trough width */
if (position > (width / 2) - padding.right)
priv->handle_x = width / 2 - padding.right;
else if (position < padding.left)
priv->handle_x = 0;
else
priv->handle_x = position;
/* we need to redraw the handle */
gtk_widget_queue_draw (widget);
}
static void
gtk_switch_pan_gesture_drag_end (GtkGestureDrag *gesture,
gdouble x,
gdouble y,
GtkSwitch *sw)
{
GtkSwitchPrivate *priv = sw->priv;
GdkEventSequence *sequence;
GtkAllocation allocation;
gboolean active = FALSE;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (gtk_gesture_get_sequence_state (GTK_GESTURE (gesture), sequence) == GTK_EVENT_SEQUENCE_CLAIMED)
{
priv->in_press = FALSE;
gtk_switch_set_active (GTK_SWITCH (widget), !priv->is_active);
return GDK_EVENT_STOP;
}
/* toggle the switch if the handle was clicked but a drag had not been
* initiated */
if (!priv->is_dragging && !priv->in_press)
{
gtk_switch_set_active (GTK_SWITCH (widget), !priv->is_active);
return GDK_EVENT_STOP;
}
/* dragged toggle */
if (priv->is_dragging)
{
priv->is_dragging = FALSE;
gtk_widget_get_allocation (GTK_WIDGET (sw), &allocation);
/* if half the handle passed the middle of the switch, then we
* consider it to be on
*/
if ((priv->handle_x + (allocation.width / 4)) >= (allocation.width / 2))
{
gtk_switch_set_active (GTK_SWITCH (widget), TRUE);
priv->handle_x = allocation.width / 2;
}
else
{
gtk_switch_set_active (GTK_SWITCH (widget), FALSE);
priv->handle_x = 0;
}
gtk_widget_queue_draw (widget);
return GDK_EVENT_STOP;
active = TRUE;
}
else if (!gtk_gesture_handles_sequence (priv->multipress_gesture, sequence))
active = priv->is_active;
else
return;
return GDK_EVENT_PROPAGATE;
if (active)
priv->handle_x = allocation.width / 2;
else
priv->handle_x = 0;
gtk_switch_set_active (sw, active);
gtk_widget_queue_draw (GTK_WIDGET (sw));
}
static gboolean
@ -593,7 +554,7 @@ gtk_switch_draw (GtkWidget *widget,
g_object_unref (layout);
if (priv->is_dragging)
if (gtk_gesture_is_recognized (priv->pan_gesture))
handle.x = x + priv->handle_x;
else if (priv->is_active)
handle.x = x + width - handle.width;
@ -869,9 +830,6 @@ gtk_switch_class_init (GtkSwitchClass *klass)
widget_class->map = gtk_switch_map;
widget_class->unmap = gtk_switch_unmap;
widget_class->draw = gtk_switch_draw;
widget_class->button_press_event = gtk_switch_button_press;
widget_class->button_release_event = gtk_switch_button_release;
widget_class->motion_notify_event = gtk_switch_motion;
widget_class->enter_notify_event = gtk_switch_enter;
widget_class->leave_notify_event = gtk_switch_leave;
@ -952,10 +910,33 @@ gtk_switch_class_init (GtkSwitchClass *klass)
static void
gtk_switch_init (GtkSwitch *self)
{
GtkGesture *gesture;
self->priv = gtk_switch_get_instance_private (self);
self->priv->use_action_appearance = TRUE;
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
gesture = gtk_gesture_multi_press_new (GTK_WIDGET (self));
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (gesture), TRUE);
g_signal_connect (gesture, "pressed",
G_CALLBACK (gtk_switch_multipress_gesture_pressed), self);
g_signal_connect (gesture, "released",
G_CALLBACK (gtk_switch_multipress_gesture_released), self);
gtk_gesture_attach (gesture, GTK_PHASE_TARGET);
self->priv->multipress_gesture = gesture;
gesture = gtk_gesture_pan_new (GTK_WIDGET (self),
GTK_PAN_ORIENTATION_HORIZONTAL);
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (gesture), TRUE);
g_signal_connect (gesture, "pan",
G_CALLBACK (gtk_switch_pan_gesture_pan), self);
g_signal_connect (gesture, "drag-end",
G_CALLBACK (gtk_switch_pan_gesture_drag_end), self);
gtk_gesture_attach (gesture, GTK_PHASE_TARGET);
self->priv->pan_gesture = gesture;
}
/**

View File

@ -102,11 +102,14 @@ _gtk_text_handle_draw (GtkTextHandle *handle,
priv = handle->priv;
context = gtk_widget_get_style_context (priv->parent);
_gtk_text_handle_get_size (handle, &width, &height);
cairo_save (cr);
if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
cairo_translate (cr, 0, priv->windows[pos].pointing_to.height);
cairo_translate (cr, width, priv->windows[pos].pointing_to.height);
else
cairo_translate (cr, width, height);
gtk_style_context_save (context);
gtk_style_context_add_class (context,
@ -125,7 +128,6 @@ _gtk_text_handle_draw (GtkTextHandle *handle,
gtk_style_context_add_class (context,
GTK_STYLE_CLASS_TOP);
_gtk_text_handle_get_size (handle, &width, &height);
gtk_render_background (context, cr, 0, 0, width, height);
gtk_style_context_restore (context);
@ -191,14 +193,18 @@ gtk_text_handle_widget_event (GtkWidget *widget,
event->motion.state & GDK_BUTTON1_MASK &&
priv->windows[pos].dragged)
{
gint x, y, width, height;
gint x, y, width, height, handle_height;
GtkAllocation allocation;
_gtk_text_handle_get_size (handle, &width, &height);
gtk_widget_get_allocation (priv->windows[pos].widget, &allocation);
width = allocation.width;
height = allocation.height;
_gtk_text_handle_get_size (handle, NULL, &handle_height);
x = event->motion.x - priv->windows[pos].dx + (width / 2);
y = event->motion.y - priv->windows[pos].dy;
if (pos != GTK_TEXT_HANDLE_POSITION_CURSOR)
y += height;
y += height - handle_height;
y += priv->windows[pos].pointing_to.height / 2;
@ -313,6 +319,13 @@ _gtk_text_handle_update (GtkTextHandle *handle,
rect.width = width;
rect.height = 0;
/* Make the window 3 times as wide, and 2 times as high (plus
* handle_window->pointing_to.height), the handle will be rendered
* in the center. Making the rest an invisible input area.
*/
width *= 3;
height *= 2;
_handle_update_child_visible (handle, pos);
window = gtk_widget_get_parent (handle_window->widget);

File diff suppressed because it is too large Load Diff

View File

@ -436,6 +436,9 @@ struct _GtkTreeViewPrivate
gpointer row_separator_data;
GDestroyNotify row_separator_destroy;
/* Gestures */
GtkGesture *multipress_gesture;
/* Tooltip support */
gint tooltip_column;
@ -883,6 +886,8 @@ static gboolean scroll_row_timeout (gpointer data);
static void add_scroll_timeout (GtkTreeView *tree_view);
static void remove_scroll_timeout (GtkTreeView *tree_view);
static void grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view);
static guint tree_view_signals [LAST_SIGNAL] = { 0 };
@ -1731,6 +1736,38 @@ G_GNUC_END_IGNORE_DEPRECATIONS
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
}
static void
_tree_view_multipress_pressed (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y,
GtkTreeView *tree_view)
{
GtkTreeViewColumn *column;
GtkTreePath *path;
gint bin_x, bin_y;
gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y,
&bin_x, &bin_y);
gtk_tree_view_get_path_at_pos (tree_view, bin_x, bin_y,
&path, &column, NULL, NULL);
if (n_press == 2 || (n_press == 1 && tree_view->priv->activate_on_single_click))
gtk_tree_view_row_activated (tree_view, path, column);
else
{
if (n_press == 1)
{
tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
}
grab_focus_and_unset_draw_keyfocus (tree_view);
}
gtk_tree_path_free (path);
}
static void
gtk_tree_view_init (GtkTreeView *tree_view)
{
@ -1799,6 +1836,12 @@ gtk_tree_view_init (GtkTreeView *tree_view)
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tree_view)),
GTK_STYLE_CLASS_VIEW);
tree_view->priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (tree_view));
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (tree_view->priv->multipress_gesture), FALSE);
g_signal_connect (tree_view->priv->multipress_gesture, "pressed",
G_CALLBACK (_tree_view_multipress_pressed), tree_view);
gtk_gesture_attach (tree_view->priv->multipress_gesture, GTK_PHASE_BUBBLE);
}
@ -2163,6 +2206,12 @@ gtk_tree_view_destroy (GtkWidget *widget)
_gtk_pixel_cache_free (tree_view->priv->pixel_cache);
tree_view->priv->pixel_cache = NULL;
if (tree_view->priv->multipress_gesture)
{
gtk_gesture_detach (tree_view->priv->multipress_gesture);
g_clear_object (&tree_view->priv->multipress_gesture);
}
GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
}
@ -2995,7 +3044,6 @@ gtk_tree_view_button_press (GtkWidget *widget,
gint pre_val, aft_val;
GtkTreeViewColumn *column = NULL;
gint column_handled_click = FALSE;
gboolean row_double_click = FALSE;
gboolean rtl;
gboolean node_selected;
GdkModifierType extend_mod_mask;
@ -3015,7 +3063,6 @@ gtk_tree_view_button_press (GtkWidget *widget,
{
if (event->button == GDK_BUTTON_PRIMARY)
{
gtk_grab_add (widget);
tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
@ -3245,67 +3292,6 @@ gtk_tree_view_button_press (GtkWidget *widget,
}
}
if (event->button == GDK_BUTTON_PRIMARY && event->type == GDK_BUTTON_PRESS)
{
/* Test if a double click happened on the same row. */
if (!tree_view->priv->activate_on_single_click)
{
int double_click_time, double_click_distance;
g_object_get (gtk_settings_get_default (),
"gtk-double-click-time", &double_click_time,
"gtk-double-click-distance", &double_click_distance,
NULL);
/* Same conditions as _gdk_event_button_generate */
if (tree_view->priv->last_button_x != -1 &&
(event->time < tree_view->priv->last_button_time + double_click_time) &&
(ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
(ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
{
/* We do no longer compare paths of this row and the
* row clicked previously. We use the double click
* distance to decide whether this is a valid click,
* allowing the mouse to slightly move over another row.
*/
row_double_click = TRUE;
tree_view->priv->last_button_time = 0;
tree_view->priv->last_button_x = -1;
tree_view->priv->last_button_y = -1;
}
else
{
tree_view->priv->last_button_time = event->time;
tree_view->priv->last_button_x = event->x;
tree_view->priv->last_button_y = event->y;
}
}
else
{
tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
}
}
if (row_double_click)
{
gtk_grab_remove (widget);
gtk_tree_view_row_activated (tree_view, path, column);
if (tree_view->priv->pressed_button == event->button)
tree_view->priv->pressed_button = -1;
}
gtk_tree_path_free (path);
/* If we activated the row through a double click we don't want to grab
* focus back, as moving focus to another widget is pretty common.
*/
if (!row_double_click)
grab_focus_and_unset_draw_keyfocus (tree_view);
return TRUE;
}
@ -3341,7 +3327,6 @@ gtk_tree_view_button_press (GtkWidget *widget,
event->time) != GDK_GRAB_SUCCESS)
return FALSE;
gtk_grab_add (widget);
tree_view->priv->in_column_resize = TRUE;
/* block attached dnd signal handler */
@ -3467,7 +3452,6 @@ gtk_tree_view_button_release_column_resize (GtkWidget *widget,
drag_data);
tree_view->priv->in_column_resize = FALSE;
gtk_grab_remove (widget);
gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
return TRUE;
}
@ -3531,7 +3515,6 @@ gtk_tree_view_button_release (GtkWidget *widget,
gtk_tree_path_free (path);
}
gtk_grab_remove (widget);
tree_view->priv->button_pressed_tree = NULL;
tree_view->priv->button_pressed_node = NULL;
}
@ -4241,7 +4224,6 @@ static void
gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
{
remove_scroll_timeout (tree_view);
gtk_grab_remove (GTK_WIDGET (tree_view));
if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
{
@ -4590,7 +4572,6 @@ gtk_tree_view_motion_bin_window (GtkWidget *widget,
if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
{
gtk_grab_add (GTK_WIDGET (tree_view));
gtk_tree_view_update_rubber_band (tree_view);
tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
@ -9928,8 +9909,6 @@ _gtk_tree_view_column_start_drag (GtkTreeView *tree_view,
gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
gtk_grab_remove (button);
send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
send_event->crossing.send_event = TRUE;
send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));

View File

@ -66,6 +66,7 @@
#include "gtktypebuiltins.h"
#include "a11y/gtkwidgetaccessible.h"
#include "gtkapplicationprivate.h"
#include "gtkgestureprivate.h"
/* for the use of round() */
#include "fallback-c89.c"
@ -396,6 +397,14 @@ typedef struct {
GDestroyNotify destroy_notify;
} GtkWidgetTemplate;
typedef struct {
GtkEventController *controller;
GtkPropagationPhase phase;
guint evmask_notify_id;
guint grab_notify_id;
guint sequence_state_changed_id;
} EventControllerData;
struct _GtkWidgetPrivate
{
/* The state of the widget. Needs to be able to hold all GtkStateFlags bits
@ -505,6 +514,8 @@ struct _GtkWidgetPrivate
/* Number of gtk_widget_push_verify_invariants () */
guint verifying_invariants_count;
#endif /* G_ENABLE_DEBUG */
GList *event_controllers;
};
struct _GtkWidgetClassPrivate
@ -676,10 +687,17 @@ static gboolean gtk_widget_real_query_tooltip (GtkWidget *widget,
static void gtk_widget_real_style_updated (GtkWidget *widget);
static gboolean gtk_widget_real_show_help (GtkWidget *widget,
GtkWidgetHelpType help_type);
static gboolean _gtk_widget_run_controllers (GtkWidget *widget,
const GdkEvent *event,
GtkPropagationPhase phase);
static void gtk_widget_dispatch_child_properties_changed (GtkWidget *object,
guint n_pspecs,
GParamSpec **pspecs);
static gboolean gtk_widget_real_button_event (GtkWidget *widget,
GdkEventButton *event);
static gboolean gtk_widget_real_motion_event (GtkWidget *widget,
GdkEventMotion *event);
static gboolean gtk_widget_real_key_press_event (GtkWidget *widget,
GdkEventKey *event);
static gboolean gtk_widget_real_key_release_event (GtkWidget *widget,
@ -690,6 +708,8 @@ static gboolean gtk_widget_real_focus_out_event (GtkWidget *widget,
GdkEventFocus *event);
static gboolean gtk_widget_real_touch_event (GtkWidget *widget,
GdkEventTouch *event);
static gboolean gtk_widget_real_grab_broken_event (GtkWidget *widget,
GdkEventGrabBroken *event);
static gboolean gtk_widget_real_focus (GtkWidget *widget,
GtkDirectionType direction);
static void gtk_widget_real_move_focus (GtkWidget *widget,
@ -1080,9 +1100,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->move_focus = gtk_widget_real_move_focus;
klass->keynav_failed = gtk_widget_real_keynav_failed;
klass->event = NULL;
klass->button_press_event = NULL;
klass->button_release_event = NULL;
klass->motion_notify_event = NULL;
klass->button_press_event = gtk_widget_real_button_event;
klass->button_release_event = gtk_widget_real_button_event;
klass->motion_notify_event = gtk_widget_real_motion_event;
klass->touch_event = gtk_widget_real_touch_event;
klass->delete_event = NULL;
klass->destroy_event = NULL;
@ -1112,7 +1132,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->drag_data_received = NULL;
klass->screen_changed = NULL;
klass->can_activate_accel = gtk_widget_real_can_activate_accel;
klass->grab_broken_event = NULL;
klass->grab_broken_event = gtk_widget_real_grab_broken_event;
klass->query_tooltip = gtk_widget_real_query_tooltip;
klass->style_updated = gtk_widget_real_style_updated;
@ -4027,6 +4047,307 @@ gtk_widget_get_property (GObject *object,
}
}
static void
_gtk_widget_emulate_press (GtkWidget *widget,
const GdkEvent *event)
{
GtkWidget *event_widget, *next_child, *parent;
GdkEvent *press;
event_widget = gtk_get_event_widget ((GdkEvent *) event);
if (event_widget == widget)
return;
if (event->type == GDK_TOUCH_BEGIN ||
event->type == GDK_TOUCH_UPDATE ||
event->type == GDK_TOUCH_END)
{
press = gdk_event_copy (event);
press->type = GDK_TOUCH_BEGIN;
}
else if (event->type == GDK_BUTTON_PRESS ||
event->type == GDK_BUTTON_RELEASE)
{
press = gdk_event_copy (event);
press->type = GDK_BUTTON_PRESS;
}
else if (event->type == GDK_MOTION_NOTIFY)
{
press = gdk_event_new (GDK_BUTTON_PRESS);
press->button.window = g_object_ref (event->motion.window);
press->button.time = event->motion.time;
press->button.x = event->motion.x;
press->button.y = event->motion.y;
press->button.x_root = event->motion.x_root;
press->button.y_root = event->motion.y_root;
press->button.state = event->motion.state;
press->button.axes = g_memdup (event->motion.axes,
sizeof (gdouble) *
gdk_device_get_n_axes (event->motion.device));
if (event->motion.state & GDK_BUTTON3_MASK)
press->button.button = 3;
else if (event->motion.state & GDK_BUTTON2_MASK)
press->button.button = 2;
else
{
if ((event->motion.state & GDK_BUTTON1_MASK) == 0)
g_critical ("Guessing button number 1 on generated button press event");
press->button.button = 1;
}
gdk_event_set_device (press, gdk_event_get_device (event));
gdk_event_set_source_device (press, gdk_event_get_source_device (event));
}
else
return;
press->any.send_event = TRUE;
next_child = event_widget;
parent = gtk_widget_get_parent (next_child);
while (parent != widget)
{
next_child = parent;
parent = gtk_widget_get_parent (parent);
}
/* Perform propagation state starting from the next child in the chain */
if (!_gtk_propagate_captured_event (event_widget, press, next_child))
gtk_propagate_event (event_widget, press);
gdk_event_free (press);
}
static const GdkEvent *
_gtk_widget_get_last_event (GtkWidget *widget,
GdkEventSequence *sequence)
{
GtkWidgetPrivate *priv = widget->priv;
EventControllerData *data;
const GdkEvent *event;
GList *l;
for (l = priv->event_controllers; l; l = l->next)
{
data = l->data;
if (!GTK_IS_GESTURE (data->controller))
continue;
event = gtk_gesture_get_last_event (GTK_GESTURE (data->controller),
sequence);
if (event)
return event;
}
return NULL;
}
static gboolean
_gtk_widget_get_emulating_sequence (GtkWidget *widget,
GdkEventSequence *sequence,
GdkEventSequence **sequence_out)
{
GtkWidgetPrivate *priv = widget->priv;
GList *l;
*sequence_out = sequence;
if (sequence)
{
const GdkEvent *last_event;
last_event = _gtk_widget_get_last_event (widget, sequence);
if (last_event &&
(last_event->type == GDK_TOUCH_BEGIN ||
last_event->type == GDK_TOUCH_UPDATE ||
last_event->type == GDK_TOUCH_END) &&
last_event->touch.emulating_pointer)
return TRUE;
}
else
{
/* For a NULL(pointer) sequence, find the pointer emulating one */
for (l = priv->event_controllers; l; l = l->next)
{
EventControllerData *data = l->data;
if (!GTK_IS_GESTURE (data->controller))
continue;
if (_gtk_gesture_get_pointer_emulating_sequence (GTK_GESTURE (data->controller),
sequence_out))
return TRUE;
}
}
return FALSE;
}
static gboolean
gtk_widget_needs_press_emulation (GtkWidget *widget,
GdkEventSequence *sequence)
{
GtkWidgetPrivate *priv = widget->priv;
gboolean sequence_press_handled = FALSE;
GList *l;
/* Check whether there is any remaining gesture in
* the capture phase that handled the press event
*/
for (l = priv->event_controllers; l; l = l->next)
{
EventControllerData *data;
GtkGesture *gesture;
data = l->data;
if (data->phase != GTK_PHASE_CAPTURE)
continue;
if (!GTK_IS_GESTURE (data->controller))
continue;
gesture = GTK_GESTURE (data->controller);
sequence_press_handled |=
(gtk_gesture_handles_sequence (gesture, sequence) &&
_gtk_gesture_handled_sequence_press (gesture, sequence));
}
return !sequence_press_handled;
}
static gint
_gtk_widget_set_sequence_state_internal (GtkWidget *widget,
GdkEventSequence *sequence,
GtkEventSequenceState state,
GtkGesture *emitter)
{
gboolean emulates_pointer, sequence_handled = FALSE;
GtkWidgetPrivate *priv = widget->priv;
const GdkEvent *mimic_event;
GList *group = NULL, *l;
GdkEventSequence *seq;
gint n_handled = 0;
if (!priv->event_controllers && state != GTK_EVENT_SEQUENCE_CLAIMED)
return TRUE;
if (emitter)
group = gtk_gesture_get_group (emitter);
emulates_pointer = _gtk_widget_get_emulating_sequence (widget, sequence, &seq);
mimic_event = _gtk_widget_get_last_event (widget, seq);
for (l = priv->event_controllers; l; l = l->next)
{
GtkEventSequenceState gesture_state;
EventControllerData *data;
GtkGesture *gesture;
gboolean retval;
seq = sequence;
data = l->data;
gesture_state = state;
if (!GTK_IS_GESTURE (data->controller))
continue;
gesture = GTK_GESTURE (data->controller);
if (gesture == emitter)
{
sequence_handled |=
_gtk_gesture_handled_sequence_press (gesture, sequence);
n_handled++;
continue;
}
if (seq && emulates_pointer &&
!gtk_gesture_handles_sequence (gesture, seq))
seq = NULL;
if (group && !g_list_find (group, data->controller))
{
/* If a group is provided, ensure only gestures pertaining to the group
* get a "claimed" state, all other claiming gestures must deny the sequence.
*/
if (gesture_state == GTK_EVENT_SEQUENCE_CLAIMED &&
gtk_gesture_get_sequence_state (gesture, sequence) == GTK_EVENT_SEQUENCE_CLAIMED)
gesture_state = GTK_EVENT_SEQUENCE_DENIED;
else
continue;
}
g_signal_handler_block (data->controller, data->sequence_state_changed_id);
retval = gtk_gesture_set_sequence_state (gesture, seq, gesture_state);
g_signal_handler_unblock (data->controller, data->sequence_state_changed_id);
if (retval || gesture == emitter)
{
sequence_handled |=
_gtk_gesture_handled_sequence_press (gesture, seq);
n_handled++;
}
}
/* If the sequence goes denied, check whether this is a controller attached
* to the capture phase, that additionally handled the button/touch press (ie.
* it was consumed), the corresponding press will be emulated for widgets
* beneath, so the widgets beneath get a coherent stream of events from now on.
*/
if (n_handled > 0 && sequence_handled &&
state == GTK_EVENT_SEQUENCE_DENIED &&
gtk_widget_needs_press_emulation (widget, sequence))
_gtk_widget_emulate_press (widget, mimic_event);
g_list_free (group);
return n_handled;
}
static gboolean
_gtk_widget_cancel_sequence (GtkWidget *widget,
GdkEventSequence *sequence)
{
GtkWidgetPrivate *priv = widget->priv;
gboolean emulates_pointer;
gboolean handled = FALSE;
GdkEventSequence *seq;
GList *l;
emulates_pointer = _gtk_widget_get_emulating_sequence (widget, sequence, &seq);
for (l = priv->event_controllers; l; l = l->next)
{
EventControllerData *data;
GtkGesture *gesture;
seq = sequence;
data = l->data;
if (!GTK_IS_GESTURE (data->controller))
continue;
gesture = GTK_GESTURE (data->controller);
if (seq && emulates_pointer &&
!gtk_gesture_handles_sequence (gesture, seq))
seq = NULL;
if (!gtk_gesture_handles_sequence (gesture, seq))
continue;
handled |= _gtk_gesture_cancel_sequence (gesture, seq);
}
return handled;
}
static void
gtk_widget_init (GtkWidget *widget)
{
@ -6783,6 +7104,22 @@ gtk_widget_draw (GtkWidget *widget,
_gtk_widget_draw (widget, cr);
}
static gboolean
gtk_widget_real_button_event (GtkWidget *widget,
GdkEventButton *event)
{
return _gtk_widget_run_controllers (widget, (GdkEvent *) event,
GTK_PHASE_TARGET);
}
static gboolean
gtk_widget_real_motion_event (GtkWidget *widget,
GdkEventMotion *event)
{
return _gtk_widget_run_controllers (widget, (GdkEvent *) event,
GTK_PHASE_TARGET);
}
static gboolean
gtk_widget_real_key_press_event (GtkWidget *widget,
GdkEventKey *event)
@ -6824,7 +7161,8 @@ gtk_widget_real_touch_event (GtkWidget *widget,
gint signum;
if (!event->emulating_pointer)
return FALSE;
return _gtk_widget_run_controllers (widget, (GdkEvent*) event,
GTK_PHASE_TARGET);
if (event->type == GDK_TOUCH_BEGIN ||
event->type == GDK_TOUCH_END)
@ -6884,6 +7222,13 @@ gtk_widget_real_touch_event (GtkWidget *widget,
return return_val;
}
static gboolean
gtk_widget_real_grab_broken_event (GtkWidget *widget,
GdkEventGrabBroken *event)
{
return _gtk_widget_run_controllers (widget, (GdkEvent*) event,
GTK_PHASE_TARGET);
}
#define WIDGET_REALIZED_FOR_EVENT(widget, event) \
(event->type == GDK_FOCUS_CHANGE || gtk_widget_get_realized(widget))
@ -6930,6 +7275,61 @@ _gtk_widget_set_captured_event_handler (GtkWidget *widget,
g_object_set_data (G_OBJECT (widget), "captured-event-handler", callback);
}
static GdkEventMask
_gtk_widget_get_controllers_evmask (GtkWidget *widget)
{
EventControllerData *data;
GdkEventMask evmask = 0;
GtkWidgetPrivate *priv;
GList *l;
priv = widget->priv;
for (l = priv->event_controllers; l; l = l->next)
{
data = l->data;
if (data->controller)
evmask |= gtk_event_controller_get_event_mask (GTK_EVENT_CONTROLLER (data->controller));
}
return evmask;
}
static gboolean
_gtk_widget_run_controllers (GtkWidget *widget,
const GdkEvent *event,
GtkPropagationPhase phase)
{
EventControllerData *data;
gboolean handled = FALSE;
GtkWidgetPrivate *priv;
GList *l;
priv = widget->priv;
g_object_ref (widget);
l = priv->event_controllers;
while (l != NULL)
{
GList *next = l->next;
data = l->data;
if (data->controller == NULL)
{
priv->event_controllers = g_list_delete_link (priv->event_controllers, l);
g_free (data);
}
else if (data->phase == phase)
handled |= gtk_event_controller_handle_event (data->controller, event);
l = next;
}
g_object_unref (widget);
return handled;
}
gboolean
_gtk_widget_captured_event (GtkWidget *widget,
GdkEvent *event)
@ -6951,13 +7351,15 @@ _gtk_widget_captured_event (GtkWidget *widget,
if (!event_window_is_still_viewable (event))
return TRUE;
return_val = _gtk_widget_run_controllers (widget, event, GTK_PHASE_CAPTURE);
handler = g_object_get_data (G_OBJECT (widget), "captured-event-handler");
if (!handler)
return FALSE;
return return_val;
g_object_ref (widget);
return_val = handler (widget, event);
return_val |= handler (widget, event);
return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
/* The widget that was originally to receive the event
@ -7143,7 +7545,7 @@ static gint
gtk_widget_event_internal (GtkWidget *widget,
GdkEvent *event)
{
gboolean return_val = FALSE;
gboolean return_val = FALSE, handled;
/* We check only once for is-still-visible; if someone
* hides the window in on of the signals on the widget,
@ -7155,8 +7557,8 @@ gtk_widget_event_internal (GtkWidget *widget,
g_object_ref (widget);
g_signal_emit (widget, widget_signals[EVENT], 0, event, &return_val);
return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
g_signal_emit (widget, widget_signals[EVENT], 0, event, &handled);
return_val |= handled | !WIDGET_REALIZED_FOR_EVENT (widget, event);
if (!return_val)
{
gint signal_num;
@ -7258,13 +7660,18 @@ gtk_widget_event_internal (GtkWidget *widget,
break;
}
if (signal_num != -1)
g_signal_emit (widget, widget_signals[signal_num], 0, event, &return_val);
{
g_signal_emit (widget, widget_signals[signal_num], 0, event, &handled);
return_val |= handled;
}
}
if (WIDGET_REALIZED_FOR_EVENT (widget, event))
g_signal_emit (widget, widget_signals[EVENT_AFTER], 0, event);
else
return_val = TRUE;
return_val |= _gtk_widget_run_controllers (widget, event, GTK_PHASE_BUBBLE);
g_object_unref (widget);
return return_val;
@ -10701,8 +11108,11 @@ gtk_widget_add_events_internal_list (GtkWidget *widget,
gint events,
GList *window_list)
{
GdkEventMask controllers_mask;
GList *l;
controllers_mask = _gtk_widget_get_controllers_evmask (widget);
for (l = window_list; l != NULL; l = l->next)
{
GdkWindow *window = l->data;
@ -10714,9 +11124,16 @@ gtk_widget_add_events_internal_list (GtkWidget *widget,
GList *children;
if (device)
gdk_window_set_device_events (window, device, gdk_window_get_events (window) | events);
{
gdk_window_set_device_events (window, device,
gdk_window_get_events (window) |
events | controllers_mask);
}
else
gdk_window_set_events (window, gdk_window_get_events (window) | events);
{
gdk_window_set_events (window, gdk_window_get_events (window) |
events | controllers_mask);
}
children = gdk_window_get_children (window);
gtk_widget_add_events_internal_list (widget, device, events, children);
@ -11375,6 +11792,7 @@ gtk_widget_dispose (GObject *object)
{
GtkWidget *widget = GTK_WIDGET (object);
GtkWidgetPrivate *priv = widget->priv;
GList *l;
if (priv->parent)
gtk_container_remove (GTK_CONTAINER (priv->parent), widget);
@ -11397,6 +11815,15 @@ gtk_widget_dispose (GObject *object)
while (priv->attached_windows)
gtk_window_set_attached_to (priv->attached_windows->data, NULL);
for (l = priv->event_controllers; l; l = l->next)
{
EventControllerData *data = l->data;
if (data->controller)
_gtk_widget_remove_controller (widget, data->controller);
}
g_list_free_full (priv->event_controllers, g_free);
priv->event_controllers = NULL;
G_OBJECT_CLASS (gtk_widget_parent_class)->dispose (object);
}
@ -16277,3 +16704,211 @@ _gtk_widget_get_action_group (GtkWidget *widget,
return gtk_action_muxer_lookup (widget->priv->muxer, prefix);
return NULL;
}
static void
event_controller_grab_notify (GtkWidget *widget,
gboolean was_grabbed,
EventControllerData *data)
{
GtkWidget *grab_widget, *toplevel;
GtkWindowGroup *group;
GdkDevice *device;
device = gtk_gesture_get_device (GTK_GESTURE (data->controller));
if (!device)
return;
toplevel = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (toplevel))
group = gtk_window_get_group (GTK_WINDOW (toplevel));
else
group = gtk_window_get_group (NULL);
grab_widget = gtk_window_group_get_current_device_grab (group, device);
if (!grab_widget)
grab_widget = gtk_window_group_get_current_grab (group);
if (!grab_widget || grab_widget == widget)
return;
if ((data->phase != GTK_PHASE_CAPTURE &&
!gtk_widget_is_ancestor (widget, grab_widget)) ||
(data->phase == GTK_PHASE_CAPTURE &&
!gtk_widget_is_ancestor (widget, grab_widget) &&
!gtk_widget_is_ancestor (grab_widget, widget)))
{
gtk_event_controller_reset (data->controller);
}
}
static void
_gtk_widget_update_evmask (GtkWidget *widget)
{
if (gtk_widget_get_realized (widget))
{
gint events = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (widget),
quark_event_mask));
gtk_widget_add_events_internal (widget, NULL, events);
}
}
static void
event_controller_notify_event_mask (GtkEventController *controller,
GParamSpec *pspec,
GtkWidget *widget)
{
_gtk_widget_update_evmask (widget);
}
static void
event_controller_sequence_state_changed (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkEventSequenceState state,
GtkWidget *widget)
{
gboolean handled = FALSE;
GtkWidget *event_widget;
gboolean cancel = TRUE;
const GdkEvent *event;
handled = _gtk_widget_set_sequence_state_internal (widget, sequence,
state, gesture);
if (!handled || state != GTK_EVENT_SEQUENCE_CLAIMED)
return;
event = _gtk_widget_get_last_event (widget, sequence);
if (!event)
return;
event_widget = gtk_get_event_widget ((GdkEvent *) event);
while (event_widget)
{
if (event_widget == widget)
cancel = FALSE;
else if (cancel)
_gtk_widget_cancel_sequence (event_widget, sequence);
else
_gtk_widget_set_sequence_state_internal (event_widget, sequence,
GTK_EVENT_SEQUENCE_DENIED,
NULL);
event_widget = gtk_widget_get_parent (event_widget);
}
}
EventControllerData *
_gtk_widget_has_controller (GtkWidget *widget,
GtkEventController *controller)
{
EventControllerData *data;
GtkWidgetPrivate *priv;
GList *l;
priv = widget->priv;
for (l = priv->event_controllers; l; l = l->next)
{
data = l->data;
if (data->controller == controller)
return data;
}
return NULL;
}
void
_gtk_widget_add_controller (GtkWidget *widget,
GtkEventController *controller,
GtkPropagationPhase phase)
{
EventControllerData *data;
GtkWidgetPrivate *priv;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
g_return_if_fail (widget == gtk_event_controller_get_widget (controller));
g_return_if_fail (phase >= GTK_PHASE_NONE && phase <= GTK_PHASE_TARGET);
priv = widget->priv;
data = _gtk_widget_has_controller (widget, controller);
if (data)
{
data->phase = phase;
return;
}
data = g_new0 (EventControllerData, 1);
data->controller = g_object_ref (controller);
data->phase = phase;
data->evmask_notify_id =
g_signal_connect (controller, "notify::event-mask",
G_CALLBACK (event_controller_notify_event_mask), widget);
data->grab_notify_id =
g_signal_connect (widget, "grab-notify",
G_CALLBACK (event_controller_grab_notify), data);
if (GTK_IS_GESTURE (controller))
{
data->sequence_state_changed_id =
g_signal_connect (controller, "sequence-state-changed",
G_CALLBACK (event_controller_sequence_state_changed),
widget);
}
priv->event_controllers = g_list_prepend (priv->event_controllers, data);
_gtk_widget_update_evmask (widget);
}
void
_gtk_widget_remove_controller (GtkWidget *widget,
GtkEventController *controller)
{
EventControllerData *data;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
data = _gtk_widget_has_controller (widget, controller);
if (!data)
return;
if (g_signal_handler_is_connected (widget, data->grab_notify_id))
g_signal_handler_disconnect (widget, data->grab_notify_id);
g_signal_handler_disconnect (data->controller, data->evmask_notify_id);
g_signal_handler_disconnect (data->controller, data->sequence_state_changed_id);
gtk_event_controller_reset (GTK_EVENT_CONTROLLER (data->controller));
g_object_unref (data->controller);
data->controller = NULL;
}
GList *
_gtk_widget_list_controllers (GtkWidget *widget,
GtkPropagationPhase phase)
{
EventControllerData *data;
GtkWidgetPrivate *priv;
GList *l, *retval = NULL;
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
priv = widget->priv;
for (l = priv->event_controllers; l; l = l->next)
{
data = l->data;
if (data->phase == phase && data->controller != NULL)
retval = g_list_prepend (retval, data->controller);
}
return retval;
}

View File

@ -33,6 +33,7 @@
#include <gtk/gtkaccelgroup.h>
#include <gtk/gtkborder.h>
#include <gtk/gtktypes.h>
#include <gtk/gtkgesture.h>
#include <atk/atk.h>
G_BEGIN_DECLS

View File

@ -152,6 +152,14 @@ gchar ** _gtk_widget_list_action_prefixes (GtkWidget *widget
GActionGroup * _gtk_widget_get_action_group (GtkWidget *widget,
const gchar *prefix);
void _gtk_widget_add_controller (GtkWidget *widget,
GtkEventController *controller,
GtkPropagationPhase phase);
void _gtk_widget_remove_controller (GtkWidget *widget,
GtkEventController *controller);
GList * _gtk_widget_list_controllers (GtkWidget *widget,
GtkPropagationPhase phase);
G_END_DECLS
#endif /* __GTK_WIDGET_PRIVATE_H__ */

View File

@ -234,9 +234,7 @@ struct _GtkWindowPrivate
guint drag_possible : 1;
gint button_press_x;
gint button_press_y;
guint32 button_press_time;
GtkGesture *multipress_gesture;
};
enum {
@ -387,6 +385,9 @@ struct _GtkWindowGroupPrivate
GSList *device_grabs;
};
static GObject *gtk_window_constructor (GType type,
guint n_params,
GObjectConstructParam *params);
static void gtk_window_dispose (GObject *object);
static void gtk_window_finalize (GObject *object);
static void gtk_window_destroy (GtkWidget *widget);
@ -406,12 +407,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,
@ -582,6 +577,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)
@ -668,6 +668,7 @@ gtk_window_class_init (GtkWindowClass *klass)
quark_gtk_window_icon_info = g_quark_from_static_string ("gtk-window-icon-info");
quark_gtk_buildable_accels = g_quark_from_static_string ("gtk-window-buildable-accels");
gobject_class->constructor = gtk_window_constructor;
gobject_class->dispose = gtk_window_dispose;
gobject_class->finalize = gtk_window_finalize;
@ -687,9 +688,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;
@ -1382,6 +1380,131 @@ popover_destroy (GtkWindowPopover *popover)
g_free (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);
if (!event)
return;
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_gesture_set_sequence_state (GTK_GESTURE (gesture),
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_gesture_set_sequence_state (GTK_GESTURE (gesture),
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_gesture_set_sequence_state (GTK_GESTURE (gesture),
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_gesture_set_sequence_state (GTK_GESTURE (gesture),
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));
}
gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
priv->drag_possible = FALSE;
}
static void
gtk_window_init (GtkWindow *window)
{
@ -1453,6 +1576,31 @@ gtk_window_init (GtkWindow *window)
priv->scale = gtk_widget_get_scale_factor (widget);
}
static GObject *
gtk_window_constructor (GType type,
guint n_params,
GObjectConstructParam *params)
{
GObject *object;
GtkWindowPrivate *priv;
object = G_OBJECT_CLASS (gtk_window_parent_class)->constructor (type, n_params, params);
priv = GTK_WINDOW (object)->priv;
if (priv->type == GTK_WINDOW_TOPLEVEL)
{
priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (object));
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), object);
g_signal_connect (priv->multipress_gesture, "stopped",
G_CALLBACK (multipress_gesture_stopped_cb), object);
gtk_gesture_attach (priv->multipress_gesture, GTK_PHASE_CAPTURE);
}
return object;
}
static void
gtk_window_set_property (GObject *object,
guint prop_id,
@ -5333,6 +5481,12 @@ gtk_window_finalize (GObject *object)
priv->mnemonics_display_timeout_id = 0;
}
if (priv->multipress_gesture)
{
gtk_gesture_detach (priv->multipress_gesture);
g_object_unref (priv->multipress_gesture);
}
G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
}
@ -7727,234 +7881,26 @@ 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)
{
GtkWindowPrivate *priv;
GtkWidget *widget;
widget = gtk_get_event_widget (event);
if (!GTK_IS_WINDOW (widget))
return FALSE;
if (GTK_IS_WINDOW (widget) &&
(event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE ||
event->type == GDK_TOUCH_BEGIN || event->type == GDK_TOUCH_UPDATE ||
event->type == GDK_MOTION_NOTIFY || event->type == GDK_TOUCH_END))
{
priv = GTK_WINDOW (widget)->priv;
if (priv->multipress_gesture)
return gtk_event_controller_handle_event (GTK_EVENT_CONTROLLER (priv->multipress_gesture),
(const GdkEvent*) event);
}
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;
return FALSE;
}
static void

View File

@ -27,6 +27,8 @@ libgtkinspector_la_SOURCES = \
data-list.c \
general.h \
general.c \
gestures.h \
gestures.c \
init.h \
init.c \
inspect-button.c \

262
gtk/inspector/gestures.c Normal file
View File

@ -0,0 +1,262 @@
/*
* Copyright (c) 2014 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 <glib/gi18n-lib.h>
#include "gestures.h"
#include "gtkwidgetprivate.h"
#include "widget-tree.h"
enum
{
PROP_0,
PROP_WIDGET_TREE
};
struct _GtkInspectorGesturesPrivate
{
GtkSizeGroup *sizegroup;
GObject *object;
GtkWidget *widget_tree;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorGestures, gtk_inspector_gestures, GTK_TYPE_BOX)
static void
gtk_inspector_gestures_init (GtkInspectorGestures *sl)
{
sl->priv = gtk_inspector_gestures_get_instance_private (sl);
sl->priv->sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
g_object_set (sl,
"orientation", GTK_ORIENTATION_VERTICAL,
"margin", 60,
"spacing", 10,
NULL);
}
static void
clear_all (GtkInspectorGestures *sl)
{
GList *children, *l;
GtkWidget *child;
children = gtk_container_get_children (GTK_CONTAINER (sl));
for (l = children; l; l = l->next)
{
child = l->data;
gtk_container_remove (GTK_CONTAINER (sl), child);
}
g_list_free (children);
}
static void
phase_changed_cb (GtkComboBox *combo, GtkInspectorGestures *sl)
{
GtkWidget *row;
GtkPropagationPhase phase;
GtkGesture *gesture;
phase = gtk_combo_box_get_active (combo);
row = gtk_widget_get_ancestor (GTK_WIDGET (combo), GTK_TYPE_LIST_BOX_ROW);
gesture = GTK_GESTURE (g_object_get_data (G_OBJECT (row), "gesture"));
gtk_gesture_attach (gesture, phase);
}
static void
row_activated (GtkListBox *box,
GtkListBoxRow *row,
GtkInspectorGestures *sl)
{
GObject *gesture;
gesture = G_OBJECT (g_object_get_data (G_OBJECT (row), "gesture"));
gtk_inspector_widget_tree_select_object (GTK_INSPECTOR_WIDGET_TREE (sl->priv->widget_tree),
gesture);
}
static void
add_gesture (GtkInspectorGestures *sl,
GObject *object,
GtkWidget *listbox,
GtkGesture *gesture,
GtkPropagationPhase phase)
{
GtkWidget *row;
GtkWidget *box;
GtkWidget *label;
GtkWidget *combo;
row = gtk_list_box_row_new ();
gtk_container_add (GTK_CONTAINER (listbox), row);
gtk_widget_show (row);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 40);
gtk_container_add (GTK_CONTAINER (row), box);
g_object_set (box, "margin", 10, NULL);
gtk_widget_show (box);
label = gtk_label_new (g_type_name_from_instance ((GTypeInstance*)gesture));
g_object_set (label, "xalign", 0.0, NULL);
gtk_container_add (GTK_CONTAINER (box), label);
gtk_size_group_add_widget (sl->priv->sizegroup, label);
gtk_widget_show (label);
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
combo = gtk_combo_box_text_new ();
gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combo), GTK_PHASE_NONE, _("None"));
gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combo), GTK_PHASE_CAPTURE, _("Capture"));
gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combo), GTK_PHASE_BUBBLE, _("Bubble"));
gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combo), GTK_PHASE_TARGET, _("Target"));
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), phase);
gtk_container_add (GTK_CONTAINER (box), combo);
gtk_widget_show (combo);
gtk_widget_set_halign (label, GTK_ALIGN_END);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
g_object_set_data (G_OBJECT (row), "gesture", gesture);
g_signal_connect (combo, "changed", G_CALLBACK (phase_changed_cb), sl);
}
static void
add_gesture_group (GtkInspectorGestures *sl,
GObject *object,
GtkGesture *gesture,
GHashTable *hash)
{
GtkWidget *frame;
GtkWidget *listbox;
GList *list, *l;
GtkGesture *g;
GtkPropagationPhase phase;
frame = gtk_frame_new (NULL);
gtk_widget_show (frame);
gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
listbox = gtk_list_box_new ();
g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), sl);
gtk_container_add (GTK_CONTAINER (frame), listbox);
gtk_widget_show (listbox);
gtk_list_box_set_selection_mode (GTK_LIST_BOX (listbox), GTK_SELECTION_NONE);
list = gtk_gesture_get_group (gesture);
for (l = list; l; l = l->next)
{
g = l->data;
phase = GPOINTER_TO_INT (g_hash_table_lookup (hash, g));
add_gesture (sl, object, listbox, g, phase);
g_hash_table_remove (hash, g);
}
g_list_free (list);
gtk_container_add (GTK_CONTAINER (sl), frame);
}
void
gtk_inspector_gestures_set_object (GtkInspectorGestures *sl,
GObject *object)
{
clear_all (sl);
if (GTK_IS_WIDGET (object))
{
GHashTable *hash;
GHashTableIter iter;
GList *list, *l;
gint phase;
hash = g_hash_table_new (g_direct_hash, g_direct_equal);
for (phase = GTK_PHASE_NONE; phase <= GTK_PHASE_TARGET; phase++)
{
list = _gtk_widget_list_controllers (GTK_WIDGET (object), phase);
for (l = list; l; l = l->next)
g_hash_table_insert (hash, l->data, GINT_TO_POINTER (phase));
g_list_free (list);
}
while (g_hash_table_size (hash) > 0)
{
gpointer key, value;
GtkGesture *gesture;
g_hash_table_iter_init (&iter, hash);
g_hash_table_iter_next (&iter, &key, &value);
gesture = key;
add_gesture_group (sl, object, gesture, hash);
}
g_hash_table_unref (hash);
gtk_widget_show (GTK_WIDGET (sl));
}
else
gtk_widget_hide (GTK_WIDGET (sl));
}
static void
get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
GtkInspectorGestures *sl = GTK_INSPECTOR_GESTURES (object);
switch (param_id)
{
case PROP_WIDGET_TREE:
g_value_take_object (value, sl->priv->widget_tree);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
GtkInspectorGestures *sl = GTK_INSPECTOR_GESTURES (object);
switch (param_id)
{
case PROP_WIDGET_TREE:
sl->priv->widget_tree = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gtk_inspector_gestures_class_init (GtkInspectorGesturesClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = get_property;
object_class->set_property = set_property;
g_object_class_install_property (object_class, PROP_WIDGET_TREE,
g_param_spec_object ("widget-tree", "Widget Tree", "Widget tree",
GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
// vim: set et sw=2 ts=2:

54
gtk/inspector/gestures.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2014 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/>.
*/
#ifndef _GTK_INSPECTOR_GESTURES_H_
#define _GTK_INSPECTOR_GESTURES_H_
#include <gtk/gtk.h>
#define GTK_TYPE_INSPECTOR_GESTURES (gtk_inspector_gestures_get_type())
#define GTK_INSPECTOR_GESTURES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_INSPECTOR_GESTURES, GtkInspectorGestures))
#define GTK_INSPECTOR_GESTURES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_INSPECTOR_GESTURES, GtkInspectorGesturesClass))
#define GTK_INSPECTOR_IS_GESTURES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_INSPECTOR_GESTURES))
#define GTK_INSPECTOR_IS_GESTURES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_INSPECTOR_GESTURES))
#define GTK_INSPECTOR_GESTURES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_INSPECTOR_GESTURES, GtkInspectorGesturesClass))
typedef struct _GtkInspectorGesturesPrivate GtkInspectorGesturesPrivate;
typedef struct _GtkInspectorGestures
{
GtkBox parent;
GtkInspectorGesturesPrivate *priv;
} GtkInspectorGestures;
typedef struct _GtkInspectorGesturesClass
{
GtkBoxClass parent;
} GtkInspectorGesturesClass;
G_BEGIN_DECLS
GType gtk_inspector_gestures_get_type (void);
void gtk_inspector_gestures_set_object (GtkInspectorGestures *sl,
GObject *object);
G_END_DECLS
#endif // _GTK_INSPECTOR_GESTURES_H_
// vim: set et sw=2 ts=2:

View File

@ -28,6 +28,7 @@
#include "css-editor.h"
#include "data-list.h"
#include "general.h"
#include "gestures.h"
#include "object-hierarchy.h"
#include "prop-list.h"
#include "python-hooks.h"
@ -55,6 +56,7 @@ gtk_inspector_init (void)
g_type_ensure (GTK_TYPE_INSPECTOR_CSS_EDITOR);
g_type_ensure (GTK_TYPE_INSPECTOR_DATA_LIST);
g_type_ensure (GTK_TYPE_INSPECTOR_GENERAL);
g_type_ensure (GTK_TYPE_INSPECTOR_GESTURES);
g_type_ensure (GTK_TYPE_INSPECTOR_OBJECT_HIERARCHY);
g_type_ensure (GTK_TYPE_INSPECTOR_PROP_LIST);
g_type_ensure (GTK_TYPE_INSPECTOR_PYTHON_SHELL);

View File

@ -24,6 +24,7 @@
#include "prop-list.h"
#include "widget-tree.h"
#include "gtkwidgetprivate.h"
#include <string.h>
enum
@ -316,6 +317,33 @@ gtk_inspector_widget_tree_append_object (GtkInspectorWidgetTree *wt,
g_free (address);
if (GTK_IS_WIDGET (object))
{
struct {
GtkPropagationPhase phase;
const gchar *name;
} phases[] = {
{ GTK_PHASE_CAPTURE, "capture" },
{ GTK_PHASE_TARGET, "target" },
{ GTK_PHASE_BUBBLE, "bubble" },
{ GTK_PHASE_NONE, "" }
};
gint i;
for (i = 0; i < G_N_ELEMENTS (phases); i++)
{
GList *list, *l;
list = _gtk_widget_list_controllers (GTK_WIDGET (object), phases[i].phase);
for (l = list; l; l = l->next)
{
GObject *controller = l->data;
gtk_inspector_widget_tree_append_object (wt, controller, &iter, phases[i].name);
}
g_list_free (list);
}
}
if (GTK_IS_CONTAINER (object))
{
FindAllData data;

View File

@ -36,6 +36,7 @@
#include "button-path.h"
#include "size-groups.h"
#include "data-list.h"
#include "gestures.h"
#include "signals-list.h"
#include "actions.h"
@ -74,6 +75,8 @@ on_widget_tree_selection_changed (GtkInspectorWidgetTree *wt,
gtk_inspector_size_groups_set_object (GTK_INSPECTOR_SIZE_GROUPS (iw->size_groups), selected);
gtk_inspector_data_list_set_object (GTK_INSPECTOR_DATA_LIST (iw->data_list), selected);
gtk_inspector_actions_set_object (GTK_INSPECTOR_ACTIONS (iw->actions), selected);
gtk_inspector_gestures_set_object (GTK_INSPECTOR_GESTURES (iw->gestures), selected);
if (GTK_IS_WIDGET (selected))
gtk_inspector_flash_widget (iw, GTK_WIDGET (selected));
}
@ -173,6 +176,7 @@ gtk_inspector_window_class_init (GtkInspectorWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, size_groups);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, data_list);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, actions);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, gestures);
gtk_widget_class_bind_template_callback (widget_class, on_inspect);
gtk_widget_class_bind_template_callback (widget_class, on_widget_tree_selection_changed);

View File

@ -53,6 +53,7 @@ typedef struct
GtkWidget *size_groups;
GtkWidget *data_list;
GtkWidget *actions;
GtkWidget *gestures;
GtkWidget *widget_popup;

View File

@ -239,6 +239,17 @@
<property name="label" translatable="yes">Actions</property>
</object>
</child>
<child>
<object class="GtkInspectorGestures" id="gestures">
<property name="widget-tree">widget_tree</property>
</object>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Gestures</property>
</object>
</child>
</object>
<packing>
<property name="resize">True</property>

View File

@ -276,6 +276,7 @@ gtk/inspector/css-editor.c
gtk/inspector/css-editor.ui.h
gtk/inspector/data-list.ui.h
gtk/inspector/general.ui.h
gtk/inspector/gestures.c
gtk/inspector/inspect-button.c
gtk/inspector/object-hierarchy.ui.h
gtk/inspector/prop-editor.c