← Back to team overview

torios-dev team mailing list archive

upower battery monitor

 

Hi,
My development computer is running 14.10, and for some reason the
xfce4-power-manager doesn't display a tray icon in JWM :(

So... I borrowed some stuff from sdesk, and I have a scratched together
tray icon for power 'management'

Basically it displays an icon (from your current icon theme) and if you
pass in:
-s
it will suspend when you close the lid (if your computer can suspend).
if you pass in
-v
it will print out lots of information.

you will need to install all the depends:
build-essential libgtk2.0-dev libgcc1 libupower-glib1 libgio2.0-cil-dev

maybe more... but run this:

gcc `pkg-config gtk+-x11-2.0 --cflags` `pkg-config upower-glib --cflags`
`pkg-config gobject-2.0 --cflags` -finline-small-functions
-ffunction-sections -fdata-sections -fmerge-all-constants
-fomit-frame-pointer -mno-accumulate-outgoing-args -fno-unwind-tables
-fno-asynchronous-unwind-tables -Os batteri.c -o batteri -lgobject-2.0
-lglib-2.0 -lgio-2.0 -lupower-glib -lgtk-x11-2.0 -lgdk-x11-2.0


and you will have a tiny binary (around 14 Kb) that uses aroung 4MB
memory to monitor your power and suspend.  Very simple!  I eventually
want to make some sort of menu for it, or configuration...  but it
solved my problem :)

Sorry if the code is kinda wacky... I don't normally write C, and the
code needs to be cleaned up and done a bit better (i.e comments, no
global variables).

But it works on newer systems, since proc2imdgd doesn't use upower :(

And our polkit rules mean it should work on ToriOS just fine!!

-- 
Regards

-Israel
ToriOS Team

/*
gcc `pkg-config gtk+-x11-2.0 --cflags` `pkg-config upower-glib --cflags` `pkg-config gobject-2.0 --cflags` batt.c -o batteri -lgobject-2.0 -lglib-2.0 -lgio-2.0 -lupower-glib -lgtk-x11-2.0 -lgdk-x11-2.0
*/

#include <gtk/gtk.h>
#include <libupower-glib/upower.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const gchar* icon;
char tooltip_message[150];
int debug = 0;
int suspend = 0;
GtkStatusIcon *si;
const char* path_icon;
const char* battery_full;
const char* battery_good;
const char* battery_low;
const char* battery_caution;
const char* battery_empty;
//sdesk
static void run(gpointer s){
	printf("yo");
}

void key_press_event(GtkWidget *widget, GdkEventKey *event){
	g_print("KEY=%s\n",gdk_keyval_name(event->keyval));
}

void button_press_event(GtkWidget *widget, GdkEventButton *event){
	g_print("BUTTON=%d\nBUTTON_X=%d\nBUTTON_Y=%d\n",event->button,
	(unsigned int) event->x, (unsigned int)event->y);
}

static void leftclick(GtkStatusIcon *si, gpointer s){run(s);}
static void rightclick(GtkStatusIcon *si, guint b,guint a_t, gpointer s){run(s);}

/** refreshes the status icon image from file if it changes */
static void refresh(GFileMonitor *monitor, GFile *file, GFile *to_file, GFileMonitorEvent event, gpointer si){
	gtk_status_icon_set_from_file(si,g_file_get_path(file));
}


/** refreshes the background image from file if it changes */
static void bg_refresh(GFileMonitor *monitor, GFile *file, GFile *to_file, GFileMonitorEvent event, gpointer bg){
	gtk_image_set_from_file(GTK_IMAGE(bg),g_file_get_path(file));
}
/** gets a new mouse over tooltip from file if it changes */
static void updatetooltip(GFileMonitor *monitor,   GFile *file, GFile *to_file, GFileMonitorEvent event, gpointer si){
	gtk_status_icon_set_tooltip_markup(si, g_mapped_file_get_contents(g_mapped_file_new(g_file_get_path(file), FALSE, NULL)));
}

//kseds

static void report_combined_battery_status(UpClient* client){
    GPtrArray* devices = up_client_get_devices(client);
    if (!devices)
        return;

    // single battery data
    UpDevice* device;
    UpDeviceKind kind;
    UpDeviceState state;
    gboolean is_present;
    gdouble energy, energy_empty, energy_full, energy_rate;
    gdouble percentage;

    /*
     * Combined battery data.
     */
    int num_battery_devices = 0;
    // Set the initial state to unknown - there might be no battery devices.
    UpDeviceState c_state = 0;
    gdouble c_energy = 0, c_energy_full = 0, c_energy_rate = 0;

    /*
     * Final battery data.
     */
    UpDeviceState f_state;
    gdouble f_percentage = 0;
    gdouble f_charging_time = 0;
    gdouble f_discharging_time = 0;

    int i;
    for (i = 0; i < devices->len; i++) {
        device = g_ptr_array_index(devices, i);
        g_object_get(device,
                     "kind", &kind,
                     "state", &state,
                     "is-present", &is_present,
                     "energy", &energy,
                     "energy-empty", &energy_empty,
                     "energy-full", &energy_full,
                     "energy-rate", &energy_rate, NULL);

        // Only take into account present battery devices
        if (kind != UP_DEVICE_KIND_BATTERY || !is_present)
            continue;

        num_battery_devices++;

        // Only update the state if the current combined state does not indicate
        // that a battery device is discharging to keep the system running
        //if (c_state != UP_DEVICE_STATE_DISCHARGING)
        //    c_state = state;
        c_state |= (1 << state);

        c_energy += energy - energy_empty;
        c_energy_full += energy_full;
        c_energy_rate += energy_rate;
    }

    g_ptr_array_unref(devices);

    if (c_energy_full > 0)
        f_percentage = c_energy / c_energy_full;

    if (c_state & (1 << UP_DEVICE_STATE_DISCHARGING))
        f_state = UP_DEVICE_STATE_DISCHARGING;
    else if (c_state & (1 << UP_DEVICE_STATE_CHARGING))
        f_state = UP_DEVICE_STATE_CHARGING;
    else if (c_state & (1 << UP_DEVICE_STATE_FULLY_CHARGED))
        f_state = UP_DEVICE_STATE_FULLY_CHARGED;
    else
        f_state = UP_DEVICE_STATE_UNKNOWN;

    float percent = f_percentage * 100.0;
    const char* status = up_device_state_to_string(c_state);
    if (f_state == UP_DEVICE_STATE_DISCHARGING){
		status = up_device_state_to_string(c_state);
        f_discharging_time = 3600.0 * c_energy / c_energy_rate;
	//set icon based on percent
		battery_full = "battery-full";
		battery_good = "battery-good";
		battery_low = "battery-low";
		battery_caution = "battery-caution";
		battery_empty = "battery-empty";
		if(percentage > 80){icon = battery_full;} /// /usr/share/icons/Numix/scalable/status/
		else if(percent > 40){icon = battery_good;}
		else if(percent > 20){icon = battery_low;}
		else if(percent > 5){icon = battery_caution;}
		else {icon = battery_empty;}
		sprintf(tooltip_message, "State:\t %s \nPercentage: %f \nDischarging Time:\t %f \nLevel:\t %f", status, percent, f_discharging_time, f_percentage);
    }
    else if (f_state == UP_DEVICE_STATE_CHARGING){
		status = up_device_state_to_string(c_state);
        f_charging_time = 3600.0 * (c_energy_full - c_energy) / c_energy_rate;
	//set icon based on percent
		if(percent > 80){icon = "battery-full-charging";} //battery-full-charging";}//-symbolic
		else if(percent > 40){icon = "battery-good-charging";}
		else if(percent > 20){icon = "battery-low-charging";}
		else{icon = "battery-caution-charging";}
		sprintf(tooltip_message, "State:\t %s \nPercentage: %f \nCharging Time:\t %f \nLevel:\t %f", status, percent, f_charging_time, f_percentage);
    }
    int num_batteries = num_battery_devices;
    if (!num_battery_devices) {
        g_message("\tno battery status data to report, ending");
        return;
    }
    
    const char* chargin = "";
    if(UP_DEVICE_STATE_DISCHARGING){chargin="true";}
    else{chargin="false";}
    //const char* chargin = //UP_DEVICE_STATE_DISCHARGING ? "false" : "true";
    //g_message("\t%s /* charging */,", f_state == UP_DEVICE_STATE_DISCHARGING ? "false" : "true");
    float chargin_time = f_charging_time;
    float dischargin_time = f_discharging_time;
    float percent_level = f_percentage;
    //sprintf(tooltip_message, "Level:\t%f", percent_level);
    make_icon(icon);
    const gchar* gtooltip_message = tooltip_message;
    tooltip(tooltip_message);
    if(debug){
		g_message("\t%d battery device(s) present", num_battery_devices);
		g_message(" ");
		g_message("State: %s", up_device_state_to_string(c_state));
		g_message("Percentage: %f", f_percentage * 100.0);
		g_message(" ");
		g_message("\t%f /* chargingTime */,", f_charging_time);
		g_message("\t%f /* dischargingTime */,", f_discharging_time);
		g_message("\t%f /* level */", f_percentage);
		g_message("--- end of report ---");
		g_message("Icon: %s", icon);
    }
}

static void power_device_alteration(UpClient* client, UpDevice* device, gpointer data)
{
    UpDeviceKind kind;
    g_object_get(device,
                 "kind", &kind, NULL);
    if (kind != UP_DEVICE_KIND_BATTERY)
        return;

    report_combined_battery_status(client);
}

int make_icon(const gchar* name_of_icon){
  if (name_of_icon==NULL){return 2;}
	char temp_icon[70];
	sprintf(temp_icon,"%s-symbolic", name_of_icon);
    name_of_icon=temp_icon;
	GdkPixbuf      *pix = NULL;
	pix = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
                                     name_of_icon,
                                    32,
                                    GTK_ICON_LOOKUP_USE_BUILTIN,
                                    NULL);
	gtk_status_icon_set_from_pixbuf(si,pix);
                                    /*
    
    gtk_status_icon_set_from_icon_name(si, name_of_icon);
    */
    
}
int tooltip(const gchar* tooltip_message){
/** tooltip **/
	gtk_status_icon_set_tooltip_markup(si, tooltip_message);
}

int main(int argc, char* argv[]){
	char i=1;
	gtk_init (&argc, &argv);
	while(i<argc && argv[i][0]=='-'){
	  switch(argv[i][1]){
		case 'v':
			debug = 1;
			break;
		case 's':
			suspend=1;
			break;
		case 'h':
			g_printerr(
				"usage:\n%s [-d] [-s]\n"
				"  -v	turn Verbose mode on\n"
				"  -s	turn suspend on (if possible)\n"
				,argv[0]);
				return 1;
				break;
		default:
			break;
	  }
	  i++;
	}
    GError* error = NULL;
	const char* right="right";
	const char* left="left";
    UpClient* powerClient = up_client_new();
    gboolean is_lid = up_client_get_lid_is_present (powerClient);
    gboolean can_suspend=up_client_get_can_suspend (powerClient);
    if(suspend*is_lid*can_suspend){
		g_message("can suspend");
		if(up_client_get_lid_is_closed (powerClient)){
			if(up_client_suspend_sync (powerClient,NULL,&error)){
				g_message("Suspending");
				}
		}
	}
    if (!up_client_enumerate_devices_sync(powerClient, NULL, &error))
        g_error("unable to enumerate devices - %s", error->message);
    si = gtk_status_icon_new ();
    icon = "battery-good";
    make_icon(icon);
    report_combined_battery_status(powerClient);
    g_signal_connect(powerClient, "device-changed",
                     G_CALLBACK(power_device_alteration), NULL);
    g_signal_connect(powerClient, "device-added",
                     G_CALLBACK(power_device_alteration), NULL);
    g_signal_connect(powerClient, "device-removed",
                     G_CALLBACK(power_device_alteration), NULL);
	g_signal_connect(G_OBJECT(si), "activate", G_CALLBACK(leftclick),(gpointer) left);
	g_signal_connect(G_OBJECT(si), "popup-menu", G_CALLBACK(rightclick), (gpointer) right);
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);

    g_object_unref(powerClient);

    return 0;
}