From aebcc2d9a4090d8136f750463b1cfbb73916d717 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Sat, 12 Mar 2022 18:16:39 -0500 Subject: [PATCH] Reduce redrawing on resize events. 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 | 3 +++ src/motif_ui.c | 71 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/motif.h b/src/motif.h index 6461f06..a515293 100644 --- a/src/motif.h +++ b/src/motif.h @@ -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; diff --git a/src/motif_ui.c b/src/motif_ui.c index 726e24f..4559ff6 100644 --- a/src/motif_ui.c +++ b/src/motif_ui.c @@ -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); } -- 2.43.2