Battery monitor shows percentage on icon

This commit is contained in:
Sasha Koshka 2023-11-10 17:36:45 -05:00
parent 3ba59aa2ab
commit dda82b48a3

View File

@ -1,17 +1,20 @@
/* C99 */
#define _XOPEN_SOURCE
#include <Xm/Xm.h>
#include <Xm/MainW.h>
#include <Xm/Scale.h>
#include <Xm/LabelG.h>
#include <Xm/PushB.h>
#include <Xm/MessageB.h>
#include <Xm/RowColumn.h>
#include <Xm/Separator.h>
#include <Xmd/Icon.h>
#include <Xmd/Exec.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "icons/level0.xbm"
#include "icons/level1.xbm"
@ -39,34 +42,39 @@ typedef struct {
} BatteryInfo;
BatteryInfo getBatteryInfo (void);
Pixmap selectBatteryIcon (BatteryInfo);
void loadAllPixmaps (Widget);
Pixmap selectBatteryIcon (BatteryInfo, Pixmap[8]);
void loadAllPixmaps (Widget, Pixmap[8]);
void batteryPoll (XtPointer, XtIntervalId *);
void resetBatteryPollTimeout(void);
void batteryInfoDialog (Widget, XtPointer, XtPointer);
Pixmap levels[8] = { 0 };
Pixmap iconLevels[8] = { 0 };
XtAppContext application;
Widget icon;
Widget text;
Widget layout;
Widget window;
Widget topLevel;
int main (int argc, char *argv[]) {
window = XtVaAppInitialize (
topLevel = XtVaAppInitialize (
&application, "Battery",
NULL, 0,
&argc, argv,
NULL,
XmNtitle, "Battery",
XmNiconName, "Battery",
NULL);
Widget window = XtVaCreateManagedWidget (
"window", xmMainWindowWidgetClass, topLevel,
NULL);
layout = XtVaCreateWidget (
"layout", xmRowColumnWidgetClass, window,
XmNorientation, XmHORIZONTAL,
NULL);
loadAllPixmaps(layout);
loadAllPixmaps(topLevel, iconLevels);
loadAllPixmaps(layout, levels);
icon = XtVaCreateManagedWidget (
"batteryIcon", xmPushButtonWidgetClass, layout,
XmNleftAttachment, XmATTACH_FORM,
@ -87,7 +95,7 @@ int main (int argc, char *argv[]) {
batteryPoll(NULL, NULL);
XtManageChild(layout);
XtRealizeWidget(window);
XtRealizeWidget(topLevel);
XtAppMainLoop(application);
}
@ -96,7 +104,11 @@ BatteryInfo getBatteryInfo (void) {
char charging[16] = { 0 };
int battery;
FILE *stream = popen("acpi -b", "r");
pid_t child;
FILE *stream = XmdVaPipedExecPath (
"acpi", &child, "r",
"acpi", "-b",
NULL);
if (stream == NULL) {
result.state = BatteryStateError;
return result;
@ -113,13 +125,14 @@ BatteryInfo getBatteryInfo (void) {
case 'F': result.state = BatteryStateFull; break;
default: result.state = BatteryStateError; break;
}
if (pclose(stream) != 0) {
if (fclose(stream) != 0) {
result.state = BatteryStateError;
}
waitpid(child, NULL, 0);
return result;
}
Pixmap selectBatteryIcon (BatteryInfo info) {
Pixmap selectBatteryIcon (BatteryInfo info, Pixmap levels[8]) {
if (info.state == BatteryStateCharging) {
return levels[5];
} else if (info.state == BatteryStateNotCharging) {
@ -139,15 +152,15 @@ Pixmap selectBatteryIcon (BatteryInfo info) {
}
}
void loadAllPixmaps (Widget widget) {
levels[0] = XmdLoadBitmapIcon(widget, level0);
levels[1] = XmdLoadBitmapIcon(widget, level1);
levels[2] = XmdLoadBitmapIcon(widget, level2);
levels[3] = XmdLoadBitmapIcon(widget, level3);
levels[4] = XmdLoadBitmapIcon(widget, level4);
levels[5] = XmdLoadBitmapIcon(widget, charging);
levels[6] = XmdLoadBitmapIcon(widget, error);
levels[7] = XmdLoadBitmapIcon(widget, not);
void loadAllPixmaps (Widget widget, Pixmap destination[8]) {
destination[0] = XmdLoadBitmapIcon(widget, level0);
destination[1] = XmdLoadBitmapIcon(widget, level1);
destination[2] = XmdLoadBitmapIcon(widget, level2);
destination[3] = XmdLoadBitmapIcon(widget, level3);
destination[4] = XmdLoadBitmapIcon(widget, level4);
destination[5] = XmdLoadBitmapIcon(widget, charging);
destination[6] = XmdLoadBitmapIcon(widget, error);
destination[7] = XmdLoadBitmapIcon(widget, not);
}
void batteryPoll (XtPointer clientData, XtIntervalId *timer) {
@ -158,17 +171,15 @@ void batteryPoll (XtPointer clientData, XtIntervalId *timer) {
XtVaSetValues (
icon,
XmNlabelType, XmPIXMAP,
XmNlabelPixmap, selectBatteryIcon(info),
XmNlabelPixmap, selectBatteryIcon(info, levels),
NULL);
XtVaSetValues (
window,
XmNiconPixmap, selectBatteryIcon(info),
topLevel,
XmNiconPixmap, selectBatteryIcon(info, iconLevels),
NULL);
#define BUFFER_LEN 32
char buffer[BUFFER_LEN];
snprintf(buffer, BUFFER_LEN, "%d%%", info.level);
#undef BUFFER_LEN
char buffer[32];
snprintf(buffer, XtNumber(buffer), "%d%%", info.level);
/* if we don't unmanage and then re-manage the child, the text flies to
* the top which is rather annoying. this little quirk bent me over and
@ -182,6 +193,11 @@ void batteryPoll (XtPointer clientData, XtIntervalId *timer) {
XmStringFree(string);
XtManageChild(text);
XtVaSetValues (
topLevel,
XmNiconName, buffer,
NULL);
resetBatteryPollTimeout();
}
@ -195,35 +211,40 @@ void batteryInfoDialog (Widget button, XtPointer clientData, XtPointer callData)
BatteryInfo info = getBatteryInfo();
static const char *states[] = {
static const String states[] = {
"Charging",
"Not charging",
"Full",
"Discharging",
"Error"
};
#define BUFFER_LEN 48
char timeBuffer[BUFFER_LEN] = { 0 };
String messageBuffer = NULL;
switch (info.state) {
case BatteryStateCharging:
snprintf (
timeBuffer, BUFFER_LEN, "\n%d:%02d:%02d until charged.",
XtAsprintf (
&messageBuffer,
"%d%%, %s\n"
"%d:%02d:%02d until charged.",
info.level, states[info.state],
info.hours, info.minutes, info.seconds);
break;
case BatteryStateDischarging:
snprintf (
timeBuffer, BUFFER_LEN, "\n%d:%02d:%02d until empty.",
XtAsprintf (
&messageBuffer,
"%d%%, %s\n"
"%d:%02d:%02d until empty.",
info.level, states[info.state],
info.hours, info.minutes, info.seconds);
break;
default:
XtAsprintf (
&messageBuffer,
"%d%%, %s",
info.level, states[info.state]);
break;
}
#undef BUFFER_LEN
#define BUFFER_LEN 128
char messageBuffer[BUFFER_LEN];
snprintf (
messageBuffer, BUFFER_LEN, "%d%%, %s%s",
info.level, states[info.state], timeBuffer);
#undef BUFFER_LEN
Arg args[5] = { 0 };
int n = 0;