]> git.draconx.ca Git - rrace.git/commitdiff
Reduce redrawing on resize events.
authorNick Bowler <nbowler@draconx.ca>
Sat, 12 Mar 2022 23:16:39 +0000 (18:16 -0500)
committerNick Bowler <nbowler@draconx.ca>
Mon, 14 Mar 2022 04:17:12 +0000 (00:17 -0400)
It is a waste of time redrawing parts of the window on resize that
will be redrawn due to expose events immediately afterwards.  This
is particularly noticeable when the program is first started and
everything is drawn twice.

src/motif.h
src/motif_ui.c

index 6461f06e12779525f9a79e6110894aba10024b0d..a5152939886fada6bd629e49d0515baf9a1fddec 100644 (file)
@@ -29,6 +29,9 @@ struct app_state {
 
        Widget game, goal;
 
+       /* Current window width/height for resize handling. */
+       Dimension game_sz[2], goal_sz[2];
+
        /* If true, the goal will be displayed over the main play area. */
        int view_goal_on_game;
 
index 726e24fd06033691f60d7f2af4fedd0045d0a4e2..4559ff664e6e6461f50dff86a5f90b22113b5274 100644 (file)
@@ -205,18 +205,6 @@ construct_menu(const struct ui_menuitem *root, Widget parent, unsigned i)
        }
 }
 
-static void game_resize(Widget w, void *data, void *cb_data)
-{
-       if (XtIsRealized(w))
-               x11_redraw_game(data, -1);
-}
-
-static void goal_resize(Widget w, void *data, void *cb_data)
-{
-       if (XtIsRealized(w))
-               x11_redraw_goal(data, -1);
-}
-
 /* Figure out which tiles intersect a rectangle. */
 static uint_fast32_t
 expose_mask(int rect_x, int rect_y, int rect_w, int rect_h,
@@ -228,6 +216,57 @@ expose_mask(int rect_x, int rect_y, int rect_w, int rect_h,
             & board_left((rect_x + rect_w - 1) / tile_w);
 }
 
+/*
+ * Calculate which tiles need to be redrawn after resizing.  This is the
+ * tiles which (at the new size) are fully contained in the previous area.
+ *
+ * When shrinking, this is all tiles, but when enlarging, the generated
+ * expose events will trigger drawing of the new area.
+ */
+static uint_fast32_t resize_helper(Widget w, Dimension *oldsz, int gridsz)
+{
+       Dimension new_w, new_h, common_w, common_h;
+
+       if (!XtIsRealized(w))
+               return 0;
+
+       XtVaGetValues(w, XmNwidth, &new_w, XmNheight, &new_h, (char *)NULL);
+       common_w = MIN(new_w, oldsz[0]);
+       common_h = MIN(new_h, oldsz[1]);
+       oldsz[0] = new_w;
+       oldsz[1] = new_h;
+       new_w /= gridsz;
+       new_h /= gridsz;
+
+       /* Round down to multiple of tile dimensions */
+       common_w = common_w / new_w * new_w;
+       common_h = common_h / new_h * new_h;
+
+       if (new_w > 0 && new_h > 0)
+               return expose_mask(0, 0, common_w, common_h, new_w, new_h);
+       return 0;
+}
+
+static void game_resize(Widget w, void *data, void *cb_data)
+{
+       struct app_state *state = data;
+       uint_fast32_t mask;
+
+       mask = resize_helper(w, state->game_sz, 5);
+       if (mask)
+               x11_redraw_game(data, mask);
+}
+
+static void goal_resize(Widget w, void *data, void *cb_data)
+{
+       struct app_state *state = data;
+       uint_fast32_t mask;
+
+       mask = resize_helper(w, state->goal_sz, 3);
+       if (mask)
+               x11_redraw_goal(data, mask);
+}
+
 static void game_expose(Widget w, void *data, void *cb_data)
 {
        XmDrawingAreaCallbackStruct *cbs = cb_data;
@@ -271,8 +310,16 @@ void ui_initialize(struct app_state *state, Widget shell)
        XtVaSetValues(menubar, XmNmenuHelpWidget, help, (char *)NULL);
 
        configure_mainwin(state, XtNameToWidget(shell, "*game"));
+
+       XtVaGetValues(state->game, XmNwidth, &state->game_sz[0],
+                                  XmNheight, &state->game_sz[1],
+                                  (char *)NULL);
        XtAddCallback(state->game, XmNresizeCallback, game_resize, state);
        XtAddCallback(state->game, XmNexposeCallback, game_expose, state);
+
+       XtVaGetValues(state->game, XmNwidth, &state->goal_sz[0],
+                                  XmNheight, &state->goal_sz[1],
+                                  (char *)NULL);
        XtAddCallback(state->goal, XmNresizeCallback, goal_resize, state);
        XtAddCallback(state->goal, XmNexposeCallback, goal_expose, state);
 }