Fix elementary copy/paste for wayland. Rework copy/paste code in elm.

This is part of a larger copy/paste fix for efl/elm wayland.
Previously, copy/paste would not work via keyboard shortcuts. This
series of changes fixes that issue (wrt elm_entry anyway).

This also adds addtional copy/paste support (wrt efl wayland),
including support for various mime types (text/plain, elm-markup, and
html).

Signed-off-by: Chris Michael <cp.michael@samsung.com>
This commit is contained in:
Chris Michael 2013-11-07 11:57:14 +00:00
parent f9edf8901d
commit b4925b0db0
1 changed files with 255 additions and 34 deletions

View File

@ -2147,11 +2147,31 @@ struct _Wl_Cnp_Selection
Evas_Object *widget;
Evas_Object *requestwidget;
void *udata;
Elm_Sel_Type seltype;
Elm_Sel_Format requestformat;
Elm_Drop_Cb datacb;
Elm_Selection_Loss_Cb loss_cb;
void *loss_data;
Elm_Sel_Format format;
Ecore_Wl_Window *win;
Elm_Xdnd_Action action;
Eina_Bool active : 1;
};
static Eina_Bool _wl_elm_cnp_init(void);
static Wl_Cnp_Selection wl_cnp_selection = {0, 0, NULL, NULL};
static Wl_Cnp_Selection wl_cnp_selection =
{
0, 0, NULL, NULL,
NULL, 0, 0, NULL, NULL, NULL,
0, NULL, 0, EINA_FALSE
};
static void _wl_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
static Eina_Bool _wl_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, const void *selbuf, size_t buflen);
static Eina_Bool _wl_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb __UNUSED__, void *udata __UNUSED__);
@ -2187,6 +2207,14 @@ static void _wl_dropable_all_set(unsigned int win, Evas_Coord x, Evas_Coord y, E
static Eina_Bool _wl_drops_accept(const char *type);
static unsigned int _wl_elm_widget_window_get(Evas_Object *obj);
static void
_wl_sel_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
{
Wl_Cnp_Selection *sel = data;
if (sel->widget == obj) sel->widget = NULL;
if (dragwidget == obj) dragwidget = NULL;
}
static void
_wl_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
{
@ -2195,59 +2223,187 @@ _wl_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_i
}
static Eina_Bool
_wl_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, const void *selbuf, size_t buflen)
_wl_elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, const void *selbuf, size_t buflen)
{
const char *types[10] = {0, };
Ecore_Wl_Window *win;
Wl_Cnp_Selection *sel = &wl_cnp_selection;
if ((!selbuf) && (format != ELM_SEL_FORMAT_IMAGE))
return elm_object_cnp_selection_clear(obj, selection);
_wl_elm_cnp_init();
/* TODO: other EML_SEL_TYPE and ELM_SEL_FORMAT */
if (ELM_SEL_TYPE_CLIPBOARD == selection)
{
types[0] = "text/plain;charset=utf-8";
ecore_wl_dnd_selection_set(ecore_wl_input_get(), types);
win = elm_win_wl_window_get(obj);
if (wl_cnp_selection.selbuf) free(wl_cnp_selection.selbuf);
wl_cnp_selection.selbuf = strdup((char*)selbuf);
wl_cnp_selection.buflen = buflen;
return EINA_TRUE;
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,
_wl_sel_obj_del, &wl_cnp_selection);
sel->widget = NULL;
sel->active = EINA_TRUE;
sel->seltype = selection;
sel->widget = obj;
sel->win = win;
/* sel->set(win, &selection, sizeof(Elm_Sel_Type)); */
sel->format = format;
sel->loss_cb = NULL;
sel->loss_data = NULL;
evas_object_event_callback_add
(sel->widget, EVAS_CALLBACK_DEL, _wl_sel_obj_del,
&wl_cnp_selection);
if (selbuf)
{
if (format & ELM_SEL_FORMAT_IMAGE)
{
/* FIXME */
// selbuf is actual image data, not text/string
sel->selbuf = malloc(buflen + 1);
if (!sel->selbuf)
{
elm_object_cnp_selection_clear(obj, selection);
return EINA_FALSE;
}
memcpy(sel->selbuf, selbuf, buflen);
sel->selbuf[buflen] = 0;
}
else
{
const char *types[10] = {0, };
int i = -1;
if (format & ELM_SEL_FORMAT_TEXT)
{
types[++i] = "text/plain";
types[++i] = "text/plain;charset=utf-8";
}
if (format & ELM_SEL_FORMAT_MARKUP)
types[++i] = "application/x-elementary-markup";
if (format & ELM_SEL_FORMAT_HTML)
{
types[++i] = "text/html";
types[++i] = "text/html;charset=utf-8";
}
if (i < 0) return EINA_FALSE;
ecore_wl_dnd_selection_set(ecore_wl_input_get(), types);
if (sel->selbuf) free(sel->selbuf);
sel->buflen = buflen;
sel->selbuf = strdup((char*)selbuf);
return EINA_TRUE;
}
}
else
sel->selbuf = NULL;
return EINA_FALSE;
}
static Eina_Bool
_wl_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb __UNUSED__, void *udata __UNUSED__)
_wl_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
{
Ecore_Wl_Window *win;
Wl_Cnp_Selection *sel = &wl_cnp_selection;
_wl_elm_cnp_init();
/* For now, just avoid overlapped request */
if (wl_cnp_selection.requestwidget) return EINA_FALSE;
win = elm_win_wl_window_get(obj);
/* TODO: other EML_SEL_TYPE and ELM_SEL_FORMAT */
if (ELM_SEL_TYPE_CLIPBOARD == selection)
if (sel->requestwidget)
evas_object_event_callback_del_full(sel->requestwidget,
EVAS_CALLBACK_DEL,
_wl_sel_obj_del2, &wl_cnp_selection);
sel->requestwidget = NULL;
sel->requestformat = format;
sel->requestwidget = obj;
sel->win = win;
/* sel->request(win, ECORE_X_SELECTION_TARGET_TARGETS); */
sel->datacb = datacb;
sel->udata = udata;
evas_object_event_callback_add(sel->requestwidget,
EVAS_CALLBACK_DEL, _wl_sel_obj_del2,
&wl_cnp_selection);
if (selection == ELM_SEL_TYPE_CLIPBOARD)
{
wl_cnp_selection.requestwidget = obj;
evas_object_event_callback_add(wl_cnp_selection.requestwidget, EVAS_CALLBACK_DEL,
_wl_sel_obj_del2, &wl_cnp_selection);
ecore_wl_dnd_selection_get(ecore_wl_input_get(),
"text/plain;charset=utf-8");
const char *types[10] = {0, };
int i = -1;
if (format & ELM_SEL_FORMAT_TEXT)
{
types[++i] = "text/plain";
types[++i] = "text/plain;charset=utf-8";
}
if (format & ELM_SEL_FORMAT_MARKUP)
types[++i] = "application/x-elementary-markup";
if (format & ELM_SEL_FORMAT_HTML)
{
types[++i] = "text/html";
types[++i] = "text/html;charset=utf-8";
}
if (i < 0) return EINA_FALSE;
ecore_wl_dnd_selection_get(ecore_wl_input_get(), *types);
}
return EINA_TRUE;
}
static Eina_Bool
_wl_elm_cnp_selection_clear(Evas_Object *obj EINA_UNUSED, Elm_Sel_Type selection)
static void
_wl_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection __UNUSED__, Elm_Selection_Loss_Cb func, const void *data)
{
Wl_Cnp_Selection *sel = &wl_cnp_selection;
_wl_elm_cnp_init();
if (ELM_SEL_TYPE_CLIPBOARD == selection)
{
wl_cnp_selection.requestwidget = NULL;
if (wl_cnp_selection.selbuf) free(wl_cnp_selection.selbuf);
wl_cnp_selection.buflen = 0;
ecore_wl_dnd_selection_clear(ecore_wl_input_get());
}
sel->loss_cb = func;
sel->loss_data = (void *)data;
}
static Eina_Bool
_wl_elm_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection __UNUSED__)
{
Wl_Cnp_Selection *sel = &wl_cnp_selection;
_wl_elm_cnp_init();
if ((!sel->active) || (sel->widget != obj))
return EINA_TRUE;
if (sel->widget)
evas_object_event_callback_del_full(sel->widget,
EVAS_CALLBACK_DEL,
_wl_sel_obj_del, &wl_cnp_selection);
if (sel->requestwidget)
evas_object_event_callback_del_full(sel->requestwidget,
EVAS_CALLBACK_DEL,
_wl_sel_obj_del2, &wl_cnp_selection);
sel->widget = NULL;
sel->requestwidget = NULL;
sel->loss_cb = NULL;
sel->loss_data = NULL;
sel->active = EINA_FALSE;
ELM_SAFE_FREE(sel->selbuf, free);
sel->buflen = 0;
/* sel->clear(); */
ecore_wl_dnd_selection_clear(ecore_wl_input_get());
return EINA_TRUE;
}
@ -2290,17 +2446,78 @@ _wl_selection_receive(void *udata, int type __UNUSED__, void *event)
{
if (!ev->done)
{
/* TODO BUG: should never NEVER assume it's an elm_entry! */
_elm_entry_entry_paste(sel->requestwidget, ev->data);
if (sel->seltype == ELM_SEL_TYPE_XDND)
{
Elm_Selection_Data sdata;
Eina_List *l;
Dropable *dropable;
EINA_LIST_FOREACH(drops, l, dropable)
{
if (dropable->obj == sel->requestwidget) break;
dropable = NULL;
}
if (dropable)
{
Dropable_Cbs *cbs;
sdata.x = savedtypes.x;
sdata.y = savedtypes.y;
sdata.format = ELM_SEL_FORMAT_TEXT;
sdata.data = ev->data;
sdata.len = ev->len;
sdata.action = sel->action;
EINA_INLIST_FOREACH(dropable->cbs_list, cbs)
if (cbs->dropcb)
cbs->dropcb(cbs->dropdata, dropable->obj, &sdata);
goto end;
}
}
if (sel->datacb)
{
Elm_Selection_Data sdata;
sdata.x = sdata.y = 0;
sdata.format = ELM_SEL_FORMAT_TEXT;
sdata.data = ev->data;
sdata.len = ev->len;
sdata.action = sel->action;
sel->datacb(sel->udata, sel->widget, &sdata);
}
else
{
char *stripstr, *mkupstr;
stripstr = malloc(ev->len + 1);
if (!stripstr) goto end;
strncpy(stripstr, (char *)ev->data, ev->len);
stripstr[ev->len] = '\0';
mkupstr = _elm_util_text_to_mkup((const char *)stripstr);
/* TODO BUG: should never NEVER assume it's an elm_entry! */
_elm_entry_entry_paste(sel->requestwidget, mkupstr);
free(stripstr);
free(mkupstr);
}
}
else
{
evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
evas_object_event_callback_del_full(sel->requestwidget,
EVAS_CALLBACK_DEL,
_wl_sel_obj_del2, sel);
sel->requestwidget = NULL;
}
}
end:
if (sel->seltype == ELM_SEL_TYPE_XDND)
{
/* FIXME: Send Finished ?? */
}
return ECORE_CALLBACK_PASS_ON;
}
@ -3426,6 +3643,10 @@ elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type selection,
#ifdef HAVE_ELEMENTARY_X
if (_x11_elm_widget_xwin_get(obj))
_x11_elm_cnp_selection_loss_callback_set(obj, selection, func, data);
#endif
#ifdef HAVE_ELEMENTARY_WAYLAND
if (elm_win_wl_window_get(obj))
_wl_elm_cnp_selection_loss_callback_set(obj, selection, func, data);
#endif
_local_elm_cnp_selection_loss_callback_set(obj, selection, func, data);
}