diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 4fec1955..4a8fb0bf 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -21,9 +21,10 @@ static void surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time) { struct wlr_wl_backend_output *output = data; assert(output); - wlr_output_send_frame(&output->wlr_output); wl_callback_destroy(cb); output->frame_callback = NULL; + + wlr_output_send_frame(&output->wlr_output); } static struct wl_callback_listener frame_listener = { @@ -50,6 +51,11 @@ static bool wlr_wl_output_swap_buffers(struct wlr_output *wlr_output) { struct wlr_wl_backend_output *output = (struct wlr_wl_backend_output *)wlr_output; + if (output->frame_callback != NULL) { + wlr_log(L_ERROR, "Skipping buffer swap"); + return false; + } + output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 5b6ba3e7..3eb1c6ff 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -77,6 +77,8 @@ struct wlr_output { struct wl_signal destroy; } events; + struct wl_event_source *idle_frame; + struct wlr_surface *fullscreen_surface; struct wl_listener fullscreen_surface_commit; struct wl_listener fullscreen_surface_destroy; diff --git a/types/wlr_output.c b/types/wlr_output.c index 8c9de541..54f4baf8 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -273,6 +273,8 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, output->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &output->display_destroy); + + output->frame_pending = true; } void wlr_output_destroy(struct wlr_output *output) { @@ -466,6 +468,15 @@ surface_damage_finish: bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, pixman_region32_t *damage) { + if (output->frame_pending) { + wlr_log(L_ERROR, "Tried to swap buffers when a frame is pending"); + return false; + } + if (output->idle_frame != NULL) { + wl_event_source_remove(output->idle_frame); + output->idle_frame = NULL; + } + wl_signal_emit(&output->events.swap_buffers, damage); int width, height; @@ -522,18 +533,21 @@ void wlr_output_send_frame(struct wlr_output *output) { static void schedule_frame_handle_idle_timer(void *data) { struct wlr_output *output = data; - wlr_output_send_frame(output); + output->idle_frame = NULL; + if (!output->frame_pending) { + wlr_output_send_frame(output); + } } void wlr_output_schedule_frame(struct wlr_output *output) { - if (output->frame_pending) { + if (output->frame_pending || output->idle_frame != NULL) { return; } // TODO: ask the backend to send a frame event when appropriate instead struct wl_event_loop *ev = wl_display_get_event_loop(output->display); - wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output); - output->frame_pending = true; + output->idle_frame = + wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output); } void wlr_output_set_gamma(struct wlr_output *output,