main neuswc / libswc / pointer.c
  1/* swc: libswc/pointer.c
  2 *
  3 * Copyright (c) 2013-2020 Michael Forney
  4 *
  5 * Permission is hereby granted, free of charge, to any person obtaining a copy
  6 * of this software and associated documentation files (the "Software"), to deal
  7 * in the Software without restriction, including without limitation the rights
  8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 * copies of the Software, and to permit persons to whom the Software is
 10 * furnished to do so, subject to the following conditions:
 11 *
 12 * The above copyright notice and this permission notice shall be included in
 13 * all copies or substantial portions of the Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21 * SOFTWARE.
 22 */
 23
 24#include "pointer.h"
 25#include "compositor.h"
 26#include "cursor/cursor_data.h"
 27#include "event.h"
 28#include "internal.h"
 29#include "plane.h"
 30#include "screen.h"
 31#include "seat.h"
 32#include "shm.h"
 33#include "surface.h"
 34#include "util.h"
 35
 36#include <assert.h>
 37#include <stdio.h>
 38#include <string.h>
 39#include <wld/wld.h>
 40
 41static enum swc_cursor_kind cursor_override = SWC_CURSOR_DEFAULT;
 42static enum swc_cursor_mode cursor_mode = SWC_CURSOR_MODE_CLIENT;
 43
 44static struct {
 45	const uint32_t *data;
 46	uint32_t width, height;
 47	int32_t hotspot_x, hotspot_y;
 48	bool active;
 49} cursor_images[6];
 50
 51EXPORT void
 52swc_pointer_send_button(uint32_t time, uint32_t button, uint32_t state)
 53{
 54	struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
 55	struct wl_resource *resource;
 56	uint32_t serial;
 57
 58	if (!pointer || wl_list_empty(&pointer->focus.active)) {
 59		return;
 60	}
 61
 62	serial = wl_display_next_serial(swc.display);
 63	wl_resource_for_each(resource, &pointer->focus.active)
 64	    wl_pointer_send_button(resource, serial, time, button, state);
 65	wl_resource_for_each(resource, &pointer->focus.active)
 66	{
 67		if (wl_resource_get_version(resource) >=
 68		    WL_POINTER_FRAME_SINCE_VERSION) {
 69			wl_pointer_send_frame(resource);
 70		}
 71	}
 72	pointer->client_axis_source = -1;
 73}
 74
 75EXPORT void
 76swc_pointer_send_axis(uint32_t time, uint32_t axis, int32_t value120)
 77{
 78	struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
 79	struct wl_resource *resource;
 80	wl_fixed_t value;
 81
 82	if (!pointer || wl_list_empty(&pointer->focus.active)) {
 83		return;
 84	}
 85
 86	value = wl_fixed_from_double((double)value120 / 120.0);
 87
 88	wl_resource_for_each(resource, &pointer->focus.active)
 89	{
 90		int ver = wl_resource_get_version(resource);
 91
 92		if (ver >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
 93			wl_pointer_send_axis_source(resource, WL_POINTER_AXIS_SOURCE_WHEEL);
 94		}
 95		if (value120) {
 96			if (ver >= WL_POINTER_AXIS_VALUE120_SINCE_VERSION) {
 97				wl_pointer_send_axis_value120(resource, axis, value120);
 98			} else if (ver >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
 99				wl_pointer_send_axis_discrete(resource, axis, value120 / 120);
100			}
101		}
102
103		if (value) {
104			wl_pointer_send_axis(resource, time, axis, value);
105		} else if (ver >= WL_POINTER_AXIS_STOP_SINCE_VERSION) {
106			wl_pointer_send_axis_stop(resource, time, axis);
107		}
108	}
109
110	wl_resource_for_each(resource, &pointer->focus.active)
111	{
112		if (wl_resource_get_version(resource) >=
113		    WL_POINTER_FRAME_SINCE_VERSION) {
114			wl_pointer_send_frame(resource);
115		}
116	}
117	pointer->client_axis_source = -1;
118}
119
120static void
121enter(struct input_focus_handler *handler, struct wl_list *resources,
122      struct compositor_view *view)
123{
124	struct pointer *pointer = wl_container_of(handler, pointer, focus_handler);
125	struct wl_resource *resource;
126	uint32_t serial;
127	wl_fixed_t surface_x, surface_y;
128	int32_t origin_x, origin_y;
129
130	if (wl_list_empty(resources)) {
131		pointer_set_cursor(pointer, cursor_left_ptr);
132		return;
133	}
134	serial = wl_display_next_serial(swc.display);
135	/* do based on buffer origin, holy fuck */
136	origin_x = view->base.geometry.x - view->buffer_offset_x;
137	origin_y = view->base.geometry.y - view->buffer_offset_y;
138	surface_x = pointer->x - wl_fixed_from_int(origin_x);
139	surface_y = pointer->y - wl_fixed_from_int(origin_y);
140	wl_resource_for_each(resource, resources) wl_pointer_send_enter(
141	    resource, serial, view->surface->resource, surface_x, surface_y);
142}
143
144static void
145leave(struct input_focus_handler *handler, struct wl_list *resources,
146      struct compositor_view *view)
147{
148	struct wl_resource *resource;
149	uint32_t serial;
150
151	serial = wl_display_next_serial(swc.display);
152	wl_resource_for_each(resource, resources)
153	    wl_pointer_send_leave(resource, serial, view->surface->resource);
154}
155
156static void
157handle_cursor_surface_destroy(struct wl_listener *listener, void *data)
158{
159	struct pointer *pointer =
160	    wl_container_of(listener, pointer, cursor.destroy_listener);
161
162	view_attach(&pointer->cursor.view, NULL);
163	pointer->cursor.surface = NULL;
164}
165
166static bool
167update(struct view *view)
168{
169	view_frame(view, get_time());
170	return true;
171}
172
173static int
174attach(struct view *view, struct wld_buffer *buffer)
175{
176	struct pointer *pointer = wl_container_of(view, pointer, cursor.view);
177	struct surface *surface = pointer->cursor.surface;
178	struct screen *screen;
179
180	if (surface && !pixman_region32_not_empty(&surface->state.damage)) {
181		return 0;
182	}
183
184	wld_set_target_buffer(swc.shm->renderer, pointer->cursor.buffer);
185	wld_fill_rectangle(swc.shm->renderer, 0x00000000, 0, 0,
186	                   pointer->cursor.buffer->width,
187	                   pointer->cursor.buffer->height);
188
189	if (buffer) {
190		wld_copy_rectangle(swc.shm->renderer, buffer, 0, 0, 0, 0, buffer->width,
191		                   buffer->height);
192	}
193
194	wld_flush(swc.shm->renderer);
195
196	if (surface) {
197		pixman_region32_clear(&surface->state.damage);
198	}
199
200	/* TODO: Send an early release to the buffer */
201
202	if (view_set_size_from_buffer(view, buffer)) {
203		view_update_screens(view);
204	}
205
206	wl_list_for_each(screen, &swc.screens, link)
207	{
208		view_attach(&screen->planes.cursor->view,
209		            buffer ? pointer->cursor.buffer : NULL);
210		view_update(&screen->planes.cursor->view);
211	}
212
213	return 0;
214}
215
216static bool
217move(struct view *view, int32_t x, int32_t y)
218{
219	struct screen *screen;
220
221	if (view_set_position(view, x, y)) {
222		view_update_screens(view);
223	}
224
225	wl_list_for_each(screen, &swc.screens, link)
226	{
227		view_move(&screen->planes.cursor->view, view->geometry.x,
228		          view->geometry.y);
229		view_update(&screen->planes.cursor->view);
230	}
231
232	return true;
233}
234
235static const struct view_impl view_impl = {
236    .update = update,
237    .attach = attach,
238    .move = move,
239};
240
241static inline void
242update_cursor(struct pointer *pointer)
243{
244	int32_t x = wl_fixed_to_int(pointer->x) - pointer->cursor.hotspot.x,
245	        y = wl_fixed_to_int(pointer->y) - pointer->cursor.hotspot.y;
246
247	view_move(&pointer->cursor.view, x, y);
248}
249
250static void
251drop_client_cursor_surface(struct pointer *pointer)
252{
253	if (!pointer || !pointer->cursor.surface) {
254		return;
255	}
256	surface_set_view(pointer->cursor.surface, NULL);
257	wl_list_remove(&pointer->cursor.destroy_listener.link);
258	pointer->cursor.surface = NULL;
259}
260
261static void
262apply_cursor_override(struct pointer *pointer)
263{
264	if (!pointer || pointer->cursor.surface) {
265		return;
266	}
267
268	pointer_set_cursor(pointer, cursor_left_ptr);
269}
270
271EXPORT void
272swc_set_cursor(enum swc_cursor_kind kind)
273{
274	struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
275
276	cursor_override = kind;
277
278	drop_client_cursor_surface(pointer);
279
280	apply_cursor_override(pointer);
281}
282
283EXPORT void
284swc_set_cursor_mode(enum swc_cursor_mode mode)
285{
286	struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
287
288	cursor_mode = mode;
289	if (cursor_mode == SWC_CURSOR_MODE_COMPOSITOR) {
290		drop_client_cursor_surface(pointer);
291	}
292	apply_cursor_override(pointer);
293}
294
295EXPORT void
296swc_set_cursor_image(enum swc_cursor_kind kind, const uint32_t *argb8888,
297                     uint32_t width, uint32_t height, int32_t hotspot_x,
298                     int32_t hotspot_y)
299{
300	struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
301
302	if (kind < 0 || kind >= (int)ARRAY_LENGTH(cursor_images)) {
303		return;
304	}
305	if (!argb8888 || width == 0 || height == 0) {
306		return;
307	}
308
309	cursor_images[kind].data = argb8888;
310	cursor_images[kind].width = width;
311	cursor_images[kind].height = height;
312	cursor_images[kind].hotspot_x = hotspot_x;
313	cursor_images[kind].hotspot_y = hotspot_y;
314	cursor_images[kind].active = true;
315
316	if (cursor_mode == SWC_CURSOR_MODE_COMPOSITOR) {
317		drop_client_cursor_surface(pointer);
318	}
319	apply_cursor_override(pointer);
320}
321
322EXPORT void
323swc_clear_cursor_image(enum swc_cursor_kind kind)
324{
325	struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
326
327	if (kind < 0 || kind >= (int)ARRAY_LENGTH(cursor_images)) {
328		return;
329	}
330
331	cursor_images[kind].active = false;
332	cursor_images[kind].data = NULL;
333
334	apply_cursor_override(pointer);
335}
336
337void
338pointer_set_cursor(struct pointer *pointer, uint32_t id)
339{
340	struct cursor *cursor = &cursor_metadata[id];
341	const uint32_t *data = cursor_data;
342	union wld_object object = {.ptr = &cursor_data[cursor->offset]};
343	struct wld_buffer *buffer;
344
345	if (id == cursor_left_ptr) {
346		enum swc_cursor_kind kind = cursor_override;
347		if (kind < 0 || kind >= (int)ARRAY_LENGTH(cursor_images)) {
348			kind = SWC_CURSOR_DEFAULT;
349		}
350
351		if (cursor_images[kind].active) {
352			static struct cursor custom_cursor;
353			custom_cursor.width = (int)cursor_images[kind].width;
354			custom_cursor.height = (int)cursor_images[kind].height;
355			custom_cursor.hotspot_x = (int)cursor_images[kind].hotspot_x;
356			custom_cursor.hotspot_y = (int)cursor_images[kind].hotspot_y;
357			custom_cursor.offset = 0;
358
359			cursor = &custom_cursor;
360			data = cursor_images[kind].data;
361			object.ptr = (void *)data;
362		}
363	}
364
365	if (pointer->cursor.internal_buffer) {
366		wld_buffer_unreference(pointer->cursor.internal_buffer);
367	}
368	if (pointer->cursor.surface) {
369		surface_set_view(pointer->cursor.surface, NULL);
370		wl_list_remove(&pointer->cursor.destroy_listener.link);
371		pointer->cursor.surface = NULL;
372	}
373
374	buffer = wld_import_buffer(swc.shm->context, WLD_OBJECT_DATA, object,
375	                           cursor->width, cursor->height,
376	                           WLD_FORMAT_ARGB8888, cursor->width * 4);
377	if (!buffer) {
378		WARNING("Failed to create cursor buffer\n");
379	}
380	pointer->cursor.internal_buffer = buffer;
381	pointer->cursor.hotspot.x = cursor->hotspot_x;
382	pointer->cursor.hotspot.y = cursor->hotspot_y;
383	update_cursor(pointer);
384	view_attach(&pointer->cursor.view, buffer);
385}
386
387static bool
388client_handle_motion(struct pointer_handler *handler, uint32_t time,
389                     wl_fixed_t x, wl_fixed_t y)
390{
391	struct pointer *pointer = wl_container_of(handler, pointer, client_handler);
392	struct wl_resource *resource;
393	wl_fixed_t sx, sy;
394	int32_t origin_x, origin_y;
395
396	if (wl_list_empty(&pointer->focus.active)) {
397		return false;
398	}
399
400	origin_x = pointer->focus.view->base.geometry.x -
401	           pointer->focus.view->buffer_offset_x;
402	origin_y = pointer->focus.view->base.geometry.y -
403	           pointer->focus.view->buffer_offset_y;
404	sx = x - wl_fixed_from_int(origin_x);
405	sy = y - wl_fixed_from_int(origin_y);
406	wl_resource_for_each(resource, &pointer->focus.active)
407	    wl_pointer_send_motion(resource, time, sx, sy);
408	return true;
409}
410
411static bool
412client_handle_button(struct pointer_handler *handler, uint32_t time,
413                     struct button *button, uint32_t state)
414{
415	struct pointer *pointer = wl_container_of(handler, pointer, client_handler);
416	struct wl_resource *resource;
417
418	if (wl_list_empty(&pointer->focus.active)) {
419		return false;
420	}
421
422	wl_resource_for_each(resource, &pointer->focus.active)
423	    wl_pointer_send_button(resource, button->press.serial, time,
424	                           button->press.value, state);
425	return true;
426}
427
428static bool
429client_handle_axis(struct pointer_handler *handler, uint32_t time,
430                   enum wl_pointer_axis axis,
431                   enum wl_pointer_axis_source source, wl_fixed_t value,
432                   int value120)
433{
434	struct pointer *pointer = wl_container_of(handler, pointer, client_handler);
435	struct wl_resource *resource;
436	int ver;
437
438	if (wl_list_empty(&pointer->focus.active)) {
439		return false;
440	}
441
442	if (pointer->client_axis_source != -1) {
443		assert(pointer->client_axis_source == source);
444		source = -1;
445	} else {
446		pointer->client_axis_source = source;
447	}
448
449	wl_resource_for_each(resource, &pointer->focus.active)
450	{
451		ver = wl_resource_get_version(resource);
452		if (source != -1 && ver >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
453			wl_pointer_send_axis_source(resource, source);
454		}
455		if (value120) {
456			if (ver >= WL_POINTER_AXIS_VALUE120_SINCE_VERSION) {
457				wl_pointer_send_axis_value120(resource, axis, value120);
458			} else if (ver >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
459				wl_pointer_send_axis_discrete(resource, axis, value120 / 120);
460			}
461		}
462		if (value) {
463			wl_pointer_send_axis(resource, time, axis, value);
464		} else if (ver >= WL_POINTER_AXIS_STOP_SINCE_VERSION) {
465			wl_pointer_send_axis_stop(resource, time, axis);
466		}
467	}
468	return true;
469}
470
471static void
472client_handle_frame(struct pointer_handler *handler)
473{
474	struct pointer *pointer = wl_container_of(handler, pointer, client_handler);
475	struct wl_resource *resource;
476
477	wl_resource_for_each(resource, &pointer->focus.active)
478	{
479		if (wl_resource_get_version(resource) >=
480		    WL_POINTER_FRAME_SINCE_VERSION) {
481			wl_pointer_send_frame(resource);
482		}
483	}
484	pointer->client_axis_source = -1;
485}
486
487bool
488pointer_initialize(struct pointer *pointer)
489{
490	struct screen *screen = wl_container_of(swc.screens.next, screen, link);
491	struct swc_rectangle *geom = &screen->base.geometry;
492
493	/* Center cursor in the geometry of the first screen. */
494	screen = wl_container_of(swc.screens.next, screen, link);
495	pointer->x = wl_fixed_from_int(geom->x + geom->width / 2);
496	pointer->y = wl_fixed_from_int(geom->y + geom->height / 2);
497	pointer->focus_handler.enter = enter;
498	pointer->focus_handler.leave = leave;
499	pointer->client_handler.motion = client_handle_motion;
500	pointer->client_handler.button = client_handle_button;
501	pointer->client_handler.axis = client_handle_axis;
502	pointer->client_handler.frame = client_handle_frame;
503	pointer->client_handler.pending = false;
504	pointer->client_axis_source = -1;
505	wl_list_init(&pointer->handlers);
506	wl_list_insert(&pointer->handlers, &pointer->client_handler.link);
507	wl_array_init(&pointer->buttons);
508
509	view_initialize(&pointer->cursor.view, &view_impl);
510	pointer->cursor.surface = NULL;
511	pointer->cursor.destroy_listener.notify = &handle_cursor_surface_destroy;
512	pointer->cursor.buffer = wld_create_buffer(
513	    swc.drm->context, swc.drm->cursor_w, swc.drm->cursor_h,
514	    WLD_FORMAT_ARGB8888, WLD_FLAG_MAP | WLD_FLAG_CURSOR);
515	pointer->cursor.internal_buffer = NULL;
516
517	if (!pointer->cursor.buffer) {
518		return false;
519	}
520
521	pointer_set_cursor(pointer, cursor_left_ptr);
522
523	wl_list_for_each(screen, &swc.screens, link)
524	    view_attach(&screen->planes.cursor->view, pointer->cursor.buffer);
525
526	input_focus_initialize(&pointer->focus, &pointer->focus_handler);
527	pixman_region32_init(&pointer->region);
528
529	return true;
530}
531
532void
533pointer_finalize(struct pointer *pointer)
534{
535	input_focus_finalize(&pointer->focus);
536	pixman_region32_fini(&pointer->region);
537}
538
539void
540pointer_set_focus(struct pointer *pointer, struct compositor_view *view)
541{
542	input_focus_set(&pointer->focus, view);
543}
544
545static void
546clip_position(struct pointer *pointer, wl_fixed_t fx, wl_fixed_t fy)
547{
548	int32_t x, y, last_x, last_y;
549	pixman_box32_t box;
550
551	x = wl_fixed_to_int(fx);
552	y = wl_fixed_to_int(fy);
553	last_x = wl_fixed_to_int(pointer->x);
554	last_y = wl_fixed_to_int(pointer->y);
555
556	if (!pixman_region32_contains_point(&pointer->region, x, y, NULL)) {
557		if (!pixman_region32_contains_point(&pointer->region, last_x, last_y,
558		                                    &box)) {
559			WARNING("cursor is not in the visible screen area\n");
560			pointer->x = 0;
561			pointer->y = 0;
562			return;
563		}
564
565		/* Do some clipping. */
566		fx = wl_fixed_from_int(MAX(MIN(x, box.x2 - 1), box.x1));
567		fy = wl_fixed_from_int(MAX(MIN(y, box.y2 - 1), box.y1));
568	}
569
570	pointer->x = fx;
571	pointer->y = fy;
572}
573
574void
575pointer_set_region(struct pointer *pointer, pixman_region32_t *region)
576{
577	pixman_region32_copy(&pointer->region, region);
578	clip_position(pointer, pointer->x, pointer->y);
579}
580
581static void
582set_cursor(struct wl_client *client, struct wl_resource *resource,
583           uint32_t serial, struct wl_resource *surface_resource,
584           int32_t hotspot_x, int32_t hotspot_y)
585{
586	struct pointer *pointer = wl_resource_get_user_data(resource);
587	struct surface *surface;
588
589	(void)serial;
590
591	if (client != pointer->focus.client) {
592		return;
593	}
594
595	/* If forcing compositor cursor, ignore client cursor surfaces. */
596	if (cursor_mode == SWC_CURSOR_MODE_COMPOSITOR ||
597	    cursor_override != SWC_CURSOR_DEFAULT) {
598		return;
599	}
600
601	if (pointer->cursor.surface) {
602		surface_set_view(pointer->cursor.surface, NULL);
603		wl_list_remove(&pointer->cursor.destroy_listener.link);
604	}
605
606	surface =
607	    surface_resource ? wl_resource_get_user_data(surface_resource) : NULL;
608	pointer->cursor.surface = surface;
609	pointer->cursor.hotspot.x = hotspot_x;
610	pointer->cursor.hotspot.y = hotspot_y;
611
612	if (surface) {
613		surface_set_view(surface, &pointer->cursor.view);
614		wl_resource_add_destroy_listener(surface->resource,
615		                                 &pointer->cursor.destroy_listener);
616		update_cursor(pointer);
617	}
618}
619
620static const struct wl_pointer_interface pointer_impl = {
621    .set_cursor = set_cursor,
622    .release = destroy_resource,
623};
624
625static void
626unbind(struct wl_resource *resource)
627{
628	struct pointer *pointer = wl_resource_get_user_data(resource);
629	input_focus_remove_resource(&pointer->focus, resource);
630}
631
632struct wl_resource *
633pointer_bind(struct pointer *pointer, struct wl_client *client,
634             uint32_t version, uint32_t id)
635{
636	struct wl_resource *client_resource;
637
638	client_resource =
639	    wl_resource_create(client, &wl_pointer_interface, version, id);
640	if (!client_resource) {
641		return NULL;
642	}
643	wl_resource_set_implementation(client_resource, &pointer_impl, pointer,
644	                               &unbind);
645	input_focus_add_resource(&pointer->focus, client_resource);
646
647	return client_resource;
648}
649
650struct button *
651pointer_get_button(struct pointer *pointer, uint32_t serial)
652{
653	struct button *button;
654
655	wl_array_for_each(button, &pointer->buttons)
656	{
657		if (button->press.serial == serial) {
658			return button;
659		}
660	}
661
662	return NULL;
663}
664
665void
666pointer_handle_button(struct pointer *pointer, uint32_t time, uint32_t value,
667                      uint32_t state)
668{
669	struct pointer_handler *handler;
670	struct button *button;
671	uint32_t serial;
672
673	serial = wl_display_next_serial(swc.display);
674
675	if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
676		wl_array_for_each(button, &pointer->buttons)
677		{
678			if (button->press.value == value) {
679				if (button->handler) {
680					button->press.serial = serial;
681					button->handler->button(button->handler, time, button,
682					                        state);
683					button->handler->pending = true;
684				}
685
686				array_remove(&pointer->buttons, button, sizeof(*button));
687				break;
688			}
689		}
690	} else {
691		button = wl_array_add(&pointer->buttons, sizeof(*button));
692
693		if (!button) {
694			return;
695		}
696
697		button->press.value = value;
698		button->press.serial = serial;
699		button->handler = NULL;
700
701		wl_list_for_each(handler, &pointer->handlers, link)
702		{
703			if (handler->button &&
704			    handler->button(handler, time, button, state)) {
705				button->handler = handler;
706				handler->pending = true;
707				break;
708			}
709		}
710	}
711}
712
713void
714pointer_handle_axis(struct pointer *pointer, uint32_t time,
715                    enum wl_pointer_axis axis,
716                    enum wl_pointer_axis_source source, wl_fixed_t value,
717                    int value120)
718{
719	struct pointer_handler *handler;
720
721	wl_list_for_each(handler, &pointer->handlers, link)
722	{
723		if (handler->axis &&
724		    handler->axis(handler, time, axis, source, value, value120)) {
725			handler->pending = true;
726			break;
727		}
728	}
729}
730
731void
732pointer_handle_relative_motion(struct pointer *pointer, uint32_t time,
733                               wl_fixed_t dx, wl_fixed_t dy)
734{
735	pointer_handle_absolute_motion(pointer, time, pointer->x + dx,
736	                               pointer->y + dy);
737}
738
739void
740pointer_handle_absolute_motion(struct pointer *pointer, uint32_t time,
741                               wl_fixed_t x, wl_fixed_t y)
742{
743	struct pointer_handler *handler;
744
745	clip_position(pointer, x, y);
746
747	wl_list_for_each(handler, &pointer->handlers, link)
748	{
749		if (handler->motion &&
750		    handler->motion(handler, time, pointer->x, pointer->y)) {
751			handler->pending = true;
752			break;
753		}
754	}
755
756	update_cursor(pointer);
757}
758
759void
760pointer_handle_frame(struct pointer *pointer)
761{
762	struct pointer_handler *handler;
763
764	wl_list_for_each(handler, &pointer->handlers, link)
765	{
766		if (handler->pending && handler->frame) {
767			handler->frame(handler);
768			handler->pending = false;
769		}
770	}
771
772	update_cursor(pointer);
773}