/* $Id: battery.c 2394 2007-01-17 17:40:47Z nick $ * * Copyright (c) 2003 Nicholas Penwarden * Copyright (c) 2003 Benedikt Meurer * Copyright (c) 2003 Edscott Wilson Garcia * Copyright (c) 2005 Eduard Roccatello * Copyright (c) 2006 Nick Schermer * * 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 2 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, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #ifdef __FreeBSD__ #include #elif __OpenBSD__ #include #include #elif __NetBSD__ #include #include #include #define APMDEVICE "/dev/apm" #elif __linux__ #include #endif #include #include #include #include #include #include #include #include #include #include #include "libacpi.h" #include #include #define BORDER 8 #define HIGH_COLOR "#00ff00" #define LOW_COLOR "#ffff00" #define CRITICAL_COLOR "#ff0000" #define AVERAGING_CYCLE 5 #define PLUGIN_WEBSITE "http://goodies.xfce.org/projects/panel-plugins/xfce4-battery-plugin" typedef struct { gboolean display_label; /* Options */ gboolean display_icon; /* Options */ gboolean display_power; /* Options */ gboolean display_percentage; /* Options */ gboolean display_time; gboolean hide_when_full; gboolean tooltip_display_percentage; gboolean tooltip_display_time; int low_percentage; int critical_percentage; int action_on_low; int action_on_critical; char *command_on_low; char *command_on_critical; float hsize; float vsize; } t_battmon_options; typedef struct { XfcePanelPlugin *plugin; GtkTooltips *tips; GtkWidget *vbox; /* Widgets */ GtkWidget *ebox; GtkWidget *battstatus; int timeoutid; /* To update apm status */ int method; gboolean flag; gboolean low; gboolean critical; t_battmon_options options; GdkColor colorH; GdkColor colorL; GdkColor colorC; GtkLabel *label; GtkLabel *charge; GtkLabel *rtime; GtkLabel *alt_rtime; GtkLabel *acfan; GtkLabel *temp; GtkWidget *image; } t_battmon; typedef struct { GtkWidget *cb_disp_power; GtkWidget *cb_disp_label; GtkWidget *cb_disp_percentage; GtkWidget *cb_disp_time; GtkWidget *cb_hide_when_full; GtkWidget *cb_disp_tooltip_percentage; GtkWidget *cb_disp_tooltip_time; GtkWidget *cb_disp_icon; GtkWidget *sb_low_percentage; GtkWidget *sb_critical_percentage; GtkWidget *om_action_low; GtkWidget *om_action_critical; GtkWidget *en_command_low; GtkWidget *en_command_critical; t_battmon *battmon; } t_battmon_dialog; enum {BM_DO_NOTHING, BM_MESSAGE, BM_COMMAND, BM_COMMAND_TERM}; enum {BM_BROKEN, BM_USE_ACPI, BM_USE_APM}; static void init_options(t_battmon_options *options) { options->display_icon = FALSE; options->display_label = FALSE; options->display_power = FALSE; options->display_percentage = TRUE; options->display_time = FALSE; options->tooltip_display_percentage = FALSE; options->tooltip_display_time = FALSE; options->low_percentage = 10; options->critical_percentage = 5; options->action_on_low = 1; options->action_on_critical = 1; options->command_on_low = NULL; options->command_on_critical = NULL; options->hsize = 1.75; options->vsize = 0.5; } gboolean detect_battery_info(t_battmon *battmon) { #ifdef __FreeBSD__ /* This is how I read the information from the APM subsystem under FreeBSD. Each time this functions is called (once every second) the APM device is opened, read from and then closed. except that is does not work on FreeBSD */ struct apm_info apm; int fd; /* First check to see if ACPI is available */ if (check_acpi() == 0) { int i; /* ACPI detected */ battmon->method = BM_USE_ACPI; /* consider battery 0 first... */ for (i=0;imethod = BM_BROKEN; #ifdef APMDEVICE fd = open(APMDEVICE, O_RDONLY); if (fd == -1) return FALSE; if (ioctl(fd, APMIO_GETINFO, &apm) == -1) { close(fd); return FALSE; } close(fd); battmon->method = BM_USE_APM; #endif return TRUE; #elif defined(__OpenBSD__) || defined(__NetBSD__) /* Code for OpenBSD by Joe Ammond . Using the same procedure as for FreeBSD. Made to work on NetBSD by Stefan Sperling */ struct apm_power_info apm; int fd; battmon->method = BM_BROKEN; fd = open(APMDEVICE, O_RDONLY); if (fd == -1) return FALSE; + if (ioctl(fd, APM_IOC_GETPOWER, &apm) == -1) { close(fd); return FALSE; } close(fd); battmon->method = BM_USE_APM; return TRUE; #elif __linux__ struct apm_info apm; /* First check to see if ACPI is available */ if(check_acpi()==0) { /* ACPI detected */ int i; battmon->method = BM_USE_ACPI; for (i=0;ipercentage; apm.battery_time=acpistate->rtime; } return TRUE; } if(apm_read(&apm) == 0) { /* ACPI not detected, but APM works */ battmon->method = BM_USE_APM; return TRUE; } /* Neither ACPI or APM detected/working */ battmon->method = BM_BROKEN; return FALSE; #endif } static gboolean battmon_time_labels_fits(t_battmon *battmon) { int plugin_size, labels_size; GtkRequisition widget_size; gtk_widget_size_request( GTK_WIDGET(battmon->plugin), &widget_size ); plugin_size = widget_size.height; labels_size = 0; gtk_widget_size_request( GTK_WIDGET(battmon->charge), &widget_size ); labels_size += widget_size.height; gtk_widget_size_request( GTK_WIDGET(battmon->rtime), &widget_size ); labels_size += widget_size.height; return labels_size <= plugin_size; } static gboolean update_apm_status(t_battmon *battmon) { int charge=0, rate; int lcapacity, ccapacity; gboolean fan=FALSE; const char *temp; int time_remaining=0; gboolean acline; gchar buffer[128]; static int update_time = AVERAGING_CYCLE; static int sum_lcapacity = 0; static int sum_ccapacity = 0; static int sum_rate = 0; static int last_ccapacity = 0; static int last_lcapacity = 0; static int last_rate = 0; static int last_acline = 0; #if defined(__OpenBSD__) || defined(__NetBSD__) /* Code for OpenBSD by Joe Ammond . Using the same procedure as for FreeBSD. Made to work on NetBSD by Stefan Sperling */ struct apm_power_info apm; int fd; battmon->method = BM_BROKEN; fd = open(APMDEVICE, O_RDONLY); if (fd == -1) return TRUE; if (ioctl(fd, APM_IOC_GETPOWER, &apminfo) == -1) return TRUE; close(fd); charge = apm.battery_life; time_remaining = apm.minutes_left; acline = apm.ac_state ? TRUE : FALSE; #else struct apm_info apm; DBG ("Updating battery status..."); if(battmon->method == BM_BROKEN) { /* See if ACPI or APM support has been enabled yet */ if(!detect_battery_info(battmon)) return TRUE; if(battmon->timeoutid != 0) g_source_remove(battmon->timeoutid); /* Poll only once per minute if using ACPI due to a bug */ #ifdef TUTTLE_UPDATES /* what bug? I don't see any bug here. */ if(battmon->method == BM_USE_ACPI) { battmon->timeoutid = g_timeout_add(60 * 1024, (GSourceFunc) update_apm_status, battmon); } else #endif battmon->timeoutid = g_timeout_add(2 * 1024, (GSourceFunc) update_apm_status, battmon); } /* Show initial state if using ACPI rather than waiting a minute */ if(battmon->flag) { g_source_remove(battmon->timeoutid); battmon->timeoutid = g_timeout_add(2 * 1024, (GSourceFunc) update_apm_status, battmon); } if(battmon->method == BM_USE_ACPI) { int i; acline = read_acad_state(); lcapacity = rate = ccapacity = 0; for (i=0;ilast_full_capacity; ccapacity += acpistate->rcapacity; rate += acpistate->prate; } if ( battmon->flag ) { last_ccapacity = ccapacity; last_lcapacity = lcapacity; last_rate = rate; } sum_lcapacity += lcapacity; sum_ccapacity += ccapacity; sum_rate += rate; update_time++; if ( update_time >= AVERAGING_CYCLE || last_acline != acline ) { if ( last_acline != acline ) { last_ccapacity = ccapacity; last_lcapacity = lcapacity; last_rate = rate; } else { last_ccapacity = ccapacity = (float)(sum_ccapacity)/(float)(update_time); last_lcapacity = lcapacity = (float)(sum_lcapacity)/(float)(update_time); last_rate = rate = (float)(sum_rate)/(float)(update_time); } update_time = 0; sum_ccapacity = sum_lcapacity = sum_rate = 0; } else { ccapacity = last_ccapacity; lcapacity = last_lcapacity; rate = last_rate; } #ifdef __linux__ charge = (((float)ccapacity)/((float)lcapacity))*100; if ( last_acline ) time_remaining = ((float)(lcapacity-ccapacity)/(float)(rate))*60; else time_remaining = ((float)(ccapacity)/(float)(rate))*60; if ( time_remaining < 0 ) time_remaining = 0; last_acline = acline; #elif __FreeBSD__ charge = acpistate->percentage; if ( last_acline ) time_remaining = acpistate->rtime; else time_remaining = acpistate->rtime; if ( time_remaining < 0 ) time_remaining = 0; last_acline = acline; #endif } #ifdef __linux__ else { DBG ("Trying apm_read()..."); apm_read(&apm); /* not broken and not using ACPI, assume APM */ charge = apm.battery_percentage; time_remaining = apm.battery_time; acline = apm.ac_line_status ? TRUE : FALSE; } #elif __FreeBSD__ else { /* This is how I read the information from the APM subsystem under FreeBSD. Each time this functions is called (once every second) the APM device is opened, read from and then closed. except it don't work with 5.x: battmon.c: In function `update_apm_status': battmon.c:241: `APMDEVICE' undeclared (first use in this function) battmon.c:241: (Each undeclared identifier is reported only once battmon.c:241: for each function it appears in.) *** Error code 1 */ #ifdef APMDEVICE int fd; battmon->method = BM_BROKEN; fd = open(APMDEVICE, O_RDONLY); if (fd == -1) return TRUE; if (ioctl(fd, APMIO_GETINFO, &apm) == -1) { close(fd); return TRUE; } close(fd); acline = apm.ai_acline ? TRUE : FALSE; time_remaining = apm.ai_batt_time; time_remaining = time_remaining / 60; /* convert from seconds to minutes */ charge = apm.ai_batt_life; #else /* FIXME: apm stuff needs fix for 5.x kernels */ acline=0; time_remaining=0; charge=0; #endif } #endif #endif battmon->flag = FALSE; charge = CLAMP (charge, 0, 100); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(battmon->battstatus), charge / 100.0); if(battmon->options.display_label){ gtk_widget_show((GtkWidget *)battmon->label); } else { gtk_widget_hide((GtkWidget *)battmon->label); } if(battmon->options.display_icon){ gtk_widget_show(battmon->image); } else { gtk_widget_hide(battmon->image); } if(battmon->options.display_percentage && !(battmon->options.hide_when_full && acline && charge >= 99)){ gtk_widget_show((GtkWidget *)battmon->charge); g_snprintf(buffer, sizeof(buffer),"%d%% ", charge); gtk_label_set_text(battmon->charge,buffer); } else { gtk_widget_hide((GtkWidget *)battmon->charge); } if (battmon->options.display_time && !(battmon->options.hide_when_full && acline && charge >= 99 )){ GtkLabel *active_label; if ( battmon_time_labels_fits( battmon ) ) { active_label = battmon->rtime; gtk_widget_hide( (GtkWidget*)battmon->alt_rtime ); } else { active_label = battmon->alt_rtime; gtk_widget_hide( (GtkWidget*)battmon->rtime ); } gtk_widget_show((GtkWidget *)active_label); g_snprintf(buffer, sizeof(buffer),"%02d:%02d ",time_remaining/60,time_remaining%60); gtk_label_set_text(active_label,buffer); } else { gtk_widget_hide((GtkWidget *)battmon->rtime); gtk_widget_hide((GtkWidget *)battmon->alt_rtime); } if(acline) { char *t=(charge<99.9)?_("(Charging from AC)"):_("(AC on-line)"); if(battmon->options.tooltip_display_percentage) { g_snprintf(buffer, sizeof(buffer), "%d%% %s", charge,t); } else g_snprintf(buffer, sizeof(buffer), "%s",t); } else { if(battmon->options.tooltip_display_percentage && battmon->options.tooltip_display_time) g_snprintf(buffer, sizeof(buffer), _("%d%% (%02d:%02d) remaining"), charge, time_remaining / 60, time_remaining % 60); else if(battmon->options.tooltip_display_time) g_snprintf(buffer, sizeof(buffer), _("%02d:%02d remaining"),time_remaining / 60, time_remaining % 60); else if(battmon->options.tooltip_display_percentage) g_snprintf(buffer, sizeof(buffer), _("%d%% remaining"), charge); else g_snprintf(buffer, sizeof(buffer), _("AC off-line")); } gtk_tooltips_set_tip (battmon->tips, battmon->ebox, buffer, NULL); if(battmon->options.display_power){ gtk_widget_show((GtkWidget *)battmon->acfan); gtk_widget_show((GtkWidget *)battmon->temp); fan=get_fan_status(); if(acline && fan) gtk_label_set_text(battmon->acfan,"AC FAN"); else if(acline && !fan) gtk_label_set_text(battmon->acfan,"AC"); else if(!acline && fan) gtk_label_set_text(battmon->acfan,"FAN"); else { gtk_label_set_text(battmon->acfan,""); gtk_widget_hide((GtkWidget *)battmon->acfan); } temp=get_temperature(); DBG ("Temp: %s", temp); if(temp) gtk_label_set_text(battmon->temp,temp); else { gtk_label_set_text(battmon->temp,""); gtk_widget_hide((GtkWidget *)battmon->temp); } } else { gtk_widget_hide((GtkWidget *)battmon->acfan); gtk_widget_hide((GtkWidget *)battmon->temp); } gtk_progress_bar_set_text(GTK_PROGRESS_BAR(battmon->battstatus), NULL); /* bar colors and state flags */ if (acline) { battmon->low = battmon->critical = FALSE; gtk_widget_modify_bg(battmon->battstatus, GTK_STATE_PRELIGHT, NULL); } else { if(charge <= battmon->options.critical_percentage) { gtk_widget_modify_bg(battmon->battstatus, GTK_STATE_PRELIGHT, &(battmon->colorC)); } else if(charge <= battmon->options.low_percentage) { gtk_widget_modify_bg(battmon->battstatus, GTK_STATE_PRELIGHT, &(battmon->colorL)); battmon->critical = FALSE; } else { battmon->low = battmon->critical = FALSE; gtk_widget_modify_bg(battmon->battstatus, GTK_STATE_PRELIGHT, &(battmon->colorH)); } } /* alarms */ /* FIXME: should put in a timeout to terminate the alarm boxes after one * minute because if they are left open, they block the event loop for * the panel, and that means the critical action will not be performed! */ if (!acline && charge <= battmon->options.low_percentage){ if(!battmon->critical && charge <= battmon->options.critical_percentage) { battmon->critical = TRUE; if(battmon->options.action_on_critical == BM_MESSAGE){ do_critical_warn: xfce_warn(_("WARNING: Your battery has reached critical status. You should plug in or shutdown your computer now to avoid possible data loss.")); return TRUE; } if(battmon->options.action_on_critical == BM_COMMAND || battmon->options.action_on_critical == BM_COMMAND_TERM){ int interm=(battmon->options.action_on_critical == BM_COMMAND_TERM)?1:0; if (!battmon->options.command_on_critical || !strlen(battmon->options.command_on_critical)) goto do_critical_warn; xfce_exec (battmon->options.command_on_critical, interm, 0, NULL); } } else if (!battmon->low){ battmon->low = TRUE; if(battmon->options.action_on_low == BM_MESSAGE){ do_low_warn: xfce_warn(_("WARNING: Your battery is running low. You should consider plugging in or shutting down your computer soon to avoid possible data loss.")); return TRUE; } if(battmon->options.action_on_low == BM_COMMAND || battmon->options.action_on_low == BM_COMMAND_TERM){ int interm=(battmon->options.action_on_low == BM_COMMAND_TERM)?1:0; if (!battmon->options.command_on_low || !strlen(battmon->options.command_on_low)) goto do_low_warn; xfce_exec(battmon->options.command_on_low, interm, 0, NULL); } } } return TRUE; } static GdkPixbuf * battmon_icon (t_battmon *battmon) { GdkPixbuf *icon; GtkOrientation orientation; gint width, height, size; /* panel info */ orientation = xfce_panel_plugin_get_orientation (battmon->plugin); size = xfce_panel_plugin_get_size (battmon->plugin) - 6; /* icon size is 41x64px */ if (orientation == GTK_ORIENTATION_HORIZONTAL) { height = size; width = height * 0.625; } else /* vertical */ { width = size; height = width * 1.6; } /* try to load battery icon from your current icon theme */ icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "battery", size , 0, NULL); return icon; } static void setup_battmon(t_battmon *battmon, GtkOrientation orientation) { GtkWidget *box,*vbox; GdkPixbuf *icon; battmon->battstatus = gtk_progress_bar_new(); if (orientation == GTK_ORIENTATION_HORIZONTAL) { gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(battmon->battstatus), GTK_PROGRESS_BOTTOM_TO_TOP); box=gtk_hbox_new(FALSE, 0); battmon->vbox = gtk_hbox_new(FALSE, 0); } else { gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(battmon->battstatus), GTK_PROGRESS_LEFT_TO_RIGHT); box=gtk_vbox_new(FALSE, 0); battmon->vbox = gtk_vbox_new(FALSE, 0); } gtk_container_set_border_width(GTK_CONTAINER(battmon->vbox), BORDER / 2); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(battmon->battstatus), 0.0); icon = battmon_icon (battmon); if (icon) { battmon->image = gtk_image_new_from_pixbuf (icon); g_object_unref (G_OBJECT (icon)); } else { battmon->image = gtk_image_new_from_icon_name ("battery", GTK_ICON_SIZE_BUTTON); } gtk_box_pack_start(GTK_BOX(box),GTK_WIDGET(battmon->image), FALSE, FALSE, 2); /* init hide the widget */ gtk_widget_hide(battmon->image); battmon->label = (GtkLabel *)gtk_label_new(_("Battery")); gtk_box_pack_start(GTK_BOX(box),GTK_WIDGET(battmon->label),FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(battmon->battstatus), FALSE, FALSE, 2); vbox = gtk_vbox_new(FALSE, 0); /* percent + rtime */ gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(vbox), FALSE, FALSE, 0); battmon->charge = (GtkLabel *)gtk_label_new("50%%"); gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(battmon->charge),TRUE, TRUE, 0); battmon->rtime = (GtkLabel *)gtk_label_new("01:00"); gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(battmon->rtime),TRUE, TRUE, 0); vbox=gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(vbox), FALSE, FALSE, 0); battmon->alt_rtime = (GtkLabel *)gtk_label_new("01:00"); gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(battmon->alt_rtime),TRUE, TRUE, 0); vbox=gtk_vbox_new(FALSE, 0); /* ac-fan-temp */ gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(vbox), FALSE, FALSE, 0); battmon->acfan = (GtkLabel *)gtk_label_new("AC FAN"); gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(battmon->acfan),TRUE, TRUE, 0); battmon->temp = (GtkLabel *)gtk_label_new("40°C"); gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(battmon->temp),TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(battmon->vbox), box, FALSE, FALSE, 0); gtk_widget_show_all(battmon->vbox); if(!battmon->options.display_label) gtk_widget_hide((GtkWidget *)battmon->label); if(!battmon->options.display_power){ gtk_widget_hide((GtkWidget *)battmon->acfan); gtk_widget_hide((GtkWidget *)battmon->temp); } if(!battmon->options.display_percentage){ gtk_widget_hide((GtkWidget *)battmon->charge); } if (!battmon->options.display_time){ gtk_widget_hide((GtkWidget *)battmon->rtime); gtk_widget_hide((GtkWidget *)battmon->alt_rtime); } else { if ( battmon_time_labels_fits(battmon) ) { gtk_widget_hide((GtkWidget*)battmon->alt_rtime); } else { gtk_widget_hide((GtkWidget*)battmon->rtime); } } gtk_container_add(GTK_CONTAINER(battmon->ebox),GTK_WIDGET(battmon->vbox)); gtk_widget_show(battmon->ebox); gdk_color_parse(HIGH_COLOR, &(battmon->colorH)); gdk_color_parse(LOW_COLOR, &(battmon->colorL)); gdk_color_parse(CRITICAL_COLOR, &(battmon->colorC)); gtk_widget_set_size_request(battmon->ebox, -1, -1); } static gboolean battmon_set_orientation (XfcePanelPlugin *plugin, GtkOrientation orientation, t_battmon *battmon) { if (battmon->timeoutid) g_source_remove(battmon->timeoutid); gtk_container_remove(GTK_CONTAINER(battmon->ebox), GTK_WIDGET(battmon->vbox)); setup_battmon(battmon,orientation); update_apm_status( battmon ); battmon->timeoutid = g_timeout_add(1 * 1024, (GSourceFunc) update_apm_status, battmon); return TRUE; } static t_battmon* battmon_create(XfcePanelPlugin *plugin) { t_battmon *battmon; battmon = g_new(t_battmon, 1); init_options(&(battmon->options)); battmon->plugin = plugin; battmon->low = FALSE; battmon->critical = FALSE; battmon->ebox = gtk_event_box_new(); setup_battmon(battmon, xfce_panel_plugin_get_orientation (plugin)); battmon->timeoutid = 0; battmon->flag = FALSE; battmon->tips = gtk_tooltips_new (); g_object_ref (G_OBJECT (battmon->tips)); gtk_object_sink (GTK_OBJECT (battmon->tips)); return battmon; } static void battmon_free(XfcePanelPlugin *plugin, t_battmon *battmon) { if(battmon->timeoutid != 0) { g_source_remove(battmon->timeoutid); battmon->timeoutid = 0; } /* cleanup options */ g_free (battmon->options.command_on_low); g_free (battmon->options.command_on_critical); /* free tooltip */ gtk_tooltips_set_tip (battmon->tips, battmon->ebox, NULL, NULL); g_object_unref (G_OBJECT (battmon->tips)); g_free(battmon); } static void battmon_read_config(XfcePanelPlugin *plugin, t_battmon *battmon) { const char *value; char *file; XfceRc *rc; if (!(file = xfce_panel_plugin_lookup_rc_file (plugin))) return; rc = xfce_rc_simple_open (file, TRUE); g_free (file); if (!rc) return; battmon->options.display_label = xfce_rc_read_bool_entry (rc, "display_label", FALSE); battmon->options.display_icon = xfce_rc_read_bool_entry (rc, "display_icon", FALSE); battmon->options.display_power = xfce_rc_read_bool_entry (rc, "display_power", FALSE); battmon->options.display_percentage = xfce_rc_read_bool_entry (rc, "display_percentage", FALSE); battmon->options.display_time = xfce_rc_read_bool_entry (rc, "display_time", FALSE); battmon->options.tooltip_display_percentage = xfce_rc_read_bool_entry (rc, "tooltip_display_percentage", FALSE); battmon->options.tooltip_display_time = xfce_rc_read_bool_entry (rc, "tooltip_display_time", FALSE); battmon->options.low_percentage = xfce_rc_read_int_entry (rc, "low_percentage", 10); battmon->options.critical_percentage = xfce_rc_read_int_entry (rc, "critical_percentage", 5); battmon->options.action_on_low = xfce_rc_read_int_entry (rc, "action_on_low", 0); battmon->options.action_on_critical = xfce_rc_read_int_entry (rc, "action_on_critical", 0); battmon->options.hide_when_full = xfce_rc_read_int_entry (rc, "hide_when_full", 0); if ((value = xfce_rc_read_entry (rc, "command_on_low", NULL)) && *value) battmon->options.command_on_low = g_strdup (value); if((value = xfce_rc_read_entry (rc, "command_on_critical", NULL)) && *value) battmon->options.command_on_critical = g_strdup (value); xfce_rc_close (rc); } static void battmon_write_config(XfcePanelPlugin *plugin, t_battmon *battmon) { XfceRc *rc; gchar *file; if (!(file = xfce_panel_plugin_save_location (plugin, TRUE))) return; rc = xfce_rc_simple_open (file, FALSE); g_free (file); if (!rc) return; xfce_rc_write_bool_entry (rc, "display_label", battmon->options.display_label); xfce_rc_write_bool_entry (rc, "display_icon", battmon->options.display_icon); xfce_rc_write_bool_entry (rc, "display_power", battmon->options.display_power); xfce_rc_write_bool_entry (rc, "display_percentage", battmon->options.display_percentage); xfce_rc_write_bool_entry (rc, "display_time", battmon->options.display_time); xfce_rc_write_bool_entry (rc, "tooltip_display_percentage", battmon->options.tooltip_display_percentage); xfce_rc_write_bool_entry (rc, "tooltip_display_time", battmon->options.tooltip_display_time); xfce_rc_write_int_entry (rc, "low_percentage", battmon->options.low_percentage); xfce_rc_write_int_entry (rc, "critical_percentage", battmon->options.critical_percentage); xfce_rc_write_int_entry (rc, "action_on_low", battmon->options.action_on_low); xfce_rc_write_int_entry (rc, "action_on_critical", battmon->options.action_on_critical); xfce_rc_write_int_entry (rc, "hide_when_full", battmon->options.hide_when_full ); xfce_rc_write_entry (rc, "command_on_low", battmon->options.command_on_low ? battmon->options.command_on_low : ""); xfce_rc_write_entry (rc, "command_on_critical", battmon->options.command_on_critical ? battmon->options.command_on_critical : ""); xfce_rc_close (rc); } static gboolean battmon_set_size(XfcePanelPlugin *plugin, int size, t_battmon *battmon) { GdkPixbuf *icon; if (xfce_panel_plugin_get_orientation (plugin) == GTK_ORIENTATION_HORIZONTAL) { /* force size of the panel plugin */ gtk_widget_set_size_request(GTK_WIDGET(battmon->plugin), -1, size); /* size of the progressbar */ gtk_widget_set_size_request(GTK_WIDGET(battmon->battstatus), BORDER, size); } else { /* size of the plugin */ gtk_widget_set_size_request(GTK_WIDGET(battmon->plugin), size, -1); /* size of the progressbar */ gtk_widget_set_size_request(GTK_WIDGET(battmon->battstatus), size, BORDER); } /* update the icon */ icon = battmon_icon (battmon); if (icon) { gtk_image_set_from_pixbuf (GTK_IMAGE (battmon->image), icon); g_object_unref (G_OBJECT (icon)); } return TRUE; } static void refresh_dialog(t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->sb_low_percentage), battmon->options.low_percentage); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->sb_critical_percentage), battmon->options.critical_percentage); gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->om_action_low), battmon->options.action_on_low); if(battmon->options.command_on_low) gtk_entry_set_text(GTK_ENTRY(dialog->en_command_low), battmon->options.command_on_low); else gtk_entry_set_text(GTK_ENTRY(dialog->en_command_low), ""); gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->om_action_critical), battmon->options.action_on_critical); if(battmon->options.command_on_critical) gtk_entry_set_text(GTK_ENTRY(dialog->en_command_critical), battmon->options.command_on_critical); else gtk_entry_set_text(GTK_ENTRY(dialog->en_command_critical), ""); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cb_disp_label), battmon->options.display_label); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cb_disp_icon), battmon->options.display_icon); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cb_disp_power), battmon->options.display_power); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cb_disp_percentage), battmon->options.display_percentage); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cb_disp_time), battmon->options.display_time); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cb_disp_tooltip_percentage), battmon->options.tooltip_display_percentage); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cb_disp_tooltip_time), battmon->options.tooltip_display_time); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cb_hide_when_full), battmon->options.hide_when_full); gtk_widget_set_sensitive(dialog->en_command_low, (battmon->options.action_on_low > 1) ? 1 : 0); gtk_widget_set_sensitive(dialog->en_command_critical, (battmon->options.action_on_critical > 1) ? 1 : 0); } static void set_disp_percentage(GtkToggleButton *tb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.display_percentage = gtk_toggle_button_get_active(tb); update_apm_status(dialog->battmon); } static void set_disp_time(GtkToggleButton *tb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.display_time = gtk_toggle_button_get_active(tb); update_apm_status(dialog->battmon); } static void set_hide_when_full(GtkToggleButton *tb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.hide_when_full = gtk_toggle_button_get_active(tb); update_apm_status(dialog->battmon); } static void set_tooltip_disp_percentage(GtkToggleButton *tb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.tooltip_display_percentage = gtk_toggle_button_get_active(tb); } static void set_disp_power(GtkToggleButton *tb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.display_power = gtk_toggle_button_get_active(tb); update_apm_status(dialog->battmon); } static void set_disp_label(GtkToggleButton *tb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.display_label = gtk_toggle_button_get_active(tb); update_apm_status(dialog->battmon); } static void set_disp_icon(GtkToggleButton *tb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.display_icon = gtk_toggle_button_get_active(tb); update_apm_status(dialog->battmon); } static void set_tooltip_time(GtkToggleButton *tb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.tooltip_display_time = gtk_toggle_button_get_active(tb); } static void set_low_percentage(GtkSpinButton *sb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.low_percentage = gtk_spin_button_get_value_as_int(sb); update_apm_status(dialog->battmon); } static void set_critical_percentage(GtkSpinButton *sb, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.critical_percentage = gtk_spin_button_get_value_as_int(sb); update_apm_status(dialog->battmon); } static void set_action_low(GtkOptionMenu *om, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.action_on_low = gtk_option_menu_get_history(om); gtk_widget_set_sensitive(dialog->en_command_low, (gtk_option_menu_get_history(om) > 1) ? 1 : 0); update_apm_status(dialog->battmon); } static void set_action_critical(GtkOptionMenu *om, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; battmon->options.action_on_critical = gtk_option_menu_get_history(om); gtk_widget_set_sensitive(dialog->en_command_critical, (gtk_option_menu_get_history(om) > 1) ? 1 : 0); update_apm_status(dialog->battmon); } static gboolean set_command_low(GtkEntry *en, GdkEventFocus *event, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; const char *temp; g_free(battmon->options.command_on_low); temp = gtk_entry_get_text(en); battmon->options.command_on_low = g_strdup(temp); update_apm_status(dialog->battmon); /* Prevents a GTK crash */ return FALSE; } static gboolean set_command_critical(GtkEntry *en, GdkEventFocus *event, t_battmon_dialog *dialog) { t_battmon *battmon = dialog->battmon; const char *temp; g_free(battmon->options.command_on_critical); temp = gtk_entry_get_text(en); battmon->options.command_on_critical = g_strdup(temp); update_apm_status(dialog->battmon); /* Prevents a GTK crash */ return FALSE; } static char * select_file_name (const char *title, const char *path, GtkWidget * parent) { const char *t; GtkWidget *fs; char *name = NULL; t = (title) ? title : _("Select file"); fs = gtk_file_chooser_dialog_new (t, GTK_WINDOW(parent), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); if (path && *path && g_file_test (path, G_FILE_TEST_EXISTS)) { if (!g_path_is_absolute (path)) { char *current, *full; current = g_get_current_dir (); full = g_build_filename (current, path, NULL); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fs), full); g_free (current); g_free (full); } else { gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fs), path); } } if (gtk_dialog_run (GTK_DIALOG (fs)) == GTK_RESPONSE_ACCEPT) { name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)); } gtk_widget_destroy (fs); return name; } static void command_browse_cb (GtkWidget *b, GtkEntry *entry) { char *file = select_file_name(_("Select command"), gtk_entry_get_text(entry), gtk_widget_get_toplevel (b)); if (file) { gtk_entry_set_text (entry, file); g_free (file); } } static void battmon_dialog_response (GtkWidget *dlg, int response, t_battmon *battmon) { gboolean result; if (response == GTK_RESPONSE_HELP) { /* show help */ result = g_spawn_command_line_async ("exo-open --launch WebBrowser " PLUGIN_WEBSITE, NULL); if (G_UNLIKELY (result == FALSE)) g_warning (_("Unable to open the following url: %s"), PLUGIN_WEBSITE); } else { gtk_widget_destroy (dlg); xfce_panel_plugin_unblock_menu (battmon->plugin); battmon_write_config (battmon->plugin, battmon); } } static void battmon_create_options(XfcePanelPlugin *plugin, t_battmon *battmon) { GtkWidget *dlg; GtkWidget *vbox, *vbox2, *hbox, *label, *menu, *mi, *button, *button2; GtkSizeGroup *sg; t_battmon_dialog *dialog; dialog = g_new0(t_battmon_dialog, 1); dialog->battmon = battmon; xfce_panel_plugin_block_menu (plugin); dlg = xfce_titled_dialog_new_with_buttons (_("Battery Monitor"), GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (plugin))), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL); gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER); gtk_window_set_icon_name (GTK_WINDOW (dlg), "xfce4-settings"); g_signal_connect (dlg, "response", G_CALLBACK (battmon_dialog_response), battmon); gtk_container_set_border_width (GTK_CONTAINER (dlg), 2); vbox = gtk_vbox_new(FALSE, BORDER); gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER - 2); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox, TRUE, TRUE, 0); /* Create size group to keep widgets aligned */ sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); /* Low and Critical percentage settings */ hbox = gtk_hbox_new(FALSE, BORDER); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Low percentage:")); gtk_size_group_add_widget(sg, label); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); dialog->sb_low_percentage = gtk_spin_button_new_with_range(1, 100, 1); gtk_box_pack_start(GTK_BOX(hbox), dialog->sb_low_percentage, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, BORDER); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Critical percentage:")); gtk_size_group_add_widget(sg, label); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); dialog->sb_critical_percentage = gtk_spin_button_new_with_range(1, 100, 1); gtk_box_pack_start(GTK_BOX(hbox), dialog->sb_critical_percentage, FALSE, FALSE, 0); /* Low battery action settings */ hbox = gtk_hbox_new(FALSE, BORDER); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Low battery action:")); gtk_size_group_add_widget(sg, label); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); menu = gtk_menu_new(); mi = gtk_menu_item_new_with_label(_("Do nothing")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label(_("Display a warning message")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label(_("Run command")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label(_("Run command in terminal")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); dialog->om_action_low = gtk_option_menu_new(); gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->om_action_low), menu); gtk_box_pack_start(GTK_BOX(hbox), dialog->om_action_low, FALSE, FALSE, 0); /* Low battery command */ hbox = gtk_hbox_new(FALSE, BORDER); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); label = gtk_label_new(_("Command:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_size_group_add_widget(sg, label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); dialog->en_command_low = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), dialog->en_command_low, FALSE, FALSE, 0); button = gtk_button_new_with_label("..."); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); /* Critical battery action settings */ hbox = gtk_hbox_new(FALSE, BORDER); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Critical battery action:")); gtk_size_group_add_widget(sg, label); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); menu = gtk_menu_new(); mi = gtk_menu_item_new_with_label(_("Do nothing")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label(_("Display a warning message")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label(_("Run command")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label(_("Run command in terminal")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); dialog->om_action_critical = gtk_option_menu_new(); gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->om_action_critical), menu); gtk_box_pack_start(GTK_BOX(hbox), dialog->om_action_critical, FALSE, FALSE, 0); /* Critical battery command */ hbox = gtk_hbox_new(FALSE, BORDER); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); label = gtk_label_new(_("Command:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_size_group_add_widget(sg, label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); dialog->en_command_critical = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), dialog->en_command_critical, FALSE, FALSE, 0); button2 = gtk_button_new_with_label("..."); gtk_box_pack_start(GTK_BOX(hbox), button2, FALSE, FALSE, 0); /* Create checkbox options */ hbox = gtk_hbox_new(FALSE, BORDER); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(NULL); gtk_size_group_add_widget(sg, label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); vbox2 = gtk_vbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0); dialog->cb_disp_label = gtk_check_button_new_with_mnemonic(_("Display label")); gtk_box_pack_start(GTK_BOX(vbox2), dialog->cb_disp_label, FALSE, FALSE, 0); dialog->cb_disp_percentage = gtk_check_button_new_with_mnemonic(_("Display percentage")); gtk_box_pack_start(GTK_BOX(vbox2), dialog->cb_disp_percentage, FALSE, FALSE, 0); dialog->cb_disp_time = gtk_check_button_new_with_mnemonic(_("Display time")); gtk_box_pack_start(GTK_BOX(vbox2), dialog->cb_disp_time, FALSE, FALSE, 0); dialog->cb_hide_when_full = gtk_check_button_new_with_mnemonic(_("Hide time/percentage when full")); gtk_box_pack_start(GTK_BOX(vbox2), dialog->cb_hide_when_full, FALSE, FALSE, 0); dialog->cb_disp_tooltip_percentage = gtk_check_button_new_with_mnemonic(_("Display percentage in tooltip")); gtk_box_pack_start(GTK_BOX(vbox2), dialog->cb_disp_tooltip_percentage, FALSE, FALSE, 0); dialog->cb_disp_tooltip_time = gtk_check_button_new_with_mnemonic(_("Display time remaining in tooltip")); gtk_box_pack_start(GTK_BOX(vbox2), dialog->cb_disp_tooltip_time, FALSE, FALSE, 0); dialog->cb_disp_power = gtk_check_button_new_with_mnemonic(_("Display power")); gtk_box_pack_start(GTK_BOX(vbox2), dialog->cb_disp_power, FALSE, FALSE, 0); dialog->cb_disp_icon = gtk_check_button_new_with_mnemonic(_("Display icon")); gtk_box_pack_start(GTK_BOX(vbox2), dialog->cb_disp_icon, FALSE, FALSE, 0); /* Signal connections should be set after setting tate of toggle buttons...*/ refresh_dialog(dialog); g_signal_connect(button, "clicked", G_CALLBACK(command_browse_cb), dialog->en_command_low); g_signal_connect(button2, "clicked", G_CALLBACK(command_browse_cb), dialog->en_command_critical); g_signal_connect(dialog->cb_disp_percentage, "toggled", G_CALLBACK(set_disp_percentage), dialog); g_signal_connect(dialog->cb_disp_time, "toggled", G_CALLBACK(set_disp_time), dialog); g_signal_connect(dialog->cb_hide_when_full, "toggled", G_CALLBACK(set_hide_when_full), dialog); g_signal_connect(dialog->cb_disp_tooltip_percentage, "toggled", G_CALLBACK(set_tooltip_disp_percentage), dialog); g_signal_connect(dialog->cb_disp_power, "toggled", G_CALLBACK(set_disp_power), dialog); g_signal_connect(dialog->cb_disp_tooltip_time, "toggled", G_CALLBACK(set_tooltip_time), dialog); g_signal_connect(dialog->cb_disp_label, "toggled", G_CALLBACK(set_disp_label), dialog); g_signal_connect(dialog->cb_disp_icon, "toggled", G_CALLBACK(set_disp_icon), dialog); g_signal_connect(dialog->sb_low_percentage, "value-changed", G_CALLBACK(set_low_percentage), dialog); g_signal_connect(dialog->sb_critical_percentage, "value-changed", G_CALLBACK(set_critical_percentage), dialog); g_signal_connect(dialog->om_action_low, "changed", G_CALLBACK(set_action_low), dialog); g_signal_connect(dialog->om_action_critical, "changed", G_CALLBACK(set_action_critical), dialog); g_signal_connect(dialog->en_command_low, "focus-out-event", G_CALLBACK(set_command_low), dialog); g_signal_connect(dialog->en_command_critical, "focus-out-event", G_CALLBACK(set_command_critical), dialog); gtk_widget_show_all (dlg); } /* create the plugin */ static void battmon_construct (XfcePanelPlugin *plugin) { t_battmon *battmon; xfce_textdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8"); battmon = battmon_create (plugin); battmon_read_config (plugin, battmon); g_signal_connect (plugin, "free-data", G_CALLBACK (battmon_free), battmon); g_signal_connect (plugin, "save", G_CALLBACK (battmon_write_config), battmon); xfce_panel_plugin_menu_show_configure (plugin); g_signal_connect (plugin, "configure-plugin", G_CALLBACK (battmon_create_options), battmon); g_signal_connect (plugin, "size-changed", G_CALLBACK (battmon_set_size), battmon); g_signal_connect (plugin, "orientation-changed", G_CALLBACK (battmon_set_orientation), battmon); gtk_container_add(GTK_CONTAINER(plugin), battmon->ebox); xfce_panel_plugin_add_action_widget (plugin, battmon->ebox); xfce_panel_plugin_add_action_widget (plugin, battmon->battstatus); /* Determine what facility to use and initialize reading */ battmon->method = BM_BROKEN; update_apm_status(battmon); /* If neither ACPI nor APM are enabled, check for either every 60 seconds */ if(battmon->timeoutid == 0) battmon->timeoutid = g_timeout_add(60 * 1024, (GSourceFunc) update_apm_status, battmon); /* Required for the percentage and tooltip to be initially displayed due to the long timeout for ACPI */ if(battmon->method == BM_USE_ACPI) { battmon->flag = TRUE; g_source_remove(battmon->timeoutid); battmon->timeoutid = g_timeout_add(1000, (GSourceFunc) update_apm_status, battmon); } } /* register the plugin */ XFCE_PANEL_PLUGIN_REGISTER_EXTERNAL (battmon_construct);