1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2017, 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): Matthias Clasen <mclasen@redhat.com>
18 */
19
20 /**
21 * SECTION:gtkeventcontrollermotion
22 * @Short_description: Event controller for motion events
23 * @Title: GtkEventControllerMotion
24 * @See_also: #GtkEventController
25 *
26 * #GtkEventControllerMotion is an event controller meant for situations
27 * where you need to track the position of the pointer.
28 *
29 * This object was added in 3.24.
30 **/
31 #include "config.h"
32
33 #include "gtkeventcontrollermotion.h"
34
35 #if GTK_CHECK_VERSION(3, 24, 0)
36 # error "Cannot use this in conjunction with 3.24"
37 #endif
38
39 #define I_(s) (g_intern_static_string(s))
40
41 struct _GtkEventControllerMotion
42 {
43 /* EventController adds no new instance fields up to 3.24 */
44 /* GtkEventController parent_instance; */
45 GObject parent_instance;
46 };
47
48 struct _GtkEventControllerClass
49 {
50 GObjectClass parent_class;
51
52 gboolean (* handle_event) (GtkEventController *controller,
53 const GdkEvent *event);
54 void (* reset) (GtkEventController *controller);
55
56 /*<private>*/
57
58 /* Tells whether the event is filtered out, %TRUE makes
59 * the event unseen by the handle_event vfunc.
60 */
61 gboolean (* filter_event) (GtkEventController *controller,
62 const GdkEvent *event);
63 gpointer padding[10];
64 };
65
66 struct _GtkEventControllerMotionClass
67 {
68 GtkEventControllerClass parent_class;
69 };
70
71 enum {
72 ENTER,
73 LEAVE,
74 MOTION,
75 N_SIGNALS
76 };
77
78 static guint signals[N_SIGNALS] = { 0 };
79
G_DEFINE_TYPE(GtkEventControllerMotion,gtk_event_controller_motion,GTK_TYPE_EVENT_CONTROLLER)80 G_DEFINE_TYPE (GtkEventControllerMotion, gtk_event_controller_motion, GTK_TYPE_EVENT_CONTROLLER)
81
82 static void
83 get_coords (GtkWidget *widget,
84 const GdkEvent *event,
85 double *x,
86 double *y)
87 {
88 GdkWindow *window, *ancestor;
89 GtkAllocation alloc;
90
91 gtk_widget_get_allocation (widget, &alloc);
92 gdk_event_get_coords (event, x, y);
93
94 ancestor = gtk_widget_get_window (widget);
95 window = gdk_event_get_window (event);
96
97 while (window && ancestor && (window != ancestor))
98 {
99 gdk_window_coords_to_parent (window, *x, *y, x, y);
100 window = gdk_window_get_parent (window);
101 }
102
103 if (!gtk_widget_get_has_window (widget))
104 {
105 *x -= alloc.x;
106 *y -= alloc.y;
107 }
108 }
109
110 static gboolean
gtk_event_controller_motion_handle_event(GtkEventController * controller,const GdkEvent * event)111 gtk_event_controller_motion_handle_event (GtkEventController *controller,
112 const GdkEvent *event)
113 {
114 GtkEventControllerClass *parent_class;
115 GtkWidget *widget;
116 GdkEventType type;
117
118 widget = gtk_event_controller_get_widget (controller);
119
120 type = gdk_event_get_event_type (event);
121 if (type == GDK_ENTER_NOTIFY)
122 {
123 double x, y;
124 get_coords (widget, event, &x, &y);
125 g_signal_emit (controller, signals[ENTER], 0, x, y);
126 }
127 else if (type == GDK_LEAVE_NOTIFY)
128 {
129 g_signal_emit (controller, signals[LEAVE], 0);
130 }
131 else if (type == GDK_MOTION_NOTIFY)
132 {
133 double x, y;
134 get_coords (widget, event, &x, &y);
135 g_signal_emit (controller, signals[MOTION], 0, x, y);
136 }
137
138 parent_class = GTK_EVENT_CONTROLLER_CLASS (gtk_event_controller_motion_parent_class);
139
140 return parent_class->handle_event (controller, event);
141 }
142
143 static void
gtk_event_controller_motion_class_init(GtkEventControllerMotionClass * klass)144 gtk_event_controller_motion_class_init (GtkEventControllerMotionClass *klass)
145 {
146 GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
147
148 controller_class->handle_event = gtk_event_controller_motion_handle_event;
149
150 /**
151 * GtkEventControllerMotion::enter:
152 * @controller: The object that received the signal
153 * @x: the x coordinate
154 * @y: the y coordinate
155 *
156 * Signals that the pointer has entered the widget.
157 */
158 signals[ENTER] =
159 g_signal_new (I_("enter"),
160 GTK_TYPE_EVENT_CONTROLLER_MOTION,
161 G_SIGNAL_RUN_FIRST,
162 0, NULL, NULL,
163 NULL,
164 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
165
166 /**
167 * GtkEventControllerMotion::leave:
168 * @controller: The object that received the signal
169 *
170 * Signals that pointer has left the widget.
171 */
172 signals[LEAVE] =
173 g_signal_new (I_("leave"),
174 GTK_TYPE_EVENT_CONTROLLER_MOTION,
175 G_SIGNAL_RUN_FIRST,
176 0, NULL, NULL,
177 NULL,
178 G_TYPE_NONE, 0);
179
180 /**
181 * GtkEventControllerMotion::motion:
182 * @controller: The object that received the signal
183 * @x: the x coordinate
184 * @y: the y coordinate
185 *
186 * Emitted when the pointer moves inside the widget.
187 */
188 signals[MOTION] =
189 g_signal_new (I_("motion"),
190 GTK_TYPE_EVENT_CONTROLLER_MOTION,
191 G_SIGNAL_RUN_FIRST,
192 0, NULL, NULL,
193 NULL,
194 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
195 }
196
197 static void
gtk_event_controller_motion_init(GtkEventControllerMotion * motion)198 gtk_event_controller_motion_init (GtkEventControllerMotion *motion)
199 {
200 }
201
202 /**
203 * gtk_event_controller_motion_new:
204 * @widget: a #GtkWidget
205 *
206 * Creates a new event controller that will handle motion events
207 * for the given @widget.
208 *
209 * Returns: a new #GtkEventControllerMotion
210 *
211 * Since: 3.24
212 **/
213 GtkEventController *
gtk_event_controller_motion_new(GtkWidget * widget)214 gtk_event_controller_motion_new (GtkWidget *widget)
215 {
216 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
217
218 return g_object_new (GTK_TYPE_EVENT_CONTROLLER_MOTION,
219 "widget", widget,
220 NULL);
221 }
222