From edd93346ad5df3bd9a244c24077c08a37c4f4732 Mon Sep 17 00:00:00 2001 From: Vincent Torri Date: Thu, 15 Oct 2015 23:13:42 +0200 Subject: [PATCH] cnp: add Copy & Paste support for Windows It needs the clipboard management in Ecore_Win32 @feature Change-Id: I20f6f6bf31475b52d4341257d80801d6d4efb67a Signed-off-by: Cedric BAIL --- src/lib/elm_cnp.c | 339 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib/elm_config.c | 5 +- src/lib/elm_priv.h | 3 + src/lib/elm_win.c | 84 ++++++++++++ src/lib/elm_win.eo | 10 ++ src/lib/elm_win_legacy.h | 17 +++ 6 files changed, 457 insertions(+), 1 deletion(-) diff --git a/src/lib/elm_cnp.c b/src/lib/elm_cnp.c index 3dedf00..b933058 100644 --- a/src/lib/elm_cnp.c +++ b/src/lib/elm_cnp.c @@ -4865,6 +4865,320 @@ _local_elm_selection_selection_has_owner(Evas_Object *obj EINA_UNUSED) } #endif +// win32 specific stuff +//////////////////////////////////////////////////////////////////////////// +#ifdef HAVE_ELEMENTARY_WIN32 + +typedef struct _Win32_Cnp_Selection Win32_Cnp_Selection; + +struct _Win32_Cnp_Selection +{ + const char *debug; + Evas_Object *widget; + char *selbuf; + Evas_Object *requestwidget; + void *udata; + Elm_Sel_Format requestformat; + Elm_Drop_Cb datacb; + Eina_Bool (*set)(const Ecore_Win32_Window *window, const void *data, int size); + Eina_Bool (*clear)(const Ecore_Win32_Window *window); + Eina_Bool (*get)(const Ecore_Win32_Window *window , void **data, int *size); + Elm_Selection_Loss_Cb loss_cb; + void *loss_data; + + Elm_Sel_Format format; + Ecore_Win32_Selection ecore_sel; + Ecore_Win32_Window *win; + Elm_Xdnd_Action action; + + Eina_Bool active : 1; +}; + +#define ARRAYINIT(foo) [foo] = + +static Win32_Cnp_Selection _win32_selections[ELM_SEL_TYPE_CLIPBOARD + 1] = +{ + ARRAYINIT(ELM_SEL_TYPE_PRIMARY) + { + .debug = "Primary", + .ecore_sel = ECORE_WIN32_SELECTION_PRIMARY, + .set = ecore_win32_clipboard_set, + .clear = ecore_win32_clipboard_clear, + .get = ecore_win32_clipboard_get, + }, + ARRAYINIT(ELM_SEL_TYPE_SECONDARY) + { + .debug = "Secondary", + .ecore_sel = ECORE_WIN32_SELECTION_OTHER, + }, + ARRAYINIT(ELM_SEL_TYPE_XDND) + { + .debug = "XDnD", + .ecore_sel = ECORE_WIN32_SELECTION_OTHER, + }, + ARRAYINIT(ELM_SEL_TYPE_CLIPBOARD) + { + .debug = "Clipboard", + .ecore_sel = ECORE_WIN32_SELECTION_CLIPBOARD, + .set = ecore_win32_clipboard_set, + .clear = ecore_win32_clipboard_clear, + .get = ecore_win32_clipboard_get, + } +}; + + +static void +_win32_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Win32_Cnp_Selection *sel = data; + if (sel->widget == obj) sel->widget = NULL; + if (dragwidget == obj) dragwidget = NULL; +} + +static void +_win32_sel_obj_del2(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Win32_Cnp_Selection *sel = data; + if (sel->requestwidget == obj) sel->requestwidget = NULL; +} + +static Eina_Bool +_win32_elm_cnp_init(void) +{ + static int _init_count = 0; + + if (_init_count > 0) return EINA_TRUE; + _init_count++; + return EINA_TRUE; +} + +static Ecore_Win32_Window * +_win32_elm_widget_window_get(const Evas_Object *obj) +{ + Evas_Object *top; + Ecore_Win32_Window *win = NULL; + + if (elm_widget_is(obj)) + { + top = elm_widget_top_get(obj); + if (!top) + { + Evas_Object *par; + par = elm_widget_parent_widget_get(obj); + if (par) top = elm_widget_top_get(par); + } + if (top && (eo_isa(top, ELM_WIN_CLASS))) + win = elm_win_win32_window_get(top); + } + + if (!win) + { + Ecore_Evas *ee; + Evas *evas; + const char *engine_name; + + evas = evas_object_evas_get(obj); + if (!evas) return NULL; + + ee = ecore_evas_ecore_evas_get(evas); + if (!ee) return NULL; + + engine_name = ecore_evas_engine_name_get(ee); + if (!strcmp(engine_name, ELM_BUFFER)) + { + ee = ecore_evas_buffer_ecore_evas_parent_get(ee); + if (!ee) return NULL; + win = ecore_evas_win32_window_get(ee); + } + else + { + if ((strcmp(engine_name, ELM_SOFTWARE_WIN32) == 0) || + (strcmp(engine_name, ELM_SOFTWARE_DDRAW) == 0)) + return ecore_evas_win32_window_get(ee); + } + } + + return win; +} + +static Eina_Bool +_win32_elm_cnp_selection_set(Ecore_Win32_Window *win, Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, const void *selbuf, size_t buflen) +{ + Win32_Cnp_Selection *sel; + + if (selection != ELM_SEL_TYPE_CLIPBOARD) + return EINA_FALSE; + + _win32_elm_cnp_init(); + if ((!selbuf) && (format != ELM_SEL_FORMAT_IMAGE)) + return elm_object_cnp_selection_clear(obj, selection); + + sel = _win32_selections + selection; + if (sel->widget != obj && sel->loss_cb) sel->loss_cb(sel->loss_data, selection); + if (sel->widget) + evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL, + _win32_sel_obj_del, sel); + sel->active = EINA_TRUE; + sel->widget = obj; + sel->win = win; + if (sel->set) sel->set(win, selbuf, buflen); + sel->format = format; + sel->loss_cb = NULL; + sel->loss_data = NULL; + + evas_object_event_callback_add + (sel->widget, EVAS_CALLBACK_DEL, _win32_sel_obj_del, sel); + + ELM_SAFE_FREE(sel->selbuf, free); + if (selbuf) + { + if (format == ELM_SEL_FORMAT_IMAGE) + { + // 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 + sel->selbuf = strdup((char*)selbuf); + } + + return EINA_TRUE; +} + +static void +_win32_elm_cnp_selection_loss_callback_set(Evas_Object *obj EINA_UNUSED, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data) +{ + Win32_Cnp_Selection *sel; + + if (selection != ELM_SEL_TYPE_CLIPBOARD) + return; + + _win32_elm_cnp_init(); + sel = _win32_selections + selection; + sel->loss_cb = func; + sel->loss_data = (void *)data; +} + +static Eina_Bool +_win32_elm_object_cnp_selection_clear(Ecore_Win32_Window *win, Evas_Object *obj, Elm_Sel_Type selection) +{ + Win32_Cnp_Selection *sel; + + if (selection != ELM_SEL_TYPE_CLIPBOARD) + return EINA_FALSE; + + _win32_elm_cnp_init(); + + sel = _win32_selections + selection; + + /* No longer this selection: Consider it gone! */ + if ((!sel->active) || (sel->widget != obj)) + return EINA_TRUE; + + if (sel->widget) + evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL, + _win32_sel_obj_del, sel); + if (sel->requestwidget) + evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL, + _win32_sel_obj_del2, sel); + 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->clear(win); */ + + return EINA_TRUE; +} + +static Eina_Bool +_win32_elm_cnp_selection_get(Ecore_Win32_Window *win, + const Evas_Object *obj, + Elm_Sel_Type selection, + Elm_Sel_Format format, + Elm_Drop_Cb datacb, + void *udata) +{ + Win32_Cnp_Selection *sel; + void *data; + int size; + + if (selection != ELM_SEL_TYPE_CLIPBOARD) + return EINA_FALSE; + + _win32_elm_cnp_init(); + + sel = _win32_selections + selection; + + if (sel->requestwidget) + evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL, + _win32_sel_obj_del2, sel); + sel->requestformat = format; + sel->requestwidget = (Evas_Object *)obj; + sel->win = win; + sel->get(win, &data, &size); + sel->datacb = datacb; + sel->udata = udata; + + if (!data || (size <= 0)) + goto cb_add; + + if ((sel->format & ELM_SEL_FORMAT_MARKUP) || + (sel->format & ELM_SEL_FORMAT_HTML)) + { + char *str; + + str = (char *)malloc(size + 1); + if (str) + { + memcpy(str, data, size); + str[size] = '\0'; + data = _elm_util_mkup_to_text(str); + free(str); + if (data) + size = strlen(data); + else + size = 0; + } + else + { + free(data); + data = NULL; + } + } + + if (sel->datacb && data && (size > 0)) + { + Elm_Selection_Data sdata; + + sdata.x = sdata.y = 0; + sdata.format = ELM_SEL_FORMAT_TEXT; + sdata.data = data; + sdata.len = size; + sdata.action = sel->action; + sel->datacb(sel->udata, sel->requestwidget, &sdata); + } + + if (data) + free(data); + + cb_add: + evas_object_event_callback_add + (sel->requestwidget, EVAS_CALLBACK_DEL, _win32_sel_obj_del2, sel); + + return EINA_TRUE; +} + +#endif /* HAVE_ELEMENTARY_WIN32 */ + // common internal funcs //////////////////////////////////////////////////////////////////////////// static Eina_Bool @@ -5009,6 +5323,13 @@ elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, if (win) return _cocoa_elm_cnp_selection_set(win, obj, selection, format, selbuf, buflen); #endif +#ifdef HAVE_ELEMENTARY_WIN32 + Ecore_Win32_Window *win; + + win = _win32_elm_widget_window_get(obj); + if (win) + return _win32_elm_cnp_selection_set(win, obj, selection, format, selbuf, buflen); +#endif return _local_elm_cnp_selection_set(obj, selection, format, selbuf, buflen); } @@ -5031,6 +5352,10 @@ elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type selection, if (_cocoa_elm_widget_cocoa_window_get(obj)) _cocoa_elm_cnp_selection_loss_callback_set(obj, selection, func, data); #endif +#ifdef HAVE_ELEMENTARY_WIN32 + if (_win32_elm_widget_window_get(obj)) + _win32_elm_cnp_selection_loss_callback_set(obj, selection, func, data); +#endif _local_elm_cnp_selection_loss_callback_set(obj, selection, func, data); } @@ -5051,6 +5376,13 @@ elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection) if (_cocoa_elm_widget_cocoa_window_get(obj)) return _cocoa_elm_cnp_selection_clear(obj, selection); #endif +#ifdef HAVE_ELEMENTARY_WIN32 + Ecore_Win32_Window *win; + + win = _win32_elm_widget_window_get(obj); + if (win) + return _win32_elm_object_cnp_selection_clear(win, obj, selection); +#endif return _local_elm_object_cnp_selection_clear(obj, selection); } @@ -5074,6 +5406,13 @@ elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type selection, if (win) return _cocoa_elm_cnp_selection_get(obj, win, selection, format, datacb, udata); #endif +#ifdef HAVE_ELEMENTARY_WIN32 + Ecore_Win32_Window *win; + + win = _win32_elm_widget_window_get(obj); + if (win) + return _win32_elm_cnp_selection_get(win, obj, selection, format, datacb, udata); +#endif return _local_elm_cnp_selection_get(obj, selection, format, datacb, udata); } diff --git a/src/lib/elm_config.c b/src/lib/elm_config.c index 75b004a..192f550 100644 --- a/src/lib/elm_config.c +++ b/src/lib/elm_config.c @@ -3764,7 +3764,7 @@ _elm_config_file_monitor_cb(void *data EINA_UNUSED, void _elm_config_sub_init(void) { -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WAYLAND) +#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WAYLAND) || defined(HAVE_ELEMENTARY_WIN32) const char *ev = getenv("ELM_DISPLAY"); #endif @@ -3830,6 +3830,9 @@ _elm_config_sub_init(void) ecore_wl_init(NULL); } #endif +#ifdef HAVE_ELEMENTARY_WIN32 + ecore_win32_init(); +#endif char buf[PATH_MAX]; int ok = 0; diff --git a/src/lib/elm_priv.h b/src/lib/elm_priv.h index 5c71c35..f04d8ba 100644 --- a/src/lib/elm_priv.h +++ b/src/lib/elm_priv.h @@ -20,6 +20,9 @@ #endif # include #endif +#ifdef HAVE_ELEMENTARY_WIN32 +#include +#endif #include diff --git a/src/lib/elm_win.c b/src/lib/elm_win.c index 6706554..087a4c3 100644 --- a/src/lib/elm_win.c +++ b/src/lib/elm_win.c @@ -127,6 +127,12 @@ struct _Elm_Win_Data Ecore_Cocoa_Window *win; } cocoa; #endif +#ifdef HAVE_ELEMENTARY_WIN32 + struct + { + Ecore_Win32_Window *win; + } win32; +#endif Ecore_Job *deferred_resize_job; Ecore_Job *deferred_child_eval_job; @@ -2551,6 +2557,28 @@ _elm_ee_cocoa_win_get(const Ecore_Evas *ee) engine_name = ecore_evas_engine_name_get(ee); if (EINA_UNLIKELY(!engine_name)) return NULL; + if ((!strcmp(engine_name, ELM_SOFTWARE_WIN32)) || + (!strcmp(engine_name, ELM_SOFTWARE_DDRAW))) + { + return ecore_evas_win32_window_get(ee); + } +#else + (void)ee; +#endif + return NULL; +} + +Ecore_Win32_Window * +_elm_ee_win32win_get(const Ecore_Evas *ee) +{ +#ifdef HAVE_ELEMENTARY_WIN32 + const char *engine_name; + + if (!ee) return NULL; + + engine_name = ecore_evas_engine_name_get(ee); + if (EINA_UNLIKELY(!engine_name)) return NULL; + if (!strcmp(engine_name, "opengl_cocoa") || !strcmp(engine_name, "gl_cocoa")) return ecore_evas_cocoa_window_get(ee); @@ -2568,6 +2596,14 @@ _elm_win_cocoawindow_get(Elm_Win_Data *sd) } #endif +#ifdef HAVE_ELEMENTARY_WIN32 +static void +_internal_elm_win_win32window_get(Elm_Win_Data *sd) +{ + sd->win32.win = _elm_ee_win32win_get(sd->ee); +} +#endif + #ifdef HAVE_ELEMENTARY_X static void _elm_win_xwin_update(Elm_Win_Data *sd) @@ -4346,6 +4382,9 @@ _elm_win_finalize_internal(Eo *obj, Elm_Win_Data *sd, const char *name, Elm_Win_ #ifdef HAVE_ELEMENTARY_COCOA _elm_win_cocoawindow_get(sd); #endif +#ifdef HAVE_ELEMENTARY_WIN32 + _internal_elm_win_win32window_get(sd); +#endif if ((_elm_config->bgpixmap) #ifdef HAVE_ELEMENTARY_X @@ -6230,6 +6269,41 @@ _elm_win_wl_window_get(Eo *obj EINA_UNUSED, Elm_Win_Data *sd) return NULL; } +EAPI Ecore_Win32_Window * +elm_win_win32_window_get(const Evas_Object *obj) +{ + ELM_WIN_CHECK(obj) NULL; + ELM_WIN_DATA_GET_OR_RETURN_VAL(obj, sd, NULL); + const char *engine_name = ecore_evas_engine_name_get(sd->ee); + + if (!(engine_name && + ((!strcmp(engine_name, ELM_SOFTWARE_WIN32)) || + (!strcmp(engine_name, ELM_SOFTWARE_DDRAW))))) + return NULL; + + if (!evas_object_smart_type_check_ptr(obj, MY_CLASS_NAME_LEGACY)) + { + Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + return _elm_ee_win32win_get(ee); + } + + Ecore_Win32_Window *ret = NULL; + eo_do((Eo *) obj, ret = elm_obj_win_win32_window_get()); + return ret; +} + +EOLIAN static Ecore_Win32_Window * +_elm_win_win32_window_get(Eo *obj EINA_UNUSED, Elm_Win_Data *sd) +{ +#if HAVE_ELEMENTARY_WIN32 + if (sd->win32.win) return sd->win32.win; + if (sd->parent) return elm_win_win32_window_get(sd->parent); +#else + (void)sd; +#endif + return NULL; +} + EAPI Eina_Bool elm_win_trap_set(const Elm_Win_Trap *t) { @@ -6353,6 +6427,16 @@ _elm_win_window_id_get(Eo *obj EINA_UNUSED, Elm_Win_Data *sd) } #endif } + else if ((engine_name && + ((!strcmp(engine_name, ELM_SOFTWARE_WIN32)) || + (!strcmp(engine_name, ELM_SOFTWARE_DDRAW))))) + { +#ifdef HAVE_ELEMENTARY_WIN32 + _internal_elm_win_win32window_get(sd); + if (sd->win32.win) return (Ecore_Window)sd->win32.win; + if (sd->parent) return (Ecore_Window)elm_win_win32_window_get(sd->parent); +#endif + } return 0; } diff --git a/src/lib/elm_win.eo b/src/lib/elm_win.eo index 1881ae7..d0219c6 100644 --- a/src/lib/elm_win.eo +++ b/src/lib/elm_win.eo @@ -996,6 +996,16 @@ class Elm.Win (Elm.Widget, Elm_Interface_Atspi_Window, get { [[Get the Ecore_Cocoa_Window of an Evas.Object.]] return: Ecore_Cocoa_Window *; [[The Ecore_Cocoa_Window of $obj.]] + } + } + @property win32_window { + get { + [[Get the Ecore_Win32_Window of an Evas_Object + + @since 1.16 + ]] + return: Ecore_Win32_Window *; [[The Ecore_Win32_Window of $obj.]] + legacy: null; } } @property window_id { diff --git a/src/lib/elm_win_legacy.h b/src/lib/elm_win_legacy.h index 091d1cc..60040fb 100644 --- a/src/lib/elm_win_legacy.h +++ b/src/lib/elm_win_legacy.h @@ -197,6 +197,23 @@ EAPI void elm_win_render(Evas_Object *obj); */ EAPI Ecore_Wl_Window *elm_win_wl_window_get(const Evas_Object *obj); +/* Windows specific call - returns NULL on non-Windows engines */ +/** + * Get the Ecore_Win32_Window of an Evas_Object + * + * Do not use this function if you'd like your application/library be portable. + * You have been warned. + * + * @param obj the object + * + * @return The Ecore_Win32_Window of @p obj + * + * @ingroup Win + * + * @since 1.16 + */ +EAPI Ecore_Win32_Window *elm_win_win32_window_get(const Evas_Object *obj); + /** * Set the preferred rotation value. * -- 2.7.4