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