diff options
author | William Hua <william.hua@canonical.com> | 2016-10-12 16:56:01 -0400 |
---|---|---|
committer | William Hua <william.hua@canonical.com> | 2017-01-05 17:57:36 -0500 |
commit | 516c0a2aab2bcc19e81fd94e3a007a667dd1996c (patch) | |
tree | c4e7e5b8364f500843463be5656ebffe1a5b9847 /gdk | |
parent | dcda372c15f5c6585331bb9bbd2b27f5d13b30e6 (diff) | |
download | gtk+-516c0a2aab2bcc19e81fd94e3a007a667dd1996c.tar.gz |
mir: copy clipboard data to content-hub
https://bugzilla.gnome.org/show_bug.cgi?id=775732
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/mir/gdkmir-private.h | 5 | ||||
-rw-r--r-- | gdk/mir/gdkmirdisplay.c | 60 | ||||
-rw-r--r-- | gdk/mir/gdkmirwindowimpl.c | 150 |
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 |