+
+/*
+ * 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, NULL);
+ x11_redraw_game(state, state->render_game_mask);
+
+ state->render_goal_mask = state->render_game_mask = 0;
+ return True;
+}
+
+static void start_render(void *data, XtIntervalId *id)
+{
+ struct app_state *state = data;
+ XtAppContext app;
+
+ if (state->render_game_mask & X11_PROC_INSTALLED)
+ return;
+
+ state->render_game_mask |= X11_PROC_INSTALLED;
+ app = XtWidgetToApplicationContext(state->game);
+ XtAppAddWorkProc(app, do_render, state);
+}
+
+void x11_queue_render(struct app_state *state, uint_fast32_t mask, int mode)
+{
+ uint_fast32_t changed = 0;
+ XtAppContext app;
+
+ mask &= GAME_MASK;
+ if (mode & RENDER_MODE_GOAL)
+ changed |= state->render_goal_mask |= mask;
+ if (mode & RENDER_MODE_GAME)
+ changed |= state->render_game_mask |= mask;
+
+ if (changed & X11_TICK_INSTALLED || !changed)
+ return;
+
+ state->render_game_mask |= X11_TICK_INSTALLED;
+ app = XtWidgetToApplicationContext(state->game);
+ XtAppAddTimeOut(app, 3, start_render, state);
+}