[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: