[PATCH weston] window: use wl_cursor_frame_and_duration() for mouse cursor updates
Derek Foreman
derekf at osg.samsung.com
Tue Mar 3 13:26:30 PST 2015
Instead of a frame callback we can now use a timerfd and the time
left in the current cursor frame. This saves us from setting
the cursor at 60hz even when no updates are required.
Signed-off-by: Derek Foreman <derekf at osg.samsung.com>
---
NOTE: this requires a wayland change I just posted...
clients/window.c | 124 +++++++++++++++++++++++++++++++------------------------
1 file changed, 71 insertions(+), 53 deletions(-)
diff --git a/clients/window.c b/clients/window.c
index a04cef9..6cef8d4 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -38,6 +38,7 @@
#include <sys/mman.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
+#include <stdbool.h>
#ifdef HAVE_CAIRO_EGL
#include <wayland-egl.h>
@@ -315,7 +316,9 @@ struct input {
struct window *touch_focus;
int current_cursor;
uint32_t cursor_anim_start;
- struct wl_callback *cursor_frame_cb;
+ int cursor_delay_fd;
+ bool cursor_timer_running;
+ struct task cursor_task;
struct wl_surface *pointer_surface;
uint32_t modifiers;
uint32_t pointer_enter_serial;
@@ -2641,6 +2644,25 @@ input_ungrab(struct input *input)
}
static void
+cursor_delay_timer_reset(struct input *input, uint32_t duration)
+{
+ struct itimerspec its;
+
+ if (!duration)
+ input->cursor_timer_running = false;
+ else
+ input->cursor_timer_running = true;
+
+ its.it_interval.tv_sec = 0;
+ its.it_interval.tv_nsec = 0;
+ its.it_value.tv_sec = duration / 1000;
+ its.it_value.tv_nsec = (duration % 1000) * 1000 * 1000;
+ if (timerfd_settime(input->cursor_delay_fd, 0, &its, NULL) < 0) {
+ fprintf(stderr, "could not set cursor timerfd\n: %m");
+ }
+}
+
+static void
input_remove_pointer_focus(struct input *input)
{
struct window *window = input->pointer_focus;
@@ -2652,6 +2674,7 @@ input_remove_pointer_focus(struct input *input)
input->pointer_focus = NULL;
input->current_cursor = CURSOR_UNSET;
+ cursor_delay_timer_reset(input, 0);
}
static void
@@ -3522,67 +3545,42 @@ input_set_pointer_image_index(struct input *input, int index)
image->hotspot_x, image->hotspot_y);
}
-static const struct wl_callback_listener pointer_surface_listener;
-
static void
-pointer_surface_frame_callback(void *data, struct wl_callback *callback,
- uint32_t time)
+cursor_func(struct task *task, uint32_t events)
{
- struct input *input = data;
+ struct input *input = container_of(task, struct input, cursor_task);
+ struct timespec tp;
struct wl_cursor *cursor;
+ uint32_t time, duration;
+ uint64_t exp;
int i;
- if (callback) {
- assert(callback == input->cursor_frame_cb);
- wl_callback_destroy(callback);
- input->cursor_frame_cb = NULL;
- }
+ if (read(input->cursor_delay_fd, &exp, sizeof (uint64_t)) != sizeof (uint64_t))
+ abort();
- if (!input->pointer)
+ if (!input->cursor_timer_running)
return;
- if (input->current_cursor == CURSOR_BLANK) {
- wl_pointer_set_cursor(input->pointer,
- input->pointer_enter_serial,
- NULL, 0, 0);
- return;
- }
-
- if (input->current_cursor == CURSOR_UNSET)
- return;
cursor = input->display->cursors[input->current_cursor];
if (!cursor)
return;
- /* FIXME We don't have the current time on the first call so we set
- * the animation start to the time of the first frame callback. */
- if (time == 0)
- input->cursor_anim_start = 0;
- else if (input->cursor_anim_start == 0)
- input->cursor_anim_start = time;
-
- if (time == 0 || input->cursor_anim_start == 0)
- i = 0;
- else
- i = wl_cursor_frame(cursor, time - input->cursor_anim_start);
-
- if (cursor->image_count > 1) {
- input->cursor_frame_cb =
- wl_surface_frame(input->pointer_surface);
- wl_callback_add_listener(input->cursor_frame_cb,
- &pointer_surface_listener, input);
- }
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ time = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
+ i = wl_cursor_frame_and_duration(cursor,
+ time - input->cursor_anim_start,
+ &duration);
input_set_pointer_image_index(input, i);
+ cursor_delay_timer_reset(input, duration);
}
-static const struct wl_callback_listener pointer_surface_listener = {
- pointer_surface_frame_callback
-};
-
void
input_set_pointer_image(struct input *input, int pointer)
{
+ struct wl_cursor *cursor;
+ struct timespec tp;
+ uint32_t duration;
int force = 0;
if (!input->pointer)
@@ -3596,17 +3594,31 @@ input_set_pointer_image(struct input *input, int pointer)
input->current_cursor = pointer;
input->cursor_serial = input->pointer_enter_serial;
- if (!input->cursor_frame_cb)
- pointer_surface_frame_callback(input, NULL, 0);
- else if (force) {
- /* The current frame callback may be stuck if, for instance,
- * the set cursor request was processed by the server after
- * this client lost the focus. In this case the cursor surface
- * might not be mapped and the frame callback wouldn't ever
- * complete. Send a set_cursor and attach to try to map the
- * cursor surface again so that the callback will finish */
- input_set_pointer_image_index(input, 0);
+
+ cursor_delay_timer_reset(input, 0);
+
+ if (input->current_cursor == CURSOR_UNSET)
+ return;
+
+ if (input->current_cursor == CURSOR_BLANK) {
+ wl_pointer_set_cursor(input->pointer,
+ input->pointer_enter_serial,
+ NULL, 0, 0);
+ return;
}
+
+ cursor = input->display->cursors[input->current_cursor];
+ if (!cursor)
+ return;
+
+ input_set_pointer_image_index(input, 0);
+ if (cursor->image_count == 1)
+ return;
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ input->cursor_anim_start = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
+ wl_cursor_frame_and_duration(cursor, 0, &duration);
+ cursor_delay_timer_reset(input, duration);
}
struct wl_data_device *
@@ -5165,6 +5177,11 @@ display_add_input(struct display *d, uint32_t id)
}
input->pointer_surface = wl_compositor_create_surface(d->compositor);
+ input->cursor_task.run = cursor_func;
+
+ input->cursor_delay_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+ display_watch_fd(d, input->cursor_delay_fd, EPOLLIN,
+ &input->cursor_task);
set_repeat_info(input, 40, 400);
@@ -5207,6 +5224,7 @@ input_destroy(struct input *input)
wl_list_remove(&input->link);
wl_seat_destroy(input->seat);
close(input->repeat_timer_fd);
+ close(input->cursor_delay_fd);
free(input);
}
--
2.1.4
More information about the wayland-devel
mailing list