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 "gtkintl.h"
34 #include "gtkmarshalers.h"
35 #include "gtkwidget.h"
36 #include "gtkeventcontrollerprivate.h"
37 #include "gtkeventcontrollermotion.h"
38 #include "gtktypebuiltins.h"
39 #include "gtkmarshalers.h"
40
41 struct _GtkEventControllerMotion
42 {
43 GtkEventController parent_instance;
44 };
45
46 struct _GtkEventControllerMotionClass
47 {
48 GtkEventControllerClass parent_class;
49 };
50
51 enum {
52 ENTER,
53 LEAVE,
54 MOTION,
55 N_SIGNALS
56 };
57
58 static guint signals[N_SIGNALS] = { 0 };
59
G_DEFINE_TYPE(GtkEventControllerMotion,gtk_event_controller_motion,GTK_TYPE_EVENT_CONTROLLER)60 G_DEFINE_TYPE (GtkEventControllerMotion, gtk_event_controller_motion, GTK_TYPE_EVENT_CONTROLLER)
61
62 static void
63 get_coords (GtkWidget *widget,
64 const GdkEvent *event,
65 double *x,
66 double *y)
67 {
68 GdkWindow *window, *ancestor;
69 GtkAllocation alloc;
70
71 gtk_widget_get_allocation (widget, &alloc);
72 gdk_event_get_coords (event, x, y);
73
74 ancestor = gtk_widget_get_window (widget);
75 window = gdk_event_get_window (event);
76
77 while (window && ancestor && (window != ancestor))
78 {
79 gdk_window_coords_to_parent (window, *x, *y, x, y);
80 window = gdk_window_get_parent (window);
81 }
82
83 if (!gtk_widget_get_has_window (widget))
84 {
85 *x -= alloc.x;
86 *y -= alloc.y;
87 }
88 }
89
90 static gboolean
gtk_event_controller_motion_handle_event(GtkEventController * controller,const GdkEvent * event)91 gtk_event_controller_motion_handle_event (GtkEventController *controller,
92 const GdkEvent *event)
93 {
94 GtkEventControllerClass *parent_class;
95 GtkWidget *widget;
96 GdkEventType type;
97
98 widget = gtk_event_controller_get_widget (controller);
99
100 type = gdk_event_get_event_type (event);
101 if (type == GDK_ENTER_NOTIFY)
102 {
103 double x, y;
104 get_coords (widget, event, &x, &y);
105 g_signal_emit (controller, signals[ENTER], 0, x, y);
106 }
107 else if (type == GDK_LEAVE_NOTIFY)
108 {
109 g_signal_emit (controller, signals[LEAVE], 0);
110 }
111 else if (type == GDK_MOTION_NOTIFY)
112 {
113 double x, y;
114 get_coords (widget, event, &x, &y);
115 g_signal_emit (controller, signals[MOTION], 0, x, y);
116 }
117
118 parent_class = GTK_EVENT_CONTROLLER_CLASS (gtk_event_controller_motion_parent_class);
119
120 return parent_class->handle_event (controller, event);
121 }
122
123 static void
gtk_event_controller_motion_class_init(GtkEventControllerMotionClass * klass)124 gtk_event_controller_motion_class_init (GtkEventControllerMotionClass *klass)
125 {
126 GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
127
128 controller_class->handle_event = gtk_event_controller_motion_handle_event;
129
130 /**
131 * GtkEventControllerMotion::enter:
132 * @controller: The object that received the signal
133 * @x: the x coordinate
134 * @y: the y coordinate
135 *
136 * Signals that the pointer has entered the widget.
137 */
138 signals[ENTER] =
139 g_signal_new (I_("enter"),
140 GTK_TYPE_EVENT_CONTROLLER_MOTION,
141 G_SIGNAL_RUN_FIRST,
142 0, NULL, NULL,
143 _gtk_marshal_VOID__DOUBLE_DOUBLE,
144 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
145 g_signal_set_va_marshaller (signals[ENTER],
146 G_TYPE_FROM_CLASS (klass),
147 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
148
149 /**
150 * GtkEventControllerMotion::leave:
151 * @controller: The object that received the signal
152 *
153 * Signals that pointer has left the widget.
154 */
155 signals[LEAVE] =
156 g_signal_new (I_("leave"),
157 GTK_TYPE_EVENT_CONTROLLER_MOTION,
158 G_SIGNAL_RUN_FIRST,
159 0, NULL, NULL,
160 NULL,
161 G_TYPE_NONE, 0);
162
163 /**
164 * GtkEventControllerMotion::motion:
165 * @controller: The object that received the signal
166 * @x: the x coordinate
167 * @y: the y coordinate
168 *
169 * Emitted when the pointer moves inside the widget.
170 */
171 signals[MOTION] =
172 g_signal_new (I_("motion"),
173 GTK_TYPE_EVENT_CONTROLLER_MOTION,
174 G_SIGNAL_RUN_FIRST,
175 0, NULL, NULL,
176 _gtk_marshal_VOID__DOUBLE_DOUBLE,
177 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
178 g_signal_set_va_marshaller (signals[MOTION],
179 G_TYPE_FROM_CLASS (klass),
180 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
181 }
182
183 static void
gtk_event_controller_motion_init(GtkEventControllerMotion * motion)184 gtk_event_controller_motion_init (GtkEventControllerMotion *motion)
185 {
186 }
187
188 /**
189 * gtk_event_controller_motion_new:
190 * @widget: a #GtkWidget
191 *
192 * Creates a new event controller that will handle motion events
193 * for the given @widget.
194 *
195 * Returns: a new #GtkEventControllerMotion
196 *
197 * Since: 3.24
198 **/
199 GtkEventController *
gtk_event_controller_motion_new(GtkWidget * widget)200 gtk_event_controller_motion_new (GtkWidget *widget)
201 {
202 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
203
204 return g_object_new (GTK_TYPE_EVENT_CONTROLLER_MOTION,
205 "widget", widget,
206 NULL);
207 }
208