Re: Mac/PMU Gnome 3 Battery Applet
On 08 April 2015 at 16:10 Bill Chatfield <bill_chatfield@yahoo.com> wrote:
>
> Here is a gtk2 version that works with Mate:
> https://github.com/gungwald/mac-battery-applet-gtk2
> I guess a better solution would be to add PMU support to the existing
> Gnome/Mate battery applets. But, I still need to figure out how to check out
> the right code (deb source or upstream) and then submit patches.
>
Hi Bill,
Attached is a version ported to C. I can't test as I don't have a PowerPC
machine that has a battery. Could you compile it (instructions in the comment at
the top of the file), run it, and let me know if you encounter any problems?
Cheers,
Chris
/* Copyright © 2015 Bill Chatfield
*
* Ported to C by Chris Wareham
*
* To compile:
*
* $ gcc `pkg-config --cflags --libs gtk+-2.0` -o battery_applet battery_applet.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/param.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
const char *PROC_DIR = "/proc";
const char *BATTERY_FILE = "/proc/pmu/battery_0";
const guint UPDATE_INTERVAL_MS = 10000;
typedef struct {
gint percentage;
gint max_charge;
gint charge;
gint charging;
gboolean error;
} BatteryStatus;
static void readBatteryStatus(BatteryStatus *);
static gboolean updateBatteryIcon(gpointer);
static gboolean desktopSupported(void);
static int processRunning(const char *);
int
main(int argc, char *argv[])
{
if (desktopSupported()) {
GtkStatusIcon *icon = gtk_status_icon_new();
updateBatteryIcon(NULL);
g_timeout_add(UPDATE_INTERVAL_MS, updateBatteryIcon, icon);
gtk_main();
}
return 0;
}
static void
readBatteryStatus(BatteryStatus *status)
{
FILE *f;
char *key;
char *value;
char *buf;
size_t bufsiz = 1024;
status->percentage = 0;
status->max_charge = 0;
status->charge = 0;
status->charging = 0;
status->error = TRUE;
if ((f = fopen(BATTERY_FILE, "r"))) {
status->error = FALSE;
buf = malloc(bufsiz);
while (getline(&buf, &bufsiz, f) != -1) {
key = buf;
value = strchr(buf, ':');
if (value) {
*value = '\0';
++value;
if (strstr(key, "max_charge"))
status->max_charge = atoi(value);
else if (strstr(key, "charge") == 0)
status->charge = atoi(value);
else if (strstr(key, "flags") == 0)
status->charging = atoi(value) & 0x00000002;
}
}
free(buf);
status->percentage = status->charge / status->max_charge * 100;
}
fclose(f);
}
static gboolean
updateBatteryIcon(gpointer data)
{
GtkStatusIcon *icon;
BatteryStatus status;
char tooltip[1024];
char *iconname;
icon = (GtkStatusIcon *) data;
readBatteryStatus(&status);
if (status.error) {
gtk_status_icon_set_tooltip(icon, "Error");
gtk_status_icon_set_from_icon_name(icon, "battery-missing");
} else {
snprintf(tooltip, sizeof(tooltip), "Power at %02d%% and %s",
status.percentage, status.charging ? "charging" : "draining");
if (status.percentage >= 90)
iconname = status.charging ? "battery-full" : "battery-full-charging";
else if (status.percentage >= 20)
iconname = status.charging ? "battery-good" : "battery-good-charging";
else if (status.percentage >= 10)
iconname = status.charging ? "battery-low" : "battery-low-charging";
else if (status.percentage >= 5)
iconname = status.charging ? "battery-caution" : "battery-caution-charging";
else
iconname = "battery-empty";
gtk_status_icon_set_tooltip(icon, tooltip);
gtk_status_icon_set_from_icon_name(icon, iconname);
}
return TRUE;
}
static gboolean
desktopSupported(void)
{
char *var;
var = getenv("DESKTOP_SESSION");
if (var) {
/*
* Special cases: Canonical sets $DESKTOP_SESSION to Lubuntu
* rather than LXDE if using LXDE. There is no guarantee that
* they will not do the same with the other desktop environments.
*/
if (strcmp(var, "gnome") == 0)
return TRUE;
if (strcmp(var, "unity") == 0 || strcmp(var, "ubuntu") == 0)
return TRUE;
if (strcmp(var, "cinnamon") == 0)
return TRUE;
if (strcmp(var, "mate") == 0)
return TRUE;
if (strcmp(var, "xfce") == 0 || strcmp(var, "xfce4") == 0 || strcmp(var, "xubuntu") == 0)
return TRUE;
if (strcmp(var, "lxde") == 0 || strcmp(var, "lubuntu") == 0)
return TRUE;
}
if ((var = getenv("GNOME_DESKTOP_SESSION_ID")) && strstr(var, "deprecated"))
return TRUE;
if (processRunning("xfce-mcs-manage"))
return TRUE;
return FALSE;
}
/*
* FIXME : only check processes owned by the current user?
*/
static int
processRunning(const char *process)
{
int running;
int pid;
DIR *dir;
struct dirent* de;
char buf[MAXPATHLEN + 1];
char *taskname;
size_t tasknamesize;
running = 0;
if ((dir = opendir(PROC_DIR))) {
while (!running && (de = readdir(dir))) {
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
continue;
if (sscanf(de->d_name, "%d", &pid) != 1)
continue;
if (snprintf(buf, sizeof(buf), "%s/%d/cmdline", PROC_DIR, pid) > MAXPATHLEN)
continue;
FILE *cmdline = fopen(buf, "r");
taskname = NULL;
tasknamesize = 0;
if (getline(&taskname, &tasknamesize, cmdline) != -1) {
if (strstr(taskname, process))
running = 1;
free(taskname);
}
fclose(cmdline);
}
closedir(dir);
}
return running;
}
Reply to: