/* * This is a simple X11 program that displays the battery percentage * on NetBSD. * * If you are curious about how it works, you can download the commented * version of the source code at the following address: * * http://img.ankarstrom.se/xbattext.pdf * * xbattext should be compiled with the following flags: * * CFLAGS = -I/usr/X11R7/include -I/usr/pkg/include * LDFLAGS = -lXm -L/usr/X11R7/lib -L/usr/pkg/lib * LDFLAGS += -Wl,-R/usr/X11R7/lib -Wl,-R/usr/pkg/lib * * It requires x11/motif to be installed. * * The follow resources are used: * * xbattext*fontList = normal font * xbattext*foreground = normal text color * xbattext*alertFontList = font when battery is low * xbattext*alertForeground = text color when battery is low * xbattext*chargeFontList = font when charging * xbattext*chargeForeground = text color when charging * * Set their values in ~/.Xdefaults to customize the battery display. * * xbattext is written by John Ankarstr\xf6m and * is released into the public domain; do whatever you want with it. */ #include #include #include #include #include #include #include /* interval in seconds */ #define INTERVAL 5 /* low battery level */ #define ALERT 25 /* resources */ struct res { XmFontList font_list; XmFontList alert_font_list; XmFontList charge_font_list; Pixel foreground; Pixel alert_foreground; Pixel charge_foreground; } res; static XtResource res_opts[] = { {"fontList", "FontList", XmRFontList, sizeof(XmFontList), XtOffset(struct res*, font_list), XtRImmediate, (caddr_t)NULL}, {"alertFontList", "AlertFontList", XmRFontList, sizeof(XmFontList), XtOffset(struct res*, alert_font_list), XtRImmediate, (caddr_t)NULL}, {"chargeFontList", "ChargeFontList", XmRFontList, sizeof(XmFontList), XtOffset(struct res*, charge_font_list), XtRImmediate, (caddr_t)NULL}, {"foreground", "foreground", XmRPixel, sizeof(Pixel), XtOffset(struct res*, foreground), XtRImmediate, (caddr_t)NULL}, {"alertForeground", "AlertForeground", XmRPixel, sizeof(Pixel), XtOffset(struct res*, alert_foreground), XtRImmediate, (caddr_t)NULL}, {"chargeForeground", "ChargeForeground", XmRPixel, sizeof(Pixel), XtOffset(struct res*, charge_foreground), XtRImmediate, (caddr_t)NULL}, }; /* state changes */ enum { SET_NONE = 0, SET_NOALERT = 1 << 0, SET_NOCHARGE = 1 << 1, SET_ALERT = 1 << 2, SET_CHARGE = 1 << 3 } change; /* application state */ Arg wargs[10]; char *s; int alerting, apmfd, charging, i; struct apm_power_info info; Widget toplevel, label; XmString xms; XtAppContext app_context; void update(XtPointer, XtIntervalId *); /* program start */ int main(int argc, char* argv[]) { toplevel = XtVaAppInitialize( &app_context, "xbattext", NULL, 0, &argc, argv, NULL, NULL); if ((apmfd = open("/dev/apm", O_RDONLY)) == -1) err(1, "open"); if ((s = malloc(5*sizeof(char))) == NULL) err(1, "malloc"); /* load application resources */ XtGetApplicationResources(toplevel, &res, res_opts, XtNumber(res_opts), NULL, 0); /* create motif label */ label = XtVaCreateManagedWidget("label", xmLabelWidgetClass, toplevel, XmNlabel, "", NULL); alerting = 0; charging = 0; update(NULL, NULL); XtRealizeWidget(toplevel); XtAppMainLoop(app_context); } /* update battery status and (re-)add timer */ void update(XtPointer client_data, XtIntervalId *t) { /* reset temporary variables */ i = 0; change = SET_NONE; /* get battery info */ memset(&info, 0, sizeof(info)); if (ioctl(apmfd, APM_IOC_GETPOWER, &info) == -1) err(1, "ioctl"); /* put battery status into label */ sprintf(s, "%d%%", info.battery_life); xms = XmStringCreate(s, XmFONTLIST_DEFAULT_TAG); XtSetArg(wargs[i], XmNlabelString, xms); i++; /* check charging status */ if (!charging && info.ac_state == APM_AC_ON) change |= SET_CHARGE; else if (charging && info.ac_state != APM_AC_ON) change |= SET_NOCHARGE; charging = info.ac_state == APM_AC_ON; /* check low battery */ if (!alerting && info.battery_life < ALERT) change |= SET_ALERT; else if (alerting && info.battery_life >= ALERT) change |= SET_NOALERT; alerting = info.battery_life < ALERT; /* prioritize charging and low battery indications */ if (change & SET_CHARGE) change = SET_CHARGE; if (change & SET_NOCHARGE && alerting) change = SET_ALERT; if (change & SET_NOALERT && charging) change = SET_CHARGE; /* act on state changes */ switch(change & 0xf) { case SET_NOCHARGE: case SET_NOALERT: XtSetArg(wargs[i], XtNforeground, res.foreground); i++; if (res.font_list != NULL) { XtSetArg(wargs[i], XmNfontList, res.font_list); i++; } break; case SET_ALERT: XtSetArg(wargs[i], XtNforeground, res.alert_foreground); i++; if (res.alert_font_list != NULL) { XtSetArg(wargs[i], XmNfontList, res.alert_font_list); i++; } break; case SET_CHARGE: XtSetArg(wargs[i], XtNforeground, res.charge_foreground); i++; if (res.charge_font_list != NULL) { XtSetArg(wargs[i], XmNfontList, res.charge_font_list); i++; } else if (res.font_list != NULL) { XtSetArg(wargs[i], XmNfontList, res.font_list); i++; } break; } set: XtSetValues(label, wargs, i); XmStringFree(xms); /* add new timer */ end: XtAppAddTimeOut(app_context, INTERVAL * 1000, update, NULL); }