1 #include <assert.h>
2 #include <stdlib.h>
3 #include <wlr/types/wlr_seat.h>
4 #include <wlr/types/wlr_virtual_pointer_v1.h>
5 #include <wlr/types/wlr_pointer.h>
6 #include <wlr/util/log.h>
7 #include "util/signal.h"
8 #include "wlr-virtual-pointer-unstable-v1-protocol.h"
9
input_device_destroy(struct wlr_input_device * dev)10 static void input_device_destroy(struct wlr_input_device *dev) {
11 struct wlr_virtual_pointer_v1 *pointer =
12 (struct wlr_virtual_pointer_v1 *)dev;
13 wl_resource_set_user_data(pointer->resource, NULL);
14 wlr_signal_emit_safe(&pointer->events.destroy, pointer);
15 wl_list_remove(&pointer->link);
16 free(pointer);
17 }
18
19 static const struct wlr_input_device_impl input_device_impl = {
20 .destroy = input_device_destroy
21 };
22
23 static const struct zwlr_virtual_pointer_v1_interface virtual_pointer_impl;
24
virtual_pointer_from_resource(struct wl_resource * resource)25 static struct wlr_virtual_pointer_v1 *virtual_pointer_from_resource(
26 struct wl_resource *resource) {
27 assert(wl_resource_instance_of(resource,
28 &zwlr_virtual_pointer_v1_interface, &virtual_pointer_impl));
29 return wl_resource_get_user_data(resource);
30 }
31
virtual_pointer_motion(struct wl_client * client,struct wl_resource * resource,uint32_t time,wl_fixed_t dx,wl_fixed_t dy)32 static void virtual_pointer_motion(struct wl_client *client,
33 struct wl_resource *resource, uint32_t time,
34 wl_fixed_t dx, wl_fixed_t dy) {
35 struct wlr_virtual_pointer_v1 *pointer =
36 virtual_pointer_from_resource(resource);
37 if (pointer == NULL) {
38 return;
39 }
40 struct wlr_input_device *wlr_dev = &pointer->input_device;
41 struct wlr_event_pointer_motion event = {
42 .device = wlr_dev,
43 .time_msec = time,
44 .delta_x = wl_fixed_to_double(dx),
45 .delta_y = wl_fixed_to_double(dy),
46 .unaccel_dx = wl_fixed_to_double(dx),
47 .unaccel_dy = wl_fixed_to_double(dy),
48 };
49 wlr_signal_emit_safe(&wlr_dev->pointer->events.motion, &event);
50 }
51
virtual_pointer_motion_absolute(struct wl_client * client,struct wl_resource * resource,uint32_t time,uint32_t x,uint32_t y,uint32_t x_extent,uint32_t y_extent)52 static void virtual_pointer_motion_absolute(struct wl_client *client,
53 struct wl_resource *resource, uint32_t time, uint32_t x, uint32_t y,
54 uint32_t x_extent, uint32_t y_extent) {
55 struct wlr_virtual_pointer_v1 *pointer =
56 virtual_pointer_from_resource(resource);
57 if (pointer == NULL) {
58 return;
59 }
60 if (x_extent == 0 || y_extent == 0) {
61 return;
62 }
63 struct wlr_input_device *wlr_dev = &pointer->input_device;
64 struct wlr_event_pointer_motion_absolute event = {
65 .device = wlr_dev,
66 .time_msec = time,
67 .x = (double)x / x_extent,
68 .y = (double)y / y_extent,
69 };
70 wlr_signal_emit_safe(&wlr_dev->pointer->events.motion_absolute, &event);
71 }
72
virtual_pointer_button(struct wl_client * client,struct wl_resource * resource,uint32_t time,uint32_t button,uint32_t state)73 static void virtual_pointer_button(struct wl_client *client,
74 struct wl_resource *resource, uint32_t time, uint32_t button,
75 uint32_t state) {
76 struct wlr_virtual_pointer_v1 *pointer =
77 virtual_pointer_from_resource(resource);
78 if (pointer == NULL) {
79 return;
80 }
81 struct wlr_input_device *wlr_dev = &pointer->input_device;
82 struct wlr_event_pointer_button event = {
83 .device = wlr_dev,
84 .time_msec = time,
85 .button = button,
86 .state = state ? WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED
87 };
88 wlr_signal_emit_safe(&wlr_dev->pointer->events.button, &event);
89 }
90
virtual_pointer_axis(struct wl_client * client,struct wl_resource * resource,uint32_t time,uint32_t axis,wl_fixed_t value)91 static void virtual_pointer_axis(struct wl_client *client,
92 struct wl_resource *resource, uint32_t time, uint32_t axis,
93 wl_fixed_t value) {
94 if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
95 wl_resource_post_error(resource,
96 ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS,
97 "Invalid enumeration value %" PRIu32, axis);
98 return;
99 }
100 struct wlr_virtual_pointer_v1 *pointer =
101 virtual_pointer_from_resource(resource);
102 if (pointer == NULL) {
103 return;
104 }
105 struct wlr_input_device *wlr_dev = &pointer->input_device;
106 pointer->axis = axis;
107 pointer->axis_valid[pointer->axis] = true;
108 pointer->axis_event[pointer->axis].device = wlr_dev;
109 pointer->axis_event[pointer->axis].time_msec = time;
110 pointer->axis_event[pointer->axis].orientation = axis;
111 pointer->axis_event[pointer->axis].delta = wl_fixed_to_double(value);
112 }
113
virtual_pointer_frame(struct wl_client * client,struct wl_resource * resource)114 static void virtual_pointer_frame(struct wl_client *client,
115 struct wl_resource *resource) {
116 struct wlr_virtual_pointer_v1 *pointer =
117 virtual_pointer_from_resource(resource);
118 if (pointer == NULL) {
119 return;
120 }
121 struct wlr_input_device *wlr_dev = &pointer->input_device;
122
123 for (size_t i = 0;
124 i < sizeof(pointer->axis_valid) / sizeof(pointer->axis_valid[0]);
125 ++i) {
126 if (pointer->axis_valid[i]) {
127 /* Deliver pending axis event */
128 wlr_signal_emit_safe(&wlr_dev->pointer->events.axis,
129 &pointer->axis_event[i]);
130 memset(&pointer->axis_event[i], 0, sizeof(pointer->axis_event[i]));
131 pointer->axis_valid[i] = false;
132 }
133 }
134
135 wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer);
136 }
137
virtual_pointer_axis_source(struct wl_client * client,struct wl_resource * resource,uint32_t source)138 static void virtual_pointer_axis_source(struct wl_client *client,
139 struct wl_resource *resource, uint32_t source) {
140 if (source > WL_POINTER_AXIS_SOURCE_WHEEL_TILT) {
141 wl_resource_post_error(resource,
142 ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS_SOURCE,
143 "Invalid enumeration value %" PRIu32, source);
144 return;
145 }
146 struct wlr_virtual_pointer_v1 *pointer =
147 virtual_pointer_from_resource(resource);
148 if (pointer == NULL) {
149 return;
150 }
151 struct wlr_input_device *wlr_dev = &pointer->input_device;
152 pointer->axis_event[pointer->axis].device = wlr_dev;
153 pointer->axis_event[pointer->axis].source = source;
154 }
155
virtual_pointer_axis_stop(struct wl_client * client,struct wl_resource * resource,uint32_t time,uint32_t axis)156 static void virtual_pointer_axis_stop(struct wl_client *client,
157 struct wl_resource *resource, uint32_t time, uint32_t axis) {
158 if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
159 wl_resource_post_error(resource,
160 ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS,
161 "Invalid enumeration value %" PRIu32, axis);
162 return;
163 }
164 struct wlr_virtual_pointer_v1 *pointer =
165 virtual_pointer_from_resource(resource);
166 if (pointer == NULL) {
167 return;
168 }
169 struct wlr_input_device *wlr_dev = &pointer->input_device;
170 pointer->axis = axis;
171 pointer->axis_valid[pointer->axis] = true;
172 pointer->axis_event[pointer->axis].device = wlr_dev;
173 pointer->axis_event[pointer->axis].time_msec = time;
174 pointer->axis_event[pointer->axis].orientation = axis;
175 pointer->axis_event[pointer->axis].delta = 0;
176 pointer->axis_event[pointer->axis].delta_discrete = 0;
177 }
178
virtual_pointer_axis_discrete(struct wl_client * client,struct wl_resource * resource,uint32_t time,uint32_t axis,wl_fixed_t value,int32_t discrete)179 static void virtual_pointer_axis_discrete(struct wl_client *client,
180 struct wl_resource *resource, uint32_t time, uint32_t axis,
181 wl_fixed_t value, int32_t discrete) {
182 if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
183 wl_resource_post_error(resource,
184 ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS,
185 "Invalid enumeration value %" PRIu32, axis);
186 return;
187 }
188 struct wlr_virtual_pointer_v1 *pointer =
189 virtual_pointer_from_resource(resource);
190 if (pointer == NULL) {
191 return;
192 }
193 struct wlr_input_device *wlr_dev = &pointer->input_device;
194 pointer->axis = axis;
195 pointer->axis_valid[pointer->axis] = true;
196 pointer->axis_event[pointer->axis].device = wlr_dev;
197 pointer->axis_event[pointer->axis].time_msec = time;
198 pointer->axis_event[pointer->axis].orientation = axis;
199 pointer->axis_event[pointer->axis].delta = wl_fixed_to_double(value);
200 pointer->axis_event[pointer->axis].delta_discrete = discrete;
201 }
202
virtual_pointer_destroy_resource(struct wl_resource * resource)203 static void virtual_pointer_destroy_resource(struct wl_resource *resource) {
204 struct wlr_virtual_pointer_v1 *pointer =
205 virtual_pointer_from_resource(resource);
206 if (pointer != NULL) {
207 wlr_input_device_destroy(&pointer->input_device);
208 }
209 }
210
virtual_pointer_destroy(struct wl_client * client,struct wl_resource * resource)211 static void virtual_pointer_destroy(struct wl_client *client,
212 struct wl_resource *resource) {
213 wl_resource_destroy(resource);
214 }
215
216 static const struct zwlr_virtual_pointer_v1_interface virtual_pointer_impl = {
217 .motion = virtual_pointer_motion,
218 .motion_absolute = virtual_pointer_motion_absolute,
219 .button = virtual_pointer_button,
220 .axis = virtual_pointer_axis,
221 .frame = virtual_pointer_frame,
222 .axis_source = virtual_pointer_axis_source,
223 .axis_stop = virtual_pointer_axis_stop,
224 .axis_discrete = virtual_pointer_axis_discrete,
225 .destroy = virtual_pointer_destroy,
226 };
227
228 static const struct zwlr_virtual_pointer_manager_v1_interface manager_impl;
229
manager_from_resource(struct wl_resource * resource)230 static struct wlr_virtual_pointer_manager_v1 *manager_from_resource(
231 struct wl_resource *resource) {
232 assert(wl_resource_instance_of(resource,
233 &zwlr_virtual_pointer_manager_v1_interface, &manager_impl));
234 return wl_resource_get_user_data(resource);
235 }
236
virtual_pointer_manager_create_virtual_pointer_with_output(struct wl_client * client,struct wl_resource * resource,struct wl_resource * seat,struct wl_resource * output,uint32_t id)237 static void virtual_pointer_manager_create_virtual_pointer_with_output(
238 struct wl_client *client, struct wl_resource *resource,
239 struct wl_resource *seat, struct wl_resource *output,
240 uint32_t id) {
241 struct wlr_virtual_pointer_manager_v1 *manager = manager_from_resource(resource);
242
243 struct wlr_virtual_pointer_v1 *virtual_pointer = calloc(1,
244 sizeof(struct wlr_virtual_pointer_v1));
245 if (!virtual_pointer) {
246 wl_client_post_no_memory(client);
247 return;
248 }
249
250 struct wlr_pointer *pointer = calloc(1, sizeof(struct wlr_pointer));
251 if (!pointer) {
252 wlr_log(WLR_ERROR, "Cannot allocate wlr_pointer");
253 free(virtual_pointer);
254 wl_client_post_no_memory(client);
255 return;
256 }
257 wlr_pointer_init(pointer, NULL);
258
259 struct wl_resource *pointer_resource = wl_resource_create(client,
260 &zwlr_virtual_pointer_v1_interface, wl_resource_get_version(resource),
261 id);
262 if (!pointer_resource) {
263 free(pointer);
264 free(virtual_pointer);
265 wl_client_post_no_memory(client);
266 return;
267 }
268
269 wl_resource_set_implementation(pointer_resource, &virtual_pointer_impl,
270 virtual_pointer, virtual_pointer_destroy_resource);
271
272 wlr_input_device_init(&virtual_pointer->input_device,
273 WLR_INPUT_DEVICE_POINTER, &input_device_impl, "virtual pointer",
274 0x0, 0x0);
275
276 struct wlr_virtual_pointer_v1_new_pointer_event event = {
277 .new_pointer = virtual_pointer,
278 };
279
280 if (seat) {
281 struct wlr_seat_client *seat_client =
282 wlr_seat_client_from_resource(seat);
283 event.suggested_seat = seat_client->seat;
284 }
285
286 if (output) {
287 struct wlr_output *wlr_output = wlr_output_from_resource(output);
288 event.suggested_output = wlr_output;
289 }
290
291 virtual_pointer->input_device.pointer = pointer;
292 virtual_pointer->resource = pointer_resource;
293 wl_signal_init(&virtual_pointer->events.destroy);
294
295 wl_list_insert(&manager->virtual_pointers, &virtual_pointer->link);
296 wlr_signal_emit_safe(&manager->events.new_virtual_pointer, &event);
297 }
298
virtual_pointer_manager_create_virtual_pointer(struct wl_client * client,struct wl_resource * resource,struct wl_resource * seat,uint32_t id)299 static void virtual_pointer_manager_create_virtual_pointer(
300 struct wl_client *client, struct wl_resource *resource,
301 struct wl_resource *seat, uint32_t id) {
302 virtual_pointer_manager_create_virtual_pointer_with_output(client,
303 resource, seat, NULL, id);
304 }
virtual_pointer_manager_destroy(struct wl_client * client,struct wl_resource * resource)305 static void virtual_pointer_manager_destroy(struct wl_client *client,
306 struct wl_resource *resource) {
307 wl_resource_destroy(resource);
308 }
309
310 static const struct zwlr_virtual_pointer_manager_v1_interface manager_impl = {
311 .create_virtual_pointer = virtual_pointer_manager_create_virtual_pointer,
312 .create_virtual_pointer_with_output = virtual_pointer_manager_create_virtual_pointer_with_output,
313 .destroy = virtual_pointer_manager_destroy,
314 };
315
virtual_pointer_manager_bind(struct wl_client * client,void * data,uint32_t version,uint32_t id)316 static void virtual_pointer_manager_bind(struct wl_client *client, void *data,
317 uint32_t version, uint32_t id) {
318 struct wlr_virtual_pointer_manager_v1 *manager = data;
319
320 struct wl_resource *resource = wl_resource_create(client,
321 &zwlr_virtual_pointer_manager_v1_interface, version, id);
322
323 if (!resource) {
324 wl_client_post_no_memory(client);
325 return;
326 }
327
328 wl_resource_set_implementation(resource, &manager_impl, manager, NULL);
329 }
330
handle_display_destroy(struct wl_listener * listener,void * data)331 static void handle_display_destroy(struct wl_listener *listener, void *data) {
332 struct wlr_virtual_pointer_manager_v1 *manager =
333 wl_container_of(listener, manager, display_destroy);
334 wlr_signal_emit_safe(&manager->events.destroy, manager);
335 wl_list_remove(&manager->display_destroy.link);
336 wl_global_destroy(manager->global);
337 struct wlr_virtual_pointer_v1 *pointer, *pointer_tmp;
338 wl_list_for_each_safe(pointer, pointer_tmp,
339 &manager->virtual_pointers, link) {
340 wl_resource_destroy(pointer->resource);
341 }
342 free(manager);
343 }
344
wlr_virtual_pointer_manager_v1_create(struct wl_display * display)345 struct wlr_virtual_pointer_manager_v1* wlr_virtual_pointer_manager_v1_create(
346 struct wl_display *display) {
347 struct wlr_virtual_pointer_manager_v1 *manager = calloc(1,
348 sizeof(struct wlr_virtual_pointer_manager_v1));
349 if (!manager) {
350 return NULL;
351 }
352
353 wl_list_init(&manager->virtual_pointers);
354
355 wl_signal_init(&manager->events.new_virtual_pointer);
356 wl_signal_init(&manager->events.destroy);
357 manager->global = wl_global_create(display,
358 &zwlr_virtual_pointer_manager_v1_interface, 2, manager,
359 virtual_pointer_manager_bind);
360 if (!manager->global) {
361 free(manager);
362 return NULL;
363 }
364
365 manager->display_destroy.notify = handle_display_destroy;
366 wl_display_add_destroy_listener(display, &manager->display_destroy);
367 return manager;
368 }
369