WIP: Implement the primary selection protocol

This commit is contained in:
Carlos Garnacho 2016-02-03 18:39:58 +01:00
parent 3f60a2e48a
commit 297d11b323
6 changed files with 328 additions and 11 deletions

View File

@ -45,6 +45,8 @@ mutter_built_sources = \
if HAVE_WAYLAND
mutter_built_sources += \
primary-selection-unstable-v1-protocol.c \
primary-selection-unstable-v1-server-protocol.h \
pointer-gestures-unstable-v1-protocol.c \
pointer-gestures-unstable-v1-server-protocol.h \
gtk-shell-protocol.c \

View File

@ -31,4 +31,10 @@ G_DECLARE_FINAL_TYPE (MetaWaylandDataSourceWayland,
META, WAYLAND_DATA_SOURCE_WAYLAND,
MetaWaylandDataSource);
#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY (meta_wayland_data_source_primary_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimary,
meta_wayland_data_source_primary,
META, WAYLAND_DATA_SOURCE_PRIMARY,
MetaWaylandDataSourceWayland);
#endif /* META_WAYLAND_DATA_DEVICE_PRIVATE_H */

View File

@ -37,6 +37,8 @@
#include "meta-wayland-private.h"
#include "meta-dnd-actor-private.h"
#include "primary-selection-unstable-v1-server-protocol.h"
#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
@ -70,13 +72,22 @@ typedef struct _MetaWaylandDataSourceWayland
struct wl_resource *resource;
} MetaWaylandDataSourceWayland;
typedef struct _MetaWaylandDataSourcePrimary
{
MetaWaylandDataSourceWayland parent;
} MetaWaylandDataSourcePrimary;
G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandDataSource, meta_wayland_data_source,
G_TYPE_OBJECT);
G_DEFINE_TYPE (MetaWaylandDataSourceWayland, meta_wayland_data_source_wayland,
META_TYPE_WAYLAND_DATA_SOURCE);
G_DEFINE_TYPE (MetaWaylandDataSourcePrimary, meta_wayland_data_source_primary,
META_TYPE_WAYLAND_DATA_SOURCE_WAYLAND);
static MetaWaylandDataSource *
meta_wayland_data_source_wayland_new (struct wl_resource *resource);
static MetaWaylandDataSource *
meta_wayland_data_source_primary_new (struct wl_resource *resource);
static void
drag_grab_data_source_destroyed (gpointer data, GObject *where_the_object_was);
@ -160,6 +171,7 @@ static void
meta_wayland_data_source_target (MetaWaylandDataSource *source,
const char *mime_type)
{
if (META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target)
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
}
@ -430,6 +442,32 @@ static const struct wl_data_offer_interface data_offer_interface = {
data_offer_set_actions,
};
static void
primary_offer_receive (struct wl_client *client, struct wl_resource *resource,
const char *mime_type, int32_t fd, uint32_t serial)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
MetaWaylandDataSource *source = offer->source;
MetaWaylandSeat *seat;
if (!source)
{
close (fd);
return;
}
seat = meta_wayland_data_source_get_seat (source);
if (serial == seat->keyboard.key_serial ||
serial == seat->pointer.click_serial)
meta_wayland_data_source_send (source, mime_type, fd);
}
static const struct zwp_primary_selection_offer_v1_interface primary_offer_interface = {
primary_offer_receive,
data_offer_destroy,
};
static void
meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source)
{
@ -500,6 +538,35 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
return offer->resource;
}
static struct wl_resource *
meta_wayland_data_source_send_primary_offer (MetaWaylandDataSource *source,
struct wl_resource *target)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer);
char **p;
offer->source = source;
g_object_add_weak_pointer (G_OBJECT (source), (gpointer *)&offer->source);
offer->resource = wl_resource_create (wl_resource_get_client (target),
&zwp_primary_selection_offer_v1_interface,
wl_resource_get_version (target), 0);
wl_resource_set_implementation (offer->resource,
&primary_offer_interface,
offer,
destroy_data_offer);
zwp_primary_selection_device_v1_send_data_offer (target, offer->resource);
wl_array_for_each (p, &priv->mime_types)
zwp_primary_selection_offer_v1_send_offer (offer->resource, *p);
meta_wayland_data_source_set_current_offer (source, offer);
return offer->resource;
}
static void
data_source_offer (struct wl_client *client,
struct wl_resource *resource, const char *type)
@ -561,6 +628,11 @@ static struct wl_data_source_interface data_source_interface = {
data_source_set_actions
};
static struct zwp_primary_selection_source_v1_interface primary_source_interface = {
data_source_offer,
data_source_destroy,
};
struct _MetaWaylandDragGrab {
MetaWaylandPointerGrab generic;
@ -1108,6 +1180,43 @@ meta_wayland_data_source_wayland_class_init (MetaWaylandDataSourceWaylandClass *
data_source_class->drag_finished = meta_wayland_source_drag_finished;
}
static void
meta_wayland_data_source_primary_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
MetaWaylandDataSourceWayland *source_wayland;
source_wayland = (MetaWaylandDataSourceWayland *) source;
zwp_primary_selection_source_v1_send_send (source_wayland->resource,
mime_type, fd);
}
static void
meta_wayland_data_source_primary_cancel (MetaWaylandDataSource *source)
{
MetaWaylandDataSourceWayland *source_wayland;
source_wayland = (MetaWaylandDataSourceWayland *) source;
zwp_primary_selection_source_v1_send_cancelled (source_wayland->resource);
}
static void
meta_wayland_data_source_primary_init (MetaWaylandDataSourcePrimary *source_primary)
{
}
static void
meta_wayland_data_source_primary_class_init (MetaWaylandDataSourcePrimaryClass *klass)
{
MetaWaylandDataSourceClass *data_source_class =
META_WAYLAND_DATA_SOURCE_CLASS (klass);
data_source_class->send = meta_wayland_data_source_primary_send;
data_source_class->cancel = meta_wayland_data_source_primary_cancel;
data_source_class->target = NULL;
}
static void
meta_wayland_data_source_finalize (GObject *object)
{
@ -1299,6 +1408,7 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
if (source)
{
meta_wayland_data_source_set_seat (source, seat);
g_object_weak_ref (G_OBJECT (source),
selection_data_source_destroyed,
data_device);
@ -1351,6 +1461,93 @@ static const struct wl_data_device_interface data_device_interface = {
data_device_release,
};
static void
primary_source_destroyed (gpointer data,
GObject *object_was_here)
{
MetaWaylandDataDevice *data_device = data;
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_client *focus_client = NULL;
data_device->primary_data_source = NULL;
focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
if (focus_client)
{
struct wl_resource *data_device_resource;
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
}
}
void
meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_resource *data_device_resource, *offer;
struct wl_client *focus_client;
if (data_device->primary_data_source)
{
meta_wayland_data_source_cancel (data_device->primary_data_source);
g_object_weak_unref (G_OBJECT (data_device->primary_data_source),
primary_source_destroyed,
data_device);
data_device->primary_data_source = NULL;
}
data_device->primary_data_source = source;
focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
if (focus_client)
{
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
{
if (data_device->primary_data_source)
{
offer = meta_wayland_data_source_send_primary_offer (data_device->primary_data_source,
data_device_resource);
zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
}
else
{
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
}
}
}
if (source)
{
meta_wayland_data_source_set_seat (source, seat);
g_object_weak_ref (G_OBJECT (source),
primary_source_destroyed,
data_device);
}
wl_signal_emit (&data_device->primary_ownership_signal, source);
}
static void
primary_device_set_selection (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *source_resource)
{
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandDataSource *source;
source = wl_resource_get_user_data (source_resource);
meta_wayland_data_device_set_primary (data_device, source);
}
static const struct zwp_primary_selection_device_v1_interface primary_device_interface = {
primary_device_set_selection,
data_device_release,
};
static void
destroy_data_source (struct wl_resource *resource)
{
@ -1389,6 +1586,48 @@ static const struct wl_data_device_manager_interface manager_interface = {
get_data_device
};
static void
primary_device_manager_create_source (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id)
{
struct wl_resource *source_resource;
source_resource =
wl_resource_create (client, &zwp_primary_selection_source_v1_interface,
wl_resource_get_version (manager_resource),
id);
meta_wayland_data_source_primary_new (source_resource);
}
static void
primary_device_manager_get_device (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id,
struct wl_resource *seat_resource)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
struct wl_resource *cr;
cr = wl_resource_create (client, &zwp_primary_selection_device_v1_interface,
wl_resource_get_version (manager_resource), id);
wl_resource_set_implementation (cr, &primary_device_interface,
&seat->data_device, unbind_resource);
wl_list_insert (&seat->data_device.primary_resource_list, wl_resource_get_link (cr));
}
static void
primary_device_manager_destroy (struct wl_client *client,
struct wl_resource *manager_resource)
{
}
static const struct zwp_primary_selection_device_manager_v1_interface primary_manager_interface = {
primary_device_manager_create_source,
primary_device_manager_get_device,
primary_device_manager_destroy
};
static void
bind_manager (struct wl_client *client,
void *data, guint32 version, guint32 id)
@ -1398,6 +1637,19 @@ bind_manager (struct wl_client *client,
wl_resource_set_implementation (resource, &manager_interface, NULL, NULL);
}
static void
bind_primary_manager (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_primary_selection_device_manager_v1_interface,
version, id);
wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
}
void
meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor)
{
@ -1406,13 +1658,20 @@ meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor)
META_WL_DATA_DEVICE_MANAGER_VERSION,
NULL, bind_manager) == NULL)
g_error ("Could not create data_device");
if (wl_global_create (compositor->wayland_display,
&zwp_primary_selection_device_manager_v1_interface,
1, NULL, bind_primary_manager) == NULL)
g_error ("Could not create data_device");
}
void
meta_wayland_data_device_init (MetaWaylandDataDevice *data_device)
{
wl_list_init (&data_device->resource_list);
wl_list_init (&data_device->primary_resource_list);
wl_signal_init (&data_device->selection_ownership_signal);
wl_signal_init (&data_device->primary_ownership_signal);
wl_signal_init (&data_device->dnd_ownership_signal);
}
@ -1435,9 +1694,8 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
return;
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
if (!data_device_resource)
return;
if (data_device_resource)
{
source = data_device->selection_data_source;
if (source)
{
@ -1448,6 +1706,22 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
wl_data_device_send_selection (data_device_resource, NULL);
}
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
{
source = data_device->primary_data_source;
if (source)
{
offer = meta_wayland_data_source_send_primary_offer (source, data_device_resource);
zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
}
else
{
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
}
}
}
gboolean
meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
MetaWaylandSurface *surface)
@ -1486,6 +1760,19 @@ meta_wayland_data_source_wayland_new (struct wl_resource *resource)
return META_WAYLAND_DATA_SOURCE (source_wayland);
}
static MetaWaylandDataSource *
meta_wayland_data_source_primary_new (struct wl_resource *resource)
{
MetaWaylandDataSourceWayland *source_wayland =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY, NULL);
source_wayland->resource = resource;
wl_resource_set_implementation (resource, &primary_source_interface,
source_wayland, destroy_data_source);
return META_WAYLAND_DATA_SOURCE (source_wayland);
}
gboolean
meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const gchar *mime_type)

View File

@ -57,13 +57,16 @@ struct _MetaWaylandDataDevice
uint32_t selection_serial;
MetaWaylandDataSource *selection_data_source;
MetaWaylandDataSource *dnd_data_source;
MetaWaylandDataSource *primary_data_source;
struct wl_listener selection_data_source_listener;
struct wl_list resource_list;
struct wl_list primary_resource_list;
MetaWaylandDragGrab *current_grab;
struct wl_client *focus_client;
struct wl_signal selection_ownership_signal;
struct wl_signal dnd_ownership_signal;
struct wl_signal primary_ownership_signal;
};
void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
@ -80,6 +83,8 @@ void meta_wayland_data_device_set_dnd_source (MetaWaylandDataDevice *data_de
void meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source,
guint32 serial);
void meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source);
gboolean meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const gchar *mime_type);

View File

@ -400,6 +400,9 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
time = clutter_event_get_time (event);
serial = wl_display_next_serial (display);
if (event->type == CLUTTER_BUTTON_PRESS)
pointer->click_serial = serial;
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
{
wl_pointer_send_button (resource, serial,

View File

@ -91,6 +91,7 @@ struct _MetaWaylandDataSourceXWayland
struct _MetaXWaylandSelection {
MetaSelectionBridge clipboard;
MetaSelectionBridge primary;
MetaDndBridge dnd;
};
@ -396,6 +397,8 @@ atom_to_selection_bridge (MetaWaylandCompositor *compositor,
if (selection_atom == selection_data->clipboard.selection_atom)
return &selection_data->clipboard;
else if (selection_atom == selection_data->primary.selection_atom)
return &selection_data->primary;
else if (selection_atom == selection_data->dnd.selection.selection_atom)
return &selection_data->dnd.selection;
else
@ -530,6 +533,8 @@ data_device_get_active_source_for_atom (MetaWaylandDataDevice *data_device,
{
if (selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
return data_device->selection_data_source;
else if (selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
return data_device->primary_data_source;
else if (selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
return data_device->dnd_data_source;
else
@ -1058,6 +1063,10 @@ meta_xwayland_selection_get_x11_targets (MetaWaylandCompositor *compositor,
meta_wayland_data_device_set_selection (&compositor->seat->data_device, data_source,
wl_display_next_serial (compositor->wayland_display));
}
else if (selection->selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
{
meta_wayland_data_device_set_primary (&compositor->seat->data_device, data_source);
}
}
else
g_object_unref (data_source);
@ -1529,7 +1538,8 @@ meta_xwayland_selection_handle_xfixes_selection_notify (MetaWaylandCompositor *c
if (!selection)
return FALSE;
if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD") ||
selection->selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
{
if (event->owner == None)
{
@ -1712,6 +1722,9 @@ meta_xwayland_init_selection (void)
init_selection_bridge (&manager->selection_data->clipboard,
gdk_x11_get_xatom_by_name ("CLIPBOARD"),
&compositor->seat->data_device.selection_ownership_signal);
init_selection_bridge (&manager->selection_data->primary,
gdk_x11_get_xatom_by_name ("PRIMARY"),
&compositor->seat->data_device.primary_ownership_signal);
init_selection_bridge (&manager->selection_data->dnd.selection,
xdnd_atoms[ATOM_DND_SELECTION],
&compositor->seat->data_device.dnd_ownership_signal);
@ -1730,6 +1743,7 @@ meta_xwayland_shutdown_selection (void)
meta_xwayland_shutdown_dnd (manager);
shutdown_selection_bridge (&selection->clipboard);
shutdown_selection_bridge (&selection->primary);
shutdown_selection_bridge (&selection->dnd.selection);
g_slice_free (MetaXWaylandSelection, selection);