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

[E-devel] e_gadcon_client - some refactoring ideas



I was looking thru the new gadcon API as used by modules and I noticed that somethings could be abstracted away even more. I've attached a modified e_mod_main.c (from the battery module), gcc.c and gcc.h.

In gcc.* I have some functions which I pulled out of the battery module. The new e_mod_main.c using the gcc_* functions reduces some code repitition.

Another thing there is that I could not make the battery callbacks benefit from this code reduction (at least not in a way immedietly obvious to me), b/cos the module subsystem passes a void * around which is what we materialize as the struct Instance.

The thing though is that the Instance contains a pointer to an E_Gadcon_Client, which incidentally also has a void *data which is actualy the Instance. I think it may be more beneficial (from the perpective of less confusing code) to make the module subsystem pass round the E_Gadcon_Client blob instead of the instance blob. That way, all functions just take an E_Gadcon_Client as their first parameter, and you can always grab the instance blob via the ->data member of the gadcon client, but you don't have to do the reverse twisted process of cast void *data to Instance and then grab Instance->gcc just to get to the Gadcon Client.

Also, doing this will allow more refactorings to be possible.

If this make some sort of sense, I'm willing to put my code where my mouth is and do some of the heavy lifting required.

Cheers,
Essien
/*
 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
 */
#include "e.h"
#include "e_mod_main.h"
#include "gcc.h"

#ifdef __FreeBSD__
# include <sys/types.h>
# include <sys/sysctl.h>
# include <fcntl.h>
# ifdef __i386__
#  include <machine/apm_bios.h>
# endif
# include <stdio.h>
#endif
#ifdef HAVE_CFBASE_H
#include <CFBase.h>
#include <CFNumber.h>
#include <CFArray.h>
#include <CFDictionary.h>
#include <CFRunLoop.h>
#include <ps/IOPSKeys.h>
#include <ps/IOPowerSources.h>
#endif

/***************************************************************************/
/**/
/* gadcon requirements */
static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style);
static void _gc_shutdown(E_Gadcon_Client *gcc);
static void _gc_orient(E_Gadcon_Client *gcc);
static char *_gc_label(void);
static Evas_Object *_gc_icon(Evas *evas);
/* and actually define the gadcon class that this module provides (just 1) */
static const E_Gadcon_Client_Class _gadcon_class =
{
   GADCON_CLIENT_CLASS_VERSION,
     "battery",
     {
        _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon
     }
};
/**/
/***************************************************************************/

/***************************************************************************/
/**/
/* actual module specifics */


*static void _button_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _menu_cb_post(void *data, E_Menu *m);
static Status *_battery_linux_acpi_check(void);
static Status *_battery_linux_apm_check(void);
static Status *_battery_linux_powerbook_check(void);
#ifdef __FreeBSD__
static Status *_battery_bsd_acpi_check(void);
static Status *_battery_bsd_apm_check(void);
#endif
#ifdef HAVE_CFBASE_H
static Status *_battery_darwin_check(void);
#endif
static void _battery_face_level_set(Instance *inst, double level);
static int _battery_int_get(char *buf);
static char *_battery_string_get(char *buf);
static int _battery_cb_check(void *data);
static void _battery_face_cb_menu_configure(void *data, E_Menu *m, E_Menu_Item *mi);

    
static E_Config_DD *conf_edd = NULL;

Config *battery_config = NULL;

static E_Gadcon_Client *
_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
{
   E_Gadcon_Client *gcc = gcc_create(gc, name, id, style);
   gcc_edje_set(gcc, "base/theme/modules/battery", "modules/battery/main");
   gcc_event_callback_add(gcc, EVAS_CALLBACK_MOUSE_DOWN, _button_cb_mouse_down);

   battery_config->instances = evas_list_append(battery_config->instances, gcc_instance_get(gcc));
   battery_config->battery_check_mode = CHECK_NONE;
   battery_config->battery_prev_drain = 1;
   battery_config->battery_prev_ac = -1;
   battery_config->battery_prev_battery = -1;
   _battery_cb_check(NULL);
   return gcc;
}

static void
_gc_shutdown(E_Gadcon_Client *gcc)
{
   battery_config->instances = evas_list_remove(battery_config->instances, gcc_instance_get(gcc));
   gcc_free(gcc);

}

static void
_gc_orient(E_Gadcon_Client *gcc)
{
   e_gadcon_client_aspect_set(gcc, 16, 16);
   e_gadcon_client_min_size_set(gcc, 16, 16);
}

static char *
_gc_label(void)
{
   return _("Battery");
}

static Evas_Object *
_gc_icon(Evas *evas)
{
   Evas_Object *o;
   char buf[4096];
   
   o = edje_object_add(evas);
   snprintf(buf, sizeof(buf), "%s/module.eap",
	    e_module_dir_get(battery_config->module));
   edje_object_file_set(o, buf, "icon");
   return o;
}
/**/
/***************************************************************************/

/***************************************************************************/
/**/
static void
_button_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Instance *inst;
   Evas_Event_Mouse_Down *ev;
   
   inst = data;
   ev = event_info;
   if ((ev->button == 3) && (!battery_config->menu))
     {
	E_Menu *mn;
	E_Menu_Item *mi;
	int cx, cy, cw, ch;
	
	mn = e_menu_new();
	e_menu_post_deactivate_callback_set(mn, _menu_cb_post, inst);
	battery_config->menu = mn;

	mi = e_menu_item_new(mn);
	e_menu_item_label_set(mi, _("Configuration"));
	e_util_menu_item_edje_icon_set(mi, "enlightenment/configuration");   
	e_menu_item_callback_set(mi, _battery_face_cb_menu_configure, NULL);
	
	e_gadcon_client_util_menu_items_append(inst->gcc, mn, 0);
	
	e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon,
					  &cx, &cy, &cw, &ch);
	e_menu_activate_mouse(mn,
			      e_util_zone_current_get(e_manager_current_get()),
			      cx + ev->output.x, cy + ev->output.y, 1, 1,
			      E_MENU_POP_DIRECTION_DOWN, ev->timestamp);
	evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button,
				 EVAS_BUTTON_NONE, ev->timestamp, NULL);
     }
}

static void
_menu_cb_post(void *data, E_Menu *m)
{
   if (!battery_config->menu) return;
   e_object_del(E_OBJECT(battery_config->menu));
   battery_config->menu = NULL;
}

static int
_battery_cb_check(void *data)
{
   Instance *inst;
   Status *ret = NULL;
   Evas_List *l;
#ifdef __FreeBSD__
   int acline;
   size_t len;
   int apm_fd = -1;
   int acline_mib[3] = {-1};
#endif

#ifdef __FreeBSD__
   if (battery_config->battery_check_mode == 0)
     {
      	len = sizeof(acline);
      	if (sysctlbyname("hw.acpi.acline", &acline, &len, NULL, 0) == 0) 
      	  {
	     len = 3;
	     if (sysctlnametomib("hw.acpi.acline", acline_mib, &len) == 0)
      	        battery_config->battery_check_mode = CHECK_ACPI; 
	  }
	else
	  {
	     apm_fd = open("/dev/apm", O_RDONLY); 
	     if (apm_fd != -1)
	       battery_config->battery_check_mode = CHECK_APM;
	  }
     }
   switch (battery_config->battery_check_mode)
     {
      case CHECK_ACPI:
	ret = _battery_bsd_acpi_check();
	break;
      case CHECK_APM:
	ret = _battery_bsd_apm_check();
	break;
      default:
	break;
     }
#elif defined(HAVE_CFBASE_H) /* OS X */
   ret = _battery_darwin_check();
#else
   if (battery_config->battery_check_mode == 0)
     {
	if (ecore_file_is_dir("/proc/acpi"))
	  battery_config->battery_check_mode = CHECK_ACPI;
	else if (ecore_file_exists("/proc/apm"))
	  battery_config->battery_check_mode = CHECK_APM;
	else if (ecore_file_is_dir("/proc/pmu"))
	  battery_config->battery_check_mode = CHECK_PMU;
     }
   switch (battery_config->battery_check_mode)
     {
      case CHECK_ACPI:
	ret = _battery_linux_acpi_check();
	break;
      case CHECK_APM:
	ret = _battery_linux_apm_check();
	break;
      case CHECK_PMU:
	ret = _battery_linux_powerbook_check();
	break;
      default:
	break;
     }
#endif
   for (l = battery_config->instances; l; l = l->next)
     {
	Instance *inst;
	
	inst = l->data;
	if (ret)
	  {
	     if (ret->has_battery)
	       {
		  if (ret->state == BATTERY_STATE_CHARGING)
		    {
		       if (battery_config->battery_prev_ac != 1)
			 edje_object_signal_emit(inst->evo, "charge", "");
		       edje_object_signal_emit(inst->evo, "pulsestop", "");
		       edje_object_part_text_set(inst->evo, "reading", ret->reading);
		       edje_object_part_text_set(inst->evo, "time", ret->time);
		       _battery_face_level_set(inst, ret->level);
		       battery_config->battery_prev_ac = 1;
		    }
		  else if (ret->state == BATTERY_STATE_DISCHARGING)
		    {
		       if (battery_config->battery_prev_ac != 0)
			 edje_object_signal_emit(inst->evo, "discharge", "");
		       if (ret->alarm)
			 {
			    if (!battery_config->alarm_triggered)
			      {
				 E_Dialog *dia;
				 
				 dia = e_dialog_new(e_container_current_get(e_manager_current_get()));
				 if (!dia) return 0;
				 e_dialog_title_set(dia, "Enlightenment Battery Module");
				 e_dialog_icon_set(dia, "enlightenment/e", 64);
				 e_dialog_text_set(dia,
						   _("Battery Running Low<br>"
						     "Your battery is running low.<br>"
						     "You may wish to switch to an AC source."));
				 e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
				 e_win_centered_set(dia->win, 1);
				 e_dialog_show(dia);
			      }
			    edje_object_signal_emit(inst->evo, "pulse", "");
			 }
		       edje_object_part_text_set(inst->evo, "reading", ret->reading);
		       edje_object_part_text_set(inst->evo, "time", ret->time);
		       _battery_face_level_set(inst, ret->level);
		       battery_config->battery_prev_ac = 0;
		       if (ret->alarm)
			 battery_config->alarm_triggered = 1;
		    }
		  else
		    {
		       /* ret->state == BATTERY_STATE_NONE */
		       if (battery_config->battery_prev_ac != 1)
			 edje_object_signal_emit(inst->evo, "charge", "");
		       if (battery_config->battery_prev_battery == 0)
			 edje_object_signal_emit(inst->evo, "charge", "");
		       edje_object_part_text_set(inst->evo, "reading", ret->reading);
		       edje_object_part_text_set(inst->evo, "time", ret->time);
		       _battery_face_level_set(inst, ret->level);
		       battery_config->battery_prev_ac = 1;
		       battery_config->battery_prev_battery = 1;
		    }
	       }
	     else
	       {
		  /* Hasn't battery */
		  if (battery_config->battery_prev_battery != 0)
		    edje_object_signal_emit(inst->evo, "unknown", "");
		  edje_object_part_text_set(inst->evo, "reading", ret->reading);
		  edje_object_part_text_set(inst->evo, "time", ret->time);
		  _battery_face_level_set(inst, ret->level);
		  battery_config->battery_prev_battery = 0;
	       }
	     free(ret->reading);
	     free(ret->time);
	     free(ret);
	  }
	else
	  {
	     /* Error reading status */
	     if (battery_config->battery_prev_battery != -2)
	       edje_object_signal_emit(inst->evo, "unknown", "");
	     edje_object_part_text_set(inst->evo, "reading", _("NO INFO"));
	     edje_object_part_text_set(inst->evo, "time", "--:--");
	     _battery_face_level_set(inst, (double)(rand() & 0xff) / 255.0);
	     battery_config->battery_prev_battery = -2;
	     battery_config->battery_check_mode = CHECK_NONE;
	  }
     }
   return 1;
}

static Status *
_battery_linux_acpi_check(void)
{
   Ecore_List *bats;
   char buf[4096], buf2[4096];
   char *name;
   int bat_max = 0;
   int bat_filled = 0;
   int bat_level = 0;
   int bat_drain = 1;
   int bat_val = 0;
   int discharging = 0;
   int charging = 0;
   int battery = 0;
   int design_cap_unknown = 0;
   int last_full_unknown = 0;
   int rate_unknown = 0;
   int level_unknown = 0;
   int hours, minutes;
   Status *stat;

   stat = E_NEW(Status, 1);
   if (!stat) return NULL;

   /* Read some information on first run. */
   bats = ecore_file_ls("/proc/acpi/battery");
   if (bats)
     {
	while ((name = ecore_list_next(bats)))
	  {
	     FILE *f;
	     char *tmp;

	     snprintf(buf, sizeof(buf), "/proc/acpi/battery/%s/info", name);
	     f = fopen(buf, "r");
	     if (f)
	       {
		  int design_cap = 0;
		  int last_full = 0;

		  /* present */
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  /* design capacity */
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  tmp = _battery_string_get(buf2);
		  if (tmp)
		    {
		       if (!strcmp(tmp, "unknown")) design_cap_unknown = 1;
		       else design_cap = atoi(tmp);
		       free(tmp);
		    }
		  /* last full capacity */
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  tmp = _battery_string_get(buf2);
		  if (tmp)
		    {
		       if (!strcmp(tmp, "unknown")) last_full_unknown = 1;
		       else last_full = atoi(tmp);
		       free(tmp);
		    }
		  fclose(f);
		  bat_max += design_cap;
		  bat_filled += last_full;
	       }
	     snprintf(buf, sizeof(buf), "/proc/acpi/battery/%s/state", name);
	     f = fopen(buf, "r");
	     if (f)
	       {
		  char *present;
		  char *capacity_state;
		  char *charging_state;
		  char *tmp;
		  int rate = 1;
		  int level = 0;

		  /* present */
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  present = _battery_string_get(buf2);
		  /* capacity state */
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  capacity_state = _battery_string_get(buf2);
		  /* charging state */
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  charging_state = _battery_string_get(buf2);
		  /* present rate */
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  tmp = _battery_string_get(buf2);
		  if (tmp)
		    {
		       if (!strcmp(tmp, "unknown")) rate_unknown = 1;
		       else rate = atoi(tmp);
		       free(tmp);
		    }
		  /* remaining capacity */
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  tmp = _battery_string_get(buf2);
		  if (tmp)
		    {
		       if (!strcmp(tmp, "unknown")) level_unknown = 1;
		       else level = atoi(tmp);
		       free(tmp);
		    }
		  fclose(f);
		  if (present)
		    {
		       if (!strcmp(present, "yes")) battery++;
		       free(present);
		    }
		  if (charging_state)
		    {
		       if (!strcmp(charging_state, "discharging"))
			 {
			    discharging++;
			    if ((rate == 0) && (rate_unknown == 0)) rate_unknown = 1;
			 }
		       else if (!strcmp(charging_state, "charging"))
			 {
			    charging++;
			    if ((rate == 0) && (rate_unknown == 0)) rate_unknown = 1;
			 }
		       else if (!strcmp(charging_state, "charged"))
			 rate_unknown = 0;
		       free(charging_state);
		    }
		  E_FREE(capacity_state);

		  bat_drain += rate;
		  bat_level += level;
	       }
	  }
	ecore_list_destroy(bats);
     }

   if (battery_config->battery_prev_drain < 1) battery_config->battery_prev_drain = 1;
   if (bat_drain < 1) bat_drain = battery_config->battery_prev_drain;
   battery_config->battery_prev_drain = bat_drain;

   if (bat_filled > 0) bat_val = (100 * bat_level) / bat_filled;
   else bat_val = 100;
   
   if (discharging) minutes = (60 * bat_level) / bat_drain;
   else
     {
	/* FIXME: Batteries charge in paralell! */
	if (bat_filled > 0)
	  minutes = (60 * (bat_filled - bat_level)) / bat_drain;
	else
	  minutes = 0;
     }
   hours = minutes / 60;
   minutes -= (hours * 60);

   if (hours < 0) hours = 0;
   if (minutes < 0) minutes = 0;

   if (!battery)
     {
	stat->has_battery = 0;
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup(_("NO BAT"));
	stat->time = strdup("--:--");
	stat->level = 1.0;
     }
   else if ((charging) || (discharging))
     {
	battery_config->battery_prev_battery = 1;
	stat->has_battery = 1;
        if (charging)
          {
	     stat->state = BATTERY_STATE_CHARGING;
	     battery_config->alarm_triggered = 0;
          }
	else if (discharging)
	  {
	     stat->state = BATTERY_STATE_DISCHARGING;
	     if (stat->level < 0.1)
	       {
		  if (((hours * 60) + minutes) <= battery_config->alarm)
		    stat->alarm = 1;
	       }
	  }
	if (level_unknown)
          {
	     stat->reading = strdup(_("BAD DRIVER"));
	     stat->time = strdup("--:--");
	     stat->level = 0.0;
          }
	else if (rate_unknown)
          {
             snprintf(buf, sizeof(buf), "%i%%", bat_val);
	     stat->reading = strdup(buf);
	     stat->time = strdup("--:--");
	     stat->level = (double)bat_val / 100.0;
          }
	else
          {
             snprintf(buf, sizeof(buf), "%i%%", bat_val);
	     stat->reading = strdup(buf);
             snprintf(buf, sizeof(buf), "%i:%02i", hours, minutes);
	     stat->time = strdup(buf);
	     stat->level = (double)bat_val / 100.0;
          }
     }
   else
     {
	stat->has_battery = 1;
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup(_("FULL"));
	stat->time = strdup("--:--");
	stat->level = 1.0;
     }
   return stat;
}

static Status *
_battery_linux_apm_check(void)
{
   FILE *f;
   char s[256], s1[32], s2[32], s3[32], buf[4096];
   int  apm_flags, ac_stat, bat_stat, bat_flags, bat_val, time_val;
   int  hours, minutes;

   Status *stat;

   f = fopen("/proc/apm", "r");
   if (!f) return NULL;

   fgets(s, sizeof(s), f); s[sizeof(s) - 1] = 0;
   if (sscanf(s, "%*s %*s %x %x %x %x %s %s %s",
	      &apm_flags, &ac_stat, &bat_stat, &bat_flags, s1, s2, s3) != 7)
     {
	fclose(f);
	return NULL;
     }
   s1[strlen(s1) - 1] = 0;
   bat_val = atoi(s1);
   if (!strcmp(s3, "sec")) time_val = atoi(s2);
   else if (!strcmp(s3, "min")) time_val = atoi(s2) * 60;
   fclose(f);

   stat = E_NEW(Status, 1);
   if (!stat) return NULL;

   if ((bat_flags != 0xff) && (bat_flags & 0x80))
     {
	stat->has_battery = 0;
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup("NO BAT");
	stat->time = strdup("--:--");
	stat->level = 1.0;
	return stat;
     }
   
   
   battery_config->battery_prev_battery = 1;
   stat->has_battery = 1;
   if (bat_val >= 0)
     {
	if (bat_val > 100) bat_val = 100;
	snprintf(buf, sizeof(buf), "%i%%", bat_val);
	stat->reading = strdup(buf);
	stat->level = (double)bat_val / 100.0;
     }
   else
     {
	switch (bat_stat)
	  {
	   case 0:
	      stat->reading = strdup(_("High"));
	      stat->level = 1.0;
	      break;
	   case 1:
	      stat->reading = strdup(_("Low"));
	      stat->level = 0.5;
	      break;
	   case 2:
	      stat->reading = strdup(_("Danger"));
	      stat->level = 0.25;
	      break;
	   case 3:
	      stat->reading = strdup(_("Charging"));
	      stat->level = 1.0;
	      break;
	  }
     }

   if (ac_stat == 1)
     {
	stat->state = BATTERY_STATE_CHARGING;
	stat->time = strdup("--:--");
     }
   else
     {
	/* ac_stat == 0 */
	stat->state = BATTERY_STATE_DISCHARGING;

	hours = time_val / 3600;
	minutes = (time_val / 60) % 60;
	snprintf(buf, sizeof(buf), "%i:%02i", hours, minutes);
	stat->time = strdup(buf);
	if (stat->level < 0.1)
	  {
	     if (((hours * 60) + minutes) <= battery_config->alarm)
	       stat->alarm = 1;
	  }
     }

   return stat;
}


/* hack for pmu */

/* This function converts a string to an integer. Additionally to
 * atoi() it converts also hexadecimal values
 */
static int
axtoi(char *arg)
{
   int n, val, pwr=1, m, rc = 0;
   char hex[9], c;
   
   for (n = 0, m = 0; n < strlen(arg); n++)
     {
	if (arg[n] != ' ')
	  {
	     hex[m++] = c = toupper(arg[n]);
	     if ((m == sizeof(hex)) || (c < '0') || (c > 'F'))
	       return 0;   /* overflow or invalid */
	  }
     }
   hex[m] = '\0';  /* terminate string */
   
   for (n = 0; n < m; n++)
     {
	c = hex[m-n-1];
	if ((c >= 'A') && (c <= 'F'))
	  val = c -'A' + 10;
	else
	  val = c - '0';
	rc = rc + val * pwr;
	pwr *= 16;
     }
   return rc;
}

static Status *
_battery_linux_powerbook_check(void)
{
   Ecore_List *bats;
   char buf[4096], buf2[4096];
   char *name;
   char *token;
   FILE *f;
   int discharging = 0;
   int charging = 0;
   int battery = 0;
   int ac = 0;
   int seconds = 0;
   int hours, minutes;
   int flags;
   int voltage;
   int charge;
   int max_charge;
   double tmp;
   Status *stat;

   stat = E_NEW(Status, 1);
   if (!stat) return NULL;

   /* Read some information. */
   f = fopen("/proc/pmu/info", "r");
   if (f)
     {
	/* Skip driver */
	fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
	/* Skip firmware */
	fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
	/* Read ac */
	fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
	ac = _battery_int_get(buf2);
	fclose(f);
     }

   bats = ecore_file_ls("/proc/pmu");
   if (bats)
     {
	while ((name = ecore_list_next(bats)))
	  {
	     if (strncmp(name, "battery", 7))
	       continue;

	     snprintf(buf, sizeof(buf), "/proc/pmu/%s", name);
	     f = fopen(buf, "r");
	     if (f)
	       {
		  int time = 0;
		  int current = 0;

		  while (fgets (buf,sizeof (buf), f))
		    {
		       if ((token = strtok (buf, ":")))
			 {
			    if (!strncmp ("flags", token, 5))
			      flags = axtoi (strtok (0, ": "));
			    else if (!strncmp ("charge", token, 6)) 
			      charge = atoi(strtok(0, ": "));
			    else if (!strncmp ("max_charge", token, 9))
			      max_charge = atoi (strtok(0,": "));
			    else if (!strncmp ("current", token, 7))
			      current = atoi (strtok(0, ": "));
			    else if (!strncmp ("time rem", token, 8))
			      time = atoi (strtok(0, ": "));
			    else if (!strncmp ("voltage", token, 7))
			      voltage = atoi (strtok(0,": "));
			    else
			      strtok (0,": ");
			 }
		    }
		  /* Skip flag;
		  int tmp = 0;		  
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  tmp = _battery_int_get(buf2);
		  charge += tmp;
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  tmp = _battery_int_get(buf2);
		  max_charge += tmp;
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  current = _battery_int_get(buf2);
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  fgets(buf2, sizeof(buf2), f); buf2[sizeof(buf2) - 1] = 0;
		  time = _battery_int_get(buf2);
		   */
		  fclose(f);

		  battery = 1;
		  if (!current)
		    {
		       /* Neither charging nor discharging */
		    }
		  else if (!ac)
		    {
		       /* When on dc, we are discharging */
		       discharging = 1;
		       seconds += time;
		    }
		  else
		    {
		       /* Charging */
		       charging = 1;
		       /* Charging works in paralell */
		       seconds = MAX(time, seconds);
		    }

	       }
	  }
	ecore_list_destroy(bats);
     }
   hours = seconds / (60 * 60);
   seconds -= hours * (60 * 60);
   minutes = seconds / 60;
   seconds -= minutes * 60;

   if (hours < 0) hours = 0;
   if (minutes < 0) minutes = 0;

   
   if (!battery)
     {
	stat->has_battery = 0;
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup(_("NO BAT"));
	stat->time = strdup("--:--");
	stat->level = 1.0;
     }
   else if ((charging) || (discharging))
     {
	stat->has_battery = 1;
        if (charging)
          {
	     stat->state = BATTERY_STATE_CHARGING;
	     battery_config->alarm_triggered = 0;
          }
	else if (discharging)
	  {
	     stat->state = BATTERY_STATE_DISCHARGING;
	     if (stat->level < 0.1)
	       {
		  if (((hours * 60) + minutes) <= battery_config->alarm)
		    stat->alarm = 1;
	       }
	  }
	stat->level = (double)charge / (double)max_charge;
       if (stat->level > 1.0) stat->level = 1.0;
	tmp = (double)max_charge / 100;
	tmp = (double)charge / tmp;
	stat->level = (double)tmp / 100;

	snprintf(buf, sizeof(buf), "%.0f%%", tmp);
	stat->reading = strdup(buf);
	snprintf(buf, sizeof(buf), "%i:%02i", hours, minutes);
	stat->time = strdup(buf);
     }
   else
     {
	stat->has_battery = 1;
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup(_("FULL"));
	stat->time = strdup("--:--");
	stat->level = 1.0;
     }
   return stat;
}

#ifdef __FreeBSD__
static Status *
_battery_bsd_acpi_check(void)
{
   /* Assumes only a single battery - I don't know how multiple batts 
    * are represented in sysctl */

   Ecore_List *bats;
   char buf[4096], buf2[4096];
   char *name;

   int bat_max = 0;
   int bat_filled = 0;
   int bat_level = 0;
   int bat_drain = 1;

   int bat_val = 0;

   int discharging = 0;
   int charging = 0;
   int battery = 0;

   int design_cap_unknown = 0;
   int last_full_unknown = 0;
   int rate_unknown = 0;
   int level_unknown = 0;

   int hours, minutes;
   
   int mib_state[4];
   int mib_life[4];
   int mib_time[4];
   int mib_units[4];
   size_t len;
   int state;
   int level;
   int time;
   int life;
   int batteries;

   Status *stat;

   stat = E_NEW(Status, 1);
   if (!stat) return NULL;

   /* Read some information on first run. */
   len = 4;
   sysctlnametomib("hw.acpi.battery.state", mib_state, &len);
   len = sizeof(state);
   if (sysctl(mib_state, 4, &state, &len, NULL, 0) == -1)
      /* ERROR */
      state = -1;     

   len = 4;
   sysctlnametomib("hw.acpi.battery.life", mib_life, &len);
   len = sizeof(life);
   if (sysctl(mib_life, 4, &life, &len, NULL, 0) == -1)
      /* ERROR */
      level = -1; 

   bat_val = life;
      
   len = 4;
   sysctlnametomib("hw.acpi.battery.time", mib_time, &len);
   len = sizeof(time);
   if (sysctl(mib_time, 4, &time, &len, NULL, 0) == -1)
      /* ERROR */
      time = -2;     

   len = 4;
   sysctlnametomib("hw.acpi.battery.units", mib_units, &len);
   len = sizeof(batteries);
   if (sysctl(mib_time, 4, &batteries, &len, NULL, 0) == -1)
      /* ERROR */
      batteries = 1;     
   
   if (battery_config->battery_prev_drain < 1)  
     battery_config->battery_prev_drain = 1;
   
   if (bat_drain < 1) 
     bat_drain = battery_config->battery_prev_drain;
   
   battery_config->battery_prev_drain = bat_drain;

   /*if (bat_filled > 0) 
     bat_val = (100 * bat_level) / bat_filled;
   else 
     bat_val = 100;

   if (state == BATTERY_STATE_DISCHARGING) 
     minutes = (60 * bat_level) / bat_drain;
   else
     {
	if (bat_filled > 0)
	  minutes = (60 * (bat_filled - bat_level)) / bat_drain;
	else
	  minutes = 0;
     }*/
   minutes = time;
   hours = minutes / 60;
   minutes -= (hours * 60);

   if (hours < 0) 
     hours = 0;
   if (minutes < 0) 
     minutes = 0;

   if (batteries == 1) /* hw.acpi.battery.units = 1 means NO BATTS */
     {
	stat->has_battery = 0;
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup(_("NO BAT"));
	stat->time = strdup("--:--");
	stat->level = 1.0;
     }
   else if ((state == BATTERY_STATE_CHARGING) || 
	    (state == BATTERY_STATE_DISCHARGING)) 
     {
	battery_config->battery_prev_battery = 1;
	stat->has_battery = 1;
        if (state == BATTERY_STATE_CHARGING)
          {
	     stat->state = BATTERY_STATE_CHARGING;
	     battery_config->alarm_triggered = 0;
          }
	else if (state == BATTERY_STATE_DISCHARGING)
	  {
	     stat->state = BATTERY_STATE_DISCHARGING;
	     if (stat->level < 0.1) /* Why this if condition */
	       {
		  if (((hours * 60) + minutes) <= battery_config->alarm)
		    stat->alarm = 1;
	       }
	  }
	if (!level)
          {
	     stat->reading = strdup(_("BAD DRIVER"));
	     stat->time = strdup("--:--");
	     stat->level = 0.0;
          }
	else if (time == -1)
          {
             snprintf(buf, sizeof(buf), "%i%%", bat_val);
	     stat->reading = strdup(buf);
	     stat->time = strdup("--:--");
	     stat->level = (double)bat_val / 100.0;
          }
	else
          {
             snprintf(buf, sizeof(buf), "%i%%", bat_val);
	     stat->reading = strdup(buf);
             snprintf(buf, sizeof(buf), "%i:%02i", hours, minutes);
	     stat->time = strdup(buf);
	     stat->level = (double)bat_val / 100.0;
          }
     }
   else
     {
	stat->has_battery = 1;
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup(_("FULL"));
	stat->time = strdup("--:--");
	stat->level = 1.0;
     }
   return stat;
}

static Status *
_battery_bsd_apm_check(void)
{
#ifdef __i386__
   int  ac_stat, bat_stat, bat_val, time_val;
   char buf[4096];
   int  hours, minutes;
   int apm_fd = -1;
   struct apm_info info;
   
   Status *stat;

   apm_fd = open("/dev/apm", O_RDONLY);
   
   if (apm_fd != -1 && ioctl(apm_fd, APMIO_GETINFO, &info) != -1)
     {
	/* set values */
	ac_stat = info.ai_acline;
	bat_stat = info.ai_batt_stat;
	bat_val = info.ai_batt_life;
	time_val = info.ai_batt_time;
     }
   else
     {
        return NULL;
     }

   stat = E_NEW(Status, 1);
   if (!stat) return NULL;

   if (info.ai_batteries == 1) /* ai_batteries == 1 means NO battery,
				  ai_batteries == 2 means 1 battery */
     {
	stat->has_battery = 0;
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup("NO BAT");
	stat->time = strdup("--:--");
	stat->level = 1.0;
	return stat;
     }
   
   
   battery_config->battery_prev_battery = 1;
   stat->has_battery = 1;

   if (ac_stat) /* Wallpowered */
     {
	stat->state = BATTERY_STATE_CHARGING;
	stat->time = strdup("--:--");
	switch (bat_stat) /* On FreeBSD the time_val is -1 when AC ist plugged
			     in. This means we don't know how long the battery
			     will recharge */ 
	  {
	   case 0:
	      stat->reading = strdup(_("High"));
	      stat->level = 1.0; 
	      break;
	   case 1:
	      stat->reading = strdup(_("Low"));
	      stat->level = 0.5;
	      break;
	   case 2:
	      stat->reading = strdup(_("Danger"));
	      stat->level = 0.25;
	      break;
	   case 3:
	      stat->reading = strdup(_("Charging"));
	      stat->level = 1.0;
	      break;
	  }
     }
   else /* Running on battery */
     {
	stat->state = BATTERY_STATE_DISCHARGING;
	
        snprintf(buf, sizeof(buf), "%i%%", bat_val);
        stat->reading = strdup(buf);
        stat->level = (double)bat_val / 100.0;
	
	hours = time_val / 3600;
	minutes = (time_val / 60) % 60;
	snprintf(buf, sizeof(buf), "%i:%02i", hours, minutes);
	stat->time = strdup(buf);

	if (stat->level < 0.1) /* Why this if condition? */
	  {
	     if (((hours * 60) + minutes) <= battery_config->alarm)
	       stat->alarm = 1;
	  }
     }
   
   return stat;
#else
   return NULL;
#endif
}
#endif

#ifdef HAVE_CFBASE_H
/*
 * There is a good chance this will work with a UPS as well as a battery.
 */
static Status *
_battery_darwin_check(void)
{
   const void *values;
   int device_num;
   int device_count;
   int  hours, minutes;
   int currentval = 0;
   int maxval = 0;
   char buf[4096];
   CFTypeRef blob;
   CFArrayRef sources;
   CFDictionaryRef device_dict;
   
   Status *stat;

   stat = E_NEW(Status, 1);
   if (!stat) return NULL;

   /*
    * Retrieve the power source data and the array of sources.
    */
   blob = IOPSCopyPowerSourcesInfo();
   sources = IOPSCopyPowerSourcesList(blob);
   device_count = CFArrayGetCount(sources); 

   for (device_num = 0; device_num < device_count; device_num++)
     {
	CFTypeRef ps;

	printf("device %d of %d\n", device_num, device_count);

	/*
	 * Retrieve a dictionary of values for this device and the
	 * count of keys in the dictionary.
	 */
	ps = CFArrayGetValueAtIndex(sources, device_num);
	device_dict = IOPSGetPowerSourceDescription(blob, ps);

	/*
	 * Retrieve the charging key and save the present charging value if
	 * one exists.
	 */
	if (CFDictionaryGetValueIfPresent(device_dict, CFSTR(kIOPSIsChargingKey), &values))
	  {
	     stat->has_battery = 1;
	     printf("%s: %d\n", kIOPSIsChargingKey, CFBooleanGetValue(values));
	     if (CFBooleanGetValue(values) > 0)
	       {
		  stat->state = BATTERY_STATE_CHARGING;
	       }
	     else
	       {
		  stat->state = BATTERY_STATE_DISCHARGING;
	       }
	     /* CFRelease(values); */
	     break;
	  }

     }

   /*
    * Check for battery.
    */
   if (!stat->has_battery)
     {
	CFRelease(sources);
	CFRelease(blob);
	stat->state = BATTERY_STATE_NONE;
	stat->reading = strdup("NO BAT");
	stat->time = strdup("--:--");
	stat->level = 1.0;
	return stat;
     }

   /*
    * A battery was found so move along based on that assumption.
    */
   battery_config->battery_prev_battery = 1;
   stat->has_battery = 1;

   /*
    * Retrieve the current capacity key.
    */
   values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSCurrentCapacityKey));
   CFNumberGetValue(values, kCFNumberSInt32Type, &currentval);
   /* CFRelease(values); */

   /*
    * Retrieve the max capacity key.
    */
   values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSMaxCapacityKey));
   CFNumberGetValue(values, kCFNumberSInt32Type, &maxval);
   /* CFRelease(values); */

   /*
    * Calculate the percentage charged.
    */
   stat->level = (double)currentval / (double)maxval;
   printf("Battery charge %g\n", stat->level);

   /*
    * Retrieve the remaining battery power or time until charged in minutes.
    */
   if (stat->state == BATTERY_STATE_DISCHARGING)
     {
	values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSTimeToEmptyKey));
	CFNumberGetValue(values, kCFNumberSInt32Type, &currentval);
	/* CFRelease(values); */

	/*
	 * Display remaining battery percentage.
	 */
	snprintf(buf, sizeof(buf), "%i%%", (int)(stat->level * 100));
	stat->reading = strdup(buf);

	hours = currentval / 60;
	minutes = currentval % 60;

	/*
	 * Check if an alarm should be raised.
	 */
	if (currentval <= battery_config->alarm)
	  stat->alarm = 1;
     }
   else
     {
	values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSTimeToFullChargeKey));
	CFNumberGetValue(values, kCFNumberSInt32Type, &currentval);
	/* CFRelease(values); */

	stat->reading = strdup(_("Charging"));

	hours = currentval / 60;
	minutes = currentval % 60;
     }

   /*
    * Store the time remaining.
    */
   if (minutes >= 0)
     {
	snprintf(buf, sizeof(buf), "%i:%02i", hours, minutes);
	stat->time = strdup(buf);
     }
   else
     stat->time = strdup("--:--");

   CFRelease(sources);
   CFRelease(blob);

   return stat;
}
#endif

static void
_battery_face_level_set(Instance *inst, double level)
{
   Edje_Message_Float msg;

   if (level < 0.0) level = 0.0;
   else if (level > 1.0) level = 1.0;
   msg.val = level;
   edje_object_message_send(inst->evo, EDJE_MESSAGE_FLOAT, 1, &msg);
}

static int
_battery_int_get(char *buf)
{
   char *p, *q;

   p = strchr(buf, ':');
   if (!p) return 0;
   p++;
   while (*p == ' ') p++;
   q = p;
   while ((*q != ' ') && (*q != '\n')) q++;
   if (q) *q = 0;
   return atoi(p);
}

static char *
_battery_string_get(char *buf)
{
   char *p, *q;

   p = strchr(buf, ':');
   if (!p) return NULL;
   p++;
   while (*p == ' ') p++;
   q = p;
   while ((*q != ' ') && (*q != '\n')) q++;
   if (q) *q = 0;
   return strdup(p);
}

static void 
_battery_face_cb_menu_configure(void *data, E_Menu *m, E_Menu_Item *mi) 
{
   if (!battery_config) return;
   if (battery_config->config_dialog) return;
   _config_battery_module();
}

void
_battery_config_updated(void)
{
   if (!battery_config) return;
   ecore_timer_del(battery_config->battery_check_timer);
   battery_config->battery_check_timer = ecore_timer_add(battery_config->poll_time,
						 _battery_cb_check, NULL);
   _battery_cb_check(NULL);
}

/***************************************************************************/
/**/
/* module setup */
EAPI E_Module_Api e_modapi = 
{
   E_MODULE_API_VERSION,
     "Battery"
};

EAPI void *
e_modapi_init(E_Module *m)
{
   conf_edd = E_CONFIG_DD_NEW("Battery_Config", Config);
#undef T
#undef D
#define T Config
#define D conf_edd
   E_CONFIG_VAL(D, T, poll_time, DOUBLE);
   E_CONFIG_VAL(D, T, alarm, INT);

   battery_config = e_config_domain_load("module.battery", conf_edd);
   if (!battery_config)
     {
       battery_config = E_NEW(Config, 1);
       battery_config->poll_time = 30.0;
       battery_config->alarm = 30;
     }
   E_CONFIG_LIMIT(battery_config->poll_time, 0.5, 1000.0);
   E_CONFIG_LIMIT(battery_config->alarm, 0, 60);
   
   battery_config->battery_check_mode = CHECK_NONE;
   battery_config->battery_prev_drain = 1;
   battery_config->battery_prev_ac = -1;
   battery_config->battery_prev_battery = -1;
   battery_config->battery_check_timer = ecore_timer_add(battery_config->poll_time,
						 _battery_cb_check, NULL);
   battery_config->module = m;
   
   e_gadcon_provider_register(&_gadcon_class);
   return 1;
}

EAPI int
e_modapi_shutdown(E_Module *m)
{
   e_gadcon_provider_unregister(&_gadcon_class);
   
   if (battery_config->config_dialog)
     e_object_del(E_OBJECT(battery_config->config_dialog));
   if (battery_config->battery_check_timer)
     ecore_timer_del(battery_config->battery_check_timer);
   if (battery_config->menu)
     {
        e_menu_post_deactivate_callback_set(battery_config->menu, NULL, NULL);
	e_object_del(E_OBJECT(battery_config->menu));
	battery_config->menu = NULL;
     }
   free(battery_config);
   battery_config = NULL;
   E_CONFIG_DD_FREE(conf_edd);
   return 1;
}

EAPI int
e_modapi_save(E_Module *m)
{
   e_config_domain_save("module.battery", conf_edd, battery_config);
   return 1;
}

EAPI int
e_modapi_about(E_Module *m)
{
   e_module_dialog_show(_("Enlightenment Battery Module"),
		       _("A basic battery meter that uses either"
		 	 "<hilight>ACPI</hilight> or <hilight>APM</hilight><br>"
			 "on Linux to monitor your battery and AC power adaptor<br>"
			 "status. This will work under Linux and FreeBSD and is only<br>"
			 "as accurate as your BIOS or kernel drivers."));
   return 1;
}

EAPI int
e_modapi_config(E_Module *m)
{
   if (!battery_config) return 0;
   if (battery_config->config_dialog) return 0;
   _config_battery_module();
   return 1;
}
/**/
/***************************************************************************/
typedef struct _Instance Instance;

struct _Instance
{
   E_Gadcon_Client *gcc;
   Evas_Object     *evo;
};


Instance * gcc_instance_get(E_Gadcon_Client *gcc)
{
   return gcc->data;
}

E_Gadcon_Client * gcc_create(E_Gadcon *gc, const char *name, const char *id, const char *style)
{
   Evas_Object *o;
   E_Gadcon_Client *gcc;
   Instance *inst;
   
   inst = E_NEW(Instance, 1);
   
   gcc = e_gadcon_client_new(gc, name, id, style, o);
   inst->gcc = gcc;

   o = edje_object_add(gc->evas);
   inst->evo = o; 

   gcc->data = inst;
   return gcc;
}

void gcc_theme_set(E_Gadcon_Client *gcc, const char *base, const char *part)
{
   Instance *inst = gcc_instance_get(gcc);
   e_theme_edje_object_set(inst->evo, base, part);
}

void gcc_event_callback_add(E_Gadcon_Client *gcc, Evas_Callback_Type type, void (*func) (void *data, Evas *e, Evas_Object *obj, void *event_info))
{
   Instance *inst = gcc_instance_get(gcc);
   evas_object_event_callback_add(inst->evo, type, func, inst);
}

void gcc_free(E_Gadcon_Client *gcc)
{
   Instance *inst = gcc_instance_get(gcc);
   evas_object_del(inst->evo);
   free(inst);
}
#ifndef GCC_H
#define GCC_H

typedef struct _Instance Instance;

Instance* gcc_instance_get(E_Gadcon_Client *);
E_Gadcon_Client* gcc_create(E_Gadcon*, const char *, const char *, const char *style);

void gcc_theme_set(E_Gadcon_Client *gcc, const char *, const char *part);
void gcc_event_callback_add(E_Gadcon_Client *gcc, Evas_Callback_Type type, void (*) (void *, Evas *, Evas_Object *, void *));

void gcc_free(E_Gadcon_Client *gcc);


#endif