forked from enlightenment/enlightenment
see http://e18releasemanager.wordpress.com/2013/06/14/why/ for more infodevs/sachiel/e19
parent
c00785634a
commit
f4a327a0ca
15 changed files with 1906 additions and 11 deletions
@ -0,0 +1,19 @@ |
||||
teamworkdir = $(MDIR)/teamwork |
||||
teamwork_DATA = teamwork/e-module-teamwork.edj \ |
||||
teamwork/module.desktop |
||||
|
||||
EXTRA_DIST += $(teamwork_DATA) |
||||
|
||||
teamworkpkgdir = $(MDIR)/teamwork/$(MODULE_ARCH) |
||||
teamworkpkg_LTLIBRARIES = teamwork/module.la |
||||
|
||||
teamwork_module_la_SOURCES = teamwork/e_mod_main.c \ |
||||
teamwork/e_mod_config.c \ |
||||
teamwork/e_mod_main.h \ |
||||
teamwork/e_mod_tw.c \ |
||||
teamwork/sha1.c \ |
||||
teamwork/sha1.h |
||||
|
||||
.PHONY: teamwork install-teamwork |
||||
teamwork: $(teamworkpkg_LTLIBRARIES) $(teamwork_DATA) |
||||
install-teamwork: install-teamworkDATA install-teamworkpkgLTLIBRARIES |
Binary file not shown.
@ -0,0 +1,157 @@ |
||||
#include "e_mod_main.h" |
||||
|
||||
struct _E_Config_Dialog_Data |
||||
{ |
||||
int disable_media_fetch; |
||||
double allowed_media_size; |
||||
double allowed_media_age; |
||||
|
||||
double mouse_out_delay; |
||||
double popup_size; |
||||
double popup_opacity; |
||||
}; |
||||
|
||||
static void * |
||||
_create_data(E_Config_Dialog *cfd EINA_UNUSED) |
||||
{ |
||||
E_Config_Dialog_Data *cfdata; |
||||
|
||||
cfdata = E_NEW(E_Config_Dialog_Data, 1); |
||||
#define SET(X) \ |
||||
cfdata->X = tw_config->X |
||||
SET(disable_media_fetch); |
||||
SET(allowed_media_size); |
||||
SET(allowed_media_age); |
||||
|
||||
SET(mouse_out_delay); |
||||
SET(popup_size); |
||||
SET(popup_opacity); |
||||
#undef SET |
||||
return cfdata; |
||||
} |
||||
|
||||
static void |
||||
_free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) |
||||
{ |
||||
tw_mod->cfd = NULL; |
||||
free(cfdata); |
||||
} |
||||
|
||||
static int |
||||
_basic_check_changed(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) |
||||
{ |
||||
#define CHECK(X) \ |
||||
if (cfdata->X != tw_config->X) return 1 |
||||
|
||||
CHECK(disable_media_fetch); |
||||
if (lround(cfdata->allowed_media_age) != tw_config->allowed_media_age) return 1; |
||||
if (lround(cfdata->allowed_media_size) != tw_config->allowed_media_size) return 1; |
||||
|
||||
if (fabs(cfdata->mouse_out_delay - tw_config->allowed_media_size) > 0.45) return 1; |
||||
|
||||
if (fabs(cfdata->popup_size - tw_config->popup_size) > 0.9) return 1; |
||||
if (fabs(cfdata->popup_opacity - tw_config->popup_opacity) > 0.9) return 1; |
||||
|
||||
#undef CHECK |
||||
return 0; |
||||
} |
||||
|
||||
static Evas_Object * |
||||
_basic_create_widgets(E_Config_Dialog *cfd EINA_UNUSED, |
||||
Evas *evas, |
||||
E_Config_Dialog_Data *cfdata) |
||||
{ |
||||
Evas_Object *ob, *ol, *otb, *tab; |
||||
|
||||
tab = e_widget_table_add(evas, 0); |
||||
|
||||
otb = e_widget_toolbook_add(evas, 48 * e_scale, 48 * e_scale); |
||||
|
||||
///////////////////////////////////////////
|
||||
|
||||
ol = e_widget_list_add(evas, 0, 0); |
||||
|
||||
ob = e_widget_check_add(evas, _("Disable remote media fetching"), &cfdata->disable_media_fetch); |
||||
e_widget_list_object_append(ol, ob, 1, 0, 0.5); |
||||
|
||||
ob = e_widget_label_add(evas, _("Maximum media cache size in RAM")); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
ob = e_widget_slider_add(evas, 1, 0, _("%4.0f MiB"), 0, 1024, 16, 0, &cfdata->allowed_media_size, NULL, 150); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
ob = e_widget_label_add(evas, _("Maximum media cache age on disk")); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
ob = e_widget_slider_add(evas, 1, 0, _("%3.0f Days"), -1, 180, 1, 0, &cfdata->allowed_media_age, NULL, 150); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
|
||||
e_widget_toolbook_page_append(otb, NULL, _("Cache"), ol, 1, 1, 1, 1, 0.5, 0.5); |
||||
|
||||
///////////////////////////////////////////
|
||||
|
||||
ol = e_widget_list_add(evas, 0, 0); |
||||
|
||||
ob = e_widget_label_add(evas, _("Mouse-out hide delay")); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
ob = e_widget_slider_add(evas, 1, 0, _("%1.1f seconds"), 0, 5, 0.5, 0, &cfdata->mouse_out_delay, NULL, 150); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
ob = e_widget_label_add(evas, _("Maximum size (Percentage of screens size)")); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
ob = e_widget_slider_add(evas, 1, 0, _("%3.0f"), 10, 100, 1, 0, &cfdata->popup_size, NULL, 150); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
ob = e_widget_label_add(evas, _("Opacity")); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
ob = e_widget_slider_add(evas, 1, 0, _("%3.0f"), 10, 100, 1, 0, &cfdata->popup_opacity, NULL, 150); |
||||
e_widget_list_object_append(ol, ob, 1, 1, 0.5); |
||||
|
||||
e_widget_toolbook_page_append(otb, NULL, _("Popups"), ol, 1, 1, 1, 1, 0.5, 0.5); |
||||
|
||||
e_widget_toolbook_page_show(otb, 0); |
||||
|
||||
e_widget_table_object_append(tab, otb, 0, 0, 1, 1, 1, 1, 1, 1); |
||||
return tab; |
||||
} |
||||
|
||||
|
||||
static int |
||||
_basic_apply_data(E_Config_Dialog *cfd EINA_UNUSED, |
||||
E_Config_Dialog_Data *cfdata) |
||||
{ |
||||
|
||||
#define SET(X) tw_config->X = cfdata->X |
||||
SET(disable_media_fetch); |
||||
SET(allowed_media_size); |
||||
SET(allowed_media_age); |
||||
|
||||
SET(mouse_out_delay); |
||||
SET(popup_size); |
||||
if (fabs(cfdata->popup_opacity - tw_config->popup_opacity) > 0.9) |
||||
{ |
||||
SET(popup_opacity); |
||||
tw_popup_opacity_set(); |
||||
} |
||||
|
||||
e_config_save_queue(); |
||||
return 1; |
||||
} |
||||
|
||||
EINTERN E_Config_Dialog * |
||||
e_int_config_teamwork_module(E_Container *con, const char *params EINA_UNUSED) |
||||
{ |
||||
E_Config_Dialog *cfd; |
||||
E_Config_Dialog_View *v; |
||||
char buf[4096]; |
||||
|
||||
if (tw_mod->cfd) return NULL; |
||||
snprintf(buf, sizeof(buf), "%s/e-module-teamwork.edj", e_module_dir_get(tw_mod->module)); |
||||
v = E_NEW(E_Config_Dialog_View, 1); |
||||
|
||||
v->create_cfdata = _create_data; |
||||
v->free_cfdata = _free_data; |
||||
v->basic.apply_cfdata = _basic_apply_data; |
||||
v->basic.create_widgets = _basic_create_widgets; |
||||
v->basic.check_changed = _basic_check_changed; |
||||
|
||||
cfd = e_config_dialog_new(con, _("Teamwork Settings"), |
||||
"E", "applications/teamwork", buf, 32, v, tw_mod); |
||||
tw_mod->cfd = cfd; |
||||
return cfd; |
||||
} |
@ -0,0 +1,207 @@ |
||||
#include "e_mod_main.h" |
||||
#include "sha1.h" |
||||
|
||||
EINTERN int _e_teamwork_log_dom = -1; |
||||
EINTERN Mod *tw_mod = NULL; |
||||
EINTERN Teamwork_Config *tw_config = NULL; |
||||
|
||||
EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Teamwork"}; |
||||
|
||||
static E_Config_DD *conf_edd = NULL; |
||||
|
||||
static E_Action *e_tw_toggle = NULL; |
||||
static const char _act_toggle[] = "tw_toggle"; |
||||
static const char _e_tw_name[] = N_("Teamwork"); |
||||
static const char _lbl_toggle[] = N_("Toggle Popup Visibility"); |
||||
|
||||
static const char * |
||||
_sha1_to_string(const unsigned char *hashout) |
||||
{ |
||||
const char hextab[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; |
||||
char sha1[41] = {0}; |
||||
unsigned int i = 0; |
||||
|
||||
for (i = 0; i < 20; i++) |
||||
{ |
||||
sha1[2 * i] = hextab[(hashout[i] >> 4) & 0x0f]; |
||||
sha1[2 * i + 1] = hextab[hashout[i] & 0x0f]; |
||||
} |
||||
return eina_stringshare_add(sha1); |
||||
} |
||||
|
||||
const char * |
||||
sha1_encode(const unsigned char *data, size_t len) |
||||
{ |
||||
SHA_CTX2 ctx; |
||||
unsigned char hashout[20]; |
||||
unsigned char *buf; |
||||
|
||||
if (EINA_UNLIKELY(len > 65000)) |
||||
buf = malloc(len); |
||||
else |
||||
buf = alloca(len); |
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL); |
||||
memcpy(buf, data, len); |
||||
|
||||
SHA1_Init2(&ctx); |
||||
SHA1_Update2(&ctx, buf, len); |
||||
SHA1_Final2(hashout, &ctx); |
||||
if (EINA_UNLIKELY(len > 65000)) free(buf); |
||||
return _sha1_to_string(hashout); |
||||
} |
||||
|
||||
//////////////////////////////
|
||||
static Teamwork_Config * |
||||
e_tw_config_new(void) |
||||
{ |
||||
Teamwork_Config *cf; |
||||
|
||||
cf = E_NEW(Teamwork_Config, 1); |
||||
cf->config_version = MOD_CONFIG_FILE_VERSION; |
||||
|
||||
cf->allowed_media_size = 10; // 10 megabytes
|
||||
cf->allowed_media_age = 3; // 3 days
|
||||
|
||||
cf->mouse_out_delay = 0.0; |
||||
cf->popup_size = 10.0; |
||||
cf->popup_opacity = 90.0; |
||||
|
||||
return cf; |
||||
} |
||||
|
||||
static E_Config_DD * |
||||
e_tw_config_dd_new(void) |
||||
{ |
||||
conf_edd = E_CONFIG_DD_NEW("Teamwork_Config", Teamwork_Config); |
||||
|
||||
#undef T |
||||
#undef D |
||||
#define T Teamwork_Config |
||||
#define D conf_edd |
||||
E_CONFIG_VAL(D, T, config_version, UINT); |
||||
E_CONFIG_VAL(D, T, disable_media_fetch, UCHAR); |
||||
E_CONFIG_VAL(D, T, allowed_media_size, LL); |
||||
E_CONFIG_VAL(D, T, allowed_media_age, INT); |
||||
|
||||
E_CONFIG_VAL(D, T, mouse_out_delay, DOUBLE); |
||||
E_CONFIG_VAL(D, T, popup_size, DOUBLE); |
||||
E_CONFIG_VAL(D, T, popup_opacity, DOUBLE); |
||||
return conf_edd; |
||||
} |
||||
//////////////////////////////
|
||||
static void |
||||
e_tw_act_toggle_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED) |
||||
{ |
||||
if (!tw_mod->pop) return; |
||||
if (tw_mod->sticky) |
||||
tw_hide(NULL); |
||||
tw_mod->sticky = !tw_mod->sticky; |
||||
} |
||||
//////////////////////////////
|
||||
EAPI void * |
||||
e_modapi_init(E_Module *m) |
||||
{ |
||||
char buf[PATH_MAX]; |
||||
E_Configure_Option *co; |
||||
|
||||
snprintf(buf, sizeof(buf), "%s/e-module-teamwork.edj", e_module_dir_get(m)); |
||||
e_configure_registry_category_add("applications", 20, _("Apps"), NULL, |
||||
"preferences-applications"); |
||||
e_configure_registry_item_add("applications/teamwork", 1, _("Teamwork"), NULL, |
||||
buf, e_int_config_teamwork_module); |
||||
|
||||
tw_mod = E_NEW(Mod, 1); |
||||
tw_mod->module = m; |
||||
m->data = tw_mod; |
||||
conf_edd = e_tw_config_dd_new(); |
||||
tw_config = e_config_domain_load("module.teamwork", conf_edd); |
||||
if (tw_config) |
||||
{ |
||||
if (!e_util_module_config_check(_("Teamwork"), tw_config->config_version, MOD_CONFIG_FILE_VERSION)) |
||||
E_FREE_FUNC(tw_config, free); |
||||
} |
||||
|
||||
if (tw_config) |
||||
{ |
||||
/* sanity checks */ |
||||
tw_config->mouse_out_delay = E_CLAMP(tw_config->mouse_out_delay, 0.0, 5.0); |
||||
tw_config->popup_size = E_CLAMP(tw_config->popup_size, 10.0, 100.0); |
||||
tw_config->popup_opacity = E_CLAMP(tw_config->popup_opacity, 10.0, 100.0); |
||||
} |
||||
else |
||||
tw_config = e_tw_config_new(); |
||||
tw_config->config_version = MOD_CONFIG_FILE_VERSION; |
||||
|
||||
_e_teamwork_log_dom = eina_log_domain_register("teamwork", EINA_COLOR_ORANGE); |
||||
eina_log_domain_level_set("teamwork", EINA_LOG_LEVEL_DBG); |
||||
|
||||
if (!e_tw_init()) |
||||
{ |
||||
e_modapi_shutdown(NULL); |
||||
return NULL; |
||||
} |
||||
e_tw_toggle = e_action_add(_act_toggle); |
||||
e_tw_toggle->func.go = e_tw_act_toggle_cb; |
||||
e_action_predef_name_set(_e_tw_name, _lbl_toggle, _act_toggle, NULL, NULL, 0); |
||||
|
||||
e_configure_option_domain_current_set("teamwork"); |
||||
|
||||
E_CONFIGURE_OPTION_ADD_CUSTOM(co, "teamwork-settings", _("Teamwork settings panel"), _("teamwork"), _("applications")); |
||||
co->info = eina_stringshare_add("applications/teamwork"); |
||||
E_CONFIGURE_OPTION_ICON(co, buf); |
||||
E_CONFIGURE_OPTION_ADD(co, BOOL, disable_media_fetch, tw_config, _("Disable Teamwork remote media fetching"), _("teamwork")); |
||||
E_CONFIGURE_OPTION_ADD(co, DOUBLE, allowed_media_size, tw_config, _("Maximum total size of Teamwork media to keep in RAM"), _("teamwork"), _("cache")); |
||||
E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 0, 1024, 16, _("%4.0f MiB")); |
||||
E_CONFIGURE_OPTION_HELP(co, _("This option determines how much memory will be used to cache recent media for faster loading.")); |
||||
E_CONFIGURE_OPTION_ADD(co, DOUBLE, allowed_media_age, tw_config, _("Maximum age for a disk-cached Teamwork media item"), _("teamwork"), _("cache")); |
||||
E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, -1, 180, 1, _("%3.0f Days")); |
||||
E_CONFIGURE_OPTION_HELP(co, _("This option determines how long media will remain in the disk cache before it is pruned.</ps>" |
||||
"Set to -1 to never delete media, or to 0 to never cache media on disk.")); |
||||
|
||||
E_CONFIGURE_OPTION_ADD(co, DOUBLE, mouse_out_delay, tw_config, _("Delay before closing a Teamwork popup on mouse-out"), _("teamwork"), _("mouse")); |
||||
E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 0, 5, 0.5, _("%1.1f seconds")); |
||||
E_CONFIGURE_OPTION_ADD(co, DOUBLE, popup_size, tw_config, _("Maximum percentage of screen to use for Teamwork popups"), _("teamwork"), _("screen")); |
||||
E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 10, 100, 1, _("%3.0f")); |
||||
E_CONFIGURE_OPTION_ADD(co, DOUBLE, popup_opacity, tw_config, _("Opacity to use for Teamwork popups"), _("teamwork")); |
||||
E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 10, 100, 1, _("%3.0f")); |
||||
co->funcs[0].none = tw_popup_opacity_set; |
||||
|
||||
e_configure_option_category_tag_add(_("applications"), _("teamwork")); |
||||
e_configure_option_category_tag_add(_("teamwork"), _("teamwork")); |
||||
e_configure_option_category_icon_set(_("teamwork"), buf); |
||||
|
||||
return m; |
||||
} |
||||
|
||||
EAPI int |
||||
e_modapi_shutdown(E_Module *m __UNUSED__) |
||||
{ |
||||
e_tw_shutdown(); |
||||
|
||||
E_CONFIG_DD_FREE(conf_edd); |
||||
eina_log_domain_unregister(_e_teamwork_log_dom); |
||||
_e_teamwork_log_dom = -1; |
||||
|
||||
e_configure_registry_item_del("applications/teamwork"); |
||||
e_configure_registry_category_del("applications"); |
||||
|
||||
e_configure_option_domain_clear("teamwork"); |
||||
e_configure_option_category_tag_del(_("teamwork"), _("teamwork")); |
||||
e_configure_option_category_tag_del(_("applications"), _("teamwork")); |
||||
|
||||
e_action_predef_name_del(_e_tw_name, _lbl_toggle); |
||||
e_action_del(_act_toggle); |
||||
e_tw_toggle = NULL; |
||||
|
||||
E_FREE(tw_config); |
||||
E_FREE(tw_mod); |
||||
return 1; |
||||
} |
||||
|
||||
EAPI int |
||||
e_modapi_save(E_Module *m __UNUSED__) |
||||
{ |
||||
e_config_domain_save("module.teamwork", conf_edd, tw_config); |
||||
return 1; |
||||
} |
||||
|
@ -0,0 +1,65 @@ |
||||
#ifndef E_MOD_MAIN_H |
||||
#define E_MOD_MAIN_H |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "e.h" |
||||
|
||||
/* Increment for Major Changes */ |
||||
#define MOD_CONFIG_FILE_EPOCH 1 |
||||
/* Increment for Minor Changes (ie: user doesn't need a new config) */ |
||||
#define MOD_CONFIG_FILE_GENERATION 0 |
||||
#define MOD_CONFIG_FILE_VERSION ((MOD_CONFIG_FILE_EPOCH * 1000000) + MOD_CONFIG_FILE_GENERATION) |
||||
|
||||
typedef struct Teamwork_Config |
||||
{ |
||||
unsigned int config_version; |
||||
|
||||
Eina_Bool disable_media_fetch; |
||||
long long int allowed_media_size; |
||||
int allowed_media_age; |
||||
|
||||
double mouse_out_delay; |
||||
double popup_size; |
||||
double popup_opacity; |
||||
} Teamwork_Config; |
||||
|
||||
typedef struct Mod |
||||
{ |
||||
E_Module *module; |
||||
E_Config_Dialog *cfd; |
||||
size_t media_size; |
||||
Eina_Inlist *media_list; |
||||
Eina_Hash *media; |
||||
E_Popup *pop; |
||||
Eina_Bool sticky : 1; |
||||
} Mod; |
||||
|
||||
extern Teamwork_Config *tw_config; |
||||
extern Mod *tw_mod; |
||||
extern int _e_teamwork_log_dom; |
||||
|
||||
EINTERN const char *sha1_encode(const unsigned char *data, size_t len); |
||||
|
||||
EINTERN int e_tw_init(void); |
||||
EINTERN void e_tw_shutdown(void); |
||||
EINTERN Eina_Bool tw_hide(void *d EINA_UNUSED); |
||||
EINTERN void tw_popup_opacity_set(void); |
||||
|
||||
EINTERN E_Config_Dialog *e_int_config_teamwork_module(E_Container *con, const char *params EINA_UNUSED);
|
||||
|
||||
EAPI int e_modapi_shutdown(E_Module *m __UNUSED__); |
||||
#undef DBG |
||||
#undef INF |
||||
#undef WRN |
||||
#undef ERR |
||||
#undef CRIT |
||||
#define DBG(...) EINA_LOG_DOM_DBG(_e_teamwork_log_dom, __VA_ARGS__) |
||||
#define INF(...) EINA_LOG_DOM_INFO(_e_teamwork_log_dom, __VA_ARGS__) |
||||
#define WRN(...) EINA_LOG_DOM_WARN(_e_teamwork_log_dom, __VA_ARGS__) |
||||
#define ERR(...) EINA_LOG_DOM_ERR(_e_teamwork_log_dom, __VA_ARGS__) |
||||
#define CRIT(...) EINA_LOG_DOM_CRIT(_e_teamwork_log_dom, __VA_ARGS__) |
||||
|
||||
#endif |
@ -0,0 +1,873 @@ |
||||
#include "e_mod_main.h" |
||||
|
||||
#define IMAGE_FETCH_TRIES 5 |
||||
|
||||
typedef struct |
||||
{ |
||||
const char *sha1; |
||||
unsigned long long timestamp; |
||||
} Media_Cache; |
||||
|
||||
typedef struct Media_Cache_List |
||||
{ |
||||
Eina_List *cache; |
||||
} Media_Cache_List; |
||||
|
||||
typedef struct Media |
||||
{ |
||||
EINA_INLIST; |
||||
Ecore_Con_Url *client; |
||||
Eina_Binbuf *buf; |
||||
const char *addr; |
||||
unsigned long long timestamp; |
||||
unsigned int tries; |
||||
Eina_Bool dummy : 1; |
||||
Eina_Bool valid : 1; |
||||
Eina_Bool show : 1; |
||||
} Media; |
||||
|
||||
static Eet_File *media = NULL; |
||||
static Eet_File *dummies = NULL; |
||||
static Eet_Data_Descriptor *cleaner_edd = NULL; |
||||
static Eet_Data_Descriptor *cache_edd = NULL; |
||||
static Ecore_Idler *media_cleaner = NULL; |
||||
static Eina_List *handlers = NULL; |
||||
static Media_Cache_List *tw_cache_list = NULL; |
||||
|
||||
static Evas_Point last_coords = {0}; |
||||
|
||||
static Ecore_Timer *tw_hide_timer = NULL; |
||||
|
||||
static Eldbus_Service_Interface *tw_dbus_iface = NULL; |
||||
|
||||
typedef enum |
||||
{ |
||||
TEAMWORK_LINK_TYPE_NONE, |
||||
TEAMWORK_LINK_TYPE_LOCAL_FILE, |
||||
TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY, |
||||
TEAMWORK_LINK_TYPE_REMOTE |
||||
} Teamwork_Link_Type; |
||||
|
||||
typedef enum |
||||
{ |
||||
TEAMWORK_SIGNAL_LINK_DOWNLOADING, |
||||
TEAMWORK_SIGNAL_LINK_PROGRESS, |
||||
TEAMWORK_SIGNAL_LINK_COMPLETE, |
||||
TEAMWORK_SIGNAL_LINK_INVALID, |
||||
} Teamwork_Signal; |
||||
|
||||
static const Eldbus_Signal tw_signals[] = |
||||
{ |
||||
[TEAMWORK_SIGNAL_LINK_DOWNLOADING] = {"LinkDownloading", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0}, |
||||
[TEAMWORK_SIGNAL_LINK_PROGRESS] = {"LinkProgress", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"d", "Percent Completion"}), 0}, |
||||
[TEAMWORK_SIGNAL_LINK_COMPLETE] = {"LinkComplete", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0}, |
||||
[TEAMWORK_SIGNAL_LINK_INVALID] = {"LinkInvalid", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0}, |
||||
{} |
||||
}; |
||||
|
||||
static void tw_show(Media *i); |
||||
static void tw_show_local_file(const char *uri); |
||||
static void tw_show_local_dir(const char *uri); |
||||
static int tw_media_add(const char *url, Eina_Binbuf *buf, unsigned long long timestamp); |
||||
static void download_media_cleanup(void); |
||||
static void tw_dummy_add(const char *url); |
||||
static Eina_Bool tw_dummy_check(const char *url); |
||||
static void tw_media_ping(const char *url, unsigned long long timestamp); |
||||
static Eina_Binbuf *tw_media_get(const char *url, unsigned long long timestamp); |
||||
static Eina_Bool tw_idler_start(void); |
||||
|
||||
static void |
||||
dbus_signal_link_complete(Media *i) |
||||
{ |
||||
unsigned int u = ecore_time_unix_get(); |
||||
if (i->show) tw_show(i); |
||||
i->show = 0; |
||||
eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_COMPLETE, i->addr, u); |
||||
} |
||||
|
||||
static void |
||||
dbus_signal_link_invalid(Media *i) |
||||
{ |
||||
unsigned int u = ecore_time_unix_get(); |
||||
eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_INVALID, i->addr, u); |
||||
} |
||||
|
||||
static void |
||||
dbus_signal_link_progress(Media *i, double pr) |
||||
{ |
||||
unsigned int u = ecore_time_unix_get(); |
||||
eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_PROGRESS, i->addr, u, pr); |
||||
} |
||||
|
||||
static void |
||||
dbus_signal_link_downloading(Media *i) |
||||
{ |
||||
unsigned int u = ecore_time_unix_get(); |
||||
eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_DOWNLOADING, i->addr, u); |
||||
} |
||||
|
||||
static Eina_Bool |
||||
download_media_complete(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Complete *ev) |
||||
{ |
||||
Media *i; |
||||
|
||||
if (data != tw_mod) return ECORE_CALLBACK_RENEW; |
||||
i = ecore_con_url_data_get(ev->url_con); |
||||
if (!i) return ECORE_CALLBACK_RENEW; |
||||
if (!i->valid) return ECORE_CALLBACK_RENEW; |
||||
i->timestamp = (unsigned long long)ecore_time_unix_get(); |
||||
if (tw_media_add(i->addr, i->buf, i->timestamp) == 1) |
||||
tw_mod->media_size += eina_binbuf_length_get(i->buf); |
||||
E_FREE_FUNC(i->client, ecore_con_url_free); |
||||
dbus_signal_link_complete(i); |
||||
download_media_cleanup(); |
||||
INF("MEDIA CACHE: %zu bytes", tw_mod->media_size); |
||||
return ECORE_CALLBACK_RENEW; |
||||
} |
||||
|
||||
static Eina_Bool |
||||
download_media_data(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Data *ev) |
||||
{ |
||||
Media *i; |
||||
|
||||
if (data != tw_mod) return ECORE_CALLBACK_RENEW; |
||||
i = ecore_con_url_data_get(ev->url_con); |
||||
if (!i) return ECORE_CALLBACK_RENEW; |
||||
if (i->dummy) return ECORE_CALLBACK_RENEW; |
||||
if (!i->buf) i->buf = eina_binbuf_new(); |
||||
eina_binbuf_append_length(i->buf, ev->data, ev->size); |
||||
return ECORE_CALLBACK_RENEW; |
||||
} |
||||
|
||||
static Eina_Bool |
||||
download_media_status(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Progress *ev) |
||||
{ |
||||
int status; |
||||
const char *h; |
||||
Media *i; |
||||
const Eina_List *l; |
||||
|
||||
if (data != tw_mod) return ECORE_CALLBACK_RENEW; |
||||
i = ecore_con_url_data_get(ev->url_con); |
||||
if (!i) return ECORE_CALLBACK_RENEW; |
||||
|
||||
if (i->valid) return ECORE_CALLBACK_RENEW; //already checked
|
||||
status = ecore_con_url_status_code_get(ev->url_con); |
||||
if (!status) return ECORE_CALLBACK_RENEW; //not ready yet
|
||||
DBG("%i code for media: %s", status, i->addr); |
||||
if (status != 200) |
||||
{ |
||||
E_FREE_FUNC(i->buf, eina_binbuf_free); |
||||
E_FREE_FUNC(i->client, ecore_con_url_free); |
||||
if ((status >= 400) || (status <= 300)) goto dummy; |
||||
if (++i->tries < IMAGE_FETCH_TRIES) |
||||
{ |
||||
i->client = ecore_con_url_new(i->addr); |
||||
ecore_con_url_data_set(i->client, i); |
||||
if (!ecore_con_url_get(i->client)) goto dummy; |
||||
} |
||||
return ECORE_CALLBACK_RENEW; |
||||
} |
||||
EINA_LIST_FOREACH(ecore_con_url_response_headers_get(ev->url_con), l, h) |
||||
{ |
||||
if (strncasecmp(h, "Content-Type: ", sizeof("Content-Type: ") - 1)) continue; |
||||
if (strncasecmp(h + sizeof("Content-Type: ") - 1, "image/", 6)) goto dummy; |
||||
} |
||||
i->valid = !i->dummy; |
||||
if (i->valid) dbus_signal_link_progress(i, ev->down.now / ev->down.total); |
||||
|
||||
return ECORE_CALLBACK_RENEW; |
||||
dummy: |
||||
dbus_signal_link_invalid(i); |
||||
tw_dummy_add(i->addr); |
||||
i->dummy = EINA_TRUE; |
||||
E_FREE_FUNC(i->buf, eina_binbuf_free); |
||||
E_FREE_FUNC(i->client, ecore_con_url_free); |
||||
return ECORE_CALLBACK_RENEW; |
||||
} |
||||
|
||||
static int |
||||
download_media_sort_cb(Media *a, Media *b) |
||||
{ |
||||
long long diff; |
||||
diff = a->timestamp - b->timestamp; |
||||
if (diff < 0) return -1; |
||||
if (!diff) return 0; |
||||
return 1; |
||||
} |
||||
|
||||
static Media * |
||||
download_media_add(const char *url) |
||||
{ |
||||
Media *i; |
||||
unsigned long long t; |
||||
|
||||
t = (unsigned long long)ecore_time_unix_get(); |
||||
|
||||
i = eina_hash_find(tw_mod->media, url); |
||||
if (i) |
||||
{ |
||||
if (i->buf) |
||||
{ |
||||
i->timestamp = t; |
||||
tw_media_ping(url, i->timestamp); |
||||
} |
||||
else |
||||
{ |
||||
/* randomly deleted during cache pruning */ |
||||
i->buf = tw_media_get(url, t); |
||||
tw_mod->media_size += eina_binbuf_length_get(i->buf); |
||||
} |
||||
tw_mod->media_list = eina_inlist_promote(tw_mod->media_list, EINA_INLIST_GET(i)); |
||||
download_media_cleanup(); |
||||
return i; |
||||
} |
||||
if (tw_dummy_check(url)) return NULL; |
||||
if (tw_config->disable_media_fetch) return NULL; |
||||
i = calloc(1, sizeof(Media)); |
||||
i->addr = eina_stringshare_add(url); |
||||
i->buf = tw_media_get(url, t); |
||||
if (i->buf) |
||||
tw_mod->media_size += eina_binbuf_length_get(i->buf); |
||||
else |
||||
{ |
||||
i->client = ecore_con_url_new(url); |
||||
ecore_con_url_data_set(i->client, i); |
||||
ecore_con_url_get(i->client); |
||||
dbus_signal_link_downloading(i); |
||||
} |
||||
eina_hash_direct_add(tw_mod->media, url, i); |
||||
tw_mod->media_list = eina_inlist_sorted_insert(tw_mod->media_list, EINA_INLIST_GET(i), (Eina_Compare_Cb)download_media_sort_cb); |
||||
return i; |
||||
} |
||||
|
||||
static void |
||||
download_media_free(Media *i) |
||||
{ |
||||
if (!i) return; |
||||
tw_mod->media_list = eina_inlist_remove(tw_mod->media_list, EINA_INLIST_GET(i)); |
||||
if (i->client) ecore_con_url_free(i->client); |
||||
if (i->buf) eina_binbuf_free(i->buf); |
||||
eina_stringshare_del(i->addr); |
||||
free(i); |
||||
} |
||||
|
||||
static void |
||||
download_media_cleanup(void) |
||||
{ |
||||
Media *i; |
||||
Eina_Inlist *l; |
||||
|
||||
if (tw_config->allowed_media_age) |
||||
{ |
||||
if (tw_config->allowed_media_size < 0) return; |
||||
if ((size_t)tw_config->allowed_media_size > (tw_mod->media_size / 1024 / 1024)) return; |
||||
} |
||||
if (!tw_mod->media_list) return; |
||||
l = tw_mod->media_list->last; |
||||
while (l) |
||||
{ |
||||
i = EINA_INLIST_CONTAINER_GET(l, Media); |
||||
l = l->prev; |
||||
if (!i->buf) continue; |
||||
/* only free the buffers here where possible to avoid having to deal with multiple list entries */ |
||||
if (tw_mod->media_size && (tw_mod->media_size >= eina_binbuf_length_get(i->buf))) |
||||
tw_mod->media_size -= eina_binbuf_length_get(i->buf); |
||||
E_FREE_FUNC(i->buf, eina_binbuf_free); |
||||
if (!tw_config->allowed_media_age) |
||||
/* if caching is disabled, just delete */ |
||||
eina_hash_del_by_key(tw_mod->media, i->addr); |
||||
if ((size_t)tw_config->allowed_media_size > (tw_mod->media_size / 1024 / 1024)) |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static Teamwork_Link_Type |
||||
dbus_link_uri_local_type_get(const char *uri) |
||||
{ |
||||
size_t len = strlen(uri); |
||||
|
||||
if (uri[len - 1] == '/') return TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY; |
||||
return TEAMWORK_LINK_TYPE_LOCAL_FILE; |
||||
} |
||||
|
||||
static Teamwork_Link_Type |
||||
dbus_link_uri_type_get(const char *uri) |
||||
{ |
||||
if (!uri[0]) return TEAMWORK_LINK_TYPE_NONE; //invalid
|
||||
if (uri[0] == '/') return dbus_link_uri_local_type_get(uri + 1); //probably a file?
|
||||
if ((!strncasecmp(uri, "http://", 7)) || (!strncasecmp(uri, "https://", 8))) return TEAMWORK_LINK_TYPE_REMOTE; |
||||
if (!strncmp(uri, "file://", 7)) return dbus_link_uri_local_type_get(uri + 7); |
||||
WRN("Unknown link type for '%s'", uri); |
||||
return TEAMWORK_LINK_TYPE_NONE; |
||||
} |
||||
|
||||
static Eldbus_Message * |
||||
dbus_link_detect_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) |
||||
{ |
||||
const char *uri; |
||||
unsigned int t; |
||||
|
||||
if (!tw_config->allowed_media_age) goto out; |
||||
if (!eldbus_message_arguments_get(msg, "su", &uri, &t)) goto out; |
||||
|
||||
if (dbus_link_uri_type_get(uri) == TEAMWORK_LINK_TYPE_REMOTE) |
||||
download_media_add(uri); |
||||
out: |
||||
return eldbus_message_method_return_new(msg); |
||||
} |
||||
|
||||
static void |
||||
dbus_link_show_helper(const char *uri, Eina_Bool signal_open) |
||||
{ |
||||
Teamwork_Link_Type type; |
||||
|
||||
if (tw_mod->pop && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri))) return; |
||||
type = dbus_link_uri_type_get(uri); |
||||
switch (type) |
||||
{ |
||||
case TEAMWORK_LINK_TYPE_NONE: break; |
||||
case TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY: |
||||
if (signal_open) tw_show_local_dir(uri); |
||||
break; |
||||
case TEAMWORK_LINK_TYPE_LOCAL_FILE: |
||||
tw_show_local_file(uri); |
||||
break; |
||||
case TEAMWORK_LINK_TYPE_REMOTE: |
||||
{ |
||||
Media *i; |
||||
|
||||
i = eina_hash_find(tw_mod->media, uri); |
||||
if (!i) |
||||
{ |
||||
if (tw_dummy_check(uri)) break; |
||||
i = download_media_add(uri); |
||||
if (i) |
||||
{ |
||||
if (i->buf) tw_show(i); |
||||
else if (i->dummy) break; |
||||
else i->show = 1; |
||||
} |
||||
} |
||||
else if (!i->dummy) tw_show(i); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static Eldbus_Message * |
||||
dbus_link_show_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) |
||||
{ |
||||
const char *uri; |
||||
|
||||
if (eldbus_message_arguments_get(msg, "s", &uri)) |
||||
{ |
||||
last_coords.x = last_coords.y = -1; |
||||
dbus_link_show_helper(uri, 1); |
||||
} |
||||
return eldbus_message_method_return_new(msg); |
||||
} |
||||
|
||||
static Eldbus_Message * |
||||
dbus_link_hide_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) |
||||
{ |
||||
const char *uri; |
||||
|
||||
if (eldbus_message_arguments_get(msg, "s", &uri)) |
||||
{ |
||||
if (tw_mod->pop && (!tw_mod->sticky) && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri))) |
||||
tw_hide(NULL); |
||||
} |
||||
return eldbus_message_method_return_new(msg); |
||||
} |
||||
|
||||
static Eldbus_Message * |
||||
dbus_link_mouse_in_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) |
||||
{ |
||||
const char *uri; |
||||
unsigned int t; |
||||
|
||||
if (eldbus_message_arguments_get(msg, "suii", &uri, &t, &last_coords.x, &last_coords.y)) |
||||
dbus_link_show_helper(uri, 0); |
||||
return eldbus_message_method_return_new(msg); |
||||
} |
||||
|
||||
static Eldbus_Message * |
||||
dbus_link_mouse_out_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) |
||||
{ |
||||
const char *uri; |
||||
unsigned int t; |
||||
|
||||
if (eldbus_message_arguments_get(msg, "suii", &uri, &t, &last_coords.x, &last_coords.y)) |
||||
{ |
||||
if (tw_mod->pop && (!tw_mod->sticky) && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri))) |
||||
{ |
||||
if (tw_config->mouse_out_delay) |
||||
{ |
||||
if (tw_hide_timer) ecore_timer_reset(tw_hide_timer); |
||||
else tw_hide_timer = ecore_timer_add(tw_config->mouse_out_delay, tw_hide, NULL); |
||||
} |
||||
else |
||||
tw_hide(NULL); |
||||
} |
||||
} |
||||
return eldbus_message_method_return_new(msg); |
||||
} |
||||
|
||||
static Eldbus_Message * |
||||
dbus_link_open_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) |
||||
{ |
||||
const char *uri; |
||||
|
||||
if (eldbus_message_arguments_get(msg, "s", &uri)) |
||||
{ |
||||
char *sb; |
||||
size_t size = 4096, len = sizeof(E_BINDIR "/enlightenment_open ") - 1; |
||||
|
||||
sb = malloc(size); |
||||
memcpy(sb, E_BINDIR "/enlightenment_open ", len); |
||||
sb = e_util_string_append_quoted(sb, &size, &len, uri); |
||||
ecore_exe_run(sb, NULL); |
||||
free(sb); |
||||
} |
||||
return eldbus_message_method_return_new(msg); |
||||
} |
||||
|
||||
|
||||
static const Eldbus_Method tw_methods[] = { |
||||
{ "LinkDetect", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), NULL, dbus_link_detect_cb }, |
||||
{ "LinkMouseIn", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"i", "X Coordinate"}, {"i", "Y Coordinate"}), NULL, dbus_link_mouse_in_cb }, |
||||
{ "LinkMouseOut", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"i", "X Coordinate"}, {"i", "Y Coordinate"}), NULL, dbus_link_mouse_out_cb }, |
||||
{ "LinkShow", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_show_cb }, |
||||
{ "LinkHide", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_hide_cb }, |
||||
{ "LinkOpen", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_open_cb }, |
||||
{ } |
||||
}; |
||||
|
||||
static const Eldbus_Service_Interface_Desc tw_desc = |
||||
{ |
||||
"org.enlightenment.wm.Teamwork", tw_methods, tw_signals |
||||
}; |
||||
|
||||
static Eet_Data_Descriptor * |
||||
media_cache_edd_new(void) |
||||
{ |
||||
Eet_Data_Descriptor *edd; |
||||
Eet_Data_Descriptor_Class eddc; |
||||
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Media_Cache); |
||||
edd = eet_data_descriptor_stream_new(&eddc); |
||||
#define ADD(name, type) \ |
||||
EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Media_Cache, #name, name, EET_T_##type) |
||||
|
||||
ADD(sha1, INLINED_STRING); |
||||
ADD(timestamp, ULONG_LONG); |
||||
#undef ADD |
||||
return edd; |
||||
} |
||||
|
||||
static int |
||||
media_cache_compare(Media_Cache *a, Media_Cache *b) |
||||
{ |
||||
long long diff; |
||||
diff = a->timestamp - b->timestamp; |
||||
if (diff < 0) return -1; |
||||
if (!diff) return 0; |
||||
return 1; |
||||
} |
||||
|
||||
static void |
||||
media_cache_add(const char *sha1, unsigned long long timestamp) |
||||
{ |
||||
Media_Cache *ic; |
||||
if (!tw_cache_list) return; |
||||
ic = malloc(sizeof(Media_Cache)); |
||||
ic->sha1 = eina_stringshare_ref(sha1); |
||||
ic->timestamp = timestamp; |
||||
tw_cache_list->cache = eina_list_sorted_insert(tw_cache_list->cache, (Eina_Compare_Cb)media_cache_compare, ic); |
||||
} |
||||
|
||||
static void |
||||
media_cache_del(const char *sha1) |
||||
{ |
||||
Eina_List *l, *l2; |
||||
Media_Cache *ic; |
||||
|
||||
if (!tw_cache_list) return; |
||||
EINA_LIST_FOREACH_SAFE(tw_cache_list->cache, l, l2, ic) |
||||
{ |
||||
if (ic->sha1 == sha1) continue; |
||||
tw_cache_list->cache = eina_list_remove_list(tw_cache_list->cache, l); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
static void |
||||
media_cache_update(const char *sha1, unsigned long long timestamp) |
||||
{ |
||||
Media_Cache *ic; |
||||
Eina_List *l; |
||||
|
||||
if (!tw_cache_list) return; |
||||
EINA_LIST_FOREACH(tw_cache_list->cache, l, ic) |
||||
{ |
||||
if (ic->sha1 != sha1) continue; |
||||
ic->timestamp = timestamp; |
||||
break; |
||||
} |
||||
tw_cache_list->cache = eina_list_sort(tw_cache_list->cache, eina_list_count(tw_cache_list->cache), (Eina_Compare_Cb)media_cache_compare); |
||||
} |
||||
|
||||