From d56bd908bf898cefbc209ea57c47a2c896d96975 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 5 Jun 2012 09:58:51 -0400 Subject: [PATCH] shell: Use a busy cursor animation for unresponsive surfaces --- clients/desktop-shell.c | 64 ++++++++++++++++ clients/window.c | 6 ++ clients/window.h | 3 + protocol/desktop-shell.xml | 4 + src/shell.c | 177 +++++++++++++++++++++++++++++---------------- 5 files changed, 190 insertions(+), 64 deletions(-) diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index cceeadf..b767839 100644 --- a/clients/desktop-shell.c +++ b/clients/desktop-shell.c @@ -46,6 +46,9 @@ struct desktop { struct unlock_dialog *unlock_dialog; struct task unlock_task; struct wl_list outputs; + + struct window *busy_window; + struct widget *busy_widget; }; struct surface { @@ -651,6 +654,64 @@ background_create(struct desktop *desktop) return background; } +static const struct wl_callback_listener busy_cursor_listener; + +static void +busy_cursor_frame_callback(void *data, + struct wl_callback *callback, uint32_t time) +{ + struct input *input = data; + struct display *display = input_get_display(input); + struct desktop *desktop = display_get_user_data(display); + struct wl_surface *surface; + int index; + + if (callback) + wl_callback_destroy(callback); + if (input_get_focus_widget(input) != desktop->busy_widget) + return; + + /* FIXME: Get frame duration and number of frames from cursor. */ + index = (time / 100) % 8; + input_set_pointer_image_index(input, CURSOR_WATCH, index); + + surface = window_get_wl_surface(desktop->busy_window); + callback = wl_surface_frame(surface); + wl_callback_add_listener(callback, &busy_cursor_listener, input); +} + +static const struct wl_callback_listener busy_cursor_listener = { + busy_cursor_frame_callback +}; + +static int +busy_surface_enter_handler(struct widget *widget, struct input *input, + float x, float y, void *data) +{ + busy_cursor_frame_callback(input, NULL, 0); + + return CURSOR_WATCH; +} + +static void +busy_surface_create(struct desktop *desktop) +{ + struct wl_surface *s; + + desktop->busy_window = window_create(desktop->display); + s = window_get_wl_surface(desktop->busy_window); + desktop_shell_set_busy_surface(desktop->shell, s); + + desktop->busy_widget = + window_add_widget(desktop->busy_window, desktop); + /* We set the allocation to 1x1 at 0,0 so the fake enter event + * at 0,0 will go to this widget. */ + widget_set_allocation(desktop->busy_widget, 0, 0, 1, 1); + + widget_set_enter_handler(desktop->busy_widget, + busy_surface_enter_handler); +} + static void create_output(struct desktop *desktop, uint32_t id) { @@ -729,6 +790,7 @@ int main(int argc, char *argv[]) return -1; } + display_set_user_data(desktop.display, &desktop); wl_display_add_global_listener(display_get_display(desktop.display), global_handler, &desktop); @@ -744,6 +806,8 @@ int main(int argc, char *argv[]) desktop_shell_set_background(desktop.shell, output->output, s); } + busy_surface_create(&desktop); + config_file = config_file_path("weston.ini"); ret = parse_config_file(config_file, config_sections, ARRAY_LENGTH(config_sections), diff --git a/clients/window.c b/clients/window.c index 6b36c84..36d8613 100644 --- a/clients/window.c +++ b/clients/window.c @@ -2084,6 +2084,12 @@ input_get_position(struct input *input, int32_t *x, int32_t *y) *y = input->sy; } +struct display * +input_get_display(struct input *input) +{ + return input->display; +} + struct wl_seat * input_get_seat(struct input *input) { diff --git a/clients/window.h b/clients/window.h index 2521964..8b8e816 100644 --- a/clients/window.h +++ b/clients/window.h @@ -389,6 +389,9 @@ input_ungrab(struct input *input); struct widget * input_get_focus_widget(struct input *input); +struct display * +input_get_display(struct input *input); + struct wl_seat * input_get_seat(struct input *input); diff --git a/protocol/desktop-shell.xml b/protocol/desktop-shell.xml index d2bb3eb..a9c181c 100644 --- a/protocol/desktop-shell.xml +++ b/protocol/desktop-shell.xml @@ -23,6 +23,10 @@ + + + + diff --git a/src/shell.c b/src/shell.c index 40e84b6..ba421b5 100644 --- a/src/shell.c +++ b/src/shell.c @@ -57,6 +57,9 @@ struct desktop_shell { struct weston_layer background_layer; struct weston_layer lock_layer; + struct wl_listener pointer_focus_listener; + struct weston_surface *busy_surface; + struct { struct weston_process process; struct wl_client *client; @@ -151,13 +154,6 @@ struct shell_surface { struct ping_timer *ping_timer; - struct { - struct weston_animation current; - int exists; - int fading_in; - uint32_t timestamp; - } unresponsive_animation; - struct weston_output *fullscreen_output; struct weston_output *output; struct wl_list link; @@ -357,65 +353,68 @@ static const struct wl_pointer_grab_interface move_grab_interface = { }; static void -unresponsive_surface_fade(struct shell_surface *shsurf, bool reverse) +busy_cursor_grab_focus(struct wl_pointer_grab *base, + struct wl_surface *surface, int32_t x, int32_t y) { - shsurf->unresponsive_animation.fading_in = reverse ? 0 : 1; + struct shell_grab *grab = (struct shell_grab *) base; + struct wl_pointer *pointer = base->pointer; - if(!shsurf->unresponsive_animation.exists) { - wl_list_insert(&shsurf->surface->compositor->animation_list, - &shsurf->unresponsive_animation.current.link); - shsurf->unresponsive_animation.exists = 1; - shsurf->unresponsive_animation.timestamp = weston_compositor_get_time(); - weston_surface_damage(shsurf->surface); + if (grab->grab.focus != surface) { + shell_grab_finish(grab); + wl_pointer_end_grab(pointer); + free(grab); } } static void -unresponsive_fade_frame(struct weston_animation *animation, - struct weston_output *output, uint32_t msecs) +busy_cursor_grab_motion(struct wl_pointer_grab *grab, + uint32_t time, int32_t x, int32_t y) { - struct shell_surface *shsurf = - container_of(animation, struct shell_surface, unresponsive_animation.current); - struct weston_surface *surface = shsurf->surface; - unsigned int step = 8; +} - if (!surface || !shsurf) +static void +busy_cursor_grab_button(struct wl_pointer_grab *grab, + uint32_t time, uint32_t button, uint32_t state) +{ +} + +static const struct wl_pointer_grab_interface busy_cursor_grab_interface = { + busy_cursor_grab_focus, + busy_cursor_grab_motion, + busy_cursor_grab_button, +}; + +static void +set_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer) +{ + struct shell_grab *grab; + struct desktop_shell *shell = shsurf->shell; + struct weston_seat *seat = (struct weston_seat *) pointer->seat; + struct weston_surface *sprite; + + grab = malloc(sizeof *grab); + if (!grab) return; - if (shsurf->unresponsive_animation.fading_in) { - while (step < msecs - shsurf->unresponsive_animation.timestamp) { - if (surface->saturation > 1) - surface->saturation -= 5; - if (surface->brightness > 200) - surface->brightness--; + shell_grab_init(grab, &busy_cursor_grab_interface, shsurf); + grab->grab.focus = &shsurf->surface->surface; + wl_pointer_start_grab(pointer, &grab->grab); + wl_pointer_set_focus(pointer, &shell->busy_surface->surface, 0, 0); - shsurf->unresponsive_animation.timestamp += step; - } + sprite = (struct weston_surface *) seat->sprite; + shell->busy_surface->output = sprite->output; +} - if (surface->saturation <= 1 && surface->brightness <= 200) { - wl_list_remove(&shsurf->unresponsive_animation.current.link); - shsurf->unresponsive_animation.exists = 0; - } - } - else { - while (step < msecs - shsurf->unresponsive_animation.timestamp) { - if (surface->saturation < 255) - surface->saturation += 5; - if (surface->brightness < 255) - surface->brightness++; - - shsurf->unresponsive_animation.timestamp += step; - } +static void +end_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer) +{ + struct shell_grab *grab = (struct shell_grab *) pointer->grab; - if (surface->saturation >= 255 && surface->brightness >= 255) { - surface->saturation = surface->brightness = 255; - wl_list_remove(&shsurf->unresponsive_animation.current.link); - shsurf->unresponsive_animation.exists = 0; - } + if (grab->grab.interface == &busy_cursor_grab_interface) { + shell_grab_finish(grab); + wl_pointer_end_grab(pointer); + free(grab); } - - surface->geometry.dirty = 1; - weston_surface_damage(surface); } static void @@ -435,10 +434,14 @@ static int ping_timeout_handler(void *data) { struct shell_surface *shsurf = data; + struct weston_seat *seat; /* Client is not responding */ shsurf->unresponsive = 1; - unresponsive_surface_fade(shsurf, false); + + wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link) + if (seat->seat.pointer->focus == &shsurf->surface->surface) + set_busy_cursor(shsurf, seat->seat.pointer); return 1; } @@ -448,7 +451,7 @@ ping_handler(struct weston_surface *surface, uint32_t serial) { struct shell_surface *shsurf = get_shell_surface(surface); struct wl_event_loop *loop; - int ping_timeout = 2500; + int ping_timeout = 200; if (!shsurf) return; @@ -471,17 +474,54 @@ ping_handler(struct weston_surface *surface, uint32_t serial) } static void +handle_pointer_focus(struct wl_listener *listener, void *data) +{ + struct wl_pointer *pointer = data; + struct weston_surface *surface = + (struct weston_surface *) pointer->focus; + struct weston_compositor *compositor; + struct shell_surface *shsurf; + uint32_t serial; + + if (!surface) + return; + + compositor = surface->compositor; + shsurf = get_shell_surface(surface); + + if (shsurf->unresponsive) { + set_busy_cursor(shsurf, pointer); + } else { + serial = wl_display_next_serial(compositor->wl_display); + ping_handler(surface, serial); + } +} + +static void shell_surface_pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { struct shell_surface *shsurf = resource->data; + struct desktop_shell *shell = shsurf->shell; + struct weston_seat *seat; + struct weston_compositor *ec = shsurf->surface->compositor; + struct wl_pointer *pointer; + int was_unresponsive; if (shsurf->ping_timer->serial == serial) { - if (shsurf->unresponsive) { + was_unresponsive = shsurf->unresponsive; + shsurf->unresponsive = 0; + if (was_unresponsive) { /* Received pong from previously unresponsive client */ - unresponsive_surface_fade(shsurf, true); + wl_list_for_each(seat, &ec->seat_list, link) { + pointer = seat->seat.pointer; + if (pointer->focus == + &shell->busy_surface->surface && + pointer->current == + &shsurf->surface->surface) + end_busy_cursor(shsurf, pointer); + } } - shsurf->unresponsive = 0; ping_timer_destroy(shsurf); } } @@ -1223,9 +1263,6 @@ destroy_shell_surface(struct shell_surface *shsurf) shsurf->surface->configure = NULL; ping_timer_destroy(shsurf); - if (shsurf->unresponsive_animation.exists) - wl_list_remove(&shsurf->unresponsive_animation.current.link); - wl_list_remove(&shsurf->link); free(shsurf); } @@ -1291,9 +1328,6 @@ create_shell_surface(void *shell, struct weston_surface *surface, shsurf->shell = (struct desktop_shell *) shell; shsurf->unresponsive = 0; - shsurf->unresponsive_animation.exists = 0; - shsurf->unresponsive_animation.fading_in = 0; - shsurf->unresponsive_animation.current.frame = unresponsive_fade_frame; shsurf->saved_position_valid = false; shsurf->saved_rotation_valid = false; shsurf->surface = surface; @@ -1522,11 +1556,22 @@ desktop_shell_unlock(struct wl_client *client, resume_desktop(shell); } +static void +desktop_shell_set_busy_surface(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *surface_resource) +{ + struct desktop_shell *shell = resource->data; + + shell->busy_surface = surface_resource->data; +} + static const struct desktop_shell_interface desktop_shell_implementation = { desktop_shell_set_background, desktop_shell_set_panel, desktop_shell_set_lock_surface, - desktop_shell_unlock + desktop_shell_unlock, + desktop_shell_set_busy_surface }; static enum shell_surface_type @@ -2735,6 +2780,10 @@ shell_init(struct weston_compositor *ec) if (launch_desktop_shell_process(shell) != 0) return -1; + shell->pointer_focus_listener.notify = handle_pointer_focus; + wl_signal_add(&ec->seat->seat.pointer->focus_signal, + &shell->pointer_focus_listener); + shell_add_bindings(ec, shell); return 0; -- 2.7.4