#ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "Emotion.h" typedef struct _External_Emotion_Params External_Emotion_Params; typedef struct _External_Emotion_Signals_Proxy_Context External_Emotion_Signals_Proxy_Context; struct _External_Emotion_Params { #define _STR(M) const char *M #define _BOOL(M) Eina_Bool M:1; Eina_Bool M##_exists:1 #define _INT(M) int M; Eina_Bool M##_exists:1 #define _DOUBLE(M) double M; Eina_Bool M##_exists:1 _STR(file); _BOOL(play); _DOUBLE(position); _BOOL(smooth_scale); _DOUBLE(audio_volume); _BOOL(audio_mute); _INT(audio_channel); _BOOL(video_mute); _INT(video_channel); _BOOL(spu_mute); _INT(spu_channel); _INT(chapter); _DOUBLE(play_speed); _DOUBLE(play_length); //_INT(vis); #undef _STR #undef _BOOL #undef _INT #undef _DOUBLE }; struct _External_Emotion_Signals_Proxy_Context { const char *emission; const char *source; Evas_Object *edje; }; static int _log_dom = -1; #define CRI(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__) #define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__) #define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__) #define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__) #define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__) static const char *_external_emotion_engines[] = { #if EMOTION_BUILD_GSTREAMER1 "gstreamer1", #endif NULL, }; static const char _external_emotion_engine_def[] = #if defined(EMOTION_BUILD_GSTREAMER1) "gstreamer1"; #else "impossible"; #endif static void _external_emotion_signal_proxy_free_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { External_Emotion_Signals_Proxy_Context *ctxt = data; free(ctxt); } static void _external_emotion_signal_proxy_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { External_Emotion_Signals_Proxy_Context *ctxt = data; // TODO: Is it worth to check Evas_Smart_Cb_Description and do something // TODO: with event_info given its description? edje_object_signal_emit(ctxt->edje, ctxt->emission, ctxt->source); } static Evas_Object * _external_emotion_add(void *data EINA_UNUSED, Evas *evas, Evas_Object *edje EINA_UNUSED, const Eina_List *params, const char *part_name) { const Evas_Smart_Cb_Description **cls_descs, **inst_descs; unsigned int cls_count, inst_count, total; External_Emotion_Signals_Proxy_Context *ctxt; Evas_Object *obj; const char *engine; if (!edje_external_param_choice_get(params, "engine", &engine)) engine = NULL; if (!engine) engine = _external_emotion_engine_def; obj = emotion_object_add(evas); if (!emotion_object_init(obj, engine)) { ERR("failed to initialize emotion with engine '%s'.", engine); return NULL; } evas_object_smart_callbacks_descriptions_get (obj, &cls_descs, &cls_count, &inst_descs, &inst_count); total = cls_count + inst_count; if (!total) goto end; ctxt = malloc(sizeof(External_Emotion_Signals_Proxy_Context) * total); if (!ctxt) goto end; evas_object_event_callback_add (obj, EVAS_CALLBACK_DEL, _external_emotion_signal_proxy_free_cb, ctxt); for (; cls_count > 0; cls_count--, cls_descs++, ctxt++) { const Evas_Smart_Cb_Description *d = *cls_descs; ctxt->emission = d->name; ctxt->source = part_name; ctxt->edje = edje; evas_object_smart_callback_add (obj, d->name, _external_emotion_signal_proxy_cb, ctxt); } for (; inst_count > 0; inst_count--, inst_descs++, ctxt++) { const Evas_Smart_Cb_Description *d = *inst_descs; ctxt->emission = d->name; ctxt->source = part_name; ctxt->edje = edje; evas_object_smart_callback_add (obj, d->name, _external_emotion_signal_proxy_cb, ctxt); } end: return obj; } static void _external_emotion_signal(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *signal, const char *source) { DBG("External Signal received: '%s' '%s'", signal, source); } static void _external_emotion_state_set(void *data EINA_UNUSED, Evas_Object *obj, const void *from_params, const void *to_params, float pos EINA_UNUSED) { const External_Emotion_Params *p; if (to_params) p = to_params; else if (from_params) p = from_params; else return; #define _STR(M) if (p->M) emotion_object_##M##_set(obj, p->M) #define _BOOL(M) if (p->M##_exists) emotion_object_##M##_set(obj, p->M) #define _INT(M) if (p->M##_exists) emotion_object_##M##_set(obj, p->M) #define _DOUBLE(M) if (p->M##_exists) emotion_object_##M##_set(obj, p->M) _STR(file); _BOOL(play); //_DOUBLE(position); if (p->position_exists) WRN("position should not be set from state description! Ignored."); _BOOL(smooth_scale); _DOUBLE(audio_volume); _BOOL(audio_mute); _INT(audio_channel); _BOOL(video_mute); _INT(video_channel); _BOOL(spu_mute); _INT(spu_channel); _INT(chapter); _DOUBLE(play_speed); if (p->play_length_exists) ERR("play_length is read-only"); //_INT(vis); #undef _STR #undef _BOOL #undef _INT #undef _DOUBLE } static Eina_Bool _external_emotion_param_set(void *data EINA_UNUSED, Evas_Object *obj, const Edje_External_Param *param) { if (!strcmp(param->name, "engine")) { // TODO WRN("engine is a property that can be set only at object creation!"); return EINA_FALSE; } #define _STR(M) \ else if (!strcmp(param->name, #M)) \ { \ if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) \ { \ emotion_object_##M##_set(obj, param->s); \ return EINA_TRUE; \ } \ } #define _BOOL(M) \ else if (!strcmp(param->name, #M)) \ { \ if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) \ { \ emotion_object_##M##_set(obj, param->i); \ return EINA_TRUE; \ } \ } #define _INT(M) \ else if (!strcmp(param->name, #M)) \ { \ if (param->type == EDJE_EXTERNAL_PARAM_TYPE_INT) \ { \ emotion_object_##M##_set(obj, param->i); \ return EINA_TRUE; \ } \ } #define _DOUBLE(M) \ else if (!strcmp(param->name, #M)) \ { \ if (param->type == EDJE_EXTERNAL_PARAM_TYPE_DOUBLE) \ { \ emotion_object_##M##_set(obj, param->d); \ return EINA_TRUE; \ } \ } if (0) {} // so else if works... _STR(file) _BOOL(play) _DOUBLE(position) _BOOL(smooth_scale) _DOUBLE(audio_volume) _BOOL(audio_mute) _INT(audio_channel) _BOOL(video_mute) _INT(video_channel) _BOOL(spu_mute) _INT(spu_channel) _INT(chapter) _DOUBLE(play_speed) else if (!strcmp(param->name, "play_length")) { ERR("play_length is read-only"); return EINA_FALSE; } //_INT(vis); #undef _STR #undef _BOOL #undef _INT #undef _DOUBLE ERR("unknown parameter '%s' of type '%s'", param->name, edje_external_param_type_str(param->type)); return EINA_FALSE; } static Eina_Bool _external_emotion_param_get(void *data EINA_UNUSED, const Evas_Object *obj, Edje_External_Param *param) { #define _STR(M) \ else if (!strcmp(param->name, #M)) \ { \ if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) \ { \ param->s = emotion_object_##M##_get(obj); \ return EINA_TRUE; \ } \ } #define _BOOL(M) \ else if (!strcmp(param->name, #M)) \ { \ if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) \ { \ param->i = emotion_object_##M##_get(obj); \ return EINA_TRUE; \ } \ } #define _INT(M) \ else if (!strcmp(param->name, #M)) \ { \ if (param->type == EDJE_EXTERNAL_PARAM_TYPE_INT) \ { \ param->i = emotion_object_##M##_get(obj); \ return EINA_TRUE; \ } \ } #define _DOUBLE(M) \ else if (!strcmp(param->name, #M)) \ { \ if (param->type == EDJE_EXTERNAL_PARAM_TYPE_DOUBLE) \ { \ param->d = emotion_object_##M##_get(obj); \ return EINA_TRUE; \ } \ } if (0) {} // so else if works... _STR(file) _BOOL(play) _DOUBLE(position) _BOOL(smooth_scale) _DOUBLE(audio_volume) _BOOL(audio_mute) _INT(audio_channel) _BOOL(video_mute) _INT(video_channel) _BOOL(spu_mute) _INT(spu_channel) _INT(chapter) _DOUBLE(play_speed) _DOUBLE(play_length) //_INT(vis) #undef _STR #undef _BOOL #undef _INT #undef _DOUBLE ERR("unknown parameter '%s' of type '%s'", param->name, edje_external_param_type_str(param->type)); return EINA_FALSE; } static void * _external_emotion_params_parse(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const Eina_List *params) { const Edje_External_Param *param; const Eina_List *l; External_Emotion_Params *p = calloc(1, sizeof(External_Emotion_Params)); if (!p) return NULL; EINA_LIST_FOREACH(params, l, param) { #define _STR(M) \ if (!strcmp(param->name, #M)) p->M = eina_stringshare_add(param->s) #define _BOOL(M) \ if (!strcmp(param->name, #M)) \ { \ p->M = param->i; \ p->M##_exists = EINA_TRUE; \ } #define _INT(M) \ if (!strcmp(param->name, #M)) \ { \ p->M = param->i; \ p->M##_exists = EINA_TRUE; \ } #define _DOUBLE(M) \ if (!strcmp(param->name, #M)) \ { \ p->M = param->d; \ p->M##_exists = EINA_TRUE; \ } _STR(file); _BOOL(play); _DOUBLE(position); _BOOL(smooth_scale); _DOUBLE(audio_volume); _BOOL(audio_mute); _INT(audio_channel); _BOOL(video_mute); _INT(video_channel); _BOOL(spu_mute); _INT(spu_channel); _INT(chapter); _DOUBLE(play_speed); _DOUBLE(play_length); //_INT(vis); #undef _STR #undef _BOOL #undef _INT #undef _DOUBLE } return p; } static void _external_emotion_params_free(void *params) { External_Emotion_Params *p = params; #define _STR(M) eina_stringshare_del(p->M) #define _BOOL(M) do {} while (0) #define _INT(M) do {} while (0) #define _DOUBLE(M) do {} while (0) _STR(file); _BOOL(play); _DOUBLE(position); _BOOL(smooth_scale); _DOUBLE(audio_volume); _BOOL(audio_mute); _INT(audio_channel); _BOOL(video_mute); _INT(video_channel); _BOOL(spu_mute); _INT(spu_channel); _INT(chapter); _DOUBLE(play_speed); _DOUBLE(play_length); //_INT(vis); #undef _STR #undef _BOOL #undef _INT #undef _DOUBLE free(p); } static const char * _external_emotion_label_get(void *data EINA_UNUSED) { return "Emotion"; } static Evas_Object * _external_emotion_icon_add(void *data EINA_UNUSED, Evas *e) { Evas_Object *ic; int w = 0, h = 0; ic = edje_object_add(e); edje_object_file_set(ic, PACKAGE_DATA_DIR"/data/icon.edj", "icon"); edje_object_size_min_get(ic, &w, &h); if (w < 1) w = 20; if (h < 1) h = 10; evas_object_size_hint_min_set(ic, w, h); evas_object_size_hint_max_set(ic, w, h); return ic; } static const char * _external_emotion_translate(void *data EINA_UNUSED, const char *orig) { // in future, mark all params as translatable and use dgettext() // with "emotion" text domain here. return orig; } static Edje_External_Param_Info _external_emotion_params[] = { EDJE_EXTERNAL_PARAM_INFO_CHOICE_FULL ("engine", _external_emotion_engine_def, _external_emotion_engines), EDJE_EXTERNAL_PARAM_INFO_STRING("file"), EDJE_EXTERNAL_PARAM_INFO_BOOL_DEFAULT("play", EINA_FALSE), EDJE_EXTERNAL_PARAM_INFO_DOUBLE("position"), EDJE_EXTERNAL_PARAM_INFO_BOOL_DEFAULT("smooth_scale", EINA_FALSE), EDJE_EXTERNAL_PARAM_INFO_DOUBLE_DEFAULT("audio_volume", 0.9), EDJE_EXTERNAL_PARAM_INFO_BOOL_DEFAULT("audio_mute", EINA_FALSE), EDJE_EXTERNAL_PARAM_INFO_INT_DEFAULT("audio_channel", 0), EDJE_EXTERNAL_PARAM_INFO_BOOL_DEFAULT("video_mute", EINA_FALSE), EDJE_EXTERNAL_PARAM_INFO_INT_DEFAULT("video_channel", 0), EDJE_EXTERNAL_PARAM_INFO_BOOL_DEFAULT("spu_mute", EINA_FALSE), EDJE_EXTERNAL_PARAM_INFO_INT_DEFAULT("spu_channel", 0), EDJE_EXTERNAL_PARAM_INFO_INT("chapter"), EDJE_EXTERNAL_PARAM_INFO_DOUBLE_DEFAULT("play_speed", 1.0), EDJE_EXTERNAL_PARAM_INFO_DOUBLE("play_length"), //EDJE_EXTERNAL_PARAM_INFO_CHOICE_FULL("vis", ...), EDJE_EXTERNAL_PARAM_INFO_SENTINEL }; static const Edje_External_Type _external_emotion_type = { .abi_version = EDJE_EXTERNAL_TYPE_ABI_VERSION, .module = "emotion", .module_name = "Emotion", .add = _external_emotion_add, .state_set = _external_emotion_state_set, .signal_emit = _external_emotion_signal, .param_set = _external_emotion_param_set, .param_get = _external_emotion_param_get, .params_parse = _external_emotion_params_parse, .params_free = _external_emotion_params_free, .label_get = _external_emotion_label_get, .description_get = NULL, .icon_add = _external_emotion_icon_add, .preview_add = NULL, .translate = _external_emotion_translate, .parameters_info = _external_emotion_params, .data = NULL }; static Edje_External_Type_Info _external_emotion_types[] = { {"emotion", &_external_emotion_type}, {NULL, NULL} }; static Eina_Bool external_emotion_mod_init(void) { _log_dom = eina_log_domain_register ("emotion-externals", EINA_COLOR_LIGHTBLUE); edje_external_type_array_register(_external_emotion_types); return EINA_TRUE; } static void external_emotion_mod_shutdown(void) { edje_external_type_array_unregister(_external_emotion_types); eina_log_domain_unregister(_log_dom); _log_dom = -1; } EINA_MODULE_INIT(external_emotion_mod_init); EINA_MODULE_SHUTDOWN(external_emotion_mod_shutdown);