main shrub/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	pointer->x = wl_fixed_from_int(geom->x + geom->width / 2);
495	pointer->y = wl_fixed_from_int(geom->y + geom->height / 2);
496	pointer->focus_handler.enter = enter;
497	pointer->focus_handler.leave = leave;
498	pointer->client_handler.motion = client_handle_motion;
499	pointer->client_handler.button = client_handle_button;
500	pointer->client_handler.axis = client_handle_axis;
501	pointer->client_handler.frame = client_handle_frame;
502	pointer->client_handler.pending = false;
503	pointer->client_axis_source = -1;
504	wl_list_init(&pointer->handlers);
505	wl_list_insert(&pointer->handlers, &pointer->client_handler.link);
506	wl_array_init(&pointer->buttons);
507
508	view_initialize(&pointer->cursor.view, &view_impl);
509	pointer->cursor.surface = NULL;
510	pointer->cursor.destroy_listener.notify = &handle_cursor_surface_destroy;
511	pointer->cursor.buffer = wld_create_buffer(
512	    swc.drm->context, swc.drm->cursor_w, swc.drm->cursor_h,
513	    WLD_FORMAT_ARGB8888, WLD_FLAG_MAP | WLD_FLAG_CURSOR);
514	pointer->cursor.internal_buffer = NULL;
515
516	if (!pointer->cursor.buffer) {
517		return false;
518	}
519
520	pointer_set_cursor(pointer, cursor_left_ptr);
521
522	wl_list_for_each(screen, &swc.screens, link)
523	    view_attach(&screen->planes.cursor->view, pointer->cursor.buffer);
524
525	input_focus_initialize(&pointer->focus, &pointer->focus_handler);
526	pixman_region32_init(&pointer->region);
527
528	return true;
529}
530
531void
532pointer_finalize(struct pointer *pointer)
533{
534	input_focus_finalize(&pointer->focus);
535	pixman_region32_fini(&pointer->region);
536}
537
538void
539pointer_set_focus(struct pointer *pointer, struct compositor_view *view)
540{
541	input_focus_set(&pointer->focus, view);
542}
543
544static void
545clip_position(struct pointer *pointer, wl_fixed_t fx, wl_fixed_t fy)
546{
547	int32_t x, y, last_x, last_y;
548	pixman_box32_t box;
549
550	x = wl_fixed_to_int(fx);
551	y = wl_fixed_to_int(fy);
552	last_x = wl_fixed_to_int(pointer->x);
553	last_y = wl_fixed_to_int(pointer->y);
554
555	if (!pixman_region32_contains_point(&pointer->region, x, y, NULL)) {
556		if (!pixman_region32_contains_point(&pointer->region, last_x, last_y,
557		                                    &box)) {
558			WARNING("cursor is not in the visible screen area\n");
559			pointer->x = 0;
560			pointer->y = 0;
561			return;
562		}
563
564		/* Do some clipping. */
565		fx = wl_fixed_from_int(MAX(MIN(x, box.x2 - 1), box.x1));
566		fy = wl_fixed_from_int(MAX(MIN(y, box.y2 - 1), box.y1));
567	}
568
569	pointer->x = fx;
570	pointer->y = fy;
571}
572
573void
574pointer_set_region(struct pointer *pointer, pixman_region32_t *region)
575{
576	pixman_region32_copy(&pointer->region, region);
577	clip_position(pointer, pointer->x, pointer->y);
578}
579
580static void
581set_cursor(struct wl_client *client, struct wl_resource *resource,
582           uint32_t serial, struct wl_resource *surface_resource,
583           int32_t hotspot_x, int32_t hotspot_y)
584{
585	struct pointer *pointer = wl_resource_get_user_data(resource);
586	struct surface *surface;
587
588	(void)serial;
589
590	if (client != pointer->focus.client) {
591		return;
592	}
593
594	/* If forcing compositor cursor, ignore client cursor surfaces. */
595	if (cursor_mode == SWC_CURSOR_MODE_COMPOSITOR ||
596	    cursor_override != SWC_CURSOR_DEFAULT) {
597		return;
598	}
599
600	if (pointer->cursor.surface) {
601		surface_set_view(pointer->cursor.surface, NULL);
602		wl_list_remove(&pointer->cursor.destroy_listener.link);
603	}
604
605	surface =
606	    surface_resource ? wl_resource_get_user_data(surface_resource) : NULL;
607	pointer->cursor.surface = surface;
608	pointer->cursor.hotspot.x = hotspot_x;
609	pointer->cursor.hotspot.y = hotspot_y;
610
611	if (surface) {
612		surface_set_view(surface, &pointer->cursor.view);
613		wl_resource_add_destroy_listener(surface->resource,
614		                                 &pointer->cursor.destroy_listener);
615		update_cursor(pointer);
616	}
617}
618
619static const struct wl_pointer_interface pointer_impl = {
620    .set_cursor = set_cursor,
621    .release = destroy_resource,
622};
623
624static void
625unbind(struct wl_resource *resource)
626{
627	struct pointer *pointer = wl_resource_get_user_data(resource);
628	input_focus_remove_resource(&pointer->focus, resource);
629}
630
631struct wl_resource *
632pointer_bind(struct pointer *pointer, struct wl_client *client,
633             uint32_t version, uint32_t id)
634{
635	struct wl_resource *client_resource;
636
637	client_resource =
638	    wl_resource_create(client, &wl_pointer_interface, version, id);
639	if (!client_resource) {
640		return NULL;
641	}
642	wl_resource_set_implementation(client_resource, &pointer_impl, pointer,
643	                               &unbind);
644	input_focus_add_resource(&pointer->focus, client_resource);
645
646	return client_resource;
647}
648
649struct button *
650pointer_get_button(struct pointer *pointer, uint32_t serial)
651{
652	struct button *button;
653
654	wl_array_for_each(button, &pointer->buttons)
655	{
656		if (button->press.serial == serial) {
657			return button;
658		}
659	}
660
661	return NULL;
662}
663
664void
665pointer_handle_button(struct pointer *pointer, uint32_t time, uint32_t value,
666                      uint32_t state)
667{
668	struct pointer_handler *handler;
669	struct button *button;
670	uint32_t serial;
671
672	serial = wl_display_next_serial(swc.display);
673
674	if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
675		wl_array_for_each(button, &pointer->buttons)
676		{
677			if (button->press.value == value) {
678				if (button->handler) {
679					button->press.serial = serial;
680					button->handler->button(button->handler, time, button,
681					                        state);
682					button->handler->pending = true;
683				}
684
685				array_remove(&pointer->buttons, button, sizeof(*button));
686				break;
687			}
688		}
689	} else {
690		button = wl_array_add(&pointer->buttons, sizeof(*button));
691
692		if (!button) {
693			return;
694		}
695
696		button->press.value = value;
697		button->press.serial = serial;
698		button->handler = NULL;
699
700		wl_list_for_each(handler, &pointer->handlers, link)
701		{
702			if (handler->button &&
703			    handler->button(handler, time, button, state)) {
704				button->handler = handler;
705				handler->pending = true;
706				break;
707			}
708		}
709	}
710}
711
712void
713pointer_handle_axis(struct pointer *pointer, uint32_t time,
714                    enum wl_pointer_axis axis,
715                    enum wl_pointer_axis_source source, wl_fixed_t value,
716                    int value120)
717{
718	struct pointer_handler *handler;
719
720	wl_list_for_each(handler, &pointer->handlers, link)
721	{
722		if (handler->axis &&
723		    handler->axis(handler, time, axis, source, value, value120)) {
724			handler->pending = true;
725			break;
726		}
727	}
728}
729
730void
731pointer_handle_relative_motion(struct pointer *pointer, uint32_t time,
732                               wl_fixed_t dx, wl_fixed_t dy)
733{
734	pointer_handle_absolute_motion(pointer, time, pointer->x + dx,
735	                               pointer->y + dy);
736}
737
738void
739pointer_handle_absolute_motion(struct pointer *pointer, uint32_t time,
740                               wl_fixed_t x, wl_fixed_t y)
741{
742	struct pointer_handler *handler;
743
744	clip_position(pointer, x, y);
745
746	wl_list_for_each(handler, &pointer->handlers, link)
747	{
748		if (handler->motion &&
749		    handler->motion(handler, time, pointer->x, pointer->y)) {
750			handler->pending = true;
751			break;
752		}
753	}
754
755	update_cursor(pointer);
756}
757
758void
759pointer_handle_frame(struct pointer *pointer)
760{
761	struct pointer_handler *handler;
762
763	wl_list_for_each(handler, &pointer->handlers, link)
764	{
765		if (handler->pending && handler->frame) {
766			handler->frame(handler);
767			handler->pending = false;
768		}
769	}
770
771	update_cursor(pointer);
772}