aboutsummaryrefslogtreecommitdiff
path: root/xbattext.ms
blob: 4061235cb8738fb57931f91ee8a5b1ed8627c37b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
.so /home/john/prj/re/re.tmac
.ds Sf MR
.de Q
\\$3\(lq\\$1\(rq\\$2
..
.DA
.TL
.BI xbattext ,
an X11 battery monitor for NetBSD
.AU
John Ankarström
.AB
.LP
.I xbattext
is a simple X11 program that displays, in text,
the current battery level.
Its source code serves as a good introduction to X11 programming.
It is short, simple and easy to follow,
as it accounts only for a single system \(en NetBSD.
It makes use of both Xt (X toolkit intrinsics) and Xm (Motif),
two of the most popular X libraries.
It demonstrates how to access resources from
.I ~/.Xdefaults ,
how to display text in various colors and fonts and
how to set timers outside of the main event loop
to perform asynchronous tasks that are not triggered by user interaction.
.PP
This document is a commented version of the
.I xbattext
source code.
It is generated with
.I re ,
a reference-based literate programming system available at
http://git.\:ankarstrom.se/re/.
The uncommented source code is hosted at
http://git.\:ankarstrom.se/x11/xbattext/.
.PP
Feel free to read the three sections of the document out of order.
As the structure of the document strictly mirrors
the structure of the source code,
it begins with the least interesting part
and ends with the most exciting part;
as mentioned above,
it is simply an annotated version of the original source code,
not a story in itself.
If you want to see a screenshot of the resulting program,
skip ahead to the last page.
.AE
.SH
.ce
.sp -1v
Definitions
.sp 1.2v
.Re xbattext.c:/^#include/
.LP
Most of the includes regard standard C features,
but there are two special ones worth mentioning:
.PP
.I Xm/Label.h
contains the definitions for Motif's label widget,
which is used to display the battery percentage.
It includes the rest of the relevant X11 headers for us.
.PP
.I machine/apmvar.h
defines the
.I apm_power_info
structure,
which is needed in order to inspect the battery status on NetBSD.
It will be retrieved via an
.I ioctl
request, so
.I sys/ioctl.h
is included as well.
.Re xbattext.c:/^\/\* interval in seconds/
.LP
The battery status is checked every five seconds by default.
.Re xbattext.c:/^\/\* low battery level/
.LP
The battery level is considered to be
.Q low
if it is below 25 percent.
.PP
The user is encouraged to modify this and the previous constant
according to his own personal preferences.
.bp
.Re xbattext.c:/^\/\* resources/
.LP
Two structures are needed to access the application's resources:
.I res ,
which will hold the values of the resources, and
.I res_opts ,
which de\%fines the manner in which the re\%sources should be assigned
to the members of the
.I res
structure.\**
.FS
.Q Resources
are the settings set by the user in
.I ~/.Xdefaults
or
.I ~/.Xresources .
For more information about resource management and the structure of the
.I XtResource
type, see
.nh
http://lesstif.sourceforge.net/doc/super-ux/g1ae03e/part1/\:chap9.html.
.hy
.FE
.PP
At the beginning of the program's execution, the
.I res
structure is filled by the function
.I XtGetApp\%licationResources
according to the definitions in
.I res_opts .
.PP
The
.I Pixel
type is an unsigned long value representing a color, like
.I black
or
.I red3 .
The
.I XmFont\%List
type
technically represents a list of fonts,
but for all intents and purposes,
it will be used here only to represent a single font selection.
.PP
As you might guess from these resource definitions,
.I xbattext
allows the user to control the color and font of the battery display
depending on the battery status.
.Re xbattext.c:/^\/\* state changes/
.LP
.I xbattext
inspects the state of the battery every five seconds.
On every iteration, it updates the percentage displayed,
but the font and color are changed only
when it detects a relevant change in the battery's state.
.PP
When such a change is de\%tected,
the
.I change
variable is set.
Its possible values represent the range of relevant changes in battery state.
The program then changes the color and font depending on the value of
.I change .
.bp
.Re xbattext.c:/^\/\* application state/
.LP
.I wargs
is an array used by
.I XtSet\%Arg ,
which stores arguments in it, and
.I XtSetValues ,
which applies new settings to a given widget
according to the arguments stored in it.
.PP
The boolean values
.I alerting
and
.I charging
that are set to true
whenever
.I xbattext
detects that the battery is low or
that the AC adapter is plugged in.
.PP
The other variables will be explained as we go along.
.Rr
.SH
.ce
Initial setup
.sp 0.6v
.Re xbattext.c:/\/\* program start/
\&
.Re xbattext.c:/XtVaAppInitialize(/
.LP
The application is initialized.
.I top\%level
is set, which will serve as the parent for all widgets.
.PP
Note that many Xt functions have two variants:
one that uses
.I Xt\%SetArg
to collect arguments,
and a variadic variant, marked by
.I Va .
.Re xbattext.c:/open("\/dev\/apm"/
.LP
The battery level is queried through
.I ioctl
requests to
.I /dev/apm .
The file descriptor is closed by the kernel when the program exits.
.Re xbattext.c:/^	\/\* load application resources/
.LP
.I XtGetApplicationResources
fills the
.I res
structure with the resources set in
.I res_opts .
.Re xbattext.c:/^	\/\* create motif label/
.LP
The battery level will be displayed in a Motif label widget.
It starts out containing an empty string.
.Re xbattext.c:/^	update(/
.LP
Before starting the main event loop, the
.I update
function is called, which creates a timer that will run
independently of the event loop.\**
.FS
For more information about timeouts, see
http://motifdeveloper.com/tips/tip16.html.
.FE
.bp
.Rr
.SH
.ce
Operation
.sp -0.1v
.Re xbattext.c:/^\/\* update battery status and (re-)add timer/
.LP
The
.I update
both sets up the timer and is called at the end of each timeout.
Along the way, it checks the battery status
and updates the text displayed in the label widget.
.PP
The first argument to
.I update
is a pointer to an arbitrary value set by the user
when the timeout is registered.
The second argument contains a pointer to the timeout identifier.
Neither argument is used here.
.Re xbattext.c:/^	\/\* get battery info/
.LP
As mentioned above,
the battery status is retrieved through an
.I ioctl
request,
.CW APM_IOC_GETPOWER .
It returns an
.I apm_power_info
structure (which must be zeroed first).
.Re xbattext.c:/^	\/\* put battery status into label/
.LP
The battery percentage, contained in
.I info.battery_life ,
is written to an
.I XmString ,
a special type of string used by Motif.
It is associated with a
.Q "font list element tag" ,
containing information about the visual characteristics of the text.
We just use the default.
.Re xbattext.c:/^	XtSetArg(/
.LP
The
.I wargs
array mentioned above now starts being filled with arguments
that determine the state of the label widget.
The number of arguments set is kept track of in the
.I i
variable.
To begin with, the label string is set to the
.I XmString
value defined earlier.
.Re xbattext.c:/^	\/\* check charging status/
.LP
The
.CW SET_CHARGE
or
.CW SET_NO\:CHARGE
bit is added to the
.I change
bitmap when a change in
.I info.ac_\:state
is detected.
.PP
(The value of
.I charging
is checked and updated in order to prevent the font and color changes
from unnecessarily being applied at every timeout
regardless of whether the charging status has changed.)
.bp
.Re xbattext.c:/^	\/\* check low battery/
.LP
The same applies when the program checks whether the battery level is below
.CW ALERT .
.Re xbattext.c:/^	\/\* prioritize/
.LP
Before the bits in
.I change
are acted upon,
some prioritization is necessary.
The charging indication overrides any other indication.
The low battery indication is activated
if the AC adapter is plugged out,
but the battery is still low.
Likewise, the charging indication is activated
if the battery rises above the
.CW ALERT
threshold,
but the AC adapter is still plugged in.
.PP
(Remember that
the
.I change
bitmap reflects a
.B change
in state.
It does not reflect the current
.B state .)
.Re xbattext.c:/^	\/\* act on state changes/
.LP
After collecting and prioritizing the state changes,
the foreground color and font of the label widget are set accordingly.
.PP
Note that if a
.I Pixel
resource is not defined,
.I XtGetApplicationResources
gives it the integer value zero,
which also signifies the color black.
Thus, the program cannot tell the difference
between a missing value and a value of
.I black .
.PP
Font lists, however, are set to null if undefined.
If the
.I alert
or
.I charge
font list is undefined,
.I xbattext
uses the main font list instead.
.Re xbattext.c:/^	case SET_CHARGE:/
\&
.Re xbattext.c:/^set:/
.LP
Finally, the values collected in
.I wargs
are associated with the label widget through the
.I XtSetValues
function.
The
.I XmString
is freed,
as a new one will be created on the next call to
.I update ,
which at the end is registered through the
.I Xt\%AppAddTimeOut
function to occur in
.CW INTERVAL
seconds.
.Rr
.sp \(PN
.LP
That is the totality of the
.I xbattext
source
(almost; a long comment at the beginning of the file, explaining
what the program does and how it should be compiled, was excluded).
Hopefully, it shows that graphical UNIX programming is nothing to be afraid of.
While Xlib, Xt and Xm tend nowadays not to be considered
.Q "best practice" ,
they have a low barrier to entry,
require little resources of the computer and
are often installed by default on UNIX systems.
It is better to use worse practices to create
.I something
than it is to use best practices and create nothing at all;
if those are the alternatives,
then perhaps best practices aren't.
.PP
If, after reading all this, you are still wondering
why anyone would want a small window on their screen
displaying the current battery level,
then you should get acquainted with the X11 window manager
.I jwm \**
.FS
.I jwm
is available at https://joewing.net/projects/jwm/.
The author's personal fork of
.I jwm
1.8,
which has a more traditional visual appearance,
is available at http://git.ankarstrom.se/jwm/.
.FE
and its
.Q swallowing
feature,
which displays an arbitrary X11 program in the tray.
It's like tray icons, but in a UNIX sort of way.
.sp 0.6v
.PSPIC tray.eps
.sp 0.2v
.ad c
.ps -1p
.B "Figure 1."
.I xbattext
beside
.I xclock .