+
+/*
+ * Deferred redraw of tiles after resize/expose to avoid redundant drawing.
+ *
+ * Record any tiles that need to be redrawn due to resizes or expose events,
+ * then, after a short delay, perform all the accumulated redraws at once.
+ *
+ * This is implemented using both a work proc and a timeout, because it seems
+ * that rendering directly inside the timeout callback gives poor results:
+ * possibly redrawing outdated intermediate positions during "fast" resizes
+ * long after the resizing has stopped. This does not happen when drawing
+ * from a work proc.
+ */
+static Boolean do_render(void *data)
+{
+ struct app_state *state = data;
+
+ x11_redraw_goal(state, state->render_goal_mask);
+ x11_redraw_game(state, state->render_game_mask);
+
+ state->render_goal_mask = state->render_game_mask = 0;
+ state->render_proc = 0;
+ state->render_tick = 0;
+ return True;
+}
+
+static void start_render(void *data, XtIntervalId *id)
+{
+ struct app_state *state = data;
+ XtAppContext app;
+
+ if (state->render_proc)
+ return;
+
+ app = XtWidgetToApplicationContext(state->game);
+ state->render_proc = XtAppAddWorkProc(app, do_render, state);
+}
+
+void x11_queue_render(struct app_state *state, uint_fast32_t game_mask,
+ uint_fast16_t goal_mask)
+{
+ uint_fast32_t changed = 0;
+ XtAppContext app;
+
+ changed |= state->render_game_mask |= game_mask;
+ changed |= state->render_goal_mask |= goal_mask;
+
+ if (state->render_tick || !changed)
+ return;
+
+ app = XtWidgetToApplicationContext(state->game);
+ state->render_tick = XtAppAddTimeOut(app, 3, start_render, state);
+}