improve cnp to tell you when you lost a selection and track obj

deletions.



SVN revision: 72798
This commit is contained in:
Carsten Haitzler 2012-06-25 11:16:25 +00:00
parent cab76c1f57
commit af564b3dc7
3 changed files with 326 additions and 206 deletions

View File

@ -215,3 +215,10 @@
* Genlist: Fixed tree expand bug. Check item type when an item is requested * Genlist: Fixed tree expand bug. Check item type when an item is requested
to be expanded/contracted. to be expanded/contracted.
2012-06-25 Carsten Haitzler (The Rasterman)
* add elm_cnp_selection_loss_callback_set() so you know when you
lose a selection as a client
* improve robustness of cnp to track target object deletions.

View File

@ -42,7 +42,7 @@
#define ARRAYINIT(foo) [foo] = #define ARRAYINIT(foo) [foo] =
#define DEBUGON 1 //#define DEBUGON 1
#ifdef DEBUGON #ifdef DEBUGON
# define cnp_debug(x...) fprintf(stderr, __FILE__": " x) # define cnp_debug(x...) fprintf(stderr, __FILE__": " x)
@ -102,6 +102,8 @@ struct _Cnp_Selection
Eina_Bool (*set) (Ecore_X_Window, const void *data, int size); Eina_Bool (*set) (Ecore_X_Window, const void *data, int size);
Eina_Bool (*clear) (void); Eina_Bool (*clear) (void);
void (*request) (Ecore_X_Window, const char *target); void (*request) (Ecore_X_Window, const char *target);
Elm_Selection_Loss_Cb loss_cb;
void *loss_data;
Elm_Sel_Format format; Elm_Sel_Format format;
Ecore_X_Selection ecore_sel; Ecore_X_Selection ecore_sel;
@ -179,209 +181,209 @@ static int vcard_receive(Cnp_Selection *sed, Ecore_X_Event_Selection_Notify *not
static Eina_Bool pasteimage_append(char *file, Evas_Object *entry); static Eina_Bool pasteimage_append(char *file, Evas_Object *entry);
static Cnp_Atom atoms[CNP_N_ATOMS] = { static Cnp_Atom atoms[CNP_N_ATOMS] = {
[CNP_ATOM_TARGETS] = { [CNP_ATOM_TARGETS] = {
"TARGETS", "TARGETS",
ELM_SEL_FORMAT_TARGETS, ELM_SEL_FORMAT_TARGETS,
targets_converter, targets_converter,
response_handler_targets, response_handler_targets,
notify_handler_targets, notify_handler_targets,
0 0
}, },
[CNP_ATOM_ATOM] = { [CNP_ATOM_ATOM] = {
"ATOM", // for opera browser "ATOM", // for opera browser
ELM_SEL_FORMAT_TARGETS, ELM_SEL_FORMAT_TARGETS,
targets_converter, targets_converter,
response_handler_targets, response_handler_targets,
notify_handler_targets, notify_handler_targets,
0 0
}, },
[CNP_ATOM_XELM] = { [CNP_ATOM_XELM] = {
"application/x-elementary-markup", "application/x-elementary-markup",
ELM_SEL_FORMAT_MARKUP, ELM_SEL_FORMAT_MARKUP,
general_converter, general_converter,
NULL, NULL,
NULL, NULL,
0 0
}, },
[CNP_ATOM_text_uri] = { [CNP_ATOM_text_uri] = {
"text/uri", "text/uri",
ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE, /* Either images or entries */ ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE, /* Either images or entries */
general_converter, general_converter,
NULL, NULL,
notify_handler_uri, notify_handler_uri,
0 0
}, },
[CNP_ATOM_text_urilist] = { [CNP_ATOM_text_urilist] = {
"text/uri-list", "text/uri-list",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
general_converter, general_converter,
NULL, NULL,
notify_handler_uri, notify_handler_uri,
0 0
}, },
[CNP_ATOM_text_x_vcard] = { [CNP_ATOM_text_x_vcard] = {
"text/x-vcard", "text/x-vcard",
ELM_SEL_FORMAT_VCARD, ELM_SEL_FORMAT_VCARD,
vcard_send, NULL, vcard_send, NULL,
vcard_receive, 0 vcard_receive, 0
}, },
[CNP_ATOM_image_png] = { [CNP_ATOM_image_png] = {
"image/png", "image/png",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image, notify_handler_image,
0 0
}, },
[CNP_ATOM_image_jpeg] = { [CNP_ATOM_image_jpeg] = {
"image/jpeg", "image/jpeg",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image,/* Raw image data is the same */ notify_handler_image,/* Raw image data is the same */
0 0
}, },
[CNP_ATOM_image_bmp] = { [CNP_ATOM_image_bmp] = {
"image/x-ms-bmp", "image/x-ms-bmp",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image,/* Raw image data is the same */ notify_handler_image,/* Raw image data is the same */
0 0
}, },
[CNP_ATOM_image_gif] = { [CNP_ATOM_image_gif] = {
"image/gif", "image/gif",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image,/* Raw image data is the same */ notify_handler_image,/* Raw image data is the same */
0 0
}, },
[CNP_ATOM_image_tiff] = { [CNP_ATOM_image_tiff] = {
"image/tiff", "image/tiff",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image,/* Raw image data is the same */ notify_handler_image,/* Raw image data is the same */
0 0
}, },
[CNP_ATOM_image_svg] = { [CNP_ATOM_image_svg] = {
"image/svg+xml", "image/svg+xml",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image,/* Raw image data is the same */ notify_handler_image,/* Raw image data is the same */
0 0
}, },
[CNP_ATOM_image_xpm] = { [CNP_ATOM_image_xpm] = {
"image/x-xpixmap", "image/x-xpixmap",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image,/* Raw image data is the same */ notify_handler_image,/* Raw image data is the same */
0 0
}, },
[CNP_ATOM_image_tga] = { [CNP_ATOM_image_tga] = {
"image/x-tga", "image/x-tga",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image,/* Raw image data is the same */ notify_handler_image,/* Raw image data is the same */
0 0
}, },
[CNP_ATOM_image_ppm] = { [CNP_ATOM_image_ppm] = {
"image/x-portable-pixmap", "image/x-portable-pixmap",
ELM_SEL_FORMAT_IMAGE, ELM_SEL_FORMAT_IMAGE,
image_converter, image_converter,
NULL, NULL,
notify_handler_image,/* Raw image data is the same */ notify_handler_image,/* Raw image data is the same */
0 0
}, },
[CNP_ATOM_text_html_utf8] = { [CNP_ATOM_text_html_utf8] = {
"text/html;charset=utf-8", "text/html;charset=utf-8",
ELM_SEL_FORMAT_HTML, ELM_SEL_FORMAT_HTML,
general_converter, general_converter,
NULL, NULL,
notify_handler_html, notify_handler_html,
0 0
}, },
[CNP_ATOM_text_html] = { [CNP_ATOM_text_html] = {
"text/html", "text/html",
ELM_SEL_FORMAT_HTML, ELM_SEL_FORMAT_HTML,
general_converter, general_converter,
NULL, NULL,
notify_handler_html, /* No encoding: Webkit only */ notify_handler_html, /* No encoding: Webkit only */
0 0
}, },
[CNP_ATOM_UTF8STRING] = { [CNP_ATOM_UTF8STRING] = {
"UTF8_STRING", "UTF8_STRING",
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML, ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
text_converter, text_converter,
NULL, NULL,
notify_handler_text, notify_handler_text,
0 0
}, },
[CNP_ATOM_STRING] = { [CNP_ATOM_STRING] = {
"STRING", "STRING",
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML, ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
text_converter, text_converter,
NULL, NULL,
notify_handler_text, notify_handler_text,
0 0
}, },
[CNP_ATOM_TEXT] = { [CNP_ATOM_TEXT] = {
"TEXT", "TEXT",
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML, ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
text_converter, text_converter,
NULL, NULL,
NULL, NULL,
0 0
}, },
[CNP_ATOM_text_plain_utf8] = { [CNP_ATOM_text_plain_utf8] = {
"text/plain;charset=utf-8", "text/plain;charset=utf-8",
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML, ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
text_converter, text_converter,
NULL, NULL,
NULL, NULL,
0 0
}, },
[CNP_ATOM_text_plain] = { [CNP_ATOM_text_plain] = {
"text/plain", "text/plain",
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML, ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
text_converter, text_converter,
NULL, NULL,
NULL, NULL,
0 0
}, },
}; };
static Cnp_Selection selections[ELM_SEL_TYPE_CLIPBOARD + 1] = { static Cnp_Selection selections[ELM_SEL_TYPE_CLIPBOARD + 1] = {
ARRAYINIT(ELM_SEL_TYPE_PRIMARY) { ARRAYINIT(ELM_SEL_TYPE_PRIMARY) {
.debug = "Primary", .debug = "Primary",
.ecore_sel = ECORE_X_SELECTION_PRIMARY, .ecore_sel = ECORE_X_SELECTION_PRIMARY,
.set = ecore_x_selection_primary_set, .set = ecore_x_selection_primary_set,
.clear = ecore_x_selection_primary_clear, .clear = ecore_x_selection_primary_clear,
.request = ecore_x_selection_primary_request, .request = ecore_x_selection_primary_request,
}, },
ARRAYINIT(ELM_SEL_TYPE_SECONDARY) { ARRAYINIT(ELM_SEL_TYPE_SECONDARY) {
.debug = "Secondary", .debug = "Secondary",
.ecore_sel = ECORE_X_SELECTION_SECONDARY, .ecore_sel = ECORE_X_SELECTION_SECONDARY,
.set = ecore_x_selection_secondary_set, .set = ecore_x_selection_secondary_set,
.clear = ecore_x_selection_secondary_clear, .clear = ecore_x_selection_secondary_clear,
.request = ecore_x_selection_secondary_request, .request = ecore_x_selection_secondary_request,
}, },
ARRAYINIT(ELM_SEL_TYPE_XDND) { ARRAYINIT(ELM_SEL_TYPE_XDND) {
.debug = "XDnD", .debug = "XDnD",
.ecore_sel = ECORE_X_SELECTION_XDND, .ecore_sel = ECORE_X_SELECTION_XDND,
.request = ecore_x_selection_xdnd_request, .request = ecore_x_selection_xdnd_request,
}, },
ARRAYINIT(ELM_SEL_TYPE_CLIPBOARD) { ARRAYINIT(ELM_SEL_TYPE_CLIPBOARD) {
.debug = "Clipboard", .debug = "Clipboard",
.ecore_sel = ECORE_X_SELECTION_CLIPBOARD, .ecore_sel = ECORE_X_SELECTION_CLIPBOARD,
.set = ecore_x_selection_clipboard_set, .set = ecore_x_selection_clipboard_set,
.clear = ecore_x_selection_clipboard_clear, .clear = ecore_x_selection_clipboard_clear,
.request = ecore_x_selection_clipboard_request, .request = ecore_x_selection_clipboard_request,
}, },
}; };
/* Data for DND in progress */ /* Data for DND in progress */
@ -427,12 +429,12 @@ _elm_widget_xwin_get(const Evas_Object *obj)
{ {
Evas_Object *top; Evas_Object *top;
Ecore_X_Window xwin = 0; Ecore_X_Window xwin = 0;
top = elm_widget_top_get(obj); top = elm_widget_top_get(obj);
if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj)); if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj));
if (top) xwin = elm_win_xwindow_get(top); if (top) xwin = elm_win_xwindow_get(top);
if (!xwin) if (!xwin)
{ {
Ecore_Evas *ee; Ecore_Evas *ee;
@ -447,6 +449,22 @@ _elm_widget_xwin_get(const Evas_Object *obj)
} }
#endif #endif
#ifdef HAVE_ELEMENTARY_X
static void
_sel_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
{
Cnp_Selection *sel = data;
if (sel->widget == obj) sel->widget = NULL;
}
static void
_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
{
Cnp_Selection *sel = data;
if (sel->requestwidget == obj) sel->requestwidget = NULL;
}
#endif
EAPI Eina_Bool EAPI Eina_Bool
elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
Elm_Sel_Format format, const void *selbuf, size_t buflen) Elm_Sel_Format format, const void *selbuf, size_t buflen)
@ -454,7 +472,7 @@ elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
#ifdef HAVE_ELEMENTARY_X #ifdef HAVE_ELEMENTARY_X
Ecore_X_Window xwin = _elm_widget_xwin_get(obj); Ecore_X_Window xwin = _elm_widget_xwin_get(obj);
Cnp_Selection *sel; Cnp_Selection *sel;
if ((!xwin) || (selection > ELM_SEL_TYPE_CLIPBOARD)) if ((!xwin) || (selection > ELM_SEL_TYPE_CLIPBOARD))
return EINA_FALSE; return EINA_FALSE;
if (!_elm_cnp_init_count) _elm_cnp_init(); if (!_elm_cnp_init_count) _elm_cnp_init();
@ -463,12 +481,24 @@ elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
sel = selections + selection; sel = selections + selection;
if (sel->loss_cb) sel->loss_cb(sel->loss_data, selection);
if (sel->widget)
evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
_sel_obj_del, sel);
sel->widget = NULL;
sel->active = EINA_TRUE; sel->active = EINA_TRUE;
sel->widget = obj; sel->widget = obj;
sel->xwin = xwin; sel->xwin = xwin;
sel->set(xwin, &selection, sizeof(Elm_Sel_Type)); sel->set(xwin, &selection, sizeof(Elm_Sel_Type));
sel->format = format; sel->format = format;
sel->loss_cb = NULL;
sel->loss_data = NULL;
evas_object_event_callback_add
(sel->widget, EVAS_CALLBACK_DEL, _sel_obj_del, sel);
if (selbuf) if (selbuf)
{ {
if (format == ELM_SEL_FORMAT_IMAGE) if (format == ELM_SEL_FORMAT_IMAGE)
@ -494,6 +524,19 @@ elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
#endif #endif
} }
EAPI void
elm_cnp_selection_loss_callback_set(Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data)
{
#ifdef HAVE_ELEMENTARY_X
Cnp_Selection *sel;
if (selection > ELM_SEL_TYPE_CLIPBOARD) return;
sel = selections + selection;
sel->loss_cb = func;
sel->loss_data = (void *)data;
#endif
}
EAPI Eina_Bool EAPI Eina_Bool
elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection) elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
{ {
@ -509,8 +552,18 @@ elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
/* No longer this selection: Consider it gone! */ /* No longer this selection: Consider it gone! */
if ((!sel->active) || (sel->widget != obj)) return EINA_TRUE; if ((!sel->active) || (sel->widget != obj)) return EINA_TRUE;
sel->active = EINA_FALSE; if (sel->widget)
evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
_sel_obj_del, sel);
if (sel->requestwidget)
evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
_sel_obj_del2, sel);
sel->widget = NULL; sel->widget = NULL;
sel->requestwidget = NULL;
sel->loss_cb = NULL;
sel->loss_data = NULL;
sel->active = EINA_FALSE;
if (sel->selbuf) if (sel->selbuf)
{ {
free(sel->selbuf); free(sel->selbuf);
@ -539,6 +592,11 @@ elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
sel = selections + selection; sel = selections + selection;
if (!xwin) return EINA_FALSE; if (!xwin) return EINA_FALSE;
if (sel->requestwidget)
evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
_sel_obj_del2, sel);
sel->requestwidget = NULL;
sel->requestformat = format; sel->requestformat = format;
sel->requestwidget = obj; sel->requestwidget = obj;
sel->xwin = xwin; sel->xwin = xwin;
@ -546,6 +604,9 @@ elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
sel->datacb = datacb; sel->datacb = datacb;
sel->udata = udata; sel->udata = udata;
evas_object_event_callback_add
(sel->requestwidget, EVAS_CALLBACK_DEL, _sel_obj_del2, sel);
return EINA_TRUE; return EINA_TRUE;
#else #else
return EINA_FALSE; return EINA_FALSE;
@ -590,6 +651,18 @@ selection_clear(void *udata __UNUSED__, int type __UNUSED__, void *event)
if (i > ELM_SEL_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON; if (i > ELM_SEL_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON;
sel = selections + i; sel = selections + i;
if (sel->loss_cb) sel->loss_cb(sel->loss_data, i);
if (sel->widget)
evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
_sel_obj_del, sel);
if (sel->requestwidget)
evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
_sel_obj_del2, sel);
sel->widget = NULL;
sel->requestwidget = NULL;
sel->active = EINA_FALSE; sel->active = EINA_FALSE;
sel->widget = NULL; sel->widget = NULL;
if (sel->selbuf) if (sel->selbuf)

View File

@ -97,6 +97,15 @@ typedef struct _Elm_Selection_Data Elm_Selection_Data;
*/ */
typedef Eina_Bool (*Elm_Drop_Cb)(void *data, Evas_Object *obj, Elm_Selection_Data *ev); typedef Eina_Bool (*Elm_Drop_Cb)(void *data, Evas_Object *obj, Elm_Selection_Data *ev);
/**
* Callback invoked in when the selection ownership for a given selection is lost.
*
* @param data Application specific data
* @param selection The selection that is lost
* @since 1.1
*/
typedef void (*Elm_Selection_Loss_Cb)(void *data, Elm_Sel_Type selection);
/** /**
* @brief Set copy data for a widget. * @brief Set copy data for a widget.
@ -158,6 +167,37 @@ EAPI Eina_Bool elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
EAPI Eina_Bool elm_object_cnp_selection_clear(Evas_Object *obj, EAPI Eina_Bool elm_object_cnp_selection_clear(Evas_Object *obj,
Elm_Sel_Type selection); Elm_Sel_Type selection);
/**
* @brief Set a function to be called when a selection is lost
*
* The function @p func is set of be called when selection @p selection is lost
* to another process or when elm_cnp_selection_set() is called. If @p func
* is NULL then it is not called. @p data is passed as the data parameter to
* the callback functions and selection is passed in as the selection that
* has been lost.
*
* elm_cnp_selection_set() and elm_object_cnp_selection_clear() automatically
* set this los callback to NULL when called. If you wish to take the selection
* and then be notified of loss please do this (for example):
*
* @code
* elm_cnp_selection_set(obj, ELM_SEL_TYPE_PRIMARY, ELM_SEL_FORMAT_TEXT, "hello", strlen(hello));
* elm_cnp_selection_loss_callback_set(ELM_SEL_TYPE_PRIMARY, loss_cb, NULL);
* @endcode
*
* @see also elm_cnp_selection_set()
*
* @param selection Selection to be notified of for loss
* @param func The function to call
* @param data The data pointer passed to the function.
*
* @ingroup CopyPaste
*
* @since 1.1
*/
EAPI void elm_cnp_selection_loss_callback_set(Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data);
/** /**
* @} * @}
*/ */