summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Hua <william.hua@canonical.com>2016-10-12 16:56:01 -0400
committerWilliam Hua <william.hua@canonical.com>2017-01-05 17:57:36 -0500
commit516c0a2aab2bcc19e81fd94e3a007a667dd1996c (patch)
treec4e7e5b8364f500843463be5656ebffe1a5b9847
parentdcda372c15f5c6585331bb9bbd2b27f5d13b30e6 (diff)
downloadgtk+-516c0a2aab2bcc19e81fd94e3a007a667dd1996c.tar.gz
mir: copy clipboard data to content-hub
https://bugzilla.gnome.org/show_bug.cgi?id=775732
-rw-r--r--gdk/mir/gdkmir-private.h5
-rw-r--r--gdk/mir/gdkmirdisplay.c60
-rw-r--r--gdk/mir/gdkmirwindowimpl.c150
3 files changed, 212 insertions, 3 deletions
diff --git a/gdk/mir/gdkmir-private.h b/gdk/mir/gdkmir-private.h
index 0ccf28e0b3..997cf47a08 100644
--- a/gdk/mir/gdkmir-private.h
+++ b/gdk/mir/gdkmir-private.h
@@ -111,6 +111,11 @@ void _gdk_mir_display_focus_window (GdkDisplay *display, GdkWindow *window);
void _gdk_mir_display_unfocus_window (GdkDisplay *display, GdkWindow *window);
+void _gdk_mir_display_create_paste (GdkDisplay *display,
+ const gchar * const *paste_formats,
+ gconstpointer paste_data,
+ gsize paste_size);
+
gboolean _gdk_mir_display_init_egl_display (GdkDisplay *display);
EGLDisplay _gdk_mir_display_get_egl_display (GdkDisplay *display);
diff --git a/gdk/mir/gdkmirdisplay.c b/gdk/mir/gdkmirdisplay.c
index 389c7e6e8d..058bf85c04 100644
--- a/gdk/mir/gdkmirdisplay.c
+++ b/gdk/mir/gdkmirdisplay.c
@@ -544,7 +544,28 @@ gdk_mir_display_set_selection_owner (GdkDisplay *display,
guint32 time,
gboolean send_event)
{
- //g_printerr ("gdk_mir_display_set_selection_owner\n");
+ GdkEvent *event;
+
+ if (selection == GDK_SELECTION_CLIPBOARD)
+ {
+ if (owner)
+ {
+ event = gdk_event_new (GDK_SELECTION_REQUEST);
+ event->selection.window = g_object_ref (owner);
+ event->selection.send_event = FALSE;
+ event->selection.selection = selection;
+ event->selection.target = gdk_atom_intern_static_string ("TARGETS");
+ event->selection.property = gdk_atom_intern_static_string ("AVAILABLE_TARGETS");
+ event->selection.time = GDK_CURRENT_TIME;
+ event->selection.requestor = g_object_ref (owner);
+
+ gdk_event_put (event);
+ gdk_event_free (event);
+
+ return TRUE;
+ }
+ }
+
return FALSE;
}
@@ -685,6 +706,43 @@ _gdk_mir_display_unfocus_window (GdkDisplay *display,
g_clear_object (&mir_display->focused_window);
}
+void
+_gdk_mir_display_create_paste (GdkDisplay *display,
+ const gchar * const *paste_formats,
+ gconstpointer paste_data,
+ gsize paste_size)
+{
+ GdkMirDisplay *mir_display = GDK_MIR_DISPLAY (display);
+ MirSurface *surface;
+ MirPersistentId *persistent_id;
+
+ if (!mir_display->focused_window)
+ return;
+
+ surface = gdk_mir_window_get_mir_surface (mir_display->focused_window);
+
+ if (!surface)
+ return;
+
+ persistent_id = mir_surface_request_persistent_id_sync (surface);
+
+ if (!persistent_id)
+ return;
+
+ if (mir_persistent_id_is_valid (persistent_id))
+ content_hub_service_call_create_paste_sync (
+ mir_display->content_service,
+ g_application_get_application_id (g_application_get_default ()),
+ mir_persistent_id_as_string (persistent_id),
+ g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, paste_data, paste_size, sizeof (guchar)),
+ paste_formats,
+ NULL,
+ NULL,
+ NULL);
+
+ mir_persistent_id_release (persistent_id);
+}
+
gboolean
_gdk_mir_display_init_egl_display (GdkDisplay *display)
{
diff --git a/gdk/mir/gdkmirwindowimpl.c b/gdk/mir/gdkmirwindowimpl.c
index 862fd15f70..b00e35eba5 100644
--- a/gdk/mir/gdkmirwindowimpl.c
+++ b/gdk/mir/gdkmirwindowimpl.c
@@ -1508,6 +1508,140 @@ gdk_mir_window_impl_get_property (GdkWindow *window,
}
static void
+request_targets (GdkWindow *window,
+ const GdkAtom *available_targets,
+ gint n_available_targets)
+{
+ GArray *requested_targets;
+ GdkAtom target_pair[2];
+ gchar *target_location;
+ GdkEvent *event;
+ gint i;
+
+ requested_targets = g_array_sized_new (TRUE, FALSE, sizeof (GdkAtom), 2 * n_available_targets);
+
+ for (i = 0; i < n_available_targets; i++)
+ {
+ target_pair[0] = available_targets[i];
+
+ if (target_pair[0] == gdk_atom_intern_static_string ("TIMESTAMP") ||
+ target_pair[0] == gdk_atom_intern_static_string ("TARGETS") ||
+ target_pair[0] == gdk_atom_intern_static_string ("MULTIPLE") ||
+ target_pair[0] == gdk_atom_intern_static_string ("SAVE_TARGETS"))
+ continue;
+
+ target_location = g_strdup_printf ("REQUESTED_TARGET_U%u", requested_targets->len / 2);
+ target_pair[1] = gdk_atom_intern (target_location, FALSE);
+ g_free (target_location);
+
+ g_array_append_vals (requested_targets, target_pair, 2);
+ }
+
+ gdk_property_delete (window, gdk_atom_intern_static_string ("AVAILABLE_TARGETS"));
+ gdk_property_delete (window, gdk_atom_intern_static_string ("REQUESTED_TARGETS"));
+
+ gdk_property_change (window,
+ gdk_atom_intern_static_string ("REQUESTED_TARGETS"),
+ GDK_SELECTION_TYPE_ATOM,
+ 8 * sizeof (GdkAtom),
+ GDK_PROP_MODE_REPLACE,
+ (const guchar *) requested_targets->data,
+ requested_targets->len);
+
+ g_array_unref (requested_targets);
+
+ event = gdk_event_new (GDK_SELECTION_REQUEST);
+ event->selection.window = g_object_ref (window);
+ event->selection.send_event = FALSE;
+ event->selection.selection = GDK_SELECTION_CLIPBOARD;
+ event->selection.target = gdk_atom_intern_static_string ("MULTIPLE");
+ event->selection.property = gdk_atom_intern_static_string ("REQUESTED_TARGETS");
+ event->selection.time = GDK_CURRENT_TIME;
+ event->selection.requestor = g_object_ref (window);
+
+ gdk_event_put (event);
+ gdk_event_free (event);
+}
+
+static void
+create_paste (GdkWindow *window,
+ const GdkAtom *requested_targets,
+ gint n_requested_targets)
+{
+ GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
+ GPtrArray *paste_formats;
+ GArray *paste_header;
+ GByteArray *paste_data;
+ gint sizes[4];
+ GdkMirProperty *mir_property;
+ const gchar *paste_format;
+ gint i;
+
+ paste_formats = g_ptr_array_new_full (n_requested_targets, g_free);
+ paste_header = g_array_sized_new (FALSE, FALSE, sizeof (gint), 1 + 4 * n_requested_targets);
+ paste_data = g_byte_array_new ();
+
+ g_array_append_val (paste_header, sizes[0]);
+
+ for (i = 0; i < n_requested_targets; i++)
+ {
+ if (requested_targets[i] == GDK_NONE)
+ continue;
+
+ mir_property = g_hash_table_lookup (impl->properties, requested_targets[i]);
+
+ if (!mir_property)
+ continue;
+
+ paste_format = _gdk_atom_name_const (mir_property->type);
+
+ /* skip non-MIME targets */
+ if (!strchr (paste_format, '/'))
+ {
+ g_hash_table_remove (impl->properties, requested_targets[i]);
+ continue;
+ }
+
+ sizes[0] = paste_data->len;
+ sizes[1] = strlen (paste_format);
+ sizes[2] = sizes[0] + sizes[1];
+ sizes[3] = mir_property->array->len * g_array_get_element_size (mir_property->array);
+
+ g_ptr_array_add (paste_formats, g_strdup (paste_format));
+ g_array_append_vals (paste_header, sizes, 4);
+ g_byte_array_append (paste_data, (const guint8 *) paste_format, sizes[1]);
+ g_byte_array_append (paste_data, (const guint8 *) mir_property->array->data, sizes[3]);
+
+ g_hash_table_remove (impl->properties, requested_targets[i]);
+ }
+
+ gdk_property_delete (window, gdk_atom_intern_static_string ("REQUESTED_TARGETS"));
+
+ g_array_index (paste_header, gint, 0) = paste_formats->len;
+
+ for (i = 0; i < paste_formats->len; i++)
+ {
+ g_array_index (paste_header, gint, 1 + 4 * i) += paste_header->len * sizeof (gint);
+ g_array_index (paste_header, gint, 3 + 4 * i) += paste_header->len * sizeof (gint);
+ }
+
+ g_byte_array_prepend (paste_data,
+ (const guint8 *) paste_header->data,
+ paste_header->len * g_array_get_element_size (paste_header));
+
+ g_ptr_array_add (paste_formats, NULL);
+
+ _gdk_mir_display_create_paste (gdk_window_get_display (window),
+ (const gchar * const *) paste_formats->pdata,
+ paste_data->data,
+ paste_data->len);
+
+ g_byte_array_unref (paste_data);
+ g_array_unref (paste_header);
+ g_ptr_array_unref (paste_formats);
+}
+
+static void
gdk_mir_window_impl_change_property (GdkWindow *window,
GdkAtom property,
GdkAtom type,
@@ -1518,6 +1652,7 @@ gdk_mir_window_impl_change_property (GdkWindow *window,
{
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
GdkMirProperty *mir_property;
+ gboolean existed;
GdkEvent *event;
/* ICCCM 2.7: ATOMs and ATOM_PAIRs have format 32, but GdkAtoms can be 64-bit */
@@ -1525,9 +1660,15 @@ gdk_mir_window_impl_change_property (GdkWindow *window,
format = 8 * sizeof (GdkAtom);
if (mode != GDK_PROP_MODE_REPLACE)
- mir_property = g_hash_table_lookup (impl->properties, property);
+ {
+ mir_property = g_hash_table_lookup (impl->properties, property);
+ existed = mir_property != NULL;
+ }
else
- mir_property = NULL;
+ {
+ mir_property = NULL;
+ existed = g_hash_table_contains (impl->properties, property);
+ }
if (!mir_property)
{
@@ -1554,6 +1695,11 @@ gdk_mir_window_impl_change_property (GdkWindow *window,
gdk_event_put (event);
gdk_event_free (event);
+
+ if (property == gdk_atom_intern_static_string ("AVAILABLE_TARGETS"))
+ request_targets (window, (const GdkAtom *) data, n_elements);
+ else if (property == gdk_atom_intern_static_string ("REQUESTED_TARGETS") && existed)
+ create_paste (window, (const GdkAtom *) data, n_elements);
}
static void