enlightenment/src/modules/tasks/e_mod_main.c

1325 lines
39 KiB
C

#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
E_Comp_Object_Mover *iconify_provider;
Evas_Object *o_items; // Table of items
Eina_List *items; // List of items
Eina_List *clients; // List of clients
E_Zone *zone; // Current Zone
Config_Item *config; // Configuration
int horizontal;
};
struct _Tasks_Item
{
Tasks *tasks; // Parent tasks
E_Client *client; // The client this item points to
Evas_Object *o_item; // The edje theme object
Evas_Object *o_icon; // The icon
Evas_Object *o_preview; // The preview
Ecore_Timer *timer; // The preview timer
Eina_Bool skip_taskbar E_BITFIELD;
Eina_Bool focused E_BITFIELD;
Eina_Bool urgent E_BITFIELD;
Eina_Bool iconified E_BITFIELD;
Eina_Bool iconifying E_BITFIELD;
Eina_Bool delete_me E_BITFIELD;
};
static Tasks *_tasks_new(Evas *e, 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_Client *ec);
static Tasks_Item *_tasks_item_find(Tasks *tasks, E_Client *ec);
static Tasks_Item *_tasks_item_new(Tasks *tasks, E_Client *ec);
static Tasks_Item *_tasks_all_item_find(E_Client *ec);
static int _tasks_item_check_add(Tasks *tasks, E_Client *ec);
static void _tasks_item_add(Tasks *tasks, E_Client *ec);
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 void _tasks_item_preview_add(Tasks_Item *item);
static void _tasks_item_preview_del(Tasks_Item *item);
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 EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _tasks_cb_item_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _tasks_cb_item_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _tasks_cb_item_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static Eina_Bool _tasks_cb_event_client_add(void *data, int type, void *event);
static Eina_Bool _tasks_cb_event_client_remove(void *data, int type, void *event);
static Eina_Bool _tasks_cb_event_client_iconify(void *data, int type, void *event);
static Eina_Bool _tasks_cb_event_client_uniconify(void *data, int type, void *event);
static Eina_Bool _tasks_cb_event_client_prop_change(void *data, int type, void *event);
static Eina_Bool _tasks_cb_event_client_zone_set(void *data, int type, void *event);
static Eina_Bool _tasks_cb_event_client_desk_set(void *data, int type, E_Event_Client *ev);
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_desk_show(void *data, int type, void *event);
static Eina_Bool _tasks_cb_timer_del(void *data);
static E_Config_DD *conf_edd = NULL;
static E_Config_DD *conf_item_edd = NULL;
static Ecore_Timer *task_refill_timer;
Config *tasks_config = NULL;
/* module setup */
E_API E_Module_Api e_modapi =
{
E_MODULE_API_VERSION,
"Tasks"
};
E_API 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_desktops, INT);
E_CONFIG_VAL(D, T, show_all_screens, INT);
E_CONFIG_VAL(D, T, minw, INT);
E_CONFIG_VAL(D, T, minh, INT);
E_CONFIG_VAL(D, T, preview_size, INT);
E_CONFIG_VAL(D, T, icon_only, UCHAR);
E_CONFIG_VAL(D, T, text_only, UCHAR);
E_CONFIG_VAL(D, T, preview, 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_desktops = 0;
config->show_all_screens = 0;
config->minw = 100;
config->minh = 32;
config->preview = 0;
config->preview_size = 240;
tasks_config->items = eina_list_append(tasks_config->items, config);
}
tasks_config->module = m;
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_ADD, _tasks_cb_event_client_add, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_REMOVE, _tasks_cb_event_client_remove, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_ICONIFY, _tasks_cb_event_client_iconify, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_UNICONIFY, _tasks_cb_event_client_uniconify, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_PROPERTY, _tasks_cb_event_client_prop_change, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_DESK_SET, _tasks_cb_event_client_desk_set, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_ZONE_SET, _tasks_cb_event_client_zone_set, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_FOCUS_IN, _tasks_cb_window_focus_in, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_CLIENT_FOCUS_OUT, _tasks_cb_window_focus_out, NULL);
E_LIST_HANDLER_APPEND(tasks_config->handlers, E_EVENT_DESK_SHOW, _tasks_cb_event_desk_show, NULL);
e_gadcon_provider_register(&_gadcon_class);
return m;
}
E_API int
e_modapi_shutdown(E_Module *m EINA_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);
}
free(tasks_config);
tasks_config = NULL;
E_CONFIG_DD_FREE(conf_item_edd);
E_CONFIG_DD_FREE(conf_edd);
return 1;
}
E_API int
e_modapi_save(E_Module *m EINA_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)
{
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, style, 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;
elm_box_horizontal_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;
elm_box_horizontal_set(tasks->o_items, tasks->horizontal);
_tasks_refill(tasks);
}
break;
default:
break;
}
elm_box_align_set(tasks->o_items, 0.5, 0.5);
}
static const char *
_gc_label(const E_Gadcon_Client_Class *client_class EINA_UNUSED)
{
return _("Tasks");
}
static Evas_Object *
_gc_icon(const E_Gadcon_Client_Class *client_class EINA_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 EINA_UNUSED)
{
Config_Item *config;
config = _tasks_config_item_get(NULL);
return config->id;
}
/***************************************************************************/
static void
_tasks_cb_iconify_end_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
Tasks_Item *item;
E_Client *ec = data;
if (!ec) return;
evas_object_layer_set(ec->frame, ec->layer);
ec->layer_block = 0;
if (ec->iconic) evas_object_hide(ec->frame);
item = _tasks_all_item_find(ec);
if (!item) return;
item->iconifying = 0;
if (item->delete_me) free(item);
}
static Eina_Bool
_tasks_cb_iconify_provider(void *data, Evas_Object *obj, const char *signal)
{
Tasks *tasks = data;
Tasks_Item *item;
Evas_Coord ox, oy, ow, oh;
Eina_List *l;
E_Client *ec;
ec = e_comp_object_client_get(obj);
if (ec->zone != tasks->gcc->gadcon->zone) return EINA_FALSE;
EINA_LIST_FOREACH(tasks->items, l, item)
{
E_Client *ec2;
ec2 = e_client_stack_bottom_get(item->client);
for (; ec2; ec2 = ec2->stack.next)
{
if ((ec2 == ec) && (!item->iconifying))
{
evas_object_geometry_get(item->o_item, &ox, &oy, &ow, &oh);
ec->layer_block = 1;
evas_object_layer_set(ec->frame, E_LAYER_CLIENT_PRIO);
e_comp_object_effect_set(ec->frame, "iconify/tasks");
e_comp_object_effect_params_set(ec->frame, 1, (int[]){ec->x, ec->y, ec->w, ec->h, ox, oy, ow, oh}, 8);
e_comp_object_effect_params_set(ec->frame, 0, (int[]){!!strcmp(signal, "e,action,iconify")}, 1);
item->iconifying = 1;
e_comp_object_effect_start(ec->frame, _tasks_cb_iconify_end_cb, ec);
return EINA_TRUE;
}
}
}
return EINA_FALSE;
}
static void
_taks_client_remove(E_Client *ec)
{
Tasks *tasks;
Eina_List *l;
if (!tasks_config) return;
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
tasks->clients = eina_list_remove(tasks->clients, ec);
}
_tasks_refill_all();
}
static void
_tasks_cb_client_del(void *data EINA_UNUSED, void *obj)
{
_taks_client_remove(obj);
}
static Tasks *
_tasks_new(Evas *e, E_Zone *zone, const char *id)
{
Tasks *tasks;
Eina_List *l;
E_Client *ec;
tasks = E_NEW(Tasks, 1);
tasks->config = _tasks_config_item_get(id);
tasks->o_items = elm_box_add(e_win_evas_win_get(e));
E_EXPAND(tasks->o_items);
E_FILL(tasks->o_items);
tasks->horizontal = 1;
EINA_LIST_FOREACH(e_comp->clients, l, ec)
{
if ((!e_client_util_ignored_get(ec)) && (!e_object_is_del(E_OBJECT(ec))) &&
(!e_client_util_is_popup(ec)))
{
e_object_delfn_add(E_OBJECT(ec), _tasks_cb_client_del, NULL);
tasks->clients = eina_list_append(tasks->clients, ec);
}
}
elm_box_homogeneous_set(tasks->o_items, 1);
elm_box_horizontal_set(tasks->o_items, tasks->horizontal);
elm_box_align_set(tasks->o_items, 0.5, 0.5);
tasks->zone = zone;
tasks->iconify_provider = e_comp_object_effect_mover_add(90, "e,action,*iconify", _tasks_cb_iconify_provider, tasks);
return tasks;
}
static void
_tasks_free(Tasks *tasks)
{
Tasks_Item *item;
e_comp_object_effect_mover_del(tasks->iconify_provider);
EINA_LIST_FREE(tasks->items, item)
_tasks_item_free(item);
tasks->clients = eina_list_free(tasks->clients);
evas_object_del(tasks->o_items);
free(tasks);
}
static void
_tasks_refill(Tasks *tasks)
{
Eina_List *l;
E_Client *ec;
Tasks_Item *item;
Evas_Coord w, h, tw, th;
while (tasks->items)
{
item = tasks->items->data;
_tasks_item_remove(item);
}
EINA_LIST_FOREACH(tasks->clients, l, ec)
{
_tasks_item_check_add(tasks, ec);
}
if (tasks->items)
{
item = tasks->items->data;
evas_object_geometry_get(tasks->o_items, NULL, NULL, &tw, &th);
// edje_object_size_min_calc(item->o_item, &w, &h);
if (tasks->horizontal)
edje_object_size_min_restricted_calc(item->o_item, &w, &h, 0, th);
else
edje_object_size_min_restricted_calc(item->o_item, &w, &h, tw, 0);
if (tasks->horizontal)
{
if (w < tasks->config->minw) w = tasks->config->minw;
if (tasks->config->icon_only) w = h;
}
else
{
if (h < tasks->config->minh) h = tasks->config->minh;
if (tasks->config->icon_only) h = w;
}
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));
}
if (tasks->horizontal)
{
EINA_LIST_FOREACH(tasks->items, l, item)
{
evas_object_size_hint_min_set(item->o_item, w, th);
}
}
else
{
EINA_LIST_FOREACH(tasks->items, l, item)
{
evas_object_size_hint_min_set(item->o_item, tw, h);
}
}
}
else
e_gadcon_client_min_size_set(tasks->gcc, 0, 0);
}
static Eina_Bool
_refill_timer(void *d EINA_UNUSED)
{
if (e_drag_current_get()) return EINA_TRUE;
_tasks_refill_all();
task_refill_timer = NULL;
return EINA_FALSE;
}
static void
_tasks_refill_all(void)
{
const Eina_List *l;
Tasks *tasks;
if (e_drag_current_get())
{
if (task_refill_timer)
ecore_timer_loop_reset(task_refill_timer);
else
task_refill_timer = ecore_timer_loop_add(0.5, _refill_timer, NULL);
return;
}
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
_tasks_refill(tasks);
}
}
static void
_tasks_refill_border(E_Client *ec)
{
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)
{
E_Client *ec2;
ec2 = e_client_stack_bottom_get(item->client);
for (; ec2; ec2 = ec2->stack.next)
{
if (ec2 == ec)
{
_tasks_item_refill(item);
found = EINA_TRUE;
goto done;
}
}
}
}
done:
if (!found) _tasks_refill_all();
}
static Tasks_Item *
_tasks_item_find(Tasks *tasks, E_Client *ec)
{
const Eina_List *l;
Tasks_Item *item;
EINA_LIST_FOREACH(tasks->items, l, item)
{
E_Client *ec2;
ec2 = e_client_stack_bottom_get(item->client);
for (; ec2; ec2 = ec2->stack.next)
{
if (ec2 == ec) return item;
}
}
return NULL;
}
static Tasks_Item *
_tasks_all_item_find(E_Client *ec)
{
const Eina_List *l;
Tasks *tasks;
Tasks_Item *item = NULL;
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
item = _tasks_item_find(tasks, ec);
if (item) break;
}
return item;
}
static Tasks_Item *
_tasks_item_new(Tasks *tasks, E_Client *ec)
{
Tasks_Item *item;
item = E_NEW(Tasks_Item, 1);
e_object_ref(E_OBJECT(ec));
item->tasks = tasks;
item->client = ec;
item->skip_taskbar = ec->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");
}
if (tasks->config->text_only)
{
edje_object_signal_emit(item->o_item, "e,state,text_only", "e");
edje_object_message_signal_process(item->o_item);
}
else if (tasks->config->icon_only)
{
edje_object_signal_emit(item->o_item, "e,state,icon_only", "e");
edje_object_message_signal_process(item->o_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_event_callback_add(item->o_item, EVAS_CALLBACK_MOUSE_IN,
_tasks_cb_item_mouse_in, item);
evas_object_event_callback_add(item->o_item, EVAS_CALLBACK_MOUSE_OUT,
_tasks_cb_item_mouse_out, item);
evas_object_event_callback_add(item->o_item, EVAS_CALLBACK_DEL,
_tasks_cb_item_del, item);
evas_object_show(item->o_item);
_tasks_item_fill(item);
return item;
}
static int
_tasks_item_check_add(Tasks *tasks, E_Client *ec)
{
if (ec->user_skip_winlist) return 1;
if (ec->netwm.state.skip_taskbar) return 1;
if (ec->stack.prev) return 1;
if (_tasks_item_find(tasks, ec)) return 1;
if (!tasks->config) return 1;
if (!(tasks->config->show_all_desktops))
{
if ((ec->desk != e_desk_current_get(ec->zone)) &&
(!ec->sticky))
return 1;
}
if (!(tasks->config->show_all_screens))
{
if (ec->zone != tasks->zone) return 1;
}
_tasks_item_add(tasks, ec);
return 0;
}
static void
_tasks_item_add(Tasks *tasks, E_Client *ec)
{
Tasks_Item *item;
item = _tasks_item_new(tasks, ec);
E_EXPAND(item->o_item);
E_FILL(item->o_item);
elm_box_pack_end(tasks->o_items, item->o_item);
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);
elm_box_unpack(item->tasks->o_items, item->o_item);
_tasks_item_free(item);
}
static void
_tasks_item_preview_del(Tasks_Item *item)
{
_tasks_cb_timer_del(item);
}
static void
_tasks_item_free(Tasks_Item *item)
{
if (item->o_icon)
{
evas_object_del(item->o_icon);
item->o_icon = NULL;
}
if (e_object_is_del(E_OBJECT(item->client)))
item->tasks->clients = eina_list_remove(item->tasks->clients, item->client);
e_object_unref(E_OBJECT(item->client));
_tasks_item_preview_del(item);
if (item->o_item)
{
evas_object_del(item->o_item);
item->o_item = NULL;
}
item->client = NULL;
item->tasks = NULL;
if (item->iconifying)
item->delete_me = EINA_TRUE;
else
free(item);
}
static void
_tasks_item_refill(Tasks_Item *item)
{
if (item->client->netwm.state.skip_taskbar != item->skip_taskbar)
{
_tasks_refill(item->tasks);
return;
}
if (item->o_icon)
{
evas_object_del(item->o_icon);
item->o_icon = NULL;
}
_tasks_item_fill(item);
}
static void
_tasks_focused_eval(Tasks_Item *item)
{
if (!item) return;
if (e_client_stack_focused_get(item->client) != item->focused)
{
item->focused = e_client_stack_focused_get(item->client);
if (item->focused)
_tasks_item_signal_emit(item, "e,state,focused", "e");
else
_tasks_item_signal_emit(item, "e,state,unfocused", "e");
}
}
static void
_tasks_iconified_eval(Tasks_Item *item)
{
if (!item) return;
if (e_client_stack_iconified_get(item->client) != item->iconified)
{
item->iconified = e_client_stack_iconified_get(item->client);
if (item->iconified)
_tasks_item_signal_emit(item, "e,state,iconified", "e");
else
_tasks_item_signal_emit(item, "e,state,uniconified", "e");
}
}
static void
_tasks_urgent_eval(Tasks_Item *item)
{
if (!item) return;
if (e_client_stack_urgent_get(item->client) != item->urgent)
{
item->urgent = e_client_stack_urgent_get(item->client);
if (item->urgent)
_tasks_item_signal_emit(item, "e,state,urgent", "e");
else
_tasks_item_signal_emit(item, "e,state,not_urgent", "e");
}
}
static void
_tasks_item_fill(Tasks_Item *item)
{
const char *label;
E_Client *ec;
ec = item->client;
if (!item->tasks->config->text_only)
{
item->o_icon = e_client_icon_add(ec, evas_object_evas_get(item->tasks->o_items));
edje_object_part_swallow(item->o_item, "e.swallow.icon", item->o_icon);
evas_object_pass_events_set(item->o_icon, 1);
evas_object_show(item->o_icon);
}
ec = e_client_stack_active_adjust(ec);
if (item->tasks->config->icon_only) label = "";
else label = e_client_util_name_get(ec);
edje_object_part_text_set(item->o_item, "e.text.label", label);
_tasks_iconified_eval(item);
_tasks_focused_eval(item);
_tasks_urgent_eval(item);
}
static void
_tasks_item_signal_emit(Tasks_Item *item, char *sig, char *src)
{
if (item->o_item) edje_object_signal_emit(item->o_item, sig, src);
if (item->o_icon && e_icon_edje_get(item->o_icon))
e_icon_edje_emit(item->o_icon, sig, src);
}
static Config_Item *
_tasks_config_item_get(const char *id)
{
Eina_List *l;
Config_Item *config;
char buf[128];
if (!id)
{
int num = 0;
/* Create id */
if (tasks_config->items)
{
const char *p;
config = eina_list_last(tasks_config->items)->data;
p = strrchr(config->id, '.');
if (p) num = atoi(p + 1) + 1;
}
snprintf(buf, sizeof(buf), "%s.%d", _gadcon_class.name, num);
id = buf;
}
else
{
EINA_LIST_FOREACH(tasks_config->items, l, config)
{
if (!config->id) continue;
if (!strcmp(config->id, id)) return config;
}
}
config = E_NEW(Config_Item, 1);
config->id = eina_stringshare_add(id);
config->show_all_desktops = 0;
config->show_all_screens = 0;
config->minw = 100;
config->minh = 32;
tasks_config->items = eina_list_append(tasks_config->items, config);
return config;
}
void
_tasks_config_updated(Config_Item *config)
{
const Eina_List *l;
Tasks *tasks;
if (!tasks_config) return;
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
if (tasks->config == config) _tasks_refill(tasks);
}
}
static void
_tasks_cb_menu_configure(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED)
{
Tasks *tasks;
tasks = (Tasks *)data;
_config_tasks_module(tasks->config);
}
static void
_tasks_cb_item_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Tasks_Item *item = data;
_tasks_item_preview_del(item);
}
static void
_tasks_cb_item_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Event_Mouse_Down *ev;
Tasks_Item *item;
item = (Tasks_Item *)data;
ev = event_info;
_tasks_item_preview_del(item);
if (ev->button == 3)
{
E_Menu *m;
E_Menu_Item *mi;
int cx, cy, cw, ch;
e_gadcon_canvas_zone_geometry_get(item->tasks->gcc->gadcon, &cx, &cy, &cw, &ch);
e_int_client_menu_create(item->client);
mi = e_menu_item_new(item->client->border_menu);
e_menu_item_separator_set(mi, 1);
m = e_menu_new();
mi = e_menu_item_new(m);
e_menu_item_label_set(mi, _("Settings"));
e_util_menu_item_theme_icon_set(mi, "preferences-system");
e_menu_item_callback_set(mi, _tasks_cb_menu_configure, item->tasks);
m = e_gadcon_client_util_menu_items_append(item->tasks->gcc, m, 0);
mi = e_menu_item_new(item->client->border_menu);
e_menu_item_label_set(mi, _("Tasks"));
e_menu_item_submenu_set(mi, m);
e_object_unref(E_OBJECT(m));
e_util_menu_item_theme_icon_set(mi, "preferences-system");
e_gadcon_client_menu_set(item->tasks->gcc, item->client->border_menu);
e_menu_activate_mouse(item->client->border_menu,
e_zone_current_get(),
cx + ev->output.x, cy + ev->output.y, 1, 1,
E_MENU_POP_DIRECTION_DOWN, ev->timestamp);
evas_event_feed_mouse_up(item->tasks->gcc->gadcon->evas, ev->button,
EVAS_BUTTON_NONE, ev->timestamp, NULL);
/* gadcon menu post cb won't remove this so we'll do it now to prevent problems later */
item->client->border_menu = NULL;
}
}
static Eina_Bool
_tasks_cb_timer_del(void *data)
{
Tasks_Item *item = data;
if (item->o_preview)
evas_object_del(item->o_preview);
if (item->timer)
ecore_timer_del(item->timer);
item->timer = item->o_preview = NULL;
return ECORE_CALLBACK_CANCEL;
}
static void
_tasks_item_preview_add(Tasks_Item *item)
{
E_Client *ec;
Evas_Object *o, *ot, *or, *img;
Evas_Coord ox, oy, ow, oh, size;
double n;
if (item->o_preview) _tasks_cb_timer_del(item);
evas_object_geometry_get(item->o_item, &ox, &oy, &ow, &oh);
item->o_preview = o = elm_ctxpopup_add(e_comp->elm);
evas_object_pass_events_set(o, EINA_TRUE);
elm_object_focus_allow_set(o, EINA_FALSE);
elm_object_tree_focus_allow_set(o, EINA_FALSE);
elm_object_style_set(o, "noblock");
evas_object_layer_set(o, E_LAYER_POPUP);
ot = elm_table_add(o);
evas_object_size_hint_align_set(ot, 0, 0);
elm_object_content_set(o, ot);
evas_object_show(ot);
ec = item->client;
img = e_comp_object_util_mirror_add(ec->frame);
evas_object_size_hint_aspect_set(img, EVAS_ASPECT_CONTROL_BOTH, ec->client.w, ec->client.h);
evas_object_show(img);
or = evas_object_rectangle_add(evas_object_evas_get(o));
size = item->tasks->config->preview_size;
if (ec->client.w > ec->client.h)
{
n = size * (1.0 / ec->client.w);
evas_object_size_hint_min_set(img, size, n * ec->client.h);
evas_object_size_hint_max_set(img, size, n * ec->client.h);
evas_object_size_hint_min_set(or, size + 1, (n * ec->client.h) + 1);
}
else
{
n = size * (1.0 / ec->client.h);
evas_object_size_hint_min_set(img, n * ec->client.w, size);
evas_object_size_hint_max_set(img, n * ec->client.w, size);
evas_object_size_hint_min_set(or, (n * ec->client.w) + 1, size + 1);
}
elm_table_pack(ot, or, 0, 0, 1, 1);
elm_table_pack(ot, img, 0, 0, 1, 1);
switch (item->tasks->gcc->gadcon->orient)
{
case E_GADCON_ORIENT_BOTTOM:
case E_GADCON_ORIENT_CORNER_BR:
case E_GADCON_ORIENT_CORNER_BL:
evas_object_move(o, ox + (ow / 2), oy);
elm_ctxpopup_direction_priority_set(o, ELM_CTXPOPUP_DIRECTION_UP, ELM_CTXPOPUP_DIRECTION_DOWN,
ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_RIGHT);
break;
case E_GADCON_ORIENT_TOP:
case E_GADCON_ORIENT_CORNER_TL:
case E_GADCON_ORIENT_CORNER_TR:
evas_object_move(o, ox + (ow / 2), oy + oh);
elm_ctxpopup_direction_priority_set(o, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_UP,
ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_RIGHT);
break;
case E_GADCON_ORIENT_LEFT:
case E_GADCON_ORIENT_CORNER_LB:
case E_GADCON_ORIENT_CORNER_LT:
evas_object_move(o, ox + ow, oy + (oh / 2));
elm_ctxpopup_direction_priority_set(o, ELM_CTXPOPUP_DIRECTION_RIGHT, ELM_CTXPOPUP_DIRECTION_DOWN,
ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_UP);
break;
case E_GADCON_ORIENT_RIGHT:
case E_GADCON_ORIENT_CORNER_RB:
case E_GADCON_ORIENT_CORNER_RT:
evas_object_move(o, ox, oy + (oh / 2));
elm_ctxpopup_direction_priority_set(o, ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_DOWN,
ELM_CTXPOPUP_DIRECTION_RIGHT, ELM_CTXPOPUP_DIRECTION_UP);
break;
default:
evas_object_move(o, ox + (ow / 2), oy);
elm_ctxpopup_direction_priority_set(o, ELM_CTXPOPUP_DIRECTION_UP, ELM_CTXPOPUP_DIRECTION_DOWN,
ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_RIGHT);
break;
}
evas_object_pass_events_set(o, 1);
evas_object_show(o);
}
static void
_tasks_cb_item_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Tasks_Item *item = data;
Eina_Bool show;
if (!item->tasks->config->preview) return;
show = !item->iconifying;
if ((item->tasks->gcc->gadcon->shelf) &&
(item->tasks->gcc->gadcon->shelf->hide_animator))
show = 0;
if (show) _tasks_item_preview_add(item);
}
static void
_tasks_cb_item_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Tasks_Item *item = data;
if (item->o_preview)
{
elm_ctxpopup_dismiss(item->o_preview);
item->timer = ecore_timer_add(1.0, _tasks_cb_timer_del, item);
}
}
static void
_tasks_cb_item_mouse_wheel(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Event_Mouse_Wheel *ev;
Tasks_Item *item;
ev = event_info;
item = data;
if (ev->z < 0)
{
if (item->client->iconic)
e_client_uniconify(item->client);
else
evas_object_raise(item->client->frame);
evas_object_focus_set(item->client->frame, 1);
}
else if (ev->z > 0)
e_client_iconify(item->client);
}
static void
_tasks_cb_item_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Event_Mouse_Up *ev;
Tasks_Item *item;
ev = event_info;
item = data;
_tasks_item_preview_del(item);
if (ev->button == 1)
{
if (!item->client->sticky && item->tasks->config->show_all_desktops)
e_desk_show(item->client->desk);
if (evas_key_modifier_is_set(ev->modifiers, "Alt"))
{
if (item->client->iconic)
e_client_uniconify(item->client);
else
e_client_iconify(item->client);
}
else if (evas_key_modifier_is_set(ev->modifiers, "Control"))
{
if (item->client->maximized)
e_client_unmaximize(item->client, e_config->maximize_policy);
else
e_client_maximize(item->client, e_config->maximize_policy);
}
else if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
{
if (item->client->shaded)
e_client_unshade(item->client, item->client->shade_dir);
else
e_client_shade(item->client, item->client->shade_dir);
}
else if (evas_key_modifier_is_set(ev->modifiers, "Super"))
{
e_client_act_close_begin(item->client);
}
else if (!item->iconifying)
{
if (item->client->iconic)
{
e_client_uniconify(item->client);
evas_object_focus_set(item->client->frame, 1);
}
else
{
if (item->client->focused)
{
e_client_iconify(item->client);
}
else
{
evas_object_raise(item->client->frame);
evas_object_focus_set(item->client->frame, 1);
}
}
}
}
else if (ev->button == 2)
{
if (!item->client->sticky && item->tasks->config->show_all_desktops)
e_desk_show(item->client->desk);
evas_object_raise(item->client->frame);
evas_object_focus_set(item->client->frame, 1);
if (item->client->maximized)
e_client_unmaximize(item->client, e_config->maximize_policy);
else
e_client_maximize(item->client, e_config->maximize_policy);
}
}
/************ BORDER CALLBACKS *********************/
static Eina_Bool
_tasks_cb_event_client_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
E_Event_Client *ev = event;
Tasks *tasks;
Eina_List *l;
if (e_client_util_ignored_get(ev->ec) || e_object_is_del(E_OBJECT(ev->ec))) return ECORE_CALLBACK_RENEW;
if (e_client_util_is_popup(ev->ec)) return ECORE_CALLBACK_RENEW;
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
if ((!tasks->clients) || (!eina_list_data_find(tasks->clients, ev->ec)))
{
e_object_delfn_add(E_OBJECT(ev->ec), _tasks_cb_client_del, NULL);
tasks->clients = eina_list_append(tasks->clients, ev->ec);
}
}
_tasks_refill_all();
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_event_client_remove(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
E_Event_Client *ev = event;
_taks_client_remove(ev->ec);
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_event_client_iconify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
E_Event_Client *ev = event;
Eina_List *l;
Tasks *tasks;
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
_tasks_iconified_eval(_tasks_item_find(tasks, ev->ec));
}
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_event_client_uniconify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
E_Event_Client *ev = event;
Eina_List *l;
Tasks *tasks;
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
_tasks_iconified_eval(_tasks_item_find(tasks, ev->ec));
}
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_window_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
E_Event_Client *ev = event;
Eina_List *l;
Tasks *tasks;
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
_tasks_focused_eval(_tasks_item_find(tasks, ev->ec));
}
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_window_focus_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
E_Event_Client *ev = event;
Eina_List *l;
Tasks *tasks;
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
{
_tasks_focused_eval(_tasks_item_find(tasks, ev->ec));
}
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_event_client_prop_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
E_Event_Client_Property *ev = event;
Eina_List *l;
Tasks *tasks;
if ((ev->property & E_CLIENT_PROPERTY_URGENCY) == E_CLIENT_PROPERTY_URGENCY)
{
EINA_LIST_FOREACH(tasks_config->tasks, l, tasks)
_tasks_urgent_eval(_tasks_item_find(tasks, ev->ec));
}
else if (((ev->property & E_CLIENT_PROPERTY_TITLE) == E_CLIENT_PROPERTY_TITLE) ||
((ev->property & E_CLIENT_PROPERTY_ICON) == E_CLIENT_PROPERTY_ICON))
_tasks_refill_border(ev->ec);
else if (ev->property & E_CLIENT_PROPERTY_MISC)
_tasks_refill_all();
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_event_client_zone_set(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
{
_tasks_refill_all();
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_event_client_desk_set(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Client *ev)
{
if (!ev->ec->sticky)
_tasks_refill_all();
return EINA_TRUE;
}
static Eina_Bool
_tasks_cb_event_desk_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
{
_tasks_refill_all();
return EINA_TRUE;
}
/***************************************************************************/
/**/
/**/
/***************************************************************************/