forked from AuroraMiddleware/gtk
Merge branch 'gestures'
This commit is contained in:
commit
bd35df05a5
@ -24,6 +24,7 @@ demos = \
|
||||
entry_completion.c \
|
||||
event_axes.c \
|
||||
expander.c \
|
||||
gestures.c \
|
||||
headerbar.c \
|
||||
hypertext.c \
|
||||
iconview.c \
|
||||
|
@ -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
|
||||
|
@ -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
195
demos/gtk-demo/gestures.c
Normal 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;
|
||||
}
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
10
gtk/gtk.h
10
gtk/gtk.h
@ -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>
|
||||
|
121
gtk/gtkbutton.c
121
gtk/gtkbutton.c
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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"),
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
100
gtk/gtkdnd.c
100
gtk/gtkdnd.c
@ -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;
|
||||
|
747
gtk/gtkentry.c
747
gtk/gtkentry.c
File diff suppressed because it is too large
Load Diff
@ -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
314
gtk/gtkeventcontroller.c
Normal 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
64
gtk/gtkeventcontroller.h
Normal 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__ */
|
42
gtk/gtkeventcontrollerprivate.h
Normal file
42
gtk/gtkeventcontrollerprivate.h
Normal 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
1596
gtk/gtkgesture.c
Normal file
File diff suppressed because it is too large
Load Diff
120
gtk/gtkgesture.h
Normal file
120
gtk/gtkgesture.h
Normal 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
272
gtk/gtkgesturedrag.c
Normal 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
58
gtk/gtkgesturedrag.h
Normal 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__ */
|
47
gtk/gtkgesturedragprivate.h
Normal file
47
gtk/gtkgesturedragprivate.h
Normal 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
268
gtk/gtkgesturelongpress.c
Normal 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
49
gtk/gtkgesturelongpress.h
Normal 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__ */
|
44
gtk/gtkgesturelongpressprivate.h
Normal file
44
gtk/gtkgesturelongpressprivate.h
Normal 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
465
gtk/gtkgesturemultipress.c
Normal 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;
|
||||
}
|
56
gtk/gtkgesturemultipress.h
Normal file
56
gtk/gtkgesturemultipress.h
Normal 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__ */
|
48
gtk/gtkgesturemultipressprivate.h
Normal file
48
gtk/gtkgesturemultipressprivate.h
Normal 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
343
gtk/gtkgesturepan.c
Normal 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
58
gtk/gtkgesturepan.h
Normal 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__ */
|
42
gtk/gtkgesturepanprivate.h
Normal file
42
gtk/gtkgesturepanprivate.h
Normal 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
75
gtk/gtkgestureprivate.h
Normal 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
227
gtk/gtkgesturerotate.c
Normal 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
54
gtk/gtkgesturerotate.h
Normal 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__ */
|
42
gtk/gtkgesturerotateprivate.h
Normal file
42
gtk/gtkgesturerotateprivate.h
Normal 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
504
gtk/gtkgesturesingle.c
Normal 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
75
gtk/gtkgesturesingle.h
Normal 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__ */
|
40
gtk/gtkgesturesingleprivate.h
Normal file
40
gtk/gtkgesturesingleprivate.h
Normal 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
279
gtk/gtkgestureswipe.c
Normal 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
55
gtk/gtkgestureswipe.h
Normal 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__ */
|
43
gtk/gtkgestureswipeprivate.h
Normal file
43
gtk/gtkgestureswipeprivate.h
Normal 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
220
gtk/gtkgesturezoom.c
Normal 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
54
gtk/gtkgesturezoom.h
Normal 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__ */
|
41
gtk/gtkgesturezoomprivate.h
Normal file
41
gtk/gtkgesturezoomprivate.h
Normal 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__ */
|
@ -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;
|
||||
|
||||
|
@ -52,6 +52,7 @@ OBJECT:VOID
|
||||
STRING:DOUBLE
|
||||
STRING:STRING
|
||||
VOID:DOUBLE
|
||||
VOID:DOUBLE,DOUBLE
|
||||
VOID:BOOLEAN
|
||||
VOID:BOOLEAN,BOOLEAN,BOOLEAN
|
||||
VOID:BOXED
|
||||
|
292
gtk/gtkpaned.c
292
gtk/gtkpaned.c
@ -110,10 +110,11 @@ struct _GtkPanedPrivate
|
||||
GtkOrientation orientation;
|
||||
|
||||
GdkCursorType cursor_type;
|
||||
GdkDevice *grab_device;
|
||||
GdkRectangle handle_pos;
|
||||
GdkWindow *handle;
|
||||
|
||||
GtkGesture *pan_gesture;
|
||||
|
||||
gint child1_size;
|
||||
gint drag_pos;
|
||||
gint last_allocation;
|
||||
@ -121,16 +122,14 @@ struct _GtkPanedPrivate
|
||||
gint min_position;
|
||||
gint original_position;
|
||||
|
||||
guint32 grab_time;
|
||||
|
||||
guint handle_prelit : 1;
|
||||
guint in_drag : 1;
|
||||
guint in_recursion : 1;
|
||||
guint child1_resize : 1;
|
||||
guint child1_shrink : 1;
|
||||
guint child2_resize : 1;
|
||||
guint child2_shrink : 1;
|
||||
guint position_set : 1;
|
||||
guint panning : 1;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -209,16 +208,8 @@ static gboolean gtk_paned_enter (GtkWidget *widget,
|
||||
GdkEventCrossing *event);
|
||||
static gboolean gtk_paned_leave (GtkWidget *widget,
|
||||
GdkEventCrossing *event);
|
||||
static gboolean gtk_paned_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
static gboolean gtk_paned_button_release (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
static gboolean gtk_paned_motion (GtkWidget *widget,
|
||||
GdkEventMotion *event);
|
||||
static gboolean gtk_paned_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static gboolean gtk_paned_grab_broken (GtkWidget *widget,
|
||||
GdkEventGrabBroken *event);
|
||||
static void gtk_paned_add (GtkContainer *container,
|
||||
GtkWidget *widget);
|
||||
static void gtk_paned_remove (GtkContainer *container,
|
||||
@ -252,9 +243,10 @@ static gboolean gtk_paned_cancel_position (GtkPaned *paned);
|
||||
static gboolean gtk_paned_toggle_handle_focus (GtkPaned *paned);
|
||||
|
||||
static GType gtk_paned_child_type (GtkContainer *container);
|
||||
static void gtk_paned_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
|
||||
static void update_drag (GtkPaned *paned,
|
||||
int xpos,
|
||||
int ypos);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkPaned, gtk_paned, GTK_TYPE_CONTAINER,
|
||||
G_ADD_PRIVATE (GtkPaned)
|
||||
@ -316,11 +308,6 @@ gtk_paned_class_init (GtkPanedClass *class)
|
||||
widget_class->focus = gtk_paned_focus;
|
||||
widget_class->enter_notify_event = gtk_paned_enter;
|
||||
widget_class->leave_notify_event = gtk_paned_leave;
|
||||
widget_class->button_press_event = gtk_paned_button_press;
|
||||
widget_class->button_release_event = gtk_paned_button_release;
|
||||
widget_class->motion_notify_event = gtk_paned_motion;
|
||||
widget_class->grab_broken_event = gtk_paned_grab_broken;
|
||||
widget_class->grab_notify = gtk_paned_grab_notify;
|
||||
widget_class->state_flags_changed = gtk_paned_state_flags_changed;
|
||||
|
||||
container_class->add = gtk_paned_add;
|
||||
@ -667,10 +654,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 paned’s 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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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__ */
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
275
gtk/gtkswitch.c
275
gtk/gtkswitch.c
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
@ -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)));
|
||||
|
661
gtk/gtkwidget.c
661
gtk/gtkwidget.c
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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__ */
|
||||
|
410
gtk/gtkwindow.c
410
gtk/gtkwindow.c
@ -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
|
||||
|
@ -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
262
gtk/inspector/gestures.c
Normal 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
54
gtk/inspector/gestures.h
Normal 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:
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -53,6 +53,7 @@ typedef struct
|
||||
GtkWidget *size_groups;
|
||||
GtkWidget *data_list;
|
||||
GtkWidget *actions;
|
||||
GtkWidget *gestures;
|
||||
|
||||
GtkWidget *widget_popup;
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user