implement wl->x11 dnd operations

seems to work fine, large selection data (ref T2330) still untested
This commit is contained in:
Mike Blumenkrantz 2015-08-07 21:06:47 -04:00
parent c696fa7088
commit 8e211f1950
3 changed files with 253 additions and 36 deletions

View File

@ -281,22 +281,40 @@ _e_comp_wl_data_device_drag_finished(E_Drag *drag, int dropped)
evas_object_hide(o);
evas_object_pass_events_set(o, 1);
if (e_comp->wl_comp_data->drag != drag) return;
if (e_comp->wl_comp_data->selection.target && (!dropped))
{
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);
}
}
e_comp->wl_comp_data->drag = NULL;
e_comp->wl_comp_data->drag_client = NULL;
e_comp->wl_comp_data->selection.target = NULL;
e_comp->wl_comp_data->drag_source = NULL;
e_screensaver_inhibit_toggle(0);
if (e_comp->wl_comp_data->selection.target && (!dropped))
{
#ifndef HAVE_WAYLAND_ONLY
if (e_client_has_xwindow(e_comp->wl_comp_data->selection.target))
{
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->selection.target),
ECORE_X_ATOM_XDND_DROP, ECORE_X_EVENT_MASK_NONE,
e_comp->cm_selection, 0, ecore_x_current_time_get(), 0, 0);
}
else
#endif
{
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);
}
#ifndef HAVE_WAYLAND_ONLY
if ((e_comp->comp_type != E_PIXMAP_TYPE_X) && e_comp_util_has_x())
{
ecore_x_selection_owner_set(0, ECORE_X_ATOM_SELECTION_XDND, 0);
ecore_x_window_hide(e_comp->cm_selection);
}
#endif
e_comp->wl_comp_data->selection.target = NULL;
e_comp->wl_comp_data->drag_source = NULL;
}
}
}
static void
@ -346,6 +364,13 @@ _e_comp_wl_data_device_cb_drag_start(struct wl_client *client, struct wl_resourc
if (ec)
e_drag_object_set(e_comp->wl_comp_data->drag, ec->frame);
e_drag_start(e_comp->wl_comp_data->drag, x, y);
#ifndef HAVE_WAYLAND_ONLY
if ((e_comp->comp_type != E_PIXMAP_TYPE_X) && e_comp_util_has_x())
{
ecore_x_window_show(e_comp->cm_selection);
ecore_x_selection_owner_set(e_comp->cm_selection, ECORE_X_ATOM_SELECTION_XDND, 0);
}
#endif
if (e_comp->wl_comp_data->ptr.ec)
e_comp_wl_data_device_send_enter(e_comp->wl_comp_data->ptr.ec);
e_screensaver_inhibit_toggle(1);
@ -675,38 +700,60 @@ e_comp_wl_data_device_send_enter(E_Client *ec)
uint32_t serial;
int x, y;
if (e_client_has_xwindow(ec)) return;
data_device_res =
e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));
if (!data_device_res) return;
offer_res = e_comp_wl_data_device_send_offer(ec);
if (e_comp->wl_comp_data->selection.data_source && (!offer_res)) return;
if (e_client_has_xwindow(ec) && e_client_has_xwindow(e_comp->wl_comp_data->drag_client)) return;
if (!e_client_has_xwindow(ec))
{
data_device_res =
e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));
if (!data_device_res) return;
offer_res = e_comp_wl_data_device_send_offer(ec);
if (e_comp->wl_comp_data->drag_source && (!offer_res)) return;
}
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))
if (e_client_has_xwindow(ec))
{
int d1 = 0x5UL, d2, d3, d4;
E_Comp_Wl_Data_Source *source;
Eina_List *l;
d2 = d3 = d4 = 0;
source = e_comp->wl_comp_data->drag_source;
if (e_comp->wl_comp_data->drag->num_types > 3)
d1 |= 0x1UL;
if (eina_list_count(source->mime_types) > 3)
{
const char *type, *types[eina_list_count(source->mime_types)];
int i = 0;
d1 |= 0x1UL;
EINA_LIST_FOREACH(source->mime_types, l, type)
types[i++] = type;
ecore_x_dnd_types_set(e_comp->cm_selection, types, i);
}
else
{
if (e_comp->wl_comp_data->drag->num_types > 0)
l = source->mime_types;
if (source->mime_types)
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]);
if (eina_list_count(source->mime_types) > 1)
{
l = eina_list_next(l);
d3 = ecore_x_atom_get(eina_list_data_get(l));
}
if (eina_list_count(source->mime_types) > 2)
{
l = eina_list_next(l);
d4 = ecore_x_atom_get(eina_list_data_get(l));
}
}
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client),
ecore_x_client_message32_send(e_client_util_win_get(ec),
ECORE_X_ATOM_XDND_ENTER, ECORE_X_EVENT_MASK_NONE,
e_comp->cm_selection, d1, d2, d3, d4);
return;
}
#endif
x = wl_fixed_to_int(e_comp->wl_comp_data->ptr.x) - e_comp->wl_comp_data->selection.target->client.x;
@ -721,16 +768,17 @@ e_comp_wl_data_device_send_leave(E_Client *ec)
{
struct wl_resource *res;
if (e_client_has_xwindow(ec)) return;
if (e_client_has_xwindow(ec) && e_client_has_xwindow(e_comp->wl_comp_data->drag_client)) return;
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))
if (e_client_has_xwindow(ec))
{
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->drag_client),
ecore_x_client_message32_send(e_client_util_win_get(ec),
ECORE_X_ATOM_XDND_LEAVE, ECORE_X_EVENT_MASK_NONE,
e_comp->cm_selection, 0, 0, 0, 0);
return;
}
#endif
res = e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));

View File

@ -1218,8 +1218,9 @@ _e_dnd_cb_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
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),
if (!e_client_has_xwindow(e_comp->wl_comp_data->ptr.ec)) return ECORE_CALLBACK_RENEW;
if (e_client_has_xwindow(e_comp->wl_comp_data->drag_client)) return ECORE_CALLBACK_RENEW;
ecore_x_client_message32_send(e_client_util_win_get(e_comp->wl_comp_data->ptr.ec),
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);

View File

@ -3,14 +3,39 @@
#include <dlfcn.h>
#define WL_TEXT_STR "text/plain;charset=utf-8"
#define INCR_CHUNK_SIZE 1 << 17
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 Ecore_X_Atom timestamp_atom;
static Ecore_X_Atom incr_atom;
static Ecore_X_Atom int_atom;
static int32_t cur_fd = -1;
static Eina_List *handlers;
static Eina_Hash *pipes;
typedef struct
{
Ecore_Fd_Handler *fdh;
E_Comp_Wl_Data_Source *source;
Ecore_X_Window win;
Ecore_X_Atom atom;
Ecore_X_Atom selection;
Ecore_X_Atom property;
Eina_Binbuf *buf;
Eina_Bool incr : 1;
} Pipe;
static void
_pipe_free(Pipe *p)
{
ecore_main_fd_handler_del(p->fdh);
eina_binbuf_free(p->buf);
free(p);
}
static void
_xdnd_finish(Eina_Bool success)
@ -19,6 +44,24 @@ _xdnd_finish(Eina_Bool success)
e_comp->cm_selection, !!success, (!!success) * ECORE_X_ATOM_XDND_ACTION_COPY, 0, 0);
}
static void
_incr_update(Pipe *p, Eina_Bool success)
{
ecore_x_selection_notify_send(p->win, p->selection, p->atom, (!!success) * p->property, 0);
}
static void
_incr_upload(Pipe *p)
{
size_t size;
size = eina_binbuf_length_get(p->buf);
size = MIN(size, INCR_CHUNK_SIZE);
ecore_x_window_prop_property_set(p->win, p->property, p->atom, 8, (void*)eina_binbuf_string_get(p->buf), size);
eina_binbuf_free(p->buf);
p->buf = NULL;
}
static void
_xwayland_dnd_finish(void)
{
@ -46,8 +89,6 @@ _xwayland_drop(E_Drag *drag, int dropped)
{
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;
}
@ -90,6 +131,7 @@ _xwayland_cancelled_send(E_Comp_Wl_Data_Source *source)
static Eina_Bool
_xwl_fixes_selection_notify(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Fixes_Selection_Notify *ev)
{
if (ev->owner == e_comp->cm_selection) return ECORE_CALLBACK_RENEW;
if (ev->atom == ECORE_X_ATOM_SELECTION_XDND)
{
if (ev->owner)
@ -189,6 +231,125 @@ _xwl_selection_notify(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Sele
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_xwl_pipe_read(void *data, Ecore_Fd_Handler *fdh)
{
Pipe *p = data;
ssize_t len;
unsigned char *buf;
buf = malloc(INCR_CHUNK_SIZE);
len = read(ecore_main_fd_handler_fd_get(fdh), (void*)buf, INCR_CHUNK_SIZE);
if (len < 0)
{
_incr_update(p, 0);
eina_hash_del_by_key(pipes, &p->win);
}
if (len == INCR_CHUNK_SIZE)
{
p->buf = eina_binbuf_manage_new(buf, len, 0);
if (p->incr)
_incr_upload(p);
else
{
unsigned long size = INCR_CHUNK_SIZE;
p->incr = 1;
ecore_x_window_prop_property_set(p->win, p->atom, incr_atom, 32, &size, 1);
_incr_update(p, 1);
}
ecore_main_fd_handler_active_set(p->fdh, 0);
return ECORE_CALLBACK_RENEW;
}
if (len)
p->buf = eina_binbuf_manage_new(buf, len, 0);
_incr_upload(p);
if (p->incr)
ecore_main_fd_handler_active_set(p->fdh, 0);
else
{
_incr_update(p, 1);
eina_hash_del_by_key(pipes, &p->win);
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_xwl_selection_request(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Selection_Request *ev)
{
E_Comp_Wl_Data_Source *source;
const char *type;
Eina_List *l;
if (!e_comp->wl_comp_data->drag_source) return ECORE_CALLBACK_RENEW;
source = e_comp->wl_comp_data->drag_source;
if (ev->target == ECORE_X_ATOM_SELECTION_TARGETS)
{
Ecore_X_Atom *atoms;
int i = 0;
atoms = alloca((2 + eina_list_count(source->mime_types)) * sizeof(void*));
EINA_LIST_FOREACH(source->mime_types, l, type)
atoms[i++] = ecore_x_atom_get(type);
atoms[i++] = timestamp_atom;
atoms[i++] = ECORE_X_ATOM_SELECTION_TARGETS;
ecore_x_window_prop_property_set(ev->requestor, ev->property, ECORE_X_ATOM_ATOM, 32, atoms, i);
ecore_x_selection_notify_send(ev->requestor, ev->selection, ev->target, ev->property, 0);
}
else if (ev->target == timestamp_atom)
{
Ecore_X_Time timestamp;
timestamp = ecore_x_current_time_get();
ecore_x_window_prop_property_set(ev->requestor, ev->property, int_atom, 32, (void*)&timestamp, 1);
ecore_x_selection_notify_send(ev->requestor, ev->selection, ev->target, ev->property, 0);
}
else
{
const char *name;
Pipe *p;
name = ecore_x_atom_name_get(ev->target);
EINA_LIST_FOREACH(source->mime_types, l, type)
if (eina_streq(name, type))
{
E_Client *ec;
int fds[2];
p = E_NEW(Pipe, 1);
socketpair(AF_UNIX, (SOCK_STREAM | SOCK_CLOEXEC), 0, fds);
fcntl(fds[0], F_SETFL, O_NONBLOCK);
p->fdh = ecore_main_fd_handler_add(fds[0], ECORE_FD_READ, _xwl_pipe_read, p, NULL, NULL);
p->win = ev->requestor;
p->source = source;
wl_data_source_send_send(source->resource, type, dup(fds[1]));
close(fds[1]);
p->atom = ev->target;
p->selection = ev->selection;
p->property = ev->property;
ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ev->requestor);
if (ec && ec->override)
ecore_x_window_sniff(ev->requestor);
eina_hash_add(pipes, &p->win, p);
break;
}
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_xwl_property(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Window_Property *ev)
{
Pipe *p;
p = eina_hash_find(pipes, &ev->win);
if (!p) return ECORE_CALLBACK_RENEW;
/* FIXME: WHO FORGOT THE FUCKING STATE FLAG???? */
ecore_main_fd_handler_active_set(p->fdh, ECORE_FD_READ);
return ECORE_CALLBACK_RENEW;
}
EINTERN void
dnd_init(void)
{
@ -196,9 +357,15 @@ dnd_init(void)
ecore_x_fixes_selection_notification_request(ECORE_X_ATOM_SELECTION_XDND);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, _xwl_fixes_selection_notify, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SELECTION_NOTIFY, _xwl_selection_notify, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SELECTION_REQUEST, _xwl_selection_request, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_PROPERTY, _xwl_property, NULL);
xconvertselection = dlsym(NULL, "XConvertSelection");
string_atom = ecore_x_atom_get("UTF8_STRING");
timestamp_atom = ecore_x_atom_get("TIMESTAMP");
int_atom = ecore_x_atom_get("INTEGER");
incr_atom = ecore_x_atom_get("TIMESTAMP");
xwl_dnd_atom = ecore_x_atom_get("E_XWL_DND_ATOM_HAHA");
pipes = eina_hash_int32_new((Eina_Free_Cb)_pipe_free);
e_comp_shape_queue();
}
@ -206,4 +373,5 @@ EINTERN void
dnd_shutdown(void)
{
E_FREE_LIST(handlers, ecore_event_handler_del);
E_FREE_FUNC(pipes, eina_hash_free);
}