diff --git a/libweston/compositor.c b/libweston/compositor.c
index 2ec7f8e05e077c462814f07f107921c5f738c678..4a1d568a9ca9f8e5d1a3df21290c5414e75ba44a 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -2592,6 +2592,7 @@ idle_repaint(void *data)
 
 	assert(output->repaint_status == REPAINT_BEGIN_FROM_IDLE);
 	output->repaint_status = REPAINT_AWAITING_COMPLETION;
+	output->idle_repaint_source = NULL;
 	output->start_repaint_loop(output);
 }
 
@@ -2716,7 +2717,9 @@ weston_output_schedule_repaint(struct weston_output *output)
 		return;
 
 	output->repaint_status = REPAINT_BEGIN_FROM_IDLE;
-	wl_event_loop_add_idle(loop, idle_repaint, output);
+	assert(!output->idle_repaint_source);
+	output->idle_repaint_source = wl_event_loop_add_idle(loop, idle_repaint,
+							     output);
 	TL_POINT("core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
 }
 
@@ -5676,6 +5679,9 @@ weston_output_release(struct weston_output *output)
 
 	output->destroying = 1;
 
+	if (output->idle_repaint_source)
+		wl_event_source_remove(output->idle_repaint_source);
+
 	if (output->enabled)
 		weston_compositor_remove_output(output);
 
diff --git a/libweston/compositor.h b/libweston/compositor.h
index 5ee7fdfd6f1f322cccc783dcc2e61c705a2aa552..869740df5f7f335415a12bc618b9aac88e336a9c 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -216,6 +216,9 @@ struct weston_output {
 	 *  next repaint should be run */
 	struct timespec next_repaint;
 
+	/** For cancelling the idle_repaint callback on output destruction. */
+	struct wl_event_source *idle_repaint_source;
+
 	struct weston_output_zoom zoom;
 	int dirty;
 	struct wl_signal frame_signal;