Implement selection copy & paste using data interfaces of wayland
Summary: It supports selection copy & pasete with wl_data_device_manager, wl_data_device, wl_data_offer and wl_data_source. Test Plan: 1. Build enlightenment on devs/devilhorns/e_comp_wl branch. 2. Run enlightenment. 3. Run elementary_test -to entry5 (or any entry samples). 4. Select any block of text. 5. Do copy the block and Copy anywhere you want. Reviewers: gwanglim, devilhorns CC: cedric Differential Revision: https://phab.enlightenment.org/D1094
This commit is contained in:
parent
8bd30c9b98
commit
450206b599
|
@ -107,8 +107,17 @@ struct _E_Comp_Wl_Data
|
|||
struct
|
||||
{
|
||||
struct wl_global *global;
|
||||
Eina_List *data_resource_list;
|
||||
} mgr;
|
||||
|
||||
struct
|
||||
{
|
||||
void *data_source;
|
||||
uint32_t serial;
|
||||
struct wl_signal signal;
|
||||
struct wl_listener data_source_listener;
|
||||
} selection;
|
||||
|
||||
struct
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
|
|
|
@ -2,6 +2,186 @@
|
|||
#include "e_comp_wl.h"
|
||||
#include "e_comp_wl_data.h"
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_offer_cb_accept(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *mime_type)
|
||||
{
|
||||
E_Comp_Wl_Data_Offer *offer;
|
||||
|
||||
if (!(offer = wl_resource_get_user_data(resource)))
|
||||
return;
|
||||
|
||||
if (offer->source)
|
||||
offer->source->target(offer->source, serial, mime_type);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_offer_cb_receive(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *mime_type, int32_t fd)
|
||||
{
|
||||
E_Comp_Wl_Data_Offer *offer;
|
||||
|
||||
if (!(offer = wl_resource_get_user_data(resource)))
|
||||
return;
|
||||
|
||||
if (offer->source)
|
||||
offer->source->send(offer->source, mime_type, fd);
|
||||
else
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* called by wl_data_offer_destroy */
|
||||
static void
|
||||
_e_comp_wl_data_offer_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
/* called by wl_resource_destroy */
|
||||
static void
|
||||
_e_comp_wl_data_offer_cb_resource_destroy(struct wl_resource *resource)
|
||||
{
|
||||
E_Comp_Wl_Data_Offer *offer;
|
||||
|
||||
if (!(offer = wl_resource_get_user_data(resource)))
|
||||
return;
|
||||
|
||||
if (offer->source)
|
||||
wl_list_remove(&offer->source_destroy_listener.link);
|
||||
|
||||
free(offer);
|
||||
}
|
||||
|
||||
/* called by emission of source->destroy_signal */
|
||||
static void
|
||||
_e_comp_wl_data_offer_cb_source_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
|
||||
{
|
||||
E_Comp_Wl_Data_Offer *offer;
|
||||
|
||||
offer = container_of(listener, E_Comp_Wl_Data_Offer, source_destroy_listener);
|
||||
offer->source = NULL;
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_interface _e_data_offer_interface =
|
||||
{
|
||||
_e_comp_wl_data_offer_cb_accept,
|
||||
_e_comp_wl_data_offer_cb_receive,
|
||||
_e_comp_wl_data_offer_cb_destroy,
|
||||
};
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_source_cb_offer(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *mime_type)
|
||||
{
|
||||
E_Comp_Wl_Data_Source *source;
|
||||
|
||||
if (!(source = wl_resource_get_user_data(resource)))
|
||||
return;
|
||||
|
||||
source->mime_types = eina_list_append(source->mime_types, eina_stringshare_add(mime_type));
|
||||
}
|
||||
|
||||
/* called by wl_data_source_destroy */
|
||||
static void
|
||||
_e_comp_wl_data_source_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
/* called by wl_resource_destroy */
|
||||
static void
|
||||
_e_comp_wl_data_source_cb_resource_destroy(struct wl_resource *resource)
|
||||
{
|
||||
E_Comp_Wl_Data_Source *source;
|
||||
char *t;
|
||||
|
||||
if (!(source = wl_resource_get_user_data(resource)))
|
||||
return;
|
||||
|
||||
wl_signal_emit(&source->destroy_signal, source);
|
||||
|
||||
EINA_LIST_FREE(source->mime_types, t)
|
||||
eina_stringshare_del(t);
|
||||
|
||||
free(source);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_source_target_send(E_Comp_Wl_Data_Source *source, uint32_t serial EINA_UNUSED, const char* mime_type)
|
||||
{
|
||||
wl_data_source_send_target(source->resource, mime_type);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_source_send_send(E_Comp_Wl_Data_Source *source, const char* mime_type, int32_t fd)
|
||||
{
|
||||
wl_data_source_send_send(source->resource, mime_type, fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_source_cancelled_send(E_Comp_Wl_Data_Source *source)
|
||||
{
|
||||
wl_data_source_send_cancelled(source->resource);
|
||||
}
|
||||
|
||||
static const struct wl_data_source_interface _e_data_source_interface =
|
||||
{
|
||||
_e_comp_wl_data_source_cb_offer,
|
||||
_e_comp_wl_data_source_cb_destroy,
|
||||
};
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_device_destroy_selection_data_source(struct wl_listener *listener, void *data)
|
||||
{
|
||||
E_Comp_Wl_Data *cdata;
|
||||
E_Comp_Wl_Data_Source *source;
|
||||
struct wl_resource *data_device_res;
|
||||
|
||||
if (!(source = (E_Comp_Wl_Data_Source*)data))
|
||||
return;
|
||||
|
||||
if (!(cdata = container_of(listener, E_Comp_Wl_Data, selection.data_source_listener)))
|
||||
return;
|
||||
|
||||
cdata->selection.data_source = NULL;
|
||||
|
||||
/* TODO: get data device from a focused surface */
|
||||
data_device_res = _e_comp_wl_data_find_for_client(cdata->mgr.data_resource_list, wl_resource_get_client(source->resource));
|
||||
|
||||
if (data_device_res)
|
||||
wl_data_device_send_selection(data_device_res, NULL);
|
||||
|
||||
wl_signal_emit(&cdata->selection.signal, cdata);
|
||||
}
|
||||
|
||||
static struct wl_resource*
|
||||
_e_comp_wl_data_device_data_offer_create(E_Comp_Wl_Data_Source *source, struct wl_resource *data_device_res)
|
||||
{
|
||||
E_Comp_Wl_Data_Offer *offer;
|
||||
Eina_List *l;
|
||||
char *t;
|
||||
|
||||
offer = E_NEW(E_Comp_Wl_Data_Offer, 1);
|
||||
if (!offer) return NULL;
|
||||
|
||||
offer->resource = wl_resource_create(wl_resource_get_client(data_device_res), &wl_data_offer_interface, 1, 0);
|
||||
if (!offer->resource)
|
||||
{
|
||||
free(offer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation(offer->resource, &_e_data_offer_interface, offer, _e_comp_wl_data_offer_cb_resource_destroy);
|
||||
offer->source = source;
|
||||
offer->source_destroy_listener.notify = _e_comp_wl_data_offer_cb_source_destroy;
|
||||
wl_signal_add(&source->destroy_signal, &offer->source_destroy_listener);
|
||||
|
||||
wl_data_device_send_data_offer(data_device_res, offer->resource);
|
||||
|
||||
EINA_LIST_FOREACH(source->mime_types, l, t)
|
||||
wl_data_offer_send_offer(offer->resource, t);
|
||||
|
||||
return offer->resource;
|
||||
}
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_device_cb_drag_start(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, struct wl_resource *source_resource EINA_UNUSED, struct wl_resource *origin_resource EINA_UNUSED, struct wl_resource *icon_resource EINA_UNUSED, uint32_t serial EINA_UNUSED)
|
||||
{
|
||||
|
@ -11,7 +191,51 @@ _e_comp_wl_data_device_cb_drag_start(struct wl_client *client EINA_UNUSED, struc
|
|||
static void
|
||||
_e_comp_wl_data_device_cb_selection_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, struct wl_resource *source_resource EINA_UNUSED, uint32_t serial EINA_UNUSED)
|
||||
{
|
||||
E_Comp_Wl_Data *cdata;
|
||||
E_Comp_Wl_Data_Source *source, *sel_source;
|
||||
struct wl_resource *offer_res, *data_device_res;
|
||||
|
||||
if (!source_resource) return;
|
||||
if (!(cdata = wl_resource_get_user_data(resource))) return;
|
||||
|
||||
source = wl_resource_get_user_data(source_resource);
|
||||
sel_source = (E_Comp_Wl_Data_Source*)cdata->selection.data_source;
|
||||
|
||||
if ((sel_source) &&
|
||||
(cdata->selection.serial - serial < UINT32_MAX / 2))
|
||||
return;
|
||||
|
||||
if (sel_source)
|
||||
{
|
||||
if (sel_source->cancelled)
|
||||
sel_source->cancelled(sel_source);
|
||||
wl_list_remove(&cdata->selection.data_source_listener.link);
|
||||
cdata->selection.data_source = NULL;
|
||||
}
|
||||
|
||||
cdata->selection.data_source = sel_source = source;
|
||||
cdata->selection.serial = serial;
|
||||
|
||||
/* TODO: get data device from a focused surface */
|
||||
data_device_res = _e_comp_wl_data_find_for_client(cdata->mgr.data_resource_list, wl_resource_get_client(source->resource));
|
||||
|
||||
if ((data_device_res) && (source))
|
||||
{
|
||||
offer_res = _e_comp_wl_data_device_data_offer_create(source, data_device_res);
|
||||
wl_data_device_send_selection(data_device_res, offer_res);
|
||||
}
|
||||
else if (data_device_res)
|
||||
{
|
||||
wl_data_device_send_selection(data_device_res, NULL);
|
||||
}
|
||||
|
||||
wl_signal_emit(&cdata->selection.signal, cdata);
|
||||
|
||||
if (source)
|
||||
{
|
||||
cdata->selection.data_source_listener.notify = _e_comp_wl_data_device_destroy_selection_data_source;
|
||||
wl_signal_add(&source->destroy_signal, &cdata->selection.data_source_listener);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_data_device_interface _e_data_device_interface =
|
||||
|
@ -21,13 +245,46 @@ static const struct wl_data_device_interface _e_data_device_interface =
|
|||
};
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_manager_cb_source_create(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, uint32_t id EINA_UNUSED)
|
||||
_e_comp_wl_data_device_cb_unbind(struct wl_resource *resource)
|
||||
{
|
||||
/* NB: New resource */
|
||||
E_Comp_Wl_Data *cdata;
|
||||
|
||||
if(!(cdata = wl_resource_get_user_data(resource)))
|
||||
return;
|
||||
|
||||
cdata->mgr.data_resource_list = eina_list_remove(cdata->mgr.data_resource_list, resource);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_manager_cb_device_get(struct wl_client *client EINA_UNUSED, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource)
|
||||
_e_comp_wl_data_manager_cb_source_create(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t id EINA_UNUSED)
|
||||
{
|
||||
E_Comp_Wl_Data_Source *source;
|
||||
|
||||
source = E_NEW(E_Comp_Wl_Data_Source, 1);
|
||||
if (!source)
|
||||
{
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_signal_init(&source->destroy_signal);
|
||||
source->target = _e_comp_wl_data_source_target_send;
|
||||
source->send = _e_comp_wl_data_source_send_send;
|
||||
source->cancelled = _e_comp_wl_data_source_cancelled_send;
|
||||
|
||||
source->resource = wl_resource_create(client, &wl_data_source_interface, 1, id);
|
||||
if (!source->resource)
|
||||
{
|
||||
ERR("Could not create data source resource: %m");
|
||||
free(source);
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(source->resource, &_e_data_source_interface, source, _e_comp_wl_data_source_cb_resource_destroy);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_comp_wl_data_manager_cb_device_get(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource)
|
||||
{
|
||||
E_Comp_Wl_Data *cdata;
|
||||
struct wl_resource *res;
|
||||
|
@ -46,7 +303,8 @@ _e_comp_wl_data_manager_cb_device_get(struct wl_client *client EINA_UNUSED, stru
|
|||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation(res, &_e_data_device_interface, cdata, NULL);
|
||||
cdata->mgr.data_resource_list = eina_list_append(cdata->mgr.data_resource_list, res);
|
||||
wl_resource_set_implementation(res, &_e_data_device_interface, cdata, _e_comp_wl_data_device_cb_unbind);
|
||||
}
|
||||
|
||||
static const struct wl_data_device_manager_interface _e_manager_interface =
|
||||
|
@ -105,6 +363,8 @@ e_comp_wl_data_manager_init(E_Comp_Wl_Data *cdata)
|
|||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
wl_signal_init(&cdata->selection.signal);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,29 @@
|
|||
# ifndef E_COMP_WL_DATA_H
|
||||
# define E_COMP_WL_DATA_H
|
||||
|
||||
typedef struct _E_Comp_Wl_Data_Source E_Comp_Wl_Data_Source;
|
||||
typedef struct _E_Comp_Wl_Data_Offer E_Comp_Wl_Data_Offer;
|
||||
|
||||
struct _E_Comp_Wl_Data_Source
|
||||
{
|
||||
struct wl_resource *resource; //resource of wl_data_source
|
||||
|
||||
Eina_List *mime_types; //mime_type list to offer from source
|
||||
struct wl_signal destroy_signal; //signal to emit when wl_data_source resource is destroyed
|
||||
|
||||
void (*target) (E_Comp_Wl_Data_Source *source, uint32_t serial, const char* mime_type);
|
||||
void (*send) (E_Comp_Wl_Data_Source *source, const char* mime_type, int32_t fd);
|
||||
void (*cancelled) (E_Comp_Wl_Data_Source *source);
|
||||
};
|
||||
|
||||
struct _E_Comp_Wl_Data_Offer
|
||||
{
|
||||
struct wl_resource *resource; //resource of wl_data_offer
|
||||
|
||||
E_Comp_Wl_Data_Source *source; //indicates source client data
|
||||
struct wl_listener source_destroy_listener; //listener for destroy of source
|
||||
};
|
||||
|
||||
EINTERN Eina_Bool e_comp_wl_data_manager_init(E_Comp_Wl_Data *cdata);
|
||||
EINTERN void e_comp_wl_data_manager_shutdown(E_Comp_Wl_Data *cdata);
|
||||
|
||||
|
|
Loading…
Reference in New Issue