summaryrefslogtreecommitdiff
path: root/src/modules/ecore_evas/engines/x/ecore_evas_x.c
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2020-01-12 17:38:05 +0100
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2020-03-08 10:59:34 +0100
commite0c40abb40f05efe32e263e8a59e923281b559dc (patch)
tree539c1e5e1dd087abfc2f95682edabded22cb4e44 /src/modules/ecore_evas/engines/x/ecore_evas_x.c
parent6189c2112c2c854b86821d8391e69231d78cdc29 (diff)
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. Reviewed-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com> Differential Revision: https://phab.enlightenment.org/D11195
Diffstat (limited to '')
-rw-r--r--src/modules/ecore_evas/engines/x/ecore_evas_x.c756
1 files changed, 753 insertions, 3 deletions
diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c b/src/modules/ecore_evas/engines/x/ecore_evas_x.c
index fb6eaa63f1..d689a5622c 100644
--- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c
+++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c
@@ -73,6 +73,16 @@ static Eina_Bool wm_exists;
73 73
74typedef struct _Ecore_Evas_Engine_Data_X11 Ecore_Evas_Engine_Data_X11; 74typedef struct _Ecore_Evas_Engine_Data_X11 Ecore_Evas_Engine_Data_X11;
75 75
76typedef struct {
77 Ecore_Evas_Selection_Callbacks callbacks;
78 Ecore_Evas_Selection_Buffer buffer;
79 Ecore_Evas *ee;
80 Eina_Promise *delivery;
81 Eina_Array *acceptable_type;
82 Eina_Stringshare *requested_type;
83 Eina_Stringshare *later_conversion;
84} Ecore_Evas_X11_Selection_Data;
85
76struct _Ecore_Evas_Engine_Data_X11 { 86struct _Ecore_Evas_Engine_Data_X11 {
77 Ecore_X_Window win_root; 87 Ecore_X_Window win_root;
78 Eina_List *win_extra; 88 Eina_List *win_extra;
@@ -128,6 +138,11 @@ struct _Ecore_Evas_Engine_Data_X11 {
128 void *visual; // store visual used to create pixmap 138 void *visual; // store visual used to create pixmap
129 unsigned long colormap; // store colormap used to create pixmap 139 unsigned long colormap; // store colormap used to create pixmap
130 } pixmap; 140 } pixmap;
141 Ecore_Evas_X11_Selection_Data selection_data[ECORE_EVAS_SELECTION_BUFFER_LAST];
142 Eina_Array *xserver_atom_name_during_dnd;
143 Ecore_Event_Handler *mouse_up_handler;
144 Ecore_Job *init_job;
145 int skip_clean_event;
131 Eina_Bool destroyed : 1; // X window has been deleted and cannot be used 146 Eina_Bool destroyed : 1; // X window has been deleted and cannot be used
132 Eina_Bool fully_obscured : 1; // X window is fully obscured 147 Eina_Bool fully_obscured : 1; // X window is fully obscured
133 Eina_Bool configured : 1; // X window has been configured 148 Eina_Bool configured : 1; // X window has been configured
@@ -151,6 +166,8 @@ static void _alpha_do(Ecore_Evas *, int);
151static void _transparent_do(Ecore_Evas *, int); 166static void _transparent_do(Ecore_Evas *, int);
152static void _avoid_damage_do(Ecore_Evas *, int); 167static void _avoid_damage_do(Ecore_Evas *, int);
153static void _rotation_do(Ecore_Evas *, int, int); 168static void _rotation_do(Ecore_Evas *, int, int);
169static void _ecore_evas_x_selection_init(void);
170static void _ecore_evas_x_selection_window_init(Ecore_Evas *ee);
154 171
155#define SWAP_INT(a, b) do { a ^= b; b ^= a; a ^= b; } while (0) 172#define SWAP_INT(a, b) do { a ^= b; b ^= a; a ^= b; } while (0)
156 173
@@ -1970,6 +1987,7 @@ _ecore_evas_x_init(void)
1970 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE, 1987 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE,
1971 _ecore_evas_x_event_window_create, NULL); 1988 _ecore_evas_x_event_window_create, NULL);
1972 ecore_event_evas_init(); 1989 ecore_event_evas_init();
1990 _ecore_evas_x_selection_init();
1973 return _ecore_evas_init_count; 1991 return _ecore_evas_init_count;
1974} 1992}
1975 1993
@@ -1997,6 +2015,7 @@ _ecore_evas_x_free(Ecore_Evas *ee)
1997{ 2015{
1998 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; 2016 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
1999 2017
2018 ecore_job_del(edata->init_job);
2000 if (edata->pixmap.back) 2019 if (edata->pixmap.back)
2001 ecore_x_pixmap_free(edata->pixmap.back); 2020 ecore_x_pixmap_free(edata->pixmap.back);
2002 if (edata->pixmap.front) 2021 if (edata->pixmap.front)
@@ -2696,6 +2715,7 @@ _alpha_do(Ecore_Evas *ee, int alpha)
2696 _ecore_evas_x_aux_hints_supported_update(ee); 2715 _ecore_evas_x_aux_hints_supported_update(ee);
2697 _ecore_evas_x_aux_hints_update(ee); 2716 _ecore_evas_x_aux_hints_update(ee);
2698 _ecore_evas_x_size_pos_hints_update(ee); 2717 _ecore_evas_x_size_pos_hints_update(ee);
2718 _ecore_evas_x_selection_window_init(ee);
2699#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ 2719#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
2700 if ((id = getenv("DESKTOP_STARTUP_ID"))) 2720 if ((id = getenv("DESKTOP_STARTUP_ID")))
2701 { 2721 {
@@ -2850,6 +2870,7 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
2850 _ecore_evas_x_aux_hints_supported_update(ee); 2870 _ecore_evas_x_aux_hints_supported_update(ee);
2851 _ecore_evas_x_aux_hints_update(ee); 2871 _ecore_evas_x_aux_hints_update(ee);
2852 _ecore_evas_x_size_pos_hints_update(ee); 2872 _ecore_evas_x_size_pos_hints_update(ee);
2873 _ecore_evas_x_selection_window_init(ee);
2853#endif /* BUILD_ECORE_EVAS_OPENGL_X11 */ 2874#endif /* BUILD_ECORE_EVAS_OPENGL_X11 */
2854 if ((id = getenv("DESKTOP_STARTUP_ID"))) 2875 if ((id = getenv("DESKTOP_STARTUP_ID")))
2855 { 2876 {
@@ -3667,6 +3688,731 @@ _ecore_evas_x_aux_hints_set(Ecore_Evas *ee, const char *hints)
3667 (ee->prop.window, ECORE_X_ATOM_E_WINDOW_AUX_HINT); 3688 (ee->prop.window, ECORE_X_ATOM_E_WINDOW_AUX_HINT);
3668} 3689}
3669 3690
3691static Ecore_X_Atom ecore_evas_selection_to_atom[] = {0, 0, 0, 0};
3692static Ecore_Event_Handler *ecore_evas_selection_handlers[8];
3693
3694static inline Ecore_Evas_Selection_Buffer
3695_atom_to_selection(Ecore_X_Atom atom)
3696{
3697 for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i)
3698 {
3699 if (ecore_evas_selection_to_atom[i] == atom)
3700 return i;
3701 }
3702 return ECORE_EVAS_SELECTION_BUFFER_LAST;
3703}
3704
3705static Eina_Stringshare*
3706_decrypt_type(const char *target)
3707{
3708 // reference https://tronche.com/gui/x/icccm/sec-2.html
3709 if (eina_streq(target, "TEXT")) return eina_stringshare_add("text/plain");
3710 //FIXME no support in eina_content for that so far
3711 if (eina_streq(target, "COMPOUND_TEXT")) return eina_stringshare_add("text/plain");
3712 // reference https://tronche.com/gui/x/icccm/sec-2.html
3713 if (eina_streq(target, "STRING")) return eina_stringshare_add("text/plain;charset=iso-8859-1");
3714 if (eina_streq(target, "UTF8_STRING")) return eina_stringshare_add("text/plain;charset=utf-8");
3715
3716 return eina_stringshare_add(target);
3717}
3718
3719static Eina_Stringshare*
3720_mime_to_xserver_type(const char *target)
3721{
3722 // FIXME // reference https://tronche.com/gui/x/icccm/sec-2.html says it is in the owners choice of encoding, not sure what this means directly here
3723 if (eina_streq(target, "text/plain")) return eina_stringshare_add("TEXT");
3724 // reference https://tronche.com/gui/x/icccm/sec-2.html
3725 if (eina_streq(target, "text/plain;charset=iso-8859-1")) return eina_stringshare_add("STRING");
3726 if (eina_streq(target, "text/plain;charset=utf-8")) return eina_stringshare_add("UTF8_STRING");
3727
3728 return eina_stringshare_add(target);
3729}
3730
3731static inline void
3732_clear_selection(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection)
3733{
3734 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
3735 Ecore_Evas_Selection_Callbacks *cbs = &edata->selection_data[selection].callbacks;
3736
3737 EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel);
3738
3739 cbs->cancel(ee, 1, selection);
3740 eina_array_free(cbs->available_types);
3741
3742 cbs->delivery = NULL;
3743 cbs->cancel = NULL;
3744 cbs->available_types = NULL;
3745}
3746
3747static void
3748_clear_selection_delivery(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection)
3749{
3750 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
3751 eina_stringshare_replace(&edata->selection_data[selection].requested_type, NULL);
3752 eina_stringshare_replace(&edata->selection_data[selection].later_conversion, NULL);
3753 edata->selection_data[selection].delivery = NULL;
3754 eina_array_free(edata->selection_data[selection].acceptable_type);
3755 edata->selection_data[selection].acceptable_type = NULL;
3756}
3757
3758static void
3759_ecore_x_selection_request(Ecore_X_Window win, Ecore_Evas_Selection_Buffer selection, const char *type)
3760{
3761 if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)
3762 ecore_x_selection_primary_request(win, type);
3763 else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
3764 ecore_x_selection_clipboard_request(win, type);
3765 else
3766 ecore_x_selection_xdnd_request(win, type);
3767}
3768
3769static void
3770_search_fitting_type(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Eina_Array *arr)
3771{
3772 Eina_Stringshare *mime_type;
3773 Eina_Bool found_conversion = EINA_FALSE;
3774
3775#define HANDLE_TYPE() \
3776 { \
3777 edata->selection_data[selection].requested_type = eina_stringshare_add(x11_name); \
3778 edata->selection_data[selection].later_conversion = eina_stringshare_add(acceptable_type);\
3779 found_conversion = EINA_TRUE; \
3780 break; \
3781 }
3782
3783 EINA_SAFETY_ON_NULL_RETURN(edata->selection_data[selection].acceptable_type);
3784
3785 for (unsigned int i = 0; i < eina_array_count(arr) && !found_conversion; ++i)
3786 {
3787 const char *x11_name = eina_array_data_get(arr, i);
3788 mime_type = _decrypt_type(x11_name);
3789
3790 for (unsigned int j = 0; j < eina_array_count(edata->selection_data[selection].acceptable_type) && !found_conversion; ++j)
3791 {
3792 const char *acceptable_type = (const char*) eina_array_data_get(edata->selection_data[selection].acceptable_type, j);
3793
3794 if (mime_type == acceptable_type)
3795 HANDLE_TYPE()
3796
3797 //if there is no available type yet, check if we can convert to the desiared type via this type
3798 if (!found_conversion)
3799 {
3800 const char *convertion_type = NULL;
3801 Eina_Iterator *iter = eina_content_converter_possible_conversions(mime_type);
3802 EINA_ITERATOR_FOREACH(iter, convertion_type)
3803 {
3804 if (convertion_type == acceptable_type)
3805 HANDLE_TYPE()
3806 }
3807 eina_iterator_free(iter);
3808 }
3809 }
3810 eina_stringshare_del(mime_type);
3811 }
3812 if (found_conversion)
3813 {
3814 _ecore_x_selection_request(ee->prop.window, selection, edata->selection_data[selection].requested_type);
3815 }
3816 else
3817 {
3818 eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_error_init(ecore_evas_no_matching_type));
3819 _clear_selection_delivery(ee, selection);
3820 }
3821
3822#undef HANDLE_TYPE
3823}
3824
3825static void
3826_search_fitting_type_from_event(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev)
3827{
3828 Ecore_X_Atom *available_atoms;
3829 Ecore_X_Selection_Data_Targets *targets;
3830 Eina_Array *tmp = eina_array_new(10);
3831
3832 targets = ev->data;
3833 available_atoms = (Ecore_X_Atom *)targets->data.data;
3834 for (int i = 0; i < targets->data.length; ++i)
3835 {
3836 Ecore_X_Atom atom = available_atoms[i];
3837 eina_array_push(tmp, ecore_x_atom_name_get(atom));
3838 }
3839 _search_fitting_type(ee, edata, selection, tmp);
3840 eina_array_free(tmp);
3841}
3842
3843static void
3844_deliver_content(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev)
3845{
3846 Ecore_X_Selection_Data *x11_data = ev->data;
3847 Eina_Rw_Slice data;
3848 Eina_Content *result;
3849 Eina_Stringshare *mime_type = _decrypt_type(edata->selection_data[selection].requested_type);
3850
3851 if (!strncmp(mime_type, "text", strlen("text")))
3852 {
3853 //ensure that we always have a \0 at the end, there is no assertion that \0 is included here.
3854 data.len = x11_data->length + 1;
3855 data.mem = eina_memdup(x11_data->data, x11_data->length, EINA_TRUE);
3856 }
3857 else
3858 {
3859 data.len = x11_data->length;
3860 data.mem = x11_data->data;
3861 }
3862
3863 result = eina_content_new(eina_rw_slice_slice_get(data), mime_type);
3864
3865 //ensure that we deliver the correct type, we might have choosen a convertion before
3866 if (edata->selection_data[selection].later_conversion != mime_type)
3867 {
3868 Eina_Content *tmp = eina_content_convert(result, edata->selection_data[selection].later_conversion);
3869 eina_content_free(result);
3870 result = tmp;
3871 }
3872
3873 eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_content_init(result));
3874 eina_content_free(result);
3875 _clear_selection_delivery(ee, selection);
3876
3877 if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
3878 ecore_x_dnd_send_finished();
3879}
3880
3881static Eina_Bool
3882_ecore_evas_x_selection_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
3883{
3884 Ecore_X_Event_Selection_Notify *ev = event;
3885 Ecore_Evas_Selection_Buffer selection;
3886 Ecore_Evas_Engine_Data_X11 *edata;
3887 Ecore_Evas *ee;
3888
3889 ee = ecore_event_window_match(ev->win);
3890 selection = _atom_to_selection(ev->atom);
3891 EINA_SAFETY_ON_FALSE_GOTO(!!ee, end);
3892 EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end);
3893 edata = ee->engine.data;
3894
3895 //if dnd drops above us, and even if we did not request anything, we are getting notified, refuse to do anything
3896 if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER &&
3897 !edata->selection_data[selection].later_conversion)
3898 {
3899 ecore_x_dnd_send_finished();
3900 }
3901 else
3902 {
3903 if (eina_streq(ev->target, "TARGETS") || eina_streq(ev->target, "ATOMS"))
3904 {
3905 //This will decide for a type, and will sent that via _ecore_x_selection_request
3906 EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, EINA_FALSE);
3907 EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, EINA_FALSE);
3908 _search_fitting_type_from_event(ee, edata, selection, ev);
3909 }
3910 else
3911 {
3912 //This will read the data, fill it into a Eina_Content apply all conversions required.
3913 EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].later_conversion, EINA_FALSE);
3914 EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].requested_type, EINA_FALSE);
3915 _deliver_content(ee, edata, selection, ev);
3916 }
3917 }
3918end:
3919 return ECORE_CALLBACK_PASS_ON;
3920}
3921
3922static Eina_Bool
3923_ecore_evas_x_selection_clear(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
3924{
3925 Ecore_X_Event_Selection_Clear *ev = event;
3926 Ecore_Evas_Selection_Callbacks *cbs;
3927 Ecore_Evas_Engine_Data_X11 *edata;
3928 Ecore_Evas_Selection_Buffer selection;
3929 Ecore_Evas *ee;
3930
3931 ee = ecore_event_window_match(ev->win);
3932 selection = _atom_to_selection(ev->atom);
3933 EINA_SAFETY_ON_FALSE_GOTO(ee, end);
3934 EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end);
3935 edata = ee->engine.data;
3936 cbs = &edata->selection_data[selection].callbacks;
3937
3938 //skip clean event
3939 if (edata->skip_clean_event)
3940 {
3941 edata->skip_clean_event --;
3942 goto end;
3943 }
3944
3945 if (cbs->cancel)
3946 _clear_selection(ee, selection);
3947end:
3948 return ECORE_CALLBACK_PASS_ON;
3949}
3950
3951static void
3952_force_stop_self_dnd(Ecore_Evas *ee)
3953{
3954 Ecore_Evas_Engine_Data_X11 *edata;
3955
3956 EINA_SAFETY_ON_NULL_RETURN(ee);
3957 edata = ee->engine.data;
3958 EINA_SAFETY_ON_NULL_RETURN(edata);
3959
3960 //Never clear the buffer for selection here.
3961 //Selection buffer is freed as a response to the FINISHED event.
3962 ecore_x_pointer_ungrab();
3963 ecore_x_dnd_self_drop();
3964 ecore_x_dnd_aware_set(ee->prop.window, EINA_FALSE);
3965 ecore_event_handler_del(edata->mouse_up_handler);
3966 edata->mouse_up_handler = NULL;
3967
3968 if (ee->drag.free)
3969 ee->drag.free(ee, 1, ee->drag.data, ee->drag.accepted);
3970 ee->drag.free = NULL;
3971}
3972
3973static Eina_Bool
3974_ecore_evas_x_selection_fixes_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
3975{
3976 Ecore_X_Event_Fixes_Selection_Notify *ev = event;
3977 Ecore_Evas *ee;
3978 Ecore_Evas_Selection_Buffer selection;
3979
3980 ee = ecore_event_window_match(ev->win);
3981 selection = _atom_to_selection(ev->atom);
3982 EINA_SAFETY_ON_FALSE_GOTO(!!ee, end);
3983 EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end);
3984
3985 //notify that the selection has changed on this ecore evas
3986 if (ee->func.fn_selection_changed)
3987 ee->func.fn_selection_changed(ee, 0, selection);
3988end:
3989 return ECORE_CALLBACK_PASS_ON;
3990}
3991
3992static Eina_Bool
3993_eina_content_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
3994{
3995 Ecore_Evas_X11_Selection_Data *sdata = data;
3996 Eina_Bool ret = EINA_FALSE;;
3997 if (eina_streq(target, "TARGETS") || eina_streq(target, "ATOM"))
3998 {
3999 //list all available types that we have currently
4000 Ecore_X_Atom *result = calloc(eina_array_count(sdata->callbacks.available_types), sizeof(Ecore_X_Atom));
4001 for (unsigned int i = 0; i < eina_array_count(sdata->callbacks.available_types); ++i)
4002 {
4003 result[i] = ecore_x_atom_get(eina_array_data_get(sdata->callbacks.available_types, i));
4004 }
4005 *size_ret = eina_array_count(sdata->callbacks.available_types);
4006 *data_ret = result;
4007 *ttype = ECORE_X_ATOM_ATOM;
4008 *typesize = 32; /* urk */
4009 ret = EINA_TRUE;
4010 }
4011 else
4012 {
4013 const char *mime_type = _decrypt_type(target);
4014 for (unsigned int i = 0; i < eina_array_count(sdata->callbacks.available_types); ++i)
4015 {
4016 if (mime_type == eina_array_data_get(sdata->callbacks.available_types, i))
4017 {
4018 Eina_Rw_Slice slice;
4019 sdata->callbacks.delivery(sdata->ee, 1, sdata->buffer, mime_type, &slice);
4020 *size_ret = slice.len;
4021 *data_ret = slice.mem;
4022 *ttype = ecore_x_atom_get(target); //use here target in order to get the correct atom
4023 //FIXME in selection manager we never set here the typesize, isn't that weird ?
4024 ret = EINA_TRUE;
4025 break;
4026 }
4027 }
4028 eina_stringshare_del(mime_type);
4029 }
4030
4031 return ret;
4032}
4033
4034static Eina_Bool
4035_ecore_evas_x_dnd_enter(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
4036{
4037 Ecore_X_Event_Xdnd_Enter *enter = event;
4038 Eina_Array *mime_tmp;
4039 Ecore_Evas_Engine_Data_X11 *edata;
4040 Ecore_Evas *ee;
4041
4042 mime_tmp = eina_array_new(10);
4043 ee = ecore_event_window_match(enter->win);
4044 EINA_SAFETY_ON_NULL_GOTO(ee, end);
4045 edata = ee->engine.data;
4046 edata->xserver_atom_name_during_dnd = eina_array_new(10);
4047 for (int i = 0; i < enter->num_types; ++i)
4048 {
4049 const char *mime_type = _decrypt_type(enter->types[i]);
4050 eina_array_push(mime_tmp, mime_type);
4051 eina_array_push(edata->xserver_atom_name_during_dnd, eina_stringshare_add(enter->types[i]));
4052 }
4053 ecore_evas_dnd_enter(ee, 1, eina_array_iterator_new(mime_tmp), EINA_POSITION2D(0,0)); //FIXME
4054 eina_array_free(mime_tmp);
4055
4056end:
4057 return ECORE_CALLBACK_PASS_ON;
4058}
4059
4060static Eina_Bool
4061_ecore_evas_x_dnd_leave(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
4062{
4063 Ecore_X_Event_Xdnd_Leave *leave = event;
4064 Ecore_Evas_Engine_Data_X11 *edata;
4065 Ecore_Evas *ee;
4066
4067 ee = ecore_event_window_match(leave->win);
4068 EINA_SAFETY_ON_NULL_GOTO(ee, end);
4069 edata = ee->engine.data;
4070 ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(0,0));
4071 for (unsigned int i = 0; i < eina_array_count(edata->xserver_atom_name_during_dnd); ++i)
4072 {
4073 eina_stringshare_del(eina_array_data_get(edata->xserver_atom_name_during_dnd, i));
4074 }
4075 eina_array_free(edata->xserver_atom_name_during_dnd);
4076 edata->xserver_atom_name_during_dnd = NULL;
4077end:
4078 return ECORE_CALLBACK_PASS_ON;
4079}
4080
4081static Ecore_X_Atom
4082_x11_dnd_action_rev_map(const char* action)
4083{
4084 if (eina_streq(action, "copy")) return ECORE_X_ATOM_XDND_ACTION_COPY;
4085 if (eina_streq(action, "move")) return ECORE_X_ATOM_XDND_ACTION_MOVE;
4086 else if (eina_streq(action, "privat")) return ECORE_X_ATOM_XDND_ACTION_PRIVATE;
4087 else if (eina_streq(action, "ask")) return ECORE_X_ATOM_XDND_ACTION_ASK;
4088 else if (eina_streq(action, "list")) return ECORE_X_ATOM_XDND_ACTION_LIST;
4089 else if (eina_streq(action, "link")) return ECORE_X_ATOM_XDND_ACTION_LINK;
4090 else if (eina_streq(action, "description")) return ECORE_X_ATOM_XDND_ACTION_DESCRIPTION;
4091 return 0;
4092}
4093
4094static const char*
4095_x11_dnd_action_map(Ecore_X_Atom action)
4096{
4097 if (action == ECORE_X_DND_ACTION_COPY) return "copy";
4098 if (action == ECORE_X_ATOM_XDND_ACTION_MOVE) return "move";
4099 if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE) return "privat";
4100 if (action == ECORE_X_ATOM_XDND_ACTION_ASK) return "ask";
4101 if (action == ECORE_X_ATOM_XDND_ACTION_LIST) return "list";
4102 if (action == ECORE_X_ATOM_XDND_ACTION_LINK) return "link";
4103 if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION) return "description";
4104
4105 return "unknown";
4106}
4107
4108static Eina_Bool
4109_ecore_evas_x_dnd_position(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
4110{
4111 Ecore_X_Event_Xdnd_Position *pos = event;
4112 int x, y, w, h;
4113 Ecore_Evas *ee;
4114
4115 ee = ecore_event_window_match(pos->win);
4116 EINA_SAFETY_ON_NULL_GOTO(ee, end);
4117 ecore_evas_geometry_get(ee, &x, &y, &w, &h);
4118 ecore_evas_dnd_position_set(ee, 1, EINA_POSITION2D(pos->position.x - x, pos->position.y - y));
4119 ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, (Ecore_X_Rectangle){x,y,w,h}, pos->action);
4120end:
4121 return ECORE_CALLBACK_PASS_ON;
4122}
4123
4124static Eina_Bool
4125_ecore_evas_x_dnd_drop(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
4126{
4127 Ecore_X_Event_Xdnd_Drop *drop = event;
4128 Ecore_Evas_Engine_Data_X11 *edata;
4129 Ecore_Evas *ee;
4130
4131 ee = ecore_event_window_match(drop->win);
4132 EINA_SAFETY_ON_NULL_GOTO(ee, end);
4133 edata = ee->engine.data;
4134 if (ee->func.fn_dnd_drop)
4135 ee->func.fn_dnd_drop(ee, 1, ecore_evas_dnd_pos_get(ee, 1), _x11_dnd_action_map(drop->action));
4136 if (!edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].requested_type)
4137 {
4138 ecore_x_dnd_send_finished();
4139 }
4140 ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(drop->position.x ,drop->position.y));
4141 eina_array_free(edata->xserver_atom_name_during_dnd);
4142 edata->xserver_atom_name_during_dnd = NULL;
4143end:
4144 return ECORE_CALLBACK_PASS_ON;
4145}
4146
4147static Eina_Bool
4148_ecore_evas_x_finished(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
4149{
4150 Ecore_X_Event_Xdnd_Finished *finished = event;
4151 Ecore_Evas *ee;
4152
4153 ee = ecore_event_window_match(finished->win);
4154 EINA_SAFETY_ON_NULL_GOTO(ee, end);
4155
4156 _clear_selection(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER);
4157end:
4158 return ECORE_CALLBACK_PASS_ON;
4159}
4160
4161static void
4162_ecore_evas_x_selection_init(void)
4163{
4164 Ecore_X_Atom _ecore_evas_selection_to_atom[] = {ECORE_X_ATOM_SELECTION_PRIMARY, ECORE_X_ATOM_SELECTION_CLIPBOARD, ECORE_X_ATOM_SELECTION_XDND};
4165
4166 for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i)
4167 {
4168 ecore_evas_selection_to_atom[i] = _ecore_evas_selection_to_atom[i];
4169 }
4170
4171 ecore_evas_selection_handlers[0] =
4172 ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY,
4173 _ecore_evas_x_selection_notify, NULL);
4174 ecore_evas_selection_handlers[1] =
4175 ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR,
4176 _ecore_evas_x_selection_clear, NULL);
4177 if (ECORE_X_EVENT_FIXES_SELECTION_NOTIFY)
4178 ecore_evas_selection_handlers[2] =
4179 ecore_event_handler_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY,
4180 _ecore_evas_x_selection_fixes_notify, NULL);
4181
4182 ecore_evas_selection_handlers[3] = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
4183 _ecore_evas_x_dnd_enter, NULL);
4184 ecore_evas_selection_handlers[4] = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE,
4185 _ecore_evas_x_dnd_leave, NULL);
4186 ecore_evas_selection_handlers[5] = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
4187 _ecore_evas_x_dnd_position, NULL);
4188 ecore_evas_selection_handlers[6] = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
4189 _ecore_evas_x_dnd_drop, NULL);
4190 ecore_evas_selection_handlers[7] = ecore_event_handler_add(ECORE_X_EVENT_XDND_FINISHED,
4191 _ecore_evas_x_finished, NULL);
4192 /* for us known type */
4193 char *supported_types[] = {
4194 "text/plain",
4195 "text/plain;charset=utf-8",
4196 "image/png",
4197 "image/jpeg",
4198 "image/x-ms-bmp",
4199 "image/gif",
4200 "image/tiff",
4201 "image/svg+xml",
4202 "image/x-xpixmap",
4203 "image/x-tga",
4204 "image/x-portable-pixmap",
4205 "TEXT",
4206 "COMPOUND_TEXT",
4207 "STRING",
4208 "UTF8_STRING",
4209 "text/x-vcard",
4210 "text/uri-list",
4211 "application/x-elementary-markup",
4212 "ATOM",
4213 "TARGETS",
4214 NULL
4215 };
4216 for (int i = 0; supported_types[i]; ++i)
4217 {
4218 ecore_x_selection_converter_add(supported_types[i], _eina_content_converter);
4219 }
4220}
4221
4222static Eina_Bool
4223_ecore_evas_x_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection)
4224{
4225 return !!ecore_x_selection_owner_get(ecore_evas_selection_to_atom[selection]);
4226}
4227
4228static void
4229_deliver_selection_changed(void *data)
4230{
4231 Ecore_Evas *ee = data;
4232 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
4233
4234 if (!ee->func.fn_selection_changed)
4235 goto end;
4236
4237 if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER))
4238 ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER);
4239 if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER))
4240 ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER);
4241 if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER))
4242 ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER);
4243end:
4244 edata->init_job = NULL;
4245}
4246
4247static void
4248_ecore_evas_x_selection_window_init(Ecore_Evas *ee)
4249{
4250 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
4251 for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i)
4252 {
4253 ecore_x_fixes_window_selection_notification_request(ee->prop.window, ecore_evas_selection_to_atom[i]);
4254 edata->selection_data[i].ee = ee;
4255 edata->selection_data[i].buffer = i;
4256 }
4257 ecore_x_dnd_aware_set(ee->prop.window, EINA_TRUE);
4258 edata->init_job = ecore_job_add(_deliver_selection_changed, ee);
4259}
4260
4261static void
4262_store_selection_cbs(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Eina_Bool (*delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice), void (*cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer))
4263{
4264 Ecore_Evas_X11_Selection_Data *sdata;
4265 Ecore_Evas_Engine_Data_X11 *edata;
4266 Ecore_Evas_Selection_Callbacks *cbs;
4267
4268 edata = ee->engine.data;
4269 sdata = &edata->selection_data[selection];
4270 cbs = &sdata->callbacks;
4271
4272 if (cbs->cancel)
4273 {
4274 _clear_selection(ee, selection);
4275 edata->skip_clean_event ++; //we are going to overwrite our own selection, this will emit a clean event, but we already freed it.
4276 }
4277
4278 cbs->delivery = delivery;
4279 cbs->cancel = cancel;
4280 cbs->available_types = available_types;
4281}
4282
4283static Eina_Bool
4284_ecore_evas_x_selection_claim(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Internal_Delivery delivery, Ecore_Evas_Internal_Cancel cancel)
4285{
4286 Ecore_Evas_X11_Selection_Data *sdata;
4287 Ecore_Evas_Engine_Data_X11 *edata;
4288
4289 edata = ee->engine.data;
4290 sdata = &edata->selection_data[selection];
4291
4292 _store_selection_cbs(ee, selection, available_types, delivery, cancel);
4293
4294 if (eina_array_count(available_types) > 0)
4295 {
4296 //the commands below will *copy* the content of sdata, this you have to ensure that clear is called when sdata is changed.
4297 if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)
4298 ecore_x_selection_primary_set(ee->prop.window, sdata, sizeof(Ecore_Evas_X11_Selection_Data));
4299 else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
4300 ecore_x_selection_clipboard_set(ee->prop.window, sdata, sizeof(Ecore_Evas_X11_Selection_Data));
4301 }
4302 else
4303 {
4304 if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)
4305 ecore_x_selection_primary_clear();
4306 else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
4307 ecore_x_selection_clipboard_clear();
4308 }
4309
4310 //for drag and drop, we are not calling anything in here
4311
4312 return EINA_TRUE;
4313}
4314
4315Eina_Future*
4316_ecore_evas_x_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type)
4317{
4318 Ecore_Evas_X11_Selection_Data *sdata;
4319 Ecore_Evas_Engine_Data_X11 *edata;
4320 Eina_Future *future;
4321
4322 edata = ee->engine.data;
4323 sdata = &edata->selection_data[selection];
4324
4325 if (sdata->delivery)
4326 {
4327 eina_promise_reject(sdata->delivery, ecore_evas_request_replaced);
4328 _clear_selection_delivery(ee, selection);
4329 }
4330 sdata->delivery = efl_loop_promise_new(efl_main_loop_get());
4331 sdata->acceptable_type = acceptable_type;
4332 future = eina_future_new(sdata->delivery);
4333
4334 if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
4335 {
4336 //when in dnd - we are requesting out of the set that we know from the enter event
4337 EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, NULL);
4338 EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, NULL);
4339 _search_fitting_type(ee, edata, selection, edata->xserver_atom_name_during_dnd);
4340 }
4341 else
4342 {
4343 //when not dnd - we are first wanting to know what is available
4344 _ecore_x_selection_request(ee->prop.window, selection, ECORE_X_SELECTION_TARGET_TARGETS);
4345 }
4346
4347 return future;
4348}
4349
4350static void
4351_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos)
4352{
4353 Ecore_Evas *ee = data;
4354 Eina_Rect rect;
4355
4356 ecore_evas_geometry_get(ee->drag.rep, &rect.x, &rect.y, &rect.w, &rect.h);
4357
4358 ecore_evas_move(ee->drag.rep, pos->position.x - rect.w / 2, pos->position.y - rect.h/2);
4359}
4360
4361static Eina_Bool
4362_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event EINA_UNUSED)
4363{
4364 Ecore_Evas *ee = data;
4365
4366 _force_stop_self_dnd(ee);
4367
4368 return EINA_TRUE;
4369}
4370
4371static Eina_Bool
4372_ecore_evas_x_dnd_start(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Array *available_types, Ecore_Evas *drag_rep, Eina_Bool (*delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice), void (*cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer), const char* action)
4373{
4374 Ecore_Evas_X11_Selection_Data *sdata;
4375 Ecore_Evas_Engine_Data_X11 *edata;
4376 Ecore_X_Atom actx;
4377
4378 edata = ee->engine.data;
4379 sdata = &edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER];
4380 _store_selection_cbs(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, available_types, delivery, cancel);
4381
4382 //first set all types we have
4383 ecore_x_dnd_types_set(ee->prop.window, NULL, 0);
4384 for (unsigned int i = 0; i < eina_array_count(available_types); ++i)
4385 {
4386 const char *xserver_mime_type = _mime_to_xserver_type(eina_array_data_get(available_types, i));
4387 ecore_x_dnd_type_set(ee->prop.window, xserver_mime_type, EINA_TRUE);
4388 eina_stringshare_del(xserver_mime_type);
4389 }
4390 ecore_x_dnd_aware_set(ee->prop.window, EINA_TRUE);
4391 ecore_x_dnd_callback_pos_update_set(_x11_drag_move, ee);
4392 ecore_x_dnd_self_begin(ee->prop.window, (unsigned char*)sdata, sizeof(Ecore_Evas_X11_Selection_Data));
4393 actx = _x11_dnd_action_rev_map(action);
4394 ecore_x_dnd_source_action_set(actx);
4395 ecore_x_pointer_grab(ee->prop.window);
4396
4397 ecore_x_window_ignore_set(drag_rep->prop.window, EINA_TRUE);
4398
4399 if (edata->mouse_up_handler)
4400 ecore_event_handler_del(edata->mouse_up_handler);
4401 edata->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
4402 _x11_drag_mouse_up, ee);
4403
4404 return EINA_TRUE;
4405}
4406
4407static Eina_Bool
4408_ecore_evas_x_dnd_stop(Ecore_Evas *ee, unsigned int seat EINA_UNUSED)
4409{
4410 _force_stop_self_dnd(ee);
4411 _clear_selection(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER);
4412 ecore_x_selection_xdnd_clear(); //This is needed otherwise a outdated sdata struct will be accessed
4413 return EINA_TRUE;
4414}
4415
3670static Ecore_Evas_Engine_Func _ecore_x_engine_func = 4416static Ecore_Evas_Engine_Func _ecore_x_engine_func =
3671{ 4417{
3672 _ecore_evas_x_free, 4418 _ecore_evas_x_free,
@@ -3754,9 +4500,11 @@ static Ecore_Evas_Engine_Func _ecore_x_engine_func =
3754 NULL, //fn_pointer_device_xy_get 4500 NULL, //fn_pointer_device_xy_get
3755 NULL, //fn_prepare 4501 NULL, //fn_prepare
3756 NULL, //fn_last_tick_get 4502 NULL, //fn_last_tick_get
3757 NULL, //fn_selection_claim 4503 _ecore_evas_x_selection_claim, //fn_selection_claim
3758 NULL, //fn_selection_has_owner 4504 _ecore_evas_x_selection_has_owner, //fn_selection_has_owner
3759 NULL, //fn_selection_request 4505 _ecore_evas_x_selection_request, //fn_selection_request
4506 _ecore_evas_x_dnd_start, //fn_dnd_start
4507 _ecore_evas_x_dnd_stop, //fn_dnd_stop
3760}; 4508};
3761 4509
3762/* 4510/*
@@ -4120,6 +4868,7 @@ ecore_evas_software_x11_new_internal(const char *disp_name, Ecore_X_Window paren
4120 _ecore_evas_x_wm_rotation_protocol_set(ee); 4868 _ecore_evas_x_wm_rotation_protocol_set(ee);
4121 _ecore_evas_x_aux_hints_supported_update(ee); 4869 _ecore_evas_x_aux_hints_supported_update(ee);
4122 _ecore_evas_x_aux_hints_update(ee); 4870 _ecore_evas_x_aux_hints_update(ee);
4871 _ecore_evas_x_selection_window_init(ee);
4123 4872
4124 ee->engine.func->fn_render = _ecore_evas_x_render; 4873 ee->engine.func->fn_render = _ecore_evas_x_render;
4125 ee->draw_block = EINA_TRUE; 4874 ee->draw_block = EINA_TRUE;
@@ -4556,6 +5305,7 @@ ecore_evas_gl_x11_options_new_internal(const char *disp_name, Ecore_X_Window par
4556 _ecore_evas_x_wm_rotation_protocol_set(ee); 5305 _ecore_evas_x_wm_rotation_protocol_set(ee);
4557 _ecore_evas_x_aux_hints_supported_update(ee); 5306 _ecore_evas_x_aux_hints_supported_update(ee);
4558 _ecore_evas_x_aux_hints_update(ee); 5307 _ecore_evas_x_aux_hints_update(ee);
5308 _ecore_evas_x_selection_window_init(ee);
4559 5309
4560 ee->draw_block = 1; 5310 ee->draw_block = 1;
4561 if (!wm_exists) edata->configured = 1; 5311 if (!wm_exists) edata->configured = 1;