shell: Use a busy cursor animation for unresponsive surfaces
This commit is contained in:
parent
7cee19778a
commit
d56bd908bf
@ -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),
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -23,6 +23,10 @@
|
||||
|
||||
<request name="unlock"/>
|
||||
|
||||
<request name="set_busy_surface">
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
|
||||
<!-- We'll fold most of wl_shell into this interface and then
|
||||
they'll share the configure event. -->
|
||||
<event name="configure">
|
||||
|
181
src/shell.c
181
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;
|
||||
}
|
||||
static void
|
||||
end_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
|
||||
{
|
||||
struct shell_grab *grab = (struct shell_grab *) pointer->grab;
|
||||
|
||||
if (grab->grab.interface == &busy_cursor_grab_interface) {
|
||||
shell_grab_finish(grab);
|
||||
wl_pointer_end_grab(pointer);
|
||||
free(grab);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -470,18 +473,55 @@ 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) {
|
||||
/* Received pong from previously unresponsive client */
|
||||
unresponsive_surface_fade(shsurf, true);
|
||||
}
|
||||
was_unresponsive = shsurf->unresponsive;
|
||||
shsurf->unresponsive = 0;
|
||||
if (was_unresponsive) {
|
||||
/* Received pong from previously unresponsive client */
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user