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