<commit_before>#include "e.h"
#include "e_mod_main.h"

/***************************************************************************/
/**/
/* 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, E_Gadcon_Orient orient);
static const char      *_gc_label(const E_Gadcon_Client_Class *client_class);
static Evas_Object     *_gc_icon(const E_Gadcon_Client_Class *client_class, Evas *evas);
static const char      *_gc_id_new(const E_Gadcon_Client_Class *client_class);

/* and actually define the gadcon class that this module provides (just 1) */
static E_Gadcon_Client_Class _gadcon_class = {
   GADCON_CLIENT_CLASS_VERSION,
   "tasks",
   {
      _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, NULL
   },
   E_GADCON_CLIENT_STYLE_PLAIN
};
/**/
/***************************************************************************/
/***************************************************************************/
/**/
/* actual module specifics */

typedef struct _Tasks      Tasks;
typedef struct _Tasks_Item Tasks_Item;

struct _Tasks
{
   E_Gadcon_Client *gcc; // The gadcon client
   Evas_Object     *o_items; // Table of items
   Eina_List       *items; // List of items
   E_Zone          *zone; // Current Zone
   Config_Item     *config; // Configuration
   int              horizontal;
};

struct _Tasks_Item
{
   Tasks       *tasks; // Parent tasks
   E_Border    *border; // The border this item points to
   Evas_Object *o_item; // The edje theme object
   Evas_Object *o_icon; // The icon
   Eina_Bool skip_taskbar : 1;
};

static Tasks       *_tasks_new(Evas *evas, E_Zone *zone, const char *id);
static void         _tasks_free(Tasks *tasks);
static void         _tasks_refill(Tasks *tasks);
static void         _tasks_refill_all();
static void         _tasks_refill_border(E_Border *border);
static void         _tasks_signal_emit(E_Border *border, char *sig, char *src);

static Tasks_Item  *_tasks_item_find(Tasks *tasks, E_Border *border);
static Tasks_Item  *_tasks_item_new(Tasks *tasks, E_Border *border);

static int          _tasks_item_check_add(Tasks *tasks, E_Border *border);
static void         _tasks_item_add(Tasks *tasks, E_Border *border);
static void         _tasks_item_remove(Tasks_Item *item);
static void         _tasks_item_refill(Tasks_Item *item);
static void         _tasks_item_fill(Tasks_Item *item);
static void         _tasks_item_free(Tasks_Item *item);
static void         _tasks_item_signal_emit(Tasks_Item *item, char *sig, char *src);

static Config_Item *_tasks_config_item_get(const char *id);

static void         _tasks_cb_menu_configure(void *data, E_Menu *m, E_Menu_Item *mi);
static void         _tasks_cb_item_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void         _tasks_cb_item_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void         _tasks_cb_item_mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);

static Eina_Bool    _tasks_cb_event_border_add(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_remove(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_iconify(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_uniconify(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_icon_change(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_zone_set(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_desk_set(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_window_focus_in(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_window_focus_out(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_property(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_desk_show(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_urgent_change(void *data, int type, void *event);

static E_Config_DD *conf_edd = NULL;
static E_Config_DD *conf_item_edd = NULL;

Config *tasks_config = NULL;

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

EAPI void *
e_modapi_init(E_Module *m)
{
   conf_item_edd = E_CONFIG_DD_NEW("Tasks_Config_Item", Config_Item);

#undef T
#undef D
#define T Config_Item
#define D conf_item_edd
   E_CONFIG_VAL(D, T, id, STR);
   E_CONFIG_VAL(D, T, show_all, INT);
   E_CONFIG_VAL(D, T, minw, INT);
   E_CONFIG_VAL(D, T, minh, INT);
   E_CONFIG_VAL(D, T, icon_only, UCHAR);
   E_CONFIG_VAL(D, T, text_only, UCHAR);

   conf_edd = E_CONFIG_DD_NEW("Tasks_Config", Config);

#undef T
#undef D
#define T Config
#define D conf_edd
   E_CONFIG_LIST(D, T, items, conf_item_edd);

   tasks_config = e_config_domain_load("module.tasks", conf_edd);
   if (!tasks_config)
     {
        Config_Item *config;

        tasks_config = E_NEW(Config, 1);

        config = E_NEW(Config_Item, 1);
        config->id = eina_stringshare_add("0");
        config->show_all = 0;
        config->minw = 100;
        config->minh = 32;
        tasks_config->items = eina_list_append(tasks_config->items, config);
     }

   tasks_config->module = m;

   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_ADD, _tasks_cb_event_border_add, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_REMOVE, _tasks_cb_event_border_remove, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_ICONIFY, _tasks_cb_event_border_iconify, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_UNICONIFY, _tasks_cb_event_border_uniconify, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_ICON_CHANGE, _tasks_cb_event_border_icon_change, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_DESK_SET, _tasks_cb_event_border_desk_set, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_ZONE_SET, _tasks_cb_event_border_zone_set, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_FOCUS_IN, _tasks_cb_window_focus_in, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_FOCUS_OUT, _tasks_cb_window_focus_out, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_PROPERTY, _tasks_cb_event_border_property, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_DESK_SHOW, _tasks_cb_event_desk_show, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_URGENT_CHANGE, _tasks_cb_event_border_urgent_change, NULL));

   tasks_config->borders = eina_list_clone(e_border_client_list());

   e_gadcon_provider_register(&_gadcon_class);
   return m;
}

EAPI int
e_modapi_shutdown(E_Module *m __UNUSED__)
{
   Ecore_Event_Handler *eh;
   Tasks *tasks;
   Config_Item *cfg;

   e_gadcon_provider_unregister(&_gadcon_class);

   EINA_LIST_FREE(tasks_config->tasks, tasks)
     {
        _tasks_free(tasks);
     }

   if (tasks_config->config_dialog)
     e_object_del(E_OBJECT(tasks_config->config_dialog));

   EINA_LIST_FREE(tasks_config->items, cfg)
     {
        eina_stringshare_del(cfg->id);
        free(cfg);
     }

   EINA_LIST_FREE(tasks_config->handlers, eh)
     {
        ecore_event_handler_del(eh);
     }

   eina_list_free(tasks_config->borders);

   free(tasks_config);
   tasks_config = NULL;
   E_CONFIG_DD_FREE(conf_item_edd);
   E_CONFIG_DD_FREE(conf_edd);
   return 1;
}

EAPI int
e_modapi_save(E_Module *m __UNUSED__)
{
   e_config_domain_save("module.tasks", conf_edd, tasks_config);
   return 1;
}

/**************************************************************/

static E_Gadcon_Client *
_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style __UNUSED__)
{
   Tasks *tasks;
   Evas_Object *o;
   E_Gadcon_Client *gcc;
   /* Evas_Coord x, y, w, h; */
   /* int cx, cy, cw, ch; */

   tasks = _tasks_new(gc->evas, gc->zone, id);

   o = tasks->o_items;
   gcc = e_gadcon_client_new(gc, name, id, E_GADCON_CLIENT_STYLE_INSET, o);
   gcc->data = tasks;
   tasks->gcc = gcc;

   /* e_gadcon_canvas_zone_geometry_get(gcc->gadcon, &cx, &cy, &cw, &ch); */
   /* evas_object_geometry_get(o, &x, &y, &w, &h); */

   tasks_config->tasks = eina_list_append(tasks_config->tasks, tasks);

   e_gadcon_client_autoscroll_toggle_disabled_set(gcc, 1);
   // Fill on initial config
   _tasks_config_updated(tasks->config);
   return gcc;
}

static void
_gc_shutdown(E_Gadcon_Client *gcc)
{
   Tasks *tasks;

   tasks = (Tasks *)gcc->data;
   tasks_config->tasks = eina_list_remove(tasks_config->tasks, tasks);
   _tasks_free(tasks);
}

/* TODO */
static void
_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient)
{
   Tasks *tasks;

   tasks = (Tasks *)gcc->data;

   switch (orient)
     {
      case E_GADCON_ORIENT_FLOAT:
      case E_GADCON_ORIENT_HORIZ:
      case E_GADCON_ORIENT_TOP:
      case E_GADCON_ORIENT_BOTTOM:
      case E_GADCON_ORIENT_CORNER_TL:
      case E_GADCON_ORIENT_CORNER_TR:
      case E_GADCON_ORIENT_CORNER_BL:
      case E_GADCON_ORIENT_CORNER_BR:
        if (!tasks->horizontal)
          {
             tasks->horizontal = 1;
             e_box_orientation_set(tasks->o_items, tasks->horizontal);
             _tasks_refill(tasks);
          }
        break;

      case E_GADCON_ORIENT_VERT:
      case E_GADCON_ORIENT_LEFT:
      case E_GADCON_ORIENT_RIGHT:
      case E_GADCON_ORIENT_CORNER_LT:
      case E_GADCON_ORIENT_CORNER_RT:
      case E_GADCON_ORIENT_CORNER_LB:
      case E_GADCON_ORIENT_CORNER_RB:
        if (tasks->horizontal)
          {
             tasks->horizontal = 0;
             e_box_orientation_set(tasks->o_items, tasks->horizontal);
             _tasks_refill(tasks);
          }
        break;

      default:
        break;
     }
   e_box_align_set(tasks->o_items, 0.5, 0.5);
}

static const char *
_gc_label(const E_Gadcon_Client_Class *client_class __UNUSED__)
{
   return _("Tasks");
}

static Evas_Object *
_gc_icon(const E_Gadcon_Client_Class *client_class __UNUSED__, Evas *evas)
{
   Evas_Object *o;
   char buf[4096];

   o = edje_object_add(evas);
   snprintf(buf, sizeof(buf), "%s/e-module-tasks.edj",
            e_module_dir_get(tasks_config->module));
   edje_object_file_set(o, buf, "icon");
   return o;
}

static const char *
_gc_id_new(const E_Gadcon_Client_Class *client_class __UNUSED__)
{
   Config_Item *config;

   config = _tasks_config_item_get(NULL);
   return config->id;
}

/***************************************************************************/

static Tasks *
_tasks_new(Evas *evas, E_Zone *zone, const char *id)
{
   Tasks *tasks;

   tasks = E_NEW(Tasks, 1);
   tasks->config = _tasks_config_item_get(id);
   tasks->o_items = e_box_add(evas);
   tasks->horizontal = 1;

   e_box_homogenous_set(tasks->o_items, 1);
   e_box_orientation_set(tasks->o_items, tasks->horizontal);
   e_box_align_set(tasks->o_items, 0.5, 0.5);
   tasks->zone = zone;
   return tasks;
}

static void
_tasks_free(Tasks *tasks)
{
   Tasks_Item *item;
   EINA_LIST_FREE(tasks->items, item)
     _tasks_item_free(item);
   evas_object_del(tasks->o_items);
   free(tasks);
}

static void
_tasks_refill(Tasks *tasks)
{
   Eina_List *l;
   E_Border *border;
   Tasks_Item *item;
   Evas_Coord w, h;

   while (tasks->items)
     {
        item = tasks->items->data;
        _tasks_item_remove(item);
     }
   EINA_LIST_FOREACH(tasks_config->borders, l, border)
     {
        _tasks_item_check_add(tasks, border);
     }
   if (tasks->items)
     {
        item = tasks->items->data;
        edje_object_size_min_calc(item->o_item, &w, &h);
        if (tasks->horizontal)
          {
             if (w < tasks->config->minw) w = tasks->config->minw;
          }
        else
          {
             if (h < tasks->config->minh) h = tasks->config->minh;
          }
        if (!tasks->gcc->resizable)
          {
             if (tasks->horizontal)
               e_gadcon_client_min_size_set(tasks->gcc,
                                            w * eina_list_count(tasks->items),
                                            h);
             else
               e_gadcon_client_min_size_set(tasks->gcc,
                                            w,
                                            h * eina_list_count(tasks->items));
          }
     }
   else
     e_gadcon_client_min_size_set(tasks->gcc, 0, 0);
}

static void
_tasks_refill_all(void)
{
   const Eina_List *l;
   Tasks *tasks;

   EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
     {
        _tasks_refill(tasks);
     }
}

static void
_tasks_refill_border(E_Border *border)
{
   const Eina_List *l;
   Tasks *tasks;
   Eina_Bool found = EINA_FALSE;

   EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
     {
        const Eina_List *m;
        Tasks_Item *item;
        EINA_LIST_FOREACH(tasks->items, m, item)
          {
             if (item->border == border)
               {
                  _tasks_item_refill(item);
                  found = EINA_TRUE;
                  break;
               }
          }
     }
   if (!found) _tasks_refill_all();
}

static void
_tasks_signal_emit(E_Border *border, char *sig, char *src)
{
   const Eina_List *l;
   Tasks *tasks;

   EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
     {
        const Eina_List *m;
        Tasks_Item *item;

        EINA_LIST_FOREACH(tasks->items, m, item)
          {
             if (item->border == border)
               _tasks_item_signal_emit(item, sig, src);
          }
     }
}

static Tasks_Item *
_tasks_item_find(Tasks *tasks, E_Border *border)
{
   const Eina_List *l;
   Tasks_Item *item;

   EINA_LIST_FOREACH(tasks->items, l, item)
     {
        if (item->border == border) return item;
     }
   return NULL;
}

static Tasks_Item *
_tasks_item_new(Tasks *tasks, E_Border *border)
{
   Tasks_Item *item;

   item = E_NEW(Tasks_Item, 1);
   e_object_ref(E_OBJECT(border));
   item->tasks = tasks;
   item->border = border;
   item->skip_taskbar = border->client.netwm.state.skip_taskbar;
   item->o_item = edje_object_add(evas_object_evas_get(tasks->o_items));
   if (tasks->horizontal)
     e_theme_edje_object_set(item->o_item,
                             "base/theme/modules/tasks",
                             "e/modules/tasks/item");
   else
     {
        if (!e_theme_edje_object_set(item->o_item,
                                     "base/theme/modules/tasks",
                                     "e/modules/tasks/item_vert"))
          e_theme_edje_object_set(item->o_item,
                                  "base/theme/modules/tasks",
                                  "e/modules/tasks/item");
     }
   evas_object_event_callback_add(item->o_item, EVAS_CALLBACK_MOUSE_DOWN,
                                  _tasks_cb_item_mouse_down, item);
   evas_object_event_callback_add(item->o_item, EVAS_CALLBACK_MOUSE_UP,
                                  _tasks_cb_item_mouse_up, item);
   evas_object_event_callback_add(item->o_item, EVAS_CALLBACK_MOUSE_WHEEL,
                                  _tasks_cb_item_mouse_wheel, item);
   evas_object_show(item->o_item);

   _tasks_item_fill(item);
   return item;
}

static int
_tasks_item_check_add(Tasks *tasks, E_Border *border)
{
   if (border->user_skip_winlist) return 1;
   if (border->client.netwm.state.skip_taskbar) return 1;
   if (_tasks_item_find(tasks, border)) return 1;
   if (!tasks->config) return 1;
   if (!(tasks->config->show_all))
     {
        if (border->zone != tasks->zone) return 1;
        if ((border->desk != e_desk_current_get(border->zone)) &&
            (!border->sticky))
          return 1;
     }
   _tasks_item_add(tasks, border);
   return 0;
}

static void
_tasks_item_add(Tasks *tasks, E_Border *border)
{
   Tasks_Item *item;

   item = _tasks_item_new(tasks, border);
   e_box_pack_end(tasks->o_items, item->o_item);
   e_box_pack_options_set(item->o_item,
                          1, 1, /* fill */
                          1, 1, /* expand */
                          0.5, 0.5, /* align */
                          1, 1, /* min */
                          9999, 9999 /* max */
                          );
   tasks->items = eina_list_append(tasks->items, item);
}

static void
_tasks_item_remove(Tasks_Item *item)
{
   item->tasks->items = eina_list_remove(item->tasks->items, item);
   e_box_unpack(item->o_item);
   evas_object_del(item->o_item);
   _tasks_item_free(item);
}

static void
_tasks_item_free(Tasks_Item *item)
{
   if (item->o_icon) evas_object_del(item->o_icon);
   e_object_unref(E_OBJECT(item->border));
   evas_object_del(item->o_item);
   free(item);
}

static void
_tasks_item_refill(Tasks_Item *item)
{
   if (item->border->client.netwm.state.skip_taskbar != item->skip_taskbar)
     {
        _tasks_refill(item->tasks);
        return;
     }
   if (item->o_icon) evas_object_del(item->o_icon);
   _tasks_item_fill(item);
}

static void
_tasks_item_fill(Tasks_Item *item)
{<commit_msg>fix tasks module double item del<commit_after>#include "e.h"
#include "e_mod_main.h"

/***************************************************************************/
/**/
/* 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, E_Gadcon_Orient orient);
static const char      *_gc_label(const E_Gadcon_Client_Class *client_class);
static Evas_Object     *_gc_icon(const E_Gadcon_Client_Class *client_class, Evas *evas);
static const char      *_gc_id_new(const E_Gadcon_Client_Class *client_class);

/* and actually define the gadcon class that this module provides (just 1) */
static E_Gadcon_Client_Class _gadcon_class = {
   GADCON_CLIENT_CLASS_VERSION,
   "tasks",
   {
      _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, NULL
   },
   E_GADCON_CLIENT_STYLE_PLAIN
};
/**/
/***************************************************************************/
/***************************************************************************/
/**/
/* actual module specifics */

typedef struct _Tasks      Tasks;
typedef struct _Tasks_Item Tasks_Item;

struct _Tasks
{
   E_Gadcon_Client *gcc; // The gadcon client
   Evas_Object     *o_items; // Table of items
   Eina_List       *items; // List of items
   E_Zone          *zone; // Current Zone
   Config_Item     *config; // Configuration
   int              horizontal;
};

struct _Tasks_Item
{
   Tasks       *tasks; // Parent tasks
   E_Border    *border; // The border this item points to
   Evas_Object *o_item; // The edje theme object
   Evas_Object *o_icon; // The icon
   Eina_Bool skip_taskbar : 1;
};

static Tasks       *_tasks_new(Evas *evas, E_Zone *zone, const char *id);
static void         _tasks_free(Tasks *tasks);
static void         _tasks_refill(Tasks *tasks);
static void         _tasks_refill_all();
static void         _tasks_refill_border(E_Border *border);
static void         _tasks_signal_emit(E_Border *border, char *sig, char *src);

static Tasks_Item  *_tasks_item_find(Tasks *tasks, E_Border *border);
static Tasks_Item  *_tasks_item_new(Tasks *tasks, E_Border *border);

static int          _tasks_item_check_add(Tasks *tasks, E_Border *border);
static void         _tasks_item_add(Tasks *tasks, E_Border *border);
static void         _tasks_item_remove(Tasks_Item *item);
static void         _tasks_item_refill(Tasks_Item *item);
static void         _tasks_item_fill(Tasks_Item *item);
static void         _tasks_item_free(Tasks_Item *item);
static void         _tasks_item_signal_emit(Tasks_Item *item, char *sig, char *src);

static Config_Item *_tasks_config_item_get(const char *id);

static void         _tasks_cb_menu_configure(void *data, E_Menu *m, E_Menu_Item *mi);
static void         _tasks_cb_item_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void         _tasks_cb_item_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void         _tasks_cb_item_mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);

static Eina_Bool    _tasks_cb_event_border_add(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_remove(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_iconify(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_uniconify(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_icon_change(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_zone_set(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_desk_set(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_window_focus_in(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_window_focus_out(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_property(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_desk_show(void *data, int type, void *event);
static Eina_Bool    _tasks_cb_event_border_urgent_change(void *data, int type, void *event);

static E_Config_DD *conf_edd = NULL;
static E_Config_DD *conf_item_edd = NULL;

Config *tasks_config = NULL;

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

EAPI void *
e_modapi_init(E_Module *m)
{
   conf_item_edd = E_CONFIG_DD_NEW("Tasks_Config_Item", Config_Item);

#undef T
#undef D
#define T Config_Item
#define D conf_item_edd
   E_CONFIG_VAL(D, T, id, STR);
   E_CONFIG_VAL(D, T, show_all, INT);
   E_CONFIG_VAL(D, T, minw, INT);
   E_CONFIG_VAL(D, T, minh, INT);
   E_CONFIG_VAL(D, T, icon_only, UCHAR);
   E_CONFIG_VAL(D, T, text_only, UCHAR);

   conf_edd = E_CONFIG_DD_NEW("Tasks_Config", Config);

#undef T
#undef D
#define T Config
#define D conf_edd
   E_CONFIG_LIST(D, T, items, conf_item_edd);

   tasks_config = e_config_domain_load("module.tasks", conf_edd);
   if (!tasks_config)
     {
        Config_Item *config;

        tasks_config = E_NEW(Config, 1);

        config = E_NEW(Config_Item, 1);
        config->id = eina_stringshare_add("0");
        config->show_all = 0;
        config->minw = 100;
        config->minh = 32;
        tasks_config->items = eina_list_append(tasks_config->items, config);
     }

   tasks_config->module = m;

   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_ADD, _tasks_cb_event_border_add, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_REMOVE, _tasks_cb_event_border_remove, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_ICONIFY, _tasks_cb_event_border_iconify, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_UNICONIFY, _tasks_cb_event_border_uniconify, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_ICON_CHANGE, _tasks_cb_event_border_icon_change, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_DESK_SET, _tasks_cb_event_border_desk_set, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_ZONE_SET, _tasks_cb_event_border_zone_set, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_FOCUS_IN, _tasks_cb_window_focus_in, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_FOCUS_OUT, _tasks_cb_window_focus_out, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_PROPERTY, _tasks_cb_event_border_property, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_DESK_SHOW, _tasks_cb_event_desk_show, NULL));
   tasks_config->handlers = eina_list_append
       (tasks_config->handlers, ecore_event_handler_add
         (E_EVENT_BORDER_URGENT_CHANGE, _tasks_cb_event_border_urgent_change, NULL));

   tasks_config->borders = eina_list_clone(e_border_client_list());

   e_gadcon_provider_register(&_gadcon_class);
   return m;
}

EAPI int
e_modapi_shutdown(E_Module *m __UNUSED__)
{
   Ecore_Event_Handler *eh;
   Tasks *tasks;
   Config_Item *cfg;

   e_gadcon_provider_unregister(&_gadcon_class);

   EINA_LIST_FREE(tasks_config->tasks, tasks)
     {
        _tasks_free(tasks);
     }

   if (tasks_config->config_dialog)
     e_object_del(E_OBJECT(tasks_config->config_dialog));

   EINA_LIST_FREE(tasks_config->items, cfg)
     {
        eina_stringshare_del(cfg->id);
        free(cfg);
     }

   EINA_LIST_FREE(tasks_config->handlers, eh)
     {
        ecore_event_handler_del(eh);
     }

   eina_list_free(tasks_config->borders);

   free(tasks_config);
   tasks_config = NULL;
   E_CONFIG_DD_FREE(conf_item_edd);
   E_CONFIG_DD_FREE(conf_edd);
   return 1;
}

EAPI int
e_modapi_save(E_Module *m __UNUSED__)
{
   e_config_domain_save("module.tasks", conf_edd, tasks_config);
   return 1;
}

/**************************************************************/

static E_Gadcon_Client *
_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style __UNUSED__)
{
   Tasks *tasks;
   Evas_Object *o;
   E_Gadcon_Client *gcc;
   /* Evas_Coord x, y, w, h; */
   /* int cx, cy, cw, ch; */

   tasks = _tasks_new(gc->evas, gc->zone, id);

   o = tasks->o_items;
   gcc = e_gadcon_client_new(gc, name, id, E_GADCON_CLIENT_STYLE_INSET, o);
   gcc->data = tasks;
   tasks->gcc = gcc;

   /* e_gadcon_canvas_zone_geometry_get(gcc->gadcon, &cx, &cy, &cw, &ch); */
   /* evas_object_geometry_get(o, &x, &y, &w, &h); */

   tasks_config->tasks = eina_list_append(tasks_config->tasks, tasks);

   e_gadcon_client_autoscroll_toggle_disabled_set(gcc, 1);
   // Fill on initial config
   _tasks_config_updated(tasks->config);
   return gcc;
}

static void
_gc_shutdown(E_Gadcon_Client *gcc)
{
   Tasks *tasks;

   tasks = (Tasks *)gcc->data;
   tasks_config->tasks = eina_list_remove(tasks_config->tasks, tasks);
   _tasks_free(tasks);
}

/* TODO */
static void
_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient)
{
   Tasks *tasks;

   tasks = (Tasks *)gcc->data;

   switch (orient)
     {
      case E_GADCON_ORIENT_FLOAT:
      case E_GADCON_ORIENT_HORIZ:
      case E_GADCON_ORIENT_TOP:
      case E_GADCON_ORIENT_BOTTOM:
      case E_GADCON_ORIENT_CORNER_TL:
      case E_GADCON_ORIENT_CORNER_TR:
      case E_GADCON_ORIENT_CORNER_BL:
      case E_GADCON_ORIENT_CORNER_BR:
        if (!tasks->horizontal)
          {
             tasks->horizontal = 1;
             e_box_orientation_set(tasks->o_items, tasks->horizontal);
             _tasks_refill(tasks);
          }
        break;

      case E_GADCON_ORIENT_VERT:
      case E_GADCON_ORIENT_LEFT:
      case E_GADCON_ORIENT_RIGHT:
      case E_GADCON_ORIENT_CORNER_LT:
      case E_GADCON_ORIENT_CORNER_RT:
      case E_GADCON_ORIENT_CORNER_LB:
      case E_GADCON_ORIENT_CORNER_RB:
        if (tasks->horizontal)
          {
             tasks->horizontal = 0;
             e_box_orientation_set(tasks->o_items, tasks->horizontal);
             _tasks_refill(tasks);
          }
        break;

      default:
        break;
     }
   e_box_align_set(tasks->o_items, 0.5, 0.5);
}

static const char *
_gc_label(const E_Gadcon_Client_Class *client_class __UNUSED__)
{
   return _("Tasks");
}

static Evas_Object *
_gc_icon(const E_Gadcon_Client_Class *client_class __UNUSED__, Evas *evas)
{
   Evas_Object *o;
   char buf[4096];

   o = edje_object_add(evas);
   snprintf(buf, sizeof(buf), "%s/e-module-tasks.edj",
            e_module_dir_get(tasks_config->module));
   edje_object_file_set(o, buf, "icon");
   return o;
}

static const char *
_gc_id_new(const E_Gadcon_Client_Class *client_class __UNUSED__)
{
   Config_Item *config;

   config = _tasks_config_item_get(NULL);
   return config->id;
}

/***************************************************************************/

static Tasks *
_tasks_new(Evas *evas, E_Zone *zone, const char *id)
{
   Tasks *tasks;

   tasks = E_NEW(Tasks, 1);
   tasks->config = _tasks_config_item_get(id);
   tasks->o_items = e_box_add(evas);
   tasks->horizontal = 1;

   e_box_homogenous_set(tasks->o_items, 1);
   e_box_orientation_set(tasks->o_items, tasks->horizontal);
   e_box_align_set(tasks->o_items, 0.5, 0.5);
   tasks->zone = zone;
   return tasks;
}

static void
_tasks_free(Tasks *tasks)
{
   Tasks_Item *item;
   EINA_LIST_FREE(tasks->items, item)
     _tasks_item_free(item);
   evas_object_del(tasks->o_items);
   free(tasks);
}

static void
_tasks_refill(Tasks *tasks)
{
   Eina_List *l;
   E_Border *border;
   Tasks_Item *item;
   Evas_Coord w, h;

   while (tasks->items)
     {
        item = tasks->items->data;
        _tasks_item_remove(item);
     }
   EINA_LIST_FOREACH(tasks_config->borders, l, border)
     {
        _tasks_item_check_add(tasks, border);
     }
   if (tasks->items)
     {
        item = tasks->items->data;
        edje_object_size_min_calc(item->o_item, &w, &h);
        if (tasks->horizontal)
          {
             if (w < tasks->config->minw) w = tasks->config->minw;
          }
        else
          {
             if (h < tasks->config->minh) h = tasks->config->minh;
          }
        if (!tasks->gcc->resizable)
          {
             if (tasks->horizontal)
               e_gadcon_client_min_size_set(tasks->gcc,
                                            w * eina_list_count(tasks->items),
                                            h);
             else
               e_gadcon_client_min_size_set(tasks->gcc,
                                            w,
                                            h * eina_list_count(tasks->items));
          }
     }
   else
     e_gadcon_client_min_size_set(tasks->gcc, 0, 0);
}

static void
_tasks_refill_all(void)
{
   const Eina_List *l;
   Tasks *tasks;

   EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
     {
        _tasks_refill(tasks);
     }
}

static void
_tasks_refill_border(E_Border *border)
{
   const Eina_List *l;
   Tasks *tasks;
   Eina_Bool found = EINA_FALSE;

   EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
     {
        const Eina_List *m;
        Tasks_Item *item;
        EINA_LIST_FOREACH(tasks->items, m, item)
          {
             if (item->border == border)
               {
                  _tasks_item_refill(item);
                  found = EINA_TRUE;
                  break;
               }
          }
     }
   if (!found) _tasks_refill_all();
}

static void
_tasks_signal_emit(E_Border *border, char *sig, char *src)
{
   const Eina_List *l;
   Tasks *tasks;

   EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
     {
        const Eina_List *m;
        Tasks_Item *item;

        EINA_LIST_FOREACH(tasks->items, m, item)
          {
             if (item->border == border)
               _tasks_item_signal_emit(item, sig, src);
          }
     }
}

static Tasks_Item *
_tasks_item_find(Tasks *tasks, E_Border *border)
{
   const Eina_List *l;
   Tasks_Item *item;

   EINA_LIST_FOREACH(tasks->items, l, item)
     {
        if (item->border == border) return item;
     }
   return NULL;
}

static Tasks_Item *
_tasks_item_new(Tasks *tasks, E_Border *border)
{
   Tasks_Item *item;

   item = E_NEW(Tasks_Item, 1);
   e_object_ref(E_OBJECT(border));
   item->tasks = tasks;
   item->border = border;
   item->skip_taskbar = border->client.netwm.state.skip_taskbar;
   item->o_item = edje_object_add(evas_object_evas_get(tasks->o_items));
   if (tasks->horizontal)
     e_theme_edje_object_set(item->o_item,
                             "base/theme/modules/tasks",
                             "e/modules/tasks/item");
   else
     {
        if (!e_theme_edje_object_set(item->o_item,
                                     "base/theme/modules/tasks",
                                     "e/modules/tasks/item_vert"))
          e_theme_edje_object_set(item->o_item,
                                  "base/theme/modules/tasks",
                                  "e/modules/tasks/item");
     }
   evas_object_event_callback_add(item->o_item, EVAS_CALLBACK_MOUSE_DOWN,
                                  _tasks_cb_item_mouse_down, item);
   evas_object_event_callback_add(item->o_item, EVAS_CALLBACK_MOUSE_UP,
                                  _tasks_cb_item_mouse_up, item);
   evas_object_event_callback_add(item->o_item, EVAS_CALLBACK_MOUSE_WHEEL,
                                  _tasks_cb_item_mouse_wheel, item);
   evas_object_show(item->o_item);

   _tasks_item_fill(item);
   return item;
}

static int
_tasks_item_check_add(Tasks *tasks, E_Border *border)
{
   if (border->user_skip_winlist) return 1;
   if (border->client.netwm.state.skip_taskbar) return 1;
   if (_tasks_item_find(tasks, border)) return 1;
   if (!tasks->config) return 1;
   if (!(tasks->config->show_all))
     {
        if (border->zone != tasks->zone) return 1;
        if ((border->desk != e_desk_current_get(border->zone)) &&
            (!border->sticky))
          return 1;
     }
   _tasks_item_add(tasks, border);
   return 0;
}

static void
_tasks_item_add(Tasks *tasks, E_Border *border)
{
   Tasks_Item *item;

   item = _tasks_item_new(tasks, border);
   e_box_pack_end(tasks->o_items, item->o_item);
   e_box_pack_options_set(item->o_item,
                          1, 1, /* fill */
                          1, 1, /* expand */
                          0.5, 0.5, /* align */
                          1, 1, /* min */
                          9999, 9999 /* max */
                          );
   tasks->items = eina_list_append(tasks->items, item);
}

static void
_tasks_item_remove(Tasks_Item *item)
{
   item->tasks->items = eina_list_remove(item->tasks->items, item);
   e_box_unpack(item->o_item);
   _tasks_item_free(item);
}

static void
_tasks_item_free(Tasks_Item *item)
{
   if (item->o_icon) evas_object_del(item->o_icon);
   e_object_unref(E_OBJECT(item->border));
   evas_object_del(item->o_item);
   free(item);
}

static void
_tasks_item_refill(Tasks_Item *item)
{
   if (item->border->client.netwm.state.skip_taskbar != item->skip_taskbar)
     {
        _tasks_refill(item->tasks);
        return;
     }
   if (item->o_icon) evas_object_del(item->o_icon);
   _tasks_item_fill(item);
}

static void
_tasks_item_fill(Tasks_Item *item)
{
{'fraction_non_alphanumeric': 0.1221380447848816, 'fraction_numerical': 0.003298761566632188, 'mean_word_length': 3.111251580278129, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 306, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2338466', 'n_tokens_mistral': 12883, 'n_tokens_neox': 12558, 'n_words': 2284}