From 40a62ddf94f590b2e79caf63eb399d9bc257b216 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Sat, 4 Jan 2020 15:08:08 +0100 Subject: [PATCH 01/17] eina: introduce Eina_Abstract_Content A little abstraction to have abstract data content bound to a type. Reviewed-by: Cedric BAIL Reviewed-by: Xavi Artigas Differential Revision: https://phab.enlightenment.org/D11018 --- src/lib/eina/Eina.h | 1 + src/lib/eina/eina_abstract_content.c | 443 ++++++++++++++++++++ src/lib/eina/eina_abstract_content.h | 154 +++++++ src/lib/eina/eina_main.c | 2 + src/lib/eina/eina_slice.h | 24 ++ src/lib/eina/meson.build | 4 +- src/tests/eina/eina_suite.c | 1 + src/tests/eina/eina_suite.h | 1 + src/tests/eina/eina_test_abstract_content.c | 223 ++++++++++ src/tests/eina/meson.build | 3 +- 10 files changed, 854 insertions(+), 2 deletions(-) create mode 100644 src/lib/eina/eina_abstract_content.c create mode 100644 src/lib/eina/eina_abstract_content.h create mode 100644 src/tests/eina/eina_test_abstract_content.c diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h index d2f5d4543d..23366d629a 100644 --- a/src/lib/eina/Eina.h +++ b/src/lib/eina/Eina.h @@ -272,6 +272,7 @@ extern "C" { #include #include #include +#include #undef EAPI #define EAPI diff --git a/src/lib/eina/eina_abstract_content.c b/src/lib/eina/eina_abstract_content.c new file mode 100644 index 0000000000..4b74256d25 --- /dev/null +++ b/src/lib/eina/eina_abstract_content.c @@ -0,0 +1,443 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "eina_abstract_content.h" + +struct _Eina_Content +{ + Eina_Rw_Slice data; + const char *type; + const char *file; + EINA_REFCOUNT; +}; +EAPI const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT; + +static int _eina_abstract_content_log_domain = -1; + +#ifdef ERR +#undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_eina_abstract_content_log_domain, __VA_ARGS__) + +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_eina_abstract_content_log_domain, __VA_ARGS__) + +static Eina_Hash *conversion_callbacks; + +typedef struct { + const char *to; + Eina_Content_Conversion_Callback callback; +} Eina_Content_Conversion_Node; + +static void +_eina_content_ref(Eina_Content *content) +{ + EINA_REFCOUNT_REF(content); +} + +EAPI Eina_Bool +eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback conversion) +{ + Eina_Content_Conversion_Node *node = calloc(1, sizeof(Eina_Content_Conversion_Node)); + + Eina_Stringshare *shared_from = eina_stringshare_add(from); + + if (eina_content_converter_convert_can(from, to)) + { + ERR("Convertion from %s to %s is already possible", from, to); + return EINA_FALSE; + } + + node->to = eina_stringshare_add(to); + node->callback = conversion; + + eina_hash_list_append(conversion_callbacks, shared_from, node); + + return EINA_TRUE; +} + +static inline Eina_List* +_conversion_callback_fetch_possible(const char *from) +{ + Eina_Stringshare *shared_from = eina_stringshare_add(from); + Eina_List *res = eina_hash_find(conversion_callbacks, shared_from); + eina_stringshare_del(shared_from); + return res; +} + +static inline Eina_Content_Conversion_Callback +_conversion_callback_fetch(const char *from, const char *to) +{ + Eina_List *possibilities = _conversion_callback_fetch_possible(from); + Eina_Content_Conversion_Node *n; + Eina_Content_Conversion_Callback result = NULL; + Eina_List *l; + Eina_Stringshare *shared_to = eina_stringshare_add(to); + + EINA_LIST_FOREACH(possibilities, l, n) + { + if (n->to == shared_to) + { + result = n->callback; + goto end; + } + } +end: + eina_stringshare_del(shared_to); + return result; +} + +EAPI Eina_Bool +eina_content_converter_convert_can(const char *from, const char *to) +{ + return !!_conversion_callback_fetch(from, to); +} + +static const void* +_process_cb(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED) +{ + Eina_Content_Conversion_Node *n = data; + + return n->to; + } + +EAPI Eina_Iterator* +eina_content_converter_possible_conversions(const char *from) +{ + Eina_List *possibilities = _conversion_callback_fetch_possible(from); + + return eina_iterator_processed_new(eina_list_iterator_new(possibilities) , EINA_PROCESS_CB(_process_cb), NULL, possibilities); +} + +EAPI Eina_Content* +eina_content_new(Eina_Slice data, const char *type) +{ + Eina_Content *content; + + if (!strncmp(type, "text", strlen("text"))) + { + //last char in the mem must be \0 + if (((char*)data.mem)[data.len - 1] != '\0') + { + ERR("Last character is not a null character! but type is text!"); + return NULL; + } + } + + content = calloc(1, sizeof(Eina_Content)); + EINA_SAFETY_ON_NULL_RETURN_VAL(content, NULL); + content->data = eina_slice_dup(data); + content->type = eina_stringshare_add(type); + EINA_SAFETY_ON_NULL_RETURN_VAL(content->data.mem, NULL); + + _eina_content_ref(content); + return content; +} + +EAPI void +eina_content_free(Eina_Content *content) +{ + EINA_REFCOUNT_UNREF(content) + { + if (content->file) + eina_tmpstr_del(content->file); + free(content->data.mem); + free(content); + } +} + +EAPI const char* +eina_content_as_file(Eina_Content *content) +{ + if (!content->file) + { + Eina_Tmpstr *path; + int fd = eina_file_mkstemp("prefixXXXXXX.ext", &path); + + if (fd < 0) + { + ERR("Failed to create tmp file"); + return NULL; + } + + if (write(fd, content->data.mem, content->data.len) < 0) + { + ERR("Failed to write to a file"); + eina_tmpstr_del(path); + close(fd); + return NULL; + } + + content->file = path; + close(fd); + } + return content->file; +} + +EAPI const char* +eina_content_type_get(Eina_Content *content) +{ + return content->type; +} + +EAPI const Eina_Slice +eina_content_data_get(Eina_Content *content) +{ + return eina_rw_slice_slice_get(content->data); +} + +EAPI Eina_Content* +eina_content_convert(Eina_Content *content, const char *new_type) +{ + Eina_Content_Conversion_Callback callback = _conversion_callback_fetch(content->type, new_type); + + if (!callback) + { + ERR("No suitable conversion found"); + return NULL; + } + + return callback(content, new_type); +} + +static Eina_Content* +_copy_converter(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + return eina_content_new(slice, to_type); +} + +static Eina_Content* +_latin1_to_utf8_converter(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + Eina_Strbuf *out = eina_strbuf_new(); + + for (unsigned int i = 0; i < slice.len; ++i) + { + const unsigned char c = ((char*)slice.mem)[i]; + if (c < 128) + eina_strbuf_append_char(out, c); + else + { + eina_strbuf_append_char(out, 0xc0 | c >> 6); + eina_strbuf_append_char(out, 0x80 | (c & 0x3f)); + } + } + Eina_Slice new; + new.len = eina_strbuf_length_get(out); + new.mem = eina_strbuf_string_get(out); + Eina_Content *c = eina_content_new(new, to_type); + eina_strbuf_free(out); + return c; +} + +static Eina_Bool +_eina_value_type_content_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem) +{ + memset(mem, 0, sizeof(Eina_Content*)); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_flush(const Eina_Value_Type *type EINA_UNUSED, + void *mem EINA_UNUSED) +{ + Eina_Content **content = mem; + + eina_content_free(*content); + + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_copy(const Eina_Value_Type *type EINA_UNUSED, const void *src, void *dst) +{ + Eina_Content * const *srcc = src; + Eina_Content **dstc = dst; + + *dstc = *srcc; + _eina_content_ref(*dstc); + return EINA_TRUE; +} + +static int +_eina_value_type_content_compare(const Eina_Value_Type *type EINA_UNUSED, const void *a, const void *b) +{ + Eina_Content * const *ra = a; + Eina_Content * const *rb = b; + + if ((*ra)->type != (*rb)->type) + return -1; + + return eina_rw_slice_compare((*ra)->data, (*rb)->data); +} + +static Eina_Bool +_eina_value_type_content_convert_to(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert EINA_UNUSED, const void *type_mem EINA_UNUSED, void *convert_mem EINA_UNUSED) +{ + Eina_Content * const *ra = type_mem; + + if (convert == EINA_VALUE_TYPE_STRINGSHARE || + convert == EINA_VALUE_TYPE_STRING) + { + const char *type = eina_content_type_get(*ra); + if (eina_streq(type, "text/plain;charset=utf-8")) + { + Eina_Slice data = eina_content_data_get(*ra); + return eina_value_type_pset(convert, convert_mem, &data.mem); + } + else + { + Eina_Iterator *iter = eina_content_possible_conversions(*ra); + const char *type; + + EINA_ITERATOR_FOREACH(iter, type) + { + if (eina_streq(type, "text/plain;charset=utf-8")) + { + Eina_Content *conv_result = eina_content_convert(*ra, type); + + Eina_Slice data = eina_content_data_get(conv_result); + Eina_Bool success = eina_value_type_pset(convert, convert_mem, &data.mem); + eina_content_free(conv_result); + return success; + } + } + //create some fallback + { + char buf[PATH_MAX]; + char *tmp = (char*) &buf; + snprintf(buf, sizeof(buf), "Content %p cannot be converted to \"text/plain;charset=utf-8\"", *ra); + return eina_value_type_pset(convert, convert_mem, &tmp); + } + } + } + return EINA_FALSE; +} + +static Eina_Bool +_eina_value_type_content_convert_from(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert EINA_UNUSED, void *type_mem EINA_UNUSED, const void *convert_mem EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Bool +_eina_value_type_content_pset(const Eina_Value_Type *type EINA_UNUSED, void *mem, const void *ptr) +{ + Eina_Content * const *srcc = ptr; + Eina_Content **dstc = mem; + + *dstc = *srcc; + _eina_content_ref(*dstc); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_vset(const Eina_Value_Type *type EINA_UNUSED, void *mem, va_list args) +{ + Eina_Content **dst = mem; + Eina_Content *content = va_arg(args, Eina_Content*); + + *dst = content; + _eina_content_ref(*dst); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_pget(const Eina_Value_Type *type EINA_UNUSED, const void *mem, void *ptr) +{ + Eina_Content * const *src = mem; + Eina_Content **dst = ptr; + + *dst = *src; + _eina_content_ref(*dst); + return EINA_TRUE; +} + +EAPI const Eina_Value_Type _EINA_VALUE_TYPE_CONTENT ={ + EINA_VALUE_TYPE_VERSION, + sizeof(Eina_Content*), + "Eina_Abstract_Content", + _eina_value_type_content_setup, + _eina_value_type_content_flush, + _eina_value_type_content_copy, + _eina_value_type_content_compare, + _eina_value_type_content_convert_to, + _eina_value_type_content_convert_from, + _eina_value_type_content_vset, + _eina_value_type_content_pset, + _eina_value_type_content_pget +}; + +static void +_free_node(void *v) +{ + Eina_Content_Conversion_Node *n; + EINA_LIST_FREE(v, n) + { + eina_stringshare_del(n->to); + free(n); + } +} + +Eina_Bool +eina_abstract_content_init(void) +{ + _eina_abstract_content_log_domain = eina_log_domain_register("eina_abstract_content", "white"); + conversion_callbacks = eina_hash_stringshared_new(_free_node); + + EINA_VALUE_TYPE_CONTENT = &_EINA_VALUE_TYPE_CONTENT; + + // text/plain is assumed to be charset "US-ASCII" + + eina_content_converter_conversion_register("text/plain", "text/plain;charset=utf-8", _copy_converter); + eina_content_converter_conversion_register("text/plain", "text/plain;charset=iso-8859-1", _copy_converter); + eina_content_converter_conversion_register("text/plain;charset=iso-8859-1", "text/plain;charset=utf-8", _latin1_to_utf8_converter); + eina_content_converter_conversion_register("text/plain;charset=iso-8859-1", "text/plain", _copy_converter); + + return EINA_TRUE; +} + +Eina_Bool +eina_abstract_content_shutdown(void) +{ + eina_hash_free(conversion_callbacks); + + return EINA_TRUE; +} + +Eina_Value* +eina_value_content_new(Eina_Content *content) +{ + Eina_Value *v = eina_value_new(EINA_VALUE_TYPE_CONTENT); + + eina_value_pset(v, &content); + return v; +} + + +Eina_Value +eina_value_content_init(Eina_Content *content) +{ + Eina_Value v; + + eina_value_setup(&v, EINA_VALUE_TYPE_CONTENT); + eina_value_pset(&v, &content); + + return v; +} + + +Eina_Content* +eina_value_to_content(const Eina_Value *value) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_get(value) == EINA_VALUE_TYPE_CONTENT, NULL); + Eina_Content *result = calloc(1, sizeof(Eina_Content)); + eina_value_pget(value, &result); + return result; +} diff --git a/src/lib/eina/eina_abstract_content.h b/src/lib/eina/eina_abstract_content.h new file mode 100644 index 0000000000..1436543f4e --- /dev/null +++ b/src/lib/eina/eina_abstract_content.h @@ -0,0 +1,154 @@ +#ifndef EINA_ABSTRACT_CONTENT_H +#define EINA_ABSTRACT_CONTENT_H + + +/** + * @typedef Eina_Content + * Defines a abstract content segment + * + * Each Abstract content contains out of a Eina_Slice of memory. And a type. + * The type are IANA meme types. + * + * @note if the type is a text-style type, the last byte of the slice must be \0 + * + * @since 1.24 + */ +typedef struct _Eina_Content Eina_Content; + +/** + * @typedef Eina_Content_Convertion_Callback + * + * Callback called when convertion from one type to another type is requested. + * The from and to type is specified when the callback is registered. + * The to type is also passed in the callback here. + * The type of the from pointer does not need to be checked. + */ +typedef Eina_Content* (*Eina_Content_Conversion_Callback)(Eina_Content *from, const char *to_type); + +/** + * Get the path to a file, containing the slice memory as content. + * + * @param[in] content The content that will be in the file. + * + * @return The path to the file. Do not free this. + * + */ +EAPI const char* eina_content_as_file(Eina_Content *content); + +/** + * Convert the content of the object to another type. + * + * In case the convertion cannot be performaned, NULL is returned. + * + * @param[in] content The content to convert. + * @param[in] new_type The new type the returned content will have. + * + * @return A new content object. The caller of this function is owning this. + */ +EAPI Eina_Content* eina_content_convert(Eina_Content *content, const char *new_type); + +/** + * Get the type of the passed content. + * + * @param[in] content The content to fetch the type from. + * + * @return The type of this content. Do no free this. + */ +EAPI const char* eina_content_type_get(Eina_Content *content); + +/** + * Get the type of the passed content. + * + * @param[in] content The content to fetch the type from. + * + * @return The path to the file. Do not free this. + */ +EAPI const Eina_Slice eina_content_data_get(Eina_Content *content); + +/** + * Create a new content object, with the slice of data with a specific type. + * + * @param[in] data A slice of memory, the memory is duplicated. + * @param[in] type The type of memory. + * + * @return The new content object. The caller owns this object. + */ +EAPI Eina_Content* eina_content_new(Eina_Slice data, const char *type); + +/** + * Free the content object. + * + * @param[in] content The content to free. + */ +EAPI void eina_content_free(Eina_Content *content); + +/** + * Register a new conversion callback. + * + * @param[in] from The tyoe you convert from. + * @param[in] in The type you convert to. + * + * @return True on success false otherwise. + */ +EAPI Eina_Bool eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback convertion); + +/** + * Check if a specific convertion can be performanced. + * + * A convertion can only be performed if a callback is registered. + * + * @param[in] from The type you convert from. + * @param[in] in The type you convert to. + * + * @return True if it can be performed, false if not. + */ +EAPI Eina_Bool eina_content_converter_convert_can(const char *from, const char *to); + +/** + * Returns a iterator that can be used to find all the possible types that can be converted to. + * + * @param[in] form The type you convert from + * + * @return A Iterator, containing strings, free this via eina_iterator_free. + */ +EAPI Eina_Iterator* eina_content_converter_possible_conversions(const char *from); + +EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT; + +/** + * Convert the Eina_Content object to a Eina_Value. + * + * @param[in] content The Eina_Content struct that will be converted to a Eina_Value + * + * @return A Eina_Value that is allocated, you need to free it. + */ +EAPI Eina_Value* eina_value_content_new(Eina_Content *content); + +/** + * Convert the Eina_Content object to a Eina_Value. + * + * @param[in] content The Eina_Content struct that will be converted to a Eina_Value + * + * @return A Eina_Value with type EINA_VALUE_TYPE_CONTENT + */ +EAPI Eina_Value eina_value_content_init(Eina_Content *content); + +/** + * Get the content from the Eina_Value + * + * If the value is not of the type EINA_VALUE_TYPE_CONTENT, NULL will be returned and a error will be printed. + * + * @param[in] value The value to get the content from + * + * @return A allocated Eina_Content, you need to free it. + */ +EAPI Eina_Content* eina_value_to_content(const Eina_Value *value); + + +static inline Eina_Iterator* +eina_content_possible_conversions(Eina_Content *content) +{ + return eina_content_converter_possible_conversions(eina_content_type_get(content)); +} + +#endif diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c index b8856474d3..47dd80a898 100644 --- a/src/lib/eina/eina_main.c +++ b/src/lib/eina/eina_main.c @@ -154,6 +154,7 @@ extern Eina_Lock _sysmon_lock; S(slstr); S(promise); S(vpath); + S(abstract_content); #undef S struct eina_desc_setup @@ -202,6 +203,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = { S(safepointer), S(slstr), S(promise), + S(abstract_content) #undef S }; static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / diff --git a/src/lib/eina/eina_slice.h b/src/lib/eina/eina_slice.h index a354eaa566..a597fe281e 100644 --- a/src/lib/eina/eina_slice.h +++ b/src/lib/eina/eina_slice.h @@ -464,6 +464,30 @@ static inline char *eina_rw_slice_strdup(const Eina_Rw_Slice rw_slice); #else #define EINA_SLICE_STR(str) {.len = strlen((str)), .mem = (str)} #endif +/** + * @def EINA_SLICE_STR_FULL(str) + * + * Same as EINA_SLICE_STR_FULL, but it also contains the \0 element of the string + * + * @param[in] str The string to create the slice from. + * @return The initialized slice object. + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * Eina_Slice ro_slice = EINA_SLICE_STR_FULL("hello world"); + * @endcode + * + * @see EINA_SLICE_STR_FULL() for specific version using literals. + * + * @since 1.24 + */ +#ifdef __cplusplus +#define EINA_SLICE_STR_FULL(str) {strlen((str)) + 1, (str)} +#else +#define EINA_SLICE_STR_FULL(str) {.len = strlen((str)) + 1, .mem = (str)} +#endif + /** * @def EINA_SLICE_STR_FMT diff --git a/src/lib/eina/meson.build b/src/lib/eina/meson.build index 97e1669c4f..d3d30fcf43 100644 --- a/src/lib/eina/meson.build +++ b/src/lib/eina/meson.build @@ -107,6 +107,7 @@ public_sub_headers = [ 'eina_freeq.h', 'eina_slstr.h', 'eina_vpath.h', +'eina_abstract_content.h' ] public_headers = [ @@ -188,7 +189,8 @@ sources = [ 'eina_freeq.c', 'eina_slstr.c', 'eina_vpath.c', -'eina_vpath_xdg.c' +'eina_vpath_xdg.c', +'eina_abstract_content.c', ] if sys_windows == true diff --git a/src/tests/eina/eina_suite.c b/src/tests/eina/eina_suite.c index 45316bd462..01ed82a532 100644 --- a/src/tests/eina/eina_suite.c +++ b/src/tests/eina/eina_suite.c @@ -90,6 +90,7 @@ static const Efl_Test_Case etc[] = { { "slstr", eina_test_slstr }, { "Vpath", eina_test_vpath }, { "debug", eina_test_debug }, + { "Abstract Content", eina_test_abstract_content }, { NULL, NULL } }; diff --git a/src/tests/eina/eina_suite.h b/src/tests/eina/eina_suite.h index 102de63193..84d6e60516 100644 --- a/src/tests/eina/eina_suite.h +++ b/src/tests/eina/eina_suite.h @@ -78,5 +78,6 @@ void eina_test_freeq(TCase *tc); void eina_test_slstr(TCase *tc); void eina_test_vpath(TCase *tc); void eina_test_debug(TCase *tc); +void eina_test_abstract_content(TCase *tc); #endif /* EINA_SUITE_H_ */ diff --git a/src/tests/eina/eina_test_abstract_content.c b/src/tests/eina/eina_test_abstract_content.c new file mode 100644 index 0000000000..d2270ddaad --- /dev/null +++ b/src/tests/eina/eina_test_abstract_content.c @@ -0,0 +1,223 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include "eina_suite.h" + +EFL_START_TEST(eina_test_content_create_destroy) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + ck_assert_int_eq(eina_content_data_get(content).len, strlen(text_str) + 1); + ck_assert_str_eq(eina_content_data_get(content).mem, text_str); + + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_as_file) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_File *f; + const char *file_path = eina_content_as_file(content); + + f = eina_file_open(file_path, EINA_FALSE); + const char *file_content = eina_file_map_all(f, EINA_FILE_POPULATE); + ck_assert_str_eq(file_content, text_str); + eina_file_close(f); + + eina_content_free(content); + + const char *file_path2 = eina_content_as_file(content); + ck_assert_str_eq(file_path, file_path2); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_none_existing) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + + EXPECT_ERROR_START; + ck_assert_ptr_eq(eina_content_convert(content, "ThisIsReallyNotHere"), NULL); + EXPECT_ERROR_END; +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_ascii_to_utf8) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=utf-8"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=utf-8"); + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_ascii_to_latin) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=iso-8859-1"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=iso-8859-1"); + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_utf8_to_latin) +{ + //this means AÄÜÖß + const char text_str[] = {'A', 0xc3, 0x84, 0xc3, 0x9c, 0xc3, 0x96, 0xc3, 0x9f, 0}; + const char text_str_latin[] = {'A', 0xC4, 0xDC, 0xD6, 0xDF, 0}; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str_latin), "text/plain;charset=iso-8859-1"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=utf-8"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=utf-8"); + ck_assert_int_eq(sizeof(text_str), eina_content_data_get(c).len); + for (unsigned int i = 0; i < eina_content_data_get(c).len; ++i) + { + ck_assert_int_eq(text_str[i], ((char*)eina_content_data_get(c).mem)[i]); + } + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_possible_converstions) +{ + ck_assert_int_eq(eina_content_converter_convert_can("text/plain", "text/plain;charset=utf-8"), 1); + ck_assert_int_eq(eina_content_converter_convert_can("text/plain", "ThisDoesNotExist"), 0); + ck_assert_int_eq(eina_content_converter_convert_can("ThisDoesNotExist", "text/plain;charset=utf-8"), 0); + Eina_Iterator *iterator = eina_content_converter_possible_conversions("text/plain"); + char *text; + int i = 0, j = 0; + + EINA_ITERATOR_FOREACH(iterator, text) + { + if (eina_streq(text, "text/plain;charset=utf-8")) + i ++; + if (eina_streq(text, "text/plain;charset=iso-8859-1")) + j ++; + } + ck_assert_int_eq(i, 1); + ck_assert_int_eq(j, 1); + eina_iterator_free(iterator); +} +EFL_END_TEST + +static Eina_Bool getting_called = EINA_FALSE; + +static Eina_Content* +_test_cb(Eina_Content *content EINA_UNUSED, const char *type EINA_UNUSED) +{ + getting_called = EINA_TRUE; + return eina_content_new(eina_content_data_get(content), type); +} + +EFL_START_TEST(eina_test_register_illegal) +{ + const char *test_str = "AbCdEfG"; + eina_content_converter_conversion_register("Test", "Test2", _test_cb); + EXPECT_ERROR_START; + eina_content_converter_conversion_register("Test", "Test2", _test_cb); + EXPECT_ERROR_END; + + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(test_str), "Test"); + Eina_Content *c2 = eina_content_convert(c, "Test2"); + ck_assert_ptr_ne(c2, NULL); + ck_assert_int_eq(getting_called, EINA_TRUE); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value) +{ + const char *str_a = "All"; + const char *str_b = "Out"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Content *b = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_b), "text/plain"); + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Content *d = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "Not_Text"); + Eina_Value *va = eina_value_content_new(a); + Eina_Value *vb = eina_value_content_new(b); + Eina_Value *vc = eina_value_content_new(c); + Eina_Value *vd = eina_value_content_new(d); + Eina_Value *vcopy = eina_value_new(EINA_VALUE_TYPE_CONTENT); + Eina_Content *content; + + ck_assert_int_eq(eina_value_compare(va, vc), 0); + ck_assert_int_ne(eina_value_compare(va, vb), 0); + ck_assert_int_ne(eina_value_compare(va, vd), 0); + ck_assert_int_eq(eina_value_compare(vd, vd), 0); + + ck_assert_int_eq(eina_value_copy(va, vcopy), 1); + ck_assert_int_eq(eina_value_compare(va, vcopy), 0); + + content = eina_value_to_content(vcopy); + Eina_Slice slice = eina_content_data_get(content); + ck_assert_int_eq(slice.len, strlen(str_a) + 1); + ck_assert_str_eq(slice.mem, str_a); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value_set) +{ + const char *str_a = "All"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Value *acopy = eina_value_new(EINA_VALUE_TYPE_CONTENT); + Eina_Content *content; + + eina_value_set(acopy, a); + content = eina_value_to_content(acopy); + Eina_Slice slice = eina_content_data_get(content); + ck_assert_int_eq(slice.len, strlen(str_a) + 1); + ck_assert_str_eq(slice.mem, str_a); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value_convertion) +{ + const char *str_a = "All"; + const char *str_b = "Out"; + const char *str_c = "Life"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain;charset=utf-8"); + Eina_Content *b = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_b), "text/plain"); + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_c), "application/x-elementary-markup"); + Eina_Value *av = eina_value_content_new(a); + Eina_Value *bv = eina_value_content_new(b); + Eina_Value *cv = eina_value_content_new(c); + + ck_assert_str_eq(eina_value_to_string(av), str_a); + ck_assert_str_eq(eina_value_to_string(bv), str_b); + ck_assert_str_ne(eina_value_to_string(cv), str_c); +} +EFL_END_TEST + +void +eina_test_abstract_content(TCase *tc) +{ + tcase_add_test(tc, eina_test_content_create_destroy); + tcase_add_test(tc, eina_test_content_as_file); + tcase_add_test(tc, eina_test_content_convert_none_existing); + tcase_add_test(tc, eina_test_content_convert_ascii_to_utf8); + tcase_add_test(tc, eina_test_content_convert_ascii_to_latin); + tcase_add_test(tc, eina_test_content_convert_utf8_to_latin); + tcase_add_test(tc, eina_test_content_possible_converstions); + tcase_add_test(tc, eina_test_register_illegal); + tcase_add_test(tc, eina_test_content_value); + tcase_add_test(tc, eina_test_content_value_set); + tcase_add_test(tc, eina_test_content_value_convertion); +} diff --git a/src/tests/eina/meson.build b/src/tests/eina/meson.build index f755be4c2a..18c8f91ced 100644 --- a/src/tests/eina/meson.build +++ b/src/tests/eina/meson.build @@ -54,7 +54,8 @@ eina_test_src = files( 'eina_test_slice.c', 'eina_test_freeq.c', 'eina_test_slstr.c', -'eina_test_vpath.c' +'eina_test_vpath.c', +'eina_test_abstract_content.c', ) From 39f3ce42dcde447779cb1583501b681ba85d86d4 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Sun, 5 Jan 2020 15:05:36 +0100 Subject: [PATCH 02/17] ecore_evas: Introduce cnp / dnd API for ecore evas The idea of copy and paste here is: - The user specifies the content he wants to have in the selection buffer with a Eina_Content, these content pointer ownerships are passed to the called. Internally ecore_evas code will memorieze the pointer, and pass on function callbacks to the modules, which then do not have to deal with the ownership. - In case the module does not specify these APIs, the callback implementation will be called, which only works for cnp *not* dnd. - Action and mime types are handled as strings, which allows way better custom organisations. (The docs needs improvement) Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11192 --- src/lib/ecore_evas/Ecore_Evas.h | 214 +++++++++++ src/lib/ecore_evas/ecore_evas.c | 362 +++++++++++++++++- .../ecore_evas_fallback_selection.c | 115 ++++++ src/lib/ecore_evas/ecore_evas_private.h | 53 ++- src/lib/ecore_evas/meson.build | 3 +- src/lib/elementary/meson.build | 2 +- .../ecore_evas/engines/sdl/ecore_evas_sdl.c | 3 + .../wayland/ecore_evas_wayland_common.c | 7 +- .../engines/win32/ecore_evas_win32.c | 3 + .../ecore_evas/engines/x/ecore_evas_x.c | 73 ++-- src/tests/ecore/ecore_suite.c | 1 + src/tests/ecore/ecore_suite.h | 1 + src/tests/ecore/ecore_test_ecore_evas.c | 44 +++ .../ecore/ecore_test_ecore_evas_selection.c | 89 +++++ src/tests/ecore/meson.build | 1 + .../elementary/efl_ui_window_cnp_dnd_slave.c | 191 +++++++++ src/tests/elementary/meson.build | 5 + 17 files changed, 1120 insertions(+), 47 deletions(-) create mode 100644 src/lib/ecore_evas/ecore_evas_fallback_selection.c create mode 100644 src/tests/ecore/ecore_test_ecore_evas_selection.c create mode 100644 src/tests/elementary/efl_ui_window_cnp_dnd_slave.c diff --git a/src/lib/ecore_evas/Ecore_Evas.h b/src/lib/ecore_evas/Ecore_Evas.h index d59900d788..ddc3622741 100644 --- a/src/lib/ecore_evas/Ecore_Evas.h +++ b/src/lib/ecore_evas/Ecore_Evas.h @@ -3669,6 +3669,219 @@ EAPI unsigned long ecore_evas_pixmap_colormap_get(const Ecore_Evas *ee); */ EAPI int ecore_evas_pixmap_depth_get(const Ecore_Evas *ee); +typedef enum { + ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER = 0, /**< Stores selected / highlighted selection */ + ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER = 1, /**< Stores copied things (Ctrl + C) */ + ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER = 2, /**< Stores dragged things while drag and drop is happening. */ + ECORE_EVAS_SELECTION_BUFFER_LAST = 3, +} Ecore_Evas_Selection_Buffer; + +/** + * @brief Callback called when the content of one of the selection buffers changes. + * + * @param[in] ee The Ecore_Evas that handles this selection. + * @param[in] selection The selection buffer that has changed. + */ +typedef void (*Ecore_Evas_Selection_Changed_Cb)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); + +/** + * @brief Sets a callback for Ecore_Evas to be called when a selection buffer changes. + * + * @param[in] ee The Ecore_Evas to set the callback on. + * @param[in] cb The function to call. + * + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee selections change. + * Only one such callback can exist for each Ecore_Evas. Calling this method multiple + * times overwrites previous functions. Use a NULL @p func to stop being notified. + * + * You will not be notified about selection changes caused by yourself. (TODO: bu5hm4n?) + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_selection_changed_set(Ecore_Evas *ee, Ecore_Evas_Selection_Changed_Cb cb); + +/** + * @brief Sets the content of the specified selection buffer. + * + * @param[in] ee The Ecore_Evas to set the selection buffer on. + * @param[in] buffer The selection buffer to set. + * @param[in] content Content to set to the selection buffer. The Eina_Content specifies the MIME type of the data. + * Ownership of the content is transferred. + * + * @note Only ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER and ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER + * buffers can be set. Drag and drop operations use a different set of methods. + */ +EAPI Eina_Bool ecore_evas_selection_set(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, Eina_Content *content); + +/** + * @brief Checks if the specified selection buffer has content. + * + * @param[in] ee The ecore evas to query + * @param[in] buffer Which selection buffer to ask + * + * @return EINA_TRUE if there is an available selection for the specified buffer. + * + * EINA_TRUE is also returned when the selection is in the window associated with @p ee + * + * @note Due to the asynchronous nature of selection buffers, this method might not return + * the right result when invoked from the selection callback set with ecore_evas_callback_selection_changed_set. + */ +EAPI Eina_Bool ecore_evas_selection_exists(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer); + +/** + * @brief Retrieves the content of the specified selection buffer. + * + * @param[in] ee The ecore evas to query. + * @param[in] buffer Selection buffer to retrieve. + * @param[in] acceptable_types MIME types which are acceptable for the returned Eina_Content. + * The iterator contains plain strings (char *). Ownership is transferred for the iterator but not for the strings. + * This is convenient for the usual case of a hard-coded array of strings, since the iterator can be generated + * on the fly, used and forgotten. + * + * @return An Eina_Future containing an Eina_Content which has one of the types in @p acceptable_type. + * An error is delivered when no matching type is found or when the requested selection buffer is empty. + * + * This method is time consuming, therefore, it is recommended to verify the existence of a selection + * using ecore_evas_selection_exists before calling it. + */ +EAPI Eina_Future* ecore_evas_selection_get(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, Eina_Iterator *acceptable_types); + +/** + * @brief This method is called when the mouse pointer enters or exits the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] p Position (in window coordinates) where the event occurred. + * @param[in] inside @c EINA_TRUE if the pointer just entered this window. @c EINA_FALSE if it has just exited. + * + * Set this callback using ecore_evas_callback_drop_state_changed_set. + */ +typedef void (*Ecore_Evas_Drag_Finished)(Ecore_Evas *ee, unsigned int seat, void *data, Eina_Bool accepted); + +/** + * @brief Starts a new drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] content The content to delivery at the drop site (ownership is transferred). + * The Eina_Content has data and its associated MIME type, plus a list of alternate types that can be provided. + * @param[in] drag_rep An Ecore_Evas used as a visual representation of the content being dragged. + * It must have the same type as @p ee. This is the transparent object dragged along the mouse pointer to indicate that + * a drag operation is in progress. + * @p terminate_cb will be called when @p drag_rep is not needed anymore and it must be disposed of. + * Use @p data to convey @p drag_rep to @p terminate_cb. For example, if @p drag_rep is owned by an Efl_Window, @p data + * can point to that window. + * @param[in] action Action the target application should perform upon receiving this content. It is entirely up to the + * target application to honor (or even understand) this request. + * @return @c EINA_TRUE if the drag operation has been successfully started. + * + * This method must be called when a drag operation is initiated in order to provide the necessary information. + */ +EAPI Eina_Bool ecore_evas_drag_start(Ecore_Evas *ee, unsigned int seat, Eina_Content *content, Ecore_Evas *drag_rep, const char* action, Ecore_Evas_Drag_Finished terminate_cb, void *data); + +/** + * @brief Cancels an ongoing drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @return @c EINA_TRUE if the drag operation has been successfully cancelled. + * + * The initiator of a drag operation can call this method to abort it. + */ +EAPI Eina_Bool ecore_evas_drag_cancel(Ecore_Evas *ee, unsigned int seat); + +/** + * @brief This method is called when the mouse pointer enters or exits the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] p Position (in window coordinates) where the event occurred. + * @param[in] inside @c EINA_TRUE if the pointer just entered this window. @c EINA_FALSE if it has just exited. + * + * Set this callback using ecore_evas_callback_drop_state_changed_set. + */ +typedef void (*Ecore_Evas_State_Changed)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, Eina_Bool inside); + +/** + * @brief Sets the method (callback) to call when the mouse pointer enters or exits the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] cb Method to call when the events are received. + * + * Only one such callback can exist for each Ecore_Evas. Calling this method multiple + * times overwrites previous functions. Use a NULL @cb func to stop being notified. + */ +EAPI void ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_State_Changed cb); + +/** + * @brief This method is called when the mouse pointer moves over the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] p Position (in window coordinates) where the event occurred. + * + * Set this callback using ecore_evas_callback_drop_motion_set. + */ + +typedef void (*Ecore_Evas_Motion_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p); +/** + * @brief Sets the method (callback) to call when the mouse pointer moves over the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] cb Method to call when the events are received. + * + * Only one such callback can exist for each Ecore_Evas. Calling this method multiple + * times overwrites previous functions. Use a NULL @cb func to stop being notified. + */ +EAPI void ecore_evas_callback_drop_motion_set(Ecore_Evas *ee, Ecore_Evas_Motion_Cb cb); + +/** + * @brief This method is called when the mouse pointer is released over the specified window while + * performing a drag operation (thus dropping the dragged content over the window). + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] p Position (in window coordinates) where the event occurred. + * + * The dropped data can be retrieved using ecore_evas_selection_get and the + * ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER buffer. + * + * Set this callback using ecore_evas_callback_drop_drop_set. + */ +typedef void (*Ecore_Evas_Drop_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, const char *action); + +/** + * @brief Sets the method (callback) to call when the mouse pointer is released over the specified window while + * performing a drag operation (thus dropping the dragged content over the window). + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] cb Method to call when the events are received. + * + * Only one such callback can exist for each Ecore_Evas. Calling this method multiple + * times overwrites previous functions. Use a NULL @cb func to stop being notified. + */ +EAPI void ecore_evas_callback_drop_drop_set(Ecore_Evas *ee, Ecore_Evas_Drop_Cb cb); + +// app calls this (from one of the motion cb's, for example) to know the type (and auto conversion) of the thing being dragged. +// This is the same as calling selection_get and retrieving the types from there (but faster). +/** + * @brief Retrieves the list of types the data currently being dragged can be automatically converted to. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @return + * + * This can be used in any of the drag and drop callbacks (Ecore_Evas_State_Changed, Ecore_Evas_Motion_Cb and + * Ecore_Evas_Drop_Cb) to check if the data being dragged is acceptable and give the user some early feedback + * before the data is actually dropped on the window. + * + * This is functionally equivalent to calling ecore_evas_selection_get and examining the available types in the + * returned Eina_Content, but much faster since the actual data does not have to be asynchronously requested to the + * initiator application. + */ +EAPI Eina_Accessor* ecore_evas_drop_available_types_get(Ecore_Evas *ee, unsigned int seat); + + /** * @} */ @@ -3685,3 +3898,4 @@ EAPI int ecore_evas_pixmap_depth_get(const Ecore_Evas *ee); #define EAPI #endif + diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c index d3c26ddb19..a95f7903d8 100644 --- a/src/lib/ecore_evas/ecore_evas.c +++ b/src/lib/ecore_evas/ecore_evas.c @@ -652,6 +652,10 @@ ecore_evas_init(void) iface.del = _ecore_evas_animator_del; ecore_evas_object_animator_init(&iface); + ecore_evas_no_matching_type = eina_error_msg_register("No fitting type could be found"); + ecore_evas_no_selection = eina_error_msg_register("No selection available"); + ecore_evas_request_replaced = eina_error_msg_register("Selection request replaced"); + return _ecore_evas_init_count; shutdown_ecore: @@ -2818,7 +2822,7 @@ ecore_evas_shadow_geometry_get(const Ecore_Evas *ee, int *l, int *r, int *t, int if (b) *b = ee->shadow.b; } -EAPI void +EAPI void ecore_evas_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) { if (x) *x = 0; @@ -2828,7 +2832,7 @@ ecore_evas_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) IFE; } -EAPI Eina_Bool +EAPI Eina_Bool ecore_evas_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y) { ECORE_EVAS_CHECK(ee, EINA_FALSE); @@ -2905,7 +2909,7 @@ ecore_evas_pixmap_visual_get(const Ecore_Evas *ee) return NULL; } -EAPI unsigned long +EAPI unsigned long ecore_evas_pixmap_colormap_get(const Ecore_Evas *ee) { ECORE_EVAS_CHECK(ee, 0); @@ -2932,7 +2936,7 @@ ecore_evas_pixmap_colormap_get(const Ecore_Evas *ee) return 0; } -EAPI int +EAPI int ecore_evas_pixmap_depth_get(const Ecore_Evas *ee) { ECORE_EVAS_CHECK(ee, 0); @@ -3524,6 +3528,9 @@ _ecore_evas_free(Ecore_Evas *ee) free(iface); ee->engine.ifaces = NULL; + + if (ee->fallback_interface) + fallback_selection_shutdown(ee); free(ee); } @@ -3542,7 +3549,7 @@ _ecore_evas_idle_timeout_update(Ecore_Evas *ee) { if (ee->engine.idle_flush_timer) ecore_timer_del(ee->engine.idle_flush_timer); - ee->engine.idle_flush_timer = + ee->engine.idle_flush_timer = ecore_timer_loop_add(IDLE_FLUSH_TIME, _ecore_evas_cb_idle_flush, ee); } @@ -4007,7 +4014,7 @@ ecore_evas_software_x11_pixmap_new(const char *disp_name, Ecore_X_Window parent, } -EAPI Ecore_X_Pixmap +EAPI Ecore_X_Pixmap ecore_evas_software_x11_pixmap_get(const Ecore_Evas *ee) { Ecore_Evas_Interface_Software_X11 *iface; @@ -4082,7 +4089,7 @@ ecore_evas_gl_x11_pixmap_new(const char *disp_name, Ecore_X_Window parent, int x } -EAPI Ecore_X_Pixmap +EAPI Ecore_X_Pixmap ecore_evas_gl_x11_pixmap_get(const Ecore_Evas *ee) { Ecore_Evas_Interface_Gl_X11 *iface; @@ -5449,3 +5456,344 @@ _ecore_evas_animator_thaw(Ecore_Animator *in) EINA_INLIST_GET(animator)); _ticking_start(ee); } + +EAPI void +ecore_evas_callback_selection_changed_set(Ecore_Evas *ee, Ecore_Evas_Selection_Changed_Cb func) +{ + ECORE_EVAS_CHECK(ee); + ee->func.fn_selection_changed = func; +} + +static Ecore_Evas_Selection_Seat_Buffers* +_fetch_selection_buffers_of_seat(Ecore_Evas *ee, unsigned int seat, Eina_Bool create) +{ + Ecore_Evas_Selection_Seat_Buffers *buffers; + if (!ee->selection_buffers) + ee->selection_buffers = eina_hash_int32_new(free); + + buffers = eina_hash_find(ee->selection_buffers, &seat); + + if (!buffers && create) + { + buffers = calloc(1, sizeof(Ecore_Evas_Selection_Seat_Buffers)); + buffers->seat = seat; + eina_hash_add(ee->selection_buffers, &seat, buffers); + } + return buffers; +} + +static Eina_Bool +_deliver_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice) +{ + Ecore_Evas_Selection_Seat_Buffers *buffers; + Eina_Content *content; + Eina_Content *converted = NULL; + Eina_Bool result = EINA_FALSE; + + INF("Delivery request on seat %d in buffer %d", seat, buffer); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_FALSE); + EINA_SAFETY_ON_NULL_GOTO(buffers, free_everything); + content = buffers->selection_buffer[buffer]; + EINA_SAFETY_ON_NULL_GOTO(content, free_everything); + if (!eina_streq(type, eina_content_type_get(content))) + converted = eina_content_convert(content, type); + else + converted = content; + + EINA_SAFETY_ON_NULL_GOTO(converted, free_everything); + *slice = eina_slice_dup(eina_content_data_get(converted)); + result = EINA_TRUE; + + if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + ee->drag.accepted = EINA_TRUE; + } + +free_everything: + if (converted && content && !eina_streq(type, eina_content_type_get(content))) + eina_content_free(converted); + + return result; +} + +static void +_cancel_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer) +{ + Ecore_Evas_Selection_Seat_Buffers *buffers; + + INF("Cancel request on seat %d in buffer %d", seat, buffer); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN(buffers); + EINA_SAFETY_ON_FALSE_RETURN(buffers->selection_buffer[buffer]); + eina_content_free(buffers->selection_buffer[buffer]); + buffers->selection_buffer[buffer] = NULL; + + if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + ee->drag.rep = NULL; + if (ee->drag.free) + ee->drag.free(ee, seat, ee->drag.data, EINA_FALSE); + ee->drag.free = NULL; + } +} + +#define CALL(call) (ee->engine.func->fn_ ##call ? : fallback_ ##call) + +static Eina_Array* +_iterator_to_array(Eina_Iterator *iter, const char *existing_type) +{ + Eina_Array *ret = eina_array_new(10); + const char *type; + + if (existing_type) + eina_array_push(ret, existing_type); + + EINA_ITERATOR_FOREACH(iter, type) + { + eina_array_push(ret, type); + } + eina_iterator_free(iter); + + return ret; +} + +EAPI Eina_Bool +ecore_evas_selection_set(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, Eina_Content *content) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffer >= 0 && buffer < ECORE_EVAS_SELECTION_BUFFER_LAST, EINA_FALSE); + Eina_Iterator *available_type = NULL; + Eina_Bool success; + Ecore_Evas_Selection_Seat_Buffers *buffers; + + INF("Selection set on seat %d in buffer %d", seat, buffer); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_TRUE); + + if (content) + available_type = eina_content_possible_conversions(content); + + if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + ERR("You cannot set a selection with this API, please use the API to start a drag operation"); + return EINA_FALSE; + } + + success = CALL(selection_claim)(ee, seat, buffer, _iterator_to_array(available_type, content ? eina_content_type_get(content) : NULL), content ? _deliver_cb : NULL, content ? _cancel_cb : NULL); + if (success) + { + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffers->selection_buffer[buffer] == NULL, EINA_FALSE); + //keep this after the claim, the claim might call cancel, which would overwrite this. + buffers->selection_buffer[buffer] = content; + } + else + { + eina_content_free(content); + } + + return success; +} + +EAPI Eina_Bool +ecore_evas_selection_exists(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffer >= 0 && buffer < ECORE_EVAS_SELECTION_BUFFER_LAST, EINA_FALSE); + Ecore_Evas_Selection_Seat_Buffers *buffers; + + INF("Exists request on seat %d in buffer %d", seat, buffer); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_TRUE); + if (buffers->selection_buffer[buffer]) + return EINA_TRUE; + else + { + return CALL(selection_has_owner)(ee, seat, buffer); + } +} + +static Eina_Array* +_iterator_to_array_stringshared(Eina_Iterator *iter) +{ + Eina_Array *ret = eina_array_new(10); + const char *type; + + EINA_ITERATOR_FOREACH(iter, type) + { + eina_array_push(ret, eina_stringshare_add(type)); + } + eina_iterator_free(iter); + + return ret; +} + +EAPI Eina_Future* +ecore_evas_selection_get(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, Eina_Iterator *acceptable_types) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, NULL); + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffer >= 0 && buffer < ECORE_EVAS_SELECTION_BUFFER_LAST, NULL); + + INF("Selection get request on seat %d in buffer %d", seat, buffer); + + return CALL(selection_request)(ee, seat, buffer, _iterator_to_array_stringshared(acceptable_types)); +} + +EAPI Eina_Bool +ecore_evas_drag_start(Ecore_Evas *ee, unsigned int seat, Eina_Content *content, Ecore_Evas *drag_rep, const char* action, Ecore_Evas_Drag_Finished terminate_cb, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(content, EINA_FALSE); + Eina_Iterator *available_type = eina_content_possible_conversions(content); + Eina_Bool success; + Ecore_Evas_Selection_Seat_Buffers *buffers; + + INF("Drag start on seat %d", seat); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_TRUE); + success = CALL(dnd_start)(ee, seat, _iterator_to_array(available_type, eina_content_type_get(content)), drag_rep, _deliver_cb, _cancel_cb, action); + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffers->selection_buffer[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER] == NULL, EINA_FALSE); + //keep this after the claim, the claim might call cancel, which would overwrite this. + buffers->selection_buffer[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER] = content; + + ee->drag.rep = drag_rep; + ee->drag.free = terminate_cb; + ee->drag.data = data; + ee->drag.accepted = EINA_FALSE; + + return success; +} + +EAPI Eina_Bool +ecore_evas_drag_cancel(Ecore_Evas *ee, unsigned int seat) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); + + INF("Drag cancel on seat %d", seat); + + return CALL(dnd_stop)(ee, seat); +} + +EAPI void +ecore_evas_callback_drop_motion_set(Ecore_Evas *ee, Ecore_Evas_Motion_Cb cb) +{ + ECORE_EVAS_CHECK(ee); + ee->func.fn_dnd_motion = cb; +} + +EAPI void +ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_State_Changed cb) +{ + ECORE_EVAS_CHECK(ee); + ee->func.fn_dnd_state_change = cb; +} + +EAPI void +ecore_evas_callback_drop_drop_set(Ecore_Evas *ee, Ecore_Evas_Drop_Cb cb) +{ + ECORE_EVAS_CHECK(ee); + ee->func.fn_dnd_drop = cb; +} + +typedef struct { + Eina_Array *available_mime_types; + Eina_Position2D pos; +} Ecore_Evas_Active_Dnd; + +static void +_ecore_evas_active_dnd_free(Ecore_Evas_Active_Dnd *dnd) +{ + eina_array_free(dnd->available_mime_types); + free(dnd); +} + +EAPI void +ecore_evas_dnd_enter(Ecore_Evas *ee, unsigned int seat, Eina_Iterator *available_types, Eina_Position2D pos) +{ + Eina_Stringshare *s; + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK(ee); + if (!ee->active_drags) + { + ee->active_drags = eina_hash_int32_new((Eina_Free_Cb)_ecore_evas_active_dnd_free); + } + + dnd = calloc(1, sizeof(Ecore_Evas_Active_Dnd)); + dnd->available_mime_types = eina_array_new(5); + eina_hash_add(ee->active_drags, &seat, dnd); + + EINA_ITERATOR_FOREACH(available_types, s) + { + eina_array_push(dnd->available_mime_types, s); + } + eina_iterator_free(available_types); + + if (ee->func.fn_dnd_state_change) + ee->func.fn_dnd_state_change(ee, seat, pos, EINA_TRUE); +} + +EAPI void +ecore_evas_dnd_position_set(Ecore_Evas *ee, unsigned int seat, Eina_Position2D pos) +{ + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK(ee); + EINA_SAFETY_ON_NULL_RETURN(ee->active_drags); + dnd = eina_hash_find(ee->active_drags, &seat); + EINA_SAFETY_ON_NULL_RETURN(dnd); + dnd->pos = pos; + if (ee->func.fn_dnd_motion) + ee->func.fn_dnd_motion(ee, seat, pos); +} + +EAPI void +ecore_evas_dnd_leave(Ecore_Evas *ee, unsigned int seat, Eina_Position2D pos) +{ + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK(ee); + EINA_SAFETY_ON_NULL_RETURN(ee->active_drags); + dnd = eina_hash_find(ee->active_drags, &seat); + EINA_SAFETY_ON_NULL_RETURN(dnd); + + if (ee->func.fn_dnd_state_change) + ee->func.fn_dnd_state_change(ee, seat, pos, EINA_FALSE); + eina_hash_del(ee->active_drags, &seat, dnd); + if (eina_hash_population(ee->active_drags) == 0) + { + eina_hash_free(ee->active_drags); + ee->active_drags = NULL; + } +} + +EAPI Eina_Position2D +ecore_evas_dnd_pos_get(Ecore_Evas *ee, unsigned int seat) +{ + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK_GOTO(ee, err); + EINA_SAFETY_ON_NULL_RETURN_VAL(ee->active_drags, EINA_POSITION2D(0, 0)); + dnd = eina_hash_find(ee->active_drags, &seat); + EINA_SAFETY_ON_NULL_RETURN_VAL(dnd, EINA_POSITION2D(0, 0)); + + return dnd->pos; +err: + return EINA_POSITION2D(0, 0); +} + +EAPI Eina_Accessor* +ecore_evas_drop_available_types_get(Ecore_Evas *ee, unsigned int seat) +{ + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK_GOTO(ee, err); + EINA_SAFETY_ON_NULL_RETURN_VAL(ee->active_drags, NULL); + dnd = eina_hash_find(ee->active_drags, &seat); + EINA_SAFETY_ON_NULL_RETURN_VAL(dnd, NULL); + + return eina_array_accessor_new(dnd->available_mime_types); +err: + return NULL; +} diff --git a/src/lib/ecore_evas/ecore_evas_fallback_selection.c b/src/lib/ecore_evas/ecore_evas_fallback_selection.c new file mode 100644 index 0000000000..1088e617f7 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_fallback_selection.c @@ -0,0 +1,115 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "ecore_private.h" +#include "Ecore_Evas.h" +#include "ecore_evas_private.h" +#include + +typedef struct { + Ecore_Evas_Selection_Callbacks callbacks[ECORE_EVAS_SELECTION_BUFFER_LAST]; + int seat; +} Ecore_Evas_Fallback_Selection_Data; + +static Ecore_Evas_Fallback_Selection_Data data[ECORE_EVAS_SELECTION_BUFFER_LAST]; + +void +fallback_selection_shutdown(Ecore_Evas *ee) +{ + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (data->callbacks[i].cancel) + data->callbacks[i].cancel(ee, data->seat, i); + } +} + +Eina_Bool +fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +{ + Ecore_Evas_Selection_Callbacks *callbacks = &data->callbacks[selection]; + + if (callbacks->cancel) + { + callbacks->cancel(ee, data->seat, selection); + eina_array_free(callbacks->available_types); + } + + callbacks->delivery = delivery; + callbacks->cancel = cancel; + callbacks->available_types = available_types; + data->seat = seat; + + if (ee->func.fn_selection_changed) + ee->func.fn_selection_changed(ee, seat, selection); + + return EINA_TRUE; +} + +Eina_Bool +fallback_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection EINA_UNUSED) +{ + return EINA_FALSE; //if the real selection buffer does not contain it, then we dont know it either. +} + +Eina_Stringshare* +available_types(Eina_Array *acceptable_types, Eina_Array *available_types) +{ + unsigned int found_type_id = INT_MAX; + Eina_Stringshare *found_type = NULL; + Eina_Stringshare *type; + + for (unsigned int i = 0; i < eina_array_count_get(acceptable_types); ++i) + { + unsigned int out = -1; + + type = eina_array_data_get(acceptable_types, i); + + if (!eina_array_find(available_types, type, &out)) + continue; + if (out >= found_type_id) + continue; + found_type_id = out; + found_type = type; + eina_stringshare_del(type); + } + eina_array_free(acceptable_types); + + return found_type; +} + +Eina_Future* +fallback_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type) +{ + Ecore_Evas_Selection_Callbacks callbacks = data->callbacks[selection]; + Eina_Content *result; + Eina_Stringshare *serving_type; + Eina_Rw_Slice slice_data; + Eina_Value value; + + if (!callbacks.delivery) + return eina_future_resolved(efl_loop_future_scheduler_get(efl_main_loop_get()), eina_value_int_init(0)); + + serving_type = available_types(acceptable_type, callbacks.available_types); + if (!serving_type) + return NULL; //Silent return cause we cannot deliver a good type + + EINA_SAFETY_ON_FALSE_RETURN_VAL(callbacks.delivery(ee, seat, selection, serving_type, &slice_data), NULL); + result = eina_content_new(eina_rw_slice_slice_get(slice_data), serving_type); + value = eina_value_content_init(result); + eina_content_free(result); + + return eina_future_resolved(efl_loop_future_scheduler_get(efl_main_loop_get()), value); +} +Eina_Bool +fallback_dnd_start(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Eina_Array *available_types EINA_UNUSED, Ecore_Evas *drag_rep EINA_UNUSED, Ecore_Evas_Internal_Delivery delivery EINA_UNUSED, Ecore_Evas_Internal_Cancel cancel EINA_UNUSED, const char* action EINA_UNUSED) +{ + return EINA_FALSE; +} + +Eina_Bool +fallback_dnd_stop(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED) +{ + return EINA_FALSE; +} diff --git a/src/lib/ecore_evas/ecore_evas_private.h b/src/lib/ecore_evas/ecore_evas_private.h index 474b7a35ed..10191b0152 100644 --- a/src/lib/ecore_evas/ecore_evas_private.h +++ b/src/lib/ecore_evas/ecore_evas_private.h @@ -33,6 +33,10 @@ EAPI extern int _ecore_evas_log_dom; +EAPI Eina_Error ecore_evas_no_matching_type; +EAPI Eina_Error ecore_evas_no_selection; +EAPI Eina_Error ecore_evas_request_replaced; + #ifdef ECORE_EVAS_DEFAULT_LOG_COLOR # undef ECORE_EVAS_DEFAULT_LOG_COLOR #endif @@ -78,6 +82,13 @@ typedef struct _Ecore_Evas_Interface Ecore_Evas_Interface; typedef struct _Ecore_Evas_Aux_Hint Ecore_Evas_Aux_Hint; typedef struct _Ecore_Evas_Cursor Ecore_Evas_Cursor; +typedef Eina_Bool (*Ecore_Evas_Internal_Delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice); +typedef void (*Ecore_Evas_Internal_Cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer); +typedef struct { + Ecore_Evas_Internal_Delivery delivery; + Ecore_Evas_Internal_Cancel cancel; + Eina_Array *available_types; +} Ecore_Evas_Selection_Callbacks; /* Engines interfaces */ struct _Ecore_Evas_Engine_Func { @@ -171,6 +182,12 @@ struct _Ecore_Evas_Engine_Func Eina_Bool (*fn_prepare)(Ecore_Evas *ee); double (*fn_last_tick_get)(Ecore_Evas *ee); + + Eina_Bool (*fn_selection_claim)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel); + Eina_Bool (*fn_selection_has_owner)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); + Eina_Future* (*fn_selection_request)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_types); // a future containing a Eina_Content, type must be in acceptable_types + Eina_Bool (*fn_dnd_start)(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel, const char *action); + Eina_Bool (*fn_dnd_stop)(Ecore_Evas *ee, unsigned int seat); }; struct _Ecore_Evas_Interface @@ -202,6 +219,11 @@ struct _Ecore_Evas_Cursor { int pos_y; }; +typedef struct { + unsigned int seat; + Eina_Content *selection_buffer[ECORE_EVAS_SELECTION_BUFFER_LAST]; +} Ecore_Evas_Selection_Seat_Buffers; + struct _Ecore_Evas { EINA_INLIST; @@ -224,6 +246,8 @@ struct _Ecore_Evas Eina_List *vnc_server; /* @since 1.19 */ + Eina_Hash *selection_buffers; + struct { int x, y, w, h; } req; @@ -259,7 +283,7 @@ struct _Ecore_Evas Eina_Bool supported; // indicate that the underlying window system supports window manager rotation protocol Eina_Bool app_set; // indicate that the ee supports window manager rotation protocol Eina_Bool win_resize; // indicate that the ee will be resized by the WM - int angle; // rotation value which is decided by the WM + int angle; // rotation value which is decided by the WM int w, h; // window size to rotate int preferred_rot; // preferred rotation hint int *available_rots; // array of avaialable rotation values @@ -323,6 +347,10 @@ struct _Ecore_Evas void (*fn_focus_device_out) (Ecore_Evas *ee, Efl_Input_Device *seat); void (*fn_device_mouse_in) (Ecore_Evas *ee, Efl_Input_Device *mouse); void (*fn_device_mouse_out) (Ecore_Evas *ee, Efl_Input_Device *mouse); + void (*fn_selection_changed) (Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); + void (*fn_dnd_motion) (Ecore_Evas *ee, unsigned int seat, Eina_Position2D p); + void (*fn_dnd_state_change) (Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, Eina_Bool inside); + void (*fn_dnd_drop)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, const char *action); } func; Ecore_Evas_Engine engine; @@ -353,6 +381,14 @@ struct _Ecore_Evas unsigned char rotation_changed : 1; } delayed; + Eina_Hash *active_drags; + struct { + Ecore_Evas *rep; + void *data; + Ecore_Evas_Drag_Finished free; + Eina_Bool accepted; + } drag; + int refcount; //#define ECORE_EVAS_ASYNC_RENDER_DEBUG 1 /* TODO: remove me */ #ifdef ECORE_EVAS_ASYNC_RENDER_DEBUG @@ -374,6 +410,7 @@ struct _Ecore_Evas unsigned char first_frame : 1; unsigned char self_del : 1; unsigned char evas_dying : 1; + unsigned char fallback_interface : 1; }; struct _Ecore_Evas_Aux_Hint @@ -486,6 +523,20 @@ EAPI Eina_Bool ecore_evas_render(Ecore_Evas *ee); EAPI Evas *ecore_evas_evas_new(Ecore_Evas *ee, int w, int h); EAPI void ecore_evas_done(Ecore_Evas *ee, Eina_Bool single_window); +EAPI void ecore_evas_dnd_position_set(Ecore_Evas *ee, unsigned int seat, Eina_Position2D pos); +EAPI void ecore_evas_dnd_leave(Ecore_Evas *ee, unsigned int seat, Eina_Position2D pos); +EAPI void ecore_evas_dnd_enter(Ecore_Evas *ee, unsigned int seat, Eina_Iterator *available_types, Eina_Position2D pos); +EAPI Eina_Position2D ecore_evas_dnd_pos_get(Ecore_Evas *ee, unsigned int seat); + + +void fallback_selection_init(Ecore_Evas *ee); +void fallback_selection_shutdown(Ecore_Evas *ee); +Eina_Bool fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel); +Eina_Bool fallback_selection_has_owner(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); +Eina_Future* fallback_selection_request(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type); +Eina_Bool fallback_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel, const char* action); +Eina_Bool fallback_dnd_stop(Ecore_Evas *ee, unsigned int seat); + #ifdef IPA_YLNO_ESU_LANRETNI_MLE EAPI Ecore_Evas *_wayland_shm_new(const char *disp_name, Ecore_Window parent, int x, int y, int w, int h, Eina_Bool frame); EAPI Ecore_Evas *_wayland_egl_new(const char *disp_name, Ecore_Window parent, int x, int y, int w, int h, Eina_Bool frame, const int *opt); diff --git a/src/lib/ecore_evas/meson.build b/src/lib/ecore_evas/meson.build index c0fb459a56..890e3c42b3 100644 --- a/src/lib/ecore_evas/meson.build +++ b/src/lib/ecore_evas/meson.build @@ -23,7 +23,8 @@ ecore_evas_src = [ 'ecore_evas_cocoa.h', 'ecore_evas_win32.h', 'ecore_evas_x11.h', - 'ecore_evas_util.c' + 'ecore_evas_util.c', + 'ecore_evas_fallback_selection.c' ] diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index 145d958e21..0cb3fc7db9 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -947,7 +947,7 @@ elementary_src = [ 'efl_ui_collection_view.c', 'efl_ui_pager.c', 'efl_ui_stack.c', - 'efl_ui_separator.c' + 'efl_ui_separator.c', ] elementary_deps = [emile, eo, efl, edje, ethumb, ethumb_client, emotion, ecore_imf, ecore_con, eldbus, efreet, efreet_mime, efreet_trash, eio, atspi, dl, intl] diff --git a/src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c b/src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c index 8abc7401b6..ef4ba057b9 100644 --- a/src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c +++ b/src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c @@ -455,6 +455,9 @@ static Ecore_Evas_Engine_Func _ecore_sdl_engine_func = NULL, //fn_pointer_device_xy_get NULL, //fn_prepare NULL, //fn_last_tick_get + NULL, //fn_selection_claim + NULL, //fn_selection_has_owner + NULL, //fn_selection_request }; static Ecore_Evas* diff --git a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c index c14bdbcd33..e0e2094e2f 100644 --- a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c +++ b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c @@ -881,14 +881,14 @@ _rotation_do(Ecore_Evas *ee, int rotation, int resize) { /* resize the canvas */ evas_output_size_set(ee->evas, ee->req.w, ee->req.h); - evas_output_viewport_set(ee->evas, 0, 0, + evas_output_viewport_set(ee->evas, 0, 0, ee->req.w, ee->req.h); } else { /* resize the canvas */ evas_output_size_set(ee->evas, ee->req.h, ee->req.w); - evas_output_viewport_set(ee->evas, 0, 0, + evas_output_viewport_set(ee->evas, 0, 0, ee->req.h, ee->req.w); } } @@ -2474,6 +2474,9 @@ static Ecore_Evas_Engine_Func _ecore_wl_engine_func = _ecore_evas_wl_common_pointer_device_xy_get, _ecore_evas_wl_common_prepare, NULL, //fn_last_tick_get + NULL, //fn_selection_claim + NULL, //fn_selection_has_owner + NULL, //fn_selection_request }; static void diff --git a/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c b/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c index 39def9d49f..6198ed4bac 100644 --- a/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c +++ b/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c @@ -1284,6 +1284,9 @@ static Ecore_Evas_Engine_Func _ecore_win32_engine_func = NULL, //fn_pointer_device_xy_get NULL, //fn_prepare NULL, //fn_last_tick_get + NULL, //fn_selection_claim + NULL, //fn_selection_has_owner + NULL, //fn_selection_request }; #endif /* BUILD_ECORE_EVAS_WIN32 */ diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c b/src/modules/ecore_evas/engines/x/ecore_evas_x.c index abea314d33..fb6eaa63f1 100644 --- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c +++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c @@ -361,7 +361,7 @@ _ecore_evas_x_aux_hints_supported_update(Ecore_Evas *ee) for (i = 0; i < num; i++) { hint = eina_stringshare_add(str[i]); - ee->prop.aux_hint.supported_list = + ee->prop.aux_hint.supported_list = eina_list_append(ee->prop.aux_hint.supported_list, hint); } @@ -414,7 +414,7 @@ _ecore_evas_x_gl_window_new(Ecore_Evas *ee, Ecore_X_Window parent, int x, int y, op++; einfo->vsync = opt[op]; } -#ifdef EVAS_ENGINE_GL_X11_SWAP_MODE_EXISTS +#ifdef EVAS_ENGINE_GL_X11_SWAP_MODE_EXISTS else if (opt[op] == ECORE_EVAS_GL_X11_OPT_SWAP_MODE) { op++; @@ -845,7 +845,7 @@ _ecore_evas_x_event_property_change(void *data EINA_UNUSED, int type EINA_UNUSED Eina_Bool focus_skip : 1; } prop; } prev; - + prev.x.modal = edata->state.modal; prev.x.sticky = edata->state.sticky; prev.x.maximized_v = edata->state.maximized_v; @@ -856,7 +856,7 @@ _ecore_evas_x_event_property_change(void *data EINA_UNUSED, int type EINA_UNUSED prev.x.fullscreen = edata->state.fullscreen; prev.x.above = edata->state.above; prev.x.below = edata->state.below; - + prev.prop.modal = ee->prop.modal; prev.prop.maximized = ee->prop.maximized; prev.prop.sticky = ee->prop.sticky; @@ -879,7 +879,7 @@ _ecore_evas_x_event_property_change(void *data EINA_UNUSED, int type EINA_UNUSED ee->prop.sticky = EINA_FALSE; ee->prop.fullscreen = EINA_FALSE; // ee->prop.focus_skip = EINA_FALSE; - + ecore_x_netwm_window_state_get(e->win, &state, &num); if (state) { @@ -1253,7 +1253,7 @@ _ecore_evas_x_event_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; edata = ee->engine.data; -/* +/* { time_t t; char *ct; @@ -1304,7 +1304,7 @@ _ecore_evas_x_event_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void edata->outdelay = NULL; _fake_out(ee); } - + /* if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; */ if (!_ecore_evas_mouse_in_check(ee, NULL)) { @@ -1388,7 +1388,7 @@ _ecore_evas_x_event_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, void ecore_timer_del(edata->outdelay); edata->outdelay = NULL; } - + // if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; // printf("OUT: ee->in=%i, e->mode=%i, e->detail=%i, dount_count=%i\n", // ee->in, e->mode, e->detail, evas_event_down_count_get(ee->evas)); @@ -1417,7 +1417,7 @@ _ecore_evas_x_event_window_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED ee = ecore_event_window_match(e->win); if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; -//xx// filtering with these doesnt help +//xx// filtering with these doesnt help //xx// if (e->mode == ECORE_X_EVENT_MODE_UNGRAB) return ECORE_CALLBACK_PASS_ON; _ecore_evas_focus_device_set(ee, NULL, EINA_TRUE); return ECORE_CALLBACK_PASS_ON; @@ -1433,7 +1433,7 @@ _ecore_evas_x_event_window_focus_out(void *data EINA_UNUSED, int type EINA_UNUSE ee = ecore_event_window_match(e->win); if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; -//xx// filtering with these doesnt help +//xx// filtering with these doesnt help //xx// if (e->mode == ECORE_X_EVENT_MODE_GRAB) return ECORE_CALLBACK_PASS_ON; // if (ee->prop.fullscreen) @@ -2145,7 +2145,7 @@ _ecore_evas_x_resize(Ecore_Evas *ee, int w, int h) } /* check for valid property window - * + * * NB: If we do not have one, check for valid pixmap rendering */ if (!ee->prop.window) { @@ -2153,7 +2153,7 @@ _ecore_evas_x_resize(Ecore_Evas *ee, int w, int h) if ((edata->pixmap.w != vw) || (edata->pixmap.h != vh)) { /* free the backing pixmap */ - if (edata->pixmap.back) + if (edata->pixmap.back) ecore_x_pixmap_free(edata->pixmap.back); } } @@ -2918,7 +2918,7 @@ _ecore_evas_x_aspect_set(Ecore_Evas *ee, double aspect) ee->prop.aspect = aspect; _ecore_evas_x_size_pos_hints_update(ee); -// netwm state +// netwm state // if (ee->should_be_visible) // ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, // ECORE_X_WINDOW_STATE_STICKY, -1, sticky); @@ -3545,14 +3545,14 @@ norandr: if (!found) goto norandr; } -static void +static void _ecore_evas_x_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) { if (ee->prop.window) ecore_x_pointer_xy_get(ee->prop.window, x, y); } -static Eina_Bool +static Eina_Bool _ecore_evas_x_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y) { return ecore_x_pointer_warp(ee->prop.window, x, y); @@ -3754,6 +3754,9 @@ static Ecore_Evas_Engine_Func _ecore_x_engine_func = NULL, //fn_pointer_device_xy_get NULL, //fn_prepare NULL, //fn_last_tick_get + NULL, //fn_selection_claim + NULL, //fn_selection_has_owner + NULL, //fn_selection_request }; /* @@ -3772,19 +3775,19 @@ _ecore_evas_x_render_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ /* printf("\tPixman Size: %d %d\n", edata->pixmap.w, edata->pixmap.h); */ /* printf("\tEE Size: %d %d\n", ee->w, ee->h); */ - /* before rendering to the back buffer pixmap, we should check the - * size. If the back buffer is not the proper size, destroy it and + /* before rendering to the back buffer pixmap, we should check the + * size. If the back buffer is not the proper size, destroy it and * create a new one at the proper size */ if ((edata->pixmap.w != ee->w) || (edata->pixmap.h != ee->h)) { int fw = 0, fh = 0; /* free the backing pixmap */ - if (edata->pixmap.back) + if (edata->pixmap.back) ecore_x_pixmap_free(edata->pixmap.back); - edata->pixmap.back = - ecore_x_pixmap_new(edata->win_root, ee->w, ee->h, + edata->pixmap.back = + ecore_x_pixmap_new(edata->win_root, ee->w, ee->h, edata->pixmap.depth); evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh); @@ -3803,7 +3806,7 @@ _ecore_evas_x_render_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { - ERR("evas_engine_info_set() init engine '%s' failed.", + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); } } @@ -3821,7 +3824,7 @@ _ecore_evas_x_render_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { - ERR("evas_engine_info_set() init engine '%s' failed.", + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); } } @@ -3844,8 +3847,8 @@ _ecore_evas_x_flush_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ /* printf("\tBack Pixmap: %d\n", edata->pixmap.back); */ /* printf("\tFront Pixmap: %d\n", edata->pixmap.front); */ - /* done drawing to the back buffer. flip it to the front so that - * any calls to "fetch pixmap" will return the front buffer already + /* done drawing to the back buffer. flip it to the front so that + * any calls to "fetch pixmap" will return the front buffer already * pre-rendered */ /* record the current front buffer */ @@ -3870,7 +3873,7 @@ _ecore_evas_x_flush_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { - ERR("evas_engine_info_set() init engine '%s' failed.", + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); } } @@ -3888,7 +3891,7 @@ _ecore_evas_x_flush_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { - ERR("evas_engine_info_set() init engine '%s' failed.", + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); } } @@ -4307,9 +4310,9 @@ ecore_evas_software_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Windo edata->pixmap.colormap = einfo->info.colormap; /* create front and back pixmaps for double-buffer rendering */ - edata->pixmap.front = + edata->pixmap.front = ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth); - edata->pixmap.back = + edata->pixmap.back = ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth); einfo->info.drawable = edata->pixmap.back; @@ -4322,7 +4325,7 @@ ecore_evas_software_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Windo } } - /* FIXME: Allow of these set properties or do something with the + /* FIXME: Allow of these set properties or do something with the * ee->prop.window (x window), which we do not have in pixmap case */ /* _ecore_evas_x_hints_update(ee); */ @@ -4370,7 +4373,7 @@ _ecore_evas_software_x11_pixmap_visual_get(const Ecore_Evas *ee) return edata->pixmap.visual; } -static unsigned long +static unsigned long _ecore_evas_software_x11_pixmap_colormap_get(const Ecore_Evas *ee) { if (!(!strcmp(ee->driver, "software_x11"))) return 0; @@ -4378,7 +4381,7 @@ _ecore_evas_software_x11_pixmap_colormap_get(const Ecore_Evas *ee) return edata->pixmap.colormap; } -static int +static int _ecore_evas_software_x11_pixmap_depth_get(const Ecore_Evas *ee) { if (!(!strcmp(ee->driver, "software_x11"))) return 0; @@ -4719,9 +4722,9 @@ ecore_evas_gl_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Window pare edata->pixmap.colormap = einfo->info.colormap; /* create front and back pixmaps for double-buffer rendering */ - edata->pixmap.front = + edata->pixmap.front = ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth); - edata->pixmap.back = + edata->pixmap.back = ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth); einfo->info.drawable = edata->pixmap.back; @@ -4779,7 +4782,7 @@ _ecore_evas_gl_x11_pixmap_visual_get(const Ecore_Evas *ee) return edata->pixmap.visual; } -static unsigned long +static unsigned long _ecore_evas_gl_x11_pixmap_colormap_get(const Ecore_Evas *ee) { if (!(!strcmp(ee->driver, "opengl_x11"))) return 0; @@ -4787,7 +4790,7 @@ _ecore_evas_gl_x11_pixmap_colormap_get(const Ecore_Evas *ee) return edata->pixmap.colormap; } -static int +static int _ecore_evas_gl_x11_pixmap_depth_get(const Ecore_Evas *ee) { if (!(!strcmp(ee->driver, "opengl_x11"))) return 0; diff --git a/src/tests/ecore/ecore_suite.c b/src/tests/ecore/ecore_suite.c index b9248a814a..a0f6d19aba 100644 --- a/src/tests/ecore/ecore_suite.c +++ b/src/tests/ecore/ecore_suite.c @@ -30,6 +30,7 @@ static const Efl_Test_Case etc[] = { { "Ecore_Job", ecore_test_ecore_job }, { "Ecore_Args", ecore_test_ecore_args }, { "Ecore_Pipe", ecore_test_ecore_pipe }, + { "Ecore_Evas_Selection", ecore_test_ecore_evas_selection }, { NULL, NULL } }; diff --git a/src/tests/ecore/ecore_suite.h b/src/tests/ecore/ecore_suite.h index a3327412fe..2621535f59 100644 --- a/src/tests/ecore/ecore_suite.h +++ b/src/tests/ecore/ecore_suite.h @@ -23,5 +23,6 @@ void ecore_test_ecore_file(TCase *tc); void ecore_test_ecore_job(TCase *tc); void ecore_test_ecore_args(TCase *tc); void ecore_test_ecore_pipe(TCase *tc); +void ecore_test_ecore_evas_selection(TCase *tc); #endif /* _ECORE_SUITE_H */ diff --git a/src/tests/ecore/ecore_test_ecore_evas.c b/src/tests/ecore/ecore_test_ecore_evas.c index 2e53f62082..0e7b09c41b 100644 --- a/src/tests/ecore/ecore_test_ecore_evas.c +++ b/src/tests/ecore/ecore_test_ecore_evas.c @@ -3,6 +3,7 @@ #endif #include +#include #include "ecore_suite.h" @@ -70,8 +71,51 @@ EFL_START_TEST(ecore_test_ecore_evas_cocoa) } EFL_END_TEST +static Eina_Value +_verify_and_exit(void *data, const Eina_Value value, const Eina_Future *dead_future EINA_UNUSED) +{ + ck_assert_ptr_eq(eina_value_type_get(&value), EINA_VALUE_TYPE_CONTENT); + Eina_Content *content = eina_value_to_content(&value); + Eina_Content *reference = data; + + ck_assert_int_eq(eina_content_data_get(content).len, eina_content_data_get(reference).len); + ck_assert_str_eq(eina_content_data_get(content).mem, eina_content_data_get(reference).mem); + ck_assert_str_eq(eina_content_type_get(content), eina_content_type_get(reference)); + + efl_loop_quit(efl_main_loop_get(), eina_value_int_init(0)); + + return EINA_VALUE_EMPTY; +} + +EFL_START_TEST(ecore_test_ecore_evas_fallback_selection) +{ + Ecore_Evas *ee; + ecore_evas_init(); + + ee = ecore_evas_buffer_new(WINDOW_WIDTH, WINDOW_HEIGHT); + fail_if(ee == NULL); + + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + ck_assert_int_eq(ecore_evas_selection_exists(ee, 0, i), EINA_FALSE); + } + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("asdf"), "text/plain"); + Eina_Content *ref = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("asdf"), "text/plain"); + ecore_evas_selection_set(ee, 0, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER, content); + + const char *types[] = {eina_stringshare_add("text/plain")}; + + Eina_Future *f = ecore_evas_selection_get(ee, 0, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER, EINA_C_ARRAY_ITERATOR_NEW(types)); + ck_assert_ptr_ne(f, NULL); + eina_future_then(f, _verify_and_exit, ref); + efl_task_run(efl_main_loop_get()); + ecore_evas_shutdown(); +} +EFL_END_TEST + void ecore_test_ecore_evas(TCase *tc) { tcase_add_test(tc, ecore_test_ecore_evas_associate); tcase_add_test(tc, ecore_test_ecore_evas_cocoa); + tcase_add_test(tc, ecore_test_ecore_evas_fallback_selection); } diff --git a/src/tests/ecore/ecore_test_ecore_evas_selection.c b/src/tests/ecore/ecore_test_ecore_evas_selection.c new file mode 100644 index 0000000000..9efc5fe722 --- /dev/null +++ b/src/tests/ecore/ecore_test_ecore_evas_selection.c @@ -0,0 +1,89 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "ecore_suite.h" + +#define WINDOW_HEIGHT 200 +#define WINDOW_WIDTH 200 + +static int log_abort; +static int log_abort_level; + +void +fail_on_errors_teardown(void) +{ + eina_log_abort_on_critical_set(log_abort); + eina_log_abort_on_critical_level_set(log_abort_level); +} + +void +fail_on_errors_setup(void) +{ + log_abort = eina_log_abort_on_critical_get(); + log_abort_level = eina_log_abort_on_critical_level_get(); + eina_log_abort_on_critical_level_set(2); + eina_log_abort_on_critical_set(1); +} + +static Ecore_Evas *ee; + +void +_setup(void) +{ + ecore_evas_init(); + ee = ecore_evas_buffer_new(50, 50); +} + +void +_teardown(void) +{ + ecore_evas_free(ee); + ecore_evas_shutdown(); +} + +EFL_START_TEST(ecore_test_selection_get_twice) +{ + //this is just running this and checking that we do not error + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) continue; + const char *types[] = {eina_stringshare_add("text/plain")}; + ck_assert_ptr_ne(ecore_evas_selection_get(ee, 0, i, EINA_C_ARRAY_ITERATOR_NEW(types)), NULL); + } + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) continue; + const char *types[] = {eina_stringshare_add("text/plain")}; + ck_assert_ptr_ne(ecore_evas_selection_get(ee, 0, i, EINA_C_ARRAY_ITERATOR_NEW(types)), NULL); + } +} +EFL_END_TEST + +EFL_START_TEST(ecore_test_selection_claim_twice) +{ + //this is just running this and checking that we do not error + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) continue; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("asdf"), "text/plain"); + ck_assert_int_eq(ecore_evas_selection_set(ee, 0, i, content), EINA_TRUE); + } + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) continue; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("asdf"), "text/plain"); + ck_assert_int_eq(ecore_evas_selection_set(ee, 0, i, content), EINA_TRUE); + } +} +EFL_END_TEST +void ecore_test_ecore_evas_selection(TCase *tc) +{ + tcase_add_checked_fixture(tc, fail_on_errors_setup, fail_on_errors_teardown); + tcase_add_checked_fixture(tc, _setup, _teardown); + tcase_add_test(tc, ecore_test_selection_get_twice); + tcase_add_test(tc, ecore_test_selection_claim_twice); +} diff --git a/src/tests/ecore/meson.build b/src/tests/ecore/meson.build index 9ce6848ce2..48c9350638 100644 --- a/src/tests/ecore/meson.build +++ b/src/tests/ecore/meson.build @@ -13,6 +13,7 @@ ecore_suite_src = [ 'ecore_test_job.c', 'ecore_test_args.c', 'ecore_test_pipe.c', + 'ecore_test_ecore_evas_selection.c', 'ecore_suite.h' ] diff --git a/src/tests/elementary/efl_ui_window_cnp_dnd_slave.c b/src/tests/elementary/efl_ui_window_cnp_dnd_slave.c new file mode 100644 index 0000000000..bf8c6d50bd --- /dev/null +++ b/src/tests/elementary/efl_ui_window_cnp_dnd_slave.c @@ -0,0 +1,191 @@ +#define EFL_BETA_API_SUPPORT 1 + +#include +#include +#include +#include "efl_ui_grid_view.eo.h" + +static Ecore_Evas *ee; + +static Eina_Value +_deliverty_cb(void *data, const Eina_Value value, const Eina_Future *dead_future EINA_UNUSED) +{ + Ecore_Evas_Selection_Buffer buffer = (intptr_t)data; + Eina_Content *content; + + if (eina_value_type_get(&value) != EINA_VALUE_TYPE_CONTENT) + { + char *error = eina_value_to_string(&value); + printf("Value not a content, message: \"%s\"\n", error); + return EINA_VALUE_EMPTY; + } + + content = eina_value_to_content(&value); + printf("Got Content of selection %d with type %s\n", buffer, eina_content_type_get(content)); + if (!strncmp(eina_content_type_get(content), "text", strlen("text"))) + { + printf("Content: %s\n", (char*)eina_content_data_get(content).mem); + } + + return EINA_VALUE_EMPTY; +} + +static void +_selection_changed(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection) +{ + printf("Selection %d of %p has changed\n", selection, ee); +} + +static void +_request_selection(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection) +{ + const char *types[] = {eina_stringshare_add("text/plain"), eina_stringshare_add("text/plain;charset=utf-8")}; + printf("Selection %d of %p has changed\n", selection, ee); + Eina_Future *future = ecore_evas_selection_get(ee, 0, selection, EINA_C_ARRAY_ITERATOR_NEW(types)); + eina_future_then(future, _deliverty_cb, .data = ((void*)(intptr_t)selection)); +} + +static void +_motion_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p) +{ + printf("Drag and Drop has moved on the window %p (%d, %d)\n", ee, p.x, p.y); +} + +static void +_enter_state_change_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, Eina_Bool inside) +{ + if (inside) + printf("Drag and Drop has entered the window %p (%d, %d)\n", ee, p.x, p.y); + else + printf("Drag and Drop has left the window %p (%d, %d)\n", ee, p.x, p.y); +} + +static void +_drop_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, const char *action EINA_UNUSED) +{ + const char *types[] = {eina_stringshare_add("text/plain")}; + printf("Drag and Drop has droped on the window %p (%d, %d)\n", ee, p.x, p.y); + Eina_Future *f = ecore_evas_selection_get(ee, 0, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, EINA_C_ARRAY_ITERATOR_NEW(types)); + eina_future_then(f, _deliverty_cb, .data = ((void*)(intptr_t)ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)); +} + +static void +_efl_ui_terminated(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, void *data, Eina_Bool accepted EINA_UNUSED) +{ + efl_del(data); +} + +static Eo* +_start_dnd(Ecore_Evas *ee) +{ + Ecore_Evas *ee2; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("This is sample content"), "text/plain"); + Efl_Ui_Win *win; + Efl_Ui_Button *btn; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get()); + ee2 = ecore_evas_ecore_evas_get(evas_object_evas_get(win)); + + btn = efl_add(EFL_UI_BUTTON_CLASS, win); + efl_text_set(btn, "Test"); + efl_content_set(win, btn); + + evas_object_geometry_set(win, 0, 0, 100, 100); + + ecore_evas_drag_start(ee, 0, content, ee2, "copy", _efl_ui_terminated, win); + + return win; +} + +static void +_start_op(void *data, const Efl_Event *ev EINA_UNUSED) +{ + _start_dnd(data); +} + +static Eina_Value +_delete_cb(Eo *obj, void *data EINA_UNUSED, const Eina_Value value EINA_UNUSED) +{ + Ecore_Evas *ee ; + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + + ecore_evas_drag_cancel(ee, 0); + + return EINA_VALUE_EMPTY; +} + +static void +_start_delayed_del_op(void *data, const Efl_Event *ev EINA_UNUSED) +{ + _start_dnd(data); + efl_future_then(ev->object, efl_loop_timeout(efl_main_loop_get(), 2.0), _delete_cb); +} + +EAPI_MAIN void +efl_main(void *data EINA_UNUSED, const Efl_Event *ev) +{ + Efl_Ui_Textbox *txt, *win, *bx, *btn; + Efl_Loop_Arguments *args = ev->info; + char *goal; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get()); + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(win)); + + bx = efl_add(EFL_UI_BOX_CLASS, win); + + txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_text_set(txt, "Sample for CNP and DND interaction"); + efl_pack_end(bx, txt); + + btn = efl_add(EFL_UI_BUTTON_CLASS, win); + efl_gfx_hint_weight_set(btn, 1.0, 0.0); + efl_event_callback_add(btn, EFL_INPUT_EVENT_PRESSED, _start_op, ee); + efl_text_set(btn, "Start DND op"); + efl_pack_end(bx, btn); + + btn = efl_add(EFL_UI_BUTTON_CLASS, win); + efl_gfx_hint_weight_set(btn, 1.0, 0.0); + efl_event_callback_add(btn, EFL_INPUT_EVENT_PRESSED, _start_delayed_del_op, ee); + efl_text_set(btn, "Start DND op self destroy after 2 sec"); + efl_pack_end(bx, btn); + + efl_content_set(win, bx); + efl_gfx_entity_size_set(win, EINA_SIZE2D(320, 320)); + + goal = eina_array_data_get(args->argv, 1); + + if (eina_streq(goal, "--monitor")) + { + ecore_evas_callback_selection_changed_set(ee, _selection_changed); + ecore_evas_callback_drop_drop_set(ee, _drop_cb); + ecore_evas_callback_drop_motion_set(ee, _motion_cb); + ecore_evas_callback_drop_state_changed_set(ee, _enter_state_change_cb); + } + else if (eina_streq(goal, "--show-selections")) + { + ecore_evas_callback_selection_changed_set(ee, _request_selection); + } + else if (eina_streq(goal, "--set-selection")) + { + if (eina_array_count(args->argv) < 3) + { + printf("Error, --set-selection only requires exactly 1 keyword (The selection to set).\n"); + return; + } + char *selection = eina_array_data_get(args->argv, 2); + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(selection), "text/plain"); + ecore_evas_selection_set(ee, 0, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER, content); + } + else if (eina_streq(goal, "--show-owner")) + { + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + printf("Selection buffer %d : %d\n", i, ecore_evas_selection_exists(ee, 0, i)); + } + } + else + { + printf("Error, goal %s not found\n", goal); + } +} +EFL_MAIN() diff --git a/src/tests/elementary/meson.build b/src/tests/elementary/meson.build index 7f5fd03733..1b43da7064 100644 --- a/src/tests/elementary/meson.build +++ b/src/tests/elementary/meson.build @@ -187,6 +187,11 @@ efl_ui_compile_test = executable('efl_ui_compile_test', dependencies: [elementary, eio], ) +executable('efl_ui_window_cnp_dnd_slave', + 'efl_ui_window_cnp_dnd_slave.c', + dependencies: [elementary], +) + test('elementary-suite', elementary_suite, env : test_env ) From 293b2fe7191fd591d9553a03c2ee6f6d06a07641 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Sun, 12 Jan 2020 17:36:48 +0100 Subject: [PATCH 03/17] ecore_x: add API to request selection changed events for diff. wins we need that in order to get seleciton per window events, which is required to get a nice mapping onto the ecore_evas object. Reviewed-by: Carsten Haitzler (Rasterman) Reviewed-by: Chris Michael Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11193 --- src/lib/ecore_x/Ecore_X.h | 9 +++++++++ src/lib/ecore_x/ecore_x_fixes.c | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/lib/ecore_x/Ecore_X.h b/src/lib/ecore_x/Ecore_X.h index bb5aedf39e..94b612abc6 100644 --- a/src/lib/ecore_x/Ecore_X.h +++ b/src/lib/ecore_x/Ecore_X.h @@ -2444,6 +2444,15 @@ EAPI void ecore_x_root_screen_barriers_set(Ecore_X_Rectangle *scre */ EAPI Eina_Bool ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection); +/** + * xfixes selection notification request. + * + * In addition to ecore_x_fixes_selection_notification_request you can also specify for which window you want to get them + * @since 1.24 + */ +EAPI Eina_Bool ecore_x_fixes_window_selection_notification_request(Ecore_X_Window window, Ecore_X_Atom selection); + + /* XComposite Extension Support */ EAPI Eina_Bool ecore_x_composite_query(void); EAPI void ecore_x_composite_redirect_window(Ecore_X_Window win, Ecore_X_Composite_Update_Type type); diff --git a/src/lib/ecore_x/ecore_x_fixes.c b/src/lib/ecore_x/ecore_x_fixes.c index 5582c3e3ef..4b659c2d8b 100644 --- a/src/lib/ecore_x/ecore_x_fixes.c +++ b/src/lib/ecore_x/ecore_x_fixes.c @@ -112,6 +112,26 @@ ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection) return EINA_FALSE; } +EAPI Eina_Bool +ecore_x_fixes_window_selection_notification_request(Ecore_X_Window window, Ecore_X_Atom selection) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(_ecore_x_disp, EINA_FALSE); + +#ifdef ECORE_XFIXES + if (_fixes_available) + { + XFixesSelectSelectionInput (_ecore_x_disp, + window, + selection, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + EAPI Ecore_X_Region ecore_x_region_new(Ecore_X_Rectangle *rects, int num) From 6189c2112c2c854b86821d8391e69231d78cdc29 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Tue, 21 Jan 2020 14:50:23 +0100 Subject: [PATCH 04/17] ecore_x_selection: do not skip any any atoms i dont know why we skipped the first two atoms, but right now, if a application is only providing one single target, we would crash. With this we might copy a few atoms more. However, these atoms do not matter, as we skip those, that we cannot understand Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11194 --- src/lib/ecore_x/ecore_x_selection.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/ecore_x/ecore_x_selection.c b/src/lib/ecore_x/ecore_x_selection.c index 22cd5c8c7f..733b799244 100644 --- a/src/lib/ecore_x/ecore_x_selection.c +++ b/src/lib/ecore_x/ecore_x_selection.c @@ -990,15 +990,15 @@ _ecore_x_selection_parser_targets(const char *target EINA_UNUSED, if (!sel) return NULL; targets = data; - sel->num_targets = size - 2; - sel->targets = malloc((size - 2) * sizeof(char *)); + sel->num_targets = size; + sel->targets = malloc((sel->num_targets) * sizeof(char *)); if (!sel->targets) { free(sel); return NULL; } - for (i = 2; i < size; i++) - sel->targets[i - 2] = XGetAtomName(_ecore_x_disp, targets[i]); + for (i = 0; i < size; i++) + sel->targets[i] = XGetAtomName(_ecore_x_disp, targets[i]); ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_targets_free; ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS; From e0c40abb40f05efe32e263e8a59e923281b559dc Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Sun, 12 Jan 2020 17:38:05 +0100 Subject: [PATCH 05/17] ecore_evas: introduce initial selection & dnd support for x. Seats are not implemented, if there is a type mismatch promises are going to be rejected. Most of this code is copied over from selection_manager. Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11195 --- .../ecore_evas/engines/x/ecore_evas_x.c | 756 +++++++++++++++++- 1 file changed, 753 insertions(+), 3 deletions(-) diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c b/src/modules/ecore_evas/engines/x/ecore_evas_x.c index fb6eaa63f1..d689a5622c 100644 --- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c +++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c @@ -73,6 +73,16 @@ static Eina_Bool wm_exists; typedef struct _Ecore_Evas_Engine_Data_X11 Ecore_Evas_Engine_Data_X11; +typedef struct { + Ecore_Evas_Selection_Callbacks callbacks; + Ecore_Evas_Selection_Buffer buffer; + Ecore_Evas *ee; + Eina_Promise *delivery; + Eina_Array *acceptable_type; + Eina_Stringshare *requested_type; + Eina_Stringshare *later_conversion; +} Ecore_Evas_X11_Selection_Data; + struct _Ecore_Evas_Engine_Data_X11 { Ecore_X_Window win_root; Eina_List *win_extra; @@ -128,6 +138,11 @@ struct _Ecore_Evas_Engine_Data_X11 { void *visual; // store visual used to create pixmap unsigned long colormap; // store colormap used to create pixmap } pixmap; + Ecore_Evas_X11_Selection_Data selection_data[ECORE_EVAS_SELECTION_BUFFER_LAST]; + Eina_Array *xserver_atom_name_during_dnd; + Ecore_Event_Handler *mouse_up_handler; + Ecore_Job *init_job; + int skip_clean_event; Eina_Bool destroyed : 1; // X window has been deleted and cannot be used Eina_Bool fully_obscured : 1; // X window is fully obscured Eina_Bool configured : 1; // X window has been configured @@ -151,6 +166,8 @@ static void _alpha_do(Ecore_Evas *, int); static void _transparent_do(Ecore_Evas *, int); static void _avoid_damage_do(Ecore_Evas *, int); static void _rotation_do(Ecore_Evas *, int, int); +static void _ecore_evas_x_selection_init(void); +static void _ecore_evas_x_selection_window_init(Ecore_Evas *ee); #define SWAP_INT(a, b) do { a ^= b; b ^= a; a ^= b; } while (0) @@ -1970,6 +1987,7 @@ _ecore_evas_x_init(void) ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE, _ecore_evas_x_event_window_create, NULL); ecore_event_evas_init(); + _ecore_evas_x_selection_init(); return _ecore_evas_init_count; } @@ -1997,6 +2015,7 @@ _ecore_evas_x_free(Ecore_Evas *ee) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + ecore_job_del(edata->init_job); if (edata->pixmap.back) ecore_x_pixmap_free(edata->pixmap.back); if (edata->pixmap.front) @@ -2696,6 +2715,7 @@ _alpha_do(Ecore_Evas *ee, int alpha) _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); _ecore_evas_x_size_pos_hints_update(ee); + _ecore_evas_x_selection_window_init(ee); #endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ if ((id = getenv("DESKTOP_STARTUP_ID"))) { @@ -2850,6 +2870,7 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha) _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); _ecore_evas_x_size_pos_hints_update(ee); + _ecore_evas_x_selection_window_init(ee); #endif /* BUILD_ECORE_EVAS_OPENGL_X11 */ if ((id = getenv("DESKTOP_STARTUP_ID"))) { @@ -3667,6 +3688,731 @@ _ecore_evas_x_aux_hints_set(Ecore_Evas *ee, const char *hints) (ee->prop.window, ECORE_X_ATOM_E_WINDOW_AUX_HINT); } +static Ecore_X_Atom ecore_evas_selection_to_atom[] = {0, 0, 0, 0}; +static Ecore_Event_Handler *ecore_evas_selection_handlers[8]; + +static inline Ecore_Evas_Selection_Buffer +_atom_to_selection(Ecore_X_Atom atom) +{ + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (ecore_evas_selection_to_atom[i] == atom) + return i; + } + return ECORE_EVAS_SELECTION_BUFFER_LAST; +} + +static Eina_Stringshare* +_decrypt_type(const char *target) +{ + // reference https://tronche.com/gui/x/icccm/sec-2.html + if (eina_streq(target, "TEXT")) return eina_stringshare_add("text/plain"); + //FIXME no support in eina_content for that so far + if (eina_streq(target, "COMPOUND_TEXT")) return eina_stringshare_add("text/plain"); + // reference https://tronche.com/gui/x/icccm/sec-2.html + if (eina_streq(target, "STRING")) return eina_stringshare_add("text/plain;charset=iso-8859-1"); + if (eina_streq(target, "UTF8_STRING")) return eina_stringshare_add("text/plain;charset=utf-8"); + + return eina_stringshare_add(target); +} + +static Eina_Stringshare* +_mime_to_xserver_type(const char *target) +{ + // FIXME // reference https://tronche.com/gui/x/icccm/sec-2.html says it is in the owners choice of encoding, not sure what this means directly here + if (eina_streq(target, "text/plain")) return eina_stringshare_add("TEXT"); + // reference https://tronche.com/gui/x/icccm/sec-2.html + if (eina_streq(target, "text/plain;charset=iso-8859-1")) return eina_stringshare_add("STRING"); + if (eina_streq(target, "text/plain;charset=utf-8")) return eina_stringshare_add("UTF8_STRING"); + + return eina_stringshare_add(target); +} + +static inline void +_clear_selection(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection) +{ + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + Ecore_Evas_Selection_Callbacks *cbs = &edata->selection_data[selection].callbacks; + + EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel); + + cbs->cancel(ee, 1, selection); + eina_array_free(cbs->available_types); + + cbs->delivery = NULL; + cbs->cancel = NULL; + cbs->available_types = NULL; +} + +static void +_clear_selection_delivery(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection) +{ + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + eina_stringshare_replace(&edata->selection_data[selection].requested_type, NULL); + eina_stringshare_replace(&edata->selection_data[selection].later_conversion, NULL); + edata->selection_data[selection].delivery = NULL; + eina_array_free(edata->selection_data[selection].acceptable_type); + edata->selection_data[selection].acceptable_type = NULL; +} + +static void +_ecore_x_selection_request(Ecore_X_Window win, Ecore_Evas_Selection_Buffer selection, const char *type) +{ + if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + ecore_x_selection_primary_request(win, type); + else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + ecore_x_selection_clipboard_request(win, type); + else + ecore_x_selection_xdnd_request(win, type); +} + +static void +_search_fitting_type(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Eina_Array *arr) +{ + Eina_Stringshare *mime_type; + Eina_Bool found_conversion = EINA_FALSE; + +#define HANDLE_TYPE() \ + { \ + edata->selection_data[selection].requested_type = eina_stringshare_add(x11_name); \ + edata->selection_data[selection].later_conversion = eina_stringshare_add(acceptable_type);\ + found_conversion = EINA_TRUE; \ + break; \ + } + + EINA_SAFETY_ON_NULL_RETURN(edata->selection_data[selection].acceptable_type); + + for (unsigned int i = 0; i < eina_array_count(arr) && !found_conversion; ++i) + { + const char *x11_name = eina_array_data_get(arr, i); + mime_type = _decrypt_type(x11_name); + + for (unsigned int j = 0; j < eina_array_count(edata->selection_data[selection].acceptable_type) && !found_conversion; ++j) + { + const char *acceptable_type = (const char*) eina_array_data_get(edata->selection_data[selection].acceptable_type, j); + + if (mime_type == acceptable_type) + HANDLE_TYPE() + + //if there is no available type yet, check if we can convert to the desiared type via this type + if (!found_conversion) + { + const char *convertion_type = NULL; + Eina_Iterator *iter = eina_content_converter_possible_conversions(mime_type); + EINA_ITERATOR_FOREACH(iter, convertion_type) + { + if (convertion_type == acceptable_type) + HANDLE_TYPE() + } + eina_iterator_free(iter); + } + } + eina_stringshare_del(mime_type); + } + if (found_conversion) + { + _ecore_x_selection_request(ee->prop.window, selection, edata->selection_data[selection].requested_type); + } + else + { + eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_error_init(ecore_evas_no_matching_type)); + _clear_selection_delivery(ee, selection); + } + +#undef HANDLE_TYPE +} + +static void +_search_fitting_type_from_event(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev) +{ + Ecore_X_Atom *available_atoms; + Ecore_X_Selection_Data_Targets *targets; + Eina_Array *tmp = eina_array_new(10); + + targets = ev->data; + available_atoms = (Ecore_X_Atom *)targets->data.data; + for (int i = 0; i < targets->data.length; ++i) + { + Ecore_X_Atom atom = available_atoms[i]; + eina_array_push(tmp, ecore_x_atom_name_get(atom)); + } + _search_fitting_type(ee, edata, selection, tmp); + eina_array_free(tmp); +} + +static void +_deliver_content(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev) +{ + Ecore_X_Selection_Data *x11_data = ev->data; + Eina_Rw_Slice data; + Eina_Content *result; + Eina_Stringshare *mime_type = _decrypt_type(edata->selection_data[selection].requested_type); + + if (!strncmp(mime_type, "text", strlen("text"))) + { + //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. + data.len = x11_data->length + 1; + data.mem = eina_memdup(x11_data->data, x11_data->length, EINA_TRUE); + } + else + { + data.len = x11_data->length; + data.mem = x11_data->data; + } + + result = eina_content_new(eina_rw_slice_slice_get(data), mime_type); + + //ensure that we deliver the correct type, we might have choosen a convertion before + if (edata->selection_data[selection].later_conversion != mime_type) + { + Eina_Content *tmp = eina_content_convert(result, edata->selection_data[selection].later_conversion); + eina_content_free(result); + result = tmp; + } + + eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_content_init(result)); + eina_content_free(result); + _clear_selection_delivery(ee, selection); + + if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + ecore_x_dnd_send_finished(); +} + +static Eina_Bool +_ecore_evas_x_selection_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Selection_Notify *ev = event; + Ecore_Evas_Selection_Buffer selection; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas *ee; + + ee = ecore_event_window_match(ev->win); + selection = _atom_to_selection(ev->atom); + EINA_SAFETY_ON_FALSE_GOTO(!!ee, end); + EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end); + edata = ee->engine.data; + + //if dnd drops above us, and even if we did not request anything, we are getting notified, refuse to do anything + if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER && + !edata->selection_data[selection].later_conversion) + { + ecore_x_dnd_send_finished(); + } + else + { + if (eina_streq(ev->target, "TARGETS") || eina_streq(ev->target, "ATOMS")) + { + //This will decide for a type, and will sent that via _ecore_x_selection_request + EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, EINA_FALSE); + _search_fitting_type_from_event(ee, edata, selection, ev); + } + else + { + //This will read the data, fill it into a Eina_Content apply all conversions required. + EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].later_conversion, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].requested_type, EINA_FALSE); + _deliver_content(ee, edata, selection, ev); + } + } +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_selection_clear(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Selection_Clear *ev = event; + Ecore_Evas_Selection_Callbacks *cbs; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas_Selection_Buffer selection; + Ecore_Evas *ee; + + ee = ecore_event_window_match(ev->win); + selection = _atom_to_selection(ev->atom); + EINA_SAFETY_ON_FALSE_GOTO(ee, end); + EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end); + edata = ee->engine.data; + cbs = &edata->selection_data[selection].callbacks; + + //skip clean event + if (edata->skip_clean_event) + { + edata->skip_clean_event --; + goto end; + } + + if (cbs->cancel) + _clear_selection(ee, selection); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static void +_force_stop_self_dnd(Ecore_Evas *ee) +{ + Ecore_Evas_Engine_Data_X11 *edata; + + EINA_SAFETY_ON_NULL_RETURN(ee); + edata = ee->engine.data; + EINA_SAFETY_ON_NULL_RETURN(edata); + + //Never clear the buffer for selection here. + //Selection buffer is freed as a response to the FINISHED event. + ecore_x_pointer_ungrab(); + ecore_x_dnd_self_drop(); + ecore_x_dnd_aware_set(ee->prop.window, EINA_FALSE); + ecore_event_handler_del(edata->mouse_up_handler); + edata->mouse_up_handler = NULL; + + if (ee->drag.free) + ee->drag.free(ee, 1, ee->drag.data, ee->drag.accepted); + ee->drag.free = NULL; +} + +static Eina_Bool +_ecore_evas_x_selection_fixes_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Fixes_Selection_Notify *ev = event; + Ecore_Evas *ee; + Ecore_Evas_Selection_Buffer selection; + + ee = ecore_event_window_match(ev->win); + selection = _atom_to_selection(ev->atom); + EINA_SAFETY_ON_FALSE_GOTO(!!ee, end); + EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end); + + //notify that the selection has changed on this ecore evas + if (ee->func.fn_selection_changed) + ee->func.fn_selection_changed(ee, 0, selection); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_eina_content_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize) +{ + Ecore_Evas_X11_Selection_Data *sdata = data; + Eina_Bool ret = EINA_FALSE;; + if (eina_streq(target, "TARGETS") || eina_streq(target, "ATOM")) + { + //list all available types that we have currently + Ecore_X_Atom *result = calloc(eina_array_count(sdata->callbacks.available_types), sizeof(Ecore_X_Atom)); + for (unsigned int i = 0; i < eina_array_count(sdata->callbacks.available_types); ++i) + { + result[i] = ecore_x_atom_get(eina_array_data_get(sdata->callbacks.available_types, i)); + } + *size_ret = eina_array_count(sdata->callbacks.available_types); + *data_ret = result; + *ttype = ECORE_X_ATOM_ATOM; + *typesize = 32; /* urk */ + ret = EINA_TRUE; + } + else + { + const char *mime_type = _decrypt_type(target); + for (unsigned int i = 0; i < eina_array_count(sdata->callbacks.available_types); ++i) + { + if (mime_type == eina_array_data_get(sdata->callbacks.available_types, i)) + { + Eina_Rw_Slice slice; + sdata->callbacks.delivery(sdata->ee, 1, sdata->buffer, mime_type, &slice); + *size_ret = slice.len; + *data_ret = slice.mem; + *ttype = ecore_x_atom_get(target); //use here target in order to get the correct atom + //FIXME in selection manager we never set here the typesize, isn't that weird ? + ret = EINA_TRUE; + break; + } + } + eina_stringshare_del(mime_type); + } + + return ret; +} + +static Eina_Bool +_ecore_evas_x_dnd_enter(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Enter *enter = event; + Eina_Array *mime_tmp; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas *ee; + + mime_tmp = eina_array_new(10); + ee = ecore_event_window_match(enter->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + edata = ee->engine.data; + edata->xserver_atom_name_during_dnd = eina_array_new(10); + for (int i = 0; i < enter->num_types; ++i) + { + const char *mime_type = _decrypt_type(enter->types[i]); + eina_array_push(mime_tmp, mime_type); + eina_array_push(edata->xserver_atom_name_during_dnd, eina_stringshare_add(enter->types[i])); + } + ecore_evas_dnd_enter(ee, 1, eina_array_iterator_new(mime_tmp), EINA_POSITION2D(0,0)); //FIXME + eina_array_free(mime_tmp); + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_dnd_leave(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Leave *leave = event; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas *ee; + + ee = ecore_event_window_match(leave->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + edata = ee->engine.data; + ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(0,0)); + for (unsigned int i = 0; i < eina_array_count(edata->xserver_atom_name_during_dnd); ++i) + { + eina_stringshare_del(eina_array_data_get(edata->xserver_atom_name_during_dnd, i)); + } + eina_array_free(edata->xserver_atom_name_during_dnd); + edata->xserver_atom_name_during_dnd = NULL; +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Ecore_X_Atom +_x11_dnd_action_rev_map(const char* action) +{ + if (eina_streq(action, "copy")) return ECORE_X_ATOM_XDND_ACTION_COPY; + if (eina_streq(action, "move")) return ECORE_X_ATOM_XDND_ACTION_MOVE; + else if (eina_streq(action, "privat")) return ECORE_X_ATOM_XDND_ACTION_PRIVATE; + else if (eina_streq(action, "ask")) return ECORE_X_ATOM_XDND_ACTION_ASK; + else if (eina_streq(action, "list")) return ECORE_X_ATOM_XDND_ACTION_LIST; + else if (eina_streq(action, "link")) return ECORE_X_ATOM_XDND_ACTION_LINK; + else if (eina_streq(action, "description")) return ECORE_X_ATOM_XDND_ACTION_DESCRIPTION; + return 0; +} + +static const char* +_x11_dnd_action_map(Ecore_X_Atom action) +{ + if (action == ECORE_X_DND_ACTION_COPY) return "copy"; + if (action == ECORE_X_ATOM_XDND_ACTION_MOVE) return "move"; + if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE) return "privat"; + if (action == ECORE_X_ATOM_XDND_ACTION_ASK) return "ask"; + if (action == ECORE_X_ATOM_XDND_ACTION_LIST) return "list"; + if (action == ECORE_X_ATOM_XDND_ACTION_LINK) return "link"; + if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION) return "description"; + + return "unknown"; +} + +static Eina_Bool +_ecore_evas_x_dnd_position(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Position *pos = event; + int x, y, w, h; + Ecore_Evas *ee; + + ee = ecore_event_window_match(pos->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + ecore_evas_geometry_get(ee, &x, &y, &w, &h); + ecore_evas_dnd_position_set(ee, 1, EINA_POSITION2D(pos->position.x - x, pos->position.y - y)); + ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, (Ecore_X_Rectangle){x,y,w,h}, pos->action); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_dnd_drop(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Drop *drop = event; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas *ee; + + ee = ecore_event_window_match(drop->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + edata = ee->engine.data; + if (ee->func.fn_dnd_drop) + ee->func.fn_dnd_drop(ee, 1, ecore_evas_dnd_pos_get(ee, 1), _x11_dnd_action_map(drop->action)); + if (!edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].requested_type) + { + ecore_x_dnd_send_finished(); + } + ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(drop->position.x ,drop->position.y)); + eina_array_free(edata->xserver_atom_name_during_dnd); + edata->xserver_atom_name_during_dnd = NULL; +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_finished(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Finished *finished = event; + Ecore_Evas *ee; + + ee = ecore_event_window_match(finished->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + + _clear_selection(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static void +_ecore_evas_x_selection_init(void) +{ + Ecore_X_Atom _ecore_evas_selection_to_atom[] = {ECORE_X_ATOM_SELECTION_PRIMARY, ECORE_X_ATOM_SELECTION_CLIPBOARD, ECORE_X_ATOM_SELECTION_XDND}; + + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + ecore_evas_selection_to_atom[i] = _ecore_evas_selection_to_atom[i]; + } + + ecore_evas_selection_handlers[0] = + ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, + _ecore_evas_x_selection_notify, NULL); + ecore_evas_selection_handlers[1] = + ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, + _ecore_evas_x_selection_clear, NULL); + if (ECORE_X_EVENT_FIXES_SELECTION_NOTIFY) + ecore_evas_selection_handlers[2] = + ecore_event_handler_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, + _ecore_evas_x_selection_fixes_notify, NULL); + + ecore_evas_selection_handlers[3] = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER, + _ecore_evas_x_dnd_enter, NULL); + ecore_evas_selection_handlers[4] = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE, + _ecore_evas_x_dnd_leave, NULL); + ecore_evas_selection_handlers[5] = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION, + _ecore_evas_x_dnd_position, NULL); + ecore_evas_selection_handlers[6] = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP, + _ecore_evas_x_dnd_drop, NULL); + ecore_evas_selection_handlers[7] = ecore_event_handler_add(ECORE_X_EVENT_XDND_FINISHED, + _ecore_evas_x_finished, NULL); + /* for us known type */ + char *supported_types[] = { + "text/plain", + "text/plain;charset=utf-8", + "image/png", + "image/jpeg", + "image/x-ms-bmp", + "image/gif", + "image/tiff", + "image/svg+xml", + "image/x-xpixmap", + "image/x-tga", + "image/x-portable-pixmap", + "TEXT", + "COMPOUND_TEXT", + "STRING", + "UTF8_STRING", + "text/x-vcard", + "text/uri-list", + "application/x-elementary-markup", + "ATOM", + "TARGETS", + NULL + }; + for (int i = 0; supported_types[i]; ++i) + { + ecore_x_selection_converter_add(supported_types[i], _eina_content_converter); + } +} + +static Eina_Bool +_ecore_evas_x_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection) +{ + return !!ecore_x_selection_owner_get(ecore_evas_selection_to_atom[selection]); +} + +static void +_deliver_selection_changed(void *data) +{ + Ecore_Evas *ee = data; + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + + if (!ee->func.fn_selection_changed) + goto end; + + if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)) + ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER); + if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)) + ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); + if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)) + ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER); +end: + edata->init_job = NULL; +} + +static void +_ecore_evas_x_selection_window_init(Ecore_Evas *ee) +{ + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + ecore_x_fixes_window_selection_notification_request(ee->prop.window, ecore_evas_selection_to_atom[i]); + edata->selection_data[i].ee = ee; + edata->selection_data[i].buffer = i; + } + ecore_x_dnd_aware_set(ee->prop.window, EINA_TRUE); + edata->init_job = ecore_job_add(_deliver_selection_changed, ee); +} + +static void +_store_selection_cbs(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Eina_Bool (*delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice), void (*cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer)) +{ + Ecore_Evas_X11_Selection_Data *sdata; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas_Selection_Callbacks *cbs; + + edata = ee->engine.data; + sdata = &edata->selection_data[selection]; + cbs = &sdata->callbacks; + + if (cbs->cancel) + { + _clear_selection(ee, selection); + edata->skip_clean_event ++; //we are going to overwrite our own selection, this will emit a clean event, but we already freed it. + } + + cbs->delivery = delivery; + cbs->cancel = cancel; + cbs->available_types = available_types; +} + +static Eina_Bool +_ecore_evas_x_selection_claim(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +{ + Ecore_Evas_X11_Selection_Data *sdata; + Ecore_Evas_Engine_Data_X11 *edata; + + edata = ee->engine.data; + sdata = &edata->selection_data[selection]; + + _store_selection_cbs(ee, selection, available_types, delivery, cancel); + + if (eina_array_count(available_types) > 0) + { + //the commands below will *copy* the content of sdata, this you have to ensure that clear is called when sdata is changed. + if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + ecore_x_selection_primary_set(ee->prop.window, sdata, sizeof(Ecore_Evas_X11_Selection_Data)); + else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + ecore_x_selection_clipboard_set(ee->prop.window, sdata, sizeof(Ecore_Evas_X11_Selection_Data)); + } + else + { + if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + ecore_x_selection_primary_clear(); + else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + ecore_x_selection_clipboard_clear(); + } + + //for drag and drop, we are not calling anything in here + + return EINA_TRUE; +} + +Eina_Future* +_ecore_evas_x_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type) +{ + Ecore_Evas_X11_Selection_Data *sdata; + Ecore_Evas_Engine_Data_X11 *edata; + Eina_Future *future; + + edata = ee->engine.data; + sdata = &edata->selection_data[selection]; + + if (sdata->delivery) + { + eina_promise_reject(sdata->delivery, ecore_evas_request_replaced); + _clear_selection_delivery(ee, selection); + } + sdata->delivery = efl_loop_promise_new(efl_main_loop_get()); + sdata->acceptable_type = acceptable_type; + future = eina_future_new(sdata->delivery); + + if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + //when in dnd - we are requesting out of the set that we know from the enter event + EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, NULL); + EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, NULL); + _search_fitting_type(ee, edata, selection, edata->xserver_atom_name_during_dnd); + } + else + { + //when not dnd - we are first wanting to know what is available + _ecore_x_selection_request(ee->prop.window, selection, ECORE_X_SELECTION_TARGET_TARGETS); + } + + return future; +} + +static void +_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos) +{ + Ecore_Evas *ee = data; + Eina_Rect rect; + + ecore_evas_geometry_get(ee->drag.rep, &rect.x, &rect.y, &rect.w, &rect.h); + + ecore_evas_move(ee->drag.rep, pos->position.x - rect.w / 2, pos->position.y - rect.h/2); +} + +static Eina_Bool +_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event EINA_UNUSED) +{ + Ecore_Evas *ee = data; + + _force_stop_self_dnd(ee); + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_x_dnd_start(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Array *available_types, Ecore_Evas *drag_rep, Eina_Bool (*delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice), void (*cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer), const char* action) +{ + Ecore_Evas_X11_Selection_Data *sdata; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_X_Atom actx; + + edata = ee->engine.data; + sdata = &edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER]; + _store_selection_cbs(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, available_types, delivery, cancel); + + //first set all types we have + ecore_x_dnd_types_set(ee->prop.window, NULL, 0); + for (unsigned int i = 0; i < eina_array_count(available_types); ++i) + { + const char *xserver_mime_type = _mime_to_xserver_type(eina_array_data_get(available_types, i)); + ecore_x_dnd_type_set(ee->prop.window, xserver_mime_type, EINA_TRUE); + eina_stringshare_del(xserver_mime_type); + } + ecore_x_dnd_aware_set(ee->prop.window, EINA_TRUE); + ecore_x_dnd_callback_pos_update_set(_x11_drag_move, ee); + ecore_x_dnd_self_begin(ee->prop.window, (unsigned char*)sdata, sizeof(Ecore_Evas_X11_Selection_Data)); + actx = _x11_dnd_action_rev_map(action); + ecore_x_dnd_source_action_set(actx); + ecore_x_pointer_grab(ee->prop.window); + + ecore_x_window_ignore_set(drag_rep->prop.window, EINA_TRUE); + + if (edata->mouse_up_handler) + ecore_event_handler_del(edata->mouse_up_handler); + edata->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, + _x11_drag_mouse_up, ee); + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_x_dnd_stop(Ecore_Evas *ee, unsigned int seat EINA_UNUSED) +{ + _force_stop_self_dnd(ee); + _clear_selection(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER); + ecore_x_selection_xdnd_clear(); //This is needed otherwise a outdated sdata struct will be accessed + return EINA_TRUE; +} + static Ecore_Evas_Engine_Func _ecore_x_engine_func = { _ecore_evas_x_free, @@ -3754,9 +4500,11 @@ static Ecore_Evas_Engine_Func _ecore_x_engine_func = NULL, //fn_pointer_device_xy_get NULL, //fn_prepare NULL, //fn_last_tick_get - NULL, //fn_selection_claim - NULL, //fn_selection_has_owner - NULL, //fn_selection_request + _ecore_evas_x_selection_claim, //fn_selection_claim + _ecore_evas_x_selection_has_owner, //fn_selection_has_owner + _ecore_evas_x_selection_request, //fn_selection_request + _ecore_evas_x_dnd_start, //fn_dnd_start + _ecore_evas_x_dnd_stop, //fn_dnd_stop }; /* @@ -4120,6 +4868,7 @@ ecore_evas_software_x11_new_internal(const char *disp_name, Ecore_X_Window paren _ecore_evas_x_wm_rotation_protocol_set(ee); _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); + _ecore_evas_x_selection_window_init(ee); ee->engine.func->fn_render = _ecore_evas_x_render; ee->draw_block = EINA_TRUE; @@ -4556,6 +5305,7 @@ ecore_evas_gl_x11_options_new_internal(const char *disp_name, Ecore_X_Window par _ecore_evas_x_wm_rotation_protocol_set(ee); _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); + _ecore_evas_x_selection_window_init(ee); ee->draw_block = 1; if (!wm_exists) edata->configured = 1; From 5ac02ec9acdd2b9b5bf7b0e6bb4dcd99cb6f63d7 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Mon, 10 Feb 2020 09:20:18 +0100 Subject: [PATCH 06/17] ecore_evas: introduce wayland support for cnp & dnd This adds cnp support, actions are right now only mapped to "ask", further support can be added there, and synchronization can be added to register more available actions. However, i did not find *any* wayland implementation in gtk qt nor chromiumos that even use the action to indicate anything. This here also has a slightly different behaviour to X11 in terms of coordinates for motion,leave,enter. They can contain negative coordinates (which is due to the fact that wl is CSD and X11 is SSD. However, I did not want to fix this in any regard, as you might want to use that, and it would be a none trivial amount of code to fix that. Reviewed-by: Chris Michael Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11329 --- .../wayland/ecore_evas_wayland_common.c | 471 +++++++++++++++++- .../wayland/ecore_evas_wayland_private.h | 16 +- 2 files changed, 482 insertions(+), 5 deletions(-) diff --git a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c index e0e2094e2f..d5cb3d8b49 100644 --- a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c +++ b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c @@ -4,6 +4,7 @@ #include "ecore_evas_wayland_private.h" #include +#include "ecore_wl2_internal.h" extern EAPI Eina_List *_evas_canvas_image_data_unset(Evas *eo_e); extern EAPI void _evas_canvas_image_data_regenerate(Eina_List *list); @@ -32,6 +33,7 @@ static Eina_Array *_ecore_evas_wl_event_hdls; static void _ecore_evas_wayland_resize(Ecore_Evas *ee, int location); static void _ecore_evas_wl_common_rotation_set(Ecore_Evas *ee, int rotation, int resize); +static void _ecore_evas_wl_selection_init(Ecore_Evas *ee); /* local functions */ static void @@ -1440,6 +1442,15 @@ _ecore_evas_wl_common_free(Ecore_Evas *ee) if (wdata->frame) ecore_wl2_window_frame_callback_del(wdata->frame); wdata->frame = NULL; ecore_event_handler_del(wdata->sync_handler); + ecore_event_handler_del(wdata->changed_handler); + ecore_event_handler_del(wdata->send_handler); + ecore_event_handler_del(wdata->offer_handler); + ecore_event_handler_del(wdata->dnd_leave_handler); + ecore_event_handler_del(wdata->dnd_enter_handler); + ecore_event_handler_del(wdata->dnd_motion_handler); + ecore_event_handler_del(wdata->dnd_drop_handler); + ecore_event_handler_del(wdata->dnd_end_handler); + if (wdata->win) { ecore_wl2_window_close_callback_set(wdata->win, NULL, NULL); @@ -2389,6 +2400,457 @@ _ecore_wl2_devices_setup(Ecore_Evas *ee, Ecore_Wl2_Display *display) return r; } +static void +_reeval_seat(unsigned int *seat, Ecore_Evas *ee) +{ + if (*seat == 0) + *seat = evas_device_seat_id_get(evas_default_device_get(ee->evas, EFL_INPUT_DEVICE_TYPE_SEAT)); +} + +static inline void +_clear_selection(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection) +{ + Ecore_Evas_Engine_Wl_Data *edata = ee->engine.data; + Ecore_Evas_Selection_Callbacks *cbs = &edata->selection_data[selection].callbacks; + + EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel); + + cbs->cancel(ee, seat, selection); + eina_array_free(cbs->available_types); + memset(cbs, 0, sizeof(Ecore_Evas_Selection_Callbacks)); +} + +static void +_store_selection_cbs(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +{ + Ecore_Evas_Wl_Selection_Data *sdata; + Ecore_Evas_Engine_Wl_Data *edata; + Ecore_Evas_Selection_Callbacks *cbs; + + edata = ee->engine.data; + sdata = &edata->selection_data[selection]; + cbs = &sdata->callbacks; + + if (cbs->cancel) + { + _clear_selection(ee, seat, selection); + } + + cbs->delivery = delivery; + cbs->cancel = cancel; + cbs->available_types = available_types; +} + +static inline Ecore_Wl2_Input* +_fetch_input(Ecore_Evas *ee, unsigned int seat) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + return ecore_wl2_display_input_find(ecore_wl2_window_display_get(wdata->win), seat); +} + +static Eina_Bool +_ecore_evas_wl_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection]; + char *tmp_array[eina_array_count(available_types) + 1]; + + if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + { + _store_selection_cbs(ee, seat, selection, available_types, delivery, cancel); + return EINA_TRUE; + } + + _reeval_seat(&seat, ee); + _store_selection_cbs(ee, seat, selection, available_types, delivery, cancel); + + for (unsigned int i = 0; i < eina_array_count(available_types); ++i) + { + tmp_array[i] = eina_array_data_get(available_types, i); + } + tmp_array[eina_array_count(available_types)] = NULL; + + data->sent_serial = ecore_wl2_dnd_selection_set(_fetch_input(ee, seat), (const char**)tmp_array); + return EINA_TRUE; +} + + +static Eina_Future* +_ecore_evas_wl_selection_request(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_types) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection]; + Ecore_Wl2_Input *input; + Ecore_Wl2_Offer *offer = NULL; + Eina_Future *future; + + _reeval_seat(&seat, ee); + input = _fetch_input(ee, seat); + + if (data->delivery) + { + eina_promise_reject(data->delivery, ecore_evas_request_replaced); + data->delivery = NULL; + } + data->delivery = efl_loop_promise_new(efl_main_loop_get()); + future = eina_future_new(data->delivery); + + if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + offer = data->offer = wdata->external_offer; + } + else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + { + offer = data->offer = ecore_wl2_dnd_selection_get(input); + } + + if (!offer) + { + eina_promise_reject(data->delivery, ecore_evas_no_selection); + data->delivery = NULL; + } + else + { + Eina_Array *available_types = ecore_wl2_offer_mimes_get(offer); + char *selected_type = NULL; + + for (unsigned int i = 0; i < eina_array_count(available_types) && !selected_type; ++i) + { + char *available_type = eina_array_data_get(available_types, i); + for (unsigned int j = 0; j < eina_array_count(acceptable_types) && !selected_type; ++j) + { + char *acceptable_type = eina_array_data_get(acceptable_types, j); + if (eina_streq(acceptable_type, available_type)) + { + selected_type = available_type; + data->later_convert = NULL; + break; + } + + const char *convert_available_type; + Eina_Iterator *convertions = eina_content_converter_possible_conversions(available_type); + EINA_ITERATOR_FOREACH(convertions, convert_available_type) + { + if (eina_streq(convert_available_type, acceptable_type)) + { + selected_type = available_type; + data->later_convert = acceptable_type; + } + } + eina_iterator_free(convertions); + } + + } + if (selected_type) + { + ecore_wl2_offer_receive(offer, selected_type); + ecore_wl2_display_flush(ecore_wl2_input_display_get(input)); + } + else + { + eina_promise_reject(data->delivery, ecore_evas_no_matching_type); + data->delivery = NULL; + } + } + + return future; +} + +static Eina_Bool +_ecore_evas_wl_selection_has_owner(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection EINA_UNUSED) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Wl2_Input *input; + + _reeval_seat(&seat, ee); + input = _fetch_input(ee, seat); + + if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER ) + return !!ecore_wl2_dnd_selection_get(input); + else if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection]; + return !!data->offer; + } + + return EINA_FALSE; //the selection buffer is not supportet in wayland +} + +static Eina_Bool +_wl_selection_changed(void *data, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + Ecore_Wl2_Event_Seat_Selection *sel = event; + Ecore_Evas *ee = data; + Ecore_Wl2_Input *input; + unsigned int seat = sel->seat; + + _reeval_seat(&seat, ee); + input = _fetch_input(ee, seat); + if (!ecore_wl2_dnd_selection_get(input)) + return ECORE_CALLBACK_PASS_ON; + + if (ee->func.fn_selection_changed) + ee->func.fn_selection_changed(ee, 0, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); + + return ECORE_CALLBACK_PASS_ON; +} + +typedef struct { + Eina_Rw_Slice slice; + unsigned int written_bytes; +} Delayed_Writing; + +static Eina_Bool +_write_to_fd(void *data, Ecore_Fd_Handler *fd_handler) +{ + int fd = ecore_main_fd_handler_fd_get(fd_handler); + Delayed_Writing *slice = data; + + size_t len = write(fd, slice->slice.mem + slice->written_bytes, slice->slice.len - slice->written_bytes); + + slice->written_bytes += len; + if (slice->written_bytes != slice->slice.len) + { + return EINA_TRUE; + } + else + { + ecore_main_fd_handler_del(fd_handler); + free(slice->slice.mem); + free(slice); + close(fd); + return EINA_FALSE; + } + +} + +static Eina_Bool +_wl_interaction_send(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Wl2_Event_Data_Source_Send *ev = event; + Ecore_Evas *ee = data; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Evas_Wl_Selection_Data *selection = NULL; + Delayed_Writing *forign_slice = calloc(1, sizeof(Delayed_Writing)); + Ecore_Evas_Selection_Buffer buffer = ECORE_EVAS_SELECTION_BUFFER_LAST; + + if (ev->serial == wdata->selection_data[ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER].sent_serial) + buffer = ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER; + else if (ev->serial == wdata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].sent_serial) + { + buffer = ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER; + ee->drag.accepted = EINA_TRUE; + } + + if (buffer == ECORE_EVAS_SELECTION_BUFFER_LAST) + { + //silent return, this send request was *not* for this window + return ECORE_CALLBACK_PASS_ON; + } + + selection = &wdata->selection_data[buffer]; + EINA_SAFETY_ON_NULL_GOTO(selection, end); + EINA_SAFETY_ON_NULL_GOTO(selection->callbacks.delivery, end); + EINA_SAFETY_ON_FALSE_GOTO(selection->callbacks.delivery(ee, ev->seat, buffer, ev->type, &forign_slice->slice), end); + ecore_main_fd_handler_add(ev->fd, ECORE_FD_WRITE, _write_to_fd, forign_slice, NULL, NULL); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_wl_selection_receive(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Wl2_Event_Offer_Data_Ready *ready = event; + Ecore_Evas_Selection_Buffer selection = ECORE_EVAS_SELECTION_BUFFER_LAST; + + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (wdata->selection_data[i].offer == ready->offer) + { + selection = i; + break; + } + } + + if (selection == ECORE_EVAS_SELECTION_BUFFER_LAST) + return ECORE_CALLBACK_PASS_ON; + + //Now deliver the content + Eina_Slice slice; + + if (!strncmp(ready->mimetype, "text", strlen("text"))) + { + //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. + slice.len = ready->len + 1; + slice.mem = eina_memdup((unsigned char*)ready->data, ready->len, EINA_TRUE); + } + else + { + slice.len = ready->len; + slice.mem = ready->data; + } + + Eina_Content *content = eina_content_new(slice, ready->mimetype); + + if (wdata->selection_data[selection].later_convert) + { + Eina_Content *tmp = eina_content_convert(content, wdata->selection_data[selection].later_convert); + wdata->selection_data[selection].later_convert = NULL; + eina_content_free(content); + content = tmp; + } + + eina_promise_resolve(wdata->selection_data[selection].delivery, eina_value_content_init(content)); + wdata->selection_data[selection].delivery = NULL; + eina_content_free(content); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_wl_selection_dnd_leave(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Eina_Position2D cpos; + Eina_Position2D fpos = EINA_POSITION2D(0, 0); + Ecore_Wl2_Event_Dnd_Leave *ev = event; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + + //evas_output_framespace_get(ee->evas, &fpos.x, &fpos.y, NULL, NULL); + ecore_wl2_input_pointer_xy_get(ecore_wl2_display_input_find(ev->display, ev->seat), &cpos.x, &cpos.y); + ecore_evas_dnd_leave(data, ev->seat, EINA_POSITION2D(cpos.x - fpos.x, cpos.y - fpos.y)); + wdata->external_offer = NULL; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_wl_selection_dnd_motion(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Wl2_Event_Dnd_Motion *ev = event; + Eina_Position2D fpos = EINA_POSITION2D(0, 0); + + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + + evas_output_framespace_get(ee->evas, &fpos.x, &fpos.y, NULL, NULL); + ecore_evas_dnd_position_set(data, ev->seat, EINA_POSITION2D(ev->x - fpos.x, ev->y - fpos.y)); + return ECORE_CALLBACK_PASS_ON; +} +static Eina_Bool +_wl_selection_dnd_enter(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Wl2_Event_Dnd_Enter *ev = event; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Eina_Position2D fpos = EINA_POSITION2D(0, 0); + + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + + evas_output_framespace_get(ee->evas, &fpos.x, &fpos.y, NULL, NULL); + ecore_evas_dnd_enter(data, ev->seat, eina_array_iterator_new(ecore_wl2_offer_mimes_get(ev->offer)), EINA_POSITION2D(ev->x - fpos.x, ev->y - fpos.y)); + ecore_wl2_offer_mimes_set(ev->offer, ecore_wl2_offer_mimes_get(ev->offer)); + wdata->external_offer = ev->offer; + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_wl_selection_dnd_drop(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Wl2_Event_Dnd_Drop *ev = event; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + wdata = ee->engine.data; + + if (ee->func.fn_dnd_drop) + ee->func.fn_dnd_drop(ee, ev->seat, ecore_evas_dnd_pos_get(ee, ev->seat), "ask"); + + ecore_wl2_dnd_drag_end(_fetch_input(ee, ev->seat)); + wdata->external_offer = NULL; + + return ECORE_CALLBACK_PASS_ON; +} +static Eina_Bool +_wl_selection_dnd_end(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Wl2_Event_Dnd_End *ev = event; + + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + + + if (ee->drag.free) + ee->drag.free(ee, ev->seat, ee->drag.data, ee->drag.accepted); + ee->drag.free = NULL; + //we got dropped, we should call + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_ecore_evas_wl_selection_init(Ecore_Evas *ee) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + + wdata->changed_handler = ecore_event_handler_add(ECORE_WL2_EVENT_SEAT_SELECTION, + _wl_selection_changed, ee); + wdata->send_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, + _wl_interaction_send, ee); + wdata->offer_handler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, + _wl_selection_receive, ee); + wdata->dnd_leave_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_LEAVE, + _wl_selection_dnd_leave, ee); + wdata->dnd_motion_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, + _wl_selection_dnd_motion, ee); + wdata->dnd_enter_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_ENTER, + _wl_selection_dnd_enter, ee); + wdata->dnd_drop_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, + _wl_selection_dnd_drop, ee); + wdata->dnd_end_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_DROP, + _wl_selection_dnd_end, ee); + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + wdata->selection_data[i].callbacks.available_types = NULL; + wdata->selection_data[i].callbacks.delivery = NULL; + wdata->selection_data[i].callbacks.cancel = NULL; + } +} + +static Eina_Bool +_ecore_evas_wl_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel, const char *action EINA_UNUSED) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + const char *tmp_array[eina_array_count(available_types) + 1]; + + _reeval_seat(&seat, ee); + _store_selection_cbs(ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, available_types, delivery, cancel); + + for (unsigned int i = 0; i < eina_array_count(available_types); ++i) + { + tmp_array[i] = eina_array_data_get(available_types, i); + } + tmp_array[eina_array_count(available_types)] = NULL; + + ecore_wl2_dnd_drag_types_set(_fetch_input(ee, seat), (const char**)tmp_array); + wdata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].sent_serial = + ecore_wl2_dnd_drag_start(_fetch_input(ee, seat), _ecore_evas_wayland_window_get(ee), _ecore_evas_wayland_window_get(drag_rep)); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_wl_dnd_stop(Ecore_Evas *ee, unsigned int seat) +{ + _clear_selection(ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER); + _reeval_seat(&seat, ee); + ecore_wl2_dnd_drag_end(_fetch_input(ee, seat)); + return EINA_TRUE; +} + static Ecore_Evas_Engine_Func _ecore_wl_engine_func = { _ecore_evas_wl_common_free, @@ -2474,9 +2936,11 @@ static Ecore_Evas_Engine_Func _ecore_wl_engine_func = _ecore_evas_wl_common_pointer_device_xy_get, _ecore_evas_wl_common_prepare, NULL, //fn_last_tick_get - NULL, //fn_selection_claim - NULL, //fn_selection_has_owner - NULL, //fn_selection_request + _ecore_evas_wl_selection_claim, //fn_selection_claim + _ecore_evas_wl_selection_has_owner, //fn_selection_has_owner + _ecore_evas_wl_selection_request, //fn_selection_request + _ecore_evas_wl_dnd_start, //fn_dnd_start + _ecore_evas_wl_dnd_stop, //fn_dnd_stop }; static void @@ -2653,6 +3117,7 @@ _ecore_evas_wl_common_new_internal(const char *disp_name, Ecore_Window parent, i } _ecore_evas_wl_common_wm_rotation_protocol_set(ee); + _ecore_evas_wl_selection_init(ee); ecore_evas_done(ee, EINA_FALSE); diff --git a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h index e69970f262..d042719d93 100644 --- a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h +++ b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h @@ -34,12 +34,23 @@ typedef struct _Ecore_Evas_Engine_Wl_Data Ecore_Evas_Engine_Wl_Data; +typedef struct _Ecore_Evas_Wl_Selection_Data Ecore_Evas_Wl_Selection_Data; + +struct _Ecore_Evas_Wl_Selection_Data +{ + Ecore_Evas_Selection_Callbacks callbacks; + Eina_Promise *delivery; + Ecore_Wl2_Offer *offer; + const char *later_convert; + uint32_t sent_serial; //The serial of the last sent selection op +}; + struct _Ecore_Evas_Engine_Wl_Data { Ecore_Wl2_Display *display; Eina_List *regen_objs; Ecore_Wl2_Window *parent, *win; - Ecore_Event_Handler *sync_handler; + Ecore_Event_Handler *sync_handler, *changed_handler, *end_handler, *send_handler, *offer_handler, *dnd_leave_handler, *dnd_motion_handler, *dnd_enter_handler, *dnd_drop_handler, *dnd_end_handler; int fx, fy, fw, fh; Ecore_Wl2_Frame_Cb_Handle *frame; int x_rel; @@ -47,7 +58,8 @@ struct _Ecore_Evas_Engine_Wl_Data uint32_t timestamp; Eina_List *devices_list; int cw, ch; - + Ecore_Evas_Wl_Selection_Data selection_data[ECORE_EVAS_SELECTION_BUFFER_LAST]; + Ecore_Wl2_Offer *external_offer; struct { Eina_Bool supported : 1; From 165f6f0ae285dd495547eb3dbca521ce2cfc184e Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Sun, 19 Jan 2020 13:58:26 +0100 Subject: [PATCH 07/17] rewrite efl cnp and dnd handling the previous commits introduced a abstraction for drag in drop which can be now used for this here. With this commit all the direct protocol handling in efl.ui is removed, and only the ecore evas API is used. Additionally, this lead to a giant refactor of how APIs do work. All Efl.Ui. interfaces have been removed except Efl.Ui.Selection and Efl.Ui.Dnd, these two have been restructored. A small list of what is new: - In general no function pointers are used anymore. They feel very uncompftable in bindings and in C. For us its a lot easier to just listen to a event when a drop enters or leaves, there is no need to register custom functions for that. - Asynchronous data transphere is handled via futures, which proved to be more error safe. - Formats and actions are handled as mime types / strings. - 0 is the default seat if you do not know what else to take. - Content is in general passes as a content container from eina, this also allows applications to pass custom types The legacy dnd and cnp API is implemented based on that. All cnp related things are in elm_cnp.c the dnd parts are in elm_dnd.c Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11190 --- src/lib/elementary/Efl_Ui.h | 3 - src/lib/elementary/efl_ui_dnd.c | 898 +-- src/lib/elementary/efl_ui_dnd.eo | 88 +- src/lib/elementary/efl_ui_dnd_container.eo | 46 - src/lib/elementary/efl_ui_dnd_types.eot | 60 - src/lib/elementary/efl_ui_selection.c | 313 +- src/lib/elementary/efl_ui_selection.eo | 98 +- src/lib/elementary/efl_ui_selection_manager.c | 5678 ----------------- .../elementary/efl_ui_selection_manager.eo | 139 - src/lib/elementary/efl_ui_selection_types.eot | 60 - src/lib/elementary/efl_ui_tags.c | 2 +- src/lib/elementary/efl_ui_textbox.c | 362 +- src/lib/elementary/efl_ui_textbox.eo | 12 +- src/lib/elementary/efl_ui_win.c | 252 + src/lib/elementary/elm_cnp.c | 244 + src/lib/elementary/elm_cnp.h | 2 - src/lib/elementary/elm_dnd.c | 812 +++ src/lib/elementary/elm_entry.c | 6 +- src/lib/elementary/elm_main.c | 1 - src/lib/elementary/elm_priv.h | 10 +- src/lib/elementary/meson.build | 7 +- src/lib/eo/eina_types.eot | 2 + src/lib/evas/canvas/evas_main.c | 18 + src/tests/elementary/efl_ui_test_text.c | 14 +- 24 files changed, 1782 insertions(+), 7345 deletions(-) delete mode 100644 src/lib/elementary/efl_ui_dnd_container.eo delete mode 100644 src/lib/elementary/efl_ui_dnd_types.eot delete mode 100644 src/lib/elementary/efl_ui_selection_manager.c delete mode 100644 src/lib/elementary/efl_ui_selection_manager.eo delete mode 100644 src/lib/elementary/efl_ui_selection_types.eot create mode 100644 src/lib/elementary/elm_cnp.c create mode 100644 src/lib/elementary/elm_dnd.c diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h index 5bed200264..81f4522c71 100644 --- a/src/lib/elementary/Efl_Ui.h +++ b/src/lib/elementary/Efl_Ui.h @@ -119,8 +119,6 @@ extern EAPI Eina_Error EFL_UI_THEME_APPLY_ERROR_NONE; // EO types. Defined for legacy-only builds as legacy uses typedef of EO types. #include "efl_ui.eot.h" -#include "efl_ui_selection_types.eot.h" -#include "efl_ui_dnd_types.eot.h" //define focus manager earlier since focus object and manager is circular typedef Eo Efl_Ui_Focus_Manager; @@ -322,7 +320,6 @@ typedef Eo Efl_Ui_Spotlight_Indicator; # include # include # include -# include # include # include diff --git a/src/lib/elementary/efl_ui_dnd.c b/src/lib/elementary/efl_ui_dnd.c index df79eb9762..e8bf19320b 100644 --- a/src/lib/elementary/efl_ui_dnd.c +++ b/src/lib/elementary/efl_ui_dnd.c @@ -12,838 +12,140 @@ #include #include "elm_priv.h" -typedef struct _Efl_Ui_Dnd_Container_Data Efl_Ui_Dnd_Container_Data; -struct _Efl_Ui_Dnd_Container_Data -{ - unsigned int drag_delay_time; -}; +typedef struct { + Ecore_Evas *ee; + Eina_Bool registered; +} Efl_Ui_Dnd_Data; -extern int _wl_default_seat_id_get(Evas_Object *obj); -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -#endif - -Eo* -_efl_ui_selection_manager_get(Eo *obj) -{ - if (!efl_isa(obj, EFL_UI_WIDGET_CLASS)) return NULL; - Eo *app = efl_app_main_get(); - Eo *sel_man = efl_key_data_get(app, "__selection_manager"); - if (!sel_man) - { - sel_man = efl_add(EFL_UI_SELECTION_MANAGER_CLASS, app); - efl_key_data_set(app, "__selection_manager", sel_man); - } - return sel_man; -} - -void -_efl_ui_dnd_shutdown(void) -{ - Eo *app = efl_app_main_get(); - Eo *sel_man = efl_key_data_get(app, "__selection_manager"); - - efl_del(sel_man); -} - -EOLIAN static void -_efl_ui_dnd_drag_start(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, Eina_Slice data, - Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_start(sel_man, obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - seat); -} - -EOLIAN static void -_efl_ui_dnd_drag_cancel(Eo *obj, void *pd EINA_UNUSED, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_cancel(sel_man, obj, seat); -} - -EOLIAN static void -_efl_ui_dnd_drag_action_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Action action, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_action_set(sel_man, obj, action, seat); -} - - -EOLIAN static void -_efl_ui_dnd_drop_target_add(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drop_target_add(sel_man, obj, format, seat); -} - -EOLIAN static void -_efl_ui_dnd_drop_target_del(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drop_target_del(sel_man, obj, format, seat); -} - -EOLIAN static double -_efl_ui_dnd_container_drag_delay_time_get(const Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd) -{ - return pd->drag_delay_time; -} - -EOLIAN static void -_efl_ui_dnd_container_drag_delay_time_set(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd, double drag_delay_time) -{ - pd->drag_delay_time = drag_delay_time; -} - -EOLIAN static void -_efl_ui_dnd_container_drag_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd, - void *data_func_data, Efl_Dnd_Drag_Data_Get data_func, Eina_Free_Cb data_func_free_cb, - void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - void *icon_list_func_data, Efl_Dnd_Drag_Icon_List_Create icon_list_func, Eina_Free_Cb icon_list_func_free_cb, - unsigned int seat) -{ - double drag_delay_time = pd->drag_delay_time; - double anim_time = elm_config_drag_anim_duration_get(); - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drag_item_add(sel_man, obj, drag_delay_time, anim_time, - data_func_data, data_func, data_func_free_cb, - item_func_data, item_func, item_func_free_cb, - icon_func_data, icon_func, icon_func_free_cb, - icon_list_func_data, icon_list_func, icon_list_func_free_cb, - seat); -} +typedef struct { + Eo *win; + Efl_Ui_Dnd *obj; +} Efl_Ui_Drag_Start; static void -_efl_ui_dnd_container_drag_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat) +_ecore_evas_drag_terminated(Ecore_Evas *ee EINA_UNUSED, unsigned int seat, void *data, Eina_Bool accepted) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seat); + Efl_Ui_Drag_Start *start = data; + Efl_Ui_Drag_Finished_Event ev = {seat, accepted}; + efl_event_callback_call(start->obj, EFL_UI_DND_EVENT_DRAG_FINISHED, &ev); + efl_del(start->win); + free(start); } -EOLIAN static void -_efl_ui_dnd_container_drop_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, - Efl_Ui_Selection_Format format, - void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb, - unsigned int seat) + +EOLIAN static Efl_Content* +_efl_ui_dnd_drag_start(Eo *obj, Efl_Ui_Dnd_Data *pd, Eina_Content *content, const char* action, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drop_item_add(sel_man, obj, format, item_func_data, item_func, item_func_free_cb, seat); + Eo *drag_win; + Efl_Ui_Drag_Start *start; + Efl_Ui_Drag_Started_Event ev = {seat}; + Ecore_Evas *drag_ee; + EINA_SAFETY_ON_NULL_RETURN_VAL(pd->ee, NULL); + + start = calloc(1, sizeof(Efl_Ui_Drag_Start)); + start->obj = obj; + start->win = drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); + elm_win_alpha_set(drag_win, EINA_TRUE); + elm_win_override_set(drag_win, EINA_TRUE); + elm_win_borderless_set(drag_win, EINA_TRUE); + drag_ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_win)); + + ecore_evas_drag_start(pd->ee, seat, content, drag_ee, action, _ecore_evas_drag_terminated, start); + + evas_object_show(drag_win); + + efl_event_callback_call(obj, EFL_UI_DND_EVENT_DRAG_STARTED, &ev); + + return drag_win; } EOLIAN static void -_efl_ui_dnd_container_drop_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat) +_efl_ui_dnd_drag_cancel(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seat); + ecore_evas_drag_cancel(pd->ee, seat); } - -/////////// -typedef struct _Dnd_Icon_Create Dnd_Icon_Create; -typedef struct _Dnd_Drag_Pos Dnd_Drag_Pos; -typedef struct _Dnd_Drag_Accept Dnd_Drag_Accept; -typedef struct _Dnd_Drag_Done Dnd_Drag_Done; -typedef struct _Dnd_Drag_State Dnd_Drag_State; -typedef struct _Dnd_Drop Dnd_Drop; -typedef struct _Dnd_Cont_Drag_Pos Dnd_Cont_Drag_Pos; -typedef struct _Dnd_Cont_Drop Dnd_Cont_Drop; -typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info; - -struct _Dnd_Icon_Create +EOLIAN static Eina_Future* +_efl_ui_dnd_drop_data_get(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat, Eina_Iterator *acceptable_types) { - void *icon_data; - Elm_Drag_Icon_Create_Cb icon_cb; -}; - -struct _Dnd_Drag_Pos -{ - void *pos_data; - Elm_Drag_Pos pos_cb; -}; - -struct _Dnd_Drag_Accept -{ - void *accept_data; - Elm_Drag_Accept accept_cb; -}; - -struct _Dnd_Drag_Done -{ - void *done_data; - Elm_Drag_State done_cb; - - //for deleting - Dnd_Drag_Pos *pos; - Dnd_Drag_Accept *accept; -}; - -struct _Dnd_Drag_State -{ - void *state_data; - Elm_Drag_State state_cb; -}; - -struct _Dnd_Drop -{ - Efl_Object *obj; - Elm_Sel_Format format; - void *drop_data; - Elm_Drop_Cb drop_cb; - - //for deleting - Dnd_Drag_State *enter; - Dnd_Drag_State *leave; - Dnd_Drag_Pos *pos; -}; - -struct _Dnd_Cont_Drag_Pos -{ - void *pos_data; - Elm_Drag_Item_Container_Pos pos_cb; - Elm_Xy_Item_Get_Cb item_get_cb; -}; - -struct _Dnd_Cont_Drop -{ - Efl_Object *obj; - Elm_Sel_Format format; - void *drop_data; - Elm_Drop_Item_Container_Cb drop_cb; - Elm_Xy_Item_Get_Cb item_get_cb; - - //for deleting - Dnd_Drag_State *enter; - Dnd_Drag_State *leave; - Dnd_Cont_Drag_Pos *pos; -}; - -struct _Item_Container_Drag_Info -{ - Elm_Drag_User_Info user_info; - Elm_Object_Item *it; - Elm_Item_Container_Data_Get_Cb data_get_cb; - Elm_Xy_Item_Get_Cb item_get_cb; -}; - -static Efl_Object * -_dnd_icon_create_cb(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret) -{ - Dnd_Icon_Create *ic = data; - Efl_Object *ret = ic->icon_cb(ic->icon_data, win, &pos_ret->x, &pos_ret->y); - - free(ic); - return ret; + return ecore_evas_selection_get(pd->ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, acceptable_types); } -static void -_dnd_drag_pos_cb(void *data, const Efl_Event *event) +EOLIAN static Efl_Object * +_efl_ui_dnd_efl_object_constructor(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Drag_Pos *pos = data; - Efl_Dnd_Drag_Pos *ddata = event->info; + if (!efl_constructor(efl_super(obj, EFL_UI_DND_MIXIN))) + return NULL; - if (pos->pos_cb) - pos->pos_cb(pos->pos_data, event->object, ddata->pos.x, ddata->pos.y, - (Elm_Xdnd_Action)ddata->action); -} - -static void -_dnd_drag_accept_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_Accept *accept = data; - - if (accept->accept_cb) - accept->accept_cb(accept->accept_data, event->object, *(Eina_Bool *)event->info); -} - -static void -_dnd_drag_done_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_Done *done = data; - - if (done->done_cb) - done->done_cb(done->done_data, event->object); - - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, done->pos); - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_ACCEPT, - _dnd_drag_accept_cb, done->accept); - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_DONE, - _dnd_drag_done_cb, done); - free(done->pos); - free(done->accept); - free(done); -} - -static void -_dnd_drag_enter_leave_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_State *state = data; - - if (state->state_cb) - state->state_cb(state->state_data, event->object); -} - -static void -_dnd_drop_cb(void *data, const Efl_Event *event) -{ - Dnd_Drop *drop = data; - Efl_Ui_Selection_Data *org_ddata = event->info; - Elm_Selection_Data ddata; - - ddata.x = org_ddata->pos.x; - ddata.y = org_ddata->pos.y; - ddata.format = (Elm_Sel_Format)org_ddata->format; - ddata.action = (Elm_Xdnd_Action)org_ddata->action; - ddata.data = calloc(1, org_ddata->content.len); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len); - ddata.len = org_ddata->content.len; - if (drop->drop_cb) - drop->drop_cb(drop->drop_data, event->object, &ddata); - free(ddata.data); -} - -EAPI Eina_Bool -elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, - Elm_Xdnd_Action action, - Elm_Drag_Icon_Create_Cb icon_create_cb, void *icon_create_data, - Elm_Drag_Pos drag_pos_cb, void *drag_pos_data, - Elm_Drag_Accept drag_accept_cb, void *drag_accept_data, - Elm_Drag_State drag_done_cb, void *drag_done_data) -{ - if (!data) return EINA_FALSE; - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Eina_Slice sl; - Dnd_Drag_Pos *pos = calloc(1, sizeof(Dnd_Drag_Pos)); - Dnd_Drag_Accept *accept = calloc(1, sizeof(Dnd_Drag_Accept)); - Dnd_Drag_Done *done = calloc(1, sizeof(Dnd_Drag_Done)); - Dnd_Icon_Create *ic = calloc(1, sizeof(Dnd_Icon_Create)); - if (!pos || !accept || !done || !ic) goto on_error; - - pos->pos_data = drag_pos_data; - pos->pos_cb = drag_pos_cb; - - accept->accept_data = drag_accept_data; - accept->accept_cb = drag_accept_cb; - - done->done_data = drag_done_data; - done->done_cb = drag_done_cb; - done->pos = pos; - done->accept = accept; - - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, _dnd_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, _dnd_drag_accept_cb, accept); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DONE, _dnd_drag_done_cb, done); - sl.mem = data; - sl.len = strlen(data); -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - ic->icon_data = icon_create_data; - ic->icon_cb = icon_create_cb; - efl_ui_selection_manager_drag_start(sel_man, obj, (Efl_Ui_Selection_Format)format, sl, - (Efl_Ui_Selection_Action)action, - ic, _dnd_icon_create_cb, NULL, seatid); - - return EINA_TRUE; - -on_error: - if (pos) free(pos); - if (accept) free(accept); - if (done) free(done); - if (ic) free(ic); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - efl_ui_selection_manager_drag_action_set(sel_man, obj, (Efl_Ui_Selection_Action)action, seatid); - - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_drag_cancel(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - efl_ui_selection_manager_drag_cancel(sel_man, obj, seatid); - - return EINA_TRUE; -} - -static void -_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Eina_List *drop_list; - Dnd_Drop *drop; - - drop_list = efl_key_data_get(obj, "__drop_list"); - EINA_LIST_FREE(drop_list, drop) - { - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - free(drop); - } - efl_key_data_set(obj, "__drop_list", NULL); -} - -EAPI Eina_Bool -elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Pos pos_cb, void *pos_data, - Elm_Drop_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Dnd_Drag_State *enter, *leave; - Dnd_Drag_Pos *pos; - Dnd_Drop *drop; - Eina_List *drop_list; - - enter = calloc(1, sizeof(Dnd_Drag_State)); - leave = calloc(1, sizeof(Dnd_Drag_State)); - pos = calloc(1, sizeof(Dnd_Drag_Pos)); - drop = calloc(1, sizeof(Dnd_Drop)); - if (!enter || !leave || !pos || !drop) goto on_error; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - enter->state_cb = enter_cb; - enter->state_data = enter_data; - leave->state_cb = leave_cb; - leave->state_data = leave_data; - pos->pos_cb = pos_cb; - pos->pos_data = pos_data; - drop->obj = obj; - drop->format = format; - drop->drop_cb = drop_cb; - drop->drop_data = drop_data; - drop->enter = enter; - drop->leave = leave; - drop->pos = pos; - - drop_list = efl_key_data_get(obj, "__drop_list"); - drop_list = eina_list_append(drop_list, drop); - efl_key_data_set(obj, "__drop_list", drop_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, - _drop_obj_del_cb, NULL); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, enter); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, leave); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - efl_ui_selection_manager_drop_target_add(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid); - - return EINA_TRUE; - -on_error: - if (enter) free(enter); - if (leave) free(leave); - if (pos) free(pos); - if (drop) free(drop); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Pos pos_cb, void *pos_data, - Elm_Drop_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - //Eina_List *l, *l2; - Eina_List *drop_list; - Dnd_Drop *drop; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - drop_list = efl_key_data_get(obj, "__drop_list"); - drop = eina_list_data_get(drop_list); - if (drop && - (drop->format == format) && - (drop->enter->state_cb == enter_cb) && - (drop->enter->state_data == enter_data) && - (drop->leave->state_cb == leave_cb) && - (drop->leave->state_data == leave_data) && - (drop->pos->pos_cb == pos_cb) && - (drop->pos->pos_data == pos_data) && - (drop->drop_cb == drop_cb) && - (drop->drop_data == drop_data)) - { - drop_list = eina_list_remove(drop_list, drop); - efl_key_data_set(obj, "__drop_list", drop_list); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _drop_obj_del_cb); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - free(drop); - } - efl_ui_selection_manager_drop_target_del(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid); - - return EINA_TRUE; -} - -static Efl_Object * -_dnd_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret) -{ - Elm_Xy_Item_Get_Cb item_get_cb = data; - Evas_Coord x, y; - Efl_Object *obj = NULL; - - x = y = 0; - if (item_get_cb) - obj = item_get_cb(item, pos.x, pos.y, &x, &y); - if (pos_ret) - { - pos_ret->x = x; - pos_ret->y = y; - } + pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); return obj; } -static void -_dnd_cont_drag_pos_cb(void *data, const Efl_Event *event) +EOLIAN static void +_efl_ui_dnd_efl_object_invalidate(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Cont_Drag_Pos *pos = data; - Efl_Dnd_Drag_Pos *ddata = event->info; - Evas_Coord xret = 0, yret = 0; - - if (pos->item_get_cb) + if (pd->registered) { - Evas_Coord x, y; - evas_object_geometry_get(event->object, &x, &y, NULL, NULL); - pos->item_get_cb(event->object, ddata->pos.x + x, ddata->pos.y + y, - &xret, &yret); + _drop_event_unregister(obj); } - if (pos->pos_cb) - pos->pos_cb(pos->pos_data, event->object, ddata->item, ddata->pos.x, ddata->pos.y, - xret, yret, (Elm_Xdnd_Action)ddata->action); + efl_invalidate(efl_super(obj, EFL_UI_DND_MIXIN)); + } -static void -_dnd_cont_drop_cb(void *data, const Efl_Event *event) +#define IS_DROP_EVENT(D) ( \ +(D == EFL_UI_DND_EVENT_DROP_POSITION_CHANGED) || \ +(D == EFL_UI_DND_EVENT_DROP_DROPPED) || \ +(D == EFL_UI_DND_EVENT_DROP_LEFT) || \ +(D == EFL_UI_DND_EVENT_DROP_ENTERED) \ +) + +EOLIAN static Efl_Object* +_efl_ui_dnd_efl_object_finalize(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Cont_Drop *drop = data; - Efl_Ui_Selection_Data *org_ddata = event->info; - Elm_Selection_Data ddata; - Evas_Coord xret = 0, yret = 0; + if (pd->registered) + _drop_event_register(obj); - ddata.x = org_ddata->pos.x; - ddata.y = org_ddata->pos.y; - ddata.format = (Elm_Sel_Format)org_ddata->format; - ddata.action = (Elm_Xdnd_Action)org_ddata->action; - ddata.data = calloc(1, org_ddata->content.len); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len); - ddata.len = org_ddata->content.len; + return efl_finalize(efl_super(obj, EFL_UI_DND_MIXIN)); +} - if (drop->item_get_cb) + +EOLIAN static Eina_Bool +_efl_ui_dnd_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd, + const Efl_Event_Description *desc, + Efl_Callback_Priority priority, + Efl_Event_Cb func, + const void *user_data) +{ + if (IS_DROP_EVENT(desc) && !pd->registered) + { + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _drop_event_register(obj); + } + + return efl_event_callback_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), desc, priority, func, user_data); +} + +EOLIAN static Eina_Bool +_efl_ui_dnd_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd, + const Efl_Callback_Array_Item *array, + Efl_Callback_Priority priority, + const void *user_data) +{ + for (int i = 0; array[i].desc; ++i) { - Evas_Coord x, y; - evas_object_geometry_get(event->object, &x, &y, NULL, NULL); - drop->item_get_cb(event->object, ddata.x + x, ddata.y + y, - &xret, &yret); - } - - if (drop->drop_cb) - drop->drop_cb(drop->drop_data, event->object, org_ddata->item, - &ddata, xret, yret); - free(ddata.data); -} - -static void -_cont_drop_free_data(Evas_Object *obj) -{ - Eina_List *cont_drop_list; - Dnd_Cont_Drop *drop; - - cont_drop_list = efl_key_data_get(obj, "__cont_drop_item"); - drop = eina_list_data_get(cont_drop_list); - if (drop) - { - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_cont_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_cont_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - cont_drop_list = eina_list_remove(cont_drop_list, drop); - efl_key_data_set(obj, "__cont_drop_item", cont_drop_list); - free(drop); - } -} - -static void -_cont_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - _cont_drop_free_data(obj); -} - -EAPI Eina_Bool -elm_drop_item_container_add(Evas_Object *obj, - Elm_Sel_Format format, - Elm_Xy_Item_Get_Cb item_get_cb, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Item_Container_Pos pos_cb, void *pos_data, - Elm_Drop_Item_Container_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Dnd_Drag_State *enter = NULL, *leave = NULL; - Dnd_Cont_Drag_Pos *pos = NULL; - Dnd_Cont_Drop *drop = NULL; - Eina_List *cont_drop_list; - - enter = calloc(1, sizeof(Dnd_Drag_State)); - leave = calloc(1, sizeof(Dnd_Drag_State)); - pos = calloc(1, sizeof(Dnd_Cont_Drag_Pos)); - drop = calloc(1, sizeof(Dnd_Cont_Drop)); - if (!enter || !leave || !pos || !drop) goto on_error; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - enter->state_cb = enter_cb; - enter->state_data = enter_data; - leave->state_cb = leave_cb; - leave->state_data = leave_data; - pos->pos_cb = pos_cb; - pos->pos_data = pos_data; - pos->item_get_cb = item_get_cb; - drop->obj = obj; - drop->format = format; - drop->drop_cb = drop_cb; - drop->drop_data = drop_data; - drop->enter = enter; - drop->leave = leave; - drop->pos = pos; - - cont_drop_list = efl_key_data_get(obj, "__cont_drop_item"); - cont_drop_list = eina_list_append(cont_drop_list, drop); - efl_key_data_set(obj, "__cont_drop_item", cont_drop_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, - _cont_drop_obj_del_cb, NULL); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, enter); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, leave); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_cont_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_cont_drop_cb, drop); - efl_ui_selection_manager_container_drop_item_add(sel_man, obj, (Efl_Ui_Selection_Format)format, - item_get_cb, _dnd_item_func, NULL, - seatid); - - return EINA_TRUE; - -on_error: - if (enter) free(enter); - if (leave) free(leave); - if (pos) free(pos); - if (drop) free(drop); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drop_item_container_del(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - _cont_drop_free_data(obj); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drop_obj_del_cb); - efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seatid); - - return EINA_TRUE; -} - -static void -_cont_drag_data_func(void *data, Efl_Object *obj, Efl_Ui_Selection_Format *format, - Eina_Rw_Slice *drag_data, Efl_Ui_Selection_Action *action) -{ - Item_Container_Drag_Info *di; - - di = data; - if (!di) return; - di->data_get_cb(obj, di->it, &di->user_info); - if (format) *format = (Efl_Ui_Selection_Format)di->user_info.format; - if (drag_data) - { - if (di->user_info.data) + if (IS_DROP_EVENT(array[i].desc) && !pd->registered) { - drag_data->mem = (void *)di->user_info.data; - drag_data->len = strlen(di->user_info.data); + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _drop_event_register(obj); } } - if (action) *action = (Efl_Ui_Selection_Action)di->user_info.action; + return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), array, priority, user_data); } -static Eina_List * -_cont_drag_icon_list_create(void *data, Efl_Object *obj EINA_UNUSED) -{ - Item_Container_Drag_Info *di; - - di = data; - return di->user_info.icons; -} - -static Efl_Object * -_cont_drag_icon_create(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret) -{ - Item_Container_Drag_Info *di; - Elm_Object_Item *it = NULL; - - di = data; - if (!di) return NULL; - if (!di->user_info.createicon) return NULL; - it = di->user_info.createicon(di->user_info.createdata, win, &pos_ret->x, &pos_ret->y); - di->it = it; - return it; -} - -static Efl_Object * -_cont_drag_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret) -{ - Item_Container_Drag_Info *di = data; - Evas_Coord x, y; - Efl_Object *obj = NULL; - - x = y = 0; - if (di->item_get_cb) - obj = di->item_get_cb(item, pos.x, pos.y, &x, &y); - if (pos_ret) - { - pos_ret->x = x; - pos_ret->y = y; - } - di->it = obj; - - return obj; -} - -static void -_cont_drag_free_data(Evas_Object *obj) -{ - Eina_List *di_list; - Item_Container_Drag_Info *di; - - di_list = efl_key_data_get(obj, "__cont_drag_item"); - di = eina_list_data_get(di_list); - di_list = eina_list_remove(di_list, di); - efl_key_data_set(obj, "__cont_drag_item", di_list); - free(di); -} - -static void -_cont_drag_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) -{ - _cont_drag_free_data(obj); -} - -EAPI Eina_Bool -elm_drag_item_container_add(Evas_Object *obj, double anim_tm, double tm_to_drag, - Elm_Xy_Item_Get_Cb item_get_cb, Elm_Item_Container_Data_Get_Cb data_get_cb) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Eina_List *di_list; - Item_Container_Drag_Info *di; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - di = calloc(1, sizeof(Item_Container_Drag_Info)); - if (!di) return EINA_FALSE; - di->data_get_cb = data_get_cb; - di->item_get_cb = item_get_cb; - di_list = efl_key_data_get(obj, "__cont_drag_item"); - di_list = eina_list_append(di_list, di); - efl_key_data_set(obj, "__cont_drag_item", di_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb, NULL); - efl_ui_selection_manager_container_drag_item_add(sel_man, obj, tm_to_drag, anim_tm, - di, _cont_drag_data_func, NULL, - di, _cont_drag_item_func, NULL, - di, _cont_drag_icon_create, NULL, - di, _cont_drag_icon_list_create, NULL, - seatid); - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_drag_item_container_del(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - _cont_drag_free_data(obj); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb); - efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seatid); - - return EINA_TRUE; -} +#define EFL_UI_DND_EXTRA_OPS \ + EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_dnd_efl_object_event_callback_priority_add), \ + EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_dnd_efl_object_event_callback_array_priority_add), \ #include "efl_ui_dnd.eo.c" -#include "efl_ui_dnd_container.eo.c" diff --git a/src/lib/elementary/efl_ui_dnd.eo b/src/lib/elementary/efl_ui_dnd.eo index 08f668856b..8ef19110d5 100644 --- a/src/lib/elementary/efl_ui_dnd.eo +++ b/src/lib/elementary/efl_ui_dnd.eo @@ -1,29 +1,40 @@ -import efl_ui_dnd_types; +import eina_types; -mixin @beta Efl.Ui.Dnd { - data: null; +struct @beta Efl.Ui.Drop_Event { + [[Event struct that contains information about what is avaiable at which position, in which seat]] + position : Eina.Position2D; [[The position of the Drop event]] + seat : uint; [[In which seat it is happening]] + available_types : accessor; [[which types are avaiable, you should use one of these for a call to @Efl.Ui.Dnd.drop_data_get ]] +} + +struct @beta Efl.Ui.Drop_Dropped_Event { + dnd : Efl.Ui.Drop_Event; [[The overall information]] + action : string; [[The action the client should take]] +} + +struct @beta Efl.Ui.Drag_Started_Event { + seat : uint; +} + +struct @beta Efl.Ui.Drag_Finished_Event { + seat : uint; + accepted : bool; +} + +mixin @beta Efl.Ui.Dnd requires Efl.Object { methods { drag_start { - [[Start a drag and drop process at the drag side. - During dragging, there are three events emitted as belows: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE + [[Start a drag from this client. + + @[Efl.Ui.Dnd.drag,started] will be emitted each time a successfull drag will be started. + @[Efl.Ui.Dnd.drag,finished] will be emitted every time a drag is finished. ]] params { - @in format: Efl.Ui.Selection_Format; [[The data format]] - @in data: Eina.Slice; [[The drag data]] - @in action: Efl.Ui.Selection_Action; [[Action when data is transferred]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_action_set { - [[Set the action for the drag]] - params { - @in action: Efl.Ui.Selection_Action; [[Drag action]] + content : Eina.Content @by_ref; [[The content you want to provide via dnd]] + @in action: string; [[Action when data is transferred]] @in seat: uint; [[Specified seat for multiple seats case.]] } + return : Efl.Content; [[A UI element where you can just set your visual representation into]] } drag_cancel { [[Cancel the on-going drag]] @@ -31,33 +42,26 @@ mixin @beta Efl.Ui.Dnd { @in seat: uint; [[Specified seat for multiple seats case.]] } } - drop_target_add { - [[Make the current object as drop target. - There are four events emitted: - - EFL_UI_DND_EVENT_DRAG_ENTER - - EFL_UI_DND_EVENT_DRAG_LEAVE - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_DROP.]] + drop_data_get { + [[Get the data from the object that has selection]] params { - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_target_del { - [[Delete the dropable status from object]] - params { - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] + seat : uint; [[Specified seat for multiple seats case.]] + acceptable_types : iterator; [[The types that are acceptable for you]] } + return : future @move; [[fullfilled when the content is transmitted, and ready to use]] } } events { - /* FIXME: This is not very future-proof. Better return a struct. */ - drag,accept: ptr(bool); [[accept drag data]] - drag,done: void; [[drag is done (mouse up)]] - drag,enter: void; [[called when the drag object enters this object]] - drag,leave: void; [[called when the drag object leaves this object]] - drag,pos: Efl.Dnd.Drag_Pos; [[called when the drag object changes drag position]] - drag,drop: Efl.Ui.Selection_Data; [[called when the drag object dropped on this object]] + drop,entered : Efl.Ui.Drop_Event; + drop,left : Efl.Ui.Drop_Event; + drop,position,changed : Efl.Ui.Drop_Event; + drop,dropped : Efl.Ui.Drop_Dropped_Event; + drag,started : Efl.Ui.Drag_Started_Event; + drag,finished : Efl.Ui.Drag_Finished_Event; + } + implements { + Efl.Object.constructor; + Efl.Object.invalidate; + Efl.Object.finalize; } } diff --git a/src/lib/elementary/efl_ui_dnd_container.eo b/src/lib/elementary/efl_ui_dnd_container.eo deleted file mode 100644 index 0cc1f3f945..0000000000 --- a/src/lib/elementary/efl_ui_dnd_container.eo +++ /dev/null @@ -1,46 +0,0 @@ -import efl_ui_dnd_types; - -mixin @beta Efl.Ui.Dnd_Container { - methods { - @property drag_delay_time { - [[The time since mouse down happens to drag starts.]] - set { - } - get { - } - values { - time: double; [[The drag delay time]] - } - } - drag_item_add { - [[This registers a drag for items in a container. Many items can be - dragged at a time. During dragging, there are three events emitted: - EFL_DND_EVENT_DRAG_POS, EFL_DND_EVENT_DRAG_ACCEPT, EFL_DND_EVENT_DRAG_DONE.]] - params { - @in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]] - @in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]] - @in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations CHECKING ]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_item_del { - [[Remove drag function of items in the container object.]] - params { - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_item_add { - params { - @in format: Efl.Ui.Selection_Format; [[Accepted data formats]] - @in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_item_del { - params { - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - } -} diff --git a/src/lib/elementary/efl_ui_dnd_types.eot b/src/lib/elementary/efl_ui_dnd_types.eot deleted file mode 100644 index ace1c8de7b..0000000000 --- a/src/lib/elementary/efl_ui_dnd_types.eot +++ /dev/null @@ -1,60 +0,0 @@ -import efl_ui_selection_types; - -function @beta Efl.Dnd.Drag_Icon_Create { - [[Function pointer for creating icon at the drag side.]] - params { - @in win: Efl.Canvas.Object; [[The window to create the objects relative to]] - @in drag_obj: Efl.Canvas.Object; [[The drag object]] - @out off: Eina.Position2D; [[Offset from the icon position to the cursor]] - } - return: Efl.Canvas.Object; [[The drag icon object]] -}; - -function @beta Efl.Dnd.Drag_Data_Get { - [[Function pointer for getting data and format at the drag side.]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - @out format: Efl.Ui.Selection_Format; [[Data format]] - @out drag_data: Eina.Rw_Slice; [[Data]] - @out action: Efl.Ui.Selection_Action; [[The drag action]] - } -}; - -function @beta Efl.Dnd.Item_Get { - [[Function pointer to find out which item is under position (x, y)]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - @in pos: Eina.Position2D; [[The coordinates to get item]] - @out posret: Eina.Position2D; [[position relative to item (left (-1), middle (0), right (1)]] - } - return: Efl.Object; [[Object under x,y coordinates or NULL if not found]] -}; - -function @beta Efl.Dnd.Drag_Icon_List_Create { - [[Function pointer to create list of icons at the drag side. - These icons are used for animation on combining selection icons - to one icon.]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - } - return: list; -}; - -struct @beta Efl.Dnd.Drag_Accept { - accepted: bool; -} - -struct @beta Efl.Dnd.Drag_Pos { - [[Dragging position information.]] - pos: Eina.Position2D; [[Evas Coordinate]] - action: Efl.Ui.Selection_Action; [[The drag action]] - format: Efl.Ui.Selection_Format; [[The drag format]] - item: Efl.Canvas.Object; [[The item object. It is only available for container object.]] -} - -struct @beta Efl.Dnd.Drag_Item_Container_Drop { - [[Drop information for a drag&drop operation.]] - item: Efl.Canvas.Object; [[The item object]] - data: Efl.Ui.Selection_Data; [[The selection data]] - pos: Eina.Position2D; [[Position relative to item (left (-1), middle (0), right (1)]] -} diff --git a/src/lib/elementary/efl_ui_selection.c b/src/lib/elementary/efl_ui_selection.c index 675eb0cf99..d67d1f3fef 100644 --- a/src/lib/elementary/efl_ui_selection.c +++ b/src/lib/elementary/efl_ui_selection.c @@ -9,278 +9,115 @@ #define MY_CLASS EFL_UI_SELECTION_MIXIN #define MY_CLASS_NAME "Efl.Ui.Selection" -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -#endif +typedef struct { + Ecore_Evas *ee; + Eina_Bool registered : 1; +} Efl_Ui_Selection_Data; -EOLIAN static void -_efl_ui_selection_selection_get(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, unsigned int seat) +static inline Ecore_Evas_Selection_Buffer +_ee_buffer_get(Efl_Ui_Cnp_Buffer buffer) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_selection_get(sel_man, obj, type, format, - data_func_data, data_func, - data_func_free_cb, seat); + if (buffer == EFL_UI_CNP_BUFFER_SELECTION) + return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER; + else + return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER; } -EOLIAN static Eina_Future * -_efl_ui_selection_selection_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data, unsigned int seat) +EOLIAN static Eina_Future* +_efl_ui_selection_selection_get(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat, Eina_Iterator *acceptable_types) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - return efl_ui_selection_manager_selection_set(sel_man, obj, type, format, data, seat); + return ecore_evas_selection_get(pd->ee, seat, _ee_buffer_get(buffer), acceptable_types); } EOLIAN static void -_efl_ui_selection_selection_clear(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat) +_efl_ui_selection_selection_set(Eo *obj, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, Eina_Content *content, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_selection_clear(sel_man, obj, type, seat); + _register_selection_changed(obj); + ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), content); +} + +EOLIAN static void +_efl_ui_selection_selection_clear(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat) +{ + ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), NULL); } EOLIAN static Eina_Bool -_efl_ui_selection_has_owner(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat) +_efl_ui_selection_has_selection(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, type, seat); + return ecore_evas_selection_exists(pd->ee, seat, _ee_buffer_get(buffer)); } - -////////// Support legacy APIs - -//TODO: Clear this list (when sel_man is deleted) -Eina_List *lost_cb_list = NULL; - -#ifdef HAVE_ELEMENTARY_WL2 -static Ecore_Evas * -_wl_is_wl(const Evas_Object *obj) +EOLIAN static Efl_Object* +_efl_ui_selection_efl_object_constructor(Eo *obj, Efl_Ui_Selection_Data *pd) { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; + if (!efl_constructor(efl_super(obj, EFL_UI_SELECTION_MIXIN))) + return NULL; - if (!(evas = evas_object_evas_get(obj))) - return NULL; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return NULL; + pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) + return obj; +} + +EOLIAN static void +_efl_ui_selection_efl_object_invalidate(Eo *obj, Efl_Ui_Selection_Data *pd) +{ + if (pd->registered) { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - engine_name = ecore_evas_engine_name_get(ee); + _selection_changed_event_unregister(obj); } - if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1)) - return ee; - return NULL; + efl_invalidate(efl_super(obj, EFL_UI_SELECTION_MIXIN)); } -int -_wl_default_seat_id_get(Evas_Object *obj) +EOLIAN static Eina_Bool +_efl_ui_selection_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd, + const Efl_Event_Description *desc, + Efl_Callback_Priority priority, + Efl_Event_Cb func, + const void *user_data) { - Ecore_Wl2_Window *win = _wl_window_get(obj); - Eo *seat, *parent2, *ewin; - Eina_Bool is_wl = EINA_FALSE; + if (desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered) + { - if (obj) + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _selection_changed_event_register(obj); + } + + return efl_event_callback_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), desc, priority, func, user_data); +} + +EOLIAN static Eina_Bool +_efl_ui_selection_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd, + const Efl_Callback_Array_Item *array, + Efl_Callback_Priority priority, + const void *user_data) +{ + for (int i = 0; array[i].desc; ++i) { - if (_wl_is_wl(obj)) is_wl = EINA_TRUE; - if (efl_isa(obj, EFL_UI_WIDGET_CLASS)) + if (array[i].desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered) { - Eo *top = elm_widget_top_get(obj); - if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS)) - { - parent2 = efl_ui_win_inlined_parent_get(top); - if (parent2) obj = elm_widget_top_get(parent2) ?: parent2; - } - /* fake win means canvas seat id will not match protocol seat id */ - ewin = elm_win_get(obj); - if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL; + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _selection_changed_event_register(obj); } } - - if (!obj) - { - if (is_wl) - { - Ecore_Wl2_Input *input; - Eina_Iterator *it; - - it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win)); - EINA_ITERATOR_FOREACH(it, input) break; - eina_iterator_free(it); - if (input) - return ecore_wl2_input_seat_id_get(input); - } - } - - seat = evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, 1); - return evas_device_seat_id_get(seat); -} -#endif - -typedef struct _Cnp_Data_Cb_Wrapper Cnp_Data_Cb_Wrapper; -struct _Cnp_Data_Cb_Wrapper -{ - void *udata; - Elm_Drop_Cb datacb; -}; - -static void -_selection_data_ready_cb(void *data, Efl_Object *obj, Efl_Ui_Selection_Data *seldata) -{ - Cnp_Data_Cb_Wrapper *wdata = data; - if (!wdata) return; - Elm_Selection_Data ddata; - - ddata.data = calloc(1, seldata->content.len + 1); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, seldata->content.mem, seldata->content.len); - ddata.len = seldata->content.len; - ddata.x = seldata->pos.x; - ddata.y = seldata->pos.y; - ddata.format = (Elm_Sel_Format)seldata->format; - ddata.action = (Elm_Xdnd_Action)seldata->action; - wdata->datacb(wdata->udata, obj, &ddata); - free(ddata.data); + return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), array, priority, user_data); } -typedef struct _Sel_Lost_Data Sel_Lost_Data; -struct _Sel_Lost_Data + +EOLIAN static Efl_Object* +_efl_ui_selection_efl_object_finalize(Eo *obj, Efl_Ui_Selection_Data *pd) { - const Evas_Object *obj; - Elm_Sel_Type type; - void *udata; - Elm_Selection_Loss_Cb loss_cb; -}; + if (pd->registered) + _selection_changed_event_register(obj); -static Eina_Value -_selection_lost_cb(void *data, const Eina_Value value) -{ - Eina_List *l, *l2; - Sel_Lost_Data *ldata, *ldata2; - - ldata = data; - EINA_LIST_FOREACH_SAFE(lost_cb_list, l, l2, ldata2) - { - if ((ldata->obj == ldata2->obj) && - (ldata->type == ldata2->type)) - { - ldata2->loss_cb(ldata2->udata, ldata2->type); - lost_cb_list = eina_list_remove(lost_cb_list, ldata2); - } - } - free(ldata); - - return value; + return efl_finalize(efl_super(obj, MY_CLASS)); } -EAPI Eina_Bool -elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type type, - Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - Cnp_Data_Cb_Wrapper *wdata = calloc(1, sizeof(Cnp_Data_Cb_Wrapper)); - if (!wdata) return EINA_FALSE; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get((Evas_Object *)obj); -#endif - wdata->udata = udata; - wdata->datacb = datacb; - efl_ui_selection_manager_selection_get(sel_man, (Evas_Object *)obj, (Efl_Ui_Selection_Type)type, - (Efl_Ui_Selection_Format)format, - wdata, _selection_data_ready_cb, NULL, seatid); - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type type, - Elm_Sel_Format format, const void *selbuf, size_t buflen) -{ - int seatid = 1; - Eina_Future *f; - Sel_Lost_Data *ldata; - Eo *sel_man = _efl_ui_selection_manager_get(obj); - Eina_Slice data; - - ldata = calloc(1, sizeof(Sel_Lost_Data)); - if (!ldata) return EINA_FALSE; - data.mem = selbuf; - data.len = buflen; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - f = efl_ui_selection_manager_selection_set(sel_man, obj, (Efl_Ui_Selection_Type)type, - (Efl_Ui_Selection_Format)format, data, seatid); - - ldata->obj = obj; - ldata->type = type; - eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata); - - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type type) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - efl_ui_selection_manager_selection_clear(sel_man, obj, (Efl_Ui_Selection_Type)type, seatid); - - return EINA_TRUE; -} - -EAPI void -elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, - Elm_Selection_Loss_Cb func, const void *data) -{ - Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data)); -#if HAVE_ELEMENTARY_COCOA - // Currently, we have no way to track changes in Cocoa pasteboard. - // Therefore, don't track this... - return; -#endif - if (!ldata) return; - ldata->obj = obj; - ldata->type = type; - ldata->udata = (void *)data; - ldata->loss_cb = func; - lost_cb_list = eina_list_append(lost_cb_list, ldata); -} - -EAPI Eina_Bool -elm_selection_selection_has_owner(Evas_Object *obj) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, - EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid); -} - -EAPI Eina_Bool -elm_cnp_clipboard_selection_has_owner(Evas_Object *obj) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, - EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid); -} +#define EFL_UI_SELECTION_EXTRA_OPS \ + EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_selection_efl_object_event_callback_priority_add), \ + EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_selection_efl_object_event_callback_array_priority_add), \ #include "efl_ui_selection.eo.c" diff --git a/src/lib/elementary/efl_ui_selection.eo b/src/lib/elementary/efl_ui_selection.eo index 20e42261d0..492e60e117 100644 --- a/src/lib/elementary/efl_ui_selection.eo +++ b/src/lib/elementary/efl_ui_selection.eo @@ -1,45 +1,57 @@ -import efl_ui_selection_types; +import eina_types; -mixin @beta Efl.Ui.Selection { - [[Efl Ui Selection class]] - data: null; - methods { - selection_set { - [[Set the selection data to the object]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data: Eina.Slice; [[Selection data]] - @in seat: uint;[[Specified seat for multiple seats case.]] - } - return: future; [[Future for tracking when the selection is lost]] - } - selection_get { - [[Get the data from the object that has selection]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]] - @in seat: uint;[[Specified seat for multiple seats case.]] - } - } - selection_clear { - [[Clear the selection data from the object]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - has_owner { - [[Determine whether the selection data has owner]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - return: bool; [[EINA_TRUE if there is object owns selection, otherwise EINA_FALSE]] - } - } - events { - wm_selection,changed: Efl.Ui.Selection_Changed; [[Called when display server's selection has changed]] - } +enum @beta Efl.Ui.Cnp_Buffer{ + selection = 0, + copy_and_paste = 1, +} + +struct @beta Efl.Ui.Wm_Selection_Changed { + buffer : Efl.Ui.Cnp_Buffer; + caused_by : Efl.Ui.Selection; + seat : uint; +} + +mixin @beta Efl.Ui.Selection requires Efl.Object { + methods { + selection_set { + [[Set the selection data to the object]] + params { + buffer : Efl.Ui.Cnp_Buffer; + content : Eina.Content @by_ref; + seat : uint; + } + } + selection_clear { + [[Clear the selection data from the object]] + params { + buffer : Efl.Ui.Cnp_Buffer; + seat : uint; + } + } + selection_get { + [[Get the data from the object that has selection]] + params { + buffer : Efl.Ui.Cnp_Buffer; + seat : uint; + acceptable_types : iterator; + } + return : future @move; + } + has_selection { + [[Determine whether the selection data has owner]] + params { + buffer : Efl.Ui.Cnp_Buffer; + seat : uint; + } + return : bool; [[$true if there is a available selection, $false if not]] + } + } + implements { + Efl.Object.constructor; + Efl.Object.invalidate; + Efl.Object.finalize; + } + events { + wm_selection,changed : Efl.Ui.Wm_Selection_Changed; + } } diff --git a/src/lib/elementary/efl_ui_selection_manager.c b/src/lib/elementary/efl_ui_selection_manager.c deleted file mode 100644 index 76f2c03002..0000000000 --- a/src/lib/elementary/efl_ui_selection_manager.c +++ /dev/null @@ -1,5678 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "elementary_config.h" -#endif - -#include -#include "elm_priv.h" - -#ifdef _WIN32 -# include /* mmap */ -#else -# include -#endif - -#include "efl_ui_selection_manager_private.h" - -#define MY_CLASS EFL_UI_SELECTION_MANAGER_CLASS - -//#define DEBUGON 1 -#ifdef DEBUGON -# define sel_debug(fmt, args...) fprintf(stderr, __FILE__":%s:%d : " fmt "\n", __FUNCTION__, __LINE__, ##args) -#else -# define sel_debug(x...) do { } while (0) -#endif - -static void _anim_data_free(Sel_Manager_Drag_Container *dc); -static void _cont_obj_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); -static void _cont_obj_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); -static void _item_container_del_internal(Sel_Manager_Drag_Container *dc, Eina_Bool full); - -void efl_ui_selection_manager_drop_target_del(Eo *obj, Efl_Object *target_obj, Efl_Ui_Selection_Format format, unsigned int seat); -void efl_ui_selection_manager_selection_clear(Eo *obj, Efl_Object *owner, Efl_Ui_Selection_Type type, unsigned int seat); -void efl_ui_selection_manager_drag_start(Eo *obj, Efl_Object *drag_obj, Efl_Ui_Selection_Format format, Eina_Slice data, Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, unsigned int seat); - -static Eina_List *managers; - -#ifdef HAVE_ELEMENTARY_X -static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel); -static Ecore_X_Atom _x11_dnd_action_rev_map(Efl_Ui_Selection_Action action); -static Ecore_X_Window _x11_xwin_get(const Evas_Object *obj); -#endif - -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -static Ecore_Wl2_Input *_wl_seat_get(Ecore_Wl2_Window *win, Evas_Object *obj, unsigned int seat_id); -#endif - -#ifdef HAVE_ELEMENTARY_WIN32 -static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel); -#endif - -EAPI int ELM_CNP_EVENT_SELECTION_CHANGED = -1; - -#ifdef HAVE_ELEMENTARY_X -static Sel_Manager_Seat_Selection * -_sel_manager_seat_selection_get(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Eina_List *l = NULL; - Sel_Manager_Seat_Selection *seat_sel = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if (seat_sel->seat == seat) - break; - } - if (!seat_sel) - ERR("Could not find request seat"); - - return seat_sel; -} -#endif - -static inline void -_owner_change_check(Efl_Ui_Selection_Manager *manager, Efl_Object *owner, - Sel_Manager_Seat_Selection *seat_sel, - Sel_Manager_Selection *sel, - Efl_Ui_Selection_Type type, Eina_Bool same_win) -{ - if (!same_win) - { - Eina_List *l, *l_next; - Eo *man; - - EINA_LIST_FOREACH_SAFE(managers, l, l_next, man) - { - if (man != manager) - { - Eina_List *l2, *l2_next, *l3, *l3_next; - Sel_Manager_Selection_Lost *sel_lost; - Sel_Manager_Seat_Selection *seat_sel2; - Efl_Ui_Selection_Manager_Data *pd = efl_data_scope_get(man, MY_CLASS); - - if (!pd) continue; - EINA_LIST_FOREACH_SAFE(pd->seat_list, l3, l3_next, seat_sel2) - { - EINA_LIST_FOREACH_SAFE(seat_sel2->sel_lost_list, l2, l2_next, sel_lost) - { - if ((sel_lost->request) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - seat_sel2->xwin = 0; -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WIN32) - if (seat_sel2->sel_list) - { - int i; - - for (i = 0; - i < (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) - ; i++) - { -#ifdef HAVE_ELEMENTARY_X - seat_sel2->sel_list[i].xwin = 0; -#elif defined (HAVE_ELEMENTARY_WIN32) - seat_sel2->sel_list[i].win = NULL; -#endif - seat_sel2->sel_list[i].active = EINA_FALSE; - } - } -#endif -#if defined(HAVE_ELEMENTARY_WL2) || defined(HAVE_ELEMENTARY_COCOA) - if (seat_sel2->sel) - { - seat_sel2->sel->win = 0; - seat_sel2->sel->active = EINA_FALSE; - } -#endif - } - } - } - } - if ((sel->owner != NULL) && - (sel->owner != owner) && same_win) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - } -} - -static Sel_Manager_Seat_Selection * -_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } -#ifdef HAVE_ELEMENTARY_X - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } -#endif - - return seat_sel; -} - -static void -_sel_manager_promise_cancel(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED) -{ - Sel_Manager_Selection_Lost *sel_lost = data; - sel_lost->seat_sel->sel_lost_list = eina_list_remove(sel_lost->seat_sel->sel_lost_list, sel_lost); - free(sel_lost); -} - -static inline Eina_Future * -_update_sel_lost_list(Efl_Object *obj, Efl_Ui_Selection_Type type, - Sel_Manager_Seat_Selection *seat_sel) -{ - Eina_Promise *p; - Sel_Manager_Selection_Lost *sel_lost; - - sel_lost = calloc(1, sizeof(Sel_Manager_Selection_Lost)); - if (!sel_lost) - return NULL; - sel_lost->request = obj; - sel_lost->type = type; - sel_lost->seat_sel = seat_sel; - seat_sel->sel_lost_list = eina_list_append(seat_sel->sel_lost_list, sel_lost); - - p = efl_loop_promise_new(obj); - if (!p) return NULL; - sel_lost->promise = p; - - return efl_future_then(obj, eina_future_new(p), - .data = sel_lost, - .free = _sel_manager_promise_cancel); -} - -/* TODO: this should not be an actual tempfile, but rather encode the object - * as http://dataurl.net/ if it's an image or similar. Evas should support - * decoding it as memfile. */ -static Tmp_Info * -_tempfile_new(int size) -{ -#ifdef HAVE_MMAP - Tmp_Info *info; - const char *tmppath = NULL; - mode_t cur_umask; - int len; - - info = calloc(1, sizeof(Tmp_Info)); - if (!info) return NULL; -#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) - if (getuid() == geteuid()) -#endif - tmppath = getenv("TMP"); - if (!tmppath) tmppath = P_tmpdir; - len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-"); - if (len < 0) goto on_error; - len++; - info->filename = malloc(len); - if (!info->filename) goto on_error; - snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-"); - cur_umask = umask(S_IRWXO | S_IRWXG); - info->fd = mkstemp(info->filename); - umask(cur_umask); - if (info->fd < 0) goto on_error; -# ifdef __linux__ - { - char *tmp; - /* And before someone says anything see POSIX 1003.1-2008 page 400 */ - long pid; - - pid = (long)getpid(); - /* Use pid instead of /proc/self: That way if can be passed around */ - len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd); - len++; - tmp = malloc(len); - if (tmp) - { - snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd); - unlink(info->filename); - free(info->filename); - info->filename = tmp; - } - } -# endif - sel_debug("filename is %s\n", info->filename); - if (size < 1) goto on_error; - /* Map it in */ - if (ftruncate(info->fd, size)) - { - perror("ftruncate"); - goto on_error; - } - eina_mmap_safety_enabled_set(EINA_TRUE); - info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0); - if (info->map == MAP_FAILED) - { - perror("mmap"); - goto on_error; - } - return info; - - on_error: - if (info->fd >= 0) close(info->fd); - info->fd = -1; - /* Set map to NULL and return */ - info->map = NULL; - info->len = 0; - free(info->filename); - free(info); - return NULL; -#else - (void) size; - return NULL; -#endif -} - -static int -_tmpinfo_free(Tmp_Info *info) -{ - if (!info) return 0; - free(info->filename); - free(info); - return 0; -} - -static inline void -_drop_target_cbs_del(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Efl_Object *obj) -{ - if (dropable) - { - Drop_Format *df; - while (dropable->format_list) - { - df = EINA_INLIST_CONTAINER_GET(dropable->format_list, Drop_Format); - efl_ui_selection_manager_drop_target_del(pd->sel_man, obj, - df->format, dropable->seat); - // If drop_target_del() happened to delete dropabale, then - // re-fetch it each loop to make sure it didn't - dropable = efl_key_data_get(obj, "__elm_dropable"); - if (!dropable) break; - } - } -} - -static void -_all_drop_targets_cbs_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Sel_Manager_Dropable *dropable = NULL; - - if (!pd) return; - dropable = efl_key_data_get(obj, "__elm_dropable"); - _drop_target_cbs_del(pd, dropable, obj); -} - -static void -_dropable_coords_adjust(Sel_Manager_Dropable *dropable, Eina_Position2D *pos) -{ - Ecore_Evas *ee; - Evas *evas = evas_object_evas_get(dropable->obj); - int ex = 0, ey = 0, ew = 0, eh = 0; - Evas_Object *win; - - ee = ecore_evas_ecore_evas_get(evas); - ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh); - pos->x = pos->x - ex; - pos->y = pos->y - ey; - - /* For Wayland, frame coords have to be subtracted. */ - Evas_Coord fx, fy; - evas_output_framespace_get(evas, &fx, &fy, NULL, NULL); - if (fx || fy) sel_debug("evas frame fx %d fy %d\n", fx, fy); - pos->x = pos->x - fx; - pos->y = pos->y - fy; - - if (elm_widget_is(dropable->obj)) - { - win = elm_widget_top_get(dropable->obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - { - Evas_Coord x2, y2; - int rot = elm_win_rotation_get(win); - switch (rot) - { - case 90: - x2 = ew - pos->y; - y2 = pos->x; - break; - case 180: - x2 = ew - pos->x; - y2 = eh - pos->y; - break; - case 270: - x2 = pos->y; - y2 = eh - pos->x; - break; - default: - x2 = pos->x; - y2 = pos->y; - break; - } - sel_debug("rotation %d, w %d, h %d - x:%d->%d, y:%d->%d\n", - rot, ew, eh, pos->x, x2, pos->y, y2); - pos->x = x2; - pos->y = y2; - } - } -} - -static Eina_Bool -_drag_cancel_animate(void *data, double pos) -{ /* Animation to "move back" drag-window */ - Sel_Manager_Seat_Selection *seat_sel = data; - sel_debug("in, pos: %f", pos); - if (pos >= 0.99) - { -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 0); -#endif - sel_debug("Delete drag_win"); - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - return ECORE_CALLBACK_CANCEL; - } - else - { - int x, y; - x = seat_sel->drag_win_end.x - (pos * (seat_sel->drag_win_end.x - seat_sel->drag_win_start.x)); - y = seat_sel->drag_win_end.y - (pos * (seat_sel->drag_win_end.y - seat_sel->drag_win_start.y)); - evas_object_move(seat_sel->drag_win, x, y); - } - - return ECORE_CALLBACK_RENEW; -} - -static Efl_Ui_Selection_Format -_dnd_types_to_format(Efl_Ui_Selection_Manager_Data *pd, const char **types, int ntypes) -{ - Efl_Ui_Selection_Format ret_type = 0; - int i; - for (i = 0; i < ntypes; i++) - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, types[i]); - if (atom) ret_type |= atom->format; - } - return ret_type; -} - -static Eina_List * -_dropable_list_geom_find(Efl_Ui_Selection_Manager_Data *pd, Evas *evas, Evas_Coord px, Evas_Coord py) -{ - Eina_List *itr, *top_objects_list = NULL, *dropable_list = NULL; - Evas_Object *top_obj; - Sel_Manager_Dropable *dropable = NULL; - - if (!pd->drop_list) return NULL; - - /* We retrieve the (non-smart) objects pointed by (px, py) */ - top_objects_list = evas_tree_objects_at_xy_get(evas, NULL, px, py); - /* We walk on this list from the last because if the list contains more than one - * element, all but the last will repeat events. The last one can repeat events - * or not. Anyway, this last one is the first that has to be taken into account - * for the determination of the drop target. - */ - EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj) - { - Evas_Object *object = top_obj; - /* We search for the dropable data into the object. If not found, we search into its parent. - * For example, if a button is a drop target, the first object will be an (internal) image. - * The drop target is attached to the button, i.e to image's parent. That's why we need to - * walk on the parents until NULL. - * If we find this dropable data, we found our drop target. - */ - while (object) - { - dropable = efl_key_data_get(object, "__elm_dropable"); - if (dropable) - { - Eina_Bool exist = EINA_FALSE; - Eina_List *l; - Sel_Manager_Dropable *d = NULL; - EINA_LIST_FOREACH(dropable_list, l, d) - { - if (d == dropable) - { - exist = EINA_TRUE; - break; - } - } - if (!exist) - dropable_list = eina_list_append(dropable_list, dropable); - object = evas_object_smart_parent_get(object); - if (dropable) - sel_debug("Drop target %p of type %s found\n", - dropable->obj, efl_class_name_get(efl_class_get(dropable->obj))); - } - else - object = evas_object_smart_parent_get(object); - } - } - eina_list_free(top_objects_list); - return dropable_list; -} - -#ifdef HAVE_ELEMENTARY_X -static Ecore_X_Window -_x11_xwin_get(const Efl_Object *obj) -{ - if (!obj) return 0; - - Ecore_X_Window xwin = 0; - //get top - const Evas_Object *top = obj; - const Evas_Object *parent = obj; - while(parent) - { - top = parent; - parent = efl_parent_get(parent); - } - if (efl_isa(top, EFL_UI_WIN_CLASS)) - { - xwin = elm_win_xwindow_get(top); - } - if (!xwin) - { - Ecore_Evas *ee; - Evas *evas = evas_object_evas_get(obj); - if (!evas) return 0; - ee = ecore_evas_ecore_evas_get(evas); - if (!ee) return 0; - - while(!xwin) - { - const char *engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return 0; - xwin = _elm_ee_xwin_get(ee); - } - else - { - xwin = _elm_ee_xwin_get(ee); - if (!xwin) return 0; - } - } - } - - return xwin; -} - -static Eina_Bool -_x11_is_uri_type_data(Sel_Manager_Selection *sel EINA_UNUSED, Ecore_X_Event_Selection_Notify *notify) -{ - Ecore_X_Selection_Data *data; - char *p; - - data = notify->data; - sel_debug("data->format is %d %p %p", data->format, notify, data); - if (data->content == ECORE_X_SELECTION_CONTENT_FILES) return EINA_TRUE; - p = (char *)data->data; - if (!p) return EINA_TRUE; - sel_debug("Got %s", p); - if (strncmp(p, "file:/", 6)) - { - if (*p != '/') return EINA_FALSE; - } - return EINA_TRUE; -} - -static Sel_Manager_Seat_Selection * -_x11_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel_list) - { - //TODO: reduce memory (may be just need one common sel_list) - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } - - return seat_sel; -} - -static Eina_Bool -_x11_data_preparer_text(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("text data preparer"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -static Eina_Bool -_x11_data_preparer_markup(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("markup data preparer"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_MARKUP; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -/** - * So someone is pasting an image into my entry or widget... - */ -static Eina_Bool -_x11_data_preparer_uri(Sel_Manager_Seat_Selection *seat_sel, Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("uri data preparer"); - Ecore_X_Selection_Data *data; - Ecore_X_Selection_Data_Files *files; - char *p, *stripstr = NULL; - - data = notify->data; - sel_debug("data->format is %d %p %p\n", data->format, notify, data); - if (data->content == ECORE_X_SELECTION_CONTENT_FILES) - { - Efreet_Uri *uri; - Eina_Strbuf *strbuf; - int i; - - sel_debug("got a files list\n"); - files = notify->data; - /* - if (files->num_files > 1) - { - // Don't handle many items <- this makes mr bigglesworth sad :( - sel_debug("more then one file: Bailing\n"); - return EINA_FALSE; - } - stripstr = p = strdup(files->files[0]); - */ - - strbuf = eina_strbuf_new(); - if (!strbuf) - return EINA_FALSE; - - for (i = 0; i < files->num_files ; i++) - { - uri = efreet_uri_decode(files->files[i]); - if (uri) - { - eina_strbuf_append(strbuf, uri->path); - efreet_uri_free(uri); - } - else - { - eina_strbuf_append(strbuf, files->files[i]); - } - if (i < (files->num_files - 1)) - eina_strbuf_append(strbuf, "\n"); - } - stripstr = eina_strbuf_string_steal(strbuf); - eina_strbuf_free(strbuf); - } - else - { - Efreet_Uri *uri; - - p = (char *)eina_memdup((unsigned char *)data->data, data->length, EINA_TRUE); - if (!p) return EINA_FALSE; - uri = efreet_uri_decode(p); - if (!uri) - { - /* Is there any reason why we care of URI without scheme? */ - if (p[0] == '/') stripstr = p; - else free(p); - } - else - { - free(p); - stripstr = strdup(uri->path); - efreet_uri_free(uri); - } - } - - if (!stripstr) - { - sel_debug("Couldn't find a file\n"); - return EINA_FALSE; - } - free(seat_sel->saved_types->imgfile); -#if 0 // this seems to be broken - we should be handling uri lists as text - if (seat_sel->saved_types->textreq) - { - seat_sel->saved_types->textreq = 0; - seat_sel->saved_types->imgfile = stripstr; - } - else -#endif - { - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = stripstr; - ddata->content.len = strlen(stripstr); - seat_sel->saved_types->imgfile = NULL; - } - return EINA_TRUE; -} - -/** - * Just received an vcard, either through cut and paste, or dnd. - */ -static Eina_Bool -_x11_data_preparer_vcard(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("vcard receive\n"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_VCARD; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -static Eina_Bool -_x11_data_preparer_image(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info) -{ - Ecore_X_Selection_Data *data = notify->data; - sel_debug("got a image file!\n"); - sel_debug("Size if %d\n", data->length); - - ddata->format = EFL_UI_SELECTION_FORMAT_IMAGE; - data = notify->data; - - Tmp_Info *tmp = _tempfile_new(data->length); - if (!tmp) return EINA_FALSE; - memcpy(tmp->map, data->data, data->length); - munmap(tmp->map, data->length); - ddata->content.mem = strdup(tmp->filename); - ddata->content.len = strlen(tmp->filename); - *tmp_info = tmp; - return EINA_TRUE; -} - -static Eina_Bool -_x11_win_filter(Eo *manager EINA_UNUSED, Ecore_X_Window xwin) -{ - Eo *win; - const Eina_List *l; - - EINA_LIST_FOREACH(_elm_win_list, l, win) - { - if (elm_win_window_id_get(win) == xwin) return EINA_FALSE; - } - return EINA_TRUE; -} - -/* - * Callback to handle a targets response on a selection request: - * So pick the format we'd like; and then request it. - */ -static Eina_Bool -_x11_notify_handler_targets(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Selection *sel, Ecore_X_Event_Selection_Notify *notify) -{ - sel_debug("notify handler targets"); - Ecore_X_Selection_Data_Targets *targets; - Ecore_X_Atom *atom_list; - int i, j; - - targets = notify->data; - atom_list = (Ecore_X_Atom *)(targets->data.data); - for (j = (SELECTION_ATOM_LISTING_ATOMS + 1); j < SELECTION_N_ATOMS; j++) - { - sel_debug("\t%s %d", pd->atom_list[j].name, pd->atom_list[j].x_atom); - if (!(pd->atom_list[j].format & sel->request_format)) continue; - for (i = 0; i < targets->data.length; i++) - { - if ((pd->atom_list[j].x_atom == atom_list[i]) && (pd->atom_list[j].x_data_preparer)) - { - if (j == SELECTION_ATOM_TEXT_URILIST) - { - if (!_x11_is_uri_type_data(sel, notify)) continue; - } - sel_debug("Atom %s matches", pd->atom_list[j].name); - goto done; - } - } - } - sel_debug("Couldn't find anything that matches"); - return ECORE_CALLBACK_PASS_ON; -done: - sel_debug("Sending request for %s, xwin=%#llx", - pd->atom_list[j].name, (unsigned long long)sel->xwin); - sel->request(sel->xwin, pd->atom_list[j].name); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_fixes_selection_notify(void *data, int t EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Efl_Ui_Selection_Changed e; - Elm_Cnp_Event_Selection_Changed *_e; - Ecore_X_Event_Fixes_Selection_Notify *ev = event; - Sel_Manager_Seat_Selection *seat_sel; - Efl_Ui_Selection_Type type; - Sel_Manager_Selection *sel; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - switch (ev->selection) - { - case ECORE_X_SELECTION_CLIPBOARD: - type = EFL_UI_SELECTION_TYPE_CLIPBOARD; - break; - case ECORE_X_SELECTION_PRIMARY: - type = EFL_UI_SELECTION_TYPE_PRIMARY; - break; - default: return ECORE_CALLBACK_RENEW; - } - seat_sel = _x11_sel_manager_seat_selection_init(pd, 1); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel_list + type; - if (sel->active && (sel->xwin != ev->owner)) - efl_ui_selection_manager_selection_clear(pd->sel_man, sel->owner, type, seat_sel->seat); - e.type = type; - e.seat = 1; /* under x11 this is always the default seat */ - e.exist = !!ev->owner; - - _e = calloc(1, sizeof(Elm_Cnp_Event_Selection_Changed)); - EINA_SAFETY_ON_NULL_RETURN_VAL(_e, ECORE_CALLBACK_RENEW); - _e->type = type; - _e->seat_id = 1; - _e->exists = e.exist; - - ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, _e, NULL, NULL); - efl_event_callback_call(sel->owner, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &e); - - return ECORE_CALLBACK_RENEW; -} - -/* - * Response to a selection notify: - * - So we have asked for the selection list. - * - If it's the targets list, parse it, and fire of what we want, - * else it's the data we want. - */ -//NB: x11 does not have seat, use 1 as default -static Eina_Bool -_efl_sel_manager_x11_selection_notify(void *udata, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = udata; - Ecore_X_Event_Selection_Notify *ev = event; - Sel_Manager_Selection *sel; - Sel_Manager_Seat_Selection *seat_sel = NULL; - int i; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - seat_sel = _sel_manager_seat_selection_get(pd, 1); - if (!seat_sel) - return EINA_FALSE; - - sel_debug("selection notify callback: %d", ev->selection); - switch (ev->selection) - { - case ECORE_X_SELECTION_PRIMARY: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_PRIMARY; - break; - case ECORE_X_SELECTION_SECONDARY: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_SECONDARY; - break; - case ECORE_X_SELECTION_XDND: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_DND; - break; - case ECORE_X_SELECTION_CLIPBOARD: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_CLIPBOARD; - break; - default: - return ECORE_CALLBACK_PASS_ON; - } - sel_debug("Target is %s", ev->target); - if (!sel->asked) return ECORE_CALLBACK_PASS_ON; - sel->asked--; - - if (ev->selection != ECORE_X_SELECTION_XDND && - (!strcmp(ev->target, "TARGETS") || !strcmp(ev->target, "ATOMS"))) - { - _x11_notify_handler_targets(pd, sel, ev); - return ECORE_CALLBACK_PASS_ON; - } - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (!strcmp(ev->target, pd->atom_list[i].name)) - { - if (pd->atom_list[i].x_data_preparer) - { - Efl_Ui_Selection_Data ddata = { 0 }; - Tmp_Info *tmp_info = NULL; - Eina_Bool success; - sel_debug("Found something: %s", pd->atom_list[i].name); - - success = pd->atom_list[i].x_data_preparer(seat_sel, ev, &ddata, &tmp_info); - sel_debug("ddata: %s (%zd)", (const char *)ddata.content.mem, ddata.content.len); - if ((pd->atom_list[i].format == EFL_UI_SELECTION_FORMAT_IMAGE) && - (seat_sel->saved_types->imgfile)) - break; - if (ev->selection == ECORE_X_SELECTION_XDND) - { - if (success) - { - Sel_Manager_Dropable *dropable; - Eina_List *l; - sel_debug("drag & drop\n"); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->obj == sel->request_obj) break; - dropable = NULL; - } - if (dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - ddata.action = sel->action; - if (!dropable->is_container) - { - sel_debug("normal dnd, not container"); - ddata.pos = seat_sel->saved_types->pos; - } - else - { - sel_debug("Drop on container"); - Eina_Position2D pos, posret = {0, 0}; - evas_object_geometry_get(dropable->obj, &pos.x, &pos.y, NULL, NULL); - //get item - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + pos.x, - seat_sel->saved_types->pos.y + pos.y); - Efl_Object *it = NULL; - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, - dropable->obj, pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - sel_debug("calling Drop event on: %p", dropable->obj); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - } - } - else - { - sel_debug("dnd: has NO dropable"); - } - } - /* We have to finish DnD, no matter what */ - ecore_x_dnd_send_finished(); - } - else if (sel->data_func && success) - { - ddata.pos.x = ddata.pos.y = 0; - sel->data_func(sel->data_func_data, sel->request_obj, &ddata); - } - free((void *)ddata.content.mem); - if (tmp_info) _tmpinfo_free(tmp_info); - } - else sel_debug("Ignored: No handler!"); - break; - } - } - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_selection_clear(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Ecore_X_Event_Selection_Clear *ev = event; - Sel_Manager_Selection *sel; - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - unsigned int i; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - seat_sel = _sel_manager_seat_selection_get(pd, 1); - if (!seat_sel) - return EINA_FALSE; - - for (i = EFL_UI_SELECTION_TYPE_PRIMARY; i <= EFL_UI_SELECTION_TYPE_CLIPBOARD; i++) - { - if (seat_sel->sel_list[i].ecore_sel == ev->selection) break; - } - sel_debug("selection %d clear", i); - /* Not me... Don't care */ - if (i > EFL_UI_SELECTION_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON; - - sel = seat_sel->sel_list + i; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == i)) - { - sel_debug("resolve the promise: %p", sel_lost->promise); - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - sel->active = EINA_FALSE; - sel->owner = NULL; - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_general_converter(char *target EINA_UNUSED, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - sel_debug("general converter"); - Sel_Manager_Selection *sel = *(Sel_Manager_Selection **)data; - if (sel->format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(sel->data.len * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, sel->data.mem, sel->data.len); - ((char**)(data_ret))[0][sel->data.len] = 0; - } - if (size_ret) *size_ret = sel->data.len; - } - else - { - if (sel->data.mem) - { - if (data_ret) - *data_ret = eina_memdup(sel->data.mem, sel->data.len, 1); - if (size_ret) *size_ret = sel->data.len; - } - else - { - if (data_ret) *data_ret = NULL; - if (size_ret) *size_ret = 0; - } - } - return EINA_TRUE; -} - -static Eina_Bool -_x11_targets_converter(char *target EINA_UNUSED, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize) -{ - int i, count; - Ecore_X_Atom *aret; - Sel_Manager_Selection *sel; - Efl_Ui_Selection_Format seltype; - - sel_debug("target converter"); - if (!data_ret) return EINA_FALSE; - - sel = *(Sel_Manager_Selection **)data; - seltype = sel->format; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++) - { - if (seltype & pd->atom_list[i].format) count++; - } - aret = malloc(sizeof(Ecore_X_Atom) * count); - if (!aret) return EINA_FALSE; - for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++) - { - if (seltype & pd->atom_list[i].format) - aret[count ++] = pd->atom_list[i].x_atom; - } - - *data_ret = aret; - if (typesize) *typesize = 32 /* urk */; - if (ttype) *ttype = ECORE_X_ATOM_ATOM; - if (size_ret) *size_ret = count; - return EINA_TRUE; -} - -static Eina_Bool -_x11_image_converter(char *target EINA_UNUSED, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret EINA_UNUSED, int *size_ret EINA_UNUSED, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - sel_debug("Image converter called"); - return EINA_TRUE; -} - -static Eina_Bool -_x11_vcard_send(char *target EINA_UNUSED, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - Sel_Manager_Selection *sel; - - sel_debug("Vcard send called"); - sel = *(Sel_Manager_Selection **)data; - if (data_ret) - { - char *s; - - s = malloc(sel->data.len + 1); - if (!s) return EINA_FALSE; - memcpy(s, sel->data.mem, sel->data.len); - s[sel->data.len] = 0; - *data_ret = s; - } - - if (size_ret) *size_ret = sel->data.len; - return EINA_TRUE; -} - -static Eina_Bool -_x11_text_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize) -{ - Sel_Manager_Selection *sel; - - sel = *(Sel_Manager_Selection **)data; - if (!sel) return EINA_FALSE; - - sel_debug("text converter"); - if (sel->format == EFL_UI_SELECTION_FORMAT_NONE) - { - sel_debug("none"); - if (data_ret) - { - *data_ret = malloc(sel->data.len * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, sel->data.len); - ((char**)(data_ret))[0][sel->data.len] = 0; - } - if (size_ret) *size_ret = sel->data.len; - return EINA_TRUE; - } - - if (!sel->active) return EINA_TRUE; - - if ((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *tmp = malloc(sel->data.len + 1); - if (tmp) - { - strncpy(tmp, sel->data.mem, sel->data.len); - tmp[sel->data.len] = 0; - *data_ret = _elm_util_mkup_to_text(tmp); - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - free(tmp); - sel_debug("markup or html: %s", (const char *)*data_ret); - } - else return EINA_FALSE; - } - else if (sel->format & EFL_UI_SELECTION_FORMAT_TEXT) - { - ecore_x_selection_converter_text(target, sel->data.mem, - sel->data.len, - data_ret, size_ret, - ttype, typesize); - sel_debug("text"); - } - else if (sel->format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - efl_file_simple_get(sel->request_obj, (const char **)data_ret, NULL); - if (!*data_ret) *data_ret = strdup("No file"); - else *data_ret = strdup(*data_ret); - - if (!*data_ret) - { - ERR("Failed to allocate memory!"); - *size_ret = 0; - return EINA_FALSE; - } - - *size_ret = strlen(*data_ret); - } - return EINA_TRUE; -} - -static Eina_Future * -_x11_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *owner, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data, - Ecore_X_Window xwin, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Eina_Bool same_win = EINA_FALSE; - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel_list + type; - //support 1 app with multiple window, 1 selection manager - if (seat_sel->xwin == xwin) - same_win = EINA_TRUE; - _owner_change_check(pd->sel_man, owner, seat_sel, sel, type, same_win); - seat_sel->xwin = xwin; - - sel->owner = owner; - free(sel->data.mem); - sel->xwin = xwin; - sel->data = eina_slice_dup(data); - sel->active = EINA_TRUE; - sel->format = format; - - sel->set(xwin, &sel, sizeof(Sel_Manager_Selection *)); - sel_debug("data: %p (%zu)", &sel, sizeof(Sel_Manager_Selection *)); - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_x11_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_X_Window xwin, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel;; - - sel_debug("request: %p, seat: %u, type: %d, format: %d", request, seat, type, format); - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel_list + type; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - sel->request_format = format; - sel->xwin = xwin; - - if (sel->active) - { - if (sel->data.mem && - ((format == sel->format) || (xwin == 0))) - { - sel_debug("use local data"); - Efl_Ui_Selection_Data seldata; - - seldata.content.mem = sel->data.mem; - seldata.content.len = sel->data.len; - seldata.pos.x = seldata.pos.y = 0; - seldata.format = sel->format; - sel->data_func(sel->data_func_data, sel->request_obj, &seldata); - return; - } - } - - sel->asked = 2; - sel->request(xwin, ECORE_X_SELECTION_TARGET_TARGETS); -} - -static void -_x11_win_rotation_changed_cb(void *data, const Efl_Event *event) -{ - Evas_Object *win = data; - int rot = elm_win_rotation_get(event->object); - elm_win_rotation_set(win, rot); -} - -static Eina_Bool -_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Window xwin = seat_sel->xwin; - Ecore_Event_Mouse_Button *ev = event; - - if ((ev->buttons == 1) && - (ev->event_window == xwin)) - { - Eina_Bool have_drop_list = EINA_FALSE; - Eina_List *l; - Sel_Manager_Dropable *dropable; - - ecore_x_pointer_ungrab(); - ELM_SAFE_FREE(seat_sel->mouse_up_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->dnd_status_handler, ecore_event_handler_del); - ecore_x_dnd_self_drop(); - - sel_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin); - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_FALSE); - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL); - if (seat_sel->drag_win) - { - if (seat_sel->drag_obj) - { - if (elm_widget_is(seat_sel->drag_obj)) - { - Evas_Object *win = elm_widget_top_get(seat_sel->drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - efl_event_callback_del(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - - if (!seat_sel->accept) - { /* Commit animation when drag cancelled */ - /* Record final position of dragwin, then do animation */ - ecore_evas_animator_timeline_add(seat_sel->drag_win, 0.3, - _drag_cancel_animate, seat_sel); - } - else - { /* No animation drop was committed */ - Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 0); - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - sel_debug("deleted drag_win"); - } - } - - seat_sel->drag_obj = NULL; - seat_sel->accept = EINA_FALSE; - } - return EINA_TRUE; -} - -static void -_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Dnd_Drag_Pos dp; - - evas_object_move(seat_sel->drag_win, - pos->position.x - seat_sel->drag_pos.x, - pos->position.y - seat_sel->drag_pos.y); - seat_sel->drag_win_end.x = pos->position.x - seat_sel->drag_pos.x; - seat_sel->drag_win_end.y = pos->position.y - seat_sel->drag_pos.y; - sel_debug("dragevas: %p -> %p\n", - seat_sel->drag_obj, - evas_object_evas_get(seat_sel->drag_obj)); - dp.pos.x = pos->position.x; - dp.pos.y = pos->position.y; - dp.action = seat_sel->drag_action; - //for drag side - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_POS, &dp); -} - -static void -_x11_drag_target_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Selection *sel = &seat_sel->sel_list[seat_sel->active_type]; - - if (seat_sel->drag_obj == obj) - { - sel->request_obj = NULL; - seat_sel->drag_obj = NULL; - } -} - -static Eina_Bool -_x11_dnd_status(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Ecore_X_Event_Xdnd_Status *status = ev; - - seat_sel->accept = EINA_FALSE; - - /* Only thing we care about: will accept */ - if ((status) && (status->will_accept)) - { - sel_debug("Will accept\n"); - seat_sel->accept = EINA_TRUE; - } - /* Won't accept */ - else - { - sel_debug("Won't accept accept\n"); - } - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept); - - return EINA_TRUE; -} - -static void -_x11_efl_sel_manager_drag_start(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Format format, - Eina_Slice data, Efl_Ui_Selection_Action action, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, - Eina_Free_Cb icon_func_free_cb EINA_UNUSED, - Ecore_X_Window xwin, unsigned int seat) -{ - Ecore_X_Window xdragwin; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Evas *ee; - int x, y, x2 = 0, y2 = 0, x3, y3; - Evas_Object *icon = NULL; - int w = 0, h = 0; - int ex, ey, ew, eh; - Ecore_X_Atom actx; - int i; - int xr, yr, rot; - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return; - seat_sel->active_type = EFL_UI_SELECTION_TYPE_DND; - - sel = &seat_sel->sel_list[seat_sel->active_type]; - ecore_x_dnd_types_set(xwin, NULL, 0); - for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++) - { - if (format == EFL_UI_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format)) - { - ecore_x_dnd_type_set(xwin, pd->atom_list[i].name, EINA_TRUE); - sel_debug("set dnd type: %s\n", pd->atom_list[i].name); - } - } - - sel->active = EINA_TRUE; - sel->request_obj = drag_obj; - sel->format = format; - if (sel->data.mem) free(sel->data.mem); - sel->data = eina_slice_dup(data); - sel->action = action; - seat_sel->drag_obj = drag_obj; - seat_sel->drag_action = action; - seat_sel->xwin = xwin; - - evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL, - _x11_drag_target_del, seat_sel); - /* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */ - ecore_x_dnd_aware_set(xwin, EINA_TRUE); - ecore_x_dnd_callback_pos_update_set(_x11_drag_move, seat_sel); - ecore_x_dnd_self_begin(xwin, (unsigned char *)sel, sizeof(Sel_Manager_Selection)); - actx = _x11_dnd_action_rev_map(seat_sel->drag_action); - ecore_x_dnd_source_action_set(actx); - ecore_x_pointer_grab(xwin); - seat_sel->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, - _x11_drag_mouse_up, seat_sel); - seat_sel->dnd_status_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS, - _x11_dnd_status, seat_sel); - seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); - elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE); - elm_win_override_set(seat_sel->drag_win, EINA_TRUE); - xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 1); - - /* dragwin has to be rotated as the main window is */ - if (elm_widget_is(drag_obj)) - { - Evas_Object *win = elm_widget_top_get(drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - { - elm_win_rotation_set(seat_sel->drag_win, elm_win_rotation_get(win)); - efl_event_callback_add(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - - if (icon_func) - { - Eina_Position2D off; - - icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off); - if (icon) - { - x2 = off.x; - y2 = off.y; - evas_object_geometry_get(icon, NULL, NULL, &w, &h); - } - } - else - { - icon = elm_icon_add(seat_sel->drag_win); - evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - // need to resize - } - elm_win_resize_object_add(seat_sel->drag_win, icon); - - /* Position subwindow appropriately */ - ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj)); - ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh); - evas_object_resize(seat_sel->drag_win, w, h); - - evas_object_show(icon); - evas_object_show(seat_sel->drag_win); - evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3); - - rot = ecore_evas_rotation_get(ee); - switch (rot) - { - case 90: - xr = y3; - yr = ew - x3; - seat_sel->drag_pos.x = y3 - y2; - seat_sel->drag_pos.y = x3 - x2; - break; - case 180: - xr = ew - x3; - yr = eh - y3; - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - break; - case 270: - xr = eh - y3; - yr = x3; - seat_sel->drag_pos.x = y3 - y2; - seat_sel->drag_pos.y = x3 - x2; - break; - default: - xr = x3; - yr = y3; - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - break; - } - x = ex + xr - seat_sel->drag_pos.x; - y = ey + yr - seat_sel->drag_pos.y; - evas_object_move(seat_sel->drag_win, x, y); - seat_sel->drag_win_start = EINA_POSITION2D(x, y); - seat_sel->drag_win_end = EINA_POSITION2D(x, y); -} - -static void -_x11_dnd_dropable_handle(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Eina_Position2D pos, Efl_Ui_Selection_Action action) -{ - Sel_Manager_Dropable *d, *last_dropable = NULL; - Eina_List *l; - Eina_Inlist *itr; - - EINA_LIST_FOREACH(pd->drop_list, l, d) - { - if (d->last.in) - { - last_dropable = d; - break; - } - } - if (last_dropable) - { - if (last_dropable == dropable) // same - { - Evas_Coord ox, oy; - Drop_Format *df; - - sel_debug("same obj dropable %p\n", dropable->obj); - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - Efl_Dnd_Drag_Pos pos_data; - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy); - pos_data.item = NULL; - } - else - { - Eina_Position2D posret = {0, 0}; - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - pos_data.pos = posret; - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - else - { - if (dropable) // leave last obj and enter new one - { - sel_debug("leave %p\n", last_dropable->obj); - sel_debug("enter %p\n", dropable->obj); - last_dropable->last.in = EINA_FALSE; - last_dropable->last.type = NULL; - dropable->last.in = EINA_TRUE; - - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format &dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - } - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - else // leave last obj - { - sel_debug("leave %p\n", last_dropable->obj); - last_dropable->last.in = EINA_FALSE; - last_dropable->last.type = NULL; - - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - } - } - else - { - if (dropable) // enter new obj - { - Evas_Coord ox, oy; - - sel_debug("enter %p\n", dropable->obj); - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - dropable->last.in = EINA_TRUE; - - Drop_Format *df; - Efl_Dnd_Drag_Pos pos_data; - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy); - pos_data.item = NULL; - } - else - { - Eina_Position2D posret = {0, 0}; - Efl_Object *it = NULL; - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - pos_data.pos = posret; - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - } - else - { - sel_debug("both dropable & last_dropable are null\n"); - } - } -} - -static Sel_Manager_Dropable * -_x11_dropable_find(Efl_Ui_Selection_Manager_Data *pd, Ecore_X_Window win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!pd->drop_list) return NULL; - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (_x11_xwin_get(dropable->obj) == win) return dropable; - } - return NULL; -} - -static Evas * -_x11_evas_get_from_xwin(Efl_Ui_Selection_Manager_Data *pd, Ecore_X_Window win) -{ - /* Find the Evas connected to the window */ - Sel_Manager_Dropable *dropable = _x11_dropable_find(pd, win); - return dropable ? evas_object_evas_get(dropable->obj) : NULL; -} - -static Efl_Ui_Selection_Action -_x11_dnd_action_map(Ecore_X_Atom action) -{ - Efl_Ui_Selection_Action act = EFL_UI_SELECTION_ACTION_UNKNOWN; - - if (action == ECORE_X_ATOM_XDND_ACTION_COPY) - act = EFL_UI_SELECTION_ACTION_COPY; - else if (action == ECORE_X_ATOM_XDND_ACTION_MOVE) - act = EFL_UI_SELECTION_ACTION_MOVE; - else if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE) - act = EFL_UI_SELECTION_ACTION_PRIVATE; - else if (action == ECORE_X_ATOM_XDND_ACTION_ASK) - act = EFL_UI_SELECTION_ACTION_ASK; - else if (action == ECORE_X_ATOM_XDND_ACTION_LIST) - act = EFL_UI_SELECTION_ACTION_LIST; - else if (action == ECORE_X_ATOM_XDND_ACTION_LINK) - act = EFL_UI_SELECTION_ACTION_LINK; - else if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION) - act = EFL_UI_SELECTION_ACTION_DESCRIPTION; - return act; -} - -static Ecore_X_Atom -_x11_dnd_action_rev_map(Efl_Ui_Selection_Action action) -{ - Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE; - - if (action == EFL_UI_SELECTION_ACTION_COPY) - act = ECORE_X_ATOM_XDND_ACTION_COPY; - else if (action == EFL_UI_SELECTION_ACTION_MOVE) - act = ECORE_X_ATOM_XDND_ACTION_MOVE; - else if (action == EFL_UI_SELECTION_ACTION_PRIVATE) - act = ECORE_X_ATOM_XDND_ACTION_PRIVATE; - else if (action == EFL_UI_SELECTION_ACTION_ASK) - act = ECORE_X_ATOM_XDND_ACTION_ASK; - else if (action == EFL_UI_SELECTION_ACTION_LIST) - act = ECORE_X_ATOM_XDND_ACTION_LIST; - else if (action == EFL_UI_SELECTION_ACTION_LINK) - act = ECORE_X_ATOM_XDND_ACTION_LINK; - else if (action == EFL_UI_SELECTION_ACTION_DESCRIPTION) - act = ECORE_X_ATOM_XDND_ACTION_DESCRIPTION; - return act; -} - -static Eina_Bool -_x11_dnd_enter(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Enter *enter = ev; - Sel_Manager_Dropable *dropable; - int i; - - sel_debug("In"); - if (!enter) return EINA_TRUE; - dropable = _x11_dropable_find(pd, enter->win); - if (dropable) - { - sel_debug("Enter %x\n", enter->win); - } - /* Skip it */ - sel_debug("enter types=%p (%d)\n", enter->types, enter->num_types); - if ((!enter->num_types) || (!enter->types)) return EINA_TRUE; - - sel_debug("Types\n"); - seat_sel->saved_types->ntypes = enter->num_types; - free(seat_sel->saved_types->types); - seat_sel->saved_types->types = malloc(sizeof(char *) * enter->num_types); - if (!seat_sel->saved_types->types) return EINA_FALSE; - - for (i = 0; i < enter->num_types; i++) - { - seat_sel->saved_types->types[i] = eina_stringshare_add(enter->types[i]); - sel_debug("Type is %s %p %p\n", enter->types[i], - seat_sel->saved_types->types[i], pd->text_uri); - if (seat_sel->saved_types->types[i] == pd->text_uri) - { - /* Request it, so we know what it is */ - sel_debug("Sending uri request\n"); - seat_sel->saved_types->textreq = 1; - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - ecore_x_selection_xdnd_request(enter->win, pd->text_uri); - } - } - - /* FIXME: Find an object and make it current */ - return EINA_TRUE; -} - -static Eina_Bool -_x11_dnd_position(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Position *xpos = ev; - Ecore_X_Rectangle rect = { 0, 0, 0, 0 }; - Sel_Manager_Dropable *dropable; - Efl_Ui_Selection_Action act; - - sel_debug("In"); - /* Need to send a status back */ - /* FIXME: Should check I can drop here */ - /* FIXME: Should highlight widget */ - dropable = _x11_dropable_find(pd, xpos->win); - if (dropable) - { - Evas_Coord ox = 0, oy = 0; - Eina_Position2D pos; - - act = _x11_dnd_action_map(xpos->action); - pos.x = xpos->position.x; - pos.y = xpos->position.y; - _dropable_coords_adjust(dropable, &pos); - Evas *evas = _x11_evas_get_from_xwin(pd, xpos->win); - Eina_List *dropable_list = evas ? _dropable_list_geom_find(pd, evas, pos.x, pos.y) : NULL; - /* check if there is dropable (obj) can accept this drop */ - if (dropable_list) - { - Efl_Ui_Selection_Format saved_format = _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes); - Eina_List *l; - Eina_Bool found = EINA_FALSE; - - EINA_LIST_FOREACH(dropable_list, l, dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - Efl_Ui_Selection_Format common_fmt = saved_format & df->format; - if (common_fmt) - { - //We found a target that can accept this type of data - int i, min_index = SELECTION_N_ATOMS; - //We have to find the first atom that corresponds to one - //of the supported data types. - for (i = 0; i < seat_sel->saved_types->ntypes; i++) - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, seat_sel->saved_types->types[i]); - if (atom && (atom->format & common_fmt)) - { - int atom_idx = (atom - pd->atom_list); - if (min_index > atom_idx) min_index = atom_idx; - } - } - if (min_index != SELECTION_N_ATOMS) - { - sel_debug("Found atom %s\n", pd->atom_list[min_index].name); - found = EINA_TRUE; - dropable->last.type = pd->atom_list[min_index].name; - dropable->last.format = common_fmt; - break; - } - } - } - if (found) break; - } - if (found) - { - Sel_Manager_Dropable *d = NULL; - Eina_Rectangle inter_rect = {0, 0, 0, 0}; - int idx = 0; - EINA_LIST_FOREACH(dropable_list, l, d) - { - if (idx == 0) - { - evas_object_geometry_get(d->obj, &inter_rect.x, &inter_rect.y, - &inter_rect.w, &inter_rect.h); - } - else - { - Eina_Rectangle cur_rect; - evas_object_geometry_get(d->obj, &cur_rect.x, &cur_rect.y, - &cur_rect.w, &cur_rect.h); - if (!eina_rectangle_intersection(&inter_rect, &cur_rect)) continue; - } - idx++; - } - rect.x = inter_rect.x; - rect.y = inter_rect.y; - rect.width = inter_rect.w; - rect.height = inter_rect.h; - ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position %i %i %p\n", pos.x - ox, pos.y - oy, dropable); - pos.x = pos.x - ox; - pos.y = pos.y - oy; - _x11_dnd_dropable_handle(pd, dropable, pos, act); - // CCCCCCC: call dnd exit on last obj if obj != last - // CCCCCCC: call drop position on obj - } - else - { - //if not: send false status - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position (%d, %d) not in obj\n", pos.x, pos.y); - _x11_dnd_dropable_handle(pd, NULL, EINA_POSITION2D(0, 0), act); - // CCCCCCC: call dnd exit on last obj - } - eina_list_free(dropable_list); - } - else - { - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position (%d, %d) has no drop\n", pos.x, pos.y); - _x11_dnd_dropable_handle(pd, NULL, EINA_POSITION2D(0, 0), act); - } - } - else - { - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - } - return EINA_TRUE; -} - -static Eina_Bool -_x11_dnd_leave(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Eina_Position2D pos = {0, 0}; -#ifdef DEBUGON - sel_debug("Leave %x\n", ((Ecore_X_Event_Xdnd_Leave *)ev)->win); -#else - (void)ev; -#endif - _x11_dnd_dropable_handle(seat_sel->pd, NULL, pos, EFL_UI_SELECTION_ACTION_UNKNOWN); - // CCCCCCC: call dnd exit on last obj if there was one - // leave->win leave->source - return EINA_TRUE; -} - -static Eina_Bool -_x11_dnd_drop(void *data, int etype EINA_UNUSED, void *ev) -{ - sel_debug("In"); - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Drop *drop; - Sel_Manager_Dropable *dropable = NULL; - Evas_Coord x = 0, y = 0; - Efl_Ui_Selection_Action act = EFL_UI_SELECTION_ACTION_UNKNOWN; - Eina_List *l; - Sel_Manager_Selection *sel; - - drop = ev; - sel_debug("drop_list %p (%d)\n", pd->drop_list, eina_list_count(pd->drop_list)); - if (!(dropable = _x11_dropable_find(pd, drop->win))) return EINA_TRUE; - - /* Calculate real (widget relative) position */ - // - window position - // - widget position - seat_sel->saved_types->pos = EINA_POSITION2D(drop->position.x, drop->position.y); - _dropable_coords_adjust(dropable, &seat_sel->saved_types->pos); - - sel_debug("Drop position is %d,%d\n", seat_sel->saved_types->pos.x, seat_sel->saved_types->pos.y); - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->last.in) - { - evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL); - seat_sel->saved_types->pos.x -= x; - seat_sel->saved_types->pos.y -= y; - goto found; - } - } - - sel_debug("Didn't find a target\n"); - return EINA_TRUE; - -found: - sel_debug("0x%x\n", drop->win); - - act = _x11_dnd_action_map(drop->action); - - dropable->last.in = EINA_FALSE; - sel_debug("Last type: %s - Last format: %X\n", dropable->last.type, dropable->last.format); -#if 0 // this seems to be broken and causes dnd to stop working e.g. to/from - // rage even though iut used to work fine. - Efl_Ui_Selection_Data ddata; - Eina_Inlist *itr; - if ((!strcmp(dropable->last.type, pd->text_uri))) - { - sel_debug("We found a URI... (%scached) %s\n", - seat_sel->saved_types->imgfile ? "" : "not ", - seat_sel->saved_types->imgfile); - if (seat_sel->saved_types->imgfile) - { - Drop_Format *df; - - if (!dropable->is_container) - { - ddata.pos = seat_sel->saved_types->pos; - ddata.item = NULL; - } - else - { - //for container - Efl_Object *it = NULL; - Evas_Coord x0 = 0, y0 = 0; - Eina_Position2D pos, posret = {0, 0}; - - evas_object_geometry_get(dropable->obj, &x0, &y0, NULL, NULL); - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + x0, - seat_sel->saved_types->pos.y + y0); - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - ddata.action = act; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - sel_debug("Doing image insert (%s)\n", seat_sel->saved_types->imgfile); - ddata.format = EFL_UI_SELECTION_FORMAT_IMAGE; - ddata.content.mem = (char *)seat_sel->saved_types->imgfile; - ddata.content.len = strlen(ddata.content.mem); - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - else - { - sel_debug("Item doesn't support images... passing\n"); - } - } - ecore_x_dnd_send_finished(); - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - return EINA_TRUE; - } - else if (seat_sel->saved_types->textreq) - { - /* Already asked: Pretend we asked now, and paste immediately when - * it comes in */ - seat_sel->saved_types->textreq = 0; - ecore_x_dnd_send_finished(); - return EINA_TRUE; - } - } -#endif - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_DND; - sel_debug("doing a request then: %s\n", dropable->last.type); - sel->xwin = drop->win; - sel->request_obj = dropable->obj; - sel->request_format = dropable->last.format; - sel->active = EINA_TRUE; - sel->action = act; - sel->asked++; - ecore_x_selection_xdnd_request(drop->win, dropable->last.type); - - return EINA_TRUE; -} - -static Eina_Bool -_x11_sel_manager_drop_target_add(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *target_obj, - Efl_Ui_Selection_Format format, Ecore_X_Window xwin, - unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Eina_List *l; - Eina_Bool have_drop_list = EINA_FALSE; - Sel_Manager_Seat_Selection *seat_sel = NULL; - - /* Is this the first? */ - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - dropable = NULL; // In case of error, we don't want to free it - - - Drop_Format *df = calloc(1, sizeof(Drop_Format)); - if (!df) return EINA_FALSE; - df->format = format; - - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (!dropable) - { - /* Create new drop */ - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) goto error; - dropable->last.in = EINA_FALSE; - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) goto error; - dropable->obj = target_obj; - efl_key_data_set(target_obj, "__elm_dropable", dropable); - } - dropable->format_list = eina_inlist_append(dropable->format_list, EINA_INLIST_GET(df)); - dropable->seat = seat; - - evas_object_event_callback_add(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del, pd); - if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_TRUE); - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - - if (seat_sel->enter_handler) return EINA_TRUE; - sel_debug("Adding drop target calls xwin=%#llx", (unsigned long long)xwin); - seat_sel->enter_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER, - _x11_dnd_enter, seat_sel); - seat_sel->leave_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE, - _x11_dnd_leave, seat_sel); - seat_sel->pos_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION, - _x11_dnd_position, seat_sel); - seat_sel->drop_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP, - _x11_dnd_drop, seat_sel); - return EINA_TRUE; -error: - free(df); - free(dropable); - return EINA_FALSE; -} - -#endif - -//Wayland -#ifdef HAVE_ELEMENTARY_WL2 -static Sel_Manager_Seat_Selection * -_wl_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } - - return seat_sel; -} - -static void -_wl_drag_source_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - if (seat_sel->drag_obj == obj) - seat_sel->drag_obj = NULL; -} - -static void -_wl_efl_sel_manager_drag_start(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, Efl_Object *drag_obj, - Efl_Ui_Selection_Format format, Eina_Slice data, - Efl_Ui_Selection_Action action, void *icon_func_data, - Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb EINA_UNUSED, - Ecore_Wl2_Window *win, unsigned int seat) -{ - Ecore_Evas *ee; - Evas_Object *icon = NULL; - int x, y, x2 = 0, y2 = 0, x3, y3, w = 0, h = 0; - const char *types[SELECTION_N_ATOMS + 1]; - int i, nb_types = 0; - Ecore_Wl2_Window *parent = NULL; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - sel_debug("In"); - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return; - seat_sel->active_type = EFL_UI_SELECTION_TYPE_DND; - sel = seat_sel->sel; - - sel_debug("checking drag_win: %p", seat_sel->drag_win); - /* if we already have a drag, get out */ - if (seat_sel->drag_win) return; - - for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++) - { - if (format == EFL_UI_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format)) - { - types[nb_types++] = pd->atom_list[i].name; - sel_debug("set dnd type: %s\n", pd->atom_list[i].name); - } - } - types[nb_types] = NULL; - - ecore_wl2_dnd_drag_types_set(_wl_seat_get(win, drag_obj, seat), types); - - /* set the drag data used when a drop occurs */ - free(sel->data.mem); - sel->data.len = 0; - sel->data = eina_slice_dup(data); - - /* setup callback to notify if this object gets deleted */ - evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL, - _wl_drag_source_del, sel); - - seat_sel->drag_obj = drag_obj; - seat_sel->drag_action = action; - - seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); - elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE); - elm_win_borderless_set(seat_sel->drag_win, EINA_TRUE); - elm_win_override_set(seat_sel->drag_win, EINA_TRUE); - - win = elm_win_wl_window_get(seat_sel->drag_win); - - if (icon_func) - { - Eina_Position2D off; - - icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off); - if (icon) - { - x2 = off.x; - y2 = off.y; - evas_object_geometry_get(icon, NULL, NULL, &w, &h); - } - } - else - { - icon = elm_icon_add(seat_sel->drag_win); - evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, - EVAS_HINT_EXPAND); - } - - elm_win_resize_object_add(seat_sel->drag_win, icon); - evas_object_show(icon); - - /* Position subwindow appropriately */ - ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj)); - ecore_evas_geometry_get(ee, &x, &y, NULL, NULL); - x += x2; - y += y2; - seat_sel->drag_win_start.x = seat_sel->drag_win_end.x = x; - seat_sel->drag_win_start.y = seat_sel->drag_win_end.y = y; - - evas_object_geometry_set(seat_sel->drag_win, x, y, w, h); - evas_object_show(seat_sel->drag_win); - - evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3); - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - - if (elm_widget_is(drag_obj)) - { - Evas_Object *top; - - top = elm_widget_top_get(drag_obj); - if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(drag_obj)); - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - parent = elm_win_wl_window_get(top); - } - if (!parent) - { - Evas *evas; - - if (!(evas = evas_object_evas_get(drag_obj))) - return; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return; - - parent = ecore_evas_wayland2_window_get(ee); - } - - sel->drag_serial = ecore_wl2_dnd_drag_start(_wl_seat_get(win, drag_obj, seat), parent, win); -} - -static Eina_Bool -_wl_is_uri_type_data(const char *data, int len) -{ - char *p; - if (len < 6) return EINA_FALSE; - - p = (char *)data; - if (!p) return EINA_FALSE; - if (strncmp(p, "file:/", 6)) - { - if (*p != '/') return EINA_FALSE; - } - return EINA_TRUE; -} - -static Efl_Ui_Selection_Action -_wl_to_elm(Ecore_Wl2_Drag_Action action) -{ - #define CONV(wl, elm) if (action == wl) return elm; - CONV(ECORE_WL2_DRAG_ACTION_COPY, EFL_UI_SELECTION_ACTION_COPY); - CONV(ECORE_WL2_DRAG_ACTION_MOVE, EFL_UI_SELECTION_ACTION_MOVE); - CONV(ECORE_WL2_DRAG_ACTION_ASK, EFL_UI_SELECTION_ACTION_ASK); - #undef CONV - return EFL_UI_SELECTION_ACTION_UNKNOWN; -} - -static Eina_Bool -_wl_targets_converter(char *target, Sel_Manager_Selection *sel, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret, int *size_ret) -{ - sel_debug("in\n"); - if (!data_ret) return EINA_FALSE; - - const char *sep = "\n"; - char *aret; - int len = 0; - int i = 0; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Eina_Bool is_uri = EINA_FALSE; - - if (sel->format) - { - format = sel->format; - is_uri = _wl_is_uri_type_data(sel->data.mem, sel->data.len); - } - else - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - } - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - len += strlen(pd->atom_list[i].name) + strlen(sep); - } - } - len++; //terminating null byte - aret = calloc(1, len * sizeof(char)); - if (!aret) return EINA_FALSE; - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - { - aret = strcat(aret, pd->atom_list[i].name); - aret = strcat(aret, sep); - } - } - } - *data_ret = aret; - if (size_ret) *size_ret = len; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_general_converter(char *target, Sel_Manager_Selection *sel, void *data, int size, void **data_ret, int *size_ret) -{ - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Sel_Manager_Atom *atom = NULL; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - sel_debug("in\n"); - - atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - if (format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(size * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, size); - ((char**)(data_ret))[0][size] = 0; - } - if (size_ret) *size_ret = size; - } - else - { - if ((data) && (size > 0)) - { - char *tmp = malloc(size); - if (tmp) - { - memcpy(tmp, data, size); - if (data_ret) *data_ret = tmp; - if (size_ret) *size_ret = size; - if (!data_ret) free(tmp); - } - } - else - { - if (data_ret) *data_ret = NULL; - if (size_ret) *size_ret = 0; - } - } - - return EINA_TRUE; -} - -static Eina_Bool -_wl_text_converter(char *target, Sel_Manager_Selection *sel, void *data, int size, void **data_ret, int *size_ret) -{ - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Sel_Manager_Atom *atom = NULL; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - sel_debug("in\n"); - - atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - if (format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(size * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, size); - ((char**)(data_ret))[0][size] = 0; - if (size_ret) *size_ret = size; - return EINA_TRUE; - } - } - else if ((format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *tmp = malloc(size + 1); - if (tmp) - { - strncpy(tmp, data, size); - tmp[size] = 0; - *data_ret = _elm_util_mkup_to_text(tmp); - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - free(tmp); - } - else return EINA_FALSE; - } - else if (format & EFL_UI_SELECTION_FORMAT_TEXT) - { - char *tmp = malloc(size + 1); - if (tmp) - { - strncpy(tmp, data, size); - tmp[size] = 0; - *data_ret = tmp; - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - } - else return EINA_FALSE; - } - else if (format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - sel_debug("Image %s\n", evas_object_type_get(sel->request_obj)); - efl_file_simple_get(sel->request_obj, (const char **)data_ret, NULL); - if (!*data_ret) *data_ret = strdup("No file"); - else *data_ret = strdup(*data_ret); - - if (!*data_ret) - { - ERR("Failed to allocate memory!"); - *size_ret = 0; - return EINA_FALSE; - } - - if (size_ret) *size_ret = strlen(*data_ret); - } - return EINA_TRUE; -} - -static void -_wl_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) - { - sel->owner = NULL; - } - //if (dragwidget == obj) dragwidget = NULL; -} - -static Eina_Future * -_wl_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Wl2_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - int i = 0, count = 0; - Eina_Bool is_uri = EINA_FALSE; - const char **types; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - - if (data.len <= 0) - return NULL; - - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel; - - if (sel->owner != owner) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - } - - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _wl_sel_obj_del, sel); - sel->active = EINA_TRUE; - sel->owner = owner; - sel->win = win; - /* sel->set(win, &selection, sizeof(Elm_Sel_Type)); */ - sel->format = format; - - evas_object_event_callback_add - (sel->owner, EVAS_CALLBACK_DEL, _wl_sel_obj_del, &sel); - - sel->data = eina_slice_dup(data); - if (!sel->data.mem) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - is_uri = _wl_is_uri_type_data(sel->data.mem, sel->data.len); - types = malloc(sizeof(char *)); - if (!types) return NULL; - for (i = 0, count = 1; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - { - const char **t = NULL; - - types[count - 1] = pd->atom_list[i].name; - count++; - t = realloc(types, sizeof(char *) * count); - if (!t) - { - free(types); - return NULL; - } - types = t; - } - } - } - types[count - 1] = 0; - - sel->selection_serial = ecore_wl2_dnd_selection_set(_wl_seat_get(win, owner, seat_sel->seat), types); - DBG("serial: %d", sel->selection_serial); - - free(types); - //return _local_elm_cnp_selection_set(obj, selection, format, buf, buflen); - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_wl_selection_changed_free(void *data, void *ev) -{ - ecore_wl2_display_disconnect(data); - - free(ev); -} - -static Eina_Bool -_wl_selection_changed(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Elm_Cnp_Event_Selection_Changed *_e; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Efl_Ui_Selection_Changed e; - Ecore_Wl2_Event_Seat_Selection *ev = event; - Ecore_Wl2_Input *seat; - - seat_sel = _wl_sel_manager_seat_selection_init(pd, ev->seat); - sel_debug("seat: %d", ev->seat); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel; - - seat = ecore_wl2_display_input_find(ev->display, ev->seat); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, ECORE_CALLBACK_RENEW); - e.type = EFL_UI_SELECTION_TYPE_CLIPBOARD; - e.seat = ev->seat; - /* connect again to add ref */ - e.display = ecore_wl2_display_connect(ecore_wl2_display_name_get(ev->display)); - e.exist = !!ecore_wl2_dnd_selection_get(seat); - - _e = calloc(1, sizeof(Elm_Cnp_Event_Selection_Changed)); - EINA_SAFETY_ON_NULL_RETURN_VAL(_e, ECORE_CALLBACK_RENEW); - _e->type = e.type; - _e->seat_id = e.seat; - _e->display = e.display; - _e->exists = e.exist; - - ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, _e, _wl_selection_changed_free, ev->display); - efl_event_callback_call(sel->request_obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &e); - - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_wl_selection_send(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - char *buf; - int ret, len_remained; - int len_written = 0; - Ecore_Wl2_Event_Data_Source_Send *ev; - int seat; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - void *data_ret = NULL; - int len_ret = 0; - int i = 0; - - ev = event; - seat = ev->seat; - sel_debug("seat: %d, type: %d", seat, type); - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel; - - if ((ev->serial != sel->selection_serial) && - (ev->serial != sel->drag_serial)) - return ECORE_CALLBACK_RENEW; - - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (!strcmp(pd->atom_list[i].name, ev->type)) - { - sel_debug("Found a type: %s\n", pd->atom_list[i].name); - Sel_Manager_Dropable *drop; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) - drop->last.type = pd->atom_list[i].name; - if (pd->atom_list[i].wl_converter) - { - pd->atom_list[i].wl_converter(ev->type, sel, sel->data.mem, - sel->data.len, &data_ret, &len_ret); - } - else - { - data_ret = eina_memdup(sel->data.mem, sel->data.len, 0); - len_ret = sel->data.len; - } - break; - } - } - - len_remained = len_ret; - buf = data_ret; - - while (len_written < len_ret) - { - ret = write(ev->fd, buf, len_remained); - if (ret == -1) break; - buf += ret; - len_written += ret; - len_remained -= ret; - } - free(data_ret); - - close(ev->fd); - ecore_wl2_display_flush(ev->display); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_end(void *data, int type EINA_UNUSED, void *event) -{ - sel_debug("In"); - Efl_Ui_Selection_Manager_Data *pd = data; - Ecore_Wl2_Event_Data_Source_End *ev; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - ev = event; - seat_sel = _wl_sel_manager_seat_selection_init(pd, ev->seat); - sel = seat_sel->sel; - if (ev->serial != sel->drag_serial) - return ECORE_CALLBACK_RENEW; - - if (seat_sel->active_type != EFL_UI_SELECTION_TYPE_DND) - return ECORE_CALLBACK_RENEW; - - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL); - if (seat_sel->drag_win) - { - if (!seat_sel->accept) - { - /* Commit animation when drag cancelled */ - /* Record final position of dragwin, then do animation */ - ecore_evas_animator_timeline_add(seat_sel->drag_win, 0.3, _drag_cancel_animate, seat_sel); - } - else - { - /* No animation drop was committed */ - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - } - } - - seat_sel->accept = EINA_FALSE; - - ecore_wl2_display_flush(ev->display); - return ECORE_CALLBACK_PASS_ON; -} - -static Ecore_Wl2_Input * -_wl_seat_get(Ecore_Wl2_Window *win, Evas_Object *obj, unsigned int seat_id) -{ - Eo *seat, *parent2, *ewin; - Ecore_Wl2_Input *input = NULL; - - input = ecore_wl2_display_input_find(ecore_wl2_window_display_get(win), seat_id); - if (input) return input; - - if (obj) - { - // FIXME (there might be a better solution): - // In case of inwin, we want to use the main wl2 window for cnp, but obj - // obj belongs to the buffer canvas, so the default seat for obj does not - // match the window win. - Eo *top = elm_widget_top_get(obj); - if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS)) - { - parent2 = efl_ui_win_inlined_parent_get(top); - if (parent2) obj = elm_widget_top_get(parent2) ?: parent2; - } - /* fake win means canvas seat id will not match protocol seat id */ - ewin = elm_win_get(obj); - if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL; - } - - if (!obj) - { - Eina_Iterator *it; - it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win)); - EINA_ITERATOR_FOREACH(it, input) break; - eina_iterator_free(it); - return input; - } - - seat = evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, NULL); - return ecore_wl2_display_input_find(ecore_wl2_window_display_get(win), - evas_device_seat_id_get(seat)); -} - -Ecore_Wl2_Window * -_wl_window_get(const Evas_Object *obj) -{ - Evas_Object *top; - Ecore_Wl2_Window *win = NULL; - - if (elm_widget_is(obj)) - { - top = elm_widget_top_get(obj); - if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj)); - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - win = elm_win_wl_window_get(top); - } - if (!win) - { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; - - if (!(evas = evas_object_evas_get(obj))) - return NULL; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return NULL; - - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - engine_name = ecore_evas_engine_name_get(ee); - } - if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1)) - { - /* In case the engine is not a buffer, we want to check once. */ - win = ecore_evas_wayland2_window_get(ee); - if (!win) return NULL; - } - } - - return win; -} - -static void -_wl_selection_receive_timeout(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - - if (sel->request_obj != obj) return; - - ecore_event_handler_del(sel->offer_handler); -} - -static Eina_Bool -_wl_selection_receive(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Offer_Data_Ready *ev = event; - Sel_Manager_Selection *sel = data; - - if (sel->sel_offer != ev->offer) return ECORE_CALLBACK_PASS_ON; - - if (sel->data_func) - { - Efl_Ui_Selection_Data sel_data; - - sel_data.pos.x = sel_data.pos.y = 0; - if (((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) && - (sel->want_format == EFL_UI_SELECTION_FORMAT_TEXT)) - { - char *tmp = malloc(ev->len + 1); - sel_data.format = sel->format; - sel_data.content.mem = NULL; - sel_data.content.len = 0; - if (tmp) - { - sel_data.format = sel->want_format; - strncpy(tmp, ev->data, ev->len); - tmp[ev->len] = 0; - sel_data.content.mem = _elm_util_mkup_to_text(tmp); - if (sel_data.content.mem) - sel_data.content.len = strlen(sel_data.content.mem); - free(tmp); - } - } - else - { - sel_data.format = sel->format; - sel_data.content.mem = ev->data; - sel_data.content.len = ev->len; - } - sel_data.action = _wl_to_elm(ecore_wl2_offer_action_get(sel->sel_offer)); - sel->data_func(sel->data_func_data, - sel->request_obj, - &sel_data); - } - else - { - char *stripstr, *mkupstr; - - stripstr = malloc(ev->len + 1); - if (!stripstr) return ECORE_CALLBACK_CANCEL; - strncpy(stripstr, (char *)ev->data, ev->len); - stripstr[ev->len] = '\0'; - mkupstr = _elm_util_text_to_mkup((const char *)stripstr); - /* TODO BUG: should never NEVER assume it's an elm_entry! */ - _elm_entry_entry_paste(sel->request_obj, mkupstr); - free(stripstr); - free(mkupstr); - } - - evas_object_event_callback_del_full(sel->request_obj, - EVAS_CALLBACK_DEL, - _wl_selection_receive_timeout, sel); - - ecore_event_handler_del(sel->offer_handler); - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_wl_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_Wl2_Window *win, unsigned int seat) -{ - sel_debug("In, format: %d", format); - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Wl2_Input *input; - Ecore_Wl2_Offer *offer; - int i = 0; - - if (type == EFL_UI_SELECTION_TYPE_DND) return EINA_FALSE; - - //if (sel->active) - //return _local_elm_cnp_selection_get(obj, selection, format, datacb, udata); - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - - input = _wl_seat_get(win, (Efl_Object *)request, seat_sel->seat); - offer = ecore_wl2_dnd_selection_get(input); - - //there can be no selection available - if (!offer) return EINA_FALSE; - - for (i = 0; sm_wl_convertion[i].translates; i++) - { - int j = 0; -// if (!(format & sm_wl_convertion[i].format)) continue; - - for (j = 0; sm_wl_convertion[i].translates[j]; j++) - { - if (!ecore_wl2_offer_supports_mime(offer, sm_wl_convertion[i].translates[j])) continue; - - //we have found matching mimetypes - sel->sel_offer = offer; - sel->format = sm_wl_convertion[i].format; - sel->want_format = format; - - sel_debug("request type: %s", (char *)sm_wl_convertion[i].translates[j]); - evas_object_event_callback_add(sel->request_obj, EVAS_CALLBACK_DEL, - _wl_selection_receive_timeout, sel); - sel->offer_handler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, - _wl_selection_receive, sel); - - ecore_wl2_offer_receive(offer, (char*)sm_wl_convertion[i].translates[j]); - ecore_wl2_display_flush(ecore_wl2_input_display_get(input)); - return EINA_TRUE; - } - } - - sel_debug("no type match"); - return EINA_FALSE; -} - -static void -_wl_sel_obj_del2(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static Sel_Manager_Dropable * -_wl_dropable_find(Efl_Ui_Selection_Manager_Data *pd, Ecore_Wl2_Window *win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!pd->drop_list) return NULL; - - if (!win) return NULL; - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - if (_wl_window_get(dropable->obj) == win) - return dropable; - - return NULL; -} - -static Evas * -_wl_evas_get_from_win(Efl_Ui_Selection_Manager_Data *pd, Ecore_Wl2_Window *win) -{ - Sel_Manager_Dropable *dropable = _wl_dropable_find(pd, win); - return dropable ? evas_object_evas_get(dropable->obj) : NULL; -} - -static Eina_Bool -_wl_drops_accept(Sel_Manager_Seat_Selection *seat_sel, const char *type) -{ - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Selection *sel; - Eina_List *l; - Sel_Manager_Dropable *drop; - Eina_Bool will_accept = EINA_FALSE; - - if (!type) return EINA_FALSE; - - pd = seat_sel->pd; - sel = seat_sel->sel; - EINA_LIST_FOREACH(pd->drop_list, l, drop) - { - Drop_Format *df; - EINA_INLIST_FOREACH(drop->format_list, df) - { - for (int i = 0; sm_wl_convertion[i].translates ; ++i) - { - if (!(sm_wl_convertion[i].format & df->format)) continue; - - for (int j = 0; sm_wl_convertion[i].translates[j]; ++j) - { - if (!strncmp(type, sm_wl_convertion[i].translates[j], strlen(sm_wl_convertion[i].translates[j]))) - { - sel->request_obj = drop->obj; - return EINA_TRUE; - } - } - } - } - } - - return will_accept; -} - -static void -_wl_selection_parser(void *_data, int size, char ***ret_data, int *ret_count) -{ - char **files = NULL; - int num_files = 0; - char *data = NULL; - - data = malloc(size); - if (data && (size > 0)) - { - int i, is; - char *tmp; - char **t2; - - memcpy(data, _data, size); - if (data[size - 1]) - { - char *t; - - /* Isn't nul terminated */ - size++; - t = realloc(data, size); - if (!t) goto done; - data = t; - data[size - 1] = 0; - } - - tmp = malloc(size); - if (!tmp) goto done; - i = 0; - is = 0; - while ((is < size) && (data[is])) - { - if ((i == 0) && (data[is] == '#')) - for (; ((data[is]) && (data[is] != '\n')); is++) ; - else - { - if ((data[is] != '\r') && (data[is] != '\n')) - tmp[i++] = data[is++]; - else - { - while ((data[is] == '\r') || (data[is] == '\n')) - is++; - tmp[i] = 0; - num_files++; - t2 = realloc(files, num_files * sizeof(char *)); - if (t2) - { - files = t2; - files[num_files - 1] = strdup(tmp); - } - else - { - num_files--; - goto freetmp; - } - tmp[0] = 0; - i = 0; - } - } - } - if (i > 0) - { - tmp[i] = 0; - num_files++; - t2 = realloc(files, num_files * sizeof(char *)); - if (t2) - { - files = t2; - files[num_files - 1] = strdup(tmp); - } - else - { - num_files--; - goto freetmp; - } - } -freetmp: - free(tmp); - } -done: - free(data); - if (ret_data) *ret_data = files; - else - { - int i; - - for (i = 0; i < num_files; i++) free(files[i]); - free(files); - } - if (ret_count) *ret_count = num_files; -} - -static Eina_Bool -_wl_data_preparer_markup(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_MARKUP; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_uri(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel; - char *p, *stripstr = NULL; - char *data = ev->data; - Sel_Manager_Dropable *drop; - const char *type = NULL; - - sel_debug("In\n"); - - seat_sel = sel->seat_sel; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) type = drop->last.type; - - if ((type) && (!strcmp(type, "text/uri-list"))) - { - int num_files = 0; - char **files = NULL; - Efreet_Uri *uri; - Eina_Strbuf *strbuf; - int i; - - strbuf = eina_strbuf_new(); - if (!strbuf) return EINA_FALSE; - - _wl_selection_parser(ev->data, ev->len, &files, &num_files); - sel_debug("got a files list\n"); - - for (i = 0; i < num_files; i++) - { - uri = efreet_uri_decode(files[i]); - if (uri) - { - eina_strbuf_append(strbuf, uri->path); - efreet_uri_free(uri); - } - else - { - eina_strbuf_append(strbuf, files[i]); - } - if (i < (num_files - 1)) - eina_strbuf_append(strbuf, "\n"); - free(files[i]); - } - free(files); - stripstr = eina_strbuf_string_steal(strbuf); - eina_strbuf_free(strbuf); - } - else - { - Efreet_Uri *uri; - - p = (char *)eina_memdup((unsigned char *)data, ev->len, EINA_TRUE); - if (!p) return EINA_FALSE; - uri = efreet_uri_decode(p); - if (!uri) - { - /* Is there any reason why we care of URI without scheme? */ - if (p[0] == '/') stripstr = p; - else free(p); - } - else - { - free(p); - stripstr = strdup(uri->path); - efreet_uri_free(uri); - } - } - - if (!stripstr) - { - sel_debug("Couldn't find a file\n"); - return EINA_FALSE; - } - free(seat_sel->saved_types->imgfile); - - ddata->content.mem = stripstr; - ddata->content.len = strlen(stripstr); - ddata->action = sel->action; - ddata->format = sel->request_format; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_vcard(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_VCARD; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_image(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info) -{ - sel_debug("In\n"); - Tmp_Info *tmp; - int len = 0; - - tmp = _tempfile_new(ev->len); - if (!tmp) - return EINA_FALSE; - memcpy(tmp->map, ev->data, ev->len); - munmap(tmp->map, ev->len); - - len = strlen(tmp->filename); - ddata->format = EFL_UI_SELECTION_FORMAT_IMAGE; - ddata->content.mem = eina_memdup((unsigned char*)tmp->filename, len, EINA_TRUE); - ddata->content.len = len; - ddata->action = sel->action; - *tmp_info = tmp; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_text(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - - -static void -_wl_dropable_handle(Sel_Manager_Seat_Selection *seat_sel, Sel_Manager_Dropable *dropable, Evas_Coord x, Evas_Coord y) -{ - Sel_Manager_Dropable *d, *last_dropable = NULL; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Sel_Manager_Selection *sel; - Eina_Inlist *itr; - Eina_List *l; - Eina_Position2D pos; - - EINA_LIST_FOREACH(pd->drop_list, l, d) - { - if (d->last.in) - { - last_dropable = d; - break; - } - } - - sel = seat_sel->sel; - pos = EINA_POSITION2D(x, y); - /* If we are on the same object, just update the position */ - if ((dropable) && (last_dropable == dropable)) - { - Evas_Coord ox, oy; - Efl_Dnd_Drag_Pos pos_data; - Drop_Format *df; - - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(x - ox, y - oy); - pos_data.item = NULL; - } - else - { - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &pos_data.pos); - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = sel->action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - - return; - } - /* We leave the last dropable */ - if (last_dropable) - { - Drop_Format *df; - sel_debug("leave %p\n", last_dropable->obj); - last_dropable->last.in = EINA_FALSE; - - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - /* We enter the new dropable */ - if (dropable) - { - sel_debug("enter %p\n", dropable->obj); - Evas_Coord ox, oy; - Efl_Dnd_Drag_Pos pos_data; - Drop_Format *df; - - dropable->last.in = EINA_TRUE; - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(x - ox, y - oy); - pos_data.item = NULL; - } - else - { - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &pos_data.pos); - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = sel->action; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - } -} - -static void -_wl_dropable_all_clean(Sel_Manager_Seat_Selection *seat_sel, Ecore_Wl2_Window *win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!win) return; - - EINA_LIST_FOREACH(seat_sel->pd->drop_list, l, dropable) - { - if (_wl_window_get(dropable->obj) == win) - { - dropable->last.pos.x = 0; - dropable->last.pos.y = 0; - dropable->last.in = EINA_FALSE; - } - } -} - -static void -_wl_dropable_data_handle(Sel_Manager_Selection *sel, Ecore_Wl2_Event_Offer_Data_Ready *ev) -{ - Sel_Manager_Seat_Selection *seat_sel; - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Dropable *drop; - Ecore_Wl2_Window *win; - - sel_debug("In\n"); - seat_sel = sel->seat_sel; - pd = seat_sel->pd; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) - { - Sel_Manager_Atom *atom = NULL; - - atom = eina_hash_find(pd->type_hash, drop->last.type); - if (atom && atom->wl_data_preparer) - { - Efl_Ui_Selection_Data ddata; - Tmp_Info *tmp_info = NULL; - Eina_Bool success; - - sel_debug("Call notify for: %s\n", atom->name); - success = atom->wl_data_preparer(sel, &ddata, ev, &tmp_info); - if (success) - { - Sel_Manager_Dropable *dropable; - Eina_List *l; - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->obj == sel->request_obj) break; - dropable = NULL; - } - if (dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - if (!dropable->is_container) - { - ddata.pos.x = seat_sel->saved_types->pos.x; - ddata.pos.y = seat_sel->saved_types->pos.y; - } - else - { - //for container - Efl_Object *it = NULL; - Evas_Coord x0 = 0, y0 = 0; - Eina_Position2D pos, posret = {}; - - evas_object_geometry_get(dropable->obj, &x0, &y0, NULL, NULL); - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + x0, - seat_sel->saved_types->pos.y + y0); - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - ddata.action = seat_sel->drag_action; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - } - } - win = _wl_window_get(sel->request_obj); - ecore_wl2_dnd_drag_end(_wl_seat_get(win, NULL, seat_sel->seat)); - if (tmp_info) _tmpinfo_free(tmp_info); - return; - } - } - - win = _wl_window_get(sel->request_obj); - ecore_wl2_dnd_drag_end(_wl_seat_get(win, NULL, seat_sel->seat)); - seat_sel->saved_types->textreq = 0; -} - -static Eina_Bool -_wl_dnd_enter(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Enter *ev; - Eina_Array *known, *available; - Sel_Manager_Seat_Selection *seat_sel = data; - unsigned int i = 0; - - ev = event; - - available = ecore_wl2_offer_mimes_get(ev->offer); - - free(seat_sel->saved_types->types); - - seat_sel->saved_types->ntypes = eina_array_count(available); - seat_sel->saved_types->types = malloc(sizeof(char *) * seat_sel->saved_types->ntypes); - if (!seat_sel->saved_types->types) return EINA_FALSE; - - known = eina_array_new(5); - - for (i = 0; i < eina_array_count(available); i++) - { - seat_sel->saved_types->types[i] = - eina_stringshare_add(eina_array_data_get(available, i)); - if (seat_sel->saved_types->types[i] == seat_sel->pd->text_uri) - { - seat_sel->saved_types->textreq = 1; - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - } - } - - seat_sel->accept = EINA_FALSE; - for (i = 0; i < eina_array_count(available); i++) - { - if (_wl_drops_accept(seat_sel, eina_array_data_get(available, i))) - { - eina_array_push(known, strdup(eina_array_data_get(available, i))); - } - } - - ecore_wl2_offer_mimes_set(ev->offer, known); - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_leave(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Leave *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Dropable *drop; - sel_debug("In\n"); - - ev = event; - if ((drop = _wl_dropable_find(seat_sel->pd, ev->win))) - { - _wl_dropable_handle(seat_sel, NULL, 0, 0); - _wl_dropable_all_clean(seat_sel, ev->win); - } - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_position(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Motion *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Sel_Manager_Dropable *drop; - Eina_Bool will_accept = EINA_FALSE; - - ev = event; - - sel_debug("mouse pos %i %i\n", ev->x, ev->y); - seat_sel->drag_win_end.x = ev->x - seat_sel->drag_pos.x; - seat_sel->drag_win_end.y = ev->y - seat_sel->drag_pos.y; - - drop = _wl_dropable_find(pd, ev->win); - - if (drop) - { - Eina_Position2D pos = EINA_POSITION2D(ev->x, ev->y); - Evas *evas = NULL; - Eina_List *dropable_list = NULL; - - _dropable_coords_adjust(drop, &pos); - evas = _wl_evas_get_from_win(pd, ev->win); - if (evas) - dropable_list = _dropable_list_geom_find(pd, evas, pos.x, pos.y); - - /* check if there is dropable (obj) can accept this drop */ - if (dropable_list) - { - Efl_Ui_Selection_Format saved_format; - Eina_List *l; - Eina_Bool found = EINA_FALSE; - Sel_Manager_Dropable *dropable = NULL; - - saved_format = - _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes); - - EINA_LIST_FOREACH(dropable_list, l, dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - Efl_Ui_Selection_Format common_fmt = saved_format & df->format; - - if (common_fmt) - { - /* We found a target that can accept this type of data */ - int i, min_index = SELECTION_N_ATOMS; - - /* We have to find the first atom that corresponds to one - * of the supported data types. */ - for (i = 0; i < seat_sel->saved_types->ntypes; i++) - { - Sel_Manager_Atom *atom; - - atom = eina_hash_find(pd->type_hash, - seat_sel->saved_types->types[i]); - - if (atom && (atom->format & common_fmt)) - { - int atom_idx = (atom - pd->atom_list); - - if (min_index > atom_idx) - min_index = atom_idx; - } - } - if (min_index != SELECTION_N_ATOMS) - { - sel_debug("Found atom %s\n", pd->atom_list[min_index].name); - found = EINA_TRUE; - dropable->last.type = pd->atom_list[min_index].name; - dropable->last.format = common_fmt; - break; - } - } - } - if (found) break; - } - if (found) - { - Sel_Manager_Selection *sel = seat_sel->sel; - Evas_Coord ox = 0, oy = 0; - - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - - sel_debug("Candidate %p (%s)\n", - dropable->obj, efl_class_name_get(efl_class_get(dropable->obj))); - _wl_dropable_handle(seat_sel, dropable, pos.x - ox, pos.y - oy); - sel->request_obj = dropable->obj; - will_accept = EINA_TRUE; - } - else - { - //if not: send false status - sel_debug("dnd position (%d, %d) not in obj\n", pos.x, pos.y); - _wl_dropable_handle(seat_sel, NULL, 0, 0); - // CCCCCCC: call dnd exit on last obj - } - eina_list_free(dropable_list); - } - } - - seat_sel->accept = will_accept; - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept); - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_receive(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Offer_Data_Ready *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Selection *sel; - Ecore_Wl2_Offer *offer; - sel_debug("In\n"); - - ev = event; - sel = seat_sel->sel; - offer = sel->dnd_offer; - - if (offer != ev->offer) return ECORE_CALLBACK_PASS_ON; - - if (sel->request_obj) - { - Ecore_Wl2_Drag_Action action; - - action = ecore_wl2_offer_action_get(ev->offer); - if (action == ECORE_WL2_DRAG_ACTION_ASK) - ecore_wl2_offer_actions_set(ev->offer, ECORE_WL2_DRAG_ACTION_COPY, ECORE_WL2_DRAG_ACTION_COPY); - action = ecore_wl2_offer_action_get(ev->offer); - sel->action = _wl_to_elm(action); - - _wl_dropable_data_handle(sel, ev); - evas_object_event_callback_del_full(sel->request_obj, - EVAS_CALLBACK_DEL, - _wl_sel_obj_del2, sel); - sel->request_obj = NULL; - } - - ecore_wl2_offer_finish(ev->offer); - - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_wl_dnd_drop(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Drop *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Selection *sel; - Sel_Manager_Dropable *drop; - Eina_List *l; - - sel_debug("In\n"); - ev = event; - seat_sel->saved_types->pos = EINA_POSITION2D(ev->x, ev->y); - pd = seat_sel->pd; - sel = seat_sel->sel; - sel->dnd_offer = ev->offer; - - EINA_LIST_FOREACH(pd->drop_list, l, drop) - { - if (drop->last.in) - { - sel_debug("Request data of type %s; drop: %p\n", drop->last.type, drop); - sel->request_obj = drop->obj; - sel->request_format = drop->last.format; - evas_object_event_callback_add(sel->request_obj, - EVAS_CALLBACK_DEL, _wl_sel_obj_del2, - sel); - ecore_wl2_offer_receive(ev->offer, (char*)drop->last.type); - ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, _wl_dnd_receive, seat_sel); - - return ECORE_CALLBACK_PASS_ON; - } - } - - ecore_wl2_dnd_drag_end(_wl_seat_get(ev->win, NULL, seat_sel->seat)); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_sel_manager_drop_target_add(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *target_obj, - Efl_Ui_Selection_Format format, unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Sel_Manager_Seat_Selection *seat_sel = NULL; - Drop_Format *df; - - df = calloc(1, sizeof(Drop_Format)); - if (!df) return EINA_FALSE; - df->format = format; - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (!dropable) - { - //Create new drop - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) - { - free(df); - return EINA_FALSE; - } - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) - { - free(dropable); - free(df); - return EINA_FALSE; - } - dropable->obj = target_obj; - efl_key_data_set(target_obj, "__elm_dropable", dropable); - } - - dropable->format_list = eina_inlist_append(dropable->format_list, EINA_INLIST_GET(df)); - dropable->seat = seat; - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - - evas_object_event_callback_add(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del, pd); - - if (!seat_sel->enter_handler) - { - seat_sel->enter_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_ENTER, - _wl_dnd_enter, seat_sel); - seat_sel->leave_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_LEAVE, - _wl_dnd_leave, seat_sel); - seat_sel->pos_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, - _wl_dnd_position, seat_sel); - seat_sel->drop_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, - _wl_dnd_drop, seat_sel); - } - - return EINA_TRUE; -} -#endif - -#ifdef HAVE_ELEMENTARY_COCOA -static Sel_Manager_Seat_Selection * -_cocoa_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } - - return seat_sel; -} - -static Ecore_Cocoa_Window * -_cocoa_window_get(const Evas_Object *obj) -{ - Ecore_Cocoa_Window *win = NULL; - Evas_Object *_win; - - _win = elm_win_get(obj); - if (_win) - { - win = elm_win_cocoa_window_get(_win); - } - - if (!win) - { - CRI("WIN has not been retrieved!!!"); - } - - return win; -} - -static Ecore_Cocoa_Cnp_Type -_sel_format_to_ecore_cocoa_cnp_type(Efl_Ui_Selection_Format fmt) -{ - Ecore_Cocoa_Cnp_Type type = 0; - - if ((fmt & EFL_UI_SELECTION_FORMAT_TEXT) || - (fmt & EFL_UI_SELECTION_FORMAT_VCARD)) - type |= ECORE_COCOA_CNP_TYPE_STRING; - if (fmt & EFL_UI_SELECTION_FORMAT_HTML) - type |= ECORE_COCOA_CNP_TYPE_HTML; - if (fmt & EFL_UI_SELECTION_FORMAT_IMAGE) - type |= ECORE_COCOA_CNP_TYPE_IMAGE; - - return type; -} - -static void -_cocoa_sel_obj_del_req_cb(void *data, - Evas *e EINA_UNUSED, - Evas_Object *obj, - void *ev_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static void -_cocoa_sel_obj_del_cb(void *data, - Evas *e EINA_UNUSED, - Evas_Object *obj, - void *ev_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) - { - sel->owner = NULL; - } - //if (dragwidget == obj) dragwidget = NULL; -} - -static void -_job_pb_cb(void *data) -{ - Sel_Manager_Selection *sel = data; - Efl_Ui_Selection_Data ddata; - Ecore_Cocoa_Cnp_Type type, get_type; - void *pbdata; - int pbdata_len; - - if (sel->data_func) - { - ddata.pos.x = 0; - ddata.pos.y = 0; - - /* Pass to cocoa clipboard */ - type = _sel_format_to_ecore_cocoa_cnp_type(sel->request_format); - pbdata = ecore_cocoa_clipboard_get(&pbdata_len, type, &get_type); - - ddata.format = EFL_UI_SELECTION_FORMAT_NONE; - if (get_type & ECORE_COCOA_CNP_TYPE_STRING) - ddata.format |= EFL_UI_SELECTION_FORMAT_TEXT; - if (get_type & ECORE_COCOA_CNP_TYPE_IMAGE) - ddata.format |= EFL_UI_SELECTION_FORMAT_IMAGE; - if (get_type & ECORE_COCOA_CNP_TYPE_HTML) - ddata.format |= EFL_UI_SELECTION_FORMAT_HTML; - - ddata.content.mem = pbdata; - ddata.content.len = pbdata_len; - ddata.action = EFL_UI_SELECTION_ACTION_UNKNOWN; - sel->data_func(sel->data_func_data, sel->request_obj, &ddata); - free(pbdata); - } -} - -static Eina_Future * -_cocoa_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Cocoa_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Cocoa_Cnp_Type ecore_type; - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - seat_sel = _cocoa_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - if (data.len <= 0) return NULL; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - - sel->owner = owner; - sel->win = win; - sel->format = format; - - evas_object_event_callback_add(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - ELM_SAFE_FREE(sel->data.mem, free); - - if (format == EFL_UI_SELECTION_FORMAT_MARKUP) - { - //FIXME this code assumes that sel->data.mem has a \0 at the end - sel->data.mem = evas_textblock_text_markup_to_utf8(NULL, data.mem); - sel->data.len = strlen(sel->data.mem); - //set the new text - format = EFL_UI_SELECTION_FORMAT_TEXT; - } - else - { - sel->data = eina_slice_dup(data); - } - - if (sel->data.mem) - { - ecore_type = _sel_format_to_ecore_cocoa_cnp_type(format); - ecore_cocoa_clipboard_set(sel->data.mem, sel->data.len, ecore_type); - } - else - { - CRI("Failed to allocate memory!"); - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_cocoa_efl_sel_manager_selection_get(const Efl_Object *request, - Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type EINA_UNUSED, - Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_Cocoa_Window *win, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel; - sel->request_format = format; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); - - sel->win = win; - ecore_job_add(_job_pb_cb, sel); - - evas_object_event_callback_add(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); -} - -#endif - -// win32 specific stuff -//////////////////////////////////////////////////////////////////////////// -#ifdef HAVE_ELEMENTARY_WIN32 -static Sel_Manager_Seat_Selection * -_win32_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } - - return seat_sel; -} - -static char * -_win32_text_n_to_rn(char *intext) -{ - size_t size = 0, newlines = 0; - char *outtext = NULL, *p, *o; - - if (!intext) return NULL; - for (p = intext; *p; p++) - { - if (*p == '\n') newlines++; - size++; - } - outtext = malloc(size + newlines + 1); - if (!outtext) return intext; - for (p = intext, o = outtext; *p; p++, o++) - { - if (*p == '\n') - { - o++; - *p = '\r'; - } - *o = *p; - } - *o = '\0'; - free(intext); - return outtext; -} - -static void -_win32_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) sel->owner = NULL; -} - -static void -_win32_sel_obj_del2(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static Ecore_Win32_Window * -_win32_window_get(const Evas_Object *obj) -{ - Evas_Object *top; - Ecore_Win32_Window *win = NULL; - - if (elm_widget_is(obj)) - { - top = elm_widget_top_get(obj); - if (!top) - { - Evas_Object *par; - par = elm_widget_parent_widget_get(obj); - if (par) top = elm_widget_top_get(par); - } - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - win = elm_win_win32_window_get(top); - } - - if (!win) - { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; - - evas = evas_object_evas_get(obj); - if (!evas) return NULL; - - ee = ecore_evas_ecore_evas_get(evas); - if (!ee) return NULL; - - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - win = ecore_evas_win32_window_get(ee); - } - else - { - if ((strcmp(engine_name, ELM_SOFTWARE_WIN32) == 0) || - (strcmp(engine_name, ELM_SOFTWARE_DDRAW) == 0)) - return ecore_evas_win32_window_get(ee); - } - } - - return win; -} - -static Eina_Future * -_win32_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Win32_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return NULL; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - - seat_sel = _win32_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel_list + type; - if (sel->owner != owner) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - - } - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _win32_sel_obj_del, sel); - sel->active = EINA_TRUE; - sel->owner = owner; - sel->win = win; - if (sel->set) sel->set(win, sel->data.mem, sel->data.len); - sel->format = format; - - evas_object_event_callback_add - (sel->owner, EVAS_CALLBACK_DEL, _win32_sel_obj_del, sel); - - ELM_SAFE_FREE(sel->data.mem, free); - sel->data = eina_slice_dup(data); - if (!sel->data.mem) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_win32_efl_sel_manager_selection_clear(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Sel_Manager_Seat_Selection *seat_sel) -{ - Sel_Manager_Selection *sel; - Ecore_Win32_Window *win; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return; - - sel = seat_sel->sel_list + type; - - /* No longer this selection: Consider it gone! */ - if ((!sel->active) || (sel->owner != owner)) - return; - - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _win32_sel_obj_del, sel); - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _win32_sel_obj_del2, sel); - sel->owner = NULL; - sel->request_obj = NULL; - sel->active = EINA_FALSE; - ELM_SAFE_FREE(sel->data.mem, free); - /* sel->clear(win); */ -} - -static Eina_Bool -_win32_efl_sel_manager_selection_get(const Efl_Object *request, - Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, - Eina_Free_Cb data_func_free_cb, - Ecore_Win32_Window *win, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - void *data; - int size; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return EINA_FALSE; - - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel_list + type; - - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _win32_sel_obj_del2, sel); - sel->request_format = format; - sel->request_obj = (Evas_Object *)request; - sel->win = win; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - sel->get(win, &data, &size); - - if (!data || (size <= 0)) - goto cb_add; - - if ((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *str; - - str = (char *)malloc(size + 1); - if (str) - { - memcpy(str, data, size); - str[size] = '\0'; - data = _win32_text_n_to_rn(_elm_util_mkup_to_text(str)); - free(str); - if (data) - size = strlen(data); - else - size = 0; - } - else - { - free(data); - data = NULL; - } - } - - if (sel->data_func && data && (size > 0)) - { - Efl_Ui_Selection_Data sdata; - - sdata.pos.x = sdata.pos.y = 0; - sdata.format = EFL_UI_SELECTION_FORMAT_TEXT; - sdata.content.mem = data; - sdata.content.len = size; - sdata.action = sel->action; - sel->data_func(sel->data_func_data, sel->request_obj, &sdata); - } - - if (data) - free(data); - - cb_add: - evas_object_event_callback_add - (sel->request_obj, EVAS_CALLBACK_DEL, _win32_sel_obj_del2, sel); - - return EINA_TRUE; -} - -#endif /* HAVE_ELEMENTARY_WIN32 */ - - -static int -_drop_item_container_cmp(const void *d1, const void *d2) -{ - const Item_Container_Drop_Info *di = d1; - return (((uintptr_t)di->obj) - ((uintptr_t)d2)); -} - -static Eina_Bool -_drop_item_container_del(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *cont, Eina_Bool full) -{ - Item_Container_Drop_Info *di; - - di = eina_list_search_unsorted(pd->drop_cont_list, - _drop_item_container_cmp, cont); - if (di) - { - _all_drop_targets_cbs_del(pd, NULL, cont, NULL); - di->item_func_data = NULL; - di->item_func = NULL; - - if (full) - { - pd->drop_cont_list = eina_list_remove(pd->drop_cont_list, di); - free(di); - } - return EINA_TRUE; - } - - return EINA_FALSE; -} - -static inline Eina_List * -_anim_icons_make(Sel_Manager_Drag_Container *dc) -{ - Eina_List *list = NULL, *icon_list = NULL; - Evas_Object *obj; - - if (dc->icon_list_func) - { - DBG("calling icon_list_func"); - icon_list = dc->icon_list_func(dc->icon_list_func_data, dc->cont); - } - EINA_LIST_FREE(icon_list, obj) - { - DBG("one obj in icon_list"); - Anim_Icon *ai = calloc(1, sizeof(Anim_Icon)); - if (!ai) - { - ERR("Failed to allocate for icon!"); - continue; - } - - evas_object_geometry_get(obj, &ai->start.x, &ai->start.y, &ai->start.w, &ai->start.h); - evas_object_show(obj); - ai->obj = obj; - list = eina_list_append(list, ai); - } - DBG("made icon list"); - - return list; -} - -static void -_cont_obj_drag_done_cb(void *data, const Efl_Event *ev EINA_UNUSED) -{ - Sel_Manager_Drag_Container *dc = data; - elm_widget_scroll_freeze_pop(dc->cont); -} - -static Eina_Bool -_cont_obj_drag_start(void *data) -{ - DBG("going to start draging"); - Sel_Manager_Drag_Container *dc = data; - - dc->timer = NULL; - efl_event_callback_add(dc->cont, EFL_UI_DND_EVENT_DRAG_DONE, _cont_obj_drag_done_cb, dc); - elm_widget_scroll_freeze_push(dc->cont); - efl_ui_selection_manager_drag_start(dc->pd->sel_man, dc->cont, dc->format, - eina_rw_slice_slice_get(dc->data), dc->action, - dc->icon_func_data, dc->icon_func, dc->icon_func_free_cb, - dc->seat); - - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_drag_anim_play(void *data, double pos) -{ - Sel_Manager_Drag_Container *dc = data; - - if (dc->animator) - { - Eina_List *l; - Anim_Icon *ai; - Evas_Coord xm, ym; - - if (pos > 0.99) - { - dc->animator = NULL; - EINA_LIST_FOREACH(dc->icons, l, ai) - evas_object_hide(ai->obj); - - _cont_obj_drag_start(dc); - return ECORE_CALLBACK_CANCEL; - } - - evas_pointer_canvas_xy_get(dc->e, &xm, &ym); - EINA_LIST_FOREACH(dc->icons, l, ai) - { - int x, y, w, h; - w = ai->start.w - ((dc->final_icon.w - ai->start.w) * pos); - h = ai->start.h - ((dc->final_icon.h - ai->start.h) * pos); - x = ai->start.x - (pos * (ai->start.x + (w / 2) - xm)); - y = ai->start.y - (pos * (ai->start.y + (h / 2) - ym)); - evas_object_geometry_set(ai->obj, x, y, w, h); - } - - return ECORE_CALLBACK_RENEW; - } - - return ECORE_CALLBACK_CANCEL; -} - -static inline void -_drag_anim_start(Sel_Manager_Drag_Container *dc) -{ - - dc->timer = NULL; - if (dc->icon_func) - { - Eina_Position2D pos_ret; - Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_DND); - Evas_Object *final_icon = dc->icon_func(dc->icon_func_data, temp_win, dc->cont, &pos_ret); - evas_object_geometry_get(final_icon, NULL, NULL, &dc->final_icon.w, &dc->final_icon.h); - evas_object_del(final_icon); - evas_object_del(temp_win); - } - dc->animator = ecore_evas_animator_timeline_add(dc->e, dc->anim_duration, _drag_anim_play, dc); -} - -static Eina_Bool -_cont_obj_anim_start(void *data) -{ - sel_debug("In"); - Sel_Manager_Drag_Container *dc = data; - Efl_Object *it = NULL; - Eina_Position2D posret; //does not use - - if (dc->item_get_func) - it = dc->item_get_func(dc->item_get_func_data, dc->cont, dc->down, &posret); - dc->timer = NULL; - dc->format = EFL_UI_SELECTION_FORMAT_TARGETS; //default - dc->data.len = 0; - dc->action = EFL_UI_SELECTION_ACTION_COPY; //default - dc->icons = NULL; - - //failed to get mouse-down item, abort drag - if (!it) - return ECORE_CALLBACK_CANCEL; - - if (dc->drag_data_func) - { - dc->drag_data_func(dc->drag_data_func_data, dc->cont, - &dc->format, &dc->data, &dc->action); - if (EINA_DBL_EQ(dc->anim_duration, 0.0)) - { - _cont_obj_drag_start(dc); - } - else - { - dc->icons = _anim_icons_make(dc); - if (dc->icons) - { - _drag_anim_start(dc); - } - else - { - // even if we don't manage the icons animation, we have - // to wait until it is finished before beginning drag. - dc->timer = ecore_timer_add(dc->anim_duration, - _cont_obj_drag_start, dc); - } - } - } - - return ECORE_CALLBACK_CANCEL; -} - -static void -_abort_drag(Evas_Object *obj EINA_UNUSED, Sel_Manager_Drag_Container *dc) -{ - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - _item_container_del_internal(dc, EINA_FALSE); - - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - _anim_data_free(dc); -} - -static void -_cont_obj_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - Evas_Event_Mouse_Move *ev = event_info; - - if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) - { - _abort_drag(obj, dc); - } - if (dc && - (evas_device_class_get(ev->dev) == EVAS_DEVICE_CLASS_TOUCH)) - { - int dx, dy; - int fs = elm_config_finger_size_get(); - - dx = ev->cur.canvas.x - dc->down.x; - dy = ev->cur.canvas.y - dc->down.y; - if ((dx * dx + dy * dy) > (fs * fs)) - { - sel_debug("mouse moved too much - have to cancel DnD"); - _abort_drag(obj, dc); - } - } -} - -static void -_anim_data_free(Sel_Manager_Drag_Container *dc) -{ - if (dc) - { - ELM_SAFE_FREE(dc->animator, ecore_animator_del); - Anim_Icon *ai; - - EINA_LIST_FREE(dc->icons, ai) - { - evas_object_del(ai->obj); - free(ai); - } - dc->icons = NULL; - } -} - -static void -_cont_obj_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - - if (((Evas_Event_Mouse_Up *)event_info)->button != 1) - return; - - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - - _anim_data_free(dc); -} - -static void -_cont_obj_mouse_down_cb(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - Evas_Event_Mouse_Down *ev = event_info; - if (ev->button != 1) - return; - - dc->e = e; - dc->down.x = ev->canvas.x; - dc->down.y = ev->canvas.y; - - evas_object_event_callback_add(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - ecore_timer_del(dc->timer); - if (dc->time_to_drag) - { - dc->timer = ecore_timer_add(dc->time_to_drag, _cont_obj_anim_start, dc); - evas_object_event_callback_add(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - } - else - { - _cont_obj_anim_start(dc); - } -} - -static void -_item_container_del_internal(Sel_Manager_Drag_Container *dc, Eina_Bool full) -{ - if (dc) - { - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - if (dc->animator) - _anim_data_free(dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_DOWN, - _cont_obj_mouse_down_cb, dc); - if (full) - { - dc->item_get_func = NULL; - dc->item_get_func_data = NULL; - free(dc); - } - } -} - -static int -_drag_item_container_cmp(const void *d1, const void *d2) -{ - const Sel_Manager_Drag_Container *dc = d1; - return (((uintptr_t)dc->cont) - ((uintptr_t)d2)); -} -//exposed APIs -EOLIAN static Eina_Future * -_efl_ui_selection_manager_selection_set(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, unsigned int seat) -{ - Eina_Future *p = NULL; - - sel_debug("owner: %p, seat: %d, type: %d, format: %d", owner, seat, type, format); - if (type > EFL_UI_SELECTION_TYPE_CLIPBOARD) - { - ERR("Not supported format: %d", type); - return NULL; - } - -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(owner); - if (xwin) - p = _x11_efl_sel_manager_selection_set(pd, owner, type, format, data, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(owner); - if (win) - p = _wl_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(owner); - if (win) - p = _cocoa_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(owner); - if (win) - p = _win32_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif - - return p; -} - -//TODO: add support for local -EOLIAN static void -_efl_ui_selection_manager_selection_get(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - const Efl_Object *request, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, - Eina_Free_Cb data_func_free_cb, unsigned int seat) -{ - sel_debug("request: %p, seat: %d, type: %d, format: %d", request, seat, type, format); -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(request); - if (xwin) - _x11_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(request); - if (win) - _wl_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(request); - if (win) - _cocoa_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(request); - if (win) - _win32_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -} - -EOLIAN static void -_efl_ui_selection_manager_selection_clear(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel = NULL; - - sel_debug("owner: %p, seat: %d, type: %d", owner, seat, type); - seat_sel = _sel_manager_seat_selection_init(pd, seat); -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(obj); - if (xwin) - { - sel = seat_sel->sel_list + type; - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(obj); - if (win) - { - sel = seat_sel->sel; - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(obj); - if (win) - { - sel = seat_sel->sel; - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(obj); - { - sel = seat_sel->sel_list + type; - } -#endif - if (!sel) return; - if ((!sel->active) && (sel->owner != owner)) - { - return; - } - sel->active = EINA_FALSE; -#ifdef HAVE_ELEMENTARY_X - if (xwin) - { - seat_sel->sel_list[type].data.len = 0; - if (seat_sel->sel_list[type].data.mem) - { - free(seat_sel->sel_list[type].data.mem); - seat_sel->sel_list[type].data.mem = NULL; - } - if (!sel->xwin) seat_sel->sel_list[type].clear(); - else - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - seat_sel->sel_list[type].owner = NULL; - } - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - if (win) - { - sel->selection_serial = ecore_wl2_dnd_selection_clear(_wl_seat_get(_wl_window_get(owner), owner, seat)); - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - if (win) - { - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); - sel->owner = NULL; - sel->request_obj = NULL; - ELM_SAFE_FREE(sel->data.mem, free); - sel->data.len = 0; - - ecore_cocoa_clipboard_clear(); - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - if (win) - { - _win32_efl_sel_manager_selection_clear(pd, owner, type, seat_sel); - } -#endif -} - -EOLIAN static Eina_Bool -_efl_ui_selection_manager_selection_has_owner(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd EINA_UNUSED, - Efl_Object *request, Efl_Ui_Selection_Type type, - unsigned int seat) -{ -#ifdef HAVE_ELEMENTARY_X - (void)seat; - if (_x11_xwin_get(request)) - { - Ecore_X_Atom xtype; - switch (type) - { - case EFL_UI_SELECTION_TYPE_PRIMARY: - xtype = ECORE_X_ATOM_SELECTION_PRIMARY; - break; - case EFL_UI_SELECTION_TYPE_SECONDARY: - xtype = ECORE_X_ATOM_SELECTION_SECONDARY; - break; - case EFL_UI_SELECTION_TYPE_DND: - xtype = ECORE_X_ATOM_SELECTION_XDND; - break; - default: - xtype = ECORE_X_ATOM_SELECTION_CLIPBOARD; - } - return !!ecore_x_selection_owner_get(xtype); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win; - - win = _wl_window_get(request); - if (win) - return !!ecore_wl2_dnd_selection_get(_wl_seat_get(win, request, seat)); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - // FIXME: need to check if there is clipboard data. Paste always enabled. - return EINA_TRUE; -#endif - return EINA_FALSE; -} - -EOLIAN static void -_efl_ui_selection_manager_drag_start(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Format format, - Eina_Slice data, Efl_Ui_Selection_Action action, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, - Eina_Free_Cb icon_func_free_cb, unsigned int seat) -{ -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - _x11_efl_sel_manager_drag_start(obj, pd, drag_obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(drag_obj); - if (win) - _wl_efl_sel_manager_drag_start(obj, pd, drag_obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 -#endif -#ifdef HAVE_ELEMENTARY_COCOA -#endif -} - -EOLIAN static void -_efl_ui_selection_manager_drag_cancel(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = _sel_manager_seat_selection_init(pd, seat); - -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - { - ecore_x_pointer_ungrab(); - ELM_SAFE_FREE(seat_sel->mouse_up_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->dnd_status_handler, ecore_event_handler_del); - ecore_x_dnd_abort(xwin); - if (seat_sel->drag_obj) - { - if (elm_widget_is(seat_sel->drag_obj)) - { - Evas_Object *win = elm_widget_top_get(seat_sel->drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - efl_event_callback_del(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - seat_sel->drag_obj = NULL; - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win; - - win = _wl_window_get(drag_obj); - if (win) - ecore_wl2_dnd_drag_end(_wl_seat_get(win, drag_obj, seat)); -#endif - - ELM_SAFE_FREE(seat_sel->drag_win, evas_object_del); -} - -EOLIAN static void -_efl_ui_selection_manager_drag_action_set(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Action action, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = _sel_manager_seat_selection_init(pd, seat); - if (seat_sel->drag_action == action) return; - seat_sel->drag_action = action; -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Atom actx; - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - { - actx = _x11_dnd_action_rev_map(action); - ecore_x_dnd_source_action_set(actx); - } -#endif -} - -//drop side -EOLIAN static Eina_Bool -_efl_ui_selection_manager_drop_target_add(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *target_obj, Efl_Ui_Selection_Format format, - unsigned int seat) -{ - Eina_Bool ret = EINA_FALSE; -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(target_obj); - if (xwin) - ret = _x11_sel_manager_drop_target_add(pd, target_obj, format, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(target_obj); - if (win) - ret = _wl_sel_manager_drop_target_add(pd, target_obj, format, seat); -#endif - return ret; -} - -EOLIAN static void -_efl_ui_selection_manager_drop_target_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *target_obj, Efl_Ui_Selection_Format format, - unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Sel_Manager_Seat_Selection *seat_sel; - Eina_Bool remove_handler = EINA_FALSE; - - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (dropable) - { - Eina_Inlist *itr; - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format == format) - { - dropable->format_list = eina_inlist_remove(dropable->format_list, - EINA_INLIST_GET(df)); - free(df); - } - } - if (!dropable->format_list) - { - pd->drop_list = eina_list_remove(pd->drop_list, dropable); - efl_key_data_set(target_obj, "__elm_dropable", NULL); - free(dropable); - evas_object_event_callback_del(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del); - } - } - -#ifdef HAVE_ELEMENTARY_X - if (pd->drop_list) - { - Eina_List *l; - Ecore_X_Window xwin; - Eina_Bool have_drop_list = EINA_FALSE; - - xwin = _x11_xwin_get(target_obj); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - if (!have_drop_list) - { - ecore_x_dnd_aware_set(xwin, EINA_FALSE); - remove_handler = EINA_TRUE; - } - } - else remove_handler = EINA_TRUE; -#endif - if (remove_handler) - { - seat_sel = _sel_manager_seat_selection_init(pd, seat); - ELM_SAFE_FREE(seat_sel->pos_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->drop_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->enter_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->leave_handler, ecore_event_handler_del); - } -} - -EOLIAN static void -_efl_ui_selection_manager_container_drop_item_add(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, Efl_Ui_Selection_Format format, - void *item_func_data, Efl_Dnd_Item_Get item_func, - Eina_Free_Cb item_func_free_cb EINA_UNUSED, - unsigned int seat) -{ - Item_Container_Drop_Info *di; - Sel_Manager_Dropable *dropable = NULL; - - if (_drop_item_container_del(pd, cont, EINA_FALSE)) - { - di = eina_list_search_unsorted(pd->drop_cont_list, _drop_item_container_cmp, obj); - if (!di) return; - } - else - { - di = calloc(1, sizeof(Item_Container_Drop_Info)); - if (!di) return; - - di->obj = obj; - pd->drop_cont_list = eina_list_append(pd->drop_cont_list, di); - } - di->item_func = item_func; - di->item_func_data = item_func_data; - - dropable = efl_key_data_get(cont, "__elm_dropable"); - if (!dropable) - { - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) return; - dropable->last.in = EINA_FALSE; - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) return; - dropable->obj = cont; - efl_key_data_set(cont, "__elm_dropable", dropable); - } - dropable->is_container = EINA_TRUE; - dropable->item_func = item_func; - dropable->item_func_data = item_func_data; - _efl_ui_selection_manager_drop_target_add(obj, pd, cont, format, seat); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drop_item_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, unsigned int seat EINA_UNUSED) -{ - _drop_item_container_del(pd, cont, EINA_TRUE); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drag_item_add(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, double time_to_drag, double anim_duration, - void *data_func_data, Efl_Dnd_Drag_Data_Get data_func, Eina_Free_Cb data_func_free_cb, - void *item_get_func_data, Efl_Dnd_Item_Get item_get_func, Eina_Free_Cb item_get_func_free_cb, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - void *icon_list_func_data, Efl_Dnd_Drag_Icon_List_Create icon_list_func, Eina_Free_Cb icon_list_func_free_cb, - unsigned int seat) -{ - //TODO: remove previous drag one - Sel_Manager_Drag_Container *dc = calloc(1, sizeof(Sel_Manager_Drag_Container)); - if (!dc) - { - ERR("Failed to allocate memory"); - return; - } - dc->cont = cont; - dc->time_to_drag = time_to_drag; - dc->anim_duration = anim_duration; - dc->drag_data_func_data = data_func_data; - dc->drag_data_func = data_func; - dc->drag_data_func_free_cb = data_func_free_cb; - dc->item_get_func_data = item_get_func_data; - dc->item_get_func = item_get_func; - dc->item_get_func_free_cb = item_get_func_free_cb; - dc->icon_func_data = icon_func_data; - dc->icon_func = icon_func; - dc->icon_func_free_cb = icon_func_free_cb; - dc->icon_list_func_data = icon_list_func_data; - dc->icon_list_func = icon_list_func; - dc->icon_list_func_free_cb = icon_list_func_free_cb; - dc->seat = seat; - dc->pd = pd; - - _sel_manager_seat_selection_init(pd, seat); - - pd->drag_cont_list = eina_list_append(pd->drag_cont_list, dc); - - evas_object_event_callback_add(cont, EVAS_CALLBACK_MOUSE_DOWN, - _cont_obj_mouse_down_cb, dc); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drag_item_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, unsigned int seat EINA_UNUSED) -{ - Sel_Manager_Drag_Container *dc = eina_list_search_unsorted(pd->drag_cont_list, - _drag_item_container_cmp, cont); - if (dc) - _item_container_del_internal(dc, EINA_TRUE); -} - -static Eo * -_efl_ui_selection_manager_efl_object_constructor(Eo *obj, Efl_Ui_Selection_Manager_Data *pd) -{ -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WL2) - const char *ev = getenv("ELM_DISPLAY"); -#endif - -#ifdef HAVE_ELEMENTARY_X - Eina_Bool init_x = EINA_FALSE; - Eina_Bool have_display = !!getenv("DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "x11")) /* and it is X11 */ - { - if (!have_display) /* if there is no $DISPLAY */ - { - ERR("$ELM_DISPLAY is set to x11 but $DISPLAY is not set"); - init_x = EINA_FALSE; - } - else /* if there is */ - init_x = EINA_TRUE; - } - else /* not X11 */ - init_x = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - if (have_display) /* If there is a $DISPLAY */ - init_x = EINA_TRUE; - else /* No $DISPLAY */ - init_x = EINA_FALSE; - } - if (init_x) - { - if (!ecore_x_init(NULL)) - { - ERR("Could not initialize Ecore_X"); - return NULL; - } - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Eina_Bool init_wl = EINA_FALSE; - Eina_Bool have_wl_display = !!getenv("WAYLAND_DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "wl")) /* and it is WL */ - { - /* always try to connect to wl when it is enforced */ - init_wl = EINA_TRUE; - } - else /* not wl */ - init_wl = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - /* If there is a $WAYLAND_DISPLAY */ - if ((have_wl_display) && (!getenv("DISPLAY"))) - init_wl = EINA_TRUE; - else /* No $WAYLAND_DISPLAY */ - init_wl = EINA_FALSE; - } - if (init_wl) - { - if (!ecore_wl2_init()) - { - ERR("Could not initialize Ecore_Wl2"); - return NULL; - } - _elm_wl_display = ecore_wl2_display_connect(NULL); - if (!_elm_wl_display) - { - ERR("Could not connect to Wayland Display"); - ecore_wl2_shutdown(); - return NULL; - } - } -#endif - - obj = efl_constructor(efl_super(obj, MY_CLASS)); - - pd->sel_man = obj; - pd->atom_list = calloc(1, SELECTION_N_ATOMS * sizeof(Sel_Manager_Atom)); - if (!pd->atom_list) - { - ERR("failed to allocate atom_list"); - return NULL; - } - pd->atom_list[SELECTION_ATOM_TARGETS].name = "TARGETS"; - pd->atom_list[SELECTION_ATOM_TARGETS].format = EFL_UI_SELECTION_FORMAT_TARGETS; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TARGETS].x_converter = _x11_targets_converter; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TARGETS].wl_converter = _wl_targets_converter; -#endif - pd->atom_list[SELECTION_ATOM_ATOM].name = "ATOM"; // for opera browser - pd->atom_list[SELECTION_ATOM_ATOM].format = EFL_UI_SELECTION_FORMAT_TARGETS; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_ATOM].x_converter = _x11_targets_converter; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_ATOM].wl_converter = _wl_targets_converter; -#endif - - pd->atom_list[SELECTION_ATOM_ELM].name = "application/x-elementary-markup"; - pd->atom_list[SELECTION_ATOM_ELM].format = EFL_UI_SELECTION_FORMAT_MARKUP; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_ELM].x_converter = _x11_general_converter; - pd->atom_list[SELECTION_ATOM_ELM].x_data_preparer = _x11_data_preparer_markup; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_ELM].wl_converter = _wl_general_converter; - pd->atom_list[SELECTION_ATOM_ELM].wl_data_preparer = _wl_data_preparer_markup; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].name = "text/uri-list"; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].x_converter = _x11_general_converter; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].x_data_preparer = _x11_data_preparer_uri; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].wl_converter = _wl_general_converter; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].wl_data_preparer = _wl_data_preparer_uri; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].name = "text/x-vcard"; - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].format = EFL_UI_SELECTION_FORMAT_VCARD; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].x_converter = _x11_vcard_send; - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].x_data_preparer = _x11_data_preparer_vcard; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].wl_data_preparer = _wl_data_preparer_vcard; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].name = "image/png"; - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].name = "image/jpeg"; - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].name = "image/x-ms-bmp"; - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].name = "image/gif"; - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].name = "image/tiff"; - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].name = "image/svg+xml"; - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].name = "image/x-xpixmap"; - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].name = "image/x-tga"; - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].name = "image/x-portable-pixmap"; - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_UTF8STRING].name = "UTF8_STRING"; - pd->atom_list[SELECTION_ATOM_UTF8STRING].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_UTF8STRING].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_UTF8STRING].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_UTF8STRING].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_UTF8STRING].wl_data_preparer = _wl_data_preparer_text, -#endif - - pd->atom_list[SELECTION_ATOM_STRING].name = "STRING"; - pd->atom_list[SELECTION_ATOM_STRING].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_STRING].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_STRING].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_STRING].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_STRING].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].name = "COMPOUND_TEXT"; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT].name = "TEXT"; - pd->atom_list[SELECTION_ATOM_TEXT].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].name = "text/plain;charset=utf-8"; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].name = "text/plain"; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].wl_data_preparer = _wl_data_preparer_text; -#endif - - - int i; -#ifdef HAVE_ELEMENTARY_X - if (ecore_x_display_get()) - { - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - pd->atom_list[i].x_atom = ecore_x_atom_get(pd->atom_list[i].name); - ecore_x_selection_converter_atom_add - (pd->atom_list[i].x_atom, pd->atom_list[i].x_converter); - } - pd->notify_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, - _efl_sel_manager_x11_selection_notify, pd); - pd->clear_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, - _x11_selection_clear, pd); - if (ECORE_X_EVENT_FIXES_SELECTION_NOTIFY) // If XFIXES is not available ECORE_X_EVENT_FIXES_SELECTION_NOTIFY would be NULL - pd->fix_handler = ecore_event_handler_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, - _x11_fixes_selection_notify, pd); - } -#endif - - pd->type_hash = eina_hash_string_small_new(NULL); - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - eina_hash_add(pd->type_hash, pd->atom_list[i].name, &pd->atom_list[i]); - } - pd->text_uri = eina_stringshare_add("text/uri-list"); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_elm_wl_display) - { - pd->send_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, - _wl_selection_send, pd); - pd->changed_handler = ecore_event_handler_add(ECORE_WL2_EVENT_SEAT_SELECTION, - _wl_selection_changed, pd); - pd->end_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_END, - _wl_dnd_end, pd); - } -#endif - managers = eina_list_append(managers, obj); - return obj; -} - -static void -_efl_ui_selection_manager_efl_object_destructor(Eo *obj, Efl_Ui_Selection_Manager_Data *pd) -{ - Sel_Manager_Seat_Selection *seat_sel; - Eina_List *l; - Sel_Manager_Dropable *dropable; - - managers = eina_list_remove(managers, obj); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - _drop_target_cbs_del(pd, dropable, dropable->obj); - } -#ifdef HAVE_ELEMENTARY_X - ecore_event_handler_del(pd->notify_handler); - ecore_event_handler_del(pd->clear_handler); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - ecore_event_handler_del(pd->send_handler); - ecore_event_handler_del(pd->changed_handler); - ecore_event_handler_del(pd->end_handler); -#endif - free(pd->atom_list); - EINA_LIST_FREE(pd->seat_list, seat_sel) - { - ecore_event_handler_del(seat_sel->pos_handler); - ecore_event_handler_del(seat_sel->drop_handler); - ecore_event_handler_del(seat_sel->enter_handler); - ecore_event_handler_del(seat_sel->leave_handler); -#ifdef HAVE_ELEMENTARY_X - free(seat_sel->sel_list); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - free(seat_sel->sel); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - free(seat_sel->sel); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - free(seat_sel->sel_list); -#endif - free(seat_sel->saved_types->types); - free(seat_sel->saved_types->imgfile); - free(seat_sel->saved_types); - } - eina_hash_free(pd->type_hash); - eina_stringshare_del(pd->text_uri); - - efl_destructor(efl_super(obj, MY_CLASS)); -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WL2) || defined(HAVE_ELEMENTARY_WIN32) - const char *ev = getenv("ELM_DISPLAY"); -#endif - -#ifdef HAVE_ELEMENTARY_X - Eina_Bool init_x = EINA_FALSE; - Eina_Bool have_display = !!getenv("DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "x11")) /* and it is X11 */ - { - if (!have_display) /* if there is no $DISPLAY */ - { - ERR("$ELM_DISPLAY is set to x11 but $DISPLAY is not set"); - init_x = EINA_FALSE; - } - else /* if there is */ - init_x = EINA_TRUE; - } - else /* not X11 */ - init_x = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - if (have_display) /* If there is a $DISPLAY */ - init_x = EINA_TRUE; - else /* No $DISPLAY */ - init_x = EINA_FALSE; - } - if (init_x) - { - if (ecore_x_display_get()) - ecore_x_shutdown(); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Eina_Bool init_wl = EINA_FALSE; - Eina_Bool have_wl_display = !!getenv("WAYLAND_DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "wl")) /* and it is WL */ - { - /* always try to connect to wl when it is enforced */ - init_wl = EINA_TRUE; - } - else /* not wl */ - init_wl = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - /* If there is a $WAYLAND_DISPLAY */ - if ((have_wl_display) && (!getenv("DISPLAY"))) - init_wl = EINA_TRUE; - else /* No $WAYLAND_DISPLAY */ - init_wl = EINA_FALSE; - } - if (init_wl) - { - if (!managers) ecore_wl2_display_disconnect(_elm_wl_display); - ecore_wl2_shutdown(); - } -#endif -} - -#ifdef HAVE_ELEMENTARY_X -static void -_set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel) -{ - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].debug = "Primary"; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].ecore_sel = ECORE_X_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].set = ecore_x_selection_primary_set; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].clear = ecore_x_selection_primary_clear; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].request = ecore_x_selection_primary_request; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].debug = "Secondary"; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].ecore_sel = ECORE_X_SELECTION_SECONDARY; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].set = ecore_x_selection_secondary_set; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].clear = ecore_x_selection_secondary_clear; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].request = ecore_x_selection_secondary_request; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_DND].debug = "DnD"; - sel_list[EFL_UI_SELECTION_TYPE_DND].ecore_sel = ECORE_X_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_DND].request = ecore_x_selection_xdnd_request; - sel_list[EFL_UI_SELECTION_TYPE_DND].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].debug = "Clipboard"; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].ecore_sel = ECORE_X_SELECTION_CLIPBOARD; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].set = ecore_x_selection_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].clear = ecore_x_selection_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].request = ecore_x_selection_clipboard_request; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].seat_sel = seat_sel; -} -#endif -#ifdef HAVE_ELEMENTARY_WIN32 -static void -_set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel) -{ - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].debug = "Primary"; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].ecore_sel = ECORE_WIN32_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].set = ecore_win32_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].clear = ecore_win32_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].get = ecore_win32_clipboard_get; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].debug = "Secondary"; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].ecore_sel = ECORE_WIN32_SELECTION_OTHER; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_DND].debug = "DnD"; - sel_list[EFL_UI_SELECTION_TYPE_DND].ecore_sel = ECORE_WIN32_SELECTION_OTHER; - sel_list[EFL_UI_SELECTION_TYPE_DND].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].debug = "Clipboard"; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].ecore_sel = ECORE_WIN32_SELECTION_CLIPBOARD; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].set = ecore_win32_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].clear = ecore_win32_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].seat_sel = seat_sel; -} -#endif - -#include "efl_ui_selection_manager.eo.c" diff --git a/src/lib/elementary/efl_ui_selection_manager.eo b/src/lib/elementary/efl_ui_selection_manager.eo deleted file mode 100644 index e7df9cce77..0000000000 --- a/src/lib/elementary/efl_ui_selection_manager.eo +++ /dev/null @@ -1,139 +0,0 @@ -import efl_ui_dnd_types; - -class @beta Efl.Ui.Selection_Manager extends Efl.Object { - methods { - selection_set @beta { - [[Set selection]] - params { - @in owner: Efl.Object; [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in format: Efl.Ui.Selection_Format; [[Selection format]] - @in data: Eina.Slice; [[Selection data]] - @in seat: uint @optional;[[Specified seat for multiple seats case.]] - } - return: future; [[Future for tracking when the selection is lost]] - } - selection_get @beta { - [[Get selection]] - params { - @in request: const(Efl.Object); [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]] - @in seat: uint @optional;[[Specified seat for multiple seats case.]] - } - } - selection_clear @beta { - params { - @in owner: Efl.Object; [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint @optional; [[Specified seat for multiple seats case.]] - } - } - selection_has_owner @beta { - [[Check if the request object has selection or not]] - params { - @in request: Efl.Object; [[Request object]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint @optional; [[Specified seat for multiple seats case.]] - } - return: bool; [[EINA_TRUE if the request object has selection, otherwise, EINA_FALSE]] - } - drag_start @beta { - [[This starts a drag and drop process at the drag side. - During dragging, there are three events emitted as belows: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE - ]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in format: Efl.Ui.Selection_Format; [[Data format]] - @in data: Eina.Slice; [[Data to transfer]] - @in action: Efl.Ui.Selection_Action; [[Action when data is transferred]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_action_set @beta { - [[This sets the action for the drag]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in action: Efl.Ui.Selection_Action; [[Drag action]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_cancel @beta { - [[This cancels the on-going drag]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drag_item_add @beta { - [[This registers a drag for items in a container. Many items can be - dragged at a time. During dragging, there are three events emitted: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE.]] - params { - @in cont: Efl.Object; [[Container object]] - @in time_to_drag: double; [[Time since mouse down happens to drag starts]] - @in anim_duration: double; [[animation duration]] - @in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]] - @in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]] - @in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations]] - @in seat: uint; [[Specified seat for multiple seats case]] - } - } - container_drag_item_del @beta { - [[Remove drag function of items in the container object.]] - params { - @in cont: Efl.Object; [[Container object]] - @in seat: uint; [[Specified seat for multiple seats case]] - } - } - drop_target_add @beta { - [[Add a dropable target. There are four events emitted: - - EFL_UI_DND_DROP_DRAG_ENTER - - EFL_UI_DND_DROP_DRAG_LEAVE - - EFL_UI_DND_DROP_DRAG_POS - - EFL_UI_DND_DROP_DRAG_DROP.]] - params { - @in target_obj: Efl.Object; [[Drop target]] - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - return: bool; [[$true on success, $false otherwise]] - } - drop_target_del @beta { - [[Remove a dropable target]] - params { - @in target_obj: Efl.Object; [[Drop target]] - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drop_item_add @beta { - [[Add dropable target for a container in which items can drop to it]] - params { - @in cont: Efl.Object; [[Container object]] - @in format: Efl.Ui.Selection_Format; [[Accepted data formats]] - @in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drop_item_del @beta { - [[Remove dropable target for the container]] - params { - @in cont: Efl.Object; [[Container object]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - } - implements { - Efl.Object.constructor; - Efl.Object.destructor; - } -} diff --git a/src/lib/elementary/efl_ui_selection_types.eot b/src/lib/elementary/efl_ui_selection_types.eot deleted file mode 100644 index cbe5e0dc7b..0000000000 --- a/src/lib/elementary/efl_ui_selection_types.eot +++ /dev/null @@ -1,60 +0,0 @@ -enum @beta Efl.Ui.Selection_Type -{ - [[Selection type]] - primary, [[Primary text selection (highlighted or selected text)]] - secondary, [[Used when primary selection is in use]] - dnd, [[Drag and Drop]] - clipboard [[Clipboard selection (ctrl+C)]] -} - -enum @beta Efl.Ui.Selection_Format -{ - [[Selection format]] - targets = -1, [[For matching every possible atom]] - none = 0x0, [[Content is from outside of EFL]] - text = 0x01, [[Plain unformatted text: Used for things that don't want rich markup]] - markup = 0x2, [[Edje textblock markup, including inline images]] - image = 0x4, [[Images]] - vcard = 0x08, [[Vcards]] - html = 0x10 [[Raw HTML-like data (eg. webkit)]] -} - -enum @beta Efl.Ui.Selection_Action -{ - [[Defines the kind of action associated with the drop data]] - unknown, [[Action type is unknown]] - copy, [[Copy the data]] - move, [[Move the data]] - private, [[Private action type]] - ask, [[Ask the user what to do]] - list, [[List the data]] - link, [[Link the data]] - description [[Describe the data]] -} - -struct @beta Efl.Ui.Selection_Data -{ - [[Structure holding the info about selected data]] - pos: Eina.Position2D; [[Coordinates of the drop (DND operations only)]] - format: Efl.Ui.Selection_Format; [[Format of the selection]] - content: Eina.Slice; [[Selection data]] - action: Efl.Ui.Selection_Action; [[Action to perform with the data]] - item: Efl.Object; [[Item under the drag position. It is only available for container]] -} - -function @beta Efl.Ui.Selection_Data_Ready { - [[Function pointer for getting selection]] - params { - @in obj: Efl.Object; [[Object which requested for the selection]] - @in seldata: ptr(Efl.Ui.Selection_Data); [[Selection data]] - } -}; - -struct @beta Efl.Ui.Selection_Changed -{ - [[Selection-changed specific information.]] // TODO: This needs to be filled in. - type: Efl.Ui.Selection_Type; [[Selection type]] - seat: int; [[The seat on which the selection changed, or NULL for "default"]] - display: void_ptr; [[The display connection object, NULL under X11]] - exist: bool; [[EINA_TRUE if the selection has an owner]] -} diff --git a/src/lib/elementary/efl_ui_tags.c b/src/lib/elementary/efl_ui_tags.c index 95c5ce59d7..5cc37badda 100644 --- a/src/lib/elementary/efl_ui_tags.c +++ b/src/lib/elementary/efl_ui_tags.c @@ -757,7 +757,7 @@ _view_init(Evas_Object *obj, Efl_Ui_Tags_Data *sd) sd->entry = efl_add(EFL_UI_TEXTBOX_CLASS, sd->box, efl_text_multiline_set(efl_added, EINA_FALSE), efl_text_set(efl_added, ""), - efl_ui_textbox_cnp_mode_set(efl_added, EFL_UI_SELECTION_FORMAT_MARKUP), + efl_ui_textbox_cnp_dnd_mode_set(efl_added, EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP), efl_input_text_input_panel_autoshow_set(efl_added, EINA_FALSE), efl_text_interactive_editable_set(efl_added, EINA_TRUE), efl_composite_attach(obj, efl_added)); diff --git a/src/lib/elementary/efl_ui_textbox.c b/src/lib/elementary/efl_ui_textbox.c index a53c265d38..3ffa3e096a 100644 --- a/src/lib/elementary/efl_ui_textbox.c +++ b/src/lib/elementary/efl_ui_textbox.c @@ -22,7 +22,6 @@ typedef struct _Efl_Ui_Textbox_Data Efl_Ui_Textbox_Data; typedef struct _Efl_Ui_Text_Rectangle Efl_Ui_Text_Rectangle; typedef struct _Anchor Anchor; -typedef struct _Selection_Loss_Data Selection_Loss_Data; /** * Base widget smart data extended with entry instance data. @@ -69,7 +68,7 @@ struct _Efl_Ui_Textbox_Data const char *hover_style; /**< style of a hover object */ } anchor_hover; - Efl_Ui_Selection_Format cnp_mode; + const char *cnp_mime_type; Elm_Sel_Format drop_format; struct { @@ -81,11 +80,7 @@ struct _Efl_Ui_Textbox_Data Eina_Size2D scroll; Eina_Size2D layout; } last; - struct - { - Eina_Future *primary; - Eina_Future *clipboard; - } sel_future; + Efl_Ui_Textbox_Cnp_Content content; Eina_Bool sel_handles_enabled : 1; Eina_Bool start_handler_down : 1; Eina_Bool start_handler_shown : 1; @@ -147,12 +142,6 @@ struct _Efl_Ui_Text_Rectangle Evas_Object *obj_bg, *obj_fg, *obj; }; -struct _Selection_Loss_Data -{ - Eo *obj; - Efl_Ui_Selection_Type stype; -}; - #define MY_CLASS EFL_UI_TEXTBOX_CLASS #define MY_CLASS_PFX efl_ui_textbox #define MY_CLASS_NAME "Efl.Ui.Textbox" @@ -208,7 +197,7 @@ static void _anchors_free(Efl_Ui_Textbox_Data *sd); static void _selection_defer(Eo *obj, Efl_Ui_Textbox_Data *sd); static Eina_Position2D _decoration_calc_offset(Efl_Ui_Textbox_Data *sd); static void _update_text_theme(Eo *obj, Efl_Ui_Textbox_Data *sd); -static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Selection_Type type); +static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type); static Eina_Bool _key_action_copy(Evas_Object *obj, const char *params); static Eina_Bool _key_action_paste(Evas_Object *obj, const char *params); @@ -407,16 +396,19 @@ _update_selection_handler(Eo *obj) } } -static void -_selection_data_cb(void *data EINA_UNUSED, Eo *obj, - Efl_Ui_Selection_Data *sel_data) +static Eina_Value +_selection_data_cb(Efl_Ui_Textbox *obj, void *data EINA_UNUSED, const Eina_Value value) { + Eina_Content *content; + Eina_Slice slice; Efl_Text_Cursor *cur, *start, *end; Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 }; - char *buf = eina_slice_strdup(sel_data->content); - size_t len = sel_data->content.len; + if (eina_value_type_get(&value) != EINA_VALUE_TYPE_CONTENT) + return EINA_VALUE_EMPTY; + content = eina_value_to_content(&value); + slice = eina_content_data_get(content); efl_text_interactive_selection_cursors_get(obj, &start, &end); if (!efl_text_cursor_equal(start, end)) { @@ -426,83 +418,130 @@ _selection_data_cb(void *data EINA_UNUSED, Eo *obj, cur = efl_text_interactive_main_cursor_get(obj); info.type = EFL_TEXT_CHANGE_TYPE_INSERT; info.position = efl_text_cursor_position_get(cur); - info.length = len; - info.content = buf; - if (sel_data->format == EFL_UI_SELECTION_FORMAT_MARKUP) + info.length = slice.len; + info.content = slice.mem; + if (eina_streq(eina_content_type_get(content), "application/x-elementary-markup")) { - efl_text_cursor_markup_insert(cur, buf); + efl_text_cursor_markup_insert(cur, slice.mem); + } + else if (!strncmp(eina_content_type_get(content), "image/", strlen("image/"))) + { + Eina_Strbuf *result = eina_strbuf_new(); + eina_strbuf_append_printf(result, ""); + efl_text_cursor_markup_insert(cur, eina_strbuf_string_get(result)); + eina_strbuf_free(result); } else // TEXT { - efl_text_cursor_text_insert(cur, buf); + efl_text_cursor_text_insert(cur, slice.mem); } efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info); - free(buf); + + return EINA_VALUE_EMPTY; +} + +static Eina_Array* +_figure_out_types(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) +{ + Eina_Array *types = eina_array_new(10); + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP) + eina_array_push(types, "application/x-elementary-markup"); + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE) + { + eina_array_push(types, "image/png"); + eina_array_push(types, "image/jpeg"); + eina_array_push(types, "image/x-ms-bmp"); + eina_array_push(types, "image/gif"); + eina_array_push(types, "image/tiff"); + eina_array_push(types, "image/svg+xml"); + eina_array_push(types, "image/x-xpixmap"); + eina_array_push(types, "image/x-tga"); + eina_array_push(types, "image/x-portable-pixmap"); + } + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT) + eina_array_push(types, "text/plain;charset=utf-8"); + return types; +} + +static Eina_Bool +_accepting_drops(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Accessor *mime_types) +{ + int i = 0; + const char *mime_type; + + if (efl_ui_widget_disabled_get(obj)) return EINA_FALSE; + + EINA_ACCESSOR_FOREACH(mime_types, i, mime_type) + { + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT && + eina_streq(mime_type, "text/plain;charset=utf-8")) + return EINA_TRUE; + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE && + strncmp(mime_type, "image/", strlen("image/"))) + return EINA_TRUE; + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP && + eina_streq(mime_type, "application/x-elementary-markup")) + return EINA_TRUE; + } + return EINA_FALSE; } static void _dnd_enter_cb(void *data EINA_UNUSED, - Evas_Object *obj) + const Efl_Event *ev) { - efl_ui_focus_util_focus(obj); + Efl_Ui_Drop_Event *dnd_enter = ev->info; + EFL_UI_TEXT_DATA_GET(ev->object, sd); + if (_accepting_drops(ev->object, sd, dnd_enter->available_types)) + efl_ui_focus_util_focus(ev->object); } static void -_dnd_leave_cb(void *data EINA_UNUSED, - Evas_Object *obj EINA_UNUSED) +_dnd_pos_cb(void *data EINA_UNUSED, const Efl_Event *ev) { -} + Efl_Ui_Drop_Event *dnd_pos = ev->info; + Eina_Position2D po, pe, pos; + EFL_UI_TEXT_DATA_GET(ev->object, sd); + int cursor_pos; -static void -_dnd_pos_cb(void *data EINA_UNUSED, - Evas_Object *obj, - Evas_Coord x, - Evas_Coord y, - Elm_Xdnd_Action action EINA_UNUSED) -{ - int pos; - Eina_Rect o, e; + if (!_accepting_drops(ev->object, sd, dnd_pos->available_types)) + return; - EFL_UI_TEXT_DATA_GET(obj, sd); - - o = efl_gfx_entity_geometry_get(obj); - e = efl_gfx_entity_geometry_get(sd->entry_edje); - x = x + o.x - e.x; - y = y + o.y - e.y; + po = efl_gfx_entity_position_get(ev->object); + pe = efl_gfx_entity_position_get(sd->entry_edje); + pos.x = dnd_pos->position.x + po.x - pe.x; + pos.y = dnd_pos->position.y + po.x - pe.y; edje_object_part_text_cursor_coord_set - (sd->entry_edje, "efl.text", EDJE_CURSOR_USER, x, y); - pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "efl.text", EDJE_CURSOR_USER, pos.x, pos.y); + cursor_pos = edje_object_part_text_cursor_pos_get (sd->entry_edje, "efl.text", EDJE_CURSOR_USER); edje_object_part_text_cursor_pos_set(sd->entry_edje, "efl.text", - EDJE_CURSOR_MAIN, pos); + EDJE_CURSOR_MAIN, cursor_pos); } -static Eina_Bool -_dnd_drop_cb(void *data EINA_UNUSED, - Evas_Object *obj, - Elm_Selection_Data *drop) +static void +_dnd_drop_cb(void *data EINA_UNUSED, const Efl_Event *ev) { - Eina_Bool rv; + Efl_Ui_Drop_Event *drop = ev->info; + Eina_Future *future; + Eina_Array *types; - EFL_UI_TEXT_DATA_GET(obj, sd); + EFL_UI_TEXT_DATA_GET(ev->object, sd); + types = _figure_out_types(ev->object, sd); - rv = edje_object_part_text_cursor_coord_set - (sd->entry_edje, "efl.text", EDJE_CURSOR_MAIN, drop->x, drop->y); + if (!_accepting_drops(ev->object, sd, drop->available_types)) + return; - if (!rv) WRN("Warning: Failed to position cursor: paste anyway"); + future = efl_ui_dnd_drop_data_get(ev->object, 0, eina_array_iterator_new(types)); + eina_array_free(types); - //rv = _selection_data_cb(NULL, obj, drop); - - return rv; -} - -static Elm_Sel_Format -_get_drop_format(Evas_Object *obj) -{ - if (efl_text_interactive_editable_get(obj) && (efl_text_multiline_get(obj)) && (!efl_text_password_get(obj)) && (!efl_ui_widget_disabled_get(obj))) - return EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_IMAGE; - return EFL_UI_SELECTION_FORMAT_MARKUP; + efl_future_then(ev->object, future, _selection_data_cb); } /* we can't reuse layout's here, because it's on entry_edje only */ @@ -516,12 +555,6 @@ _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Ein efl_ui_widget_disabled_set(efl_super(obj, MY_CLASS), disabled); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - emission = efl_ui_widget_disabled_get(obj) ? "efl,state,disabled" : "efl,state,enabled"; efl_layout_signal_emit(sd->entry_edje, emission, "efl"); if (sd->scroll) @@ -529,15 +562,6 @@ _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Ein efl_ui_scrollable_scroll_freeze_set(obj, efl_ui_widget_disabled_get(obj)); } - if (!efl_ui_widget_disabled_get(obj)) - { - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - } _update_text_theme(obj, sd); } @@ -804,83 +828,36 @@ _popup_position(Evas_Object *obj) efl_gfx_entity_geometry_set(sd->popup, EINA_RECT(r.x + cx, r.y + cy, m.w, m.h)); } -static Eina_Value -_selection_lost_cb(void *data, const Eina_Value value) +static void +_selection_lost_cb(void *data EINA_UNUSED, const Efl_Event *ev) { - Selection_Loss_Data *sdata = data; - EFL_UI_TEXT_DATA_GET(sdata->obj, sd); + Efl_Ui_Wm_Selection_Changed *changed = ev->info; + EFL_UI_TEXT_DATA_GET(ev->object, sd); - efl_text_interactive_all_unselect(sdata->obj); - _selection_defer(sdata->obj, sd); - switch (sdata->stype) + if (changed->buffer == EFL_UI_CNP_BUFFER_SELECTION && changed->caused_by != ev->object) { - case EFL_UI_SELECTION_TYPE_CLIPBOARD: - sd->sel_future.clipboard = NULL; - break; - case EFL_UI_SELECTION_TYPE_PRIMARY: - default: - sd->sel_future.primary = NULL; - break; + efl_text_interactive_all_unselect(ev->object); + _selection_defer(ev->object, sd); } - - return value; } static void -_selection_store(Efl_Ui_Selection_Type seltype, +_selection_store(Efl_Ui_Cnp_Buffer buffer, Evas_Object *obj) { char *sel; Efl_Text_Cursor *start, *end; - Efl_Ui_Selection_Format selformat = EFL_UI_SELECTION_FORMAT_MARKUP; - Eina_Slice slice; - Selection_Loss_Data *ldata; - Eina_Future *f; - - EFL_UI_TEXT_DATA_GET(obj, sd); + Eina_Content *content; efl_text_interactive_selection_cursors_get(obj, &start, &end); sel = efl_text_cursor_range_markup_get(start, end); if ((!sel) || (!sel[0])) return; /* avoid deleting our own selection */ - slice.len = strlen(sel); - slice.mem = sel; + content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(sel), "application/x-elementary-markup"); - switch (seltype) - { - case EFL_UI_SELECTION_TYPE_CLIPBOARD: - if (sd->sel_future.clipboard) - { - eina_future_cancel(sd->sel_future.clipboard); - } + efl_ui_selection_set(obj, buffer, content, 0); - f = sd->sel_future.clipboard = efl_ui_selection_set(obj, seltype, - selformat, slice, 1); - break; - - case EFL_UI_SELECTION_TYPE_PRIMARY: - default: - if (sd->sel_future.primary) - { - eina_future_cancel(sd->sel_future.primary); - } - - f = sd->sel_future.primary = efl_ui_selection_set(obj, seltype, - selformat, slice, 1); - break; - } - - ldata = calloc(1, sizeof(Selection_Loss_Data)); - if (!ldata) goto end; - - ldata->obj = obj; - eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata); - - //if (seltype == EFL_UI_SELECTION_TYPE_CLIPBOARD) - // eina_stringshare_replace(&sd->cut_sel, sel); - -end: free(sel); } @@ -956,7 +933,7 @@ _menu_call(Evas_Object *obj) { Eina_Bool ownersel; - ownersel = elm_selection_selection_has_owner(obj); + ownersel = elm_cnp_clipboard_selection_has_owner(obj); /* prevent stupid blank hoversel */ if (efl_text_interactive_have_selection_get(obj) && efl_text_password_get(obj)) return; if (_elm_config->desktop_entry && (!efl_text_interactive_have_selection_get(obj)) && ((!efl_text_interactive_editable_get(obj)) || (!ownersel))) @@ -1133,7 +1110,7 @@ _mouse_down_cb(void *data, const Efl_Event *event) if (ev->button == 2) { - _efl_ui_textbox_selection_paste_type(data, EFL_UI_SELECTION_TYPE_PRIMARY); + _efl_ui_textbox_selection_paste_type(data, sd, EFL_UI_CNP_BUFFER_SELECTION); } /* If right button is pressed and context menu disabled is true, @@ -1654,10 +1631,18 @@ _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd) { Eo *text_obj; + sd->content = EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP; + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); if (!elm_widget_theme_klass_get(obj)) elm_widget_theme_klass_set(obj, "text"); + + efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_lost_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_ENTERED, _dnd_enter_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, _dnd_pos_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_DROPPED, _dnd_drop_cb, NULL); + obj = efl_constructor(efl_super(obj, MY_CLASS)); efl_event_callback_add(obj, EFL_INPUT_EVENT_LONGPRESSED, _long_press_cb, obj); @@ -1674,11 +1659,9 @@ _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd) efl_composite_attach(obj, text_obj); sd->entry_edje = wd->resize_obj; - sd->cnp_mode = EFL_UI_SELECTION_FORMAT_TEXT; sd->context_menu_enabled = EINA_TRUE; efl_text_interactive_editable_set(obj, EINA_TRUE); efl_text_interactive_selection_allowed_set(obj, EINA_TRUE); - sd->drop_format = EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_IMAGE; sd->last.scroll = EINA_SIZE2D(0, 0); sd->sel_handles_enabled = EINA_FALSE; @@ -1691,12 +1674,6 @@ _efl_ui_textbox_efl_object_finalize(Eo *obj, { obj = efl_finalize(efl_super(obj, MY_CLASS)); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY); _update_guide_text(obj, sd); @@ -1805,11 +1782,6 @@ _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, E efl_text_replacement_char_set(obj, ENTRY_PASSWORD_MASK_CHARACTER_UTF8); efl_text_password_set(sd->text_obj, password); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (password) { efl_text_multiline_set(obj, EINA_FALSE); @@ -1819,12 +1791,6 @@ _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, E else { efl_text_multiline_set(obj, EINA_TRUE); - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); efl_input_text_input_content_type_set(obj, ((efl_input_text_input_content_type_get(obj) | EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE) & ~EFL_INPUT_TEXT_CONTENT_TYPE_SENSITIVE_DATA)); efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY); } @@ -1891,19 +1857,8 @@ _efl_ui_textbox_efl_text_interactive_editable_set(Eo *obj, Efl_Ui_Textbox_Data * efl_ui_widget_theme_apply(obj); efl_ui_widget_focus_allow_set(obj, editable); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (editable) { - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (sd->cursor) { efl_gfx_entity_visible_set(sd->cursor, EINA_TRUE); @@ -1961,7 +1916,7 @@ _efl_ui_textbox_selection_cut(Eo *obj, Efl_Ui_Textbox_Data *sd) /*In password mode, cut will remove text only*/ if (!efl_text_password_get(obj)) - _selection_store(EFL_UI_SELECTION_TYPE_CLIPBOARD, obj); + _selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj); efl_text_interactive_selection_cursors_get(obj, &start, &end); start_pos = efl_text_cursor_position_get(start); @@ -1993,25 +1948,27 @@ _efl_ui_textbox_selection_copy(Eo *obj, Efl_Ui_Textbox_Data *sd) efl_layout_signal_emit(sd->entry_edje, "efl,state,select,off", "efl"); efl_ui_widget_scroll_hold_pop(obj); } - _selection_store(EFL_UI_SELECTION_TYPE_CLIPBOARD, obj); + _selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj); efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_COPY, NULL); } - static void -_efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Selection_Type type) +_efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type) { - Efl_Ui_Selection_Format formats = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP; + Eina_Future *future; + Eina_Array *types = _figure_out_types(obj, sd); - efl_ui_selection_get(obj, type, formats, - NULL, _selection_data_cb, NULL, 1); + future = efl_ui_selection_get(obj, type, 0, eina_array_iterator_new(types)); + + efl_future_then(obj, future, _selection_data_cb); efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_PASTE, NULL); + eina_array_free(types); } EOLIAN static void -_efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd EINA_UNUSED) +_efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd) { - _efl_ui_textbox_selection_paste_type(obj, EFL_UI_SELECTION_TYPE_CLIPBOARD); + _efl_ui_textbox_selection_paste_type(obj, sd, EFL_UI_CNP_BUFFER_COPY_AND_PASTE); } EOLIAN static void @@ -2028,44 +1985,15 @@ _efl_ui_textbox_context_menu_enabled_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textb } EOLIAN static void -_efl_ui_textbox_cnp_mode_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Selection_Format cnp_mode) +_efl_ui_textbox_cnp_dnd_mode_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Efl_Ui_Textbox_Cnp_Content content) { - Elm_Sel_Format dnd_format = EFL_UI_SELECTION_FORMAT_MARKUP; - - if (cnp_mode != EFL_UI_SELECTION_FORMAT_TARGETS) - { - if (cnp_mode & EFL_UI_SELECTION_FORMAT_VCARD) - ERR("VCARD format not supported for copy & paste!"); - else if (cnp_mode & EFL_UI_SELECTION_FORMAT_HTML) - ERR("HTML format not supported for copy & paste!"); - cnp_mode &= ~EFL_UI_SELECTION_FORMAT_VCARD; - cnp_mode &= ~EFL_UI_SELECTION_FORMAT_HTML; - } - - if (sd->cnp_mode == cnp_mode) return; - sd->cnp_mode = cnp_mode; - if (sd->cnp_mode == EFL_UI_SELECTION_FORMAT_TEXT) - dnd_format = EFL_UI_SELECTION_FORMAT_TEXT; - else if (cnp_mode == EFL_UI_SELECTION_FORMAT_IMAGE) - dnd_format |= EFL_UI_SELECTION_FORMAT_IMAGE; - - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - sd->drop_format = dnd_format; - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); + sd->content = content; } -EOLIAN static Efl_Ui_Selection_Format -_efl_ui_textbox_cnp_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) +EOLIAN static Efl_Ui_Textbox_Cnp_Content +_efl_ui_textbox_cnp_dnd_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) { - return sd->cnp_mode; + return sd->content; } EOLIAN static void @@ -3279,7 +3207,7 @@ _efl_ui_textbox_selection_changed_cb(void *data, const Efl_Event *event EINA_UNU Eo *obj = data; EFL_UI_TEXT_DATA_GET(obj, sd); _edje_signal_emit(sd, "selection,changed", "efl.text"); - _selection_store(EFL_UI_SELECTION_TYPE_PRIMARY, obj); + _selection_store(EFL_UI_CNP_BUFFER_SELECTION, obj); _selection_defer(obj, sd); } diff --git a/src/lib/elementary/efl_ui_textbox.eo b/src/lib/elementary/efl_ui_textbox.eo index 2b7ccf9472..ff0898b6fc 100644 --- a/src/lib/elementary/efl_ui_textbox.eo +++ b/src/lib/elementary/efl_ui_textbox.eo @@ -1,3 +1,10 @@ +enum Efl.Ui.Textbox_Cnp_Content { + Nothing = 0, [[You can paste or drop nothing]] + Text = 1, [[You can paste normal Text]] + Markup = 3, [[You can paste Markup (Normal text is also just markup)]] + Image = 4, [[You can paste Images]] +} + class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Clickable, Efl.Access.Text, Efl.Access.Editable.Text composites @@ -31,8 +38,7 @@ class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Click enabled: bool; [[$true to enable the contextual menu.]] } } - @property cnp_mode @beta { - /* FIXME: Efl.Ui.Selection_Format does not allow markup without images! */ + @property cnp_dnd_mode @beta { [[Control pasting of text and images for the widget. Normally the entry allows both text and images to be pasted. @@ -44,7 +50,7 @@ class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Click get { } values { - format: Efl.Ui.Selection_Format; [[Format for copy & paste.]] + allowed_formats : Efl.Ui.Textbox_Cnp_Content; [[Format for cnp]] } } @property selection_handles_enabled { diff --git a/src/lib/elementary/efl_ui_win.c b/src/lib/elementary/efl_ui_win.c index c0450eea9c..69f2e7b6d0 100644 --- a/src/lib/elementary/efl_ui_win.c +++ b/src/lib/elementary/efl_ui_win.c @@ -213,6 +213,9 @@ struct _Efl_Ui_Win_Data int ignore_frame_resize; Eina_Bool req_wh : 1; Eina_Bool req_xy : 1; + Eina_Array *selection_changed; + Eina_Array *planned_changes; + Eina_Inarray *drop_target; struct { short pointer_move; @@ -382,6 +385,8 @@ static void _elm_win_frame_style_update(Efl_Ui_Win_Data *sd, Eina_Bool force_emi static inline void _elm_win_need_frame_adjust(Efl_Ui_Win_Data *sd, const char *engine); static void _elm_win_resize_objects_eval(Evas_Object *obj, Eina_Bool force_resize); static void _elm_win_frame_obj_update(Efl_Ui_Win_Data *sd, Eina_Bool force); +static void _ee_backbone_init(Efl_Ui_Win *obj, Efl_Ui_Win_Data *pd); +static void _ee_backbone_shutdown(Efl_Ui_Win *obj, Efl_Ui_Win_Data *pd); static inline Efl_Ui_Win_Type _elm_win_type_to_efl_ui_win_type(Elm_Win_Type type) @@ -5933,6 +5938,7 @@ _efl_ui_win_efl_object_finalize(Eo *obj, Efl_Ui_Win_Data *sd) efl_file_mmap_get(efl_super(efl_part(obj, "background"), EFL_UI_WIN_PART_CLASS))) efl_file_load(efl_part(obj, "background")); } + _ee_backbone_init(obj, sd); return obj; } @@ -5968,6 +5974,8 @@ _efl_ui_win_efl_object_destructor(Eo *obj, Efl_Ui_Win_Data *pd EINA_UNUSED) if (pd->finalize_future) eina_future_cancel(pd->finalize_future); + _ee_backbone_shutdown(obj, pd); + efl_destructor(efl_super(obj, MY_CLASS)); efl_unref(pd->provider); @@ -5984,6 +5992,7 @@ _efl_ui_win_efl_object_constructor(Eo *obj, Efl_Ui_Win_Data *pd) pd->provider = efl_add_ref(EFL_UI_FOCUS_PARENT_PROVIDER_STANDARD_CLASS, NULL); pd->profile.available = eina_array_new(4); pd->max_w = pd->max_h = -1; + pd->planned_changes = eina_array_new(10); // For bindings: if no parent, allow simple unref if (!efl_parent_get(obj)) @@ -9187,6 +9196,249 @@ elm_win_teamwork_uri_open(Efl_Ui_Win *obj EINA_UNUSED, const char *uri EINA_UNUS ERR("Calling deprecrated function '%s'", __FUNCTION__); } +/* What here follows is code that implements the glue between ecore evas and efl_ui* side */ +typedef struct { + Eo *obj; + Eina_Bool currently_inside; +} Ui_Dnd_Target; + +static inline Efl_Ui_Cnp_Buffer +_ui_buffer_get(Ecore_Evas_Selection_Buffer buffer) +{ + if (buffer == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + return EFL_UI_CNP_BUFFER_SELECTION; + else if (buffer == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return EFL_UI_CNP_BUFFER_COPY_AND_PASTE; + + return -1; +} + +void +_register_selection_changed(Efl_Ui_Selection *selection) +{ + ELM_WIN_DATA_GET(efl_provider_find(selection, EFL_UI_WIN_CLASS), pd); + + eina_array_push(pd->planned_changes, selection); +} + +static Eina_Bool +_remove_object(void *data, void *gdata) +{ + if (data == gdata) + return EINA_FALSE; + return EINA_TRUE; +} + +static void +_selection_changed_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + Efl_Ui_Wm_Selection_Changed changed = { + .seat = seat, + .buffer = _ui_buffer_get(selection), + .caused_by = eina_array_count(pd->planned_changes) > 0 ? eina_array_data_get(pd->planned_changes, 0) : NULL, + }; + + for (unsigned int i = 0; i < eina_array_count(pd->selection_changed); ++i) + { + Eo *obj = eina_array_data_get(pd->selection_changed, i); + + efl_event_callback_call(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &changed); + } + + if (changed.caused_by) + eina_array_remove(pd->planned_changes, _remove_object, changed.caused_by); +} + +static void +_motion_cb(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + Efl_Ui_Drop_Event ev = {p, seat, ecore_evas_drop_available_types_get(ee, seat)}; + + if (target->currently_inside && !inside) + { + target->currently_inside = EINA_FALSE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_LEFT, &ev); + } + else if (!target->currently_inside && inside) + { + target->currently_inside = EINA_TRUE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_ENTERED, &ev); + } + else if (target->currently_inside && inside) + { + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, &ev); + } + eina_accessor_free(ev.available_types); + } +} + +static void +_enter_state_change_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, Eina_Bool move_inside) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + Efl_Ui_Drop_Event ev = {p, seat, ecore_evas_drop_available_types_get(ee, seat)}; + + if (inside && move_inside) + { + target->currently_inside = EINA_TRUE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_ENTERED, &ev); + } + else if (!move_inside && !target->currently_inside) + { + target->currently_inside = EINA_FALSE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_LEFT, &ev); + } + } +} + +static void +_drop_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, const char *action) +{ + Eina_List *itr, *top_objects_list = NULL; + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + Eina_Array *tmp = eina_array_new(10); + Eo *top_obj; + + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + + if (inside) + { + EINA_SAFETY_ON_FALSE_GOTO(target->currently_inside, end); + eina_array_push(tmp, target->obj); + } + } + + /* We retrieve the (non-smart) objects pointed by (px, py) */ + top_objects_list = evas_tree_objects_at_xy_get(ecore_evas_get(ee), NULL, p.x, p.y); + /* We walk on this list from the last because if the list contains more than one + * element, all but the last will repeat events. The last one can repeat events + * or not. Anyway, this last one is the first that has to be taken into account + * for the determination of the drop target. + */ + EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj) + { + Evas_Object *object = top_obj; + /* We search for the dropable data into the object. If not found, we search into its parent. + * For example, if a button is a drop target, the first object will be an (internal) image. + * The drop target is attached to the button, i.e to image's parent. That's why we need to + * walk on the parents until NULL. + * If we find this dropable data, we found our drop target. + */ + while (object) + { + unsigned int out_idx; + if (!eina_array_find(tmp, object, &out_idx)) + { + object = evas_object_smart_parent_get(object); + } + else + { + Efl_Ui_Drop_Dropped_Event ev = {{p, seat, ecore_evas_drop_available_types_get(ee, seat)}, action}; + efl_event_callback_call(object, EFL_UI_DND_EVENT_DROP_DROPPED, &ev); + goto end; + } + } + } +end: + eina_list_free(top_objects_list); + eina_array_free(tmp); +} + +static void +_ee_backbone_init(Efl_Ui_Win *obj EINA_UNUSED, Efl_Ui_Win_Data *pd) +{ + pd->selection_changed = eina_array_new(1); + pd->drop_target = eina_inarray_new(sizeof(Ui_Dnd_Target), 1); + + ecore_evas_callback_selection_changed_set(pd->ee, _selection_changed_cb); + ecore_evas_callback_drop_drop_set(pd->ee, _drop_cb); + ecore_evas_callback_drop_motion_set(pd->ee, _motion_cb); + ecore_evas_callback_drop_state_changed_set(pd->ee, _enter_state_change_cb); +} + +static void +_ee_backbone_shutdown(Efl_Ui_Win *obj EINA_UNUSED, Efl_Ui_Win_Data *pd) +{ + ecore_evas_callback_selection_changed_set(pd->ee, NULL); + ecore_evas_callback_drop_drop_set(pd->ee, NULL); + ecore_evas_callback_drop_motion_set(pd->ee, NULL); + ecore_evas_callback_drop_state_changed_set(pd->ee, NULL); + + eina_array_free(pd->selection_changed); + pd->selection_changed = NULL; + eina_inarray_free(pd->drop_target); + pd->drop_target = NULL; + +} + +static Eina_Bool +_remove(void *data, void *gdata) +{ + if (data == gdata) + return EINA_FALSE; + return EINA_TRUE; +} + +void +_drop_event_register(Eo *obj) +{ + Ui_Dnd_Target target = {obj, EINA_FALSE}; + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + EINA_SAFETY_ON_NULL_RETURN(pd); + + eina_inarray_push(pd->drop_target, &target); +} + +void +_drop_event_unregister(Eo *obj) +{ + int idx = -1; + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + if (target->obj == obj) + { + //FIXME emit drop + target->currently_inside = EINA_FALSE; + idx = i; + } + } + if (idx != -1) + eina_inarray_remove_at(pd->drop_target, idx); +} + +void +_selection_changed_event_register(Eo *obj) +{ + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + eina_array_push(pd->selection_changed, obj); +} +void +_selection_changed_event_unregister(Eo *obj) +{ + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + eina_array_remove(pd->selection_changed, _remove, obj); +} /* Internal EO APIs and hidden overrides */ ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_win, Efl_Ui_Win_Data) diff --git a/src/lib/elementary/elm_cnp.c b/src/lib/elementary/elm_cnp.c new file mode 100644 index 0000000000..cf1f0eedc0 --- /dev/null +++ b/src/lib/elementary/elm_cnp.c @@ -0,0 +1,244 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include + +#include "elm_priv.h" +#include "elm_entry_eo.h" + +static inline Ecore_Evas_Selection_Buffer +_elm_sel_type_to_ee_type(Elm_Sel_Type type) +{ + if (type == ELM_SEL_TYPE_PRIMARY) + return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER; + if (type == ELM_SEL_TYPE_XDND) + return ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER; + if (type == ELM_SEL_TYPE_CLIPBOARD) + return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER; + return ECORE_EVAS_SELECTION_BUFFER_LAST; +} + +static inline Eina_Array* +_elm_sel_format_to_mime_type(Elm_Sel_Format format) +{ + Eina_Array *ret = eina_array_new(10); + if (format & ELM_SEL_FORMAT_TEXT) + eina_array_push(ret, "text/plain;charset=utf-8"); + if (format & ELM_SEL_FORMAT_MARKUP) + eina_array_push(ret, "application/x-elementary-markup"); + if (format & ELM_SEL_FORMAT_IMAGE) + { + eina_array_push(ret, "image/png"); + eina_array_push(ret, "image/jpeg"); + eina_array_push(ret, "image/x-ms-bmp"); + eina_array_push(ret, "image/gif"); + eina_array_push(ret, "image/tiff"); + eina_array_push(ret, "image/svg+xml"); + eina_array_push(ret, "image/x-xpixmap"); + eina_array_push(ret, "image/x-tga"); + eina_array_push(ret, "image/x-portable-pixmap"); + } + if (format & ELM_SEL_FORMAT_VCARD) + eina_array_push(ret, "text/vcard"); + if (format & ELM_SEL_FORMAT_HTML) + eina_array_push(ret, "application/xhtml+xml"); + + if (eina_array_count(ret) == 0) + ERR("Specified mime type is not available"); + + return ret; +} + +static inline const Elm_Sel_Format +_mime_type_to_elm_sel_format(const char *mime_type) +{ + if (eina_streq(mime_type, "text/vcard")) + return ELM_SEL_FORMAT_VCARD; + else if (eina_streq(mime_type, "application/x-elementary-markup")) + return ELM_SEL_FORMAT_MARKUP; + else if (eina_streq(mime_type, "application/xhtml+xml")) + return ELM_SEL_FORMAT_HTML; + else if (!strncmp(mime_type, "text/", strlen("text/"))) + return ELM_SEL_FORMAT_TEXT; + else if (!strncmp(mime_type, "image/", strlen("image/"))) + return ELM_SEL_FORMAT_IMAGE; + + return ELM_SEL_FORMAT_NONE; +} + +static int +_default_seat(const Eo *obj) +{ + return evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT)); +} + +EAPI Eina_Bool +elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, + Elm_Sel_Format format, + const void *buf, size_t buflen) +{ + Eina_Content *content; + Ecore_Evas *ee; + const char *mime_type; + Eina_Slice data; + Eina_Array *tmp; + + if (format == ELM_SEL_FORMAT_TEXT && ((char*)buf)[buflen - 1] != '\0') + { + data.mem = eina_memdup((unsigned char *)buf, buflen, EINA_TRUE); + data.len = buflen + 1; + } + else + { + data.mem = buf; + data.len = buflen; + } + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + + tmp = _elm_sel_format_to_mime_type(format); + if (eina_array_count(tmp) != 1) + { + ERR("You cannot specify more than one format when setting selection"); + } + mime_type = eina_array_data_get(tmp, 0); + content = eina_content_new(data, mime_type); + _register_selection_changed(obj); + + return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), content); +} + +EAPI Eina_Bool +elm_object_cnp_selection_clear(Evas_Object *obj, + Elm_Sel_Type selection) +{ + Ecore_Evas *ee; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), NULL); +} + +EAPI Eina_Bool +elm_cnp_clipboard_selection_has_owner(Evas_Object *obj) +{ + Ecore_Evas *ee; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + return ecore_evas_selection_exists(ee, _default_seat(obj), ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); + +} + +typedef struct _Sel_Lost_Data Sel_Lost_Data; +struct _Sel_Lost_Data +{ + const Evas_Object *obj; + Elm_Sel_Type type; + void *udata; + Elm_Selection_Loss_Cb loss_cb; +}; + +static void +_selection_changed_cb(void *data, const Efl_Event *ev) +{ + Sel_Lost_Data *ldata = data; + Efl_Ui_Wm_Selection_Changed *changed = ev->info; + + if (changed->buffer == EFL_UI_CNP_BUFFER_SELECTION && ldata->type != ELM_SEL_TYPE_PRIMARY) + return; + + if (changed->buffer == EFL_UI_CNP_BUFFER_COPY_AND_PASTE && ldata->type != ELM_SEL_TYPE_CLIPBOARD) + return; + + if (ldata->obj == changed->caused_by) + return; + + ldata->loss_cb(ldata->udata, ldata->type); + free(data); + efl_event_callback_del(ev->object, ev->desc, _selection_changed_cb, data); +} + +EAPI void +elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, Elm_Selection_Loss_Cb func, const void *data) +{ + Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data)); + + if (!ldata) return; + ldata->obj = obj; + ldata->type = type; + ldata->udata = (void *)data; + ldata->loss_cb = func; + efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_changed_cb, ldata); +} + +typedef struct { + Elm_Drop_Cb data_cb; + void *data; + Elm_Sel_Format format; +} Callback_Storage; + +static Eina_Value +_callback_storage_deliver(Eo *obj, void *data, const Eina_Value value) +{ + Callback_Storage *cb_storage = data; + Eina_Content *content = eina_value_to_content(&value); + Elm_Sel_Format format = _mime_type_to_elm_sel_format(eina_content_type_get(content)); + Eina_Slice cdata; + + cdata = eina_content_data_get(content); + Elm_Selection_Data d = { 0 }; + d.data = eina_memdup((unsigned char*)cdata.bytes, cdata.len, EINA_FALSE); + d.len = cdata.len; + d.format = _mime_type_to_elm_sel_format(eina_content_type_get(content)); + + if (cb_storage->data_cb) + { + cb_storage->data_cb(cb_storage->data, obj, &d); + } + else + { + EINA_SAFETY_ON_FALSE_RETURN_VAL(format == ELM_SEL_FORMAT_TEXT || format == ELM_SEL_FORMAT_MARKUP || format == ELM_SEL_FORMAT_HTML, EINA_VALUE_EMPTY); + + _elm_entry_entry_paste(obj, (const char *) d.data); + } + free(d.data); + + return EINA_VALUE_EMPTY; +} + +static Eina_Value +_callback_storage_error(Eo *obj EINA_UNUSED, void *data EINA_UNUSED, Eina_Error error) +{ + ERR("Content cound not be received because of %s.", eina_error_msg_get(error)); + return EINA_VALUE_EMPTY; +} + +static void +_callback_storage_free(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED) +{ + free(data); +} + +EAPI Eina_Bool +elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type selection, + Elm_Sel_Format format, + Elm_Drop_Cb data_cb, void *udata) +{ + Ecore_Evas *ee; + Eina_Array *mime_types; + Eina_Future *future; + Callback_Storage *storage; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + mime_types = _elm_sel_format_to_mime_type(format); + future = ecore_evas_selection_get(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), eina_array_iterator_new(mime_types)); + storage = calloc(1,sizeof(Callback_Storage)); + storage->data_cb = data_cb; + storage->data = udata; + storage->format = format; + + efl_future_then(obj, future, _callback_storage_deliver, _callback_storage_error, _callback_storage_free, EINA_VALUE_TYPE_CONTENT, storage); + + return EINA_TRUE; +} diff --git a/src/lib/elementary/elm_cnp.h b/src/lib/elementary/elm_cnp.h index 5feda3acc0..06346e40a5 100644 --- a/src/lib/elementary/elm_cnp.h +++ b/src/lib/elementary/elm_cnp.h @@ -43,8 +43,6 @@ * @{ */ -# include - /** * Event notifying that the selection has changed * @see Elm_Cnp_Event_Selection_Changed diff --git a/src/lib/elementary/elm_dnd.c b/src/lib/elementary/elm_dnd.c new file mode 100644 index 0000000000..699414bb4a --- /dev/null +++ b/src/lib/elementary/elm_dnd.c @@ -0,0 +1,812 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + + +#include +#include "elm_priv.h" + +int ELM_CNP_EVENT_SELECTION_CHANGED; + +typedef struct { + void *enter_data, *leave_data, *pos_data, *drop_data; + Elm_Drag_State enter_cb; + Elm_Drag_State leave_cb; + Elm_Drag_Pos pos_cb; + Elm_Drop_Cb drop_cb; + Eina_Array *mime_types; + Elm_Sel_Format format; + Elm_Xdnd_Action action; +} Elm_Drop_Target; + +static int +_default_seat(const Eo *obj) +{ + return evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT)); +} + +static const char* +_action_to_string(Elm_Xdnd_Action action) +{ + if (action == ELM_XDND_ACTION_COPY) return "copy"; + if (action == ELM_XDND_ACTION_MOVE) return "move"; + if (action == ELM_XDND_ACTION_PRIVATE) return "private"; + if (action == ELM_XDND_ACTION_ASK) return "ask"; + if (action == ELM_XDND_ACTION_LIST) return "list"; + if (action == ELM_XDND_ACTION_LINK) return "link"; + if (action == ELM_XDND_ACTION_DESCRIPTION) return "description"; + return "unknown"; +} + +static Elm_Xdnd_Action +_string_to_action(const char* action) +{ + if (eina_streq(action, "copy")) return ELM_XDND_ACTION_COPY; + else if (eina_streq(action, "move")) return ELM_XDND_ACTION_MOVE; + else if (eina_streq(action, "private")) return ELM_XDND_ACTION_PRIVATE; + else if (eina_streq(action, "ask")) return ELM_XDND_ACTION_ASK; + else if (eina_streq(action, "list")) return ELM_XDND_ACTION_LIST; + else if (eina_streq(action, "link")) return ELM_XDND_ACTION_LINK; + else if (eina_streq(action, "description")) return ELM_XDND_ACTION_DESCRIPTION; + return ELM_XDND_ACTION_UNKNOWN; +} + +static void +_enter_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + + if (target->enter_cb) + target->enter_cb(target->enter_data, ev->object); +} + +static void +_leave_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + + if (target->leave_cb) + target->leave_cb(target->leave_data, ev->object); +} + +static void +_pos_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + Efl_Ui_Drop_Event *event = ev->info; + + if (target->pos_cb) + target->pos_cb(target->pos_data, ev->object, event->position.x, event->position.y, target->action); //FIXME action +} + +static Eina_Value +_deliver_content(Eo *obj, void *data, const Eina_Value value) +{ + Elm_Drop_Target *target = data; + Elm_Selection_Data sel_data; + Eina_Content *content = eina_value_to_content(&value); + + sel_data.data = (void*)eina_content_data_get(content).mem; + sel_data.len = eina_content_data_get(content).len; + sel_data.action = target->action; + sel_data.format = target->format; + + if (target->drop_cb) + target->drop_cb(target->drop_data, obj, &sel_data); + + return EINA_VALUE_EMPTY; +} + +static void +_drop_cb(void *data, const Efl_Event *ev) +{ + Efl_Ui_Drop_Dropped_Event *event = ev->info; + Elm_Drop_Target *target = data; + target->action = _string_to_action(event->action); + efl_future_then(ev->object, efl_ui_dnd_drop_data_get(ev->object, _default_seat(ev->object), eina_array_iterator_new(target->mime_types)), + .success = _deliver_content, + .data = target + ); +} + +static void +_inv_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + elm_drop_target_del(ev->object, target->format, target->enter_cb, target->enter_data, target->leave_cb, + target->leave_data, target->pos_cb, target->pos_data, target->drop_cb, target->drop_data); +} + +EFL_CALLBACKS_ARRAY_DEFINE(drop_target_cb, + {EFL_UI_DND_EVENT_DROP_ENTERED, _enter_cb}, + {EFL_UI_DND_EVENT_DROP_LEFT, _leave_cb}, + {EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, _pos_cb}, + {EFL_UI_DND_EVENT_DROP_DROPPED, _drop_cb}, + {EFL_EVENT_INVALIDATE, _inv_cb} +) + +static Eina_Hash *target_register = NULL; + +static Eina_Array* +_format_to_mime_array(Elm_Sel_Format format) +{ + Eina_Array *ret = eina_array_new(10); + + if (format & ELM_SEL_FORMAT_TEXT) + eina_array_push(ret, "text/plain;charset=utf-8"); + if (format & ELM_SEL_FORMAT_MARKUP) + eina_array_push(ret, "application/x-elementary-markup"); + if (format & ELM_SEL_FORMAT_IMAGE) + { + eina_array_push(ret, "image/png"); + eina_array_push(ret, "image/jpeg"); + eina_array_push(ret, "image/x-ms-bmp"); + eina_array_push(ret, "image/gif"); + eina_array_push(ret, "image/tiff"); + eina_array_push(ret, "image/svg+xml"); + eina_array_push(ret, "image/x-xpixmap"); + eina_array_push(ret, "image/x-tga"); + eina_array_push(ret, "image/x-portable-pixmap"); + } + if (format & ELM_SEL_FORMAT_VCARD) + eina_array_push(ret, "text/vcard"); + if (format & ELM_SEL_FORMAT_HTML) + eina_array_push(ret, "text/html"); + + return ret; +} + +EAPI Eina_Bool +elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format, + Elm_Drag_State enter_cb, void *enter_data, + Elm_Drag_State leave_cb, void *leave_data, + Elm_Drag_Pos pos_cb, void *pos_data, + Elm_Drop_Cb drop_cb, void *drop_data) +{ + + Elm_Drop_Target *target = calloc(1, sizeof(Elm_Drop_Target)); + target->enter_cb = enter_cb; + target->enter_data = enter_data; + target->leave_cb = leave_cb; + target->leave_data = leave_data; + target->pos_cb = pos_cb; + target->pos_data = pos_data; + target->drop_cb = drop_cb; + target->drop_data = drop_data; + target->mime_types = _format_to_mime_array(format); + target->format = format; + + efl_event_callback_array_add(obj, drop_target_cb(), target); + + if (!target_register) + target_register = eina_hash_pointer_new(NULL); + eina_hash_list_append(target_register, &obj, target); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, + Elm_Drag_State enter_cb, void *enter_data, + Elm_Drag_State leave_cb, void *leave_data, + Elm_Drag_Pos pos_cb, void *pos_data, + Elm_Drop_Cb drop_cb, void *drop_data) +{ + Elm_Drop_Target *target; + Eina_List *n, *found = NULL; + + if (!target_register) + return EINA_TRUE; + Eina_List *targets = eina_hash_find(target_register, &obj); + + if (!targets) + return EINA_TRUE; + + EINA_LIST_FOREACH(targets, n, target) + { + if (target->enter_cb == enter_cb && target->enter_data == enter_data && + target->leave_cb == leave_cb && target->leave_data == leave_data && + target->pos_cb == pos_cb && target->pos_data == pos_data && + target->drop_cb == drop_cb && target->drop_data == drop_data && + target->format == format) + { + + found = n; + break; + } + } + if (found) + { + efl_event_callback_array_del(obj, drop_target_cb(), eina_list_data_get(found)); + eina_hash_list_remove(target_register, &obj, target); + eina_array_free(target->mime_types); + free(target); + } + + return EINA_TRUE; +} + +struct _Item_Container_Drag_Info +{ /* Info kept for containers to support drag */ + Evas_Object *obj; + Ecore_Timer *tm; /* When this expires, start drag */ + double anim_tm; /* Time period to set tm */ + double tm_to_drag; /* Time period to set tm */ + Elm_Xy_Item_Get_Cb itemgetcb; + Elm_Item_Container_Data_Get_Cb data_get; + + Evas_Coord x_down; /* Mouse down x cord when drag starts */ + Evas_Coord y_down; /* Mouse down y cord when drag starts */ + + /* Some extra information needed to impl default anim */ + Evas *e; + Eina_List *icons; /* List of icons to animate (Anim_Icon) */ + int final_icon_w; /* We need the w and h of the final icon for the animation */ + int final_icon_h; + Ecore_Animator *ea; + + Elm_Drag_User_Info user_info; +}; +typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info; + +struct _Anim_Icon +{ + int start_x; + int start_y; + int start_w; + int start_h; + Evas_Object *o; +}; +typedef struct _Anim_Icon Anim_Icon; +static Eina_List *cont_drag_tg = NULL; /* List of Item_Container_Drag_Info */ + +static Eina_Bool elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full); +static void _cont_obj_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); +static void _cont_obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); +static void _cont_obj_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info); + +static void +_cont_drag_done_cb(void *data, Evas_Object *obj EINA_UNUSED) +{ + Item_Container_Drag_Info *st = data; + elm_widget_scroll_freeze_pop(st->obj); + if (st->user_info.dragdone) + st->user_info.dragdone(st->user_info.donecbdata, NULL, EINA_FALSE); /*FIXME*/ +} + +static Eina_Bool +_cont_obj_drag_start(void *data) +{ /* Start a drag-action when timer expires */ + Item_Container_Drag_Info *st = data; + st->tm = NULL; + Elm_Drag_User_Info *info = &st->user_info; + if (info->dragstart) info->dragstart(info->startcbdata, st->obj); + elm_widget_scroll_freeze_push(st->obj); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + elm_drag_start( /* Commit the start only if data_get successful */ + st->obj, info->format, + info->data, info->action, + info->createicon, info->createdata, + info->dragpos, info->dragdata, + info->acceptcb, info->acceptdata, + _cont_drag_done_cb, st); + ELM_SAFE_FREE(info->data, free); + + return ECORE_CALLBACK_CANCEL; +} + +static inline Eina_List * +_anim_icons_make(Eina_List *icons) +{ /* Make local copies of all icons, add them to list */ + Eina_List *list = NULL, *itr; + Evas_Object *o; + + EINA_LIST_FOREACH(icons, itr, o) + { /* Now add icons to animation window */ + Anim_Icon *st = calloc(1, sizeof(*st)); + + if (!st) + { + ERR("Failed to allocate memory for icon!"); + continue; + } + + evas_object_geometry_get(o, &st->start_x, &st->start_y, &st->start_w, &st->start_h); + evas_object_show(o); + st->o = o; + list = eina_list_append(list, st); + } + + return list; +} + +static Eina_Bool +_drag_anim_play(void *data, double pos) +{ /* Impl of the animation of icons, called on frame time */ + Item_Container_Drag_Info *st = data; + Eina_List *l; + Anim_Icon *sti; + + if (st->ea) + { + if (pos > 0.99) + { + st->ea = NULL; /* Avoid deleting on mouse up */ + EINA_LIST_FOREACH(st->icons, l, sti) + evas_object_hide(sti->o); + + _cont_obj_drag_start(st); /* Start dragging */ + return ECORE_CALLBACK_CANCEL; + } + + Evas_Coord xm, ym; + evas_pointer_canvas_xy_get(st->e, &xm, &ym); + EINA_LIST_FOREACH(st->icons, l, sti) + { + int x, y, h, w; + w = sti->start_w + ((st->final_icon_w - sti->start_w) * pos); + h = sti->start_h + ((st->final_icon_h - sti->start_h) * pos); + x = sti->start_x - (pos * ((sti->start_x + (w/2) - xm))); + y = sti->start_y - (pos * ((sti->start_y + (h/2) - ym))); + evas_object_move(sti->o, x, y); + evas_object_resize(sti->o, w, h); + } + + return ECORE_CALLBACK_RENEW; + } + + return ECORE_CALLBACK_CANCEL; +} + +static inline Eina_Bool +_drag_anim_start(void *data) +{ /* Start default animation */ + Item_Container_Drag_Info *st = data; + + st->tm = NULL; + /* Now we need to build an (Anim_Icon *) list */ + st->icons = _anim_icons_make(st->user_info.icons); + if (st->user_info.createicon) + { + Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_DND); + Evas_Object *final_icon = st->user_info.createicon(st->user_info.createdata, temp_win, NULL, NULL); + evas_object_geometry_get(final_icon, NULL, NULL, &st->final_icon_w, &st->final_icon_h); + evas_object_del(final_icon); + evas_object_del(temp_win); + } + st->ea = ecore_animator_timeline_add(st->anim_tm, _drag_anim_play, st); + + return EINA_FALSE; +} + +static Eina_Bool +_cont_obj_anim_start(void *data) +{ /* Start a drag-action when timer expires */ + Item_Container_Drag_Info *st = data; + int xposret, yposret; /* Unused */ + Elm_Object_Item *it = (st->itemgetcb) ? + (st->itemgetcb(st->obj, st->x_down, st->y_down, &xposret, &yposret)) + : NULL; + + st->tm = NULL; + st->user_info.format = ELM_SEL_FORMAT_TARGETS; /* Default */ + st->icons = NULL; + st->user_info.data = NULL; + st->user_info.action = ELM_XDND_ACTION_COPY; /* Default */ + + if (!it) /* Failed to get mouse-down item, abort drag */ + return ECORE_CALLBACK_CANCEL; + + if (st->data_get) + { /* collect info then start animation or start dragging */ + if (st->data_get( /* Collect drag info */ + st->obj, /* The container object */ + it, /* Drag started on this item */ + &st->user_info)) + { + if (st->user_info.icons) + _drag_anim_start(st); + else + { + if (st->anim_tm) + { + // even if we don't manage the icons animation, we have + // to wait until it is finished before beginning drag. + st->tm = ecore_timer_add(st->anim_tm, _cont_obj_drag_start, st); + } + else + _cont_obj_drag_start(st); /* Start dragging, no anim */ + } + } + } + + return ECORE_CALLBACK_CANCEL; +} + +static int +_drag_item_container_cmp(const void *d1, + const void *d2) +{ + const Item_Container_Drag_Info *st = d1; + return (((uintptr_t) (st->obj)) - ((uintptr_t) d2)); +} + +void +_anim_st_free(Item_Container_Drag_Info *st) +{ /* Stops and free mem of ongoing animation */ + if (st) + { + ELM_SAFE_FREE(st->ea, ecore_animator_del); + Anim_Icon *sti; + + EINA_LIST_FREE(st->icons, sti) + { + evas_object_del(sti->o); + free(sti); + } + + st->icons = NULL; + } +} + +static void +_cont_obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Cancel any drag waiting to start on timeout */ + Item_Container_Drag_Info *st = data; + + if (((Evas_Event_Mouse_Up *)event_info)->button != 1) + return; /* We only process left-click at the moment */ + + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st); + + ELM_SAFE_FREE(st->tm, ecore_timer_del); + + _anim_st_free(st); +} + +static void +_cont_obj_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Cancel any drag waiting to start on timeout */ + if (((Evas_Event_Mouse_Move *)event_info)->event_flags & EVAS_EVENT_FLAG_ON_HOLD) + { + Item_Container_Drag_Info *st = data; + + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st); + elm_drag_item_container_del_internal(obj, EINA_FALSE); + + ELM_SAFE_FREE(st->tm, ecore_timer_del); + + _anim_st_free(st); + } +} + +static Eina_Bool +elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full) +{ + Item_Container_Drag_Info *st = + eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj); + + if (st) + { + ELM_SAFE_FREE(st->tm, ecore_timer_del); /* Cancel drag-start timer */ + + if (st->ea) /* Cancel ongoing default animation */ + _anim_st_free(st); + + if (full) + { + st->itemgetcb = NULL; + st->data_get = NULL; + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_MOUSE_DOWN, _cont_obj_mouse_down, st); + + cont_drag_tg = eina_list_remove(cont_drag_tg, st); + ELM_SAFE_FREE(st->user_info.data, free); + free(st); + } + + return EINA_TRUE; + } + return EINA_FALSE; +} + +static void +_cont_obj_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Launch a timer to start dragging */ + Evas_Event_Mouse_Down *ev = event_info; + if (ev->button != 1) + return; /* We only process left-click at the moment */ + + Item_Container_Drag_Info *st = data; + evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_MOVE, + _cont_obj_mouse_move, st); + + evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_UP, + _cont_obj_mouse_up, st); + + ecore_timer_del(st->tm); + + st->e = e; + st->x_down = ev->canvas.x; + st->y_down = ev->canvas.y; + st->tm = ecore_timer_add(st->tm_to_drag, _cont_obj_anim_start, st); +} +EAPI Eina_Bool +elm_drag_item_container_del(Evas_Object *obj) +{ + return elm_drag_item_container_del_internal(obj, EINA_TRUE); +} + +EAPI Eina_Bool +elm_drag_item_container_add(Evas_Object *obj, + double anim_tm, + double tm_to_drag, + Elm_Xy_Item_Get_Cb itemgetcb, + Elm_Item_Container_Data_Get_Cb data_get) +{ + Item_Container_Drag_Info *st; + + if (elm_drag_item_container_del_internal(obj, EINA_FALSE)) + { /* Updating info of existing obj */ + st = eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj); + if (!st) return EINA_FALSE; + } + else + { + st = calloc(1, sizeof(*st)); + if (!st) return EINA_FALSE; + + st->obj = obj; + cont_drag_tg = eina_list_append(cont_drag_tg, st); + + /* Register for mouse callback for container to start/abort drag */ + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, + _cont_obj_mouse_down, st); + } + + st->tm = NULL; + st->anim_tm = anim_tm; + st->tm_to_drag = tm_to_drag; + st->itemgetcb = itemgetcb; + st->data_get = data_get; + return EINA_TRUE; +} + +static Eina_List *cont_drop_tg = NULL; /* List of Item_Container_Drop_Info */ + +struct _Item_Container_Drop_Info +{ /* Info kept for containers to support drop */ + Evas_Object *obj; + Elm_Xy_Item_Get_Cb itemgetcb; + Elm_Drop_Item_Container_Cb dropcb; + Elm_Drag_Item_Container_Pos poscb; +}; +typedef struct _Item_Container_Drop_Info Item_Container_Drop_Info; + + +typedef struct +{ + Evas_Object *obj; + /* FIXME: Cache window */ + Eina_Inlist *cbs_list; /* List of Dropable_Cbs * */ + struct { + Evas_Coord x, y; + Eina_Bool in : 1; + const char *type; + Elm_Sel_Format format; + } last; +} Dropable; + +static int +_drop_item_container_cmp(const void *d1, + const void *d2) +{ + const Item_Container_Drop_Info *st = d1; + return (((uintptr_t) (st->obj)) - ((uintptr_t) d2)); +} + +static void +_elm_item_container_pos_cb(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action) +{ /* obj is the container pointer */ + Elm_Object_Item *it = NULL; + int xposret = 0; + int yposret = 0; + + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st && st->poscb) + { /* Call container drop func with specific item pointer */ + int xo = 0; + int yo = 0; + + evas_object_geometry_get(obj, &xo, &yo, NULL, NULL); + if (st->itemgetcb) + it = st->itemgetcb(obj, x+xo, y+yo, &xposret, &yposret); + + st->poscb(data, obj, it, x, y, xposret, yposret, action); + } +} + +static Eina_Bool +_elm_item_container_drop_cb(void *data, Evas_Object *obj , Elm_Selection_Data *ev) +{ /* obj is the container pointer */ + Elm_Object_Item *it = NULL; + int xposret = 0; + int yposret = 0; + + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st && st->dropcb) + { /* Call container drop func with specific item pointer */ + int xo = 0; + int yo = 0; + + evas_object_geometry_get(obj, &xo, &yo, NULL, NULL); + if (st->itemgetcb) + it = st->itemgetcb(obj, ev->x+xo, ev->y+yo, &xposret, &yposret); + + return st->dropcb(data, obj, it, ev, xposret, yposret); + } + + return EINA_FALSE; +} + +static Eina_Bool +elm_drop_item_container_del_internal(Evas_Object *obj, Eina_Bool full) +{ + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st) + { + // temp until st is stored inside data of obj. + //FIXME delete this drop container + st->itemgetcb= NULL; + st->poscb = NULL; + st->dropcb = NULL; + + if (full) + { + cont_drop_tg = eina_list_remove(cont_drop_tg, st); + free(st); + } + + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EAPI Eina_Bool +elm_drop_item_container_add(Evas_Object *obj, + Elm_Sel_Format format, + Elm_Xy_Item_Get_Cb itemgetcb, + Elm_Drag_State entercb, void *enterdata, + Elm_Drag_State leavecb, void *leavedata, + Elm_Drag_Item_Container_Pos poscb, void *posdata, + Elm_Drop_Item_Container_Cb dropcb, void *dropdata) +{ + Item_Container_Drop_Info *st; + + if (elm_drop_item_container_del_internal(obj, EINA_FALSE)) + { /* Updating info of existing obj */ + st = eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + if (!st) return EINA_FALSE; + } + else + { + st = calloc(1, sizeof(*st)); + if (!st) return EINA_FALSE; + + st->obj = obj; + cont_drop_tg = eina_list_append(cont_drop_tg, st); + } + + st->itemgetcb = itemgetcb; + st->poscb = poscb; + st->dropcb = dropcb; + elm_drop_target_add(obj, format, + entercb, enterdata, + leavecb, leavedata, + _elm_item_container_pos_cb, posdata, + _elm_item_container_drop_cb, dropdata); + return EINA_TRUE; +} + + +EAPI Eina_Bool +elm_drop_item_container_del(Evas_Object *obj) +{ + return elm_drop_item_container_del_internal(obj, EINA_TRUE); +} + +typedef struct { + void *dragdata, *acceptdata, *donecbdata; + Elm_Drag_Pos dragposcb; + Elm_Drag_Accept acceptcb; + Elm_Drag_State dragdonecb; +} Elm_Drag_Data; + +static void +_drag_finished_cb(void *data, const Efl_Event *ev) +{ + Elm_Drag_Data *dd = data; + Eina_Bool *accepted = ev->info; + + if (dd->acceptcb) + dd->acceptcb(dd->acceptdata, ev->object, *accepted); + + if (dd->dragdonecb) + dd->dragdonecb(dd->donecbdata, ev->object); + + efl_event_callback_del(ev->object, EFL_UI_DND_EVENT_DRAG_FINISHED, _drag_finished_cb, dd); + free(dd); +} + +EAPI Eina_Bool +elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, + const char *data, Elm_Xdnd_Action action, + Elm_Drag_Icon_Create_Cb createicon, + void *createdata, + Elm_Drag_Pos dragpos, void *dragdata, + Elm_Drag_Accept acceptcb, void *acceptdata, + Elm_Drag_State dragdone, void *donecbdata) +{ + Eina_Array *mime_types; + Eina_Content *content; + Efl_Content *ui; + int x, y, w, h; + Efl_Ui_Widget *widget; + Elm_Drag_Data *dd; + const char *str_action; + + str_action = _action_to_string(action); + dd = calloc(1, sizeof(Elm_Drag_Data)); + dd->dragposcb = dragpos; + dd->dragdata = dragdata; + dd->acceptcb = acceptcb; + dd->acceptdata = acceptdata; + dd->dragdonecb = dragdone; + dd->donecbdata = donecbdata; + mime_types = _format_to_mime_array(format); + if (eina_array_count(mime_types) != 1) + { + WRN("You passed more than one format, this is not going to work well"); + } + content = eina_content_new((Eina_Slice) EINA_SLICE_STR_FULL(data), eina_array_data_get(mime_types, 0)); + ui = efl_ui_dnd_drag_start(obj, content, str_action, _default_seat(obj)); + widget = createicon(createdata, ui, &x, &y); + evas_object_geometry_get(widget, NULL, NULL, &w, &h); + evas_object_show(widget); + efl_content_set(ui, widget); + efl_gfx_entity_size_set(ui, EINA_SIZE2D(w, h)); + eina_array_free(mime_types); + + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_FINISHED, _drag_finished_cb, dd); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drag_cancel(Evas_Object *obj) +{ + efl_ui_dnd_drag_cancel(obj, _default_seat(obj)); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drag_action_set(Evas_Object *obj EINA_UNUSED, Elm_Xdnd_Action action EINA_UNUSED) +{ + ERR("This operation is not supported anymore."); + return EINA_FALSE; +} diff --git a/src/lib/elementary/elm_entry.c b/src/lib/elementary/elm_entry.c index ab1f11544b..e3a81dea76 100644 --- a/src/lib/elementary/elm_entry.c +++ b/src/lib/elementary/elm_entry.c @@ -708,7 +708,7 @@ _selection_data_cb(void *data EINA_UNUSED, char *entry_tag; int len; static const char *tag_string = - ""; + ""; len = strlen(tag_string) + strlen(buf); entry_tag = alloca(len + 1); @@ -1628,7 +1628,7 @@ _selection_store(Elm_Sel_Type seltype, if ((!sel) || (!sel[0])) return; /* avoid deleting our own selection */ elm_cnp_selection_set - (obj, seltype, ELM_SEL_FORMAT_MARKUP, sel, strlen(sel)); + (obj, seltype, ELM_SEL_FORMAT_MARKUP, sel, strlen(sel) + 1); elm_cnp_selection_loss_callback_set(obj, seltype, _selection_clear, obj); if (seltype == ELM_SEL_TYPE_CLIPBOARD) eina_stringshare_replace(&sd->cut_sel, sel); @@ -1731,7 +1731,7 @@ _menu_call(Evas_Object *obj) const char *context_menu_orientation; Eina_Bool ownersel; - ownersel = elm_selection_selection_has_owner(obj); + ownersel = elm_cnp_clipboard_selection_has_owner(obj); if (!sd->items) { /* prevent stupid blank hoversel */ diff --git a/src/lib/elementary/elm_main.c b/src/lib/elementary/elm_main.c index d1d0c4a183..4bf652077b 100644 --- a/src/lib/elementary/elm_main.c +++ b/src/lib/elementary/elm_main.c @@ -910,7 +910,6 @@ elm_quicklaunch_sub_shutdown(void) _elm_module_shutdown(); if (_elm_prefs_initted) _elm_prefs_shutdown(); - _efl_ui_dnd_shutdown(); elm_color_class_shutdown(); } diff --git a/src/lib/elementary/elm_priv.h b/src/lib/elementary/elm_priv.h index 90b90fc40d..8cfc7c952a 100644 --- a/src/lib/elementary/elm_priv.h +++ b/src/lib/elementary/elm_priv.h @@ -165,7 +165,6 @@ # include "efl_ui_focus_parent_provider.eo.h" # include "efl_ui_focus_parent_provider_standard.eo.h" -# include "efl_ui_selection_manager.eo.h" # include "efl_datetime_manager.eo.h" extern const char *_efl_model_property_itemw; @@ -668,9 +667,6 @@ void _elm_prefs_data_init(void); void _elm_prefs_data_shutdown(void); /* init functions for dnd and cnp */ -Eo* _efl_ui_selection_manager_get(Eo *obj); -void _efl_ui_dnd_shutdown(void); - int _elm_ews_wm_init(void); void _elm_ews_wm_shutdown(void); void _elm_ews_wm_rescale(Elm_Theme *th, @@ -1060,4 +1056,10 @@ typedef struct Efl_Ui_Shared_Win_Data* efl_ui_win_shared_data_get(Efl_Ui_Win *win); +void _selection_changed_event_register(Eo *obj); +void _selection_changed_event_unregister(Eo *obj); +void _drop_event_register(Eo *obj); +void _drop_event_unregister(Eo *obj); +void _register_selection_changed(Efl_Ui_Selection *selection); + #endif diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index 0cb3fc7db9..6dea02ed9f 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -142,7 +142,6 @@ pub_eo_files = [ 'elm_code_widget.eo', 'efl_ui_selection.eo', 'efl_ui_dnd.eo', - 'efl_ui_dnd_container.eo', 'efl_ui_focus_manager_window_root.eo', 'efl_ui_spotlight_container.eo', 'efl_ui_spotlight_manager.eo', @@ -210,8 +209,6 @@ endforeach pub_eo_types_files = [ 'elm_general.eot', 'efl_ui.eot', - 'efl_ui_selection_types.eot', - 'efl_ui_dnd_types.eot' ] foreach eo_file : pub_eo_types_files @@ -235,7 +232,6 @@ priv_eo_files = [ 'efl_ui_focus_parent_provider.eo', 'efl_ui_focus_parent_provider_standard.eo', 'efl_ui_state_model.eo', - 'efl_ui_selection_manager.eo', 'efl_datetime_manager.eo', 'efl_ui_size_model.eo', 'efl_ui_homogeneous_model.eo', @@ -785,6 +781,8 @@ elementary_src = [ 'elm_icon.c', 'efl_ui_image.c', 'elm_index.c', + 'elm_cnp.c', + 'elm_dnd.c', 'efl_access_object.c', 'efl_access_action.c', 'efl_access_component.c', @@ -907,7 +905,6 @@ elementary_src = [ 'efl_ui_scroller.c', 'efl_ui_scroll_manager.c', 'efl_ui_pan.c', - 'efl_ui_selection_manager.c', 'efl_ui_selection_manager_private.h', 'efl_ui_selection.c', 'efl_datetime_manager.c', diff --git a/src/lib/eo/eina_types.eot b/src/lib/eo/eina_types.eot index bff83968c1..106aa0885d 100644 --- a/src/lib/eo/eina_types.eot +++ b/src/lib/eo/eina_types.eot @@ -60,6 +60,8 @@ struct @extern Eina.Matrix3 { zz: double; [[ZZ value.]] } +struct @extern Eina.Content; + struct @extern Eina.Matrix4 { [[A bidimensional array of floating point values with 4 rows and 4 columns. diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c index 95d0f36bd0..9aa455553d 100644 --- a/src/lib/evas/canvas/evas_main.c +++ b/src/lib/evas/canvas/evas_main.c @@ -120,6 +120,21 @@ _efl_gfx_image_load_error_to_evas_load_error(Eina_Error err) return EVAS_LOAD_ERROR_GENERIC; } +static Eina_Content* +_markup_to_utf8(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + char *utf8 = evas_textblock_text_markup_to_utf8(NULL, slice.mem); + return eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(utf8), to_type); +} + +static Eina_Content* +_utf8_to_markup(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + char *markup = evas_textblock_text_utf8_to_markup(NULL, slice.mem); + return eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(markup), to_type); +} EAPI int evas_init(void) @@ -179,6 +194,9 @@ evas_init(void) _efl_gfx_image_load_error_init(); + eina_content_converter_conversion_register("application/x-elementary-markup", "text/plain;charset=utf-8", _markup_to_utf8); + eina_content_converter_conversion_register("text/plain;charset=utf-8", "application/x-elementary-markup", _utf8_to_markup); + return _evas_init_count; shutdown_filter: diff --git a/src/tests/elementary/efl_ui_test_text.c b/src/tests/elementary/efl_ui_test_text.c index b7886544f1..0944afa0ef 100644 --- a/src/tests/elementary/efl_ui_test_text.c +++ b/src/tests/elementary/efl_ui_test_text.c @@ -44,6 +44,12 @@ EFL_START_TEST(text_cnp) } EFL_END_TEST +static void +_stop_event_soon(void *data EINA_UNUSED, const Efl_Event *ev) +{ + efl_event_callback_stop(ev->object); +} + EFL_START_TEST(text_all_select_all_unselect) { Eo *txt; @@ -57,7 +63,7 @@ EFL_START_TEST(text_all_select_all_unselect) efl_event_callback_add(efl_added, EFL_TEXT_INTERACTIVE_EVENT_SELECTION_CHANGED, increment_int_changed, &i_selection) ); - + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_text_set(txt, "Hello"); efl_text_interactive_all_select(txt); Efl_Text_Cursor *c1=NULL, *c2 =NULL; @@ -122,6 +128,7 @@ EFL_START_TEST(text_selection) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello"); get_me_to_those_events(txt); @@ -160,7 +167,7 @@ EFL_START_TEST(text_user_change) txt = efl_add(EFL_UI_TEXTBOX_CLASS, win, efl_event_callback_add(efl_added, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, user_changed, &info) ); - + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_text_set(txt, "Hello"); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_interactive_all_select(txt); @@ -177,6 +184,7 @@ EFL_START_TEST(text_scroll_mode) Eo *txt, *win, *cur; win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); cur = efl_text_interactive_main_cursor_get(txt); efl_text_set(txt, "Hello"); /*scroll mode is false by default*/ @@ -199,6 +207,7 @@ EFL_START_TEST(text_change_event) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello"); int i_changed = 0; @@ -223,6 +232,7 @@ EFL_START_TEST(text_keys_handler) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello"); From 06b793351274db94149a3199211d26e9a3e1fee2 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Fri, 14 Feb 2020 14:09:21 +0100 Subject: [PATCH 08/17] ecore_cocoa: change clipboard API the new API works with mimetypes, so we can remove the cnp types from Ecore_Cocoa.h and just forward the types from ecore_evas directly Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11350 --- src/lib/ecore_cocoa/Ecore_Cocoa.h | 36 +++++----------- src/lib/ecore_cocoa/ecore_cocoa_cnp.m | 61 +++++++++++++-------------- 2 files changed, 40 insertions(+), 57 deletions(-) diff --git a/src/lib/ecore_cocoa/Ecore_Cocoa.h b/src/lib/ecore_cocoa/Ecore_Cocoa.h index 36f17b490b..ca0a835be2 100644 --- a/src/lib/ecore_cocoa/Ecore_Cocoa.h +++ b/src/lib/ecore_cocoa/Ecore_Cocoa.h @@ -196,22 +196,6 @@ struct _Ecore_Cocoa_Event_Window_Destroy Ecore_Cocoa_Object *cocoa_window; /**< Handler of the Cocoa window */ }; -/** - * @typedef Ecore_Cocoa_Cnp_Type - * Type used to interact with the Cocoa pasteboard. - * It holds types that can apply to a context. - * @since 1.18 - */ -typedef enum -{ - ECORE_COCOA_CNP_TYPE_UNKNOWN = 0, /**< Undefined type */ - ECORE_COCOA_CNP_TYPE_STRING = (1 << 0), /**< String type (pure text) */ - ECORE_COCOA_CNP_TYPE_MARKUP = (1 << 1), /**< Elementary markup */ - ECORE_COCOA_CNP_TYPE_IMAGE = (1 << 2), /**< Image (all formats) */ - ECORE_COCOA_CNP_TYPE_HTML = (1 << 3) /**< HTML */ -} Ecore_Cocoa_Cnp_Type; - - /*============================================================================* * Core * *============================================================================*/ @@ -561,27 +545,22 @@ EAPI void ecore_cocoa_terminate_cb_set(Ecore_Cocoa_Terminate_Cb cb) * Sets the clipboard of Cocoa (NSPasteboard) * @param data The contents to be set in the clipboard * @param size The size in bytes of @c data - * @param type + * @param mine_type * @return EINA_TRUE on success, EINA_FALSE on failure */ EAPI Eina_Bool ecore_cocoa_clipboard_set(const void *data, - int size, - Ecore_Cocoa_Cnp_Type type); + int size, + const char *mime_type); /* * Gets the contents of the Cocoa clipboard * @param size Pointer used to retrieve the size of the received contents - * @param type The type of object to retrieve from the clipboard - * @param retrieved_types The types of objects retrieved from the clipboard + * @param mine_type The type of object to retrieve from the clipboard * @return The data retrieved from the clipboard. NULL on failure * - * If @c type was ECORE_COCOA_CNP_TYPE_STRING or ECORE_COCOA_CNP_TYPE_MARKUP, - * @c retrieved_types will contain ECORE_COCOA_CNP_TYPE_STRING and the data - * will be a C string (char*) that must be freed after use. */ EAPI void *ecore_cocoa_clipboard_get(int *size, - Ecore_Cocoa_Cnp_Type type, - Ecore_Cocoa_Cnp_Type *retrieved_types) + const char *mime_type) EINA_WARN_UNUSED_RESULT; /* @@ -589,6 +568,11 @@ EAPI void *ecore_cocoa_clipboard_get(int *size, */ EAPI void ecore_cocoa_clipboard_clear(void); +/* + * Returns true when the clipboard contains data that can be received. + */ +EAPI Eina_Bool ecore_cocoa_clipboard_exists(void); + #endif /* EFL_BETA_API_SUPPORT */ #ifdef __cplusplus diff --git a/src/lib/ecore_cocoa/ecore_cocoa_cnp.m b/src/lib/ecore_cocoa/ecore_cocoa_cnp.m index c5fd22e99d..fabfc8c5a5 100644 --- a/src/lib/ecore_cocoa/ecore_cocoa_cnp.m +++ b/src/lib/ecore_cocoa/ecore_cocoa_cnp.m @@ -9,16 +9,17 @@ #import "ecore_cocoa_app.h" EAPI Eina_Bool -ecore_cocoa_clipboard_set(const void *data, - int size, - Ecore_Cocoa_Cnp_Type type) +ecore_cocoa_clipboard_set(const void *data, + int size, + const char *raw_mime_type) { NSMutableArray *objects; NSString *str = nil; BOOL ok = YES; + NSString *mime_type = [NSString stringWithUTF8String:raw_mime_type]; objects = [[NSMutableArray alloc] init]; - if (type & ECORE_COCOA_CNP_TYPE_STRING) + if ([mime_type hasPrefix:@"text/"]) { str = [[NSString alloc] initWithBytes: data length: size @@ -26,18 +27,9 @@ ecore_cocoa_clipboard_set(const void *data, if (str) [objects addObject: str]; } - if (type & ECORE_COCOA_CNP_TYPE_MARKUP) + else { - WRN("Markup CNP: NOT IMPLEMENTED"); - } - - if (type & ECORE_COCOA_CNP_TYPE_IMAGE) - { - WRN("Image CNP: NOT IMPLEMENTED"); - } - if (type & ECORE_COCOA_CNP_TYPE_HTML) - { - WRN("HTML CNP: NOT IMPLEMENTED"); + ERR("Mimetype %s is not handled yet", raw_mime_type); } /* Write to pasteboard */ @@ -54,35 +46,45 @@ ecore_cocoa_clipboard_set(const void *data, return (ok) ? EINA_TRUE : EINA_FALSE; } +EAPI Eina_Bool +ecore_cocoa_clipboard_exists(void) +{ + NSDictionary *options; + NSPasteboard *pb; + NSArray *items; + NSMutableArray *classes; + + classes = [[NSMutableArray alloc] init]; + [classes addObject: [NSString class]]; // we only support strings for now + pb = [NSPasteboard generalPasteboard]; + options = [NSDictionary dictionary]; + return [pb canReadItemWithDataConformingToTypes: classes]; +} EAPI void * -ecore_cocoa_clipboard_get(int *size, - Ecore_Cocoa_Cnp_Type type, - Ecore_Cocoa_Cnp_Type *retrieved_types) +ecore_cocoa_clipboard_get(int *size, + const char *raw_mime_type) { NSMutableArray *classes; - void *data; + void *data = NULL; NSDictionary *options; NSPasteboard *pb; NSArray *items; unsigned int len; BOOL string_class = NO; - Ecore_Cocoa_Cnp_Type types = 0; + NSString *mime_type = [NSString stringWithUTF8String:raw_mime_type]; classes = [[NSMutableArray alloc] init]; - if (type & ECORE_COCOA_CNP_TYPE_STRING) + if ([mime_type hasPrefix:@"text/"]) { string_class = YES; [classes addObject: [NSString class]]; } - if (type & ECORE_COCOA_CNP_TYPE_IMAGE) + else { - WRN("Image CNP: NOT IMPLEMENTED"); - } - if (type & ECORE_COCOA_CNP_TYPE_HTML) - { - WRN("HTML CNP: NOT IMPLEMENTED"); + ERR("Mimetype %s is not handled yet", raw_mime_type); + goto fail; } if ([classes count] <= 0) @@ -120,7 +122,6 @@ ecore_cocoa_clipboard_get(int *size, (const char *)data, len); goto remove_fail; } - types |= ECORE_COCOA_CNP_TYPE_STRING; #if 0 if (type & ECORE_COCOA_CNP_TYPE_MARKUP) @@ -139,7 +140,7 @@ ecore_cocoa_clipboard_get(int *size, #endif } - if (!types) + if (!data) { ERR("No types retrieved!"); goto remove_fail; @@ -148,14 +149,12 @@ ecore_cocoa_clipboard_get(int *size, [classes removeAllObjects]; if (size) *size = len; - if (retrieved_types) *retrieved_types = types; return data; remove_fail: [classes removeAllObjects]; fail: if (size) *size = 0; - if (retrieved_types) *retrieved_types = 0; return NULL; } From c731cf56d5d242441d029907ea749ada6eb32ed6 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Fri, 14 Feb 2020 14:10:44 +0100 Subject: [PATCH 09/17] ecore_evas: Introduce cnp support for cocoa with this commit you can do limited cnp for cocoa. You still cannot copy and paste pictures or markup arround, only text is supported so far. However, text on its own works quite stable and good. Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11351 --- .../engines/cocoa/ecore_evas_cocoa.c | 137 +++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c b/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c index e1c5a66670..3352efb135 100644 --- a/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c +++ b/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c @@ -34,6 +34,11 @@ static Ecore_Event_Handler *ecore_evas_event_handlers[4]; static const char *_iface_name = "opengl_cocoa"; static const int _iface_version = 1; +typedef struct { + Ecore_Evas_Selection_Callbacks clipboard; + Eina_Future *delivery; +} Ecore_Evas_Cocoa_Engine_Data; + static inline Ecore_Evas * _ecore_evas_cocoa_match(Ecore_Cocoa_Object *cocoa_win) { @@ -422,6 +427,125 @@ _ecore_evas_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func ee->func.fn_delete_request = func; } +static Eina_Value +_delivery(void *data, const Eina_Value value EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED) +{ + Ecore_Evas *ee = data; + Ecore_Evas_Cocoa_Engine_Data *edata = ee->engine.data; + Eina_Rw_Slice slice; + const char *mime_type = NULL; + + EINA_SAFETY_ON_NULL_GOTO(edata->delivery, end); + + for (unsigned int i = 0; i < eina_array_count(edata->clipboard.available_types); ++i) + { + mime_type = eina_array_data_get(edata->clipboard.available_types, i); + if (!strncmp("text/", mime_type, strlen("text/"))) + break; + } + if (mime_type) + { + edata->clipboard.delivery(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER, mime_type, &slice); + EINA_SAFETY_ON_FALSE_GOTO(ecore_cocoa_clipboard_set(slice.mem, slice.len, mime_type), end); + } + else + { + ERR("No compatible mime type found"); + } + +end: + return EINA_VALUE_EMPTY; +} + +static Eina_Bool +_ecore_evas_cocoa_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +{ + if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return EINA_FALSE; + + if (!delivery && !cancel) + { + ecore_cocoa_clipboard_clear(); + return EINA_TRUE; + } + else + { + Ecore_Evas_Cocoa_Engine_Data *edata = ee->engine.data; + + if (edata->clipboard.cancel) + { + edata->clipboard.cancel(ee, seat, selection); + eina_array_free(edata->clipboard.available_types); + } + + edata->delivery = efl_loop_job(efl_main_loop_get()); + eina_future_then(edata->delivery, _delivery, ee); + edata->clipboard.delivery = delivery; + edata->clipboard.cancel = cancel; + edata->clipboard.available_types = available_types; + return EINA_TRUE; + } +} + +Eina_Future* +_ecore_evas_cocoa_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type) +{ + Eina_Future *future; + Eina_Promise *promise; + const char *mime_type; + + if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return eina_future_rejected(efl_loop_future_scheduler_get(efl_main_loop_get()), ecore_evas_no_selection); + + promise = efl_loop_promise_new(efl_main_loop_get()); + future = eina_future_new(promise); + + for (unsigned int i = 0; i < eina_array_count(acceptable_type); ++i) + { + mime_type = eina_array_data_get(acceptable_type, i); + if (!strncmp("text/", mime_type, strlen("text/"))) + break; + } + if (!mime_type) + { + eina_promise_reject(promise, ecore_evas_no_matching_type); + } + else + { + int size; + void *data; + Eina_Content *content; + Eina_Rw_Slice slice; + + data = ecore_cocoa_clipboard_get(&size, mime_type); + if (!strncmp(mime_type, "text", strlen("text"))) + { + //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. + slice.len = size + 1; + slice.mem = eina_memdup(data, size, EINA_TRUE); + } + else + { + slice.len = size; + slice.mem = data; + } + content = eina_content_new(eina_rw_slice_slice_get(slice), mime_type); + if (!content) // construction can fail because of some validation reasons + eina_promise_reject(promise, ecore_evas_no_matching_type); + else + eina_promise_resolve(promise, eina_value_content_init(content)); + } + return future; +} + +static Eina_Bool +_ecore_evas_cocoa_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection EINA_UNUSED) +{ + if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return ecore_cocoa_clipboard_exists(); + return EINA_FALSE; +} + static Ecore_Evas_Engine_Func _ecore_cocoa_engine_func = { _ecore_evas_cocoa_free, @@ -508,6 +632,11 @@ static Ecore_Evas_Engine_Func _ecore_cocoa_engine_func = NULL, //fn_pointer_device_xy_get NULL, //fn_prepare NULL, //fn_last_tick_get + _ecore_evas_cocoa_selection_claim, //fn_selection_claim + _ecore_evas_cocoa_selection_has_owner, //fn_selection_has_owner + _ecore_evas_cocoa_selection_request, //fn_selection_request + NULL, //fn_dnd_start + NULL, //fn_dnd_stop }; static Ecore_Cocoa_Window * @@ -517,11 +646,11 @@ _ecore_evas_cocoa_window_get(const Ecore_Evas *ee) return (Ecore_Cocoa_Window *)(ee->prop.window); } - EAPI Ecore_Evas * ecore_evas_cocoa_new_internal(Ecore_Cocoa_Window *parent EINA_UNUSED, int x, int y, int w, int h) { Ecore_Evas *ee; + Ecore_Evas_Cocoa_Engine_Data *edata; Ecore_Evas_Interface_Cocoa *iface; if (!ecore_cocoa_init()) @@ -532,6 +661,10 @@ ecore_evas_cocoa_new_internal(Ecore_Cocoa_Window *parent EINA_UNUSED, int x, int ee = calloc(1, sizeof(Ecore_Evas)); if (!ee) goto shutdown_ecore_cocoa; + edata = calloc(1, sizeof(Ecore_Evas_Cocoa_Engine_Data)); + if (!edata) + goto shutdown_ecore_cocoa_engine_data; + ee->engine.data = edata; ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); @@ -606,6 +739,8 @@ ecore_evas_cocoa_new_internal(Ecore_Cocoa_Window *parent EINA_UNUSED, int x, int free(ee->name); //free_ee: _ecore_evas_cocoa_shutdown(); + free(edata); + shutdown_ecore_cocoa_engine_data: free(ee); shutdown_ecore_cocoa: ecore_cocoa_shutdown(); From 7dd92a2d98b983557fc4ce21f8d5740e81fa2a74 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Sun, 8 Mar 2020 10:46:09 +0100 Subject: [PATCH 10/17] port cnp on Windows Test Plan: Ctrl-c and Ctrl-Vworking Reviewers: raster, zmike Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D11439 --- src/lib/ecore_win32/Ecore_Win32.h | 47 +-- src/lib/ecore_win32/ecore_win32_clipboard.c | 224 +++++++++----- src/lib/ecore_win32/ecore_win32_event.c | 123 +++++--- .../engines/win32/ecore_evas_win32.c | 291 +++++++++++++----- 4 files changed, 443 insertions(+), 242 deletions(-) diff --git a/src/lib/ecore_win32/Ecore_Win32.h b/src/lib/ecore_win32/Ecore_Win32.h index 91274ba74a..722f0aa124 100644 --- a/src/lib/ecore_win32/Ecore_Win32.h +++ b/src/lib/ecore_win32/Ecore_Win32.h @@ -215,21 +215,6 @@ typedef enum ECORE_WIN32_DND_EVENT_DROP = 4 /**< Drop */ } Ecore_Win32_DnD_State; -/** - * @typedef Ecore_Win32_Selection - * Type of the selection. - * - * @since 1.16 - */ -typedef enum -{ - ECORE_WIN32_SELECTION_PRIMARY, - ECORE_WIN32_SELECTION_SECONDARY, - ECORE_WIN32_SELECTION_DND, - ECORE_WIN32_SELECTION_CLIPBOARD, - ECORE_WIN32_SELECTION_OTHER -} Ecore_Win32_Selection; - /** * @typedef Ecore_Win32_Window * Abstract type for a window. @@ -326,7 +311,7 @@ typedef struct _Ecore_Win32_Event_Window_Delete_Request Ecore_Win32_Event_Window * @typedef Ecore_Win32_Event_Selection_Clear * Event sent when the content of the clipboard has been removed. * - * @since 1.16 + * @since 1.24 */ typedef struct _Ecore_Win32_Event_Selection_Clear Ecore_Win32_Event_Selection_Clear; @@ -334,7 +319,7 @@ typedef struct _Ecore_Win32_Event_Selection_Clear Ecore_Win32_Event_Selection_Cl * @typedef Ecore_Win32_Event_Selection_Notify * Event sent when the content of the clipboard has been added. * - * @since 1.16 + * @since 1.24 */ typedef struct _Ecore_Win32_Event_Selection_Notify Ecore_Win32_Event_Selection_Notify; @@ -490,26 +475,26 @@ struct _Ecore_Win32_Event_Window_Delete_Request * @struct _Ecore_Win32_Event_Selection_Clear * Event sent when the content of the clipboard has been removed. * - * @since 1.16 + * @since 1.24 */ struct _Ecore_Win32_Event_Selection_Clear { Ecore_Win32_Window *window; /**< The window that received the event */ unsigned long timestamp; /**< The time the event occurred */ - Ecore_Win32_Selection selection; /**< The type of the selection */ + char *selection; /**< The type of the selection */ }; /** * @struct _Ecore_Win32_Event_Selection_Notify * Event sent when the content of the clipboard has been added. * - * @since 1.16 + * @since 1.24 */ struct _Ecore_Win32_Event_Selection_Notify { Ecore_Win32_Window *window; /**< The window that received the event */ unsigned long timestamp; /**< The time the event occurred */ - Ecore_Win32_Selection selection; /**< The type of the selection */ + char *selection; /**< The type of the selection */ void *data; /**< The data of the selection */ }; @@ -698,6 +683,7 @@ EAPI void ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window * @param[in] window The window that owns the clipboard. * @param[in] data The data to set. * @param[in] size The size of the data. + * @param[in] mime_type The mime type describing the data in the clipboard. * @return #EINA_TRUE on success, #EINA_FALSE otherwise. * * This function sets @p data of size @p size in the clipboard owned by @@ -705,11 +691,12 @@ EAPI void ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window * #EINA_FALSE otherwise. If @p window or @p data are @c NULL, or @p size * is less than or equal to 0, this function returns #EINA_FALSE. * - * @since 1.16 + * @since 1.24 */ EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window, const void *data, - int size); + size_t size, + const char *mime_type); /** * @brief Get data from the clipboard. @@ -717,6 +704,7 @@ EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window, * @param[in] window The window that owns the clipboard. * @param[out] data The retrieved data. * @param[out] size The size of the data. + * @param[in] mime_type The mime type describing the data in the clipboard. * @return #EINA_TRUE on success, #EINA_FALSE otherwise. * * This function gets @p data of size @p size from the clipboard owned by @@ -724,25 +712,24 @@ EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window, * #EINA_FALSE otherwise. If @p window is @c NULL, this function returns * #EINA_FALSE. @p data and @p size must be valid buffers. * - * @since 1.16 + * @since 1.24 */ -EAPI Eina_Bool ecore_win32_clipboard_get(const Ecore_Win32_Window *window, - void **data, - int *size); +EAPI void * ecore_win32_clipboard_get(const Ecore_Win32_Window *window, + size_t *size, + const char *mime_type); /** * @brief Cleat the clipboard. * * @param[in] window The window that owns the clipboard. - * @return #EINA_TRUE on success, #EINA_FALSE otherwise. * * This function clears the clipboard owned by @p window. This * function returns #EINA_TRUE on success, and #EINA_FALSE otherwise. * If @p window is @c NULL, this function returns #EINA_FALSE. * - * @since 1.16 + * @since 1.24 */ -EAPI Eina_Bool ecore_win32_clipboard_clear(const Ecore_Win32_Window *window); +EAPI void ecore_win32_clipboard_clear(const Ecore_Win32_Window *window); /** * @typedef Ecore_Win32_Monitor diff --git a/src/lib/ecore_win32/ecore_win32_clipboard.c b/src/lib/ecore_win32/ecore_win32_clipboard.c index a20be680c0..da4960370a 100644 --- a/src/lib/ecore_win32/ecore_win32_clipboard.c +++ b/src/lib/ecore_win32/ecore_win32_clipboard.c @@ -6,6 +6,7 @@ #include #undef WIN32_LEAN_AND_MEAN +#include /* utf-8 and utf-16 conversion */ #include #include "Ecore_Win32.h" @@ -39,10 +40,13 @@ EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window, const void *data, - int size) + size_t size, + const char *mime_type) { HGLOBAL global; char *d; + Eina_Bool supported_mime_text; + Eina_Bool res = EINA_FALSE; /* * See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms649016%28v=vs.85%29.aspx#_win32_Copying_Information_to_the_Clipboard @@ -54,47 +58,77 @@ ecore_win32_clipboard_set(const Ecore_Win32_Window *window, INF("setting data to the clipboard"); - if (!window || !data || (size <= 0)) - return EINA_FALSE; + supported_mime_text = eina_str_has_prefix(mime_type, "text/"); + if (!supported_mime_text) + { + ERR("Mimetype %s is not handled yet", mime_type); + return EINA_FALSE; + } - if (!OpenClipboard(window->window)) + if (!window || !data || (size <= 0) || !OpenClipboard(window->window)) return EINA_FALSE; if (!EmptyClipboard()) goto close_clipboard; - global = GlobalAlloc(GMEM_MOVEABLE, size + 1); - if (!global) - goto close_clipboard; + if (supported_mime_text) + { + wchar_t *text16; + size_t size16; - d = (char *)GlobalLock(global); - if (!d) - goto unlock_global; + /* CF_TEXT (UTF-8) */ - memcpy(d, data, size); - d[size] = '\0'; - GlobalUnlock(global); - SetClipboardData(CF_TEXT, global); - CloseClipboard(); + global = GlobalAlloc(GMEM_MOVEABLE, size); + if (global) + { + d = (char *)GlobalLock(global); + if (d) + { + memcpy(d, data, size); + SetClipboardData(CF_TEXT, global); + res = EINA_TRUE; + GlobalUnlock(global); + } + } - return EINA_TRUE; + /* CF_UNICODETEXT (UTF-16) */ + + text16 = evil_utf8_to_utf16(data); + if (text16) + { + size16 = (wcslen(text16) + 1) * sizeof(wchar_t); + + global = GlobalAlloc(GMEM_MOVEABLE, size16); + if (global) + { + d = (char *)GlobalLock(global); + if (d) + { + memcpy(d, text16, size16); + SetClipboardData(CF_UNICODETEXT, global); + res = EINA_TRUE; + GlobalUnlock(global); + } + } + + free(text16); + } + } - unlock_global: - GlobalUnlock(global); close_clipboard: CloseClipboard(); - return EINA_FALSE; + return res; } -EAPI Eina_Bool +EAPI void * ecore_win32_clipboard_get(const Ecore_Win32_Window *window, - void **data, - int *size) + size_t *size, + const char *mime_type) { HGLOBAL global; + void *data; void *d; - void *p; /* * See https://msdn.microsoft.com/en-us/library/windows/desktop/ms649016%28v=vs.85%29.aspx#_win32_Pasting_Information_from_the_Clipboard @@ -107,80 +141,100 @@ ecore_win32_clipboard_get(const Ecore_Win32_Window *window, INF("getting data from the clipboard"); - if (!window) - return EINA_FALSE; + if (!eina_str_has_prefix(mime_type, "text/")) + { + ERR("Mimetype %s is not handled yet", mime_type); + return NULL; + } - if (!IsClipboardFormatAvailable(CF_TEXT)) - return EINA_FALSE; + if (!window || !size || !OpenClipboard(window->window)) + return NULL; - if (!OpenClipboard(window->window)) - goto set_val; - - /* { */ - /* UINT fmt = 0; */ - - /* while (1) */ - /* { */ - /* fmt = EnumClipboardFormats(fmt); */ - /* printf(" $ Format : %x\n", fmt); */ - /* if (!fmt) */ - /* break; */ - /* } */ - /* } */ - - global = GetClipboardData(CF_TEXT); - if (!global) - goto close_clipboard; - - d = GlobalLock(global); - if (!d) - goto unlock_global; - - *size = strlen(d); - p = malloc(*size); - if (!p) - goto unlock_global; - - memcpy(p, d, *size); - *data = p; - GlobalUnlock(global); - CloseClipboard(); - - return EINA_TRUE; - - unlock_global: - GlobalUnlock(global); - close_clipboard: - CloseClipboard(); - set_val: - *data = NULL; *size = 0; - return EINA_FALSE; +#if 0 + { + UINT fmt = 0; + + while (1) + { + char name[4096]; + int res; + fmt = EnumClipboardFormats(fmt); + res = GetClipboardFormatName(fmt, name, sizeof(name)); + fprintf(stderr, " $ Format2 : %x %d\n", fmt, res); + if (res) + fprintf(stderr, " $ Format2 : %s\n", name); + else + fprintf(stderr, " $ Format2 : error %ld\n", GetLastError()); + fflush(stderr); + if (!fmt) + break; + } + } +#endif + + if (eina_str_has_prefix(mime_type, "text/")) + { + /* first check if UTF-16 text is available */ + global = GetClipboardData(CF_UNICODETEXT); + if (global) + { + d = GlobalLock(global); + if (d) + { + data = evil_utf16_to_utf8(d); + if (data) + { + *size = strlen(data); + GlobalUnlock(global); + CloseClipboard(); + return data; + } + GlobalUnlock(global); + } + /* otherwise, we try CF_TEXT (UTF-8/ANSI) */ + } + + /* second, check if UTF-8/ANSI text is available */ + global = GetClipboardData(CF_TEXT); + if (global) + { + d = GlobalLock(global); + if (d) + { + *size = strlen(d) + 1; + data = malloc(*size); + if (data) + { + memcpy(data, d, *size); + GlobalUnlock(global); + CloseClipboard(); + return data; + } + else + *size = 0; + + GlobalUnlock(global); + } + } + } + + CloseClipboard(); + + return NULL; } -EAPI Eina_Bool +EAPI void ecore_win32_clipboard_clear(const Ecore_Win32_Window *window) { INF("clearing the clipboard"); - if (!window) - return EINA_FALSE; - - if (!OpenClipboard(window->window)) - return EINA_FALSE; - - if (!EmptyClipboard()) - goto close_clipboard; + if (!window || !OpenClipboard(window->window)) + return; + EmptyClipboard(); CloseClipboard(); - - return EINA_TRUE; - - close_clipboard: - CloseClipboard(); - - return EINA_FALSE; } /** diff --git a/src/lib/ecore_win32/ecore_win32_event.c b/src/lib/ecore_win32/ecore_win32_event.c index 0c232e7bc3..28a5b1f07e 100644 --- a/src/lib/ecore_win32/ecore_win32_event.c +++ b/src/lib/ecore_win32/ecore_win32_event.c @@ -1958,66 +1958,103 @@ _ecore_win32_event_handle_selection_notify(Ecore_Win32_Callback_Data *msg) { Ecore_Win32_Event_Selection_Notify *e; HGLOBAL global; - char *str; INF("selection_notify"); + e = calloc(1, sizeof(Ecore_Win32_Event_Selection_Notify)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->timestamp = _ecore_win32_event_last_time; + /* - * we have text data in clipboard but no data before, - * so text data has just been added + * we have data in clipboard but no data before, + * so data has just been added */ - if (IsClipboardFormatAvailable(CF_TEXT) && !_ecore_win32_clipboard_has_data) + if (!_ecore_win32_clipboard_has_data) { - e = calloc(1, sizeof(Ecore_Win32_Event_Selection_Notify)); - if (!e) return; - - e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->timestamp = _ecore_win32_event_last_time; - e->selection = ECORE_WIN32_SELECTION_CLIPBOARD; - + /* if case someone else is owning the clipboard, we can't do anything */ if (!OpenClipboard(msg->window)) - goto free_e; - - global = GetClipboardData(CF_TEXT); - if (!global) - goto close_clipboard; - - str = GlobalLock(global); - if (str) { - e->data = strdup(str); - GlobalUnlock(global); + free(e); + return; } + if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + { + global = GetClipboardData(CF_UNICODETEXT); + if (global) + { + e->selection = strdup("text/plain;charset=utf-8"); + if (e->selection) + { + wchar_t *d; + + d = (wchar_t *)GlobalLock(global); + if (d) + e->data = evil_utf16_to_utf8(d); + + GlobalUnlock(global); + if (e->data) + { + ecore_event_add(ECORE_WIN32_EVENT_SELECTION_NOTIFY, e, NULL, NULL); + _ecore_win32_clipboard_has_data = EINA_TRUE; + CloseClipboard(); + return; + } + } + } + } + + if (IsClipboardFormatAvailable(CF_TEXT)) + { + global = GetClipboardData(CF_TEXT); + if (global) + { + e->selection = strdup("text/plain;charset=utf-8"); + if (e->selection) + { + char *d; + + d = (char *)GlobalLock(global); + if (d) + e->data = strdup(d); + + GlobalUnlock(global); + if (e->data) + { + ecore_event_add(ECORE_WIN32_EVENT_SELECTION_NOTIFY, e, NULL, NULL); + + _ecore_win32_clipboard_has_data = EINA_TRUE; + CloseClipboard(); + return; + } + } + } + } + free(e->data); + free(e->selection); + free(e); CloseClipboard(); - - ecore_event_add(ECORE_WIN32_EVENT_SELECTION_NOTIFY, e, NULL, NULL); - - _ecore_win32_clipboard_has_data = EINA_TRUE; } - /* - * we have no more text data in clipboard and data before, + * otherwise, we have no more text data in clipboard and data before, * so text data has just been removed */ - if (!IsClipboardFormatAvailable(CF_TEXT) && _ecore_win32_clipboard_has_data) + else { - e = calloc(1, sizeof(Ecore_Win32_Event_Selection_Clear)); - if (!e) return; - - e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->timestamp = _ecore_win32_event_last_time; - e->selection = ECORE_WIN32_SELECTION_CLIPBOARD; - - ecore_event_add(ECORE_WIN32_EVENT_SELECTION_CLEAR, e, NULL, NULL); - - _ecore_win32_clipboard_has_data = EINA_FALSE; + if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && + !IsClipboardFormatAvailable(CF_TEXT)) + { + e->selection = strdup("text/plain;charset=utf-8"); + if (e->selection) + { + ecore_event_add(ECORE_WIN32_EVENT_SELECTION_CLEAR, e, NULL, NULL); + _ecore_win32_clipboard_has_data = EINA_FALSE; + return; + } + } } - return; - - close_clipboard: - CloseClipboard(); - free_e: free(e); } diff --git a/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c b/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c index 6198ed4bac..d0686c535c 100644 --- a/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c +++ b/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c @@ -62,11 +62,15 @@ static const int interface_win32_version = 1; typedef struct _Ecore_Evas_Engine_Data_Win32 Ecore_Evas_Engine_Data_Win32; -struct _Ecore_Evas_Engine_Data_Win32 { +struct _Ecore_Evas_Engine_Data_Win32 +{ Ecore_Win32_Window *parent; - struct { - unsigned char region : 1; - unsigned char fullscreen : 1; + Ecore_Evas_Selection_Callbacks clipboard; + Eina_Future *delivery; + struct + { + unsigned char region : 1; + unsigned char fullscreen : 1; } state; }; @@ -1197,96 +1201,215 @@ _ecore_evas_win32_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) *ydpi = y_dpi; } +static Eina_Value +_delivery(void *data, const Eina_Value value EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED) +{ + Ecore_Evas *ee = data; + Ecore_Evas_Engine_Data_Win32 *edata = ee->engine.data; + Eina_Rw_Slice slice; + const char *mime_type = NULL; + + EINA_SAFETY_ON_NULL_GOTO(edata->delivery, end); + + for (unsigned int i = 0; i < eina_array_count(edata->clipboard.available_types); ++i) + { + mime_type = eina_array_data_get(edata->clipboard.available_types, i); + if (eina_str_has_prefix(mime_type, "text/")) + break; + } + if (mime_type) + { + edata->clipboard.delivery(ee, 0, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER, mime_type, &slice); + EINA_SAFETY_ON_FALSE_GOTO(ecore_win32_clipboard_set((Ecore_Win32_Window *)ee->prop.window, slice.mem, slice.len, mime_type), end); + } + else + { + ERR("No compatible mime type found"); + } + +end: + return EINA_VALUE_EMPTY; +} + +static Eina_Bool +_ecore_evas_win32_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +{ + if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return EINA_FALSE; + + if (!delivery && !cancel) + { + ecore_win32_clipboard_clear((Ecore_Win32_Window *)ee->prop.window); + return EINA_TRUE; + } + else + { + Ecore_Evas_Engine_Data_Win32 *edata = ee->engine.data; + + if (edata->clipboard.cancel) + { + edata->clipboard.cancel(ee, seat, selection); + eina_array_free(edata->clipboard.available_types); + } + + edata->delivery = efl_loop_job(efl_main_loop_get()); + eina_future_then(edata->delivery, _delivery, ee); + edata->clipboard.delivery = delivery; + edata->clipboard.cancel = cancel; + edata->clipboard.available_types = available_types; + return EINA_TRUE; + } +} + +Eina_Future* +_ecore_evas_win32_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type) +{ + Eina_Future *future; + Eina_Promise *promise; + const char *mime_type = NULL; + + if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return eina_future_rejected(efl_loop_future_scheduler_get(efl_main_loop_get()), ecore_evas_no_selection); + + promise = efl_loop_promise_new(efl_main_loop_get()); + future = eina_future_new(promise); + + for (unsigned int i = 0; i < eina_array_count(acceptable_type); ++i) + { + mime_type = eina_array_data_get(acceptable_type, i); + if (eina_str_has_prefix(mime_type, "text/")) + break; + } + if (!mime_type) + { + eina_promise_reject(promise, ecore_evas_no_matching_type); + } + else + { + size_t size; + void *data; + Eina_Content *content; + Eina_Rw_Slice slice; + + data = ecore_win32_clipboard_get((Ecore_Win32_Window *)ee->prop.window, &size, mime_type); + if (eina_str_has_prefix(mime_type, "text/")) + { + //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. + slice.len = size + 1; + slice.mem = eina_memdup(data, size, EINA_TRUE); + } + else + { + slice.len = size; + slice.mem = data; + } + content = eina_content_new(eina_rw_slice_slice_get(slice), mime_type); + if (!content) // construction can fail because of some validation reasons + eina_promise_reject(promise, ecore_evas_no_matching_type); + else + eina_promise_resolve(promise, eina_value_content_init(content)); + } + return future; +} + +static Eina_Bool +_ecore_evas_win32_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection) +{ + return (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); +} + static Ecore_Evas_Engine_Func _ecore_win32_engine_func = { _ecore_evas_win32_free, - NULL, - NULL, - NULL, - NULL, - _ecore_evas_win32_callback_delete_request_set, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - _ecore_evas_win32_move, - NULL, - _ecore_evas_win32_resize, - _ecore_evas_win32_move_resize, - _ecore_evas_win32_rotation_set, - _ecore_evas_win32_shaped_set, - _ecore_evas_win32_show, - _ecore_evas_win32_hide, - _ecore_evas_win32_raise, - _ecore_evas_win32_lower, - _ecore_evas_win32_activate, - _ecore_evas_win32_title_set, - NULL, /* _ecore_evas_x_name_class_set */ - _ecore_evas_win32_size_min_set, - _ecore_evas_win32_size_max_set, - _ecore_evas_win32_size_base_set, - _ecore_evas_win32_size_step_set, - _ecore_evas_win32_object_cursor_set, - _ecore_evas_win32_object_cursor_unset, - NULL, /* _ecore_evas_x_layer_set */ - _ecore_evas_win32_focus_set, - _ecore_evas_win32_iconified_set, - _ecore_evas_win32_borderless_set, - _ecore_evas_win32_override_set, - NULL, - _ecore_evas_win32_fullscreen_set, - NULL, /* _ecore_evas_x_avoid_damage_set */ - NULL, /* _ecore_evas_x_withdrawn_set */ - NULL, /* _ecore_evas_x_sticky_set */ - NULL, /* _ecore_evas_x_ignore_events_set */ - _ecore_evas_win32_alpha_set, - NULL, //transparent - NULL, // profiles_set - NULL, // profile_set + NULL, + NULL, + NULL, + NULL, + _ecore_evas_win32_callback_delete_request_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_win32_move, + NULL, + _ecore_evas_win32_resize, + _ecore_evas_win32_move_resize, + _ecore_evas_win32_rotation_set, + _ecore_evas_win32_shaped_set, + _ecore_evas_win32_show, + _ecore_evas_win32_hide, + _ecore_evas_win32_raise, + _ecore_evas_win32_lower, + _ecore_evas_win32_activate, + _ecore_evas_win32_title_set, + NULL, /* _ecore_evas_x_name_class_set */ + _ecore_evas_win32_size_min_set, + _ecore_evas_win32_size_max_set, + _ecore_evas_win32_size_base_set, + _ecore_evas_win32_size_step_set, + _ecore_evas_win32_object_cursor_set, + _ecore_evas_win32_object_cursor_unset, + NULL, /* _ecore_evas_x_layer_set */ + _ecore_evas_win32_focus_set, + _ecore_evas_win32_iconified_set, + _ecore_evas_win32_borderless_set, + _ecore_evas_win32_override_set, + NULL, + _ecore_evas_win32_fullscreen_set, + NULL, /* _ecore_evas_x_avoid_damage_set */ + NULL, /* _ecore_evas_x_withdrawn_set */ + NULL, /* _ecore_evas_x_sticky_set */ + NULL, /* _ecore_evas_x_ignore_events_set */ + _ecore_evas_win32_alpha_set, + NULL, //transparent + NULL, // profiles_set + NULL, // profile_set - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, - NULL, // render - _ecore_evas_win32_screen_geometry_get, - _ecore_evas_win32_screen_dpi_get, - NULL, - NULL, // msg_send + NULL, // render + _ecore_evas_win32_screen_geometry_get, + _ecore_evas_win32_screen_dpi_get, + NULL, + NULL, // msg_send - NULL, // pointer_xy_get - NULL, // pointer_warp + NULL, // pointer_xy_get + NULL, // pointer_warp - NULL, // wm_rot_preferred_rotation_set - NULL, // wm_rot_available_rotations_set - NULL, // wm_rot_manual_rotation_done_set - NULL, // wm_rot_manual_rotation_done + NULL, // wm_rot_preferred_rotation_set + NULL, // wm_rot_available_rotations_set + NULL, // wm_rot_manual_rotation_done_set + NULL, // wm_rot_manual_rotation_done - NULL, // aux_hints_set + NULL, // aux_hints_set - NULL, // fn_animator_register - NULL, // fn_animator_unregister + NULL, // fn_animator_register + NULL, // fn_animator_unregister - NULL, // fn_evas_changed - NULL, //fn_focus_device_set - NULL, //fn_callback_focus_device_in_set - NULL, //fn_callback_focus_device_out_set - NULL, //fn_callback_device_mouse_in_set - NULL, //fn_callback_device_mouse_out_set - NULL, //fn_pointer_device_xy_get - NULL, //fn_prepare - NULL, //fn_last_tick_get - NULL, //fn_selection_claim - NULL, //fn_selection_has_owner - NULL, //fn_selection_request + NULL, // fn_evas_changed + NULL, //fn_focus_device_set + NULL, //fn_callback_focus_device_in_set + NULL, //fn_callback_focus_device_out_set + NULL, //fn_callback_device_mouse_in_set + NULL, //fn_callback_device_mouse_out_set + NULL, //fn_pointer_device_xy_get + NULL, //fn_prepare + NULL, //fn_last_tick_get + _ecore_evas_win32_selection_claim, //fn_selection_claim + _ecore_evas_win32_selection_has_owner, //fn_selection_has_owner + _ecore_evas_win32_selection_request, //fn_selection_request + NULL, //fn_dnd_start + NULL, //fn_dnd_stop }; #endif /* BUILD_ECORE_EVAS_WIN32 */ From 645c3d41ebd4b446c45e17a60fddf60302481bcc Mon Sep 17 00:00:00 2001 From: Xavi Artigas Date: Tue, 3 Mar 2020 11:12:08 +0100 Subject: [PATCH 11/17] docs: Strengthen docs for Copy&Paste and Drag&Drop Including Eina.Content And a typo/bugfix in ecore_evas_x. Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11204 --- src/lib/ecore_evas/Ecore_Evas.h | 2 - src/lib/eina/eina_abstract_content.h | 68 +++++++-------- src/lib/elementary/efl_ui_dnd.eo | 82 ++++++++++++------- src/lib/elementary/efl_ui_selection.eo | 74 +++++++++++------ src/lib/elementary/efl_ui_textbox.eo | 23 +++--- src/lib/eo/eina_types.eot | 11 ++- .../ecore_evas/engines/x/ecore_evas_x.c | 2 +- 7 files changed, 163 insertions(+), 99 deletions(-) diff --git a/src/lib/ecore_evas/Ecore_Evas.h b/src/lib/ecore_evas/Ecore_Evas.h index ddc3622741..713ad9748f 100644 --- a/src/lib/ecore_evas/Ecore_Evas.h +++ b/src/lib/ecore_evas/Ecore_Evas.h @@ -3695,8 +3695,6 @@ typedef void (*Ecore_Evas_Selection_Changed_Cb)(Ecore_Evas *ee, unsigned int sea * Only one such callback can exist for each Ecore_Evas. Calling this method multiple * times overwrites previous functions. Use a NULL @p func to stop being notified. * - * You will not be notified about selection changes caused by yourself. (TODO: bu5hm4n?) - * * @warning If and when this function is called depends on the underlying * windowing system. */ diff --git a/src/lib/eina/eina_abstract_content.h b/src/lib/eina/eina_abstract_content.h index 1436543f4e..9b723d553f 100644 --- a/src/lib/eina/eina_abstract_content.h +++ b/src/lib/eina/eina_abstract_content.h @@ -4,22 +4,22 @@ /** * @typedef Eina_Content - * Defines a abstract content segment + * Container for any type of content. * - * Each Abstract content contains out of a Eina_Slice of memory. And a type. - * The type are IANA meme types. + * Each Eina_Content is made of an Eina_Slice of memory and an IANA MIME type: + * https://www.iana.org/assignments/media-types/media-types.xhtml * - * @note if the type is a text-style type, the last byte of the slice must be \0 + * @note If the type is any kind of text the last byte of the slice must be \0. * * @since 1.24 */ typedef struct _Eina_Content Eina_Content; /** - * @typedef Eina_Content_Convertion_Callback + * @typedef Eina_Content_Conversion_Callback * - * Callback called when convertion from one type to another type is requested. - * The from and to type is specified when the callback is registered. + * Method called when conversion from one type to another is requested. + * The from and to types are specified when the callback is registered. * The to type is also passed in the callback here. * The type of the from pointer does not need to be checked. */ @@ -38,7 +38,7 @@ EAPI const char* eina_content_as_file(Eina_Content *content); /** * Convert the content of the object to another type. * - * In case the convertion cannot be performaned, NULL is returned. + * In case the conversion cannot be performed, NULL is returned. * * @param[in] content The content to convert. * @param[in] new_type The new type the returned content will have. @@ -57,19 +57,19 @@ EAPI Eina_Content* eina_content_convert(Eina_Content *content, const char *new_t EAPI const char* eina_content_type_get(Eina_Content *content); /** - * Get the type of the passed content. + * Get the Eina_Slice of the passed content. * - * @param[in] content The content to fetch the type from. + * @param[in] content The content to fetch the data from. * - * @return The path to the file. Do not free this. + * @return An Eina_Slice containing the data. Do not free. */ EAPI const Eina_Slice eina_content_data_get(Eina_Content *content); /** - * Create a new content object, with the slice of data with a specific type. + * Create a new content object, with the provided data and type. * - * @param[in] data A slice of memory, the memory is duplicated. - * @param[in] type The type of memory. + * @param[in] data A slice of memory. The memory is copied. + * @param[in] type The type this data represents. * * @return The new content object. The caller owns this object. */ @@ -85,62 +85,62 @@ EAPI void eina_content_free(Eina_Content *content); /** * Register a new conversion callback. * - * @param[in] from The tyoe you convert from. - * @param[in] in The type you convert to. + * @param[in] from The type to convert from. + * @param[in] to The type to convert to. * - * @return True on success false otherwise. + * @return True if the callback was successfully registered. */ EAPI Eina_Bool eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback convertion); /** - * Check if a specific convertion can be performanced. + * Check if a specific conversion can be performed. * - * A convertion can only be performed if a callback is registered. + * A conversion can only be performed if a callback is registered. * - * @param[in] from The type you convert from. - * @param[in] in The type you convert to. + * @param[in] from The type to convert from. + * @param[in] to The type to convert to. * - * @return True if it can be performed, false if not. + * @return True if the conversion can be performed. */ EAPI Eina_Bool eina_content_converter_convert_can(const char *from, const char *to); /** - * Returns a iterator that can be used to find all the possible types that can be converted to. + * Returns an iterator containing all the target types that the provided source type can be converted to. * - * @param[in] form The type you convert from + * @param[in] from The type to convert from. * - * @return A Iterator, containing strings, free this via eina_iterator_free. + * @return An Iterator containing MIME type strings. Free this via eina_iterator_free. */ EAPI Eina_Iterator* eina_content_converter_possible_conversions(const char *from); EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT; /** - * Convert the Eina_Content object to a Eina_Value. + * Convert the Eina_Content object to an Eina_Value. * - * @param[in] content The Eina_Content struct that will be converted to a Eina_Value + * @param[in] content The Eina_Content struct that will be converted to an Eina_Value. * - * @return A Eina_Value that is allocated, you need to free it. + * @return An newly-allocated Eina_Value. Caller owns it. */ EAPI Eina_Value* eina_value_content_new(Eina_Content *content); /** - * Convert the Eina_Content object to a Eina_Value. + * Creates an Eina_Value from an Eina_Content. * - * @param[in] content The Eina_Content struct that will be converted to a Eina_Value + * @param[in] content The Eina_Content struct that will be converted to an Eina_Value. * - * @return A Eina_Value with type EINA_VALUE_TYPE_CONTENT + * @return An Eina_Value with type EINA_VALUE_TYPE_CONTENT. */ EAPI Eina_Value eina_value_content_init(Eina_Content *content); /** - * Get the content from the Eina_Value + * Gets the content from the Eina_Value. * - * If the value is not of the type EINA_VALUE_TYPE_CONTENT, NULL will be returned and a error will be printed. + * If the value is not of the type EINA_VALUE_TYPE_CONTENT, NULL will be returned and an error will be printed. * * @param[in] value The value to get the content from * - * @return A allocated Eina_Content, you need to free it. + * @return A newly-allocated Eina_Content. Caller owns it. */ EAPI Eina_Content* eina_value_to_content(const Eina_Value *value); diff --git a/src/lib/elementary/efl_ui_dnd.eo b/src/lib/elementary/efl_ui_dnd.eo index 8ef19110d5..49ef148723 100644 --- a/src/lib/elementary/efl_ui_dnd.eo +++ b/src/lib/elementary/efl_ui_dnd.eo @@ -1,63 +1,89 @@ import eina_types; struct @beta Efl.Ui.Drop_Event { - [[Event struct that contains information about what is avaiable at which position, in which seat]] - position : Eina.Position2D; [[The position of the Drop event]] - seat : uint; [[In which seat it is happening]] - available_types : accessor; [[which types are avaiable, you should use one of these for a call to @Efl.Ui.Dnd.drop_data_get ]] + [[Information sent along with Drag & Drop events.]] + position : Eina.Position2D; [[The position where the drop event occurred, in window coordinates.]] + seat : uint; [[Which seat triggered the event.]] + available_types : accessor; [[Types with automatic conversion available. Use one of them in the call to + @Efl.Ui.Dnd.drop_data_get. + + Types are IANA MIME types: + https://www.iana.org/assignments/media-types/media-types.xhtml + ]] } struct @beta Efl.Ui.Drop_Dropped_Event { - dnd : Efl.Ui.Drop_Event; [[The overall information]] - action : string; [[The action the client should take]] + [[Information sent along with Drop events.]] + dnd : Efl.Ui.Drop_Event; [[Common information.]] + action : string; [[Requested action to perform upon reception of this data.]] } struct @beta Efl.Ui.Drag_Started_Event { - seat : uint; + [[Information sent along with @Efl.Ui.Drag_Started_Event events.]] + seat : uint; [[Which seat triggered the event.]] } struct @beta Efl.Ui.Drag_Finished_Event { - seat : uint; - accepted : bool; + [[Information sent along with @Efl.Ui.Drag_Finished_Event events.]] + seat : uint; [[Which seat triggered the event.]] + accepted : bool; [[$true if the operation completed with a Drop, or $false if it was cancelled.]] } mixin @beta Efl.Ui.Dnd requires Efl.Object { + [[This mixin provides the ability to interact with the system's Drag & Drop facilities. + + Applications starting a Drag & Drop operation operation are said to perform a "Drag" and use + the methods prefixed "drag_". + On the other hand, applications receiving dragged content are said to perform a "Drop" operation and use + the methods prefixed "drop_". + ]] methods { drag_start { - [[Start a drag from this client. + [[Starts a drag from this client. - @[Efl.Ui.Dnd.drag,started] will be emitted each time a successfull drag will be started. - @[Efl.Ui.Dnd.drag,finished] will be emitted every time a drag is finished. + @[Efl.Ui.Dnd.drag,started] is emitted each time a successful drag is started. + @[Efl.Ui.Dnd.drag,finished] is emitted every time a drag is finished. ]] params { - content : Eina.Content @by_ref; [[The content you want to provide via dnd]] - @in action: string; [[Action when data is transferred]] - @in seat: uint; [[Specified seat for multiple seats case.]] + content : Eina.Content @by_ref; [[The content being dragged.]] + @in action: string; [[Requested action to perform by the receiver once content is transferred.]] + @in seat: uint; [[Seat starting the drag operation. When in doubt use 0.]] } - return : Efl.Content; [[A UI element where you can just set your visual representation into]] + return : Efl.Content; [[An Efl.Ui element which you can use to render a visual representation + of the content being dragged (like a thumbnail, for example). + Use @Efl.Content.content.set on it to do so.]] } drag_cancel { - [[Cancel the on-going drag]] + [[Cancels an on-going drag operation.]] params { - @in seat: uint; [[Specified seat for multiple seats case.]] + @in seat: uint; [[Seat that started the drag operation. When in doubt use 0.]] } } drop_data_get { - [[Get the data from the object that has selection]] + [[Retrieves the dropped data.]] params { - seat : uint; [[Specified seat for multiple seats case.]] - acceptable_types : iterator; [[The types that are acceptable for you]] + @in seat: uint; [[Seat that started the drag operation. When in doubt use 0.]] + @in acceptable_types : iterator; [[List of strings describing the type of content the application + can accept. Types are IANA MIME types: + https://www.iana.org/assignments/media-types/media-types.xhtml.]] } - return : future @move; [[fullfilled when the content is transmitted, and ready to use]] + return : future @move; [[This future is fulfilled when the content is received (asynchronously) + and ready to use. + The Eina.Content specifies the type of the data. + If no matching type was found it returns an error. + ]] } } events { - drop,entered : Efl.Ui.Drop_Event; - drop,left : Efl.Ui.Drop_Event; - drop,position,changed : Efl.Ui.Drop_Event; - drop,dropped : Efl.Ui.Drop_Dropped_Event; - drag,started : Efl.Ui.Drag_Started_Event; - drag,finished : Efl.Ui.Drag_Finished_Event; + drop,entered : Efl.Ui.Drop_Event; [[Dragged content entered the window. Its type can already be checked with + @.drop_data_get to react before it is dropped, for example.]] + drop,left : Efl.Ui.Drop_Event; [[Dragged content left the window.]] + drop,position,changed : Efl.Ui.Drop_Event; [[Dragged content moved over the window. Its type can already be + checked with @.drop_data_get to react before it is dropped, + for example.]] + drop,dropped : Efl.Ui.Drop_Dropped_Event; [[Dragged content was dropped over the window.]] + drag,started : Efl.Ui.Drag_Started_Event; [[A Drag operation started.]] + drag,finished : Efl.Ui.Drag_Finished_Event;[[A Drag operation finished.]] } implements { Efl.Object.constructor; diff --git a/src/lib/elementary/efl_ui_selection.eo b/src/lib/elementary/efl_ui_selection.eo index 492e60e117..7e0814d348 100644 --- a/src/lib/elementary/efl_ui_selection.eo +++ b/src/lib/elementary/efl_ui_selection.eo @@ -1,49 +1,76 @@ import eina_types; -enum @beta Efl.Ui.Cnp_Buffer{ - selection = 0, - copy_and_paste = 1, +enum @beta Efl.Ui.Cnp_Buffer { + [[System buffer to use in Copy & Paste operations.]] + selection = 0, [[Buffer typically used when the user selects (highlights) some text without explicitly + requesting to copy it.]] + copy_and_paste = 1, [[Buffer used when the user requests that the current selection is copied (using + Ctrl+C, for example).]] } struct @beta Efl.Ui.Wm_Selection_Changed { - buffer : Efl.Ui.Cnp_Buffer; - caused_by : Efl.Ui.Selection; - seat : uint; + [[Information sent along the @[Efl.Ui.Selection.wm_selection,changed] event.]] + buffer : Efl.Ui.Cnp_Buffer; [[The system buffer that has changed.]] + caused_by : Efl.Ui.Selection; [[The EFL widget that triggered the change. $NULL if it is not an EFL widget.]] + seat : uint; [[The seat that triggered the change.]] } mixin @beta Efl.Ui.Selection requires Efl.Object { + [[This mixin provides the ability to interact with the system's Copy & Paste facilities. + ]] methods { selection_set { - [[Set the selection data to the object]] + [[Sets the current selection. + + This sends the selected data to the system's specified buffer, making it available to other + applications for "pasting" it. + + This is typically used when the user requests a "copy" operation. + ]] params { - buffer : Efl.Ui.Cnp_Buffer; - content : Eina.Content @by_ref; - seat : uint; + buffer : Efl.Ui.Cnp_Buffer; [[System buffer to use.]] + content : Eina.Content @by_ref; [[Data to copy.]] + seat : uint; [[Seat the data comes from. Use 0 when in doubt.]] } } selection_clear { - [[Clear the selection data from the object]] + [[Clears the current selection. + + No data will be available to other applications to paste (until something else is selected). + ]] params { - buffer : Efl.Ui.Cnp_Buffer; - seat : uint; + buffer : Efl.Ui.Cnp_Buffer; [[System buffer to clear.]] + seat : uint; [[Seat to clear. Use 0 when in doubt.]] } } selection_get { - [[Get the data from the object that has selection]] + [[Retrieves the data currently held in the specified buffer. + + This is typically used when the user requests a "paste" operation. + + This method is time consuming (since data can potentially be provided by another application), therefore, + it is recommended to verify the existence of a selection using @.has_selection before calling it. + ]] params { - buffer : Efl.Ui.Cnp_Buffer; - seat : uint; - acceptable_types : iterator; + buffer : Efl.Ui.Cnp_Buffer; [[System buffer to use.]] + seat : uint; [[Seat where the data should be pasted. Use 0 when in doubt.]] + acceptable_types : iterator; [[List of accepted IANA MIME types: + https://www.iana.org/assignments/media-types/media-types.xhtml + If automatic conversion cannot be provided to any of the accepted + types, an error will be returned. + ]] } - return : future @move; + return : future @move; [[A future that will be resolved to the requested content, or to an + error if type conversion is not available or the requested buffer + is empty.]] } has_selection { - [[Determine whether the selection data has owner]] + [[Checks if the specified system buffer has content.]] params { - buffer : Efl.Ui.Cnp_Buffer; - seat : uint; + buffer : Efl.Ui.Cnp_Buffer; [[System buffer to query.]] + seat : uint; [[Seat to query. Use 0 when in doubt.]] } - return : bool; [[$true if there is a available selection, $false if not]] + return : bool; [[$true if there is data available in the requested buffer.]] } } implements { @@ -52,6 +79,7 @@ mixin @beta Efl.Ui.Selection requires Efl.Object { Efl.Object.finalize; } events { - wm_selection,changed : Efl.Ui.Wm_Selection_Changed; + wm_selection,changed : Efl.Ui.Wm_Selection_Changed; [[Event emitted when the content of one of the system's + buffers changes.]] } } diff --git a/src/lib/elementary/efl_ui_textbox.eo b/src/lib/elementary/efl_ui_textbox.eo index ff0898b6fc..2605c477a3 100644 --- a/src/lib/elementary/efl_ui_textbox.eo +++ b/src/lib/elementary/efl_ui_textbox.eo @@ -1,8 +1,13 @@ -enum Efl.Ui.Textbox_Cnp_Content { - Nothing = 0, [[You can paste or drop nothing]] - Text = 1, [[You can paste normal Text]] - Markup = 3, [[You can paste Markup (Normal text is also just markup)]] - Image = 4, [[You can paste Images]] +enum @beta Efl.Ui.Textbox_Cnp_Content { + [[What kind of content can be pasted into this widget using Copy & Paste or Drag & Drop functionality. + + Multiple options can be OR-ed together. + ]] + Nothing = 0, [[Nothing can be pasted or dropped into this widget.]] + Text = 1, [[Plain text can be pasted or dropped into this widget.]] + Markup = 3, [[Markup text can be pasted or dropped into this widget + (This includes Plain text).]] + Image = 4, [[Images can be pasted or dropped into this widget.]] } class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Clickable, @@ -39,18 +44,16 @@ class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Click } } @property cnp_dnd_mode @beta { - [[Control pasting of text and images for the widget. + [[Controls the type of content which can be pasted into the widget. - Normally the entry allows both text and images to be pasted. - - Note: This only changes the behaviour of text. + By default, both text and images are allowed.. ]] set { } get { } values { - allowed_formats : Efl.Ui.Textbox_Cnp_Content; [[Format for cnp]] + allowed_formats : Efl.Ui.Textbox_Cnp_Content; [[Allowed content types.]] } } @property selection_handles_enabled { diff --git a/src/lib/eo/eina_types.eot b/src/lib/eo/eina_types.eot index 106aa0885d..000a2567d9 100644 --- a/src/lib/eo/eina_types.eot +++ b/src/lib/eo/eina_types.eot @@ -60,7 +60,16 @@ struct @extern Eina.Matrix3 { zz: double; [[ZZ value.]] } -struct @extern Eina.Content; +struct @extern Eina.Content; [[ + Container for any type of content. + + Each @Eina.Content is made of an @Eina.Slice of memory and an IANA MIME type: + https://www.iana.org/assignments/media-types/media-types.xhtml + + If the type is a text-style type, the last byte of the slice must be \0. + + @since 1.24 +]] struct @extern Eina.Matrix4 { [[A bidimensional array of floating point values with 4 rows and 4 columns. diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c b/src/modules/ecore_evas/engines/x/ecore_evas_x.c index d689a5622c..36afeb5495 100644 --- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c +++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c @@ -3794,7 +3794,7 @@ _search_fitting_type(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Ev if (mime_type == acceptable_type) HANDLE_TYPE() - //if there is no available type yet, check if we can convert to the desiared type via this type + //if there is no available type yet, check if we can convert to the desired type via this type if (!found_conversion) { const char *convertion_type = NULL; From 8b25bc41b33cf366ef068b04cc3de55b76310891 Mon Sep 17 00:00:00 2001 From: Xavi Artigas Date: Tue, 28 Jan 2020 17:33:42 +0000 Subject: [PATCH 12/17] mono-tests: Fix build after DnD changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test struct used to check mono bindings struct pack/unpack is no longer available. Used a different one, and checked the same things. Reviewed-by: João Paulo Taylor Ienczak Zanette Differential Revision: https://phab.enlightenment.org/D11219 --- src/tests/efl_mono/Structs.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/tests/efl_mono/Structs.cs b/src/tests/efl_mono/Structs.cs index 151bc8388d..334057c907 100644 --- a/src/tests/efl_mono/Structs.cs +++ b/src/tests/efl_mono/Structs.cs @@ -499,15 +499,14 @@ internal class TestStructTuples #if EFL_BETA public static void test_complex_fields_assign_conversion() { var pos = new Eina.Position2D(1, 2); - var action = Efl.Ui.SelectionAction.Unknown; - var format = Efl.Ui.SelectionFormat.None; - var item = null as Efl.Canvas.Vg.Object; + uint seat = 3; + var types = new System.String[] {"text", "markup"}; - Efl.Dnd.DragPos attr = (pos, action, format, item); - Test.AssertEquals(attr.Pos, pos); - Test.AssertEquals(attr.Action, action); - Test.AssertEquals(attr.Format, format); - Test.AssertEquals(attr.Item, item); + Efl.Ui.DropEvent attr = (pos, seat, types); + Test.AssertEquals(attr.Position, pos); + Test.AssertEquals(attr.Seat, seat); + Test.AssertEquals(attr.AvailableTypes.ElementAt(0), types[0]); + Test.AssertEquals(attr.AvailableTypes.ElementAt(1), types[1]); } #endif } From 7a79e15ea3c808b92482dbdecb294c6cf3212f91 Mon Sep 17 00:00:00 2001 From: Xavi Artigas Date: Tue, 3 Mar 2020 13:10:49 +0100 Subject: [PATCH 13/17] ecore_evas: Use EFL naming convention in cnp & dnd methods Some methods were missing the "Drag" or "Selection" namespaces or the _Cb suffix. Depends on D11219 Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D11426 --- src/lib/ecore_evas/Ecore_Evas.h | 19 +++++++++---------- src/lib/ecore_evas/ecore_evas.c | 6 +++--- .../ecore_evas_fallback_selection.c | 4 ++-- src/lib/ecore_evas/ecore_evas_private.h | 18 +++++++++--------- .../engines/cocoa/ecore_evas_cocoa.c | 2 +- .../wayland/ecore_evas_wayland_common.c | 6 +++--- .../engines/win32/ecore_evas_win32.c | 2 +- .../ecore_evas/engines/x/ecore_evas_x.c | 2 +- 8 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/lib/ecore_evas/Ecore_Evas.h b/src/lib/ecore_evas/Ecore_Evas.h index 713ad9748f..e3e8b63000 100644 --- a/src/lib/ecore_evas/Ecore_Evas.h +++ b/src/lib/ecore_evas/Ecore_Evas.h @@ -3756,7 +3756,7 @@ EAPI Eina_Future* ecore_evas_selection_get(Ecore_Evas *ee, unsigned int seat, Ec * * Set this callback using ecore_evas_callback_drop_state_changed_set. */ -typedef void (*Ecore_Evas_Drag_Finished)(Ecore_Evas *ee, unsigned int seat, void *data, Eina_Bool accepted); +typedef void (*Ecore_Evas_Drag_Finished_Cb)(Ecore_Evas *ee, unsigned int seat, void *data, Eina_Bool accepted); /** * @brief Starts a new drag operation. @@ -3776,7 +3776,8 @@ typedef void (*Ecore_Evas_Drag_Finished)(Ecore_Evas *ee, unsigned int seat, void * * This method must be called when a drag operation is initiated in order to provide the necessary information. */ -EAPI Eina_Bool ecore_evas_drag_start(Ecore_Evas *ee, unsigned int seat, Eina_Content *content, Ecore_Evas *drag_rep, const char* action, Ecore_Evas_Drag_Finished terminate_cb, void *data); +EAPI Eina_Bool ecore_evas_drag_start(Ecore_Evas *ee, unsigned int seat, Eina_Content *content, Ecore_Evas *drag_rep, + const char* action, Ecore_Evas_Drag_Finished_Cb terminate_cb, void *data); /** * @brief Cancels an ongoing drag operation. @@ -3798,7 +3799,7 @@ EAPI Eina_Bool ecore_evas_drag_cancel(Ecore_Evas *ee, unsigned int seat); * * Set this callback using ecore_evas_callback_drop_state_changed_set. */ -typedef void (*Ecore_Evas_State_Changed)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, Eina_Bool inside); +typedef void (*Ecore_Evas_Drag_State_Changed_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, Eina_Bool inside); /** * @brief Sets the method (callback) to call when the mouse pointer enters or exits the specified window while @@ -3810,7 +3811,7 @@ typedef void (*Ecore_Evas_State_Changed)(Ecore_Evas *ee, unsigned int seat, Eina * Only one such callback can exist for each Ecore_Evas. Calling this method multiple * times overwrites previous functions. Use a NULL @cb func to stop being notified. */ -EAPI void ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_State_Changed cb); +EAPI void ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_Drag_State_Changed_Cb cb); /** * @brief This method is called when the mouse pointer moves over the specified window while @@ -3822,7 +3823,7 @@ EAPI void ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_ * Set this callback using ecore_evas_callback_drop_motion_set. */ -typedef void (*Ecore_Evas_Motion_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p); +typedef void (*Ecore_Evas_Drag_Motion_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p); /** * @brief Sets the method (callback) to call when the mouse pointer moves over the specified window while * performing a drag operation. @@ -3833,7 +3834,7 @@ typedef void (*Ecore_Evas_Motion_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Pos * Only one such callback can exist for each Ecore_Evas. Calling this method multiple * times overwrites previous functions. Use a NULL @cb func to stop being notified. */ -EAPI void ecore_evas_callback_drop_motion_set(Ecore_Evas *ee, Ecore_Evas_Motion_Cb cb); +EAPI void ecore_evas_callback_drop_motion_set(Ecore_Evas *ee, Ecore_Evas_Drag_Motion_Cb cb); /** * @brief This method is called when the mouse pointer is released over the specified window while @@ -3861,16 +3862,14 @@ typedef void (*Ecore_Evas_Drop_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Posit */ EAPI void ecore_evas_callback_drop_drop_set(Ecore_Evas *ee, Ecore_Evas_Drop_Cb cb); -// app calls this (from one of the motion cb's, for example) to know the type (and auto conversion) of the thing being dragged. -// This is the same as calling selection_get and retrieving the types from there (but faster). /** * @brief Retrieves the list of types the data currently being dragged can be automatically converted to. * * @param[in] ee The Ecore Evas the drag operation started on. * @return * - * This can be used in any of the drag and drop callbacks (Ecore_Evas_State_Changed, Ecore_Evas_Motion_Cb and - * Ecore_Evas_Drop_Cb) to check if the data being dragged is acceptable and give the user some early feedback + * This can be used in any of the drag and drop callbacks (Ecore_Evas_Drag_State_Changed_Cb, Ecore_Evas_Drag_Motion_Cb + * and Ecore_Evas_Drop_Cb) to check if the data being dragged is acceptable and give the user some early feedback * before the data is actually dropped on the window. * * This is functionally equivalent to calling ecore_evas_selection_get and examining the available types in the diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c index a95f7903d8..ab28af1a2f 100644 --- a/src/lib/ecore_evas/ecore_evas.c +++ b/src/lib/ecore_evas/ecore_evas.c @@ -5641,7 +5641,7 @@ ecore_evas_selection_get(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection } EAPI Eina_Bool -ecore_evas_drag_start(Ecore_Evas *ee, unsigned int seat, Eina_Content *content, Ecore_Evas *drag_rep, const char* action, Ecore_Evas_Drag_Finished terminate_cb, void *data) +ecore_evas_drag_start(Ecore_Evas *ee, unsigned int seat, Eina_Content *content, Ecore_Evas *drag_rep, const char* action, Ecore_Evas_Drag_Finished_Cb terminate_cb, void *data) { EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(content, EINA_FALSE); @@ -5676,14 +5676,14 @@ ecore_evas_drag_cancel(Ecore_Evas *ee, unsigned int seat) } EAPI void -ecore_evas_callback_drop_motion_set(Ecore_Evas *ee, Ecore_Evas_Motion_Cb cb) +ecore_evas_callback_drop_motion_set(Ecore_Evas *ee, Ecore_Evas_Drag_Motion_Cb cb) { ECORE_EVAS_CHECK(ee); ee->func.fn_dnd_motion = cb; } EAPI void -ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_State_Changed cb) +ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_Drag_State_Changed_Cb cb) { ECORE_EVAS_CHECK(ee); ee->func.fn_dnd_state_change = cb; diff --git a/src/lib/ecore_evas/ecore_evas_fallback_selection.c b/src/lib/ecore_evas/ecore_evas_fallback_selection.c index 1088e617f7..b3f59c7921 100644 --- a/src/lib/ecore_evas/ecore_evas_fallback_selection.c +++ b/src/lib/ecore_evas/ecore_evas_fallback_selection.c @@ -26,7 +26,7 @@ fallback_selection_shutdown(Ecore_Evas *ee) } Eina_Bool -fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) { Ecore_Evas_Selection_Callbacks *callbacks = &data->callbacks[selection]; @@ -103,7 +103,7 @@ fallback_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat, Ecore_ return eina_future_resolved(efl_loop_future_scheduler_get(efl_main_loop_get()), value); } Eina_Bool -fallback_dnd_start(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Eina_Array *available_types EINA_UNUSED, Ecore_Evas *drag_rep EINA_UNUSED, Ecore_Evas_Internal_Delivery delivery EINA_UNUSED, Ecore_Evas_Internal_Cancel cancel EINA_UNUSED, const char* action EINA_UNUSED) +fallback_dnd_start(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Eina_Array *available_types EINA_UNUSED, Ecore_Evas *drag_rep EINA_UNUSED, Ecore_Evas_Selection_Internal_Delivery delivery EINA_UNUSED, Ecore_Evas_Selection_Internal_Cancel cancel EINA_UNUSED, const char* action EINA_UNUSED) { return EINA_FALSE; } diff --git a/src/lib/ecore_evas/ecore_evas_private.h b/src/lib/ecore_evas/ecore_evas_private.h index 10191b0152..6fb2c988b5 100644 --- a/src/lib/ecore_evas/ecore_evas_private.h +++ b/src/lib/ecore_evas/ecore_evas_private.h @@ -82,11 +82,11 @@ typedef struct _Ecore_Evas_Interface Ecore_Evas_Interface; typedef struct _Ecore_Evas_Aux_Hint Ecore_Evas_Aux_Hint; typedef struct _Ecore_Evas_Cursor Ecore_Evas_Cursor; -typedef Eina_Bool (*Ecore_Evas_Internal_Delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice); -typedef void (*Ecore_Evas_Internal_Cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer); +typedef Eina_Bool (*Ecore_Evas_Selection_Internal_Delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice); +typedef void (*Ecore_Evas_Selection_Internal_Cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer); typedef struct { - Ecore_Evas_Internal_Delivery delivery; - Ecore_Evas_Internal_Cancel cancel; + Ecore_Evas_Selection_Internal_Delivery delivery; + Ecore_Evas_Selection_Internal_Cancel cancel; Eina_Array *available_types; } Ecore_Evas_Selection_Callbacks; /* Engines interfaces */ @@ -183,10 +183,10 @@ struct _Ecore_Evas_Engine_Func double (*fn_last_tick_get)(Ecore_Evas *ee); - Eina_Bool (*fn_selection_claim)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel); + Eina_Bool (*fn_selection_claim)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel); Eina_Bool (*fn_selection_has_owner)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); Eina_Future* (*fn_selection_request)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_types); // a future containing a Eina_Content, type must be in acceptable_types - Eina_Bool (*fn_dnd_start)(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel, const char *action); + Eina_Bool (*fn_dnd_start)(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel, const char *action); Eina_Bool (*fn_dnd_stop)(Ecore_Evas *ee, unsigned int seat); }; @@ -385,7 +385,7 @@ struct _Ecore_Evas struct { Ecore_Evas *rep; void *data; - Ecore_Evas_Drag_Finished free; + Ecore_Evas_Drag_Finished_Cb free; Eina_Bool accepted; } drag; @@ -531,10 +531,10 @@ EAPI Eina_Position2D ecore_evas_dnd_pos_get(Ecore_Evas *ee, unsigned int seat); void fallback_selection_init(Ecore_Evas *ee); void fallback_selection_shutdown(Ecore_Evas *ee); -Eina_Bool fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel); +Eina_Bool fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel); Eina_Bool fallback_selection_has_owner(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); Eina_Future* fallback_selection_request(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type); -Eina_Bool fallback_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel, const char* action); +Eina_Bool fallback_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel, const char* action); Eina_Bool fallback_dnd_stop(Ecore_Evas *ee, unsigned int seat); #ifdef IPA_YLNO_ESU_LANRETNI_MLE diff --git a/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c b/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c index 3352efb135..c8e2895358 100644 --- a/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c +++ b/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c @@ -458,7 +458,7 @@ end: } static Eina_Bool -_ecore_evas_cocoa_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +_ecore_evas_cocoa_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) { if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) return EINA_FALSE; diff --git a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c index d5cb3d8b49..b2bf7c75ec 100644 --- a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c +++ b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c @@ -2421,7 +2421,7 @@ _clear_selection(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer } static void -_store_selection_cbs(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +_store_selection_cbs(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) { Ecore_Evas_Wl_Selection_Data *sdata; Ecore_Evas_Engine_Wl_Data *edata; @@ -2449,7 +2449,7 @@ _fetch_input(Ecore_Evas *ee, unsigned int seat) } static Eina_Bool -_ecore_evas_wl_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +_ecore_evas_wl_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) { Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection]; @@ -2822,7 +2822,7 @@ _ecore_evas_wl_selection_init(Ecore_Evas *ee) } static Eina_Bool -_ecore_evas_wl_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel, const char *action EINA_UNUSED) +_ecore_evas_wl_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel, const char *action EINA_UNUSED) { Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; const char *tmp_array[eina_array_count(available_types) + 1]; diff --git a/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c b/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c index d0686c535c..7f6eb98e48 100644 --- a/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c +++ b/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c @@ -1232,7 +1232,7 @@ end: } static Eina_Bool -_ecore_evas_win32_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +_ecore_evas_win32_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) { if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) return EINA_FALSE; diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c b/src/modules/ecore_evas/engines/x/ecore_evas_x.c index 36afeb5495..11719ee1b1 100644 --- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c +++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c @@ -4281,7 +4281,7 @@ _store_selection_cbs(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection, Eina } static Eina_Bool -_ecore_evas_x_selection_claim(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel) +_ecore_evas_x_selection_claim(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) { Ecore_Evas_X11_Selection_Data *sdata; Ecore_Evas_Engine_Data_X11 *edata; From b2bd0c548f03b8178e40e0cfa6e9c31c4bff38b1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 8 Mar 2020 20:20:43 +0900 Subject: [PATCH 14/17] evas gl: clip rect with proper size. gc width/height indicates the main output size, if the target surface(fbo) is larger than this, rect won't be drawn. We should clip this with current context size. @fix --- src/modules/evas/engines/gl_common/evas_gl_rectangle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/evas/engines/gl_common/evas_gl_rectangle.c b/src/modules/evas/engines/gl_common/evas_gl_rectangle.c index a188467b58..b070a7157a 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_rectangle.c +++ b/src/modules/evas/engines/gl_common/evas_gl_rectangle.c @@ -12,7 +12,7 @@ evas_gl_common_rect_draw(Evas_Engine_GL_Context *gc, int x, int y, int w, int h) Evas_GL_Texture *mtex = NULL; if ((w <= 0) || (h <= 0)) return; - if (!(RECTS_INTERSECT(x, y, w, h, 0, 0, gc->w, gc->h))) return; + if (!(RECTS_INTERSECT(x, y, w, h, 0, 0, gc->shared->w, gc->shared->h))) return; /* save out clip info */ c = gc->dc->clip.use; cx = gc->dc->clip.x; cy = gc->dc->clip.y; cw = gc->dc->clip.w; ch = gc->dc->clip.h; From 0dcbc26a5a974c76d5db5c6c59652f1ae7c4fb9f Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Sun, 8 Mar 2020 12:25:35 +0100 Subject: [PATCH 15/17] ecore_evas_x: honor forign dnd implementations enlightenment does not use the elm dnd operation implementations. Therefore we have to ensure that we only handle these operations here, when ecore_evas dnd API is used. --- src/modules/ecore_evas/engines/x/ecore_evas_x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c b/src/modules/ecore_evas/engines/x/ecore_evas_x.c index 11719ee1b1..e6463fd6a9 100644 --- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c +++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c @@ -4133,8 +4133,10 @@ _ecore_evas_x_dnd_drop(void *udata EINA_UNUSED, int type EINA_UNUSED, void *even edata = ee->engine.data; if (ee->func.fn_dnd_drop) ee->func.fn_dnd_drop(ee, 1, ecore_evas_dnd_pos_get(ee, 1), _x11_dnd_action_map(drop->action)); - if (!edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].requested_type) + if (edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].delivery && + !edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].requested_type) { + //only abort dnd if we have something to deliver here, otherwise some other dnd implementation in our own window is handling that ecore_x_dnd_send_finished(); } ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(drop->position.x ,drop->position.y)); From 075bab83c4288b5de20f6acfc6b0459656ea85e0 Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Tue, 3 Mar 2020 20:38:58 +0000 Subject: [PATCH 16/17] remove vlc, gst-0.10, xine deps, modules as they are broken they dont work. easier to remove than fix, so... remove :) only gst 1.x supported now. --- .ci/ci-configure.sh | 11 +- .ci/ubuntu-bionic-install-deps.sh | 2 +- meson.build | 3 - meson_options.txt | 16 +- src/generic/emotion/meson.build | 8 - src/generic/emotion/vlc/emotion_generic_vlc.c | 789 ------- src/generic/emotion/vlc/meson.build | 8 - src/generic/evas/meson.build | 10 +- .../emotion/generic/Emotion_Generic_Plugin.h | 148 -- src/modules/emotion/generic/README | 79 - src/modules/emotion/generic/emotion_generic.c | 1908 ----------------- src/modules/emotion/generic/emotion_generic.h | 123 -- src/modules/emotion/generic/meson.build | 24 - src/modules/emotion/libvlc/emotion_libvlc.c | 1555 -------------- src/modules/emotion/libvlc/meson.build | 14 - src/modules/emotion/meson.build | 12 +- src/modules/emotion/xine/emotion_xine.c | 1707 --------------- src/modules/emotion/xine/emotion_xine.h | 118 - .../emotion/xine/emotion_xine_vo_out.c | 766 ------- src/modules/emotion/xine/meson.build | 16 - 20 files changed, 14 insertions(+), 7303 deletions(-) delete mode 100644 src/generic/emotion/meson.build delete mode 100644 src/generic/emotion/vlc/emotion_generic_vlc.c delete mode 100644 src/generic/emotion/vlc/meson.build delete mode 100644 src/modules/emotion/generic/Emotion_Generic_Plugin.h delete mode 100644 src/modules/emotion/generic/README delete mode 100644 src/modules/emotion/generic/emotion_generic.c delete mode 100644 src/modules/emotion/generic/emotion_generic.h delete mode 100644 src/modules/emotion/generic/meson.build delete mode 100644 src/modules/emotion/libvlc/emotion_libvlc.c delete mode 100644 src/modules/emotion/libvlc/meson.build delete mode 100644 src/modules/emotion/xine/emotion_xine.c delete mode 100644 src/modules/emotion/xine/emotion_xine.h delete mode 100644 src/modules/emotion/xine/emotion_xine_vo_out.c delete mode 100644 src/modules/emotion/xine/meson.build diff --git a/.ci/ci-configure.sh b/.ci/ci-configure.sh index 773e536aa1..cd7f9eb889 100755 --- a/.ci/ci-configure.sh +++ b/.ci/ci-configure.sh @@ -13,12 +13,11 @@ if [ "$DISTRO" != "" ] ; then # TODO: # - No libelogind package in fedora 30 repo - # - RPM fusion repo for xine and libvlc # - Ibus ENABLED_LINUX_COPTS=" -Dfb=true -Dsdl=true -Dbuffer=true -Dbuild-id=travis-build \ -Ddebug-threads=true -Dglib=true -Dg-mainloop=true -Dxpresent=true -Dxinput22=true \ - -Devas-loaders-disabler=json -Decore-imf-loaders-disabler= -Demotion-loaders-disabler=libvlc,xine \ - -Demotion-generic-loaders-disabler=vlc -Dharfbuzz=true -Dpixman=true -Dhyphen=true \ + -Devas-loaders-disabler=json -Decore-imf-loaders-disabler= \ + -Dharfbuzz=true -Dpixman=true -Dhyphen=true \ -Dvnc-server=true -Dbindings=luajit,cxx,mono -Delogind=false -Dinstall-eo-files=true -Dphysics=true" # Enabled png, jpeg evas loader for in tree edje file builds @@ -27,8 +26,8 @@ if [ "$DISTRO" != "" ] ; then -Dcrypto=gnutls -Dglib=false -Dgstreamer=false -Dsystemd=false -Dpulseaudio=false \ -Dnetwork-backend=connman -Dxinput2=false -Dtslib=false \ -Devas-loaders-disabler=gst,pdf,ps,raw,svg,xcf,bmp,dds,eet,generic,gif,ico,jp2k,json,pmaps,psd,tga,tgv,tiff,wbmp,webp,xpm \ - -Decore-imf-loaders-disabler=xim,ibus,scim -Demotion-loaders-disabler=gstreamer1,libvlc,xine \ - -Demotion-generic-loaders-disabler=vlc -Dfribidi=false -Dfontconfig=false \ + -Decore-imf-loaders-disabler=xim,ibus,scim \ + -Dfribidi=false -Dfontconfig=false \ -Dedje-sound-and-video=false -Dembedded-lz4=false -Dlibmount=false -Dv4l2=false \ -Delua=true -Dnls=false -Dbindings= -Dlua-interpreter=luajit -Dnative-arch-optimization=false" #evas_filter_parser.c:(.text+0xc59): undefined reference to `lua_getglobal' with interpreter lua @@ -98,7 +97,7 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then export PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig:/usr/local/Cellar/libffi/$LIBFFI_VER/lib/pkgconfig" export CC="ccache gcc" travis_fold meson meson - mkdir build && meson build -Dopengl=full -Decore-imf-loaders-disabler=scim,ibus -Dx11=false -Davahi=false -Deeze=false -Dsystemd=false -Dnls=false -Dcocoa=true -Demotion-loaders-disabler=gstreamer1,libvlc,xine + mkdir build && meson build -Dopengl=full -Decore-imf-loaders-disabler=scim,ibus -Dx11=false -Davahi=false -Deeze=false -Dsystemd=false -Dnls=false -Dcocoa=true -Dgstreamer=false travis_endfold meson else travis_fold meson meson diff --git a/.ci/ubuntu-bionic-install-deps.sh b/.ci/ubuntu-bionic-install-deps.sh index 998e74b084..9eefa7d7fc 100755 --- a/.ci/ubuntu-bionic-install-deps.sh +++ b/.ci/ubuntu-bionic-install-deps.sh @@ -1,4 +1,4 @@ #!/bin/sh sudo apt-get update -y -sudo apt-get install -y build-essential autoconf automake autopoint doxygen check luajit libharfbuzz-dev libpng-dev libudev-dev libwebp-dev libssl-dev libluajit-5.1-dev libfribidi-dev libcogl-gles2-dev libgif-dev libtiff5-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libdbus-1-dev libmount-dev libblkid-dev libpulse-dev libxrandr-dev libxtst-dev libxcursor-dev libxcomposite-dev libxinerama-dev libxkbfile-dev libbullet-dev libvlc-dev libsndfile1-dev libraw-dev libspectre-dev libpoppler-cpp-dev libpam0g-dev liblz4-dev faenza-icon-theme gettext git imagemagick libasound2-dev libbluetooth-dev libfontconfig1-dev libfreetype6-dev libibus-1.0-dev libiconv-hook-dev libjpeg-dev libjpeg-turbo8-dev libpoppler-dev libpoppler-private-dev libproxy-dev librsvg2-dev libscim-dev libsystemd-dev libtool libudisks2-dev libunibreak-dev libxcb-keysyms1-dev libxine2-dev libxss-dev linux-tools-common libcurl4-openssl-dev systemd ccache git binutils-gold python3-pip ninja-build dbus-x11 libavahi-client-dev python3-setuptools libopenjp2-7-dev +sudo apt-get install -y build-essential autoconf automake autopoint doxygen check luajit libharfbuzz-dev libpng-dev libudev-dev libwebp-dev libssl-dev libluajit-5.1-dev libfribidi-dev libcogl-gles2-dev libgif-dev libtiff5-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libdbus-1-dev libmount-dev libblkid-dev libpulse-dev libxrandr-dev libxtst-dev libxcursor-dev libxcomposite-dev libxinerama-dev libxkbfile-dev libbullet-dev libsndfile1-dev libraw-dev libspectre-dev libpoppler-cpp-dev libpam0g-dev liblz4-dev faenza-icon-theme gettext git imagemagick libasound2-dev libbluetooth-dev libfontconfig1-dev libfreetype6-dev libibus-1.0-dev libiconv-hook-dev libjpeg-dev libjpeg-turbo8-dev libpoppler-dev libpoppler-private-dev libproxy-dev librsvg2-dev libscim-dev libsystemd-dev libtool libudisks2-dev libunibreak-dev libxcb-keysyms1-dev libxss-dev linux-tools-common libcurl4-openssl-dev systemd ccache git binutils-gold python3-pip ninja-build dbus-x11 libavahi-client-dev python3-setuptools libopenjp2-7-dev sudo pip3 install meson diff --git a/meson.build b/meson.build index fb77c43570..256256d8a8 100644 --- a/meson.build +++ b/meson.build @@ -456,9 +456,6 @@ endforeach subdir(join_paths('src', 'bin', 'efl')) subdir(join_paths('src', 'generic', 'evas')) -if sys_windows == false - subdir(join_paths('src', 'generic', 'emotion')) -endif subdir('cmakeconfig') subdir(join_paths('src', 'bindings')) subdir(join_paths('src', 'edje_external')) diff --git a/meson_options.txt b/meson_options.txt index 2c6d138981..0907aff980 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -122,7 +122,7 @@ option('g-mainloop', option('gstreamer', type : 'boolean', value : true, - description : 'GStreamer 1.0+ support in efl' + description : 'GStreamer support in efl' ) option('systemd', @@ -200,20 +200,6 @@ option('ecore-imf-loaders-disabler', value : ['ibus'] ) -option('emotion-loaders-disabler', - type : 'array', - description : 'List of video back-ends to disable in efl', - choices : ['gstreamer1', 'libvlc', 'xine'], - value : ['libvlc', 'xine'] -) - -option('emotion-generic-loaders-disabler', - type : 'array', - description : 'List of out-of-process generic binary video loaders to disable in efl', - choices : ['vlc'], - value : ['vlc'] -) - option('harfbuzz', type : 'boolean', value : true, diff --git a/src/generic/emotion/meson.build b/src/generic/emotion/meson.build deleted file mode 100644 index 58cd5294aa..0000000000 --- a/src/generic/emotion/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -generic_loaders = ['vlc'] - -foreach loader : generic_loaders - if get_option('emotion-generic-loaders-disabler').contains(loader) == false - subdir(loader) - endif -endforeach - diff --git a/src/generic/emotion/vlc/emotion_generic_vlc.c b/src/generic/emotion/vlc/emotion_generic_vlc.c deleted file mode 100644 index dcfcbe9e8c..0000000000 --- a/src/generic/emotion/vlc/emotion_generic_vlc.c +++ /dev/null @@ -1,789 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -static int _em_vlc_log_dom = -1; -#define ERR(...) EINA_LOG_DOM_ERR(_em_vlc_log_dom, __VA_ARGS__) -#define DBG(...) EINA_LOG_DOM_DBG(_em_vlc_log_dom, __VA_ARGS__) -#define INF(...) EINA_LOG_DOM_INFO(_em_vlc_log_dom, __VA_ARGS__) -#define WRN(...) EINA_LOG_DOM_WARN(_em_vlc_log_dom, __VA_ARGS__) -#define CRIT(...) EINA_LOG_DOM_CRIT(_em_vlc_log_dom, __VA_ARGS__) - - -typedef struct _App App; -struct _App { - Emotion_Generic_Video_Shared *vs; - Emotion_Generic_Video_Frame vf; - - libvlc_instance_t *libvlc; - libvlc_media_t *m; - libvlc_media_player_t *mp; - libvlc_event_manager_t *event_mgr; - - Ecore_Pipe *fd_read; // read commands from emotion here - Ecore_Pipe *fd_write; // write commands for emotion here - Eina_Lock cmd_mutex;// lock used to send just one command at a time - int last_order; // current command received from emotion - - char *filename; - char *subtitle_path; - char *shmname; - unsigned w, h; - int volume; - Eina_Bool audio_muted; - - Eina_Bool opening; - Eina_Bool closing; - Eina_Bool playing; - Eina_Bool inited; -}; - -static void _player_setup(App *app); - - -/* Utilities to send commands back to emotion */ -#define SEND_CMD_PARAM(app, i) \ - if ((app)->fd_write) \ - if (!ecore_pipe_write((app)->fd_write, &(i), sizeof((i)))) \ - ecore_main_loop_quit(); - -static void -_send_cmd(App *app, int cmd) -{ - if (!app->fd_write) - return; - - eina_lock_take(&app->cmd_mutex); /* LOCK HERE */ - - if (!ecore_pipe_write(app->fd_write, &cmd, sizeof(cmd))) - ecore_main_loop_quit(); -} - -static void -_send_cmd_str(App *app, const char *str) -{ - int len; - - len = str ? strlen(str) + 1 : 0; - if (app->fd_write) - if (!ecore_pipe_write(app->fd_write, &len, sizeof(len))) - ecore_main_loop_quit(); - if (app->fd_write) - if (!ecore_pipe_write(app->fd_write, str, len)) - ecore_main_loop_quit(); -} - -static void -_send_cmd_finish(App *app) -{ - eina_lock_release(&app->cmd_mutex); /* UNLOCK HERE */ -} - -/* Commands sent to the emotion pipe */ -static void -_send_file_closed(App *app) -{ - _send_cmd(app, EM_RESULT_FILE_CLOSE); - _send_cmd_finish(app); -} - -static void -_send_time_changed(App *app) -{ - float new_time; - - if (app->vs->frame_drop > 1) - return; - - new_time = libvlc_media_player_get_time(app->mp); - new_time /= 1000; - _send_cmd(app, EM_RESULT_POSITION_CHANGED); - SEND_CMD_PARAM(app, new_time); - _send_cmd_finish(app); -} - -static void -_send_resize(App *app, int width, int height) -{ - _send_cmd(app, EM_RESULT_FRAME_SIZE); - SEND_CMD_PARAM(app, width); - SEND_CMD_PARAM(app, height); - _send_cmd_finish(app); -} - -static void -_send_track_info(App *app, int cmd, int current, int count, libvlc_track_description_t *desc) -{ - _send_cmd(app, cmd); - SEND_CMD_PARAM(app, current); - SEND_CMD_PARAM(app, count); - while (desc) - { - int tid = desc->i_id; - const char *name = desc->psz_name; - SEND_CMD_PARAM(app, tid); - _send_cmd_str(app, name); - desc = desc->p_next; - } - _send_cmd_finish(app); -} - -static void -_send_all_track_info(App *app) -{ - int track_count, current; - libvlc_track_description_t *desc; - - current = libvlc_audio_get_track(app->mp); - track_count = libvlc_audio_get_track_count(app->mp); - desc = libvlc_audio_get_track_description(app->mp); - - _send_track_info(app, EM_RESULT_AUDIO_TRACK_INFO, - current, track_count, desc); - - current = libvlc_video_get_track(app->mp); - track_count = libvlc_video_get_track_count(app->mp); - desc = libvlc_video_get_track_description(app->mp); - - _send_track_info(app, EM_RESULT_VIDEO_TRACK_INFO, - current, track_count, desc); - - current = libvlc_video_get_spu(app->mp); - track_count = libvlc_video_get_spu_count(app->mp); - desc = libvlc_video_get_spu_description(app->mp); - - _send_track_info(app, EM_RESULT_SPU_TRACK_INFO, - current, track_count, desc); -} - -static void -_send_all_meta_info(App *app) -{ - const char *meta; - - _send_cmd(app, EM_RESULT_META_INFO); - - /* - * Will send in this order: title, artist, album, year, - * genre, comments, disc id and track count. - */ - meta = libvlc_media_get_meta(app->m, libvlc_meta_Title); - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_Artist); - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_Album); - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_Date); - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_Genre); - _send_cmd_str(app, meta); - meta = NULL; // sending empty comments - _send_cmd_str(app, meta); - meta = NULL; // sending empty disc id - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_TrackNumber); - _send_cmd_str(app, meta); - - _send_cmd_finish(app); -} - -static void -_send_length_changed(App *app) -{ - float length = libvlc_media_player_get_length(app->mp); - - length /= 1000; - _send_cmd(app, EM_RESULT_LENGTH_CHANGED); - SEND_CMD_PARAM(app, length); - _send_cmd_finish(app); -} - -static void -_send_seekable_changed(App *app, const struct libvlc_event_t *ev) -{ - int seekable = ev->u.media_player_seekable_changed.new_seekable; - - _send_cmd(app, EM_RESULT_SEEKABLE_CHANGED); - SEND_CMD_PARAM(app, seekable); - _send_cmd_finish(app); -} - -static void -_send_playback_started(App *app) -{ - _send_cmd(app, EM_RESULT_PLAYBACK_STARTED); - _send_cmd_finish(app); -} - -static void -_send_playback_stopped(App *app) -{ - _send_cmd(app, EM_RESULT_PLAYBACK_STOPPED); - _send_cmd_finish(app); -} - -static void -_send_init(App *app) -{ - _send_cmd(app, EM_RESULT_INIT); - _send_cmd_finish(app); -} - -static void -_send_file_set(App *app) -{ - _send_cmd(app, EM_RESULT_FILE_SET); - _send_cmd_finish(app); -} - -static void -_send_file_set_done(App *app, int success) -{ - _send_cmd(app, EM_RESULT_FILE_SET_DONE); - SEND_CMD_PARAM(app, success); - _send_cmd_finish(app); -} - - -/* VLC events and callbacks */ -static void -_event_cb(const struct libvlc_event_t *ev, void *data) -{ - App *app = data; - - ecore_thread_main_loop_begin(); - switch (ev->type) - { - case libvlc_MediaPlayerTimeChanged: - // DBG("libvlc_MediaPlayerTimeChanged"); - _send_time_changed(app); - break; - case libvlc_MediaPlayerLengthChanged: - DBG("libvlc_MediaPlayerLengthChanged"); - _send_length_changed(app); - break; - case libvlc_MediaPlayerSeekableChanged: - DBG("libvlc_MediaPlayerSeekableChanged"); - _send_seekable_changed(app, ev); - break; - case libvlc_MediaPlayerPlaying: - DBG("libvlc_MediaPlayerPlaying"); - libvlc_audio_set_volume(app->mp, app->volume); - libvlc_audio_set_mute(app->mp, app->audio_muted); - _send_playback_started(app); - break; - case libvlc_MediaPlayerStopped: - DBG("libvlc_MediaPlayerStopped"); - _send_playback_stopped(app); - if (app->closing) - { - free(app->filename); - app->filename = NULL; - free(app->subtitle_path); - app->subtitle_path = NULL; - libvlc_media_release(app->m); - app->m = NULL; - libvlc_media_player_release(app->mp); - app->mp = NULL; - emotion_generic_shm_free(app->vs); - app->playing = EINA_FALSE; - app->closing = EINA_FALSE; - _send_file_closed(app); - } - break; - case libvlc_MediaPlayerEndReached: - DBG("libvlc_MediaPlayerEndReached"); - app->playing = EINA_FALSE; - /* vlc had released the media_playere here, we create a new one */ - app->mp = libvlc_media_player_new_from_media(app->m); - _player_setup(app); - _send_playback_stopped(app); - break; - } - ecore_thread_main_loop_end(); -} - -static void -_tmp_playing_event_cb(const struct libvlc_event_t *ev, void *data) -{ - App *app = data; - - if (ev->type != libvlc_MediaPlayerPlaying) - return; - - /* pause and stop listening the temporary event */ - libvlc_event_detach(app->event_mgr,libvlc_MediaPlayerPlaying, - _tmp_playing_event_cb, app); - libvlc_media_player_set_pause(app->mp, 1); - - /* sending size info */ - libvlc_video_get_size(app->mp, 0, &app->w, &app->h); - _send_resize(app, app->w, app->h); - - /* sending total lenght */ - _send_length_changed(app); - - /* sending audio track info */ - _send_all_track_info(app); - - /* sending meta info */ - _send_all_meta_info(app); - - /* ok, we are done! Now let emotion create the shmem for us */ - _send_file_set(app); -} - -static void * -_lock(void *data, void **pixels) -{ - App *app = data; - - if (app->playing) - *pixels = app->vf.frames[app->vs->frame.player]; - else - *pixels = NULL; - - return NULL; // picture identifier, not needed here -} - -static void -_unlock(void *data EINA_UNUSED, void *id EINA_UNUSED, void *const *pixels EINA_UNUSED) -{ -} - -static void -_display(void *data, void *id EINA_UNUSED) -{ - App *app = data; - - if (!app->playing) - return; - - eina_semaphore_lock(&app->vs->lock); - app->vs->frame.last = app->vs->frame.player; - app->vs->frame.player = app->vs->frame.next; - app->vs->frame.next = app->vs->frame.last; - if (!app->vs->frame_drop++) - { - _send_cmd(app, EM_RESULT_FRAME_NEW); - _send_cmd_finish(app); - } - eina_semaphore_release(&app->vs->lock, 1); -} - -static void -_player_setup(App *app) -{ - - libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4); - libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app); - - app->event_mgr = libvlc_media_player_event_manager(app->mp); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerEndReached, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped, - _event_cb, app); -} - -/* Commands received from the emotion pipe */ -static void -_file_set(App *app) -{ - DBG("Path: %s", app->filename); - app->m = libvlc_media_new_path(app->libvlc, app->filename); - if (!app->m) - { - ERR("could not open path: \"%s\"", app->filename); - return; - } - - app->mp = libvlc_media_player_new_from_media(app->m); - if (!app->mp) - { - ERR("could not create new player from media."); - return; - } - - app->opening = EINA_TRUE; - - /* Here we start playing and connect a temporary callback to know when - * the file is parsed and ready to be played for real. - */ - app->event_mgr = libvlc_media_player_event_manager(app->mp); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying, - _tmp_playing_event_cb, app); - - libvlc_media_player_play(app->mp); -} - -static void -_file_set_done(App *app) -{ - int r; - - DBG("Path: %s", app->filename); - app->opening = EINA_FALSE; - - r = emotion_generic_shm_get(app->shmname, &app->vs, &app->vf); - if (!r) - { - free(app->filename); - libvlc_media_release(app->m); - libvlc_media_player_release(app->mp); - app->filename = NULL; - app->m = NULL; - app->mp = NULL; - } - else - { - _player_setup(app); - } - - _send_file_set_done(app, r); -} - -static void -_file_close(App *app) -{ - DBG("closing file"); - - if (!app->mp) - return; - - app->closing = EINA_TRUE; - libvlc_media_player_stop(app->mp); -} - -static void -_stop(App *app) -{ - DBG("Stop"); - if (app->mp) - libvlc_media_player_set_pause(app->mp, 1); -} - -static void -_play(App *app, float pos) -{ - DBG("Play at %.3f", pos); - - if (!app->mp) - return; - - if (app->playing) - { - libvlc_media_player_set_pause(app->mp, 0); - } - else - { - libvlc_time_t new_time = pos * 1000; - libvlc_media_player_set_time(app->mp, new_time); - libvlc_media_player_play(app->mp); - - if (app->subtitle_path) - libvlc_video_set_subtitle_file(app->mp, app->subtitle_path); - - app->playing = EINA_TRUE; - } -} - -static void -_position_set(App *app, float position) -{ - libvlc_time_t new_time; - - DBG("Position set %.3f", position); - if (!app->mp) - return; - - new_time = position * 1000; - libvlc_media_player_set_time(app->mp, new_time); - - if (libvlc_media_player_get_state(app->mp) == libvlc_Paused) - _send_time_changed(app); -} - -static void -_speed_set(App *app, float rate) -{ - DBG("Speed set %.3f", rate); - if (!app->mp) - return; - - libvlc_media_player_set_rate(app->mp, rate); -} - -static void -_mute_set(App *app, int mute) -{ - DBG("Mute %d", mute); - if (!app->mp) - return; - - app->audio_muted = mute; - libvlc_audio_set_mute(app->mp, mute); -} - -static void -_volume_set(App *app, float volume) -{ - DBG("Volume set %.2f", volume); - if (!app->mp) - return; - - app->volume = volume * 100; - libvlc_audio_set_volume(app->mp, app->volume); -} - -static void -_spu_track_set(App *app, int track) -{ - DBG("SPU track %d", track); - libvlc_video_set_spu(app->mp, track); -} - -static void -_audio_track_set(App *app, int track) -{ - DBG("Audio track %d", track); - libvlc_audio_set_track(app->mp, track); -} - -static void -_video_track_set(App *app, int track) -{ - DBG("Video Track %d", track); - libvlc_video_set_track(app->mp, track); -} - -static void -_remote_command(void *data, void *buffer, unsigned int nbyte) -{ - App *app = data; - - if (nbyte == 0) - { - ecore_main_loop_quit(); - return ; - } - - if (app->last_order == EM_CMD_LAST) - { - if (nbyte != sizeof (int)) - { - ERR("didn't receive a valid command from emotion (%i) !", nbyte); - ecore_main_loop_quit(); - return ; - } - - app->last_order = *((int*) buffer); - - if (!app->inited && - app->last_order != EM_CMD_INIT) - { - ERR("wrong init command!"); - ecore_main_loop_quit(); - return ; - } - - switch (app->last_order) - { - case EM_CMD_FILE_SET: - if (app->opening) - { - libvlc_media_release(app->m); - libvlc_media_player_release(app->mp); - free(app->filename); - app->opening = EINA_FALSE; - } - break; - case EM_CMD_FILE_SET_DONE: - _file_set_done(app); - app->last_order = EM_CMD_LAST; - break; - case EM_CMD_FILE_CLOSE: - _file_close(app); - app->last_order = EM_CMD_LAST; - break; - case EM_CMD_STOP: - _stop(app); - app->last_order = EM_CMD_LAST; - break; - } - } - else - { - switch (app->last_order) - { - case EM_CMD_INIT: - app->shmname = strdup(buffer); - app->inited = EINA_TRUE; - _send_init(app); - break; - case EM_CMD_FILE_SET: - app->filename = strdup(buffer); - _file_set(app); - break; - case EM_CMD_SUBTITLE_SET: - app->subtitle_path = strdup(buffer); - break; - case EM_CMD_PLAY: - _play(app, *(float*) buffer); - break; - case EM_CMD_POSITION_SET: - _position_set(app, *(float*) buffer); - break; - case EM_CMD_SPEED_SET: - _speed_set(app, *(float*) buffer); - break; - case EM_CMD_AUDIO_MUTE_SET: - _mute_set(app, *(int*) buffer); - break; - case EM_CMD_VOLUME_SET: - _volume_set(app, *(float*) buffer); - break; - case EM_CMD_SPU_TRACK_SET: - _spu_track_set(app, *(int*) buffer); - break; - case EM_CMD_AUDIO_TRACK_SET: - _audio_track_set(app, *(int*) buffer); - break; - case EM_CMD_VIDEO_TRACK_SET: - _video_track_set(app, *(int*) buffer); - break; - } - app->last_order = EM_CMD_LAST; - } -} - -static void -_dummy(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int nbyte EINA_UNUSED) -{ - /* This function is useless for the pipe we use to send message back - to emotion, but still needed */ -} - -/* Main */ -static Eina_Bool -exit_func(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED) -{ - DBG("Quit signal received !"); - ecore_main_loop_quit(); - return EINA_TRUE; -} - -int -main(int argc, const char *argv[]) -{ - App app; - Ecore_Event_Handler *hld; - int vlc_argc; - - const char *vlc_argv[] = - { - "--quiet", - "--intf", "dummy", /* no interface */ - "--vout", "dummy", /* we don't want video (output) */ - "--no-video-title-show", /* nor the filename displayed */ - "--no-sub-autodetect-file", /* we don't want automatic subtitles */ - "--no-stats", /* no stats */ - "--no-inhibit", /* we don't want interfaces */ - "--no-disable-screensaver", /* we don't want interfaces */ -// XXX: causes newer vlcs to segv! -// "--codec", "avcodec", -// XXX: disable this just in case -// "--demux", "avformat" - }; - vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv); - - memset(&app, 0, sizeof(app)); - if (!eina_init()) - { - EINA_LOG_CRIT("Can't initialize generic vlc player, eina failed."); - return -1; - } - - _em_vlc_log_dom = eina_log_domain_register("emotion_generic_vlc", - EINA_COLOR_CYAN); - if (_em_vlc_log_dom < 0) - { - EINA_LOG_CRIT("Unable to register emotion_generic_vlc log domain."); - goto error; - } - - if (!eina_log_domain_level_check(_em_vlc_log_dom, EINA_LOG_LEVEL_WARN)) - eina_log_domain_level_set("emotion_generic_vlc", EINA_LOG_LEVEL_WARN); - - if (argc < 3) - { - ERR("missing parameters."); - ERR("syntax:\n\t%s ", argv[0]); - goto error; - } - - ecore_init(); - - eina_lock_new(&app.cmd_mutex); - - app.fd_read = ecore_pipe_full_add(_remote_command, &app, - atoi(argv[1]), -1, EINA_FALSE, EINA_FALSE); - app.fd_write = ecore_pipe_full_add(_dummy, NULL, - -1, atoi(argv[2]), EINA_FALSE, EINA_FALSE); - - hld = ecore_event_handler_add(ECORE_EVENT_SIGNAL_HUP, exit_func, NULL); - - app.libvlc = libvlc_new(vlc_argc, vlc_argv); - app.mp = NULL; - app.filename = NULL; - app.subtitle_path = NULL; - app.w = 0; - app.h = 0; - app.opening = EINA_FALSE; - app.playing = EINA_FALSE; - app.inited = EINA_FALSE; - app.last_order = EM_CMD_LAST; - - ecore_main_loop_begin(); - - libvlc_release(app.libvlc); - ecore_pipe_del(app.fd_read); - ecore_pipe_del(app.fd_write); - ecore_event_handler_del(hld); - eina_lock_free(&app.cmd_mutex); - - ecore_shutdown(); - eina_shutdown(); - return 0; - - error: - eina_shutdown(); - return -1; -} -#undef SEND_CMD_PARAM diff --git a/src/generic/emotion/vlc/meson.build b/src/generic/emotion/vlc/meson.build deleted file mode 100644 index b21f4a16df..0000000000 --- a/src/generic/emotion/vlc/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -vlc = dependency('libvlc') - -executable('vlc', - 'emotion_generic_vlc.c', - dependencies: [emotion_generic, eina, ecore, rt, vlc], - install: true, - install_dir: join_paths(dir_lib, 'emotion', 'generic_players', version_name) -) diff --git a/src/generic/evas/meson.build b/src/generic/evas/meson.build index 2e5b58ae4c..e651b8b16a 100644 --- a/src/generic/evas/meson.build +++ b/src/generic/evas/meson.build @@ -1,8 +1,8 @@ -generic_loaders = ['gst', 'pdf', -'ps', -'raw', -'rsvg', -'xcf'] +generic_loaders = [ 'pdf', 'ps', 'raw', 'rsvg', 'xcf' ] + +if get_option('gstreamer') == true + generic_loaders += [ 'gst' ] +endif generic_src = [] generic_deps = [] diff --git a/src/modules/emotion/generic/Emotion_Generic_Plugin.h b/src/modules/emotion/generic/Emotion_Generic_Plugin.h deleted file mode 100644 index 96b69f6421..0000000000 --- a/src/modules/emotion/generic/Emotion_Generic_Plugin.h +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef EMOTION_GENERIC_PLUGIN_H -#define EMOTION_GENERIC_PLUGIN_H - -#include -#include -#include -#include -#include - -#include - -#define DEFAULTWIDTH 320 -#define DEFAULTHEIGHT 240 -#define DEFAULTPITCH 4 - -typedef enum _Emotion_Generic_Cmd Emotion_Generic_Cmd; -typedef enum _Emotion_Generic_Result Emotion_Generic_Result; -typedef struct _Emotion_Generic_Video_Frame Emotion_Generic_Video_Frame; -typedef struct _Emotion_Generic_Video_Shared Emotion_Generic_Video_Shared; - -enum _Emotion_Generic_Cmd -{ - EM_CMD_INIT = 0, // 0 param: shared memory identifier (string) - EM_CMD_PLAY, // 1 param: position (float) - EM_CMD_STOP, // 2 param: none - EM_CMD_FILE_SET, // 3 param: filename (string) - EM_CMD_FILE_SET_DONE, // 4 param: none - EM_CMD_FILE_CLOSE, // 5 param: none - EM_CMD_POSITION_SET, // 6 param: position (float) - EM_CMD_SPEED_SET, // 7 param: speed (float) - EM_CMD_AUDIO_MUTE_SET, // 8 param: muted (int) - EM_CMD_VIDEO_MUTE_SET, // 9 param: muted (int) - EM_CMD_SPU_MUTE_SET, // 10 param: muted (int) - EM_CMD_VOLUME_SET, // 11 param: volume (float) - EM_CMD_AUDIO_TRACK_SET, // 12 param: track id (int) - EM_CMD_VIDEO_TRACK_SET, // 13 param: track id (int) - EM_CMD_SPU_TRACK_SET, // 14 param: track id (int) - EM_CMD_SUBTITLE_SET, // 15 param: subtitle filename (string) - EM_CMD_LAST -}; - -enum _Emotion_Generic_Result -{ - EM_RESULT_INIT = 0, // param: none - EM_RESULT_FILE_SET, // param: none - EM_RESULT_FILE_SET_DONE, // param: success (int) - EM_RESULT_PLAYBACK_STARTED, // param: none - EM_RESULT_PLAYBACK_STOPPED, // param: none - EM_RESULT_FILE_CLOSE, // param: none - EM_RESULT_FRAME_NEW, // param: none - EM_RESULT_FRAME_SIZE, // param: int, int (width, height) - EM_RESULT_LENGTH_CHANGED, // param: float - EM_RESULT_POSITION_CHANGED, // param: float - EM_RESULT_SEEKABLE_CHANGED, // param: int - EM_RESULT_AUDIO_TRACK_INFO, // param: current track, track count, track_id, track_name, track_id2, track_name2, ... - EM_RESULT_VIDEO_TRACK_INFO, // param: current track, track count, track_id, track_name, track_id2, track_name2, ... - EM_RESULT_SPU_TRACK_INFO, // param: current spu, spu count, spu_id, spu_name, spu_id2, spu_name2, ... - // (int, int, int, string, int, string, ...) - EM_RESULT_META_INFO, // param: title, artist, album, year, genre, comments, disc id, count (all int) - EM_RESULT_LAST -}; - -/* structure for frames 2 buffers to keep integrity */ -struct _Emotion_Generic_Video_Frame -{ - unsigned char *frames[3]; -}; - -/* structure for frames 2 buffers to keep integrity */ -struct _Emotion_Generic_Video_Shared -{ - int size; - int width; - int height; - int pitch; - /** - * - "emotion" is the frame from where the Emotion process is reading pixels. - * The player shouldn't touch this frame. - * - "player" is the frame where the slave process is writing pixels. - * The emotion process shouldn't touch this frame. - * - "last" is the last frame that was rendered by the player. Emotion will - * use this frame the next time it will fetch pixels to Evas. - * - "next" is the unused frame. The player currently using the "player" - * should, after finishing this frame, set "last" to "player", and "player" - * to "next", and finally "next" to "last" so this operation can be done - * many times in case that Emotion does not request pixels fast enough. - */ - struct { - int emotion; - int player; - int last; - int next; - } frame; - Eina_Semaphore lock; - int frame_drop; -}; - -static inline int -emotion_generic_shm_get(const char *shmname, Emotion_Generic_Video_Shared **vs, Emotion_Generic_Video_Frame *vf) -{ - int shmfd = -1; - int size; - Emotion_Generic_Video_Shared *t_vs; - - shmfd = shm_open(shmname, O_RDWR, 0700); - if (shmfd == -1) - { - fprintf(stderr, "player: could not open shm: %s: %s\n", - shmname, strerror(errno)); - return 0; - } - - t_vs = mmap(NULL, sizeof(*t_vs), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0); - if (t_vs == MAP_FAILED) - { - fprintf(stderr, "player: could not map shared memory: %s\n", - strerror(errno)); - close(shmfd); - return 0; - } - size = t_vs->size; - munmap(t_vs, sizeof(*t_vs)); - t_vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0); - if (t_vs == MAP_FAILED) - { - fprintf(stderr, "player: could not map shared memory: %s\n", - strerror(errno)); - close(shmfd); - return 0; - } - close(shmfd); - - vf->frames[0] = (unsigned char *)t_vs + sizeof(*t_vs); - vf->frames[1] = (unsigned char *)t_vs + sizeof(*t_vs) + t_vs->height * t_vs->width * t_vs->pitch; - vf->frames[2] = (unsigned char *)t_vs + sizeof(*t_vs) + 2 * t_vs->height * t_vs->width * t_vs->pitch; - - *vs = t_vs; - - return 1; -} - -static inline void -emotion_generic_shm_free(Emotion_Generic_Video_Shared *vs) -{ - munmap(vs, vs->size); -} - -#endif // EMOTION_GENERIC_PLUGIN_H diff --git a/src/modules/emotion/generic/README b/src/modules/emotion/generic/README deleted file mode 100644 index c2a028de5d..0000000000 --- a/src/modules/emotion/generic/README +++ /dev/null @@ -1,79 +0,0 @@ -Generic - emotion backend -========================= - -This generic player backend executes a separate player in another -process. It receives the bytes to be drawn on the emotion object through -a shared memory, and communicates with the player through a pipe, using -the player standard input/output. - -The player must communicate with emotion using the defined commands -specified in the Emotion_Generic_Plugin.h. It doesn't need to link -against emotion, just include this file for easier implementation. - - -How does it work? -================= - -When the module is initialized for an emotion object, it starts another process -that runs the specified player. The player command line is specified using: - - emotion_object_module_option_set(object, "player", ); - -A player using libvlc is being provided now, and the generic module internally -checks if the command given was "vlc", in which case it will use this provided -vlc player. - -When a file is set to this object, it will send the file name to the player, and -expect an answer that will tell that the player already decoded a bit of the -file, and the video size is already set on the module, so it can allocate a -shared memory with correct size. - -The module then allocates the memory, sends a message to the player and expect -an answer. After this last answer, the "open_done" signal is sent and the module -knows that it is ready for playing. Commands sent before the module being ready -are now applied (and play is resumed if necessary). - -During this setup stage, info about the file set will be stored in the module, -so commands like meta data get, length get and so will be available to sync -calls like emotion_object_play_length_get(); - -If the player dies for any reason, a "decode_stop" signal is sent (should change -to something more like an error signal), and if play is called again, it will be -restarted. The playback should start from the same point it was before the -player crashed, if the player supports seek on the current media format). - -TODO -==== - - - Provide better description for commands; - - Explain in details the communication emotion <-> player; - - Make more common functions for players; - - (maybe) add support for named pipes, so we don't rely on standard in/out - for communication; - - Add a detection on the player to know that the emotion process died (so it - can just exit); - - shmname should contain the child pid too; - - better names for commands, maybe add namespace everywhere; - - -questions -========= - - - Using semaphores to lock the critical region between process, and pthread - mutexes for the threads inside the player. Should move to only one type - (semphores or mutexes)? - - There are 2 inline functions insde Emotion_Generic_Plugin.h to make it easier - for the player to get the shared memory correctly. Any problem with this? - Would be good to add more functions/macros to make common tasks like - parsing commands there too? - - Should move players to another project (outside of emotion)? - - -problems -======== - - file_set has some critical time when file is not set yet when we can't call - some functions (I think only another file_set now); - - communication player -> emotion depends on '\n' to delimitate commands, will - remove this soon (fix this urgently!); - - need to implement missing APIs; - diff --git a/src/modules/emotion/generic/emotion_generic.c b/src/modules/emotion/generic/emotion_generic.c deleted file mode 100644 index 601e9e2d92..0000000000 --- a/src/modules/emotion/generic/emotion_generic.c +++ /dev/null @@ -1,1908 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "emotion_modules.h" -#include "emotion_generic.h" - -static Eina_Prefix *pfx = NULL; -static Eina_List *_generic_players = NULL; -static int _emotion_init_count = 0; - -static int _emotion_generic_log_domain = -1; -#ifdef DBG -#undef DBG -#endif -#define DBG(...) EINA_LOG_DOM_DBG(_emotion_generic_log_domain, __VA_ARGS__) - -#ifdef INF -#undef INF -#endif -#define INF(...) EINA_LOG_DOM_INFO(_emotion_generic_log_domain, __VA_ARGS__) - -#ifdef WRN -#undef WRN -#endif -#define WRN(...) EINA_LOG_DOM_WARN(_emotion_generic_log_domain, __VA_ARGS__) - -#ifdef ERR -#undef ERR -#endif -#define ERR(...) EINA_LOG_DOM_ERR(_emotion_generic_log_domain, __VA_ARGS__) - -#ifdef CRI -#undef CRI -#endif -#define CRI(...) EINA_LOG_DOM_CRIT(_emotion_generic_log_domain, __VA_ARGS__) - - -static Eina_Bool _fork_and_exec(Emotion_Generic_Video *ev); -static void em_partial_shutdown(Emotion_Generic_Video *ev); - - -static void -_player_send_cmd(Emotion_Generic_Video *ev, int cmd) -{ - if (cmd >= EM_CMD_LAST) - { - ERR("invalid command to player."); - return; - } - if (!ev->fd_write) - { - ERR("you should wait for emotion to be ready to take action."); - return; - } - ecore_pipe_write(ev->fd_write, &cmd, sizeof(cmd)); -} - -static void -_player_send_int(Emotion_Generic_Video *ev, int number) -{ - if (!ev->fd_write) - { - ERR("you should wait for emotion to be ready to take action."); - return; - } - ecore_pipe_write(ev->fd_write, &number, sizeof(number)); -} - -static void -_player_send_float(Emotion_Generic_Video *ev, float number) -{ - if (!ev->fd_write) - { - ERR("you should wait for emotion to be ready to take action."); - return; - } - ecore_pipe_write(ev->fd_write, &number, sizeof(number)); -} - -static void -_player_send_str(Emotion_Generic_Video *ev, const char *str, Eina_Bool stringshared) -{ - int len; - - if (stringshared) - len = str ? eina_stringshare_strlen(str) + 1 : 0; - else - len = str ? strlen(str) + 1 : 0; - - if (str) - ecore_pipe_write(ev->fd_write, str, len); -} - -static Eina_Bool -_create_shm_data(Emotion_Generic_Video *ev, const char *shmname) -{ - int shmfd; - int npages; - size_t size; - Emotion_Generic_Video_Shared *vs; - - shmfd = shm_open(shmname, O_CREAT | O_RDWR | O_TRUNC, 0700); - if (shmfd == -1) - { - ERR("player: could not create shm %s: %s", shmname, strerror(errno)); - return 0; - } - size = 3 * (ev->w * ev->h * DEFAULTPITCH) + sizeof(*vs); - - npages = (int)(size / getpagesize()) + 1; - size = npages * getpagesize(); - - if (ftruncate(shmfd, size)) - { - ERR("error when allocating shared memory (size = %zd): " - "%s", size, strerror(errno)); - close(shmfd); - shm_unlink(shmname); - return EINA_FALSE; - } - vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0); - if (vs == MAP_FAILED) - { - ERR("error when mapping shared memory: %s", strerror(errno)); - close(shmfd); - shm_unlink(shmname); - return EINA_FALSE; - } - close(shmfd); - - vs->size = size; - vs->width = ev->w; - vs->height = ev->h; - vs->pitch = DEFAULTPITCH; - vs->frame.emotion = 0; - vs->frame.player = 1; - vs->frame.last = 2; - vs->frame.next = 2; - vs->frame_drop = 0; - if (!eina_semaphore_new(&vs->lock, 1)) - { - ERR("can not create semaphore"); - munmap(vs, size); - shm_unlink(shmname); - return EINA_FALSE; - } - ev->frame.frames[0] = (unsigned char *)vs + sizeof(*vs); - ev->frame.frames[1] = (unsigned char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch; - ev->frame.frames[2] = (unsigned char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch; - - if (ev->shared) - munmap(ev->shared, ev->shared->size); - ev->shared = vs; - - return EINA_TRUE; -} - -static void -_player_new_frame(Emotion_Generic_Video *ev) -{ - if (!ev->file_ready) - return; - _emotion_frame_new(ev->obj); -} - -static void -_file_open(Emotion_Generic_Video *ev) -{ - INF("Opening file: %s", ev->filename); - ev->drop = 0; - - if (!ev->ready || !ev->filename) - return; - _player_send_cmd(ev, EM_CMD_FILE_SET); - _player_send_str(ev, ev->filename, EINA_TRUE); -} - -static void -_player_file_set_done(Emotion_Generic_Video *ev) -{ - if (ev->file_changed) - { - _file_open(ev); - ev->file_changed = EINA_FALSE; - return; - } - - if (!_create_shm_data(ev, ev->shmname)) - { - ERR("could not create shared memory."); - return; - } - _player_send_cmd(ev, EM_CMD_FILE_SET_DONE); -} - -static void -_player_ready(Emotion_Generic_Video *ev) -{ - INF("received: player ready."); - - ev->initializing = EINA_FALSE; - ev->ready = EINA_TRUE; - - if (!ev->filename) - return; - - _file_open(ev); -} - -static Eina_Bool -_player_cmd_param_read(Emotion_Generic_Video *ev, void *param, size_t size) -{ - ssize_t done, todo, i; - - /* When a parameter must be read, we cannot make sure it will be entirely - * available. Thus we store the bytes that could be read in a temp buffer, - * and when more data is read we try to complete the buffer and finally use - * the read value. - */ - if (!ev->cmd.tmp) - { - ev->cmd.tmp = malloc(size); - ev->cmd.i = 0; - ev->cmd.total = size; - } - - todo = ev->cmd.total - ev->cmd.i; - i = ev->cmd.i; - - done = (ev->offset + todo > ev->length) ? ev->length - ev->offset : todo; - memcpy(&ev->cmd.tmp[i], &ev->buffer[ev->offset], done); - ev->offset += done; - - if (done == todo) - { - memcpy(param, ev->cmd.tmp, size); - free(ev->cmd.tmp); - ev->cmd.tmp = NULL; - return EINA_TRUE; - } - - if (done > 0) - ev->cmd.i += done; - - return EINA_FALSE; -} - -static void -_player_frame_resize(Emotion_Generic_Video *ev) -{ - int w, h; - - w = ev->cmd.param.size.width; - h = ev->cmd.param.size.height; - - INF("received frame resize: %dx%d", w, h); - ev->w = w; - ev->h = h; - ev->ratio = (float)w / h; - - _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio); -} - -static void -_player_length_changed(Emotion_Generic_Video *ev) -{ - float length = ev->cmd.param.f_num; - - INF("received length changed: %0.3f", length); - - ev->len = length; - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); -} - -static void -_player_position_changed(Emotion_Generic_Video *ev) -{ - float position = ev->cmd.param.f_num; - - // INF("received position changed: %0.3f", position); - - ev->pos = position; - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); -/* hmmm. no _emotion_progress_set() is for "buffering" progress. - if (ev->len == 0) - return; - - float progress = ev->pos / ev->len; - char buf[16]; - snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100); - - _emotion_progress_set(ev->obj, buf, progress); - */ -} - -static void -_player_seekable_changed(Emotion_Generic_Video *ev) -{ - int seekable = ev->cmd.param.i_num; - - INF("received seekable changed: %d", seekable); - - seekable = !!seekable; - - ev->seekable = seekable; -} - -static void -_audio_channels_free(Emotion_Generic_Video *ev) -{ - int i; - for (i = 0; i < ev->audio_channels_count; i++) - eina_stringshare_del(ev->audio_channels[i].name); - free(ev->audio_channels); - ev->audio_channels = NULL; - ev->audio_channels_count = 0; -} - -static void -_video_channels_free(Emotion_Generic_Video *ev) -{ - int i; - for (i = 0; i < ev->video_channels_count; i++) - eina_stringshare_del(ev->video_channels[i].name); - free(ev->video_channels); - ev->video_channels = NULL; - ev->video_channels_count = 0; -} - -static void -_spu_channels_free(Emotion_Generic_Video *ev) -{ - int i; - for (i = 0; i < ev->spu_channels_count; i++) - eina_stringshare_del(ev->spu_channels[i].name); - free(ev->spu_channels); - ev->spu_channels = NULL; - ev->spu_channels_count = 0; -} - -static void -_player_tracks_info(Emotion_Generic_Video *ev, Emotion_Generic_Channel **channels, int *count, int *current) -{ - Emotion_Generic_Channel *pchannels; - int i; - - *count = ev->cmd.param.track.total; - *current = ev->cmd.param.track.current; - pchannels = ev->cmd.param.track.channels; - - INF("number of tracks: %d (current = %d):", *count, *current); - for (i = 0; i < *count; i++) - { - INF("\tchannel %d: %s", pchannels[i].id, pchannels[i].name); - } - - *channels = pchannels; -} - -static void -_player_audio_tracks_info(Emotion_Generic_Video *ev) -{ - INF("Receiving audio channels:"); - if (ev->audio_channels_count) - _audio_channels_free(ev); - - _player_tracks_info(ev, &ev->audio_channels, &ev->audio_channels_count, - &ev->audio_channel_current); -} - -static void -_player_video_tracks_info(Emotion_Generic_Video *ev) -{ - INF("Receiving video channels:"); - if (ev->video_channels_count) - _video_channels_free(ev); - - _player_tracks_info(ev, &ev->video_channels, &ev->video_channels_count, - &ev->video_channel_current); -} - -static void -_player_spu_tracks_info(Emotion_Generic_Video *ev) -{ - INF("Receiving spu channels:"); - if (ev->spu_channels_count) - _spu_channels_free(ev); - - _player_tracks_info(ev, &ev->spu_channels, &ev->spu_channels_count, - &ev->spu_channel_current); -} - -static void -_player_meta_info_free(Emotion_Generic_Video *ev) -{ - eina_stringshare_replace(&ev->meta.title, NULL); - eina_stringshare_replace(&ev->meta.artist, NULL); - eina_stringshare_replace(&ev->meta.album, NULL); - eina_stringshare_replace(&ev->meta.year, NULL); - eina_stringshare_replace(&ev->meta.genre, NULL); - eina_stringshare_replace(&ev->meta.comment, NULL); - eina_stringshare_replace(&ev->meta.disc_id, NULL); - eina_stringshare_replace(&ev->meta.count, NULL); -} - -static void -_player_meta_info_read(Emotion_Generic_Video *ev) -{ - INF("Receiving meta info:"); - _player_meta_info_free(ev); - ev->meta.title = ev->cmd.param.meta.title; - ev->meta.artist = ev->cmd.param.meta.artist; - ev->meta.album = ev->cmd.param.meta.album; - ev->meta.year = ev->cmd.param.meta.year; - ev->meta.genre = ev->cmd.param.meta.genre; - ev->meta.comment = ev->cmd.param.meta.comment; - ev->meta.disc_id = ev->cmd.param.meta.disc_id; - ev->meta.count = ev->cmd.param.meta.count; - INF("title: '%s'", ev->meta.title); - INF("artist: '%s'", ev->meta.artist); - INF("album: '%s'", ev->meta.album); - INF("year: '%s'", ev->meta.year); - INF("genre: '%s'", ev->meta.genre); - INF("comment: '%s'", ev->meta.comment); - INF("disc_id: '%s'", ev->meta.disc_id); - INF("count: '%s'", ev->meta.count); -} - -static void -_player_file_closed(Emotion_Generic_Video *ev) -{ - INF("Closed previous file."); - eina_semaphore_free(&ev->shared->lock); - ev->closing = EINA_FALSE; - - if (ev->opening) - _file_open(ev); -} - -static void -_player_open_done(Emotion_Generic_Video *ev) -{ - int success; - - success = ev->cmd.param.i_num; - shm_unlink(ev->shmname); - - if (ev->file_changed) - { - _file_open(ev); - ev->file_changed = EINA_FALSE; - return; - } - - ev->opening = EINA_FALSE; - if (!success) - { - ERR("Could not open file."); - return; - } - - ev->file_ready = EINA_TRUE; - - _emotion_open_done(ev->obj); - - _player_send_cmd(ev, EM_CMD_VOLUME_SET); - _player_send_float(ev, ev->volume); - - _player_send_cmd(ev, EM_CMD_SPEED_SET); - _player_send_float(ev, ev->speed); - - int mute = ev->audio_mute; - _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET); - _player_send_int(ev, mute); - - mute = ev->video_mute; - _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET); - _player_send_int(ev, mute); - - mute = ev->spu_mute; - _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET); - _player_send_int(ev, mute); - - if (ev->play) - { - _player_send_cmd(ev, EM_CMD_PLAY); - _player_send_float(ev, ev->pos); - } - - INF("Open done"); -} - -static void -_player_cmd_process(Emotion_Generic_Video *ev) -{ - switch (ev->cmd.type) { - case EM_RESULT_INIT: - _player_ready(ev); - break; - case EM_RESULT_FRAME_NEW: - _player_new_frame(ev); - break; - case EM_RESULT_FILE_SET: - _player_file_set_done(ev); - break; - case EM_RESULT_FILE_SET_DONE: - _player_open_done(ev); - break; - case EM_RESULT_FILE_CLOSE: - _player_file_closed(ev); - break; - case EM_RESULT_PLAYBACK_STARTED: - _emotion_playback_started(ev->obj); - break; - case EM_RESULT_PLAYBACK_STOPPED: - ev->play = 0; - _emotion_playback_finished(ev->obj); - _emotion_decode_stop(ev->obj); - break; - case EM_RESULT_FRAME_SIZE: - _player_frame_resize(ev); - break; - case EM_RESULT_LENGTH_CHANGED: - _player_length_changed(ev); - break; - case EM_RESULT_POSITION_CHANGED: - _player_position_changed(ev); - break; - case EM_RESULT_SEEKABLE_CHANGED: - _player_seekable_changed(ev); - break; - case EM_RESULT_AUDIO_TRACK_INFO: - _player_audio_tracks_info(ev); - break; - case EM_RESULT_VIDEO_TRACK_INFO: - _player_video_tracks_info(ev); - break; - case EM_RESULT_SPU_TRACK_INFO: - _player_spu_tracks_info(ev); - break; - case EM_RESULT_META_INFO: - _player_meta_info_read(ev); - break; - default: - WRN("received wrong command: %d", ev->cmd.type); - } - - ev->cmd.type = -1; -} - -static void -_player_cmd_single_int_process(Emotion_Generic_Video *ev) -{ - if (!_player_cmd_param_read(ev, &ev->cmd.param.i_num, sizeof(ev->cmd.param.i_num))) - return; - - _player_cmd_process(ev); -} - -static void -_player_cmd_single_float_process(Emotion_Generic_Video *ev) -{ - if (!_player_cmd_param_read(ev, &ev->cmd.param.f_num, sizeof(ev->cmd.param.f_num))) - return; - - _player_cmd_process(ev); -} - -static void -_player_cmd_double_int_process(Emotion_Generic_Video *ev) -{ - int param; - - if (ev->cmd.num_params == 0) - { - ev->cmd.num_params = 2; - ev->cmd.cur_param = 0; - ev->cmd.param.size.width = 0; - ev->cmd.param.size.height = 0; - } - - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - - if (ev->cmd.cur_param == 0) - ev->cmd.param.size.width = param; - else - ev->cmd.param.size.height = param; - - ev->cmd.cur_param++; - if (ev->cmd.cur_param == ev->cmd.num_params) - _player_cmd_process(ev); -} - -static void -_player_cmd_track_info(Emotion_Generic_Video *ev) -{ - int param; - int i; - - if (ev->cmd.num_params == 0) - { - ev->cmd.cur_param = 0; - ev->cmd.num_params = 2; - ev->cmd.param.track.channels = NULL; - ev->cmd.s_len = -1; - } - - while (ev->cmd.cur_param < 2) - { - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - - if (ev->cmd.cur_param == 0) - ev->cmd.param.track.current = param; - else - { - ev->cmd.param.track.total = param; - ev->cmd.num_params += param * 2; - ev->cmd.param.track.channels = - calloc(param, sizeof(*ev->cmd.param.track.channels)); - } - ev->cmd.cur_param++; - } - - if (ev->cmd.cur_param == ev->cmd.num_params) - { - _player_cmd_process(ev); - return; - } - - i = (ev->cmd.cur_param - 2) / 2; - if ((ev->cmd.cur_param % 2) == 0) // reading track id - { - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - ev->cmd.param.track.channels[i].id = param; - ev->cmd.cur_param++; - } - else // reading track name - { - char buf[PATH_MAX]; - - if (ev->cmd.s_len == -1) - { - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - ev->cmd.s_len = param; - } - - if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len)) - return; - ev->cmd.param.track.channels[i].name = - eina_stringshare_add_length(buf, ev->cmd.s_len); - ev->cmd.cur_param++; - ev->cmd.s_len = -1; - } - - if (ev->cmd.cur_param == ev->cmd.num_params) - _player_cmd_process(ev); -} - -static void -_player_cmd_meta_info(Emotion_Generic_Video *ev) -{ - int param; - const char *info; - char buf[PATH_MAX]; - - if (ev->cmd.num_params == 0) - { - ev->cmd.cur_param = 0; - ev->cmd.num_params = 8; - ev->cmd.param.meta.title = NULL; - ev->cmd.param.meta.artist = NULL; - ev->cmd.param.meta.album = NULL; - ev->cmd.param.meta.year = NULL; - ev->cmd.param.meta.genre = NULL; - ev->cmd.param.meta.comment = NULL; - ev->cmd.param.meta.disc_id = NULL; - ev->cmd.param.meta.count = NULL; - ev->cmd.s_len = -1; - } - - if (ev->cmd.s_len == -1) - { - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - ev->cmd.s_len = param; - } - - if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len)) - return; - - info = eina_stringshare_add_length(buf, ev->cmd.s_len); - ev->cmd.s_len = -1; - - if (ev->cmd.cur_param == 0) - ev->cmd.param.meta.title = info; - else if (ev->cmd.cur_param == 1) - ev->cmd.param.meta.artist = info; - else if (ev->cmd.cur_param == 2) - ev->cmd.param.meta.album = info; - else if (ev->cmd.cur_param == 3) - ev->cmd.param.meta.year = info; - else if (ev->cmd.cur_param == 4) - ev->cmd.param.meta.genre = info; - else if (ev->cmd.cur_param == 5) - ev->cmd.param.meta.comment = info; - else if (ev->cmd.cur_param == 6) - ev->cmd.param.meta.disc_id = info; - else if (ev->cmd.cur_param == 7) - ev->cmd.param.meta.count = info; - - ev->cmd.cur_param++; - - if (ev->cmd.cur_param == 8) - _player_cmd_process(ev); -} - -static void -_player_cmd_read(Emotion_Generic_Video *ev) -{ - if (ev->cmd.type < 0) - { - if (!_player_cmd_param_read(ev, &ev->cmd.type, sizeof(ev->cmd.type))) - return; - ev->cmd.num_params = 0; - } - - switch (ev->cmd.type) { - case EM_RESULT_INIT: - case EM_RESULT_FILE_SET: - case EM_RESULT_PLAYBACK_STARTED: - case EM_RESULT_PLAYBACK_STOPPED: - case EM_RESULT_FILE_CLOSE: - case EM_RESULT_FRAME_NEW: - _player_cmd_process(ev); - break; - case EM_RESULT_FILE_SET_DONE: - case EM_RESULT_SEEKABLE_CHANGED: - _player_cmd_single_int_process(ev); - break; - case EM_RESULT_LENGTH_CHANGED: - case EM_RESULT_POSITION_CHANGED: - _player_cmd_single_float_process(ev); - break; - case EM_RESULT_FRAME_SIZE: - _player_cmd_double_int_process(ev); - break; - case EM_RESULT_AUDIO_TRACK_INFO: - case EM_RESULT_VIDEO_TRACK_INFO: - case EM_RESULT_SPU_TRACK_INFO: - _player_cmd_track_info(ev); - break; - case EM_RESULT_META_INFO: - _player_cmd_meta_info(ev); - break; - - default: - WRN("received wrong command: %d", ev->cmd.type); - ev->cmd.type = -1; - } -} - -static void -_player_cmd_handler_cb(void *data, void *buffer, unsigned int nbyte) -{ - Emotion_Generic_Video *ev = data; - - ev->buffer = buffer; - ev->length = nbyte; - ev->offset = 0; - - _player_cmd_read(ev); - - ev->buffer = NULL; - ev->length = 0; -} - -static Eina_Bool -_player_data_cb(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Exe_Event_Data *ev = event; - Emotion_Generic_Video *evideo = data; - int i; - - if (ev->exe != evideo->player.exe) - { - INF("slave != ev->exe"); - return ECORE_CALLBACK_PASS_ON; - } - - for (i = 0; ev->lines[i].line; i++) - INF("received input from player: \"%s\"", ev->lines[i].line); - - return ECORE_CALLBACK_DONE; -} - -static Eina_Bool -_player_add_cb(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Exe_Event_Add *event_add = event; - Ecore_Exe *player = event_add->exe; - Emotion_Generic_Video *ev = data; - - if (ev->player.exe != player) - { - INF("ev->player != player."); - return ECORE_CALLBACK_PASS_ON; - } - - _player_send_cmd(ev, EM_CMD_INIT); - _player_send_str(ev, ev->shmname, EINA_TRUE); - - return ECORE_CALLBACK_DONE; -} - -static Eina_Bool -_player_del_cb(void *data, int type EINA_UNUSED, void *event EINA_UNUSED) -{ - Ecore_Exe_Event_Del *event_del = event; - Ecore_Exe *player = event_del->exe; - Emotion_Generic_Video *ev = data; - - if (ev->player.exe != player) - { - INF("ev->player != player."); - return ECORE_CALLBACK_PASS_ON; - } - - ERR("player died."); - - ev->player.exe = NULL; - ev->ready = EINA_FALSE; - ev->file_ready = EINA_FALSE; - ecore_pipe_del(ev->fd_read); - ecore_pipe_del(ev->fd_write); - ev->fd_read = NULL; - ev->fd_write = NULL; - _emotion_decode_stop(ev->obj); - - return ECORE_CALLBACK_DONE; -} - -static void -_player_dummy(void *data EINA_UNUSED, - void *buffer EINA_UNUSED, - unsigned int nbyte EINA_UNUSED) -{ -} - -static Eina_Bool -_player_exec(Emotion_Generic_Video *ev) -{ - Ecore_Pipe *in; - Ecore_Pipe *out; - char buf[PATH_MAX]; - - out = ecore_pipe_full_add(_player_dummy, NULL, -1, -1, EINA_TRUE, EINA_FALSE); - if (!out) - { - ERR("could not create pipe for communication emotion -> player: %s", strerror(errno)); - return EINA_FALSE; - } - - in = ecore_pipe_full_add(_player_cmd_handler_cb, ev, -1, -1, EINA_FALSE, EINA_TRUE); - if (!in) - { - ERR("could not create pipe for communication player -> emotion: %s", strerror(errno)); - ecore_pipe_del(in); - ecore_pipe_del(out); - return EINA_FALSE; - } - - snprintf(buf, sizeof(buf), "%s %d %d", ev->engine->path, - ecore_pipe_read_fd(out), - ecore_pipe_write_fd(in)); - - ev->player.exe = ecore_exe_pipe_run( - buf, ECORE_EXE_NOT_LEADER | ECORE_EXE_TERM_WITH_PARENT, ev); - - INF("created pipe emotion -> player: %d -> %d", - ecore_pipe_write_fd(out), ecore_pipe_read_fd(out)); - INF("created pipe player -> emotion: %d -> %d", - ecore_pipe_write_fd(in), ecore_pipe_read_fd(in)); - - ecore_pipe_write_close(in); - ecore_pipe_read_close(out); - - if (!ev->player.exe) - { - ecore_pipe_del(in); - ecore_pipe_del(out); - return EINA_FALSE; - } - - ev->fd_read = in; - ev->fd_write = out; - - return EINA_TRUE; -} - -static Eina_Bool -_fork_and_exec(Emotion_Generic_Video *ev) -{ - char shmname[256]; - - snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%p_%f", - getpid(), ev->obj, ecore_time_get()); - - ev->shmname = eina_stringshare_add(shmname); - - ev->player_add = ecore_event_handler_add(ECORE_EXE_EVENT_ADD, - _player_add_cb, ev); - ev->player_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, - _player_del_cb, ev); - ev->player_data = ecore_event_handler_add(ECORE_EXE_EVENT_DATA, - _player_data_cb, ev); - - if (!_player_exec(ev)) - { - eina_stringshare_del(ev->shmname); - ecore_event_handler_del(ev->player_add); - ecore_event_handler_del(ev->player_del); - ecore_event_handler_del(ev->player_data); - ERR("could not start player."); - return EINA_FALSE; - } - - ev->initializing = EINA_TRUE; - - return EINA_TRUE; -} - -typedef struct _Delay_Munmap Delay_Munmap; -struct _Delay_Munmap -{ - void *map; - size_t size; -}; - -static void -_delayed_munmap(void *data, Evas *e, void *event_info EINA_UNUSED) -{ - Delay_Munmap *dm = data; - - evas_event_callback_del_full(e, EVAS_CALLBACK_RENDER_POST, _delayed_munmap, data); - fprintf(stderr, "munmapping !\n"); - munmap(dm->map, dm->size); - free(dm); -} - -static void -_delayed_next_frame(void *data, Evas *e, void *event_info EINA_UNUSED) -{ - evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, _delayed_munmap, data); - evas_event_callback_del_full(e, EVAS_CALLBACK_RENDER_PRE, _delayed_next_frame, data); -} - -static void -em_partial_shutdown(Emotion_Generic_Video *ev) -{ - if (ev->player.exe) - { - ecore_exe_terminate(ev->player.exe); - ecore_exe_free(ev->player.exe); - ev->player.exe = NULL; - } - - ev->file_ready = EINA_FALSE; - - if (ev->shared) - { - Evas_Object *o; - Delay_Munmap *dm; - - dm = malloc(sizeof (Delay_Munmap)); - if (dm) - { - dm->map = ev->shared; - dm->size = ev->shared->size; - evas_event_callback_add(evas_object_evas_get(ev->obj), - EVAS_CALLBACK_RENDER_PRE, - _delayed_next_frame, dm); - } - - o = emotion_object_image_get(ev->obj); - evas_object_image_data_set(o, NULL); - evas_object_image_size_set(o, 1, 1); - } - ev->shared = NULL; - - _emotion_image_reset(ev->obj); - - if (ev->fd_read) - ecore_pipe_del(ev->fd_read); - ev->fd_read = NULL; - if (ev->fd_write) - ecore_pipe_del(ev->fd_write); - ev->fd_write = NULL; - - if (ev->player_add) ecore_event_handler_del(ev->player_add); - ev->player_add = NULL; - if (ev->player_data) ecore_event_handler_del(ev->player_data); - ev->player_data = NULL; - if (ev->player_del) ecore_event_handler_del(ev->player_del); - ev->player_del = NULL; -} - - -/* Emotion interface */ -static void * -em_add(const Emotion_Engine *api, Evas_Object *obj, const Emotion_Module_Options *opt EINA_UNUSED) -{ - Emotion_Generic_Video *ev; - - ev = calloc(1, sizeof(*ev)); - EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); - - ev->fd_read = NULL; - ev->fd_write = NULL; - ev->speed = 1.0; - ev->volume = 0.8; - ev->audio_mute = EINA_FALSE; - ev->cmd.type = -1; - - ev->obj = obj; - ev->engine = (Emotion_Engine_Generic *)api; - - if (!_fork_and_exec(ev)) - { - free(ev); - return NULL; - } - - return ev; -} - -static void -em_del(void *data) -{ - Emotion_Generic_Video *ev = data; - - eina_stringshare_del(ev->shmname); - - em_partial_shutdown(ev); -} - -static unsigned char -em_file_open(void *data, const char *file) -{ - Emotion_Generic_Video *ev = data; - INF("file set: %s", file); - if (!ev) return 0; - - eina_stringshare_replace(&ev->filename, file); - - ev->pos = 0; - ev->w = 0; - ev->h = 0; - ev->ratio = 1; - ev->len = 0; - - if (ev->ready && ev->opening) - { - INF("file changed while opening."); - ev->file_changed = EINA_TRUE; - return 1; - } - - ev->opening = EINA_TRUE; - - if (!ev->closing) - _file_open(ev); - - return 1; -} - -static void -em_file_close(void *data) -{ - Emotion_Generic_Video *ev = data; - - if (!ev || !ev->filename) return; - - INF("file close: %s", ev->filename); - - eina_stringshare_replace(&ev->filename, NULL); - eina_stringshare_replace(&ev->subtitle_path, NULL); - - ev->file_ready = EINA_FALSE; - _audio_channels_free(ev); - _video_channels_free(ev); - _spu_channels_free(ev); - _player_meta_info_free(ev); - - if (ev->opening) - return; - - _player_send_cmd(ev, EM_CMD_FILE_CLOSE); - ev->closing = EINA_TRUE; -} - -static Emotion_Format -em_format_get(void *ef EINA_UNUSED) -{ - return EMOTION_FORMAT_BGRA; -} - -static void -em_video_data_size_get(void *data, int *w, int *h) -{ - Emotion_Generic_Video *ev = data; - - if (!ev) return; - if (w) *w = ev->w; - if (h) *h = ev->h; -} - -static void -em_play(void *data, double pos) -{ - Emotion_Generic_Video *ev = data; - - if (!ev) - return; - - ev->play = EINA_TRUE; - INF("play: %0.3f", pos); - - if (ev->initializing || ev->opening) - return; - - if (ev->ready) - { - if (ev->subtitle_path) - { - _player_send_cmd(ev, EM_CMD_SUBTITLE_SET); - _player_send_str(ev, ev->subtitle_path, EINA_TRUE); - } - - _player_send_cmd(ev, EM_CMD_PLAY); - _player_send_float(ev, ev->pos); - - return; - } - - if (!_player_exec(ev)) - ERR("could not start player."); -} - -static void -em_stop(void *data) -{ - Emotion_Generic_Video *ev = data; - - if (!ev) - return; - - ev->play = EINA_FALSE; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_STOP); - _emotion_decode_stop(ev->obj); -} - -static void -em_size_get(void *data, int *w, int *h) -{ - Emotion_Generic_Video *ev = data; - if (w) *w = ev->w; - if (h) *h = ev->h; -} - -static void -em_pos_set(void *data, double pos) -{ - Emotion_Generic_Video *ev = data; - float position = pos; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_POSITION_SET); - _player_send_float(ev, position); - _emotion_seek_done(ev->obj); -} - -static double -em_len_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->len; -} - -static double -em_buffer_size_get(void *data EINA_UNUSED) -{ - return 1.0; -} - -static int -em_fps_num_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return (int)(ev->fps * 1000.0); -} - -static int -em_fps_den_get(void *ef EINA_UNUSED) -{ - return 1000; -} - -static double -em_fps_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->fps; -} - -static double -em_pos_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->pos; -} - -static void -em_vis_set(void *ef EINA_UNUSED, Emotion_Vis vis EINA_UNUSED) -{ -} - -static Emotion_Vis -em_vis_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->vis; -} - -static Eina_Bool -em_vis_supported(void *ef EINA_UNUSED, Emotion_Vis vis EINA_UNUSED) -{ - return EINA_FALSE; -} - -static double -em_ratio_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->ratio; -} - -static int -em_video_handled(void *ef EINA_UNUSED) -{ - DBG("video handled!"); - return 1; -} - -static int -em_audio_handled(void *ef EINA_UNUSED) -{ - DBG("audio handled!"); - return 1; -} - -static int -em_seekable(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->seekable; -} - -static void -em_frame_done(void *ef EINA_UNUSED) -{ -} - -static int -em_yuv_rows_get(void *data EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, unsigned char **yrows EINA_UNUSED, unsigned char **urows EINA_UNUSED, unsigned char **vrows EINA_UNUSED) -{ - return 0; -} - -static int -em_bgra_data_get(void *data, unsigned char **bgra_data) -{ - Emotion_Generic_Video *ev = data; - - if (!ev || !ev->file_ready) - return 0; - - // lock frame here - if (!eina_semaphore_lock(&ev->shared->lock)) - return 0; - - // send current frame to emotion - if (ev->shared->frame.emotion != ev->shared->frame.last) - { - ev->shared->frame.next = ev->shared->frame.emotion; - ev->shared->frame.emotion = ev->shared->frame.last; - } - *bgra_data = ev->frame.frames[ev->shared->frame.emotion]; - - if (ev->shared->frame_drop > 1) - WRN("dropped frames: %d", ev->shared->frame_drop - 1); - ev->shared->frame_drop = 0; - - // unlock frame here - eina_semaphore_release(&ev->shared->lock, 1); - ev->drop = 0; - - return 1; -} - -static void -em_event_feed(void *ef EINA_UNUSED, int event EINA_UNUSED) -{ -} - -static void -em_event_mouse_button_feed(void *ef EINA_UNUSED, int button EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED) -{ -} - -static void -em_event_mouse_move_feed(void *ef EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED) -{ -} - -static int -em_video_channel_count(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->video_channels_count; -} - -static void -em_video_channel_set(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->video_channels_count) - { - WRN("video channel out of range."); - return; - } - - _player_send_cmd(ev, EM_CMD_VIDEO_TRACK_SET); - _player_send_int(ev, ev->video_channels[channel].id); - ev->video_channel_current = channel; -} - -static int -em_video_channel_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->video_channel_current; -} - -static void -em_video_subtitle_file_set(void *data, const char *filepath) -{ - Emotion_Generic_Video *ev = data; - eina_stringshare_replace(&ev->subtitle_path, filepath); -} - -static const char * -em_video_subtitle_file_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->subtitle_path; -} - -static const char * -em_video_channel_name_get(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->video_channels_count) - { - WRN("video channel out of range."); - return NULL; - } - - return ev->video_channels[channel].name; -} - -static void -em_video_channel_mute_set(void *data, int mute) -{ - Emotion_Generic_Video *ev = data; - - ev->video_mute = !!mute; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET); - _player_send_int(ev, mute); -} - -static int -em_video_channel_mute_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->video_mute; -} - -static int -em_audio_channel_count(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->audio_channels_count; -} - -static void -em_audio_channel_set(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->audio_channels_count) - { - WRN("audio channel out of range."); - return; - } - - _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET); - _player_send_int(ev, ev->audio_channels[channel].id); - ev->audio_channel_current = channel; -} - -static int -em_audio_channel_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->audio_channel_current; -} - -static const char * -em_audio_channel_name_get(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->audio_channels_count) - { - WRN("audio channel out of range."); - return NULL; - } - - return ev->audio_channels[channel].name; -} - -static void -em_audio_channel_mute_set(void *data, int mute) -{ - Emotion_Generic_Video *ev = data; - - ev->audio_mute = !!mute; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET); - _player_send_int(ev, mute); -} - -static int -em_audio_channel_mute_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->audio_mute; -} - -static void -em_audio_channel_volume_set(void *data, double vol) -{ - Emotion_Generic_Video *ev = data; - - if (vol > 1.0) vol = 1.0; - if (vol < 0.0) vol = 0.0; - - ev->volume = vol; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_VOLUME_SET); - _player_send_float(ev, ev->volume); -} - -static double -em_audio_channel_volume_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->volume; -} - -static int -em_spu_channel_count(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->spu_channels_count; -} - -static void -em_spu_channel_set(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->spu_channels_count) - { - WRN("spu channel out of range."); - return; - } - - _player_send_cmd(ev, EM_CMD_SPU_TRACK_SET); - _player_send_int(ev, ev->spu_channels[channel].id); - ev->spu_channel_current = channel; -} - -static int -em_spu_channel_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->spu_channel_current; -} - -static const char * -em_spu_channel_name_get(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->spu_channels_count) - { - WRN("spu channel out of range."); - return NULL; - } - - return ev->spu_channels[channel].name; -} - -static void -em_spu_channel_mute_set(void *data, int mute) -{ - Emotion_Generic_Video *ev = data; - - ev->spu_mute = !!mute; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET); - _player_send_int(ev, mute); -} - -static int -em_spu_channel_mute_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->spu_mute; -} - -static int -em_chapter_count(void *ef EINA_UNUSED) -{ - int num = 0; - return num; -} - -static void -em_chapter_set(void *ef EINA_UNUSED, int chapter EINA_UNUSED) -{ -} - -static int -em_chapter_get(void *ef EINA_UNUSED) -{ - int num = 0; - return num; -} - -static const char * -em_chapter_name_get(void *ef EINA_UNUSED, int chapter EINA_UNUSED) -{ - return NULL; -} - -static void -em_speed_set(void *data, double speed) -{ - Emotion_Generic_Video *ev = data; - float rate = speed; - ev->speed = rate; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_SPEED_SET); - _player_send_float(ev, rate); -} - -static double -em_speed_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return (double)ev->speed; -} - -static int -em_eject(void *ef EINA_UNUSED) -{ - return 1; -} - -static const char * -em_meta_get(void *data, int meta) -{ - Emotion_Generic_Video *ev = data; - - switch (meta) - { - case EMOTION_META_INFO_TRACK_TITLE: - return ev->meta.title; - case EMOTION_META_INFO_TRACK_ARTIST: - return ev->meta.artist; - case EMOTION_META_INFO_TRACK_ALBUM: - return ev->meta.album; - case EMOTION_META_INFO_TRACK_YEAR: - return ev->meta.year; - case EMOTION_META_INFO_TRACK_GENRE: - return ev->meta.genre; - case EMOTION_META_INFO_TRACK_COMMENT: - return ev->meta.comment; - case EMOTION_META_INFO_TRACK_DISC_ID: - return ev->meta.disc_id; - case EMOTION_META_INFO_TRACK_COUNT: - return ev->meta.count; - } - - return NULL; -} - - -/* Players/modules */ -static const Emotion_Engine em_template_engine = -{ - EMOTION_ENGINE_API_VERSION, - EMOTION_ENGINE_PRIORITY_DEFAULT, - "generic", - em_add, /* add */ - em_del, /* del */ - em_file_open, /* file_open */ - em_file_close, /* file_close */ - em_play, /* play */ - em_stop, /* stop */ - em_size_get, /* size_get */ - em_pos_set, /* pos_set */ - em_len_get, /* len_get */ - em_buffer_size_get, /* buffer_size_get */ - em_fps_num_get, /* fps_num_get */ - em_fps_den_get, /* fps_den_get */ - em_fps_get, /* fps_get */ - em_pos_get, /* pos_get */ - em_vis_set, /* vis_set */ - em_vis_get, /* vis_get */ - em_vis_supported, /* vis_supported */ - em_ratio_get, /* ratio_get */ - em_video_handled, /* video_handled */ - em_audio_handled, /* audio_handled */ - em_seekable, /* seekable */ - em_frame_done, /* frame_done */ - em_format_get, /* format_get */ - em_video_data_size_get, /* video_data_size_get */ - em_yuv_rows_get, /* yuv_rows_get */ - em_bgra_data_get, /* bgra_data_get */ - em_event_feed, /* event_feed */ - em_event_mouse_button_feed, /* event_mouse_button_feed */ - em_event_mouse_move_feed, /* event_mouse_move_feed */ - em_video_channel_count, /* video_channel_count */ - em_video_channel_set, /* video_channel_set */ - em_video_channel_get, /* video_channel_get */ - em_video_subtitle_file_set, /* video_subtitle_file_set */ - em_video_subtitle_file_get, /* video_subtitle_file_get */ - em_video_channel_name_get, /* video_channel_name_get */ - em_video_channel_mute_set, /* video_channel_mute_set */ - em_video_channel_mute_get, /* video_channel_mute_get */ - em_audio_channel_count, /* audio_channel_count */ - em_audio_channel_set, /* audio_channel_set */ - em_audio_channel_get, /* audio_channel_get */ - em_audio_channel_name_get, /* audio_channel_name_get */ - em_audio_channel_mute_set, /* audio_channel_mute_set */ - em_audio_channel_mute_get, /* audio_channel_mute_get */ - em_audio_channel_volume_set, /* audio_channel_volume_set */ - em_audio_channel_volume_get, /* audio_channel_volume_get */ - em_spu_channel_count, /* spu_channel_count */ - em_spu_channel_set, /* spu_channel_set */ - em_spu_channel_get, /* spu_channel_get */ - em_spu_channel_name_get, /* spu_channel_name_get */ - em_spu_channel_mute_set, /* spu_channel_mute_set */ - em_spu_channel_mute_get, /* spu_channel_mute_get */ - em_chapter_count, /* chapter_count */ - em_chapter_set, /* chapter_set */ - em_chapter_get, /* chapter_get */ - em_chapter_name_get, /* chapter_name_get */ - em_speed_set, /* speed_set */ - em_speed_get, /* speed_get */ - em_eject, /* eject */ - em_meta_get, /* meta_get */ - NULL, /* priority_set */ - NULL, /* priority_get */ - NULL /* em_meta_artwork_get */ -}; - -static void -_player_entry_add(const Eina_File_Direct_Info *info) -{ - Emotion_Engine_Generic *eg; - const char *name; - char *endptr; - int priority; - - name = info->path + info->name_start; - - priority = strtol(name, &endptr, 10); - if (endptr == name) - priority = EMOTION_ENGINE_PRIORITY_DEFAULT; - else - { - if ((*endptr == '-') || (*endptr == '_')) - endptr++; - name = endptr; - } - - if (*name == '\0') - { - ERR("Invalid generic player: %s", info->path); - return; - } - - eg = malloc(sizeof(Emotion_Engine_Generic)); - EINA_SAFETY_ON_NULL_RETURN(eg); - - /* inherit template */ - memcpy(&(eg->engine), &em_template_engine, sizeof(em_template_engine)); - - eg->path = strdup(info->path); - EINA_SAFETY_ON_NULL_GOTO(eg->path, error_path); - - eg->engine.name = strdup(name); - EINA_SAFETY_ON_NULL_GOTO(eg->engine.name, error_name); - - eg->engine.priority = priority; - - DBG("Add player name=%s, priority=%d, path=%s", - eg->engine.name, eg->engine.priority, eg->path); - _generic_players = eina_list_append(_generic_players, eg); - - return; - - error_name: - free(eg->path); - error_path: - free(eg); -} - -static void -_player_entry_free(Emotion_Engine_Generic *eg) -{ - free(eg->path); - free((void *)eg->engine.name); - free(eg); -} - -static void -_players_all_from(const char *path) -{ - const Eina_File_Direct_Info *info; - int count = 0; - Eina_Iterator *itr = eina_file_direct_ls(path); - if (!itr) goto end; - EINA_ITERATOR_FOREACH(itr, info) - { - if (access(info->path, R_OK | X_OK) == 0) - { - _player_entry_add(info); - count++; - } - } - eina_iterator_free(itr); - - end: - if (count == 0) - DBG("No generic players at %s", path); -} - -static void -_players_load(void) -{ - char buf[PATH_MAX]; - - eina_str_join(buf, sizeof(buf), '/', - eina_prefix_lib_get(pfx), - "emotion/generic_players/" MODULE_ARCH); - _players_all_from(buf); - - if (!_generic_players) - { - WRN("no generic players available"); - } - else - { - const Eina_List *n; - const Emotion_Engine_Generic *eg; - INF("Found %d generic players", eina_list_count(_generic_players)); - EINA_LIST_FOREACH(_generic_players, n, eg) - _emotion_module_register(&(eg->engine)); - } -} - -Eina_Bool -generic_module_init(void) -{ - if (_emotion_init_count > 0) - { - _emotion_init_count++; - return EINA_TRUE; - } - - _emotion_generic_log_domain = eina_log_domain_register("emotion_generic", - EINA_COLOR_LIGHTCYAN); - if (_emotion_generic_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion_generic'"); - return EINA_FALSE; - } - - pfx = eina_prefix_new(NULL, emotion_init, - "EMOTION", "emotion", "checkme", - PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, - PACKAGE_DATA_DIR, PACKAGE_DATA_DIR); - if (!pfx) - { - CRI("Could not get prefix for emotion"); - eina_log_domain_unregister(_emotion_generic_log_domain); - _emotion_generic_log_domain = -1; - return EINA_FALSE; - } - - _players_load(); - - _emotion_init_count = 1; - return EINA_TRUE; -} - -void -generic_module_shutdown(void) -{ - Emotion_Engine_Generic *eg; - - if (_emotion_init_count > 1) - { - _emotion_init_count--; - return; - } - else if (_emotion_init_count == 0) - { - EINA_LOG_ERR("too many generic_module_shutdown()"); - return; - } - _emotion_init_count = 0; - - EINA_LIST_FREE(_generic_players, eg) - { - _emotion_module_unregister(&(eg->engine)); - _player_entry_free(eg); - } - - eina_log_domain_unregister(_emotion_generic_log_domain); - _emotion_generic_log_domain = -1; - - eina_prefix_free(pfx); - pfx = NULL; -} - -#ifndef EMOTION_STATIC_BUILD_GENERIC - -EINA_MODULE_INIT(generic_module_init); -EINA_MODULE_SHUTDOWN(generic_module_shutdown); - -#endif diff --git a/src/modules/emotion/generic/emotion_generic.h b/src/modules/emotion/generic/emotion_generic.h deleted file mode 100644 index 2830d33d4a..0000000000 --- a/src/modules/emotion/generic/emotion_generic.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef EMOTION_GENERIC_H -#define EMOTION_GENERIC_H - -#include - -#include "Emotion_Generic_Plugin.h" - -/* default values */ - -typedef struct _Emotion_Generic_Video Emotion_Generic_Video; -typedef struct _Emotion_Generic_Player Emotion_Generic_Player; -typedef struct _Emotion_Generic_Cmd_Buffer Emotion_Generic_Cmd_Buffer; -typedef struct _Emotion_Generic_Channel Emotion_Generic_Channel; -typedef struct _Emotion_Generic_Meta Emotion_Generic_Meta; - -struct _Emotion_Generic_Player -{ - Ecore_Exe *exe; -}; - -struct _Emotion_Generic_Channel -{ - int id; - const char *name; -}; - -struct _Emotion_Generic_Meta -{ - const char *title; - const char *artist; - const char *album; - const char *year; - const char *genre; - const char *comment; - const char *disc_id; - const char *count; -}; - -struct _Emotion_Generic_Cmd_Buffer -{ - char *tmp; - int type; - ssize_t i, total; - int s_len; - int num_params, cur_param; - int padding; - union { - struct { - int width; - int height; - } size; - int i_num; - float f_num; - struct { - int total; - int current; - Emotion_Generic_Channel *channels; - } track; - Emotion_Generic_Meta meta; - } param; -}; - -typedef struct _Emotion_Engine_Generic -{ - Emotion_Engine engine; - char *path; -} Emotion_Engine_Generic; - -/* emotion/generic main structure */ -struct _Emotion_Generic_Video -{ - const Emotion_Engine_Generic *engine; - const char *shmname; - - Emotion_Generic_Player player; - Emotion_Generic_Cmd_Buffer cmd; - Ecore_Event_Handler *player_add, *player_del, *player_data; - int drop; - Ecore_Pipe *fd_read; - Ecore_Pipe *fd_write; - const unsigned char *buffer; - ssize_t length; - ssize_t offset; - - const char *filename; - volatile double len; - volatile double pos; - double fps; - double ratio; - int w, h; - Evas_Object *obj; - Emotion_Generic_Video_Shared *shared; - Emotion_Generic_Video_Frame frame; - volatile int fq; - float volume; - float speed; - Emotion_Vis vis; - Eina_Bool initializing : 1; - Eina_Bool ready : 1; - Eina_Bool play : 1; - Eina_Bool video_mute : 1; - Eina_Bool audio_mute : 1; - Eina_Bool spu_mute : 1; - Eina_Bool seekable : 1; - volatile Eina_Bool opening : 1; - volatile Eina_Bool closing : 1; - Eina_Bool file_changed : 1; - Eina_Bool file_ready : 1; - int audio_channels_count; - int audio_channel_current; - Emotion_Generic_Channel *audio_channels; - int video_channels_count; - int video_channel_current; - Emotion_Generic_Channel *video_channels; - int spu_channels_count; - int spu_channel_current; - Emotion_Generic_Channel *spu_channels; - Emotion_Generic_Meta meta; - const char *subtitle_path; -}; - -#endif - diff --git a/src/modules/emotion/generic/meson.build b/src/modules/emotion/generic/meson.build deleted file mode 100644 index 4f62c7a43e..0000000000 --- a/src/modules/emotion/generic/meson.build +++ /dev/null @@ -1,24 +0,0 @@ -generic_src = files([ - 'emotion_generic.c', - 'emotion_generic.h', -]) - -emotion_generic = declare_dependency( - include_directories: include_directories('.'), - dependencies: emotion, -) - -if sys_windows == false - shared_module(emotion_loader, - generic_src, - include_directories : config_dir, - dependencies: [eina, evas, emotion, generic_deps, rt], - install: true, - install_dir : mod_install_dir, - c_args : package_c_args, - ) - - install_headers('Emotion_Generic_Plugin.h', - install_dir : dir_package_include, - ) -endif diff --git a/src/modules/emotion/libvlc/emotion_libvlc.c b/src/modules/emotion/libvlc/emotion_libvlc.c deleted file mode 100644 index 1e8f9d69b4..0000000000 --- a/src/modules/emotion/libvlc/emotion_libvlc.c +++ /dev/null @@ -1,1555 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include -#include -#include - -#include -#include -#include - -#include "emotion_modules.h" - -#ifdef DBG -#undef DBG -#endif -#define DBG(...) EINA_LOG_DOM_DBG(_emotion_libvlc_log_domain, __VA_ARGS__) - -#ifdef INF -#undef INF -#endif -#define INF(...) EINA_LOG_DOM_INFO(_emotion_libvlc_log_domain, __VA_ARGS__) - -#ifdef WRN -#undef WRN -#endif -#define WRN(...) EINA_LOG_DOM_WARN(_emotion_libvlc_log_domain, __VA_ARGS__) - -#ifdef ERR -#undef ERR -#endif -#define ERR(...) EINA_LOG_DOM_ERR(_emotion_libvlc_log_domain, __VA_ARGS__) - -#ifdef CRI -#undef CRI -#endif -#define CRI(...) EINA_LOG_DOM_CRIT(_emotion_libvlc_log_domain, __VA_ARGS__) - -static int _emotion_libvlc_log_domain = -1; -static Eina_Bool debug_fps = EINA_FALSE; -static libvlc_instance_t *libvlc = NULL; - -typedef struct _Emotion_LibVLC Emotion_LibVLC; - -static void em_file_close(void *); - -struct _Emotion_LibVLC -{ - /* Evas object */ - Evas_Object *obj; - Evas_Object *evas_obj; - Emotion_Module_Options opt; - - /* libvlc */ - libvlc_media_t *m; - libvlc_media_player_t *mp; - unsigned int nb_tracks; - libvlc_media_track_t **tracks; - int nb_chapters; - libvlc_chapter_description_t **chapters; - char *subtitle_file; - char *metas[META_TRACK_COUNT]; - - /* options */ - int video_mute; - int video_mute_force; - int audio_mute; - int spu_mute; - int audio_vol; - Emotion_Vis vis; - - /* There can be remaining mainloop callbacks that owns the Emotion_LibVLC - * object when em_del is called. Use a ref_count to delete the ev object - * when em_del is called and when all callbacks are processed. */ - unsigned int ref_count; - - /* locks */ - Eina_Lock lock; - Eina_Condition wait; - Eina_List *event_list; - - /* stats */ - double pos; - double len; - double buffer_cache; - Eina_Bool seeking; - Eina_Bool started; - Eina_Bool invalidate_tracks; -}; - -struct close_data -{ - libvlc_media_player_t *mp; - Evas_Object *evas_obj; -}; - -static const libvlc_event_type_t mp_events[] = { - //libvlc_MediaPlayerMediaChanged, - //libvlc_MediaPlayerNothingSpecial, - //libvlc_MediaPlayerOpening, - libvlc_MediaPlayerBuffering, - libvlc_MediaPlayerPlaying, - //libvlc_MediaPlayerPaused, - libvlc_MediaPlayerStopped, - libvlc_MediaPlayerForward, - //libvlc_MediaPlayerBackward, - libvlc_MediaPlayerEndReached, - libvlc_MediaPlayerEncounteredError, - libvlc_MediaPlayerTimeChanged, - //libvlc_MediaPlayerPositionChanged, - //libvlc_MediaPlayerSeekableChanged, - //libvlc_MediaPlayerPausableChanged, - //libvlc_MediaPlayerTitleChanged, - //libvlc_MediaPlayerSnapshotTaken, - libvlc_MediaPlayerLengthChanged, - //libvlc_MediaPlayerVout, - //libvlc_MediaPlayerScrambledChanged, - libvlc_MediaPlayerESAdded, - libvlc_MediaPlayerESDeleted, - //libvlc_MediaPlayerESSelected, - //libvlc_MediaPlayerCorked, - //libvlc_MediaPlayerUncorked, - //libvlc_MediaPlayerMuted, - //libvlc_MediaPlayerUnmuted, - //libvlc_MediaPlayerAudioVolume, - //libvlc_MediaPlayerAudioDevice, - -1, -}; - -static void -em_del_safe(Emotion_LibVLC *ev) -{ - eina_lock_free(&ev->lock); - eina_condition_free(&ev->wait); - free(ev->subtitle_file); - free(ev); -} - -/* Take the ev->lock from a mainloop callback. - * Returns false if the ev object is destroyed. */ -static Eina_Bool -emotion_mainloop_lock(Emotion_LibVLC *ev) -{ - eina_lock_take(&ev->lock); - _emotion_pending_ecore_end(); - if (--ev->ref_count == 0) - { - eina_lock_release(&ev->lock); - WRN("callbacks ended, deleting Emotion_LibVLC"); - em_del_safe(ev); - return EINA_FALSE; - } - return EINA_TRUE; -} - -/* Send a callback to the mainloop */ -static void -emotion_mainloop_call_locked(Emotion_LibVLC *ev, Ecore_Cb callback) -{ - ++ev->ref_count; - _emotion_pending_ecore_begin(); - ecore_main_loop_thread_safe_call_async(callback, ev); -} - -/* Process one libvlc event from the mainloop. */ -static void -emotion_mainloop_event(Emotion_LibVLC *ev, const libvlc_event_t *event) -{ - switch (event->type) - { - case libvlc_MediaPlayerBuffering: - ev->buffer_cache = event->u.media_player_buffering.new_cache / 100.0; - break; - - case libvlc_MediaPlayerPlaying: - if (!ev->started) - { - _emotion_open_done(ev->obj); - _emotion_playback_started(ev->obj); - ev->started = EINA_TRUE; - } - break; - - case libvlc_MediaPlayerStopped: - case libvlc_MediaPlayerEndReached: - case libvlc_MediaPlayerEncounteredError: - _emotion_decode_stop(ev->obj); - _emotion_playback_finished(ev->obj); - break; - - case libvlc_MediaPlayerTimeChanged: - { - if (ev->seeking) - { - _emotion_seek_done(ev->obj); - ev->seeking = EINA_FALSE; - } - - ev->pos = event->u.media_player_time_changed.new_time / 1000.0; - if (ev->pos > 0 && ev->len > 0) - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); - break; - } - - case libvlc_MediaPlayerLengthChanged: - ev->len = event->u.media_player_length_changed.new_length / 1000.0; - if (ev->pos > 0 && ev->len > 0) - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); - break; - - case libvlc_MediaPlayerESAdded: - case libvlc_MediaPlayerESDeleted: - ev->invalidate_tracks = EINA_TRUE; - _emotion_channels_change(ev->obj); - break; - } -} - -/* Mainloop callback, sent by libvlc_on_mp_event. It processes a list of libvlc - * event. */ -static void -emotion_mainloop_event_list(void *data) -{ - Emotion_LibVLC *ev = data; - Eina_List *event_list; - libvlc_event_t *event; - - if (!emotion_mainloop_lock(ev)) return; - event_list = ev->event_list; - ev->event_list = NULL; - eina_lock_release(&ev->lock); - - if (!event_list) return; - - EINA_LIST_FREE(event_list, event) - { - if (ev->mp) - emotion_mainloop_event(ev, event); - free(event); - } -} - -/* Libvlc callback, see libvlc_event_manager_t. */ -static void -libvlc_on_mp_event(const libvlc_event_t *event, void *opaque) -{ - Emotion_LibVLC *ev = opaque; - - if (eina_main_loop_is()) - { - /* Process the event directly */ - emotion_mainloop_event(ev, event); - } - else - { - /* Add the event to a list of events that will be processed by the - * mainloop */ - - void *data = malloc(sizeof(libvlc_event_t)); - if (!data) return; - memcpy(data, event, sizeof(libvlc_event_t)); - - eina_lock_take(&ev->lock); - if (!ev->event_list) - emotion_mainloop_call_locked(ev, emotion_mainloop_event_list); - ev->event_list = eina_list_append(ev->event_list, data); - eina_lock_release(&ev->lock); - } -} - -static void -evas_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, - void *event EINA_UNUSED) -{ - Emotion_LibVLC *ev = data; - int w, h; - - evas_object_image_size_get(ev->evas_obj, &w, &h); - _emotion_frame_resize(ev->obj, w, h, w / (double) h); - efl_event_callback_call(ev->obj, EFL_CANVAS_VIDEO_EVENT_FRAME_DECODE, NULL); -} - -/* Fetch all libvlc tracks. */ -static int -libvlc_fetch_tracks(Emotion_LibVLC *ev) -{ - if (ev->invalidate_tracks) - { - if (ev->nb_tracks) - libvlc_media_tracks_release(ev->tracks, ev->nb_tracks); - ev->nb_tracks = libvlc_media_tracks_get(ev->m, &ev->tracks); - ev->invalidate_tracks = EINA_FALSE; - } - return ev->nb_tracks; -} - -/* Get a libvlc tracks from a track_id. */ -static libvlc_media_track_t * -libvlc_get_track(Emotion_LibVLC *ev, libvlc_track_type_t type, int id) -{ - unsigned int i; - - if (!ev->m || id < 0 || type == libvlc_track_unknown) return NULL; - - if (!libvlc_fetch_tracks(ev)) return NULL; - - for (i = 0; i < ev->nb_tracks; ++i) - { - libvlc_media_track_t *track = ev->tracks[i]; - - if (track->i_id == id && track->i_type == type) - return track; - } - - return NULL; -} - -/* Get the current libvlc video track. */ -static libvlc_media_track_t * -libvlc_get_current_video_track(Emotion_LibVLC *ev) -{ - int id = libvlc_video_get_track(ev->mp); - return id >= 0 ? libvlc_get_track(ev, libvlc_track_video, id) : NULL; -} - -/* Get a libvlc video track at a pos. - * XXX: Libvlc use a track_id to get and select a track. The first track_id doesn't - * necessarily starts with 0. Emotion use a position (that starts with 0) to - * get and select a track. */ -static libvlc_media_track_t * -libvlc_get_track_at_pos(Emotion_LibVLC *ev, - int pos, libvlc_track_type_t type) -{ - unsigned int i; - - if (!ev->m || pos < 0 || type == libvlc_track_unknown) return NULL; - - if (!libvlc_fetch_tracks(ev)) return NULL; - - for (i = 0; i < ev->nb_tracks; ++i) - { - libvlc_media_track_t *track = ev->tracks[i]; - - if (type == track->i_type && pos-- == 0) - return track; - } - - return NULL; -} - -/* Get the position of the libvlc track. - * See libvlc_get_track_at_pos. */ -static int -libvlc_get_track_pos(Emotion_LibVLC *ev, int id, libvlc_track_type_t type) -{ - unsigned int i; - int pos = 0; - - if (!ev->m || id < 0 || type == libvlc_track_unknown) return -1; - - if (!libvlc_fetch_tracks(ev)) return -1; - - for (i = 0; i < ev->nb_tracks; ++i) - { - libvlc_media_track_t *track = ev->tracks[i]; - - if (type == track->i_type) - { - if (id == track->i_id) - return pos; - else - pos++; - } - } - - return -1; -} - -static void * -em_add(const Emotion_Engine *api EINA_UNUSED, - Evas_Object *obj, - const Emotion_Module_Options *opt) -{ - Emotion_LibVLC *ev; - ev = calloc(1, sizeof(Emotion_LibVLC)); - EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); - - ev->obj = obj; - ev->opt = *opt; - eina_lock_new(&ev->lock); - eina_condition_new(&ev->wait, &ev->lock); - ev->ref_count = 1; - ev->audio_vol = -1; - - return ev; -} - -static void -em_del(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev) return; - - em_file_close(video); - - eina_lock_take(&ev->lock); - if (--ev->ref_count > 0) - { - eina_lock_release(&ev->lock); - WRN("em_del delayed, some callbacks are still running"); - } - else - { - eina_lock_release(&ev->lock); - em_del_safe(ev); - } -} - -static Eina_Bool -em_file_open(void *video, - const char *file) -{ - int ret, i; - Emotion_LibVLC *ev = video; - libvlc_event_manager_t *event_m; - - if (!file) return EINA_FALSE; - - ev->evas_obj = emotion_object_image_get(ev->obj); - if (!ev->evas_obj) - { - WRN("emotion_object_image_get failed: no video"); - ev->opt.no_video = EINA_TRUE; - } - - evas_object_image_pixels_get_callback_set(ev->evas_obj, NULL, NULL); - - ev->invalidate_tracks = true; - - /* Create libvlc_media */ - ev->m = libvlc_media_new_path(libvlc, file); - if (strstr(file, "://") == NULL) - ev->m = libvlc_media_new_path(libvlc, file); - else - ev->m = libvlc_media_new_location(libvlc, file); - - EINA_SAFETY_ON_NULL_GOTO(ev->m, error); - - if (ev->opt.no_audio || ev->audio_mute) - libvlc_media_add_option(ev->m, ":no-audio"); - - if (ev->opt.no_video || ev->video_mute) - libvlc_media_add_option(ev->m, ":no-video"); - - if (ev->spu_mute) - libvlc_media_add_option(ev->m, ":no-spu"); - - /* Create libvlc_media_player */ - ev->mp = libvlc_media_player_new_from_media(ev->m); - EINA_SAFETY_ON_NULL_GOTO(ev->mp, error); - - event_m = libvlc_media_player_event_manager(ev->mp); - for (i = 0; mp_events[i] != -1; ++i) - libvlc_event_attach(event_m, mp_events[i], libvlc_on_mp_event, ev); - - libvlc_media_player_set_video_title_display(ev->mp, - libvlc_position_disable, 0); - - evas_object_ref(ev->evas_obj); - if (libvlc_media_player_set_evas_object(ev->mp, ev->evas_obj) == -1) - { - CRI("libvlc_media_player_set_evas_object failed"); - libvlc_media_add_option(ev->m, ":no-video"); - ev->video_mute = ev->video_mute_force = 1; - } - - evas_object_event_callback_add(ev->evas_obj, EVAS_CALLBACK_IMAGE_RESIZE, - evas_resize_cb, ev); - - if (ev->audio_vol != -1) - libvlc_audio_set_volume(ev->mp, ev->audio_vol); - - ret = libvlc_media_player_play(ev->mp); - EINA_SAFETY_ON_FALSE_GOTO(ret == 0, error); - - return EINA_TRUE; -error: - em_file_close(video); - return EINA_FALSE; -} - -static void -emotion_close_cb(void *data, Ecore_Thread *thread EINA_UNUSED) -{ - struct close_data *close_data = data; - - libvlc_media_player_release(close_data->mp); -} - -static void -emotion_close_mainloop_cb(void *data, - Ecore_Thread *thread EINA_UNUSED) -{ - struct close_data *close_data = data; - - evas_object_unref(close_data->evas_obj); - free(close_data); - _emotion_pending_ecore_end(); -} - -static void -em_file_close(void *video) -{ - Emotion_LibVLC *ev = video; - unsigned int i; - - if (ev->mp) - { - struct close_data *close_data; - libvlc_event_manager_t *event_m; - - evas_object_event_callback_del(ev->evas_obj, EVAS_CALLBACK_IMAGE_RESIZE, - evas_resize_cb); - - event_m = libvlc_media_player_event_manager(ev->mp); - for (i = 0; mp_events[i] != -1; ++i) - libvlc_event_detach(event_m, mp_events[i], libvlc_on_mp_event, ev); - - libvlc_media_player_set_evas_object(ev->mp, NULL); - - close_data = malloc(sizeof(struct close_data)); - if (close_data) - { - close_data->evas_obj = ev->evas_obj; - close_data->mp = ev->mp; - _emotion_pending_ecore_begin(); - ecore_thread_run(emotion_close_cb, - emotion_close_mainloop_cb, - NULL, close_data); - } - - ev->evas_obj = NULL; - ev->mp = NULL; - - if (ev->seeking) - { - ev->seeking = EINA_FALSE; - _emotion_seek_done(ev->obj); - } - } - if (ev->m) - { - libvlc_media_release(ev->m); - ev->m = NULL; - } - if (ev->nb_tracks > 0) - { - libvlc_media_tracks_release(ev->tracks, ev->nb_tracks); - ev->nb_tracks = 0; - ev->tracks = NULL; - } - if (ev->nb_chapters > 0) - { - libvlc_chapter_descriptions_release(ev->chapters, ev->nb_chapters); - ev->nb_chapters = 0; - ev->chapters = NULL; - } - for (i = 0; i < META_TRACK_COUNT; ++i) - { - free(ev->metas[i]); - ev->metas[i] = NULL; - } - if (ev->subtitle_file) - { - free(ev->subtitle_file); - ev->subtitle_file = NULL; - } - ev->vis = EMOTION_VIS_NONE; - ev->started = ev->seeking = ev->invalidate_tracks = EINA_FALSE; - ev->pos = ev->len = ev->buffer_cache = 0.0; -} - -static void -em_play(void *video, - double pos EINA_UNUSED) -{ - Emotion_LibVLC *ev = video; - - libvlc_media_player_set_pause(ev->mp, false); -} - -static void -em_stop(void *video) -{ - Emotion_LibVLC *ev = video; - - libvlc_media_player_set_pause(ev->mp, true); -} - -static void -em_size_get(void *video, - int *width, - int *height) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!width || !height) return; - *width = 0; - *height = 0; - - if (!ev->started) return; - - track = libvlc_get_current_video_track(ev); - if (track) - { - *width = track->video->i_width; - *height = track->video->i_height; - } -} - -static double -em_pos_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return ev->pos; -} - -static void -em_pos_set(void *video, - double pos) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) - { - _emotion_seek_done(ev->obj); - return; - } - - libvlc_media_player_set_time(ev->mp, pos * 1000); - - ev->seeking = EINA_TRUE; -} - -static double -em_len_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return ev->len; -} - -static double -em_buffer_size_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return ev->buffer_cache; -} - -static void -em_fps_num_den_get(Emotion_LibVLC *ev, int *num, int *den) -{ - libvlc_media_track_t *track; - - if (!ev->started) return; - - track = libvlc_get_current_video_track(ev); - if (track) - { - if (num) - *num = track->video->i_frame_rate_num; - if (den) - *den = track->video->i_frame_rate_den; - } -} - -static int -em_fps_num_get(void *video) -{ - int num = 0; - - em_fps_num_den_get(video, &num, NULL); - return num; -} - -static int -em_fps_den_get(void *video) -{ - int den = 0; - - em_fps_num_den_get(video, NULL, &den); - return den; -} - -static double -em_fps_get(void *video) -{ - int num = 0, den = 0; - - em_fps_num_den_get(video, &num, &den); - if (den > 0) return num / (double)den; - return 0.0; -} - -static void -em_vis_set(void *video, - Emotion_Vis vis) -{ - Emotion_LibVLC *ev = video; - - ev->vis = vis; -} - -static Emotion_Vis -em_vis_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->vis; -} - -static Eina_Bool -em_vis_supported(void *ev EINA_UNUSED, Emotion_Vis vis) -{ - /* FIXME */ - if (vis == EMOTION_VIS_NONE) - return EINA_TRUE; - else - return EINA_FALSE; -} - -static double -em_ratio_get(void *video) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!ev->started) return 0.0; - - track = libvlc_get_current_video_track(ev); - if (track) - { - double ratio = track->video->i_sar_num - / (double)track->video->i_sar_den; - return ratio; - } - else - return 0.0; -} - -static int -em_video_handled(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return libvlc_video_get_track_count(ev->mp) > 0; -} - -static int -em_audio_handled(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return libvlc_audio_get_track_count(ev->mp) > 0; -} - -static int -em_seekable(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0; - - return libvlc_media_player_is_seekable(ev->mp); -} - -static void -em_frame_done(void *video EINA_UNUSED) -{ -} - -static Emotion_Format -em_format_get(void *video EINA_UNUSED) -{ - return EMOTION_FORMAT_NONE; -} - -static void -em_video_data_size_get(void *video EINA_UNUSED, int *w EINA_UNUSED, int *h EINA_UNUSED) -{ -} - -static int -em_yuv_rows_get(void *video EINA_UNUSED, - int w EINA_UNUSED, - int h EINA_UNUSED, - unsigned char **yrows EINA_UNUSED, - unsigned char **urows EINA_UNUSED, - unsigned char **vrows EINA_UNUSED) -{ - return 0; -} - -static int -em_bgra_data_get(void *video EINA_UNUSED, unsigned char **bgra_data EINA_UNUSED) -{ - return 0; -} - -static void -em_event_feed(void *video, int event) -{ - Emotion_LibVLC *ev = video; - unsigned int navigate; - - if (!ev->started) return; - - switch (event) - { - case EMOTION_EVENT_UP: - navigate = libvlc_navigate_up; - break; - - case EMOTION_EVENT_DOWN: - navigate = libvlc_navigate_down; - break; - - case EMOTION_EVENT_LEFT: - navigate = libvlc_navigate_left; - break; - - case EMOTION_EVENT_RIGHT: - navigate = libvlc_navigate_right; - break; - - case EMOTION_EVENT_SELECT: - navigate = libvlc_navigate_activate; - break; - - /* FIXME */ - default: - case EMOTION_EVENT_MENU1: - case EMOTION_EVENT_MENU2: - case EMOTION_EVENT_MENU3: - case EMOTION_EVENT_MENU4: - case EMOTION_EVENT_MENU5: - case EMOTION_EVENT_MENU6: - case EMOTION_EVENT_MENU7: - case EMOTION_EVENT_NEXT: - case EMOTION_EVENT_PREV: - case EMOTION_EVENT_ANGLE_NEXT: - case EMOTION_EVENT_ANGLE_PREV: - case EMOTION_EVENT_FORCE: - case EMOTION_EVENT_0: - case EMOTION_EVENT_1: - case EMOTION_EVENT_2: - case EMOTION_EVENT_3: - case EMOTION_EVENT_4: - case EMOTION_EVENT_5: - case EMOTION_EVENT_6: - case EMOTION_EVENT_7: - case EMOTION_EVENT_8: - case EMOTION_EVENT_9: - case EMOTION_EVENT_10: - return; - } - libvlc_media_player_navigate(ev->mp, navigate); -} - -static void -em_event_mouse_button_feed(void *video EINA_UNUSED, int button EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED) -{ - /* Handled directly by VLC evas vout module */ -} - -static void -em_event_mouse_move_feed(void *video EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED) -{ - /* Handled directly by VLC evas vout module */ -} - -static int -em_video_channel_count(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return -1; - - return libvlc_video_get_track_count(ev->mp); -} - -static void -em_video_channel_set(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - if (channel < 0) - libvlc_video_set_track(ev->mp, -1); - else - { - libvlc_media_track_t *track; - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_video); - if (track) - libvlc_video_set_track(ev->mp, track->i_id); - } -} - -static int -em_video_channel_get(void *video) -{ - Emotion_LibVLC *ev = video; - int id; - - if (!ev->started) return -1; - - id = libvlc_video_get_track(ev->mp); - - return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_video) : -1; -} - -static void -em_video_subtitle_file_set(void *video, - const char *filepath) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - free(ev->subtitle_file); - ev->subtitle_file = filepath ? strdup(filepath) : NULL; - libvlc_video_set_subtitle_file(ev->mp, ev->subtitle_file); -} - -static const char * -em_video_subtitle_file_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->subtitle_file; -} - -static const char * -em_video_channel_name_get(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!ev->started) return NULL; - - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_video); - if (track) - return track->psz_description; - else - return NULL; -} - -static void -em_video_channel_mute_set(void *video, - int mute) -{ - Emotion_LibVLC *ev = video; - - if (ev->video_mute_force) - return; - ev->video_mute = mute; - - if (ev->started) - em_video_channel_set(video, mute ? -1 : 0); -} - -static int -em_video_channel_mute_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->video_mute; -} - -static int -em_channel_count(int vlc_count) -{ - /* vlc count the -1 track that deactivate the channel for audio and spu */ - return vlc_count > 0 ? vlc_count - 1 : vlc_count; -} - -static int -em_audio_channel_count(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return -1; - - return em_channel_count(libvlc_audio_get_track_count(ev->mp)); -} - -static void -em_audio_channel_set(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - if (channel < 0) - libvlc_audio_set_track(ev->mp, -1); - else - { - libvlc_media_track_t *track; - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_audio); - if (track) - libvlc_audio_set_track(ev->mp, track->i_id); - } -} - -static int -em_audio_channel_get(void *video) -{ - Emotion_LibVLC *ev = video; - int id; - - if (!ev->started) return -1; - - id = libvlc_audio_get_track(ev->mp); - - return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_audio) : -1; -} - -static const char * -em_audio_channel_name_get(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!ev->started) return NULL; - - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_audio); - if (track) - return track->psz_description; - else - return NULL; -} - -static void -em_audio_channel_mute_set(void *video, - int mute) -{ - Emotion_LibVLC *ev = video; - - ev->audio_mute = mute; - - if (ev->started) - em_audio_channel_set(video, mute ? -1 : 0); -} - -static int -em_audio_channel_mute_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->audio_mute; -} - -static void -em_audio_channel_volume_set(void *video, - double vol) -{ - Emotion_LibVLC *ev = video; - - if (vol < 0.0) - vol = 0.0; - else if (vol > 1.0) - vol = 1.0; - ev->audio_vol = vol * 100; - - if (!ev->started) return; - - libvlc_audio_set_volume(ev->mp, ev->audio_vol); -} - -static double -em_audio_channel_volume_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) - return ev->audio_vol / 100.0; - - return libvlc_audio_get_volume(ev->mp) / 100.0; -} - -static int -em_spu_channel_count(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return -1; - - return em_channel_count(libvlc_video_get_spu_count(ev->mp)); -} - -static void -em_spu_channel_set(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - if (channel < 0) - libvlc_video_set_spu(ev->mp, -1); - else - { - libvlc_media_track_t *track; - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_text); - if (track) - libvlc_video_set_spu(ev->mp, track->i_id); - } -} - -static int -em_spu_channel_get(void *video) -{ - Emotion_LibVLC *ev = video; - int id; - - if (!ev->started) return -1; - - id = libvlc_video_get_spu(ev->mp); - - return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_text) : -1; -} - -static const char * -em_spu_channel_name_get(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!ev->started) return NULL; - - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_text); - if (track) - return track->psz_description; - else - return NULL; -} - -static void -em_spu_channel_mute_set(void *video, int mute) -{ - Emotion_LibVLC *ev = video; - - ev->spu_mute = mute; - - if (ev->started) - em_spu_channel_set(video, mute ? -1 : 0); -} - -static int -em_spu_channel_mute_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->spu_mute; -} - -static int -em_chapter_count(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0; - - return libvlc_media_player_get_chapter_count(ev->mp); -} - -static void -em_chapter_set(void *video, int chapter) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - libvlc_media_player_set_chapter(ev->mp, chapter); -} - -static int -em_chapter_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0; - - return libvlc_media_player_get_chapter(ev->mp); -} - -static const char * -em_chapter_name_get(void *video, int chapter) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return NULL; - - if (ev->nb_chapters == 0) - { - ev->nb_chapters = - libvlc_media_player_get_full_chapter_descriptions(ev->mp, - -1, - &ev->chapters); - if (ev->nb_chapters == 0) - ev->nb_chapters = -1; - } - return chapter < ev->nb_chapters ? ev->chapters[chapter]->psz_name : NULL; -} - -static void -em_speed_set(void *video, double speed) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - libvlc_media_player_set_rate(ev->mp, speed); -} - -static double -em_speed_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 1.0; - - return libvlc_media_player_get_rate(ev->mp); -} - -static int -em_eject(void *video EINA_UNUSED) -{ - return 1; -} - -static const char * -em_meta_get(void *video, int meta) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return NULL; - - if (meta <= 0 || meta >= META_TRACK_COUNT) - return NULL; - - if (ev->metas[meta]) - return ev->metas[meta]; - else - { - libvlc_meta_t vlc_meta; - switch (meta) - { - case META_TRACK_TITLE: - vlc_meta = libvlc_meta_Title; - break; - - case META_TRACK_ARTIST: - vlc_meta = libvlc_meta_Artist; - break; - - case META_TRACK_ALBUM: - vlc_meta = libvlc_meta_Album; - break; - - case META_TRACK_YEAR: - vlc_meta = libvlc_meta_Date; - break; - - case META_TRACK_GENRE: - vlc_meta = libvlc_meta_Genre; - break; - - case META_TRACK_COMMENT: - vlc_meta = libvlc_meta_Description; - break; - - case META_TRACK_DISCID: - vlc_meta = libvlc_meta_TrackID; - break; - - default: - return NULL; - break; - } - ev->metas[meta] = libvlc_media_get_meta(ev->m, vlc_meta); - - return ev->metas[meta]; - } -} - -static const Emotion_Engine em_engine = -{ - EMOTION_ENGINE_API_VERSION, - EMOTION_ENGINE_PRIORITY_DEFAULT, - "libvlc", - em_add, /* add */ - em_del, /* del */ - em_file_open, /* file_open */ - em_file_close, /* file_close */ - em_play, /* play */ - em_stop, /* stop */ - em_size_get, /* size_get */ - em_pos_set, /* pos_set */ - em_len_get, /* len_get */ - em_buffer_size_get, /* buffer_size_get */ - em_fps_num_get, /* fps_num_get */ - em_fps_den_get, /* fps_den_get */ - em_fps_get, /* fps_get */ - em_pos_get, /* pos_get */ - em_vis_set, /* vis_set */ - em_vis_get, /* vis_get */ - em_vis_supported, /* vis_supported */ - em_ratio_get, /* ratio_get */ - em_video_handled, /* video_handled */ - em_audio_handled, /* audio_handled */ - em_seekable, /* seekable */ - em_frame_done, /* frame_done */ - em_format_get, /* format_get */ - em_video_data_size_get, /* video_data_size_get */ - em_yuv_rows_get, /* yuv_rows_get */ - em_bgra_data_get, /* bgra_data_get */ - em_event_feed, /* event_feed */ - em_event_mouse_button_feed, /* event_mouse_button_feed */ - em_event_mouse_move_feed, /* event_mouse_move_feed */ - em_video_channel_count, /* video_channel_count */ - em_video_channel_set, /* video_channel_set */ - em_video_channel_get, /* video_channel_get */ - em_video_subtitle_file_set, /* video_subtitle_file_set */ - em_video_subtitle_file_get, /* video_subtitle_file_get */ - em_video_channel_name_get, /* video_channel_name_get */ - em_video_channel_mute_set, /* video_channel_mute_set */ - em_video_channel_mute_get, /* video_channel_mute_get */ - em_audio_channel_count, /* audio_channel_count */ - em_audio_channel_set, /* audio_channel_set */ - em_audio_channel_get, /* audio_channel_get */ - em_audio_channel_name_get, /* audio_channel_name_get */ - em_audio_channel_mute_set, /* audio_channel_mute_set */ - em_audio_channel_mute_get, /* audio_channel_mute_get */ - em_audio_channel_volume_set, /* audio_channel_volume_set */ - em_audio_channel_volume_get, /* audio_channel_volume_get */ - em_spu_channel_count, /* spu_channel_count */ - em_spu_channel_set, /* spu_channel_set */ - em_spu_channel_get, /* spu_channel_get */ - em_spu_channel_name_get, /* spu_channel_name_get */ - em_spu_channel_mute_set, /* spu_channel_mute_set */ - em_spu_channel_mute_get, /* spu_channel_mute_get */ - em_chapter_count, /* chapter_count */ - em_chapter_set, /* chapter_set */ - em_chapter_get, /* chapter_get */ - em_chapter_name_get, /* chapter_name_get */ - em_speed_set, /* speed_set */ - em_speed_get, /* speed_get */ - em_eject, /* eject */ - em_meta_get, /* meta_get */ - NULL, /* priority_set */ - NULL, /* priority_get */ - NULL /* em_meta_artwork_get */ -}; - -static void -libvlc_log(void *data EINA_UNUSED, int level, - const libvlc_log_t *ctx EINA_UNUSED, - const char *fmt, va_list args) -{ - Eina_Log_Level eina_log_level; - const char *name, *header; - uintptr_t id; - - libvlc_log_get_object(ctx, &name, &header, &id); - switch (level) - { - case LIBVLC_DEBUG: - eina_log_level = EINA_LOG_LEVEL_DBG; - break; - - case LIBVLC_NOTICE: - eina_log_level = EINA_LOG_LEVEL_INFO; - break; - - case LIBVLC_WARNING: - eina_log_level = EINA_LOG_LEVEL_WARN; - break; - - case LIBVLC_ERROR: - default: - eina_log_level = EINA_LOG_LEVEL_ERR; - break; - } - eina_log_vprint(_emotion_libvlc_log_domain, eina_log_level, - "", name, id, fmt, args); -} - -static libvlc_instance_t * -libvlc_new_env_args(void) -{ - unsigned int argc = 0, i = 0; - const char **argv = NULL; - char *args_env, *args_dup = NULL, *str = NULL, *token, *saveptr; - libvlc_instance_t *instance = NULL; - - args_env = getenv("EMOTION_LIBVLC_ARGS"); - if (!args_env) - goto fallback; - - /* dup since strtok modify the str */ - args_dup = strdup(args_env); - if (!args_dup) - goto fallback; - - /* call strtok to count the numbers of arguments */ - str = strdup(args_dup); - if (!str) - goto fallback; - - token = strtok_r(str, " ", &saveptr); - while (token) - { - argc++; - token = strtok_r(NULL, " ", &saveptr); - } - if (!argc) - goto fallback; - - /* alloc argv */ - argv = calloc(1, argc * sizeof(char *)); - if (!argv) - goto fallback; - - /* call strtok to fill argv */ - free(str); - str = strdup(args_dup); - if (!str) - goto fallback; - - token = strtok_r(str, " ", &saveptr); - while (token && i < argc) - { - argv[i++] = token; - token = strtok_r(NULL, " ", &saveptr); - } - argc = i; - - for (i = 0; i < argc; ++i) - INF("libvlc_argv[%d]: %s", i, argv[i]); - - instance = libvlc_new(argc, argv); - -fallback: - free(args_dup); - free(str); - free(argv); - return instance ? instance : libvlc_new(0, NULL); -} - -Eina_Bool -libvlc_module_init(void) -{ - if (libvlc) - { - return EINA_TRUE; - } - - if (getenv("EMOTION_FPS_DEBUG")) debug_fps = EINA_TRUE; - - eina_threads_init(); - eina_log_threads_enable(); - _emotion_libvlc_log_domain = eina_log_domain_register - ("emotion-libvlc", EINA_COLOR_ORANGE); - if (_emotion_libvlc_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion-libvlc'"); - return EINA_FALSE; - } - - libvlc = libvlc_new_env_args(); - if (!libvlc) - { - CRI("could not create libvlc instance"); - goto error_register; - } - EINA_LOG_INFO("using libvlc: %s", libvlc_get_version()); - libvlc_log_set(libvlc, libvlc_log, NULL); - - if (!_emotion_module_register(&em_engine)) - { - ERR("Could not register module %p", &em_engine); - goto error_register; - } - - return EINA_TRUE; - -error_register: - if (libvlc) - { - libvlc_release(libvlc); - libvlc = NULL; - } - eina_log_domain_unregister(_emotion_libvlc_log_domain); - _emotion_libvlc_log_domain = -1; - return EINA_FALSE; -} - -void -libvlc_module_shutdown(void) -{ - if (!libvlc) - { - EINA_LOG_ERR("too many libvlc_module_shutdown()"); - return; - } - - _emotion_module_unregister(&em_engine); - - libvlc_release(libvlc); - libvlc = NULL; - - eina_log_domain_unregister(_emotion_libvlc_log_domain); - _emotion_libvlc_log_domain = -1; -} - -#ifndef EMOTION_STATIC_BUILD_LIBVLC - -EINA_MODULE_INIT(libvlc_module_init); -EINA_MODULE_SHUTDOWN(libvlc_module_shutdown); - -#endif diff --git a/src/modules/emotion/libvlc/meson.build b/src/modules/emotion/libvlc/meson.build deleted file mode 100644 index e5646a414d..0000000000 --- a/src/modules/emotion/libvlc/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -generic_src = files([ - 'emotion_libvlc.c', -]) - -generic_deps = [dependency('libvlc', version: '>= 3.0')] - -shared_module(emotion_loader, - generic_src, - include_directories : config_dir, - dependencies: [eina, evas, emotion, generic_deps], - install: true, - install_dir : mod_install_dir, - c_args : package_c_args, -) diff --git a/src/modules/emotion/meson.build b/src/modules/emotion/meson.build index e20729ad22..595557b710 100644 --- a/src/modules/emotion/meson.build +++ b/src/modules/emotion/meson.build @@ -1,19 +1,11 @@ -emotion_loaders = [ -'gstreamer1', -'libvlc', -'xine' -] - -if sys_windows == false - emotion_loaders += 'generic' -endif +emotion_loaders = [ 'gstreamer1' ] foreach emotion_loader : emotion_loaders generic_src = [] generic_deps = [] mod_install_dir = join_paths(dir_lib, 'emotion', 'modules', emotion_loader, version_name) - if get_option('emotion-loaders-disabler').contains(emotion_loader) == false + if get_option('gstreamer') == true subdir(emotion_loader) module_files += join_paths(mod_install_dir, 'lib'+emotion_loader+'.'+sys_mod_extension) config_h.set('EMOTION_BUILD_'+emotion_loader.to_upper(), 1) diff --git a/src/modules/emotion/xine/emotion_xine.c b/src/modules/emotion/xine/emotion_xine.c deleted file mode 100644 index dd84c1cbc7..0000000000 --- a/src/modules/emotion/xine/emotion_xine.c +++ /dev/null @@ -1,1707 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include - -#include "emotion_modules.h" -#include "emotion_xine.h" - -int _emotion_xine_log_domain = -1; -static int _emotion_init_count = 0; - -/* internal util calls */ -static void *_em_slave (void *par); -static void _em_slave_event (void *data, int type, void *arg); -static Eina_Bool _em_fd_active (void *data, Ecore_Fd_Handler *fdh); -static void _em_event (void *data, const xine_event_t *event); -static void _em_module_event (void *data, int type); -static Eina_Bool _em_fd_ev_active (void *data, Ecore_Fd_Handler *fdh); -//static int _em_timer (void *data); -static void *_em_get_pos_len_th(void *par); -static void _em_get_pos_len (Emotion_Xine_Video *ev); - -extern plugin_info_t emotion_xine_plugin_info[]; - -static void em_frame_done(void *ef); - -/* this is a slave controller thread for the xine module - libxine loves - * to deadlock, internally stall and otherwise have unpredictable behavior - * if we use the main process thread for many things - so a lot will be - * farmed off to this slave. its job is to handle opening, closing, file - * opening, recoder init etc. and all sorts of things can that often block. - * anything this thread needs to return, it will return via the event pipe. - */ -static void * -_em_slave(void *par) -{ - Emotion_Xine_Video *ev; - void *buf[2]; - int len; - - ev = (Emotion_Xine_Video *)par; - while ((len = read(ev->fd_slave_read, buf, sizeof(buf))) > 0) - { - if (len == sizeof(buf)) - { - Emotion_Xine_Event *eev; - - ev = buf[0]; - eev = buf[1]; - switch (eev->mtype) - { - case 0: /* noop */ - break; - case 1: /* init */ - { - ev->decoder = xine_new(); - xine_init(ev->decoder); - xine_register_plugins(ev->decoder, emotion_xine_plugin_info); - if (1) - { - xine_cfg_entry_t cf; - if (xine_config_lookup_entry(ev->decoder, "input.dvd_use_readahead", &cf)) - { - cf.num_value = 1; // 0 or 1 - xine_config_update_entry(ev->decoder, &cf); - } - } - DBG("OPEN VIDEO PLUGIN..."); - if (!ev->opt_no_video) - ev->video = xine_open_video_driver(ev->decoder, "emotion", - XINE_VISUAL_TYPE_NONE, ev); - DBG("RESULT: xine_open_video_driver() = %p", ev->video); - // Let xine autodetect the best audio output driver - if (!ev->opt_no_audio) - ev->audio = xine_open_audio_driver(ev->decoder, NULL, ev); - // ev->audio = xine_open_audio_driver(ev->decoder, "oss", ev); - // dont use alsa - alsa has oss emulation. - // ev->audio = xine_open_audio_driver(ev->decoder, "alsa", ev); - // ev->audio = xine_open_audio_driver(ev->decoder, "arts", ev); - // ev->audio = xine_open_audio_driver(ev->decoder, "esd", ev); - ev->stream = xine_stream_new(ev->decoder, ev->audio, ev->video); - ev->queue = xine_event_new_queue(ev->stream); - xine_event_create_listener_thread(ev->queue, _em_event, ev); - ev->opening = 0; - ev->play_ok = 1; - _em_module_event(ev, 1); /* event - open done */ - } - break; - case 3: /* shutdown */ - { - _em_module_event(ev, 3); - DBG("shutdown stop"); - xine_stop(ev->stream); - // pthread_mutex_lock(&(ev->get_pos_len_mutex)); - if (!ev->get_pos_thread_deleted) - { - DBG("closing get_pos thread, %p", ev); - pthread_mutex_lock(&(ev->get_pos_len_mutex)); - pthread_cond_broadcast(&(ev->get_pos_len_cond)); - pthread_mutex_unlock(&(ev->get_pos_len_mutex)); - while (ev->get_poslen); - } - DBG("dispose %p", ev); - xine_dispose(ev->stream); - DBG("dispose evq %p", ev); - xine_event_dispose_queue(ev->queue); - DBG("close video drv %p", ev); - if (ev->video) xine_close_video_driver(ev->decoder, ev->video); - DBG("wait for vo to go"); - while (ev->have_vo); - DBG("vo gone"); - DBG("close audio drv %p", ev); - if (ev->audio) xine_close_audio_driver(ev->decoder, ev->audio); - DBG("xine exit %p", ev); - xine_exit(ev->decoder); - DBG("DONE %p", ev); - close(ev->fd_write); - close(ev->fd_read); - close(ev->fd_ev_write); - close(ev->fd_ev_read); - close(ev->fd_slave_write); - close(ev->fd_slave_read); - ev->closing = 0; - if (eev->xine_event) free(eev->xine_event); - free(eev); - free(ev); - return NULL; - } - break; - case 2: /* file open */ - { - int pos_stream = 0; - int pos_time = 0; - int length_time = 0; - uint32_t v; - char *file; - - file = eev->xine_event; - DBG("OPEN STREAM %s", file); - if (xine_open(ev->stream, file)) - { - if (xine_get_pos_length(ev->stream, &pos_stream, &pos_time, &length_time)) - { - if (length_time == 0) - { - ev->pos = (double)pos_stream / 65535; - ev->len = 1.0; - ev->no_time = 1; - } - else - { - ev->pos = 0.0; - ev->len = (double)length_time / 1000.0; - } - } - else - { - ev->pos = 0.0; - ev->len = 1.0; - } - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_FRAME_DURATION); - if (v > 0) ev->fps = 90000.0 / (double)v; - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_WIDTH); - ev->w = v; - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HEIGHT); - ev->h = v; - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_RATIO); - ev->ratio = (double)v / 10000.0; - ev->just_loaded = 1; - ev->get_poslen = 0; - xine_set_param(ev->stream, XINE_PARAM_AUDIO_VOLUME, ev->volume * 100); - } - _em_module_event(ev, 2); /* event - open done */ - } - break; - case 11: /* file close */ - { - DBG("done %p", ev); - em_frame_done(ev); - DBG("stop %p", ev); - xine_stop(ev->stream); - DBG("close %p", ev); - xine_close(ev->stream); - DBG("close done %p", ev); - _em_module_event(ev, 11); - } - break; - case 4: /* play */ - { - double pos; - int pos_stream, pos_time, length_time; - - pos = *((double *)eev->xine_event); - if ((xine_get_param(ev->stream, XINE_PARAM_SPEED) == XINE_SPEED_PAUSE) && - (EINA_DBL_EQ(pos, ev->pos)) && - (!ev->just_loaded)) - { - xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); - } - else - { - if (ev->no_time) - xine_play(ev->stream, pos * 65535, 0); - else - xine_play(ev->stream, 0, pos * 1000); - } - ev->just_loaded = 0; - - if (xine_get_pos_length(ev->stream, - &pos_stream, - &pos_time, - &length_time)) - { - if (length_time == 0) - { - ev->pos = (double)pos_stream / 65535; - ev->len = 1.0; - ev->no_time = 1; - } - else - { - ev->pos = (double)pos_time / 1000.0; - ev->len = (double)length_time / 1000.0; - } - } - _em_module_event(ev, 4); - } - break; - case 5: /* stop */ - { - xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); - _em_module_event(ev, 5); - } - break; - case 6: /* seek */ - { - double pos; - - pos = *((double *)eev->xine_event); - if (ev->no_time) - xine_play(ev->stream, pos * 65535, 0); - else - xine_play(ev->stream, 0, pos * 1000); - if (!ev->play) - xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); - _em_module_event(ev, 6); - } - break; - case 7: /* eject */ - { - xine_eject(ev->stream); - _em_module_event(ev, 7); - } - break; - case 8: /* spu mute */ - { - xine_set_param(ev->stream, XINE_PARAM_IGNORE_SPU, ev->spu_mute); - _em_module_event(ev, 8); - } - break; - case 9: /* channel */ - { - xine_set_param(ev->stream, XINE_PARAM_SPU_CHANNEL, ev->spu_channel); - _em_module_event(ev, 9); - } - break; - case 10: /* vol */ - { - xine_set_param(ev->stream, XINE_PARAM_AUDIO_VOLUME, ev->volume * 100); - _em_module_event(ev, 10); - } - break; - case 12: /* audio mute */ - { - xine_set_param(ev->stream, XINE_PARAM_AUDIO_MUTE, ev->audio_mute); - } - break; - case 13: /* audio mute */ - { - xine_set_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, ev->audio_channel); - } - break; - case 14: /* audio mute */ - { - xine_set_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL, ev->video_channel); - } - break; - default: - break; - } - if (eev->xine_event) free(eev->xine_event); - free(eev); - } - } - return NULL; -} -static void -_em_slave_event(void *data, int type, void *arg) -{ - void *buf[2]; - Emotion_Xine_Event *new_ev; - Emotion_Xine_Video *ev; - - ev = data; - new_ev = calloc(1, sizeof(Emotion_Xine_Event)); - if (!new_ev) return; - new_ev->mtype = type; - new_ev->type = -1; - new_ev->xine_event = arg; - buf[0] = data; - buf[1] = new_ev; - if (write(ev->fd_slave_write, buf, sizeof(buf)) < 0) perror("write"); -} - -static void * -em_add(const Emotion_Engine *api EINA_UNUSED, - Evas_Object *obj, - const Emotion_Module_Options *opt) -{ - Emotion_Xine_Video *ev; - int fds[2]; - sigset_t oldset, newset; - - ev = calloc(1, sizeof(Emotion_Xine_Video)); - EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); - ev->obj = obj; - - if (pipe(fds) == 0) - { - ev->fd_read = fds[0]; - ev->fd_write = fds[1]; - fcntl(ev->fd_read, F_SETFL, O_NONBLOCK); - ev->fd_handler = ecore_main_fd_handler_add(ev->fd_read, ECORE_FD_READ, - _em_fd_active, ev, - NULL, NULL); - ecore_main_fd_handler_active_set(ev->fd_handler, ECORE_FD_READ); - } - if (pipe(fds) == 0) - { - ev->fd_ev_read = fds[0]; - ev->fd_ev_write = fds[1]; - fcntl(ev->fd_ev_read, F_SETFL, O_NONBLOCK); - ev->fd_ev_handler = ecore_main_fd_handler_add(ev->fd_ev_read, - ECORE_FD_READ, _em_fd_ev_active, ev, NULL, NULL); - ecore_main_fd_handler_active_set(ev->fd_ev_handler, ECORE_FD_READ); - } - if (pipe(fds) == 0) - { - ev->fd_slave_read = fds[0]; - ev->fd_slave_write = fds[1]; - if (fcntl(ev->fd_slave_write, F_SETFL, O_NONBLOCK) != 0) - ERR("Can't fcntl() slave write fd"); - } - ev->volume = 0.8; - ev->delete_me = 0; - ev->get_pos_thread_deleted = 0; - ev->opening = 1; - ev->play_ok = 0; - - if (opt) - { - ev->opt_no_audio = opt->no_audio; - ev->opt_no_video = opt->no_video; - } - - pthread_cond_init(&(ev->get_pos_len_cond), NULL); - pthread_mutex_init(&(ev->get_pos_len_mutex), NULL); - sigemptyset(&newset); - sigaddset(&newset, SIGPIPE); - sigaddset(&newset, SIGALRM); - sigaddset(&newset, SIGCHLD); - sigaddset(&newset, SIGUSR1); - sigaddset(&newset, SIGUSR2); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGTERM); -#ifdef SIGPWR - sigaddset(&newset, SIGPWR); -#endif - pthread_sigmask(SIG_BLOCK, &newset, &oldset); - pthread_create(&ev->get_pos_len_th, NULL, _em_get_pos_len_th, ev); - pthread_create(&ev->slave_th, NULL, _em_slave, ev); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - - pthread_detach(ev->slave_th); - _em_slave_event(ev, 1, NULL); - - ev->buffer = 1.0; - - return ev; -} - -static void -em_del(void *ef) -{ - Emotion_Xine_Video *ev = ef; - - ev->closing = 1; - ev->delete_me = 1; - DBG("del fds %p", ev); - ecore_main_fd_handler_del(ev->fd_handler); - ev->fd_handler = NULL; - ecore_main_fd_handler_del(ev->fd_ev_handler); - ev->fd_ev_handler = NULL; - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - - ev->closing = 1; - _em_slave_event(ev, 3, NULL); - DBG("done %p", ev); -} - -static Eina_Bool -em_file_open(void *ef, const char *file) -{ - Emotion_Xine_Video *ev = ef; - _em_slave_event(ev, 2, strdup(file)); - return EINA_TRUE; -} - -static void -em_file_close(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (!ev) return; - _em_slave_event(ev, 11, NULL); -} - -static void -em_play(void *ef, double pos) -{ - Emotion_Xine_Video *ev; - double *ppos; - - ev = (Emotion_Xine_Video *)ef; - ev->play = 1; - ev->play_ok = 0; - ppos = malloc(sizeof(double)); - *ppos = pos; - _em_slave_event(ev, 4, ppos); -} - -static void -em_stop(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - ev->play = 0; - ev->play_ok = 0; - _em_slave_event(ev, 5, NULL); -} - -static void -em_size_get(void *ef, int *w, int *h) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (w) *w = ev->w; - if (h) *h = ev->h; -} - -static void -em_pos_set(void *ef, double pos) -{ - Emotion_Xine_Video *ev; - double *ppos; - - ev = (Emotion_Xine_Video *)ef; - ppos = malloc(sizeof(double)); - *ppos = pos; - _em_slave_event(ev, 6, ppos); -} - -static double -em_len_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->len; -} - -static double -em_buffer_size_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->buffer; -} - -static int -em_fps_num_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return (int)(ev->fps * 10000.0); -} - -static int -em_fps_den_get(void *ef EINA_UNUSED) -{ - return 10000; -} - -static double -em_fps_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->fps; -} - -static double -em_pos_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - _em_get_pos_len(ev); - return ev->pos; -} - -static void -em_vis_set(void *ef, Emotion_Vis vis) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->vis == vis) return; - ev->vis = vis; -} - -static Emotion_Vis -em_vis_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - - return ev->vis; -} - -static Eina_Bool -em_vis_supported(void *ef EINA_UNUSED, Emotion_Vis vis EINA_UNUSED) -{ - return EINA_FALSE; -} - -static double -em_ratio_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->ratio; -} - -static int -em_video_handled(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED)); -} - -static int -em_audio_handled(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_AUDIO) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_HANDLED)); -} - -static int -em_seekable(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_SEEKABLE); -} - -static void -em_frame_done(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->cur_frame) - { - ev->fq--; - if (ev->cur_frame->done_func) - ev->cur_frame->done_func(ev->cur_frame->done_data); - ev->cur_frame = NULL; - } -} - -static Emotion_Format -em_format_get(void *ef) -{ - Emotion_Xine_Video *ev; - volatile Emotion_Xine_Video_Frame *fr; - - ev = (Emotion_Xine_Video *)ef; - fr = ev->cur_frame; - if (fr) return fr->format; - return EMOTION_FORMAT_YV12; -} - -static void -em_video_data_size_get(void *ef, int *w, int *h) -{ - Emotion_Xine_Video *ev; - volatile Emotion_Xine_Video_Frame *fr; - - ev = (Emotion_Xine_Video *)ef; - fr = ev->cur_frame; - if (!fr) - { - if (w) *w = 0; - if (h) *h = 0; - return; - } - if (w) *w = fr->w; - if (h) *h = fr->h; -} - -static int -em_yuv_rows_get(void *ef, int w EINA_UNUSED, int h, unsigned char **yrows, unsigned char **urows, unsigned char **vrows) -{ - Emotion_Xine_Video *ev; - volatile Emotion_Xine_Video_Frame *fr; - - ev = (Emotion_Xine_Video *)ef; - fr = ev->cur_frame; - if (!fr) return 0; - if (fr->y) - { - int i; - - for (i = 0; i < h; i++) yrows[i] = fr->y + (i * fr->y_stride); - for (i = 0; i < (h / 2); i++) urows[i] = fr->u + (i * fr->u_stride); - for (i = 0; i < (h / 2); i++) vrows[i] = fr->v + (i * fr->v_stride); - return 1; - } - return 0; -} - -static int -em_bgra_data_get(void *ef, unsigned char **bgra_data) -{ - Emotion_Xine_Video *ev; - volatile Emotion_Xine_Video_Frame *fr; - - ev = (Emotion_Xine_Video *)ef; - fr = ev->cur_frame; - if (!fr) return 0; - if (fr->bgra_data) - { - *bgra_data = fr->bgra_data; - return 1; - } - return 0; -} - -static void -em_event_feed(void *ef, int event) -{ - Emotion_Xine_Video *ev; - xine_event_t xine_event; - - ev = (Emotion_Xine_Video *)ef; - if ((ev->opening) || (!ev->play_ok)) return; - xine_event.data_length = 0; - xine_event.data = NULL; - xine_event.stream = ev->stream; - gettimeofday(&xine_event.tv, NULL); - switch (event) - { - case EMOTION_EVENT_MENU1: - xine_event.type = XINE_EVENT_INPUT_MENU1; - break; - case EMOTION_EVENT_MENU2: - xine_event.type = XINE_EVENT_INPUT_MENU2; - break; - case EMOTION_EVENT_MENU3: - xine_event.type = XINE_EVENT_INPUT_MENU3; - break; - case EMOTION_EVENT_MENU4: - xine_event.type = XINE_EVENT_INPUT_MENU4; - break; - case EMOTION_EVENT_MENU5: - xine_event.type = XINE_EVENT_INPUT_MENU5; - break; - case EMOTION_EVENT_MENU6: - xine_event.type = XINE_EVENT_INPUT_MENU6; - break; - case EMOTION_EVENT_MENU7: - xine_event.type = XINE_EVENT_INPUT_MENU7; - break; - case EMOTION_EVENT_UP: - xine_event.type = XINE_EVENT_INPUT_UP; - break; - case EMOTION_EVENT_DOWN: - xine_event.type = XINE_EVENT_INPUT_DOWN; - break; - case EMOTION_EVENT_LEFT: - xine_event.type = XINE_EVENT_INPUT_LEFT; - break; - case EMOTION_EVENT_RIGHT: - xine_event.type = XINE_EVENT_INPUT_RIGHT; - break; - case EMOTION_EVENT_SELECT: - xine_event.type = XINE_EVENT_INPUT_SELECT; - break; - case EMOTION_EVENT_NEXT: - xine_event.type = XINE_EVENT_INPUT_NEXT; - break; - case EMOTION_EVENT_PREV: - xine_event.type = XINE_EVENT_INPUT_PREVIOUS; - break; - case EMOTION_EVENT_ANGLE_NEXT: - xine_event.type = XINE_EVENT_INPUT_ANGLE_NEXT; - break; - case EMOTION_EVENT_ANGLE_PREV: - xine_event.type = XINE_EVENT_INPUT_ANGLE_PREVIOUS; - break; - case EMOTION_EVENT_FORCE: - xine_event.type = XINE_EVENT_INPUT_BUTTON_FORCE; - break; - case EMOTION_EVENT_0: - xine_event.type = XINE_EVENT_INPUT_NUMBER_0; - break; - case EMOTION_EVENT_1: - xine_event.type = XINE_EVENT_INPUT_NUMBER_1; - break; - case EMOTION_EVENT_2: - xine_event.type = XINE_EVENT_INPUT_NUMBER_2; - break; - case EMOTION_EVENT_3: - xine_event.type = XINE_EVENT_INPUT_NUMBER_3; - break; - case EMOTION_EVENT_4: - xine_event.type = XINE_EVENT_INPUT_NUMBER_4; - break; - case EMOTION_EVENT_5: - xine_event.type = XINE_EVENT_INPUT_NUMBER_5; - break; - case EMOTION_EVENT_6: - xine_event.type = XINE_EVENT_INPUT_NUMBER_6; - break; - case EMOTION_EVENT_7: - xine_event.type = XINE_EVENT_INPUT_NUMBER_7; - break; - case EMOTION_EVENT_8: - xine_event.type = XINE_EVENT_INPUT_NUMBER_8; - break; - case EMOTION_EVENT_9: - xine_event.type = XINE_EVENT_INPUT_NUMBER_9; - break; - case EMOTION_EVENT_10: - xine_event.type = XINE_EVENT_INPUT_NUMBER_10_ADD; - break; - default: - return; - break; - } - xine_event_send(ev->stream, &xine_event); -} - -static void -em_event_mouse_button_feed(void *ef, int button EINA_UNUSED, int x, int y) -{ - Emotion_Xine_Video *ev; - xine_event_t xine_event; - xine_input_data_t xine_input; - - ev = (Emotion_Xine_Video *)ef; - if ((ev->opening) || (!ev->play_ok)) return; - xine_event.stream = ev->stream; - gettimeofday(&xine_event.tv, NULL); - xine_event.type = XINE_EVENT_INPUT_MOUSE_BUTTON; - xine_input.button = 1; - xine_input.x = x; - xine_input.y = y; - xine_event.data = &xine_input; - xine_event.data_length = sizeof(xine_input); - xine_event_send(ev->stream, &xine_event); -} - -static void -em_event_mouse_move_feed(void *ef, int x, int y) -{ - Emotion_Xine_Video *ev; - xine_event_t xine_event; - xine_input_data_t xine_input; - - ev = (Emotion_Xine_Video *)ef; - if ((ev->opening) || (!ev->play_ok)) return; - xine_event.stream = ev->stream; - gettimeofday(&xine_event.tv, NULL); - xine_event.type = XINE_EVENT_INPUT_MOUSE_MOVE; - xine_input.button = 0; - xine_input.x = x; - xine_input.y = y; - xine_event.data = &xine_input; - xine_event.data_length = sizeof(xine_input); - xine_event_send(ev->stream, &xine_event); -} - -static int -em_video_channel_count(void *ef) -{ - Emotion_Xine_Video *ev; - int v; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_CHANNELS); - if ((v < 1) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO)) return 1; - return v; -} - -static void -em_video_channel_set(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (channel < 0) channel = 0; - ev->video_channel = channel; - _em_slave_event(ev, 14, NULL); -} - -static int -em_video_channel_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL); -} - -static void -em_video_subtitle_file_set(void *video EINA_UNUSED, - const char *filepath EINA_UNUSED) -{ - DBG("video_subtitle_file_set not implemented for xine yet."); -} - -static const char * -em_video_subtitle_file_get(void *video EINA_UNUSED) -{ - DBG("video_subtitle_file_get not implemented for xine yet."); - return NULL; -} - -static const char * -em_video_channel_name_get(void *ef EINA_UNUSED, int channel EINA_UNUSED) -{ - return NULL; -} - -static void -em_video_channel_mute_set(void *ef, int mute) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - ev->video_mute = mute; -} - -static int -em_video_channel_mute_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->video_mute; -} - -static int -em_audio_channel_count(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL); -} - -static void -em_audio_channel_set(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (channel < -1) channel = -1; - ev->audio_channel = channel; - _em_slave_event(ev, 13, NULL); -} - -static int -em_audio_channel_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL); -} - -static const char * -em_audio_channel_name_get(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - static char lang[XINE_LANG_MAX + 1]; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening) return NULL; - lang[0] = 0; - if (xine_get_audio_lang(ev->stream, channel, lang)) return lang; - return NULL; -} - -static void -em_audio_channel_mute_set(void *ef, int mute) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - ev->audio_mute = mute; - _em_slave_event(ev, 12, NULL); -} - -static int -em_audio_channel_mute_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->audio_mute; -} - -static void -em_audio_channel_volume_set(void *ef, double vol) -{ - Emotion_Xine_Video *ev; - - if (vol < 0.0) vol = 0.0; - else if (vol > 1.0) vol = 1.0; - - ev = (Emotion_Xine_Video *)ef; - ev->volume = vol; - _em_slave_event(ev, 10, NULL); -} - -static double -em_audio_channel_volume_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return ev->volume; - ev->volume = xine_get_param(ev->stream, XINE_PARAM_AUDIO_VOLUME) / 100.0; - return ev->volume; -} - -static int -em_spu_channel_count(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL); -} - -static void -em_spu_channel_set(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (channel < 0) channel = 0; - ev->spu_channel = channel; - _em_slave_event(ev, 9, NULL); -} - -static int -em_spu_channel_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_param(ev->stream, XINE_PARAM_SPU_CHANNEL); -} - -static const char * -em_spu_channel_name_get(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - static char lang[XINE_LANG_MAX + 1]; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening) return NULL; - lang[0] = 0; - if (xine_get_spu_lang(ev->stream, channel, lang)) return lang; - return NULL; -} - -static void -em_spu_channel_mute_set(void *ef, int mute) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - ev->spu_mute = mute; - _em_slave_event(ev, 8, NULL); -} - -static int -em_spu_channel_mute_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->spu_mute; -} - -static int -em_chapter_count(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - if (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_CHAPTERS)) - return 99; - return 0; -} - -static void -em_chapter_set(void *ef EINA_UNUSED, int chapter EINA_UNUSED) -{ -} - -static int -em_chapter_get(void *ef EINA_UNUSED) -{ - return 0; -} - -static const char * -em_chapter_name_get(void *ef EINA_UNUSED, int chapter EINA_UNUSED) -{ - return NULL; -} - -static void -em_speed_set(void *ef EINA_UNUSED, double speed EINA_UNUSED) -{ -} - -static double -em_speed_get(void *ef EINA_UNUSED) -{ - return 1.0; -} - -static int -em_eject(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - _em_slave_event(ev, 7, NULL); - return 1; -} - -static const char * -em_meta_get(void *ef, int meta) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if ((ev->opening) || (!ev->play_ok)) return NULL; - switch (meta) - { - case META_TRACK_TITLE: - return xine_get_meta_info(ev->stream, XINE_META_INFO_TITLE); - break; - case META_TRACK_ARTIST: - return xine_get_meta_info(ev->stream, XINE_META_INFO_ARTIST); - break; - case META_TRACK_GENRE: - return xine_get_meta_info(ev->stream, XINE_META_INFO_GENRE); - break; - case META_TRACK_COMMENT: - return xine_get_meta_info(ev->stream, XINE_META_INFO_COMMENT); - break; - case META_TRACK_ALBUM: - return xine_get_meta_info(ev->stream, XINE_META_INFO_ALBUM); - break; - case META_TRACK_YEAR: - return xine_get_meta_info(ev->stream, XINE_META_INFO_YEAR); - break; - case META_TRACK_DISCID: - return xine_get_meta_info(ev->stream, XINE_META_INFO_CDINDEX_DISCID); - break; - default: - break; - } - return NULL; -} - -static Eina_Bool -_em_fd_active(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh) -{ - void *buf; - int fd, len; - Emotion_Xine_Video_Frame *fr; - - fd = ecore_main_fd_handler_fd_get(fdh); - if (fd < 0) return EINA_TRUE; - while ((len = read(fd, &buf, sizeof(buf))) > 0) - { - if (len == sizeof(buf)) - { - Emotion_Xine_Video *ev; - - fr = buf; - ev = _emotion_video_get(fr->obj); - if (ev) - { - em_frame_done(ev); - ev->cur_frame = fr; - _em_get_pos_len(ev); - if ((xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO)) && - (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED))) - { - if (ev->video_mute) em_frame_done(ev); - else _emotion_frame_new(fr->obj); - } - _emotion_frame_resize(fr->obj, fr->w, fr->h, fr->ratio); - _emotion_video_pos_update(fr->obj, ev->pos, ev->len); - } - } - } - return EINA_TRUE; -} - -static void -_em_event(void *data, const xine_event_t *event) -{ - void *buf[2]; - Emotion_Xine_Event *new_ev; - Emotion_Xine_Video *ev; - - ev = data; - new_ev = calloc(1, sizeof(Emotion_Xine_Event)); - if (!new_ev) return; - new_ev->mtype = 0; - new_ev->type = event->type; - if (event->data) - { - new_ev->xine_event = malloc(event->data_length); - if (!new_ev->xine_event) - { - free(new_ev); - return; - } - memcpy(new_ev->xine_event, event->data, event->data_length); - } - buf[0] = data; - buf[1] = new_ev; - if (write(ev->fd_ev_write, buf, sizeof(buf)) < 0) perror("write"); -} - -static void -_em_module_event(void *data, int type) -{ - void *buf[2]; - Emotion_Xine_Event *new_ev; - Emotion_Xine_Video *ev; - - ev = data; - new_ev = calloc(1, sizeof(Emotion_Xine_Event)); - if (!new_ev) return; - new_ev->mtype = type; - new_ev->type = -1; - buf[0] = data; - buf[1] = new_ev; - if (write(ev->fd_ev_write, buf, sizeof(buf)) < 0) perror("write"); -} - -static Eina_Bool -_em_audio_only_poller(void *data) -{ - Emotion_Xine_Video *ev; - - ev = data; - _em_get_pos_len(ev); - return EINA_TRUE; -} - -static Eina_Bool -_em_fd_ev_active(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh) -{ - int fd, len; - void *buf[2]; - - fd = ecore_main_fd_handler_fd_get(fdh); - while ((len = read(fd, buf, sizeof(buf))) > 0) - { - if (len == sizeof(buf)) - { - Emotion_Xine_Video *ev; - Emotion_Xine_Event *eev; - - ev = buf[0]; - eev = buf[1]; - if (eev->mtype != 0) - { - switch (eev->mtype) - { - case 1: /* init done */ - ev->play_ok = 1; - break; - case 2: /* open done */ - ev->play_ok = 1; - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - _emotion_open_done(ev->obj); - _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio); - break; - case 3: /* shutdown done */ - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - ev->play_ok = 1; - break; - case 4: /* play done */ - ev->play_ok = 1; - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - if ((!(xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED))) && - (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_AUDIO) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_HANDLED))) - ev->anim = ecore_evas_animator_add(ev->obj, _em_audio_only_poller, ev); - _emotion_playback_started(ev->obj); - break; - case 5: /* stop done */ - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - ev->play_ok = 1; - break; - case 6: /* seek done */ - ev->play_ok = 1; - _emotion_seek_done(ev->obj); - _em_get_pos_len(ev); - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); - break; - case 7: /* eject done */ - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - ev->play_ok = 1; - break; - case 8: /* spu mute done */ - ev->play_ok = 1; - break; - case 9: /* channel done */ - ev->play_ok = 1; - break; - case 10: /* volume done */ - ev->play_ok = 1; - break; - case 11: /* close done */ - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - ev->play_ok = 1; - break; - case 15: /* get pos done */ - if (!EINA_DBL_EQ(ev->last_pos, ev->pos)) - { - ev->last_pos = ev->pos; - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); - } - break; - default: - break; - } - } - else - { - switch (eev->type) - { - case XINE_EVENT_UI_PLAYBACK_FINISHED: - { - ev->play = 0; - _emotion_decode_stop(ev->obj); - _emotion_playback_finished(ev->obj); - } - break; - case XINE_EVENT_UI_CHANNELS_CHANGED: - { - _emotion_channels_change(ev->obj); - } - break; - case XINE_EVENT_UI_SET_TITLE: - { - xine_ui_data_t *e; - - e = (xine_ui_data_t *)eev->xine_event; - _emotion_title_set(ev->obj, e->str); - } - break; - case XINE_EVENT_FRAME_FORMAT_CHANGE: - break; - case XINE_EVENT_UI_MESSAGE: - { - WRN("UI Message [FIXME: break this out to emotion api]"); - // e->type = error type(XINE_MSG_NO_ERROR, XINE_MSG_GENERAL_WARNING, XINE_MSG_UNKNOWN_HOST etc.) - // e->messages is a list of messages DOUBLE null terminated - } - break; - case XINE_EVENT_AUDIO_LEVEL: - { - _emotion_audio_level_change(ev->obj); - WRN("Audio Level [FIXME: break this out to emotion api]"); - // e->left (0->100) - // e->right - // e->mute - } - break; - case XINE_EVENT_PROGRESS: - { - xine_progress_data_t *e; - - e = (xine_progress_data_t *)eev->xine_event; - DBG("PROGRESS: %i", e->percent); - ev->buffer = e->percent; - _emotion_progress_set(ev->obj, (char *)e->description, (double)e->percent / 100.0); - } - break; - case XINE_EVENT_MRL_REFERENCE_EXT: - { - xine_mrl_reference_data_ext_t *e; - - e = (xine_mrl_reference_data_ext_t *)eev->xine_event; - _emotion_file_ref_set(ev->obj, e->mrl, e->alternative); - } - break; - case XINE_EVENT_UI_NUM_BUTTONS: - { - xine_ui_data_t *e; - - e = (xine_ui_data_t *)eev->xine_event; - _emotion_spu_button_num_set(ev->obj, e->num_buttons); - } - break; - case XINE_EVENT_SPU_BUTTON: - { - xine_spu_button_t *e; - - e = (xine_spu_button_t *)eev->xine_event; - if (e->direction == 1) - _emotion_spu_button_set(ev->obj, e->button); - else - _emotion_spu_button_set(ev->obj, -1); - } - break; - case XINE_EVENT_DROPPED_FRAMES: - { - xine_dropped_frames_t *e; - - e = (xine_dropped_frames_t *)eev->xine_event; - WRN("Dropped Frames (skipped %i) (discarded %i) [FIXME: break this out to the emotion api]", e->skipped_frames, e->discarded_frames); - // e->skipped_frames = % frames skipped * 10 - // e->discarded_frames = % frames skipped * 10 - } - break; - default: - // DBG("unknown event type %i", eev->type); - break; - } - } - if (eev->xine_event) free(eev->xine_event); - free(eev); - } - } - return EINA_TRUE; -} - -static void * -_em_get_pos_len_th(void *par) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)par; - - for (;;) - { - pthread_mutex_lock(&(ev->get_pos_len_mutex)); - pthread_cond_wait(&(ev->get_pos_len_cond), &(ev->get_pos_len_mutex)); - pthread_mutex_unlock(&(ev->get_pos_len_mutex)); - if (ev->get_poslen) - { - int pos_stream = 0; - int pos_time = 0; - int length_time = 0; - - if (xine_get_pos_length(ev->stream, &pos_stream, &pos_time, &length_time)) - { - if (length_time == 0) - { - ev->pos = (double)pos_stream / 65535; - ev->len = 1.0; - ev->no_time = 1; - } - else - { - ev->pos = (double)pos_time / 1000.0; - ev->len = (double)length_time / 1000.0; - ev->no_time = 0; - } - } - ev->get_poslen = 0; - _em_module_event(ev, 15); /* event - getpos done */ - //DBG("get pos %3.3f", ev->pos); - } - if (ev->delete_me) - { - ev->get_pos_thread_deleted = 1; - return NULL; - } - } - return NULL; -} - -static void -_em_get_pos_len(Emotion_Xine_Video *ev) -{ - if (!ev->play_ok) return; - ev->get_poslen = 1; - pthread_mutex_lock(&(ev->get_pos_len_mutex)); - pthread_cond_broadcast(&(ev->get_pos_len_cond)); - pthread_mutex_unlock(&(ev->get_pos_len_mutex)); -} - -static const Emotion_Engine em_engine = -{ - EMOTION_ENGINE_API_VERSION, - EMOTION_ENGINE_PRIORITY_DEFAULT, - "xine", - em_add, /* add */ - em_del, /* del */ - em_file_open, /* file_open */ - em_file_close, /* file_close */ - em_play, /* play */ - em_stop, /* stop */ - em_size_get, /* size_get */ - em_pos_set, /* pos_set */ - em_len_get, /* len_get */ - em_buffer_size_get, /* buffer_size_get */ - em_fps_num_get, /* fps_num_get */ - em_fps_den_get, /* fps_den_get */ - em_fps_get, /* fps_get */ - em_pos_get, /* pos_get */ - em_vis_set, /* vis_set */ - em_vis_get, /* vis_get */ - em_vis_supported, /* vis_supported */ - em_ratio_get, /* ratio_get */ - em_video_handled, /* video_handled */ - em_audio_handled, /* audio_handled */ - em_seekable, /* seekable */ - em_frame_done, /* frame_done */ - em_format_get, /* format_get */ - em_video_data_size_get, /* video_data_size_get */ - em_yuv_rows_get, /* yuv_rows_get */ - em_bgra_data_get, /* bgra_data_get */ - em_event_feed, /* event_feed */ - em_event_mouse_button_feed, /* event_mouse_button_feed */ - em_event_mouse_move_feed, /* event_mouse_move_feed */ - em_video_channel_count, /* video_channel_count */ - em_video_channel_set, /* video_channel_set */ - em_video_channel_get, /* video_channel_get */ - em_video_subtitle_file_set, /* video_subtitle_file_set */ - em_video_subtitle_file_get, /* video_subtitle_file_get */ - em_video_channel_name_get, /* video_channel_name_get */ - em_video_channel_mute_set, /* video_channel_mute_set */ - em_video_channel_mute_get, /* video_channel_mute_get */ - em_audio_channel_count, /* audio_channel_count */ - em_audio_channel_set, /* audio_channel_set */ - em_audio_channel_get, /* audio_channel_get */ - em_audio_channel_name_get, /* audio_channel_name_get */ - em_audio_channel_mute_set, /* audio_channel_mute_set */ - em_audio_channel_mute_get, /* audio_channel_mute_get */ - em_audio_channel_volume_set, /* audio_channel_volume_set */ - em_audio_channel_volume_get, /* audio_channel_volume_get */ - em_spu_channel_count, /* spu_channel_count */ - em_spu_channel_set, /* spu_channel_set */ - em_spu_channel_get, /* spu_channel_get */ - em_spu_channel_name_get, /* spu_channel_name_get */ - em_spu_channel_mute_set, /* spu_channel_mute_set */ - em_spu_channel_mute_get, /* spu_channel_mute_get */ - em_chapter_count, /* chapter_count */ - em_chapter_set, /* chapter_set */ - em_chapter_get, /* chapter_get */ - em_chapter_name_get, /* chapter_name_get */ - em_speed_set, /* speed_set */ - em_speed_get, /* speed_get */ - em_eject, /* eject */ - em_meta_get, /* meta_get */ - NULL, /* priority_set */ - NULL, /* priority_get */ - NULL /* em_meta_artwork_get */ -}; - -Eina_Bool -xine_module_init(void) -{ - if (_emotion_init_count > 0) - { - _emotion_init_count++; - return EINA_TRUE; - } - - eina_threads_init(); - eina_log_threads_enable(); - _emotion_xine_log_domain = eina_log_domain_register - ("emotion-xine", EINA_COLOR_LIGHTCYAN); - if (_emotion_xine_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion-xine'"); - return EINA_FALSE; - } - - if (!_emotion_module_register(&em_engine)) - { - CRI("Could not register module %p", &em_engine); - eina_log_domain_unregister(_emotion_xine_log_domain); - _emotion_xine_log_domain = -1; - return EINA_FALSE; - } - - _emotion_init_count = 1; - return EINA_TRUE; -} - -void -xine_module_shutdown(void) -{ - if (_emotion_init_count > 1) - { - _emotion_init_count--; - return; - } - else if (_emotion_init_count == 0) - { - EINA_LOG_ERR("too many xine_module_shutdown()"); - return; - } - _emotion_init_count = 0; - - _emotion_module_unregister(&em_engine); - - eina_log_domain_unregister(_emotion_xine_log_domain); - _emotion_xine_log_domain = -1; -} - -#ifndef EMOTION_STATIC_BUILD_XINE - -EINA_MODULE_INIT(xine_module_init); -EINA_MODULE_SHUTDOWN(xine_module_shutdown); - -#endif - -#if 0 -void -em_debug(Emotion_Xine_Video *ev) -{ - int has_chapters = 0; - int max_spu = 0; - int max_audio = 0; - int video_channels = 0; - int video_streams = 0; - int video_seekable = 0; - char *title; - char *comment; - char *artist; - char *genre; - char *album; - char *year; - char *cdindex_discid; - int video_channel = 0; - int audio_channel = 0; - int spu_channel = 0; - int video_ratio = 0; - int audio_mode = 0; - -// return; - has_chapters = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_CHAPTERS); - max_spu = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL); - max_audio = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL); - video_channels = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_CHANNELS); - video_streams = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_STREAMS); - video_seekable = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_SEEKABLE); - title = xine_get_meta_info(ev->stream, XINE_META_INFO_TITLE); - comment = xine_get_meta_info(ev->stream, XINE_META_INFO_COMMENT); - artist = xine_get_meta_info(ev->stream, XINE_META_INFO_ARTIST); - genre = xine_get_meta_info(ev->stream, XINE_META_INFO_GENRE); - album = xine_get_meta_info(ev->stream, XINE_META_INFO_ALBUM); - year = xine_get_meta_info(ev->stream, XINE_META_INFO_YEAR); - cdindex_discid = xine_get_meta_info(ev->stream, XINE_META_INFO_CDINDEX_DISCID); - video_channel = xine_get_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL); - audio_channel = xine_get_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL); - spu_channel = xine_get_param(ev->stream, XINE_PARAM_SPU_CHANNEL); - video_ratio = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_RATIO); - audio_mode = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_MODE); - DBG("has_chapters = %i", has_chapters); - DBG("max_spu = %i", max_spu); - DBG("max_audio = %i", max_audio); - DBG("video_channels = %i", video_channels); - DBG("video_streams = %i", video_streams); - DBG("video_seekable = %i", video_seekable); - DBG("title = %s", title); - DBG("comment = %s", comment); - DBG("artist = %s", artist); - DBG("genre = %s", genre); - DBG("album = %s", album); - DBG("year = %s", year); - DBG("cdindex_discid = %s", cdindex_discid); - DBG("video_channel = %i", video_channel); - DBG("audio_channel = %i", audio_channel); - DBG("spu_channels = %i", spu_channel); - DBG("video_ratio = %i", video_ratio); - DBG("audio_mode = %i", audio_mode); - { - int i; - - for (i = 0; i <= max_audio; i++) - { - char lang[XINE_LANG_MAX + 1]; - char buf[128] = "NONE"; - - lang[0] = 0; - if (xine_get_audio_lang(ev->stream, i, lang)) - eina_strlcpy(buf, lang, sizeof(buf)); - DBG(" AUDIO %i = %s", i, buf); - } - for (i = 0; i <= max_spu; i++) - { - char lang[XINE_LANG_MAX + 1]; - char buf[128] = "NONE"; - - lang[0] = 0; - if (xine_get_spu_lang(ev->stream, i, lang)) - eina_strlcpy(buf, lang, sizeof(buf)); - DBG(" SPU %i = %s", i, buf); - } - } -} -#endif diff --git a/src/modules/emotion/xine/emotion_xine.h b/src/modules/emotion/xine/emotion_xine.h deleted file mode 100644 index 9807624e14..0000000000 --- a/src/modules/emotion/xine/emotion_xine.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef EMOTION_XINE_H -#define EMOTION_XINE_H - -#include -#include -#include -#include -#include - -typedef struct _Emotion_Xine_Video Emotion_Xine_Video; -typedef struct _Emotion_Xine_Video_Frame Emotion_Xine_Video_Frame; -typedef struct _Emotion_Xine_Event Emotion_Xine_Event; - -struct _Emotion_Xine_Video -{ - xine_t *decoder; - xine_video_port_t *video; - xine_audio_port_t *audio; - xine_stream_t *stream; - xine_event_queue_t *queue; - volatile double len; - volatile double pos; - volatile double last_pos; - volatile double volume; - volatile double buffer; - double fps; - double ratio; - int w, h; - Evas_Object *obj; - volatile Emotion_Xine_Video_Frame *cur_frame; - volatile int get_poslen; - volatile int spu_channel; - volatile int audio_channel; - volatile int video_channel; - volatile int fq; - Emotion_Vis vis; - int fd_read; - int fd_write; - Ecore_Fd_Handler *fd_handler; - int fd_ev_read; - int fd_ev_write; - Ecore_Fd_Handler *fd_ev_handler; - Ecore_Animator *anim; - unsigned char play : 1; - unsigned char just_loaded : 1; - unsigned char video_mute : 1; - unsigned char audio_mute : 1; - unsigned char spu_mute : 1; - Eina_Bool opt_no_video : 1; - Eina_Bool opt_no_audio : 1; - volatile unsigned char delete_me : 1; - volatile unsigned char no_time : 1; - volatile unsigned char opening : 1; - volatile unsigned char closing : 1; - volatile unsigned char have_vo : 1; - volatile unsigned char play_ok : 1; - - pthread_t get_pos_len_th; - pthread_cond_t get_pos_len_cond; - pthread_mutex_t get_pos_len_mutex; - - pthread_t slave_th; - int fd_slave_read; - int fd_slave_write; - - unsigned char get_pos_thread_deleted : 1; -}; - -struct _Emotion_Xine_Video_Frame -{ - int w, h; - double ratio; - Emotion_Format format; - unsigned char *y, *u, *v; - unsigned char *bgra_data; - int y_stride, u_stride, v_stride; - Evas_Object *obj; - double timestamp; - void (*done_func)(void *data); - void *done_data; - void *frame; -}; - -struct _Emotion_Xine_Event -{ - int type; - void *xine_event; - int mtype; -}; - -#ifdef DBG -#undef DBG -#endif -#define DBG(...) EINA_LOG_DOM_DBG(_emotion_xine_log_domain, __VA_ARGS__) - -#ifdef INF -#undef INF -#endif -#define INF(...) EINA_LOG_DOM_INFO(_emotion_xine_log_domain, __VA_ARGS__) - -#ifdef WRN -#undef WRN -#endif -#define WRN(...) EINA_LOG_DOM_WARN(_emotion_xine_log_domain, __VA_ARGS__) - -#ifdef ERR -#undef ERR -#endif -#define ERR(...) EINA_LOG_DOM_ERR(_emotion_xine_log_domain, __VA_ARGS__) - -#ifdef CRI -#undef CRI -#endif -#define CRI(...) EINA_LOG_DOM_CRIT(_emotion_xine_log_domain, __VA_ARGS__) - -extern int _emotion_xine_log_domain; - -#endif diff --git a/src/modules/emotion/xine/emotion_xine_vo_out.c b/src/modules/emotion/xine/emotion_xine_vo_out.c deleted file mode 100644 index 01c18f8894..0000000000 --- a/src/modules/emotion/xine/emotion_xine_vo_out.c +++ /dev/null @@ -1,766 +0,0 @@ -/***************************************************************************/ -/*** emotion xine display engine ***/ -/***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include - -#include -#include -#include - -#include "emotion_modules.h" -#include "emotion_xine.h" - -#include -#include -#include -#include -#include - -#define BLEND_BYTE(dst, src, o) (((src)*o + ((dst)*(0xf-o)))/0xf) - -/***************************************************************************/ -typedef struct _Emotion_Frame Emotion_Frame; -typedef struct _Emotion_Driver Emotion_Driver; -typedef struct _Emotion_Class Emotion_Class; -typedef struct _Emotion_Lut Emotion_Lut; - -struct _Emotion_Frame -{ - vo_frame_t vo_frame; - int width; - int height; - double ratio; - int format; - xine_t *xine; - - Emotion_Xine_Video_Frame frame; - unsigned char in_use : 1; -}; - -struct _Emotion_Driver -{ - vo_driver_t vo_driver; - config_values_t *config; - int ratio; - xine_t *xine; - Emotion_Xine_Video *ev; -}; - -struct _Emotion_Class -{ - video_driver_class_t driver_class; - config_values_t *config; - xine_t *xine; -}; - -struct _Emotion_Lut -{ - uint8_t cb : 8; - uint8_t cr : 8; - uint8_t y : 8; - uint8_t foo : 8; -} __attribute__ ((packed)); - -typedef void (*done_func_type)(void *data); - -/***************************************************************************/ -static void *_emotion_class_init (xine_t *xine, void *visual); -static void _emotion_class_dispose (video_driver_class_t *driver_class); -static char *_emotion_class_identifier_get (video_driver_class_t *driver_class); -static char *_emotion_class_description_get (video_driver_class_t *driver_class); - -static vo_driver_t *_emotion_open (video_driver_class_t *driver_class, const void *visual); -static void _emotion_dispose (vo_driver_t *vo_driver); - -static int _emotion_redraw (vo_driver_t *vo_driver); - -static uint32_t _emotion_capabilities_get (vo_driver_t *vo_driver); -static int _emotion_gui_data_exchange (vo_driver_t *vo_driver, int data_type, void *data); - -static int _emotion_property_set (vo_driver_t *vo_driver, int property, int value); -static int _emotion_property_get (vo_driver_t *vo_driver, int property); -static void _emotion_property_min_max_get (vo_driver_t *vo_driver, int property, int *min, int *max); - -static vo_frame_t *_emotion_frame_alloc (vo_driver_t *vo_driver); -static void _emotion_frame_dispose (vo_frame_t *vo_frame); -static void _emotion_frame_format_update (vo_driver_t *vo_driver, vo_frame_t *vo_frame, uint32_t width, uint32_t height, double ratio, int format, int flags); -static void _emotion_frame_display (vo_driver_t *vo_driver, vo_frame_t *vo_frame); -static void _emotion_frame_field (vo_frame_t *vo_frame, int which_field); - -static void _emotion_frame_data_free (Emotion_Frame *fr); -static void _emotion_frame_data_unlock (Emotion_Frame *fr); - -static void _emotion_overlay_begin (vo_driver_t *vo_driver, vo_frame_t *vo_frame, int changed); -static void _emotion_overlay_end (vo_driver_t *vo_driver, vo_frame_t *vo_frame); -static void _emotion_overlay_blend (vo_driver_t *vo_driver, vo_frame_t *vo_frame, vo_overlay_t *vo_overlay); - -static void _emotion_overlay_mem_blend_8 (uint8_t *mem, uint8_t val, uint8_t o, size_t sz); -static void _emotion_overlay_blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl, int dst_width, int dst_height, int dst_pitches[3]); - -static void _emotion_yuy2_to_bgra32 (int width, int height, unsigned char *src, unsigned char *dst); - -/***************************************************************************/ -static vo_info_t _emotion_info = -{ - 1, /* priority */ - XINE_VISUAL_TYPE_NONE /* visual type */ -}; - -plugin_info_t emotion_xine_plugin_info[] = -{ - { PLUGIN_VIDEO_OUT, 21, "emotion", XINE_VERSION_CODE, &_emotion_info, _emotion_class_init }, - { PLUGIN_VIDEO_OUT, 22, "emotion", XINE_VERSION_CODE, &_emotion_info, _emotion_class_init }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; - -/***************************************************************************/ -static void * -_emotion_class_init(xine_t *xine, void *visual EINA_UNUSED) -{ - Emotion_Class *cl; - -// DBG(""); - cl = (Emotion_Class *) malloc(sizeof(Emotion_Class)); - if (!cl) return NULL; - cl->driver_class.open_plugin = _emotion_open; -#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2) - cl->driver_class.get_identifier = _emotion_class_identifier_get; - cl->driver_class.get_description = _emotion_class_description_get; -#else - cl->driver_class.identifier = _emotion_class_identifier_get(NULL); - cl->driver_class.description = _emotion_class_description_get(NULL); -#endif - cl->driver_class.dispose = _emotion_class_dispose; - cl->config = xine->config; - cl->xine = xine; - - return cl; -} - -static void -_emotion_class_dispose(video_driver_class_t *driver_class) -{ - Emotion_Class *cl; - - cl = (Emotion_Class *)driver_class; - free(cl); -} - -static char * -_emotion_class_identifier_get(video_driver_class_t *driver_class EINA_UNUSED) -{ - return "emotion"; -} - -static char * -_emotion_class_description_get(video_driver_class_t *driver_class EINA_UNUSED) -{ - return "Emotion xine video output plugin"; -} - -/***************************************************************************/ -static vo_driver_t * -_emotion_open(video_driver_class_t *driver_class, const void *visual) -{ - Emotion_Class *cl; - Emotion_Driver *dv; - - cl = (Emotion_Class *)driver_class; - /* visual here is the data ptr passed to xine_open_video_driver() */ -// DBG(""); - dv = (Emotion_Driver *)malloc(sizeof(Emotion_Driver)); - if (!dv) return NULL; - - dv->config = cl->config; - dv->xine = cl->xine; - dv->ratio = XINE_VO_ASPECT_AUTO; - dv->vo_driver.get_capabilities = _emotion_capabilities_get; - dv->vo_driver.alloc_frame = _emotion_frame_alloc; - dv->vo_driver.update_frame_format = _emotion_frame_format_update; - dv->vo_driver.overlay_begin = _emotion_overlay_begin; - dv->vo_driver.overlay_blend = _emotion_overlay_blend; - dv->vo_driver.overlay_end = _emotion_overlay_end; - dv->vo_driver.display_frame = _emotion_frame_display; - dv->vo_driver.get_property = _emotion_property_get; - dv->vo_driver.set_property = _emotion_property_set; - dv->vo_driver.get_property_min_max = _emotion_property_min_max_get; - dv->vo_driver.gui_data_exchange = _emotion_gui_data_exchange; - dv->vo_driver.dispose = _emotion_dispose; - dv->vo_driver.redraw_needed = _emotion_redraw; - dv->ev = (Emotion_Xine_Video *)visual; - dv->ev->have_vo = 1; - DBG("vo_driver = %p", &dv->vo_driver); - return &dv->vo_driver; -} - -static void -_emotion_dispose(vo_driver_t *vo_driver) -{ - Emotion_Driver *dv; - - dv = (Emotion_Driver *)vo_driver; - dv->ev->have_vo = 0; - DBG("vo_driver = %p", dv); - free(dv); -} - -/***************************************************************************/ -static int -_emotion_redraw(vo_driver_t *vo_driver EINA_UNUSED) -{ -// DBG(""); - return 0; -} - -/***************************************************************************/ -static uint32_t -_emotion_capabilities_get(vo_driver_t *vo_driver EINA_UNUSED) -{ -// DBG(""); - return VO_CAP_YV12 | VO_CAP_YUY2; -} - -/***************************************************************************/ -static int -_emotion_gui_data_exchange(vo_driver_t *vo_driver EINA_UNUSED, int data_type, void *data EINA_UNUSED) -{ -// DBG(""); - switch (data_type) - { - case XINE_GUI_SEND_COMPLETION_EVENT: - break; - case XINE_GUI_SEND_DRAWABLE_CHANGED: - break; - case XINE_GUI_SEND_EXPOSE_EVENT: - break; - case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: - break; - case XINE_GUI_SEND_VIDEOWIN_VISIBLE: - break; - case XINE_GUI_SEND_SELECT_VISUAL: - break; - default: - break; - } - return 0; -} - -/***************************************************************************/ -static int -_emotion_property_set(vo_driver_t *vo_driver, int property, int value) -{ - Emotion_Driver *dv; - - dv = (Emotion_Driver *)vo_driver; -// DBG(""); - switch (property) - { - case VO_PROP_ASPECT_RATIO: - if (value >= XINE_VO_ASPECT_NUM_RATIOS) - value = XINE_VO_ASPECT_AUTO; -// DBG("DRIVER RATIO SET %i!", value); - dv->ratio = value; - break; - default: - break; - } - return value; -} - -static int -_emotion_property_get(vo_driver_t *vo_driver, int property) -{ - Emotion_Driver *dv; - - dv = (Emotion_Driver *)vo_driver; -// DBG(""); - switch (property) - { - case VO_PROP_ASPECT_RATIO: - return dv->ratio; - break; - default: - break; - } - return 0; -} - -static void -_emotion_property_min_max_get(vo_driver_t *vo_driver EINA_UNUSED, int property EINA_UNUSED, int *min, int *max) -{ -// DBG(""); - *min = 0; - *max = 0; -} - -/***************************************************************************/ -static vo_frame_t * -_emotion_frame_alloc(vo_driver_t *vo_driver EINA_UNUSED) -{ - Emotion_Frame *fr; - -// DBG(""); - fr = (Emotion_Frame *)calloc(1, sizeof(Emotion_Frame)); - if (!fr) return NULL; - - fr->vo_frame.base[0] = NULL; - fr->vo_frame.base[1] = NULL; - fr->vo_frame.base[2] = NULL; - - fr->vo_frame.proc_slice = NULL; - fr->vo_frame.proc_frame = NULL; - fr->vo_frame.field = _emotion_frame_field; - fr->vo_frame.dispose = _emotion_frame_dispose; - fr->vo_frame.driver = vo_driver; - - return (vo_frame_t *)fr; -} - -static void -_emotion_frame_dispose(vo_frame_t *vo_frame) -{ - Emotion_Frame *fr; - - fr = (Emotion_Frame *)vo_frame; -// DBG(""); - _emotion_frame_data_free(fr); - free(fr); -} - -static void -_emotion_frame_format_update(vo_driver_t *vo_driver, vo_frame_t *vo_frame, uint32_t width, uint32_t height, double ratio, int format, int flags EINA_UNUSED) -{ - Emotion_Driver *dv; - Emotion_Frame *fr; - - dv = (Emotion_Driver *)vo_driver; - fr = (Emotion_Frame *)vo_frame; - - if ((fr->width != (int)width) || (fr->height != (int)height) || - (fr->format != format) || (!fr->vo_frame.base[0])) - { -// DBG(""); - _emotion_frame_data_free(fr); - - fr->width = width; - fr->height = height; - fr->format = format; - - switch (format) - { - case XINE_IMGFMT_YV12: - { - int y_size, uv_size; - - fr->frame.format = EMOTION_FORMAT_YV12; - fr->vo_frame.pitches[0] = 8 * ((width + 7) / 8); - fr->vo_frame.pitches[1] = 8 * ((width + 15) / 16); - fr->vo_frame.pitches[2] = 8 * ((width + 15) / 16); - - y_size = fr->vo_frame.pitches[0] * height; - uv_size = fr->vo_frame.pitches[1] * ((height + 1) / 2); - - fr->vo_frame.base[0] = malloc(y_size + (2 * uv_size)); - fr->vo_frame.base[1] = fr->vo_frame.base[0] + y_size + uv_size; - fr->vo_frame.base[2] = fr->vo_frame.base[0] + y_size; - fr->frame.w = fr->width; - fr->frame.h = fr->height; - fr->frame.ratio = fr->vo_frame.ratio; - fr->frame.y = fr->vo_frame.base[0]; - fr->frame.u = fr->vo_frame.base[1]; - fr->frame.v = fr->vo_frame.base[2]; - fr->frame.bgra_data = NULL; - fr->frame.y_stride = fr->vo_frame.pitches[0]; - fr->frame.u_stride = fr->vo_frame.pitches[1]; - fr->frame.v_stride = fr->vo_frame.pitches[2]; - fr->frame.obj = dv->ev->obj; - } - break; - case XINE_IMGFMT_YUY2: - { - fr->frame.format = EMOTION_FORMAT_BGRA; - fr->vo_frame.pitches[0] = 8 * ((width + 3) / 4); - fr->vo_frame.pitches[1] = 0; - fr->vo_frame.pitches[2] = 0; - - fr->vo_frame.base[0] = malloc(fr->vo_frame.pitches[0] * height); - fr->vo_frame.base[1] = NULL; - fr->vo_frame.base[2] = NULL; - - fr->frame.w = fr->width; - fr->frame.h = fr->height; - fr->frame.ratio = fr->vo_frame.ratio; - fr->frame.y = NULL; - fr->frame.u = NULL; - fr->frame.v = NULL; - fr->frame.bgra_data = malloc(fr->width * fr->height * 4); - fr->frame.y_stride = 0; - fr->frame.u_stride = 0; - fr->frame.v_stride = 0; - fr->frame.obj = dv->ev->obj; - } - break; - default: - break; - } - if (((format == XINE_IMGFMT_YV12) - && ((!fr->vo_frame.base[0]) - || (!fr->vo_frame.base[1]) - || (!fr->vo_frame.base[2]))) - || ((format == XINE_IMGFMT_YUY2) - && ((!fr->vo_frame.base[0]) - || (!fr->frame.bgra_data)))) - { - _emotion_frame_data_free(fr); - } - } - fr->frame.ratio = fr->vo_frame.ratio; - fr->ratio = ratio; -} - -static void -_emotion_frame_display(vo_driver_t *vo_driver, vo_frame_t *vo_frame) -{ - Emotion_Driver *dv; - Emotion_Frame *fr; - - dv = (Emotion_Driver *)vo_driver; - fr = (Emotion_Frame *)vo_frame; -// DBG("fq %i %p", dv->ev->fq, dv->ev); -// if my frame queue is too deep ( > 4 frames) simply block and wait for them -// to drain -// while (dv->ev->fq > 4) usleep(1); - if (dv->ev) - { - void *buf; - - if (dv->ev->closing) return; - if (fr->format == XINE_IMGFMT_YUY2) - { - _emotion_yuy2_to_bgra32(fr->width, fr->height, fr->vo_frame.base[0], fr->frame.bgra_data); - } - - buf = &(fr->frame); - fr->frame.timestamp = (double)fr->vo_frame.vpts / 90000.0; - fr->frame.done_func = (done_func_type)_emotion_frame_data_unlock; - fr->frame.done_data = fr; -// DBG("FRAME FOR %p", dv->ev); - if (write(dv->ev->fd_write, &buf, sizeof(void *)) < 0) perror("write"); -// DBG("-- FRAME DEC %p == %i", fr->frame.obj, ret); - fr->in_use = 1; - dv->ev->fq++; - } - /* hmm - must find a way to sanely copy data out... FIXME problem */ -// fr->vo_frame.free(&fr->vo_frame); -} - -static void -_emotion_frame_field(vo_frame_t *vo_frame EINA_UNUSED, int which_field EINA_UNUSED) -{ -// DBG(""); -} - -/***************************************************************************/ -static void -_emotion_frame_data_free(Emotion_Frame *fr) -{ - if (fr->vo_frame.base[0]) - { - free(fr->vo_frame.base[0]); - fr->vo_frame.base[0] = NULL; - fr->vo_frame.base[1] = NULL; - fr->vo_frame.base[2] = NULL; - fr->frame.y = fr->vo_frame.base[0]; - fr->frame.u = fr->vo_frame.base[1]; - fr->frame.v = fr->vo_frame.base[2]; - } - if (fr->frame.bgra_data) - { - free(fr->frame.bgra_data); - fr->frame.bgra_data = NULL; - } -} - -static void -_emotion_frame_data_unlock(Emotion_Frame *fr) -{ -// DBG(""); - if (fr->in_use) - { - fr->vo_frame.free(&fr->vo_frame); - fr->in_use = 0; - } -} - -/***************************************************************************/ -static void -_emotion_overlay_begin(vo_driver_t *vo_driver EINA_UNUSED, vo_frame_t *vo_frame EINA_UNUSED, int changed EINA_UNUSED) -{ -// DBG(""); -} - -static void -_emotion_overlay_end(vo_driver_t *vo_driver EINA_UNUSED, vo_frame_t *vo_frame EINA_UNUSED) -{ -// DBG(""); -} - -static void -_emotion_overlay_blend(vo_driver_t *vo_driver EINA_UNUSED, vo_frame_t *vo_frame, vo_overlay_t *vo_overlay EINA_UNUSED) -{ - Emotion_Frame *fr; - - fr = (Emotion_Frame *)vo_frame; -// DBG(""); - _emotion_overlay_blend_yuv(fr->vo_frame.base, vo_overlay, - fr->width, fr->height, - fr->vo_frame.pitches); -} - -static void _emotion_overlay_mem_blend_8(uint8_t *mem, uint8_t val, uint8_t o, size_t sz) -{ - uint8_t *limit = mem + sz; - while (mem < limit) - { - *mem = BLEND_BYTE(*mem, val, o); - mem++; - } -} - -static void _emotion_overlay_blend_yuv(uint8_t *dst_base[3], vo_overlay_t * img_overl, int dst_width, int dst_height, int dst_pitches[3]) -{ - Emotion_Lut *my_clut; - uint8_t *my_trans; - int src_width; - int src_height; - rle_elem_t *rle; - rle_elem_t *rle_limit; - int x_off; - int y_off; - int ymask, xmask; - int rle_this_bite; - int rle_remainder; - int rlelen; - int x, y; - int hili_right; - uint8_t clr = 0; - - src_width = img_overl->width; - src_height = img_overl->height; - rle = img_overl->rle; - rle_limit = rle + img_overl->num_rle; - x_off = img_overl->x; - y_off = img_overl->y; - - if (!rle) return; - - uint8_t *dst_y = dst_base[0] + dst_pitches[0] * y_off + x_off; - uint8_t *dst_cr = dst_base[2] + (y_off / 2) * dst_pitches[1] + (x_off / 2) + 1; - uint8_t *dst_cb = dst_base[1] + (y_off / 2) * dst_pitches[2] + (x_off / 2) + 1; - my_clut = (Emotion_Lut *) img_overl->hili_color; - my_trans = img_overl->hili_trans; - - /* avoid wraping overlay if drawing to small image */ - if( (x_off + img_overl->hili_right) < dst_width ) - hili_right = img_overl->hili_right; - else - hili_right = dst_width - 1 - x_off; - - /* avoid buffer overflow */ - if( (src_height + y_off) >= dst_height ) - src_height = dst_height - 1 - y_off; - - rlelen=rle_remainder=0; - for (y = 0; y < src_height; y++) - { - ymask = ((img_overl->hili_top > y) || (img_overl->hili_bottom < y)); - xmask = 0; - - for (x = 0; x < src_width;) - { - uint16_t o; - - if (rlelen == 0) - { - rle_remainder = rlelen = rle->len; - clr = rle->color; - rle++; - } - if (rle_remainder == 0) - { - rle_remainder = rlelen; - } - if ((rle_remainder + x) > src_width) - { - /* Do something for long rlelengths */ - rle_remainder = src_width - x; - } - - if (ymask == 0) - { - if (x <= img_overl->hili_left) - { - /* Starts outside clip area */ - if ((x + rle_remainder - 1) > img_overl->hili_left ) - { - /* Cutting needed, starts outside, ends inside */ - rle_this_bite = (img_overl->hili_left - x + 1); - rle_remainder -= rle_this_bite; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - else - { - /* no cutting needed, starts outside, ends outside */ - rle_this_bite = rle_remainder; - rle_remainder = 0; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - } - else if (x < hili_right) - { - /* Starts inside clip area */ - if ((x + rle_remainder) > hili_right ) - { - /* Cutting needed, starts inside, ends outside */ - rle_this_bite = (hili_right - x); - rle_remainder -= rle_this_bite; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->hili_color; - my_trans = img_overl->hili_trans; - xmask++; - } - else - { - /* no cutting needed, starts inside, ends inside */ - rle_this_bite = rle_remainder; - rle_remainder = 0; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->hili_color; - my_trans = img_overl->hili_trans; - xmask++; - } - } - else if (x >= hili_right) - { - /* Starts outside clip area, ends outsite clip area */ - if ((x + rle_remainder ) > src_width ) - { - /* Cutting needed, starts outside, ends at right edge */ - /* It should never reach here due to the earlier test of src_width */ - rle_this_bite = (src_width - x ); - rle_remainder -= rle_this_bite; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - else - { - /* no cutting needed, starts outside, ends outside */ - rle_this_bite = rle_remainder; - rle_remainder = 0; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - } - } - else - { - /* Outside clip are due to y */ - /* no cutting needed, starts outside, ends outside */ - rle_this_bite = rle_remainder; - rle_remainder = 0; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - o = my_trans[clr]; - if (o) - { - if (o >= 15) - { - memset(dst_y + x, my_clut[clr].y, rle_this_bite); - if (y & 1) - { - memset(dst_cr + (x >> 1), my_clut[clr].cr, (rle_this_bite+1) >> 1); - memset(dst_cb + (x >> 1), my_clut[clr].cb, (rle_this_bite+1) >> 1); - } - } - else - { - _emotion_overlay_mem_blend_8(dst_y + x, my_clut[clr].y, o, rle_this_bite); - if (y & 1) - { - /* Blending cr and cb should use a different function, with pre -128 to each sample */ - _emotion_overlay_mem_blend_8(dst_cr + (x >> 1), my_clut[clr].cr, o, (rle_this_bite+1) >> 1); - _emotion_overlay_mem_blend_8(dst_cb + (x >> 1), my_clut[clr].cb, o, (rle_this_bite+1) >> 1); - } - } - } - x += rle_this_bite; - if (rle >= rle_limit) - { - break; - } - } - if (rle >= rle_limit) - { - break; - } - - dst_y += dst_pitches[0]; - - if (y & 1) - { - dst_cr += dst_pitches[2]; - dst_cb += dst_pitches[1]; - } - } -} - -//TODO: Really need to improve this converter! -#define LIMIT(x) ((x) > 0xff ? 0xff : ((x) < 0 ? 0 : (x))) - -static void -_emotion_yuy2_to_bgra32(int width, int height, unsigned char *src, unsigned char *dst) -{ - int i, j; - unsigned char *y, *u, *v; - - y = src; - u = src + 1; - v = src + 3; - for (i = 0; i < width; i++) - { - for (j = 0; j < height; j++) - { - *dst++ = LIMIT(1.164 * (*y - 16) + 2.018 * (*u - 128)); - *dst++ = LIMIT(1.164 * (*y - 16) - 0.813 * (*v - 128) - 0.391 * (*u - 128)); - *dst++ = LIMIT(1.164 * (*y - 16) + 1.596 * (*v - 128)); - *dst++ = 0; - - y += 2; - if (j % 2 == 1) - { - u += 4; - v += 4; - } - } - } -} diff --git a/src/modules/emotion/xine/meson.build b/src/modules/emotion/xine/meson.build deleted file mode 100644 index 038d6d2eb1..0000000000 --- a/src/modules/emotion/xine/meson.build +++ /dev/null @@ -1,16 +0,0 @@ -generic_src = files([ - 'emotion_xine.h', - 'emotion_xine.c', - 'emotion_xine_vo_out.c', -]) - -generic_deps = dependency('libxine') - -shared_module(emotion_loader, - generic_src, - include_directories : config_dir, - dependencies: [eina, evas, emotion, generic_deps], - install: true, - install_dir : mod_install_dir, - c_args : package_c_args, -) From 4d0e3c37aa41863d7790a684315ee4f4df09b16a Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Sun, 8 Mar 2020 12:38:58 +0000 Subject: [PATCH 17/17] readme - adapt for removal of xine/vlc support --- README | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/README b/README index d94127bce0..ec3b27a737 100644 --- a/README +++ b/README @@ -328,15 +328,11 @@ runtime library being refactored to be extremely small. //BSD 2-Clause license// -This is a wrapper around Gstreamer and/or Xine and/or external -pluggable decoder binaries (generic binaries provided by Emotion -Generic Players or any suitable drop-in replacement). This glues in -the decoder library, and its output into a smart Evas object that will -display the playback for you as the video plays, as well as providing -higher level controls to seek, play, pause and query the stream -regardless of the back-end used. Note that using the Xine module may -effectively make this library GPL v2, so be aware of that before -turning that on. +This is a wrapper around Gstreamer 1.x pluggable decoder libraries +This glues in the decoder library, and its output into a smart Evas object +that will display the playback for you as the video plays, as well as +providing higher level controls to seek, play, pause and query the stream +regardless of the back-end used.