1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2017-2018, Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Author(s): Carlos Garnacho <carlosg@gnome.org>
18 */
19
20 /**
21 * SECTION:gtkgesturestylus
22 * @Short_description: Gesture for stylus input
23 * @Title: GtkGestureStylus
24 * @See_also: #GtkGesture, #GtkGestureSingle
25 *
26 * #GtkGestureStylus is a #GtkGesture implementation specific to stylus
27 * input. The provided signals just provide the basic information
28 */
29
30 #include "config.h"
31 #include "gtkgesturestylus.h"
32 #include "gtkgesturestylusprivate.h"
33 #include "gtkprivate.h"
34 #include "gtkintl.h"
35 #include "gtkmarshalers.h"
36 #include "gtkmain.h"
37
38 G_DEFINE_TYPE (GtkGestureStylus, gtk_gesture_stylus, GTK_TYPE_GESTURE_SINGLE)
39
40 enum {
41 PROXIMITY,
42 DOWN,
43 MOTION,
44 UP,
45 N_SIGNALS
46 };
47
48 static guint signals[N_SIGNALS] = { 0, };
49
50 static gboolean
gtk_gesture_stylus_handle_event(GtkEventController * controller,const GdkEvent * event)51 gtk_gesture_stylus_handle_event (GtkEventController *controller,
52 const GdkEvent *event)
53 {
54 GdkModifierType modifiers;
55 guint n_signal;
56 gdouble x, y;
57
58 GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_stylus_parent_class)->handle_event (controller, event);
59
60 if (!gdk_event_get_device_tool (event))
61 return FALSE;
62 if (!gdk_event_get_coords (event, &x, &y))
63 return FALSE;
64
65 switch ((guint) gdk_event_get_event_type (event))
66 {
67 case GDK_BUTTON_PRESS:
68 n_signal = DOWN;
69 break;
70 case GDK_BUTTON_RELEASE:
71 n_signal = UP;
72 break;
73 case GDK_MOTION_NOTIFY:
74 gdk_event_get_state (event, &modifiers);
75
76 if (modifiers & GDK_BUTTON1_MASK)
77 n_signal = MOTION;
78 else
79 n_signal = PROXIMITY;
80 break;
81 default:
82 return FALSE;
83 }
84
85 g_signal_emit (controller, signals[n_signal], 0, x, y);
86
87 return TRUE;
88 }
89
90 static void
gtk_gesture_stylus_class_init(GtkGestureStylusClass * klass)91 gtk_gesture_stylus_class_init (GtkGestureStylusClass *klass)
92 {
93 GtkEventControllerClass *event_controller_class;
94
95 event_controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
96 event_controller_class->handle_event = gtk_gesture_stylus_handle_event;
97
98 signals[PROXIMITY] =
99 g_signal_new (I_("proximity"),
100 G_TYPE_FROM_CLASS (klass),
101 G_SIGNAL_RUN_LAST,
102 G_STRUCT_OFFSET (GtkGestureStylusClass, proximity),
103 NULL, NULL,
104 _gtk_marshal_VOID__DOUBLE_DOUBLE,
105 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
106 g_signal_set_va_marshaller (signals[PROXIMITY],
107 G_TYPE_FROM_CLASS (klass),
108 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
109
110 signals[DOWN] =
111 g_signal_new (I_("down"),
112 G_TYPE_FROM_CLASS (klass),
113 G_SIGNAL_RUN_LAST,
114 G_STRUCT_OFFSET (GtkGestureStylusClass, down),
115 NULL, NULL,
116 _gtk_marshal_VOID__DOUBLE_DOUBLE,
117 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
118 g_signal_set_va_marshaller (signals[DOWN],
119 G_TYPE_FROM_CLASS (klass),
120 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
121
122 signals[MOTION] =
123 g_signal_new (I_("motion"),
124 G_TYPE_FROM_CLASS (klass),
125 G_SIGNAL_RUN_LAST,
126 G_STRUCT_OFFSET (GtkGestureStylusClass, motion),
127 NULL, NULL,
128 _gtk_marshal_VOID__DOUBLE_DOUBLE,
129 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
130 g_signal_set_va_marshaller (signals[MOTION],
131 G_TYPE_FROM_CLASS (klass),
132 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
133
134 signals[UP] =
135 g_signal_new (I_("up"),
136 G_TYPE_FROM_CLASS (klass),
137 G_SIGNAL_RUN_LAST,
138 G_STRUCT_OFFSET (GtkGestureStylusClass, up),
139 NULL, NULL,
140 _gtk_marshal_VOID__DOUBLE_DOUBLE,
141 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
142 g_signal_set_va_marshaller (signals[UP],
143 G_TYPE_FROM_CLASS (klass),
144 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
145 }
146
147 static void
gtk_gesture_stylus_init(GtkGestureStylus * gesture)148 gtk_gesture_stylus_init (GtkGestureStylus *gesture)
149 {
150 }
151
152 /**
153 * gtk_gesture_stylus_new:
154 * @widget: a #GtkWidget
155 *
156 * Creates a new #GtkGestureStylus.
157 *
158 * Returns: a newly created stylus gesture
159 *
160 * Since: 3.24
161 **/
162 GtkGesture *
gtk_gesture_stylus_new(GtkWidget * widget)163 gtk_gesture_stylus_new (GtkWidget *widget)
164 {
165 return g_object_new (GTK_TYPE_GESTURE_STYLUS,
166 "widget", widget,
167 NULL);
168 }
169
170 static const GdkEvent *
gesture_get_current_event(GtkGestureStylus * gesture)171 gesture_get_current_event (GtkGestureStylus *gesture)
172 {
173 GdkEventSequence *sequence;
174
175 sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
176
177 return gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
178 }
179
180 /**
181 * gtk_gesture_stylus_get_axis:
182 * @gesture: a #GtkGestureStylus
183 * @axis: requested device axis
184 * @value: (out): return location for the axis value
185 *
186 * Returns the current value for the requested @axis. This function
187 * must be called from either the #GtkGestureStylus:down,
188 * #GtkGestureStylus:motion, #GtkGestureStylus:up or #GtkGestureStylus:proximity
189 * signals.
190 *
191 * Returns: #TRUE if there is a current value for the axis
192 *
193 * Since: 3.24
194 **/
195 gboolean
gtk_gesture_stylus_get_axis(GtkGestureStylus * gesture,GdkAxisUse axis,gdouble * value)196 gtk_gesture_stylus_get_axis (GtkGestureStylus *gesture,
197 GdkAxisUse axis,
198 gdouble *value)
199 {
200 const GdkEvent *event;
201
202 g_return_val_if_fail (GTK_IS_GESTURE_STYLUS (gesture), FALSE);
203 g_return_val_if_fail (axis < GDK_AXIS_LAST, FALSE);
204 g_return_val_if_fail (value != NULL, FALSE);
205
206 event = gesture_get_current_event (gesture);
207 if (!event)
208 return FALSE;
209
210 return gdk_event_get_axis (event, axis, value);
211 }
212
213 /**
214 * gtk_gesture_stylus_get_axes:
215 * @gesture: a GtkGestureStylus
216 * @axes: (array): array of requested axes, terminated with #GDK_AXIS_IGNORE
217 * @values: (out) (array): return location for the axis values
218 *
219 * Returns the current values for the requested @axes. This function
220 * must be called from either the #GtkGestureStylus:down,
221 * #GtkGestureStylus:motion, #GtkGestureStylus:up or #GtkGestureStylus:proximity
222 * signals.
223 *
224 * Returns: #TRUE if there is a current value for the axes
225 *
226 * Since: 3.24
227 **/
228 gboolean
gtk_gesture_stylus_get_axes(GtkGestureStylus * gesture,GdkAxisUse axes[],gdouble ** values)229 gtk_gesture_stylus_get_axes (GtkGestureStylus *gesture,
230 GdkAxisUse axes[],
231 gdouble **values)
232 {
233 const GdkEvent *event;
234 GArray *array;
235 gint i = 0;
236
237 g_return_val_if_fail (GTK_IS_GESTURE_STYLUS (gesture), FALSE);
238 g_return_val_if_fail (values != NULL, FALSE);
239
240 event = gesture_get_current_event (gesture);
241 if (!event)
242 return FALSE;
243
244 array = g_array_new (TRUE, FALSE, sizeof (gdouble));
245
246 while (axes[i] != GDK_AXIS_IGNORE)
247 {
248 gdouble value;
249
250 if (axes[i] >= GDK_AXIS_LAST)
251 {
252 g_warning ("Requesting unknown axis %d, did you "
253 "forget to add a last GDK_AXIS_IGNORE axis?",
254 axes[i]);
255 g_array_free (array, TRUE);
256 return FALSE;
257 }
258
259 gdk_event_get_axis (event, axes[i], &value);
260 g_array_append_val (array, value);
261 i++;
262 }
263
264 *values = (gdouble *) g_array_free (array, FALSE);
265 return TRUE;
266 }
267
268 /**
269 * gtk_gesture_stylus_get_device_tool:
270 * @gesture: a #GtkGestureStylus
271 *
272 * Returns the #GdkDeviceTool currently driving input through this gesture.
273 * This function must be called from either the #GtkGestureStylus::down,
274 * #GtkGestureStylus::motion, #GtkGestureStylus::up or #GtkGestureStylus::proximity
275 * signal handlers.
276 *
277 * Returns: (nullable) (transfer none): The current stylus tool
278 *
279 * Since: 3.24
280 **/
281 GdkDeviceTool *
gtk_gesture_stylus_get_device_tool(GtkGestureStylus * gesture)282 gtk_gesture_stylus_get_device_tool (GtkGestureStylus *gesture)
283 {
284 const GdkEvent *event;
285
286 g_return_val_if_fail (GTK_IS_GESTURE_STYLUS (gesture), FALSE);
287
288 event = gesture_get_current_event (gesture);
289 if (!event)
290 return NULL;
291
292 return gdk_event_get_device_tool (event);
293 }
294