xdg-shell: show/hide the left_ptr cursor

Add timeout handling in the Wayland client loop, show the left pointer
image as cursor on entry/movement/button/axis, and hide it after the
usual timeout. This fixes #20531.
This commit is contained in:
Rémi Denis-Courmont 2018-05-24 20:27:07 +03:00
parent 2c221ec773
commit 3caea5a4e8
3 changed files with 92 additions and 6 deletions

View File

@ -45,7 +45,12 @@ struct seat_data
{
vout_window_t *owner;
struct wl_seat *seat;
struct wl_pointer *pointer;
mtime_t cursor_timeout;
mtime_t cursor_deadline;
uint32_t cursor_serial;
#ifdef HAVE_XKBCOMMON
struct xkb_context *xkb;
struct wl_keyboard *keyboard;
@ -58,12 +63,27 @@ struct seat_data
struct wl_list node;
};
static void pointer_show(struct seat_data *sd, struct wl_pointer *pointer)
{
int hsx, hsy;
struct wl_surface *surface = window_get_cursor(sd->owner, &hsx, &hsy);
if (surface != NULL)
{
wl_pointer_set_cursor(pointer, sd->cursor_serial, surface, hsx, hsy);
sd->cursor_deadline = mdate() + sd->cursor_timeout;
}
}
static void pointer_enter_cb(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t sx, wl_fixed_t sy)
{
(void) data; (void) pointer; (void) serial; (void) surface;
(void) sx; (void) sy; /* TODO: set_cursor */
struct seat_data *sd = data;
sd->cursor_serial = serial;
pointer_show(sd, pointer);
(void) surface; (void) sx; (void) sy;
}
static void pointer_leave_cb(void *data, struct wl_pointer *pointer,
@ -77,9 +97,10 @@ static void pointer_motion_cb(void *data, struct wl_pointer *pointer,
{
struct seat_data *sd = data;
pointer_show(sd, pointer);
vout_window_ReportMouseMoved(sd->owner,
wl_fixed_to_int(sx), wl_fixed_to_int(sy));
(void) pointer; (void) time;
(void) time;
}
static void pointer_button_cb(void *data, struct wl_pointer *pointer,
@ -89,6 +110,8 @@ static void pointer_button_cb(void *data, struct wl_pointer *pointer,
struct seat_data *sd = data;
int button;
pointer_show(sd, pointer);
switch (keycode)
{
case BTN_LEFT:
@ -114,7 +137,7 @@ static void pointer_button_cb(void *data, struct wl_pointer *pointer,
break;
}
(void) pointer; (void) serial; (void) time;
(void) serial; (void) time;
}
static void pointer_axis_cb(void *data, struct wl_pointer *pointer,
@ -125,6 +148,7 @@ static void pointer_axis_cb(void *data, struct wl_pointer *pointer,
int button;
bool plus = value > 0;
pointer_show(sd, pointer);
value = abs(value);
switch (type)
@ -145,7 +169,7 @@ static void pointer_axis_cb(void *data, struct wl_pointer *pointer,
vout_window_ReportMouseReleased(wnd, button);
value -= wl_fixed_from_int(10);
}
(void) pointer; (void) serial;
(void) serial;
}
static void pointer_frame_cb(void *data, struct wl_pointer *pointer)
@ -192,6 +216,10 @@ static void pointer_create(struct seat_data *sd)
sd->pointer = wl_seat_get_pointer(sd->seat);
if (likely(sd->pointer != NULL))
wl_pointer_add_listener(sd->pointer, &pointer_cbs, sd);
sd->cursor_timeout = var_InheritInteger(sd->owner, "mouse-hide-timeout")
* (CLOCK_FREQ / 1000);
sd->cursor_deadline = INT64_MAX;
}
static void pointer_destroy(struct seat_data *sd)
@ -425,6 +453,20 @@ int seat_create(vout_window_t *wnd, struct wl_registry *registry,
return 0;
}
static mtime_t seat_next_deadline(const struct seat_data *sd)
{
return (sd->pointer != NULL) ? sd->cursor_deadline : INT64_MAX;
}
static void seat_refresh(struct seat_data *sd, mtime_t now)
{
if (sd->pointer != NULL && sd->cursor_deadline <= now)
{ /* Hide cursor */
wl_pointer_set_cursor(sd->pointer, sd->cursor_serial, NULL, 0, 0);
sd->cursor_deadline = INT64_MAX;
}
}
static void seat_destroy(struct seat_data *sd)
{
wl_list_remove(&sd->node);
@ -466,3 +508,34 @@ void seat_destroy_all(struct wl_list *list)
while (!wl_list_empty(list))
seat_destroy(container_of(list->next, struct seat_data, node));
}
int seat_next_timeout(const struct wl_list *list)
{
struct seat_data *sd;
mtime_t deadline = INT64_MAX;
wl_list_for_each(sd, list, node)
{
mtime_t d = seat_next_deadline(sd);
if (deadline > d)
deadline = d;
}
if (deadline == INT64_MAX)
return -1;
mtime_t now = mdate();
if (now >= deadline)
return 0;
return (deadline - now) / 1000 + 1;
}
void seat_timeout(struct wl_list *list)
{
struct seat_data *sd;
mtime_t now = mdate();
wl_list_for_each(sd, list, node)
seat_refresh(sd, now);
}

View File

@ -20,9 +20,16 @@
struct vout_window_t;
struct wl_registry;
struct wl_surface;
struct wl_list;
int seat_create(struct vout_window_t *wnd, struct wl_registry *,
uint32_t name, uint32_t version, struct wl_list *list);
int seat_destroy_one(struct wl_list *list, uint32_t name);
void seat_destroy_all(struct wl_list *list);
int seat_next_timeout(const struct wl_list *list);
void seat_timeout(struct wl_list *list);
struct wl_surface *window_get_cursor(vout_window_t *wnd, int32_t *hotspot_x,
int32_t *hotspot_y);

View File

@ -124,15 +124,21 @@ static void *Thread(void *data)
for (;;)
{
int timeout;
while (wl_display_prepare_read(display) != 0)
wl_display_dispatch_pending(display);
wl_display_flush(display);
timeout = seat_next_timeout(&sys->seats);
vlc_restorecancel(canc);
while (poll(ufd, 1, -1) < 0);
int val = poll(ufd, 1, timeout);
canc = vlc_savecancel();
if (val == 0)
seat_timeout(&sys->seats);
wl_display_read_events(display);
wl_display_dispatch_pending(display);
}