.so /home/john/prj/re/re.tmac .ds Sf MR .de Q \\$3\(lq\\$1\(rq\\$2 .. .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 the WWW address http://git.\:ankarstrom.se/re/. .PP If you want to see a screenshot of .I xbattext , skip ahead to the last page. .AE .SH .ce .sp -1v Definitions .sp 1v .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 30 percent. .PP The user is encouraged to modify this and the previous constant according to his own preferences. .bp .Re xbattext.c:/^void update(/ \& .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 strcture.\** .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 1v .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 .Rr .SH .ce Operation .sp 1v .Re xbattext.c:/^\/\* update battery status and (re-)add timer/ .LP The .I update function, which is also called at the end of each timeout, is responsible for checking the battery status and updating the label. .PP The first argument is a pointer to a value set by the user when the timeout is registered. The second argument contains a pointer to the timeout ID. Neither argument is used in this program. .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 starts to be 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 widget's label string is set to the .I XmString value defined earlier. .Re xbattext.c:/^ \/\* check charging status/ .LP The bits .CW SET_CHARGE and .CW SET_\:NOCHARGE are added to the .I charge bitmap when a change in .I info.ac_\:state is detected. .PP Note that the value of .I charging is used in order to prevent these font and color changes from unnecessarily being applied every timeout regardless of whether the charging status has changed. .Re xbattext.c:/^ \/\* check low battery/ .LP The same applies when the program checks whether the battery level is below .CW ALERT , which is set to 30 by default. .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. .Re xbattext.c:/^ \/\* act on state changes/ .LP After collecting and prioritizing the state changes, the foreground color and font of the label widget is set accordingly. .PP Note that if a .I Pixel (color) resource is not defined, .I XtGetApplicationResources gives it the integer value zero, which also signifies the color black (thus, the program cannot differentiate between a missing value and a value of .I black ). Font lists, however, are set to null if undefined. If a font list resource is undefined, .I xbattext uses the default 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 scared 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 from the computer and are often installed by default on UNIX systems. It is better to use worse practices to create .I something than to use best practices and create nothing at all; if those are the alternatives, then perhaps best practices aren't. .PP If, after reading the source code, you are still wondering why anyone would want a small window 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/. My 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 removes the border from a given X11 program and displays it in the tray. You can look at it as tray icons according to the UNIX philosophy. In my tray, .I xbattext sits right beside .I xclock and .I xload . .sp 0.6v .PSPIC tray.eps .sp 0.2v .ad c .ps -1p .B "Figure 1." .I xload , .I xbattext and .I xclock .