Compare commits

...

14 Commits

Author SHA1 Message Date
Xavi Artigas 54b2ddd88e ecore_evas: Use EFL naming convention in cnp & dnd methods
Some methods were missing the Drag namespace or the _Cb suffix.
Depends on D11219

Differential Revision: https://phab.enlightenment.org/D11426
2020-03-04 17:26:30 +01:00
Xavi Artigas 8cdc8e9c8f mono-tests: Fix build after DnD changes
The test struct used to check mono bindings struct pack/unpack
is no longer available. Used a different one, and checked the same things.

Differential Revision: https://phab.enlightenment.org/D11219
2020-03-04 17:26:30 +01:00
Xavi Artigas c78841efcf docs: Strengthen docs for Copy&Paste and Drag&Drop
Including Eina.Content

And a typo/bugfix in ecore_evas_x.

Differential Revision: https://phab.enlightenment.org/D11204
2020-03-04 17:26:30 +01:00
Vincent Torri 9abd2604fa 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
2020-03-04 17:26:30 +01:00
Marcel Hollerbach 61075d45cc 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.

Differential Revision: https://phab.enlightenment.org/D11351
2020-03-04 17:26:30 +01:00
Marcel Hollerbach 072a5fa525 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

Differential Revision: https://phab.enlightenment.org/D11350
2020-03-04 17:26:30 +01:00
Marcel Hollerbach 87901ea2ff 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

Differential Revision: https://phab.enlightenment.org/D11190
2020-03-04 17:26:30 +01:00
Marcel Hollerbach 447fecd32e 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.

Differential Revision: https://phab.enlightenment.org/D11329
2020-03-04 17:26:30 +01:00
Marcel Hollerbach c391870366 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.

Differential Revision: https://phab.enlightenment.org/D11195
2020-03-04 17:26:30 +01:00
Marcel Hollerbach 2951c69c49 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

Differential Revision: https://phab.enlightenment.org/D11194
2020-03-04 17:26:29 +01:00
Marcel Hollerbach 6b337ed19b 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.

Differential Revision: https://phab.enlightenment.org/D11193
2020-03-04 17:26:29 +01:00
Marcel Hollerbach ce070a8fdf 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)

Differential Revision: https://phab.enlightenment.org/D11192
2020-03-04 17:26:29 +01:00
Marcel Hollerbach ff4cba32c3 eina: introduce Eina_Abstract_Content
A little abstraction to have abstract data content bound to a type.

Differential Revision: https://phab.enlightenment.org/D11018
2020-03-04 17:26:29 +01:00
Marcel Hollerbach c872940bae elm_label: add EFL_ACCESS_WIDGET_ACTION_MIXIN
we implement the API from it, so we should have that as a type here.

Differential Revision: https://phab.enlightenment.org/D11447
2020-03-04 15:05:08 +01:00
62 changed files with 5707 additions and 7714 deletions

View File

@ -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

View File

@ -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)
@ -112,7 +114,7 @@ ecore_cocoa_clipboard_get(int *size,
NSString *str = [items objectAtIndex: 0];
data = (void *)[str UTF8String];
len = [str lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
data = eina_strndup((const char *)data, len);
data = strndup((const char *)data, len);
if (EINA_UNLIKELY(!data))
{
@ -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;
}

View File

@ -3669,6 +3669,216 @@ 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.
*
* @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_Cb)(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_Cb 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_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
* 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_Drag_State_Changed_Cb 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_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.
*
* @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_Drag_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);
/**
* @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_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
* 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 +3895,4 @@ EAPI int ecore_evas_pixmap_depth_get(const Ecore_Evas *ee);
#define EAPI
#endif

View File

@ -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_Cb 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_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_Drag_State_Changed_Cb 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;
}

View File

@ -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;
}

View File

@ -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_Cb 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);

View File

@ -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'
]

View File

@ -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

View File

@ -6,6 +6,7 @@
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#include <evil_private.h> /* utf-8 and utf-16 conversion */
#include <Eina.h>
#include "Ecore_Win32.h"
@ -39,10 +40,12 @@
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 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 +57,78 @@ ecore_win32_clipboard_set(const Ecore_Win32_Window *window,
INF("setting data to the clipboard");
if (!window || !data || (size <= 0))
return EINA_FALSE;
if (!eina_str_has_prefix(mime_type, "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 (eina_str_has_prefix(mime_type, "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);
GlobalUnlock(global);
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);
free(text16);
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,93 @@ ecore_win32_clipboard_get(const Ecore_Win32_Window *window,
INF("getting data from the clipboard");
if (!window)
return EINA_FALSE;
if (!IsClipboardFormatAvailable(CF_TEXT))
return EINA_FALSE;
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 (!eina_str_has_prefix(mime_type, "text/"))
{
ERR("Mimetype %s is not handled yet", mime_type);
return NULL;
}
if (!window || !OpenClipboard(window->window))
return NULL;
#if 0
{
UINT fmt = 0;
while (1)
{
fmt = EnumClipboardFormats(fmt);
fprintf(stderr, " $ Format : %x\n", fmt);
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;
}
}
/* otherwise, we unlock global and try CF_TEXT (UTF-8/ANSI) */
GlobalUnlock(global);
}
/* secondly 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;
}
/**

View File

@ -1958,66 +1958,104 @@ _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,
* so text data has just been removed
*/
if (!IsClipboardFormatAvailable(CF_TEXT) && _ecore_win32_clipboard_has_data)
if (_ecore_win32_clipboard_has_data)
{
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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -272,6 +272,7 @@ extern "C" {
#include <eina_debug.h>
#include <eina_promise.h>
#include <eina_vpath.h>
#include <eina_abstract_content.h>
#undef EAPI
#define EAPI

View File

@ -0,0 +1,443 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <Eina.h>
#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;
}

View File

@ -0,0 +1,154 @@
#ifndef EINA_ABSTRACT_CONTENT_H
#define EINA_ABSTRACT_CONTENT_H
/**
* @typedef 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
*
* @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_Conversion_Callback
*
* 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.
*/
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 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.
*
* @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 Eina_Slice of the passed content.
*
* @param[in] content The content to fetch the data from.
*
* @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 provided data and type.
*
* @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.
*/
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 type to convert from.
* @param[in] to The type to convert to.
*
* @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 conversion can be performed.
*
* A conversion can only be performed if a callback is registered.
*
* @param[in] from The type to convert from.
* @param[in] to The type to convert to.
*
* @return True if the conversion can be performed.
*/
EAPI Eina_Bool eina_content_converter_convert_can(const char *from, const char *to);
/**
* Returns an iterator containing all the target types that the provided source type can be converted to.
*
* @param[in] from The type to convert from.
*
* @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 an Eina_Value.
*
* @param[in] content The Eina_Content struct that will be converted to an Eina_Value.
*
* @return An newly-allocated Eina_Value. Caller owns it.
*/
EAPI Eina_Value* eina_value_content_new(Eina_Content *content);
/**
* Creates an Eina_Value from an Eina_Content.
*
* @param[in] content The Eina_Content struct that will be converted to an Eina_Value.
*
* @return An Eina_Value with type EINA_VALUE_TYPE_CONTENT.
*/
EAPI Eina_Value eina_value_content_init(Eina_Content *content);
/**
* Gets the content from the Eina_Value.
*
* 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 newly-allocated Eina_Content. Caller owns 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

View File

@ -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) /

View File

@ -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

View File

@ -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

View File

@ -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 <efl_ui_widget_focus_manager.eo.h>
# include <efl_ui_selection.eo.h>
# include <efl_ui_dnd.eo.h>
# include <efl_ui_dnd_container.eo.h>
# include <efl_ui_timepicker.eo.h>
# include <efl_ui_datepicker.eo.h>

View File

@ -12,838 +12,140 @@
#include <Elementary_Cursor.h>
#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"

View File

@ -1,63 +1,93 @@
import efl_ui_dnd_types;
import eina_types;
mixin @beta Efl.Ui.Dnd {
data: null;
struct @beta Efl.Ui.Drop_Event {
[[Information sent along 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<string>; [[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 {
[[Information sent along 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 {
[[Information sent along @Efl.Ui.Drag_Started_Event events.]]
seat : uint; [[Which seat triggered the event.]]
}
struct @beta Efl.Ui.Drag_Finished_Event {
[[Information sent along @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 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
[[Starts a drag from this client.
@[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 {
@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]]
@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; [[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_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 {
[[Retrieves the dropped data.]]
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.]]
@in seat: uint; [[Seat that started the drag operation. When in doubt use 0.]]
@in acceptable_types : iterator<string>; [[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<Eina.Content> @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 {
/* 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; [[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;
Efl.Object.invalidate;
Efl.Object.finalize;
}
}

View File

@ -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.]]
}
}
}
}

View File

@ -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<Efl.Canvas.Object>;
};
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)]]
}

View File

@ -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"

View File

@ -1,45 +1,85 @@
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<void>; [[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 {
[[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 {
[[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 {
[[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; [[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 {
[[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; [[System buffer to clear.]]
seat : uint; [[Seat to clear. Use 0 when in doubt.]]
}
}
selection_get {
[[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; [[System buffer to use.]]
seat : uint; [[Seat where the data should be pasted. Use 0 when in doubt.]]
acceptable_types : iterator<string>; [[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<Eina.Content> @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 {
[[Checks if the specified system buffer has content.]]
params {
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 data available in the requested buffer.]]
}
}
implements {
Efl.Object.constructor;
Efl.Object.invalidate;
Efl.Object.finalize;
}
events {
wm_selection,changed : Efl.Ui.Wm_Selection_Changed; [[Event emitted when the content of one of the system's
buffers changes.]]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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<void>; [[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;
}
}

View File

@ -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]]
}

View File

@ -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));

View File

@ -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, "<item absize=240x180 href=");
eina_strbuf_append_slice(result, slice);
eina_strbuf_append_printf(result, "></item>");
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);
}

View File

@ -1,3 +1,15 @@
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,
Efl.Access.Text, Efl.Access.Editable.Text
composites
@ -31,20 +43,17 @@ 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! */
[[Control pasting of text and images for the widget.
@property cnp_dnd_mode @beta {
[[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 {
format: Efl.Ui.Selection_Format; [[Format for copy & paste.]]
allowed_formats : Efl.Ui.Textbox_Cnp_Content; [[Allowed content types.]]
}
}
@property selection_handles_enabled {

View File

@ -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)
@ -5930,6 +5935,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;
}
@ -5965,6 +5971,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);
@ -5981,6 +5989,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))
@ -9184,6 +9193,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)

View File

@ -0,0 +1,244 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include <Ecore_Evas.h>
#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;
}

View File

@ -43,8 +43,6 @@
* @{
*/
# include <efl_ui_selection_types.eot.h>
/**
* Event notifying that the selection has changed
* @see Elm_Cnp_Event_Selection_Changed

View File

@ -0,0 +1,812 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#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;
}

View File

@ -708,7 +708,7 @@ _selection_data_cb(void *data EINA_UNUSED,
char *entry_tag;
int len;
static const char *tag_string =
"<item absize=240x180 href=file://%s></item>";
"<item absize=240x180 href=%s></item>";
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 */

View File

@ -216,6 +216,6 @@ static const Efl_Class_Description _elm_label_class_desc = {
NULL
};
EFL_DEFINE_CLASS(elm_label_class_get, &_elm_label_class_desc, EFL_UI_LAYOUT_BASE_CLASS, ELM_LAYOUT_MIXIN, EFL_UI_LEGACY_INTERFACE, NULL);
EFL_DEFINE_CLASS(elm_label_class_get, &_elm_label_class_desc, EFL_UI_LAYOUT_BASE_CLASS, ELM_LAYOUT_MIXIN, EFL_UI_LEGACY_INTERFACE, EFL_ACCESS_WIDGET_ACTION_MIXIN, NULL);
#include "elm_label_eo.legacy.c"

View File

@ -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();
}

View File

@ -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

View File

@ -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',
@ -947,7 +944,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]

View File

@ -60,6 +60,17 @@ struct @extern Eina.Matrix3 {
zz: double; [[ZZ value.]]
}
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.

View File

@ -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:

View File

@ -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();

View File

@ -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*

View File

@ -4,6 +4,7 @@
#include "ecore_evas_wayland_private.h"
#include <Evas_Engine_Wayland.h>
#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
@ -881,14 +883,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);
}
}
@ -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,6 +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
_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
@ -2650,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);

View File

@ -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;

View File

@ -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,93 +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_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 */

File diff suppressed because it is too large Load Diff

View File

@ -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 }
};

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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'
]

View File

@ -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
}

View File

@ -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 }
};

View File

@ -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_ */

View File

@ -0,0 +1,223 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <Eina.h>
#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);
}

View File

@ -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',
)

View File

@ -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");

View File

@ -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()

View File

@ -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
)