summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2020-01-05 15:05:36 +0100
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2020-03-08 10:59:25 +0100
commit39f3ce42dcde447779cb1583501b681ba85d86d4 (patch)
tree4bb1c113250dbabbcd8ee6405c34c8539bf53004
parent40a62ddf94f590b2e79caf63eb399d9bc257b216 (diff)
downloadefl-39f3ce42dcde447779cb1583501b681ba85d86d4.tar.gz
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 <michael.blumenkrantz@gmail.com> Differential Revision: https://phab.enlightenment.org/D11192
-rw-r--r--src/lib/ecore_evas/Ecore_Evas.h214
-rw-r--r--src/lib/ecore_evas/ecore_evas.c362
-rw-r--r--src/lib/ecore_evas/ecore_evas_fallback_selection.c115
-rw-r--r--src/lib/ecore_evas/ecore_evas_private.h53
-rw-r--r--src/lib/ecore_evas/meson.build3
-rw-r--r--src/lib/elementary/meson.build2
-rw-r--r--src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c3
-rw-r--r--src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c7
-rw-r--r--src/modules/ecore_evas/engines/win32/ecore_evas_win32.c3
-rw-r--r--src/modules/ecore_evas/engines/x/ecore_evas_x.c73
-rw-r--r--src/tests/ecore/ecore_suite.c1
-rw-r--r--src/tests/ecore/ecore_suite.h1
-rw-r--r--src/tests/ecore/ecore_test_ecore_evas.c44
-rw-r--r--src/tests/ecore/ecore_test_ecore_evas_selection.c89
-rw-r--r--src/tests/ecore/meson.build1
-rw-r--r--src/tests/elementary/efl_ui_window_cnp_dnd_slave.c191
-rw-r--r--src/tests/elementary/meson.build5
17 files changed, 1120 insertions, 47 deletions
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 <config.h>
+#endif
+
+#include <Ecore.h>
+#include "ecore_private.h"
+#include "Ecore_Evas.h"
+#include "ecore_evas_private.h"
+#include <Efl_Core.h>
+
+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 <Ecore_Evas.h>
+#include <Efl_Core.h>
#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 <config.h>
+#endif
+
+#include <Ecore_Evas.h>
+#include <Efl_Core.h>
+
+#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 <Efl.h>
+#include <Efl_Ui.h>
+#include <Elementary.h>
+#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
)