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