2 * Helpers for implementing a rapid-update counter display in Motif.
3 * Copyright © 2022-2023 Nick Bowler
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 * A set of functions to implement a simple decimal counter display supporting
24 * rapid updates. This is intended to avoid two specific practical problems
25 * with the Motif text widgets:
27 * (1) Updating the text involves expensive(?) XmString operations, and
28 * (2) Updating the text causes the label to be cleared and redrawn.
30 * Point #2 in particular results in very annoying flicker.
32 * These functions are intended for dealing with strings that consist of
33 * "static" text interspersed with digits. For example, a string such as:
35 * "The time is 12:30:57."
37 * On a call to xcounter_init, a string like this is provided as the template.
38 * The "static" elements are all the maximal nondigit substrings, which in this
39 * instance are "The time is ", ":" (twice) and ".". These static elements
40 * are pre-rendered to an X pixmap along with all possible decimal digits.
42 * A subsequent call to xcounter_update will change the displayed string by
43 * combining the pre-rendered images in various ways. This takes a strings in
44 * the same format the original template to modify the digit sequences.
46 * This solves the practical problems by significantly simplifying the actual
47 * X drawing process (just a single operation to update any particular pixel).
48 * This avoids the flicker inherent to a clear+redraw, and a simple change
49 * tracking scheme is employed to avoid redundant drawing for a smoother
52 * To simplify the implementation, some arbitrary limits are baked in:
54 * - maximum number of static elements in a template: 10
55 * - maximum number of digits plus static elements in an update: 23
57 * Which should be more than enough to handle the RRace displays.
61 * Create xcounter based on template.
63 * The provided template must be writeable as it is internally modified by
64 * this function. However, it is restored to its original value upon return.
66 struct xcounter *xcounter_init(Widget w, char *template);
69 * Update xcounter segments according to str.
71 * Generally, the string should be in the same format as the original
72 * template, with only the digits changing between calls. However, there
73 * are two allowed exceptions:
75 * - It does not matter what exact text is placed in the static portions
76 * between digits, provided they are nonempty. These are used only to
77 * separate groups of digits. The pre-rendered text from the original
78 * template is always used.
80 * - The updated string need not include all the elements of the original
81 * template. Omitted elements from the update string are not drawn.
83 void xcounter_update(struct xcounter *xc, const char *str);
86 * Redraw the counter in response to an expose event.
88 void xcounter_expose(struct xcounter *xc, XExposeEvent *e);
91 * Resize and expose callbacks that can be registered on an XmDrawingArea.
93 void xcounter_resize_cb(Widget w, void *data, void *cb_data);
94 void xcounter_expose_cb(Widget w, void *data, void *cb_data);
97 * Call after the widget is resized to update the internal dimensions,
98 * and clear the margins.
100 * Since the pre-rendered text never changes, this is all that is needed:
101 * existing portions of the window do not need to be redrawn (except when
102 * shrinking the margins over previously-drawn text), and newly-revealed
103 * areas will get expose events to trigger redraw.
105 static inline void xcounter_resize(struct xcounter *xc)
107 xcounter_resize_cb(0, xc, 0);
110 static inline struct xcounter *xcounter_simple_init(Widget w, char *template)
112 struct xcounter *xc = xcounter_init(w, template);
114 XtAddCallback(w, XmNresizeCallback, xcounter_resize_cb, xc);
115 XtAddCallback(w, XmNexposeCallback, xcounter_expose_cb, xc);