1 | /* Gestures |
2 | * #Keywords: GtkGesture |
3 | * |
4 | * Perform gestures on touchscreens and other input devices. This |
5 | * demo reacts to long presses and swipes from all devices, plus |
6 | * multi-touch rotate and zoom gestures. |
7 | */ |
8 | |
9 | #include <gtk/gtk.h> |
10 | |
11 | static GtkGesture *rotate = NULL; |
12 | static GtkGesture *zoom = NULL; |
13 | static double swipe_x = 0; |
14 | static double swipe_y = 0; |
15 | static gboolean long_pressed = FALSE; |
16 | |
17 | static gboolean |
18 | touchpad_swipe_gesture_begin (GtkGesture *gesture, |
19 | GdkEventSequence *sequence, |
20 | GtkWidget *widget) |
21 | { |
22 | /* Disallow touchscreen events here */ |
23 | if (sequence != NULL) |
24 | gtk_gesture_set_state (gesture, state: GTK_EVENT_SEQUENCE_DENIED); |
25 | return sequence == NULL; |
26 | } |
27 | |
28 | static void |
29 | swipe_gesture_swept (GtkGestureSwipe *gesture, |
30 | double velocity_x, |
31 | double velocity_y, |
32 | GtkWidget *widget) |
33 | { |
34 | swipe_x = velocity_x / 10; |
35 | swipe_y = velocity_y / 10; |
36 | gtk_widget_queue_draw (widget); |
37 | } |
38 | |
39 | static void |
40 | long_press_gesture_pressed (GtkGestureLongPress *gesture, |
41 | double x, |
42 | double y, |
43 | GtkWidget *widget) |
44 | { |
45 | long_pressed = TRUE; |
46 | gtk_widget_queue_draw (widget); |
47 | } |
48 | |
49 | static void |
50 | long_press_gesture_end (GtkGesture *gesture, |
51 | GdkEventSequence *sequence, |
52 | GtkWidget *widget) |
53 | { |
54 | long_pressed = FALSE; |
55 | gtk_widget_queue_draw (widget); |
56 | } |
57 | |
58 | static void |
59 | rotation_angle_changed (GtkGestureRotate *gesture, |
60 | double angle, |
61 | double delta, |
62 | GtkWidget *widget) |
63 | { |
64 | gtk_widget_queue_draw (widget); |
65 | } |
66 | |
67 | static void |
68 | zoom_scale_changed (GtkGestureZoom *gesture, |
69 | double scale, |
70 | GtkWidget *widget) |
71 | { |
72 | gtk_widget_queue_draw (widget); |
73 | } |
74 | |
75 | static void |
76 | drawing_area_draw (GtkDrawingArea *area, |
77 | cairo_t *cr, |
78 | int width, |
79 | int height, |
80 | gpointer data) |
81 | { |
82 | if (swipe_x != 0 || swipe_y != 0) |
83 | { |
84 | cairo_save (cr); |
85 | cairo_set_line_width (cr, width: 6); |
86 | cairo_move_to (cr, x: width / 2, y: height / 2); |
87 | cairo_rel_line_to (cr, dx: swipe_x, dy: swipe_y); |
88 | cairo_set_source_rgba (cr, red: 1, green: 0, blue: 0, alpha: 0.5); |
89 | cairo_stroke (cr); |
90 | cairo_restore (cr); |
91 | } |
92 | |
93 | if (gtk_gesture_is_recognized (gesture: rotate) || gtk_gesture_is_recognized (gesture: zoom)) |
94 | { |
95 | cairo_pattern_t *pat; |
96 | cairo_matrix_t matrix; |
97 | double angle, scale; |
98 | double x_center, y_center; |
99 | |
100 | gtk_gesture_get_bounding_box_center (GTK_GESTURE (zoom), x: &x_center, y: &y_center); |
101 | |
102 | cairo_get_matrix (cr, matrix: &matrix); |
103 | cairo_matrix_translate (matrix: &matrix, tx: x_center, ty: y_center); |
104 | |
105 | cairo_save (cr); |
106 | |
107 | angle = gtk_gesture_rotate_get_angle_delta (GTK_GESTURE_ROTATE (rotate)); |
108 | cairo_matrix_rotate (matrix: &matrix, radians: angle); |
109 | |
110 | scale = gtk_gesture_zoom_get_scale_delta (GTK_GESTURE_ZOOM (zoom)); |
111 | cairo_matrix_scale (matrix: &matrix, sx: scale, sy: scale); |
112 | |
113 | cairo_set_matrix (cr, matrix: &matrix); |
114 | cairo_rectangle (cr, x: -100, y: -100, width: 200, height: 200); |
115 | |
116 | pat = cairo_pattern_create_linear (x0: -100, y0: 0, x1: 200, y1: 0); |
117 | cairo_pattern_add_color_stop_rgb (pattern: pat, offset: 0, red: 0, green: 0, blue: 1); |
118 | cairo_pattern_add_color_stop_rgb (pattern: pat, offset: 1, red: 1, green: 0, blue: 0); |
119 | cairo_set_source (cr, source: pat); |
120 | cairo_fill (cr); |
121 | |
122 | cairo_restore (cr); |
123 | |
124 | cairo_pattern_destroy (pattern: pat); |
125 | } |
126 | |
127 | if (long_pressed) |
128 | { |
129 | cairo_save (cr); |
130 | cairo_arc (cr, |
131 | xc: width / 2, yc: height / 2, |
132 | radius: 50, angle1: 0, angle2: 2 * G_PI); |
133 | |
134 | cairo_set_source_rgba (cr, red: 0, green: 1, blue: 0, alpha: 0.5); |
135 | cairo_stroke (cr); |
136 | |
137 | cairo_restore (cr); |
138 | } |
139 | } |
140 | |
141 | GtkWidget * |
142 | do_gestures (GtkWidget *do_widget) |
143 | { |
144 | static GtkWidget *window = NULL; |
145 | GtkWidget *drawing_area; |
146 | GtkGesture *gesture; |
147 | |
148 | if (!window) |
149 | { |
150 | window = gtk_window_new (); |
151 | gtk_window_set_default_size (GTK_WINDOW (window), width: 400, height: 400); |
152 | gtk_window_set_title (GTK_WINDOW (window), title: "Gestures" ); |
153 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window); |
154 | |
155 | drawing_area = gtk_drawing_area_new (); |
156 | gtk_window_set_child (GTK_WINDOW (window), child: drawing_area); |
157 | |
158 | gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area), |
159 | draw_func: drawing_area_draw, |
160 | NULL, NULL); |
161 | |
162 | /* Swipe */ |
163 | gesture = gtk_gesture_swipe_new (); |
164 | g_signal_connect (gesture, "swipe" , |
165 | G_CALLBACK (swipe_gesture_swept), drawing_area); |
166 | gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), |
167 | phase: GTK_PHASE_BUBBLE); |
168 | gtk_widget_add_controller (widget: drawing_area, GTK_EVENT_CONTROLLER (gesture)); |
169 | |
170 | /* 3fg swipe for touchpads */ |
171 | gesture = g_object_new (GTK_TYPE_GESTURE_SWIPE, |
172 | first_property_name: "n-points" , 3, |
173 | NULL); |
174 | g_signal_connect (gesture, "begin" , |
175 | G_CALLBACK (touchpad_swipe_gesture_begin), drawing_area); |
176 | g_signal_connect (gesture, "swipe" , |
177 | G_CALLBACK (swipe_gesture_swept), drawing_area); |
178 | gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), |
179 | phase: GTK_PHASE_BUBBLE); |
180 | gtk_widget_add_controller (widget: drawing_area, GTK_EVENT_CONTROLLER (gesture)); |
181 | |
182 | |
183 | /* Long press */ |
184 | gesture = gtk_gesture_long_press_new (); |
185 | g_signal_connect (gesture, "pressed" , |
186 | G_CALLBACK (long_press_gesture_pressed), drawing_area); |
187 | g_signal_connect (gesture, "end" , |
188 | G_CALLBACK (long_press_gesture_end), drawing_area); |
189 | gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), |
190 | phase: GTK_PHASE_BUBBLE); |
191 | gtk_widget_add_controller (widget: drawing_area, GTK_EVENT_CONTROLLER (gesture)); |
192 | |
193 | /* Rotate */ |
194 | rotate = gesture = gtk_gesture_rotate_new (); |
195 | g_signal_connect (gesture, "angle-changed" , |
196 | G_CALLBACK (rotation_angle_changed), drawing_area); |
197 | gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), |
198 | phase: GTK_PHASE_BUBBLE); |
199 | gtk_widget_add_controller (widget: drawing_area, GTK_EVENT_CONTROLLER (gesture)); |
200 | |
201 | /* Zoom */ |
202 | zoom = gesture = gtk_gesture_zoom_new (); |
203 | g_signal_connect (gesture, "scale-changed" , |
204 | G_CALLBACK (zoom_scale_changed), drawing_area); |
205 | gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), |
206 | phase: GTK_PHASE_BUBBLE); |
207 | gtk_widget_add_controller (widget: drawing_area, GTK_EVENT_CONTROLLER (gesture)); |
208 | } |
209 | |
210 | if (!gtk_widget_get_visible (widget: window)) |
211 | gtk_widget_show (widget: window); |
212 | else |
213 | gtk_window_destroy (GTK_WINDOW (window)); |
214 | |
215 | return window; |
216 | } |
217 | |