diff --git a/src/bin/e_comp_wl_data.c b/src/bin/e_comp_wl_data.c index 11d5c7841..d42fb0c91 100644 --- a/src/bin/e_comp_wl_data.c +++ b/src/bin/e_comp_wl_data.c @@ -685,6 +685,30 @@ e_comp_wl_data_device_send_enter(E_Client *ec) e_comp->wl_comp_data->selection.target = ec; evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_DEL, _e_comp_wl_data_device_target_del, ec); +#ifndef HAVE_WAYLAND_ONLY + if (e_client_has_xwindow(e_comp->wl_comp_data->drag_client)) + { + int d1 = 0x5UL, d2, d3, d4; + + d2 = d3 = d4 = 0; + + if (e_comp->wl_comp_data->drag->num_types > 3) + d1 |= 0x1UL; + else + { + if (e_comp->wl_comp_data->drag->num_types > 0) + d2 = ecore_x_atom_get(e_comp->wl_comp_data->drag->types[0]); + if (e_comp->wl_comp_data->drag->num_types > 1) + d3 = ecore_x_atom_get(e_comp->wl_comp_data->drag->types[1]); + if (e_comp->wl_comp_data->drag->num_types > 2) + d4 = ecore_x_atom_get(e_comp->wl_comp_data->drag->types[2]); + } + + ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client), + ECORE_X_ATOM_XDND_ENTER, ECORE_X_EVENT_MASK_NONE, + e_comp->cm_selection, d1, d2, d3, d4); + } +#endif x = wl_fixed_to_int(e_comp->wl_comp_data->ptr.x) - e_comp->wl_comp_data->selection.target->client.x; y = wl_fixed_to_int(e_comp->wl_comp_data->ptr.y) - e_comp->wl_comp_data->selection.target->client.y; serial = wl_display_next_serial(e_comp->wl_comp_data->wl.disp); @@ -701,8 +725,17 @@ e_comp_wl_data_device_send_leave(E_Client *ec) evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_DEL, _e_comp_wl_data_device_target_del, ec); if (e_comp->wl_comp_data->selection.target == ec) e_comp->wl_comp_data->selection.target = NULL; +#ifndef HAVE_WAYLAND_ONLY + if (e_client_has_xwindow(e_comp->wl_comp_data->drag_client)) + { + ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client), + ECORE_X_ATOM_XDND_LEAVE, ECORE_X_EVENT_MASK_NONE, + e_comp->cm_selection, 0, 0, 0, 0); + } +#endif res = e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface)); - wl_data_device_send_leave(res); + if (res) + wl_data_device_send_leave(res); } EINTERN void * diff --git a/src/bin/e_dnd.c b/src/bin/e_dnd.c index a8f5d69aa..167515e15 100644 --- a/src/bin/e_dnd.c +++ b/src/bin/e_dnd.c @@ -227,6 +227,8 @@ e_dnd_init(void) if (e_comp->comp_type == E_PIXMAP_TYPE_X) e_drop_xdnd_register_set(e_comp->ee_win, 1); + else + e_drop_xdnd_register_set(e_comp->cm_selection, 1); _action = ECORE_X_ATOM_XDND_ACTION_PRIVATE; #endif @@ -1211,6 +1213,18 @@ _e_dnd_cb_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) if (!_xdnd) _e_drag_update(_drag_win_root, ev->x, ev->y, _action ?: ECORE_X_ATOM_XDND_ACTION_PRIVATE); +# ifdef HAVE_WAYLAND + if ((e_comp->comp_type == E_PIXMAP_TYPE_WL) && e_comp_util_has_x()) + { + if (e_comp->wl_comp_data->drag != _drag_current) return ECORE_CALLBACK_RENEW; + if (!e_comp->wl_comp_data->ptr.ec) return ECORE_CALLBACK_RENEW; + if (e_client_has_xwindow(e_comp->wl_comp_data->ptr.ec)) return ECORE_CALLBACK_RENEW; + ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client), + ECORE_X_ATOM_XDND_POSITION, ECORE_X_EVENT_MASK_NONE, + e_comp->cm_selection, 0, ((ev->x << 16) & 0xffff0000) | (ev->y & 0xffff), + ev->timestamp, ECORE_X_ATOM_XDND_ACTION_COPY); + } +# endif #endif return ECORE_CALLBACK_PASS_ON; @@ -1421,6 +1435,7 @@ _e_dnd_cb_event_dnd_selection(void *data EINA_UNUSED, int type EINA_UNUSED, void if (!eina_hash_find(_drop_win_hash, &ev->win)) return ECORE_CALLBACK_PASS_ON; if (ev->selection != ECORE_X_SELECTION_XDND) return ECORE_CALLBACK_PASS_ON; + if (e_comp->comp_type != E_PIXMAP_TYPE_X) return ECORE_CALLBACK_RENEW; if (!_xdnd) { diff --git a/src/modules/Makefile_xwayland.mk b/src/modules/Makefile_xwayland.mk index 5afc15b56..56fd137fa 100644 --- a/src/modules/Makefile_xwayland.mk +++ b/src/modules/Makefile_xwayland.mk @@ -13,7 +13,8 @@ src_modules_xwayland_module_la_LIBADD = $(MOD_LIBS) @XWAYLAND_LIBS@ @WAYLAND_L src_modules_xwayland_module_la_LDFLAGS = $(MOD_LDFLAGS) src_modules_xwayland_module_la_SOURCES = \ -src/modules/xwayland/e_mod_main.c +src/modules/xwayland/e_mod_main.c \ +src/modules/xwayland/dnd.c PHONIES += xwayland install-xwayland xwayland: $(xwaylandpkg_LTLIBRARIES) diff --git a/src/modules/xwayland/dnd.c b/src/modules/xwayland/dnd.c new file mode 100644 index 000000000..69ae9b515 --- /dev/null +++ b/src/modules/xwayland/dnd.c @@ -0,0 +1,202 @@ +#define E_COMP_WL +#include "e.h" +#include + +#define WL_TEXT_STR "text/plain;charset=utf-8" + +static void (*xconvertselection)(Ecore_X_Display *, Ecore_X_Atom, Ecore_X_Atom, Ecore_X_Atom, Ecore_X_Window, Ecore_X_Time); +static Ecore_X_Atom string_atom; +static Ecore_X_Atom xwl_dnd_atom; + +static int32_t cur_fd = -1; + +static void +_xdnd_finish(Eina_Bool success) +{ + ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client), ECORE_X_ATOM_XDND_FINISHED, ECORE_X_EVENT_MASK_NONE, + e_comp->cm_selection, !!success, (!!success) * ECORE_X_ATOM_XDND_ACTION_COPY, 0, 0); +} + +static void +_xwayland_dnd_finish(void) +{ + ecore_x_window_hide(e_comp->cm_selection); + ecore_x_window_prop_property_del(e_comp->cm_selection, ECORE_X_ATOM_XDND_TYPE_LIST); + e_comp->wl_comp_data->drag_client = NULL; + e_comp->wl_comp_data->drag_source = NULL; + cur_fd = -1; +} + +static void +_xwayland_drop(E_Drag *drag, int dropped) +{ + if (e_comp->comp_type != E_PIXMAP_TYPE_WL) return; + e_comp->wl_comp_data->drag = NULL; + if (e_object_is_del(E_OBJECT(drag)) || (!e_comp->wl_comp_data->selection.target)) + _xdnd_finish(0); + else + { + struct wl_resource *res; + + res = e_comp_wl_data_find_for_client(wl_resource_get_client(e_comp->wl_comp_data->selection.target->comp_data->surface)); + if (res) + { + wl_data_device_send_drop(res); + wl_data_device_send_leave(res); + ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client), ECORE_X_ATOM_XDND_DROP, ECORE_X_EVENT_MASK_NONE, + e_comp->cm_selection, 0, ecore_x_current_time_get(), 0, 0); + } + return; + } + _xwayland_dnd_finish(); +} + +static void +_xwayland_target_send(E_Comp_Wl_Data_Source *source, uint32_t serial EINA_UNUSED, const char* mime_type) +{ + DBG("XWL Data Source Target Send"); + ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client), ECORE_X_ATOM_XDND_STATUS, ECORE_X_EVENT_MASK_NONE, + e_comp->cm_selection, 2 | !!mime_type, 0, 0, (!!mime_type) * ECORE_X_ATOM_XDND_ACTION_COPY); +} + +static void +_xwayland_send_send(E_Comp_Wl_Data_Source *source, const char* mime_type, int32_t fd) +{ + Ecore_X_Atom type; + + DBG("XWL Data Source Source Send"); + + _xdnd_finish(0); + + if (eina_streq(mime_type, WL_TEXT_STR)) + type = string_atom; + else + type = ecore_x_atom_get(mime_type); + + cur_fd = fd; + xconvertselection(ecore_x_display_get(), ECORE_X_ATOM_SELECTION_XDND, type, xwl_dnd_atom, e_comp->cm_selection, 0); +} + +static void +_xwayland_cancelled_send(E_Comp_Wl_Data_Source *source) +{ + DBG("XWL Data Source Cancelled Send"); + e_object_del(E_OBJECT(e_comp->wl_comp_data->drag)); +} + +static Eina_Bool +_xwl_fixes_selection_notify(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Fixes_Selection_Notify *ev) +{ + if (ev->atom == ECORE_X_ATOM_SELECTION_XDND) + { + if (ev->owner) + { + int x, y, num; + unsigned char *data; + const char **names = NULL; + Eina_List *namelist = NULL; + E_Comp_Wl_Data_Source *source; + + if (ecore_x_window_prop_property_get(ev->owner, + ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, + 32, + &data, + &num)) + { + int i; + Ecore_X_Atom *types = (void*)data; + + names = malloc(num * sizeof(void*)); + for (i = 0; i < num; i++) + { + const char *name; + + if (types[i] == string_atom) + { + name = names[i] = "UTF8_STRING"; + namelist = eina_list_append(namelist, eina_stringshare_add(WL_TEXT_STR)); + } + else + names[i] = name = ecore_x_atom_name_get(types[i]); + namelist = eina_list_append(namelist, eina_stringshare_add(name)); + } + if (num > 3) + { + ecore_x_window_prop_property_set(e_comp->cm_selection, + ECORE_X_ATOM_XDND_TYPE_LIST, ECORE_X_ATOM_ATOM, 32, names, num); + } + + free(data); + } + evas_pointer_canvas_xy_get(e_comp->evas, &x, &y); + e_comp->wl_comp_data->drag_client = e_pixmap_find_client(E_PIXMAP_TYPE_X, ev->owner); + e_comp->wl_comp_data->drag = e_drag_new(x, y, names, num, NULL, 0, NULL, _xwayland_drop); + ecore_x_window_move_resize(e_comp->cm_selection, 0, 0, e_comp->w, e_comp->h); + ecore_x_window_show(e_comp->cm_selection); + e_drag_start(e_comp->wl_comp_data->drag, x, y); + if (e_comp->wl_comp_data->ptr.ec) + e_comp_wl_data_device_send_enter(e_comp->wl_comp_data->ptr.ec); + e_comp_canvas_feed_mouse_up(0); + source = e_comp_wl_data_manager_source_create(e_comp->wl_comp_data->xwl_client, + e_comp->wl_comp_data->mgr.resource, 1); + e_comp->wl_comp_data->drag_source = source; + source->target = _xwayland_target_send; + source->send = _xwayland_send_send; + source->cancelled = _xwayland_cancelled_send; + source->mime_types = namelist; + free(names); + } + else + { + if (e_comp->wl_comp_data->drag) + e_object_del(E_OBJECT(e_comp->wl_comp_data->drag)); + ecore_x_window_hide(e_comp->cm_selection); + e_comp->wl_comp_data->drag = NULL; + e_comp->wl_comp_data->drag_client = NULL; + } + e_screensaver_inhibit_toggle(!!ev->owner); + return ECORE_CALLBACK_RENEW; + } + //if (ev->atom == ECORE_X_ATOM_SELECTION_CLIPBOARD) + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_xwl_selection_notify(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Selection_Notify *ev) +{ + Ecore_X_Selection_Data *sd; + int wrote = 0; + + DBG("XWL SELECTION NOTIFY"); + if ((ev->selection != ECORE_X_SELECTION_XDND) && (ev->selection == ECORE_X_SELECTION_CLIPBOARD)) + { + e_object_del(E_OBJECT(e_comp->wl_comp_data->drag)); + return ECORE_CALLBACK_RENEW; + } + /* FIXME: ecore-x events are fucked */ + //if (ecore_x_atom_get(ev->target) != xwl_dnd_atom) return ECORE_CALLBACK_RENEW; + sd = ev->data; + + do + { + wrote += write(cur_fd, sd->data, sd->length); + } while (wrote < sd->length); + _xdnd_finish(1); + close(cur_fd); + _xwayland_dnd_finish(); + return ECORE_CALLBACK_RENEW; +} + +EINTERN void +dnd_init(void) +{ + ecore_x_fixes_selection_notification_request(ecore_x_atom_get("CLIPBOARD")); + ecore_x_fixes_selection_notification_request(ECORE_X_ATOM_SELECTION_XDND); + ecore_event_handler_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, (Ecore_Event_Handler_Cb)_xwl_fixes_selection_notify, NULL); + ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, (Ecore_Event_Handler_Cb)_xwl_selection_notify, NULL); + xconvertselection = dlsym(NULL, "XConvertSelection"); + string_atom = ecore_x_atom_get("UTF8_STRING"); + xwl_dnd_atom = ecore_x_atom_get("E_XWL_DND_ATOM_HAHA"); + e_comp_shape_queue(); +} diff --git a/src/modules/xwayland/e_mod_main.c b/src/modules/xwayland/e_mod_main.c index 5926ad691..8cacc27db 100644 --- a/src/modules/xwayland/e_mod_main.c +++ b/src/modules/xwayland/e_mod_main.c @@ -3,6 +3,8 @@ #include #include +EINTERN void dnd_init(void); + /* local structures */ typedef struct _E_XWayland_Server E_XWayland_Server; struct _E_XWayland_Server @@ -256,6 +258,7 @@ xnotify(void *d EINA_UNUSED, Ecore_Thread *eth EINA_UNUSED, void *disp) } assert(ecore_x_init_from_display(disp)); e_comp_x_init(); + dnd_init(); } static void