[gtk+] x11: Implement storing the clipboard
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] x11: Implement storing the clipboard
- Date: Sun, 3 Dec 2017 04:55:15 +0000 (UTC)
commit 5abd7a39a2c7b1615af359ad91b058c164491d79
Author: Benjamin Otte <otte redhat com>
Date: Fri Dec 1 06:20:28 2017 +0100
x11: Implement storing the clipboard
gdk/x11/gdkclipboard-x11.c | 164 ++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 158 insertions(+), 6 deletions(-)
---
diff --git a/gdk/x11/gdkclipboard-x11.c b/gdk/x11/gdkclipboard-x11.c
index 9075000..8037912 100644
--- a/gdk/x11/gdkclipboard-x11.c
+++ b/gdk/x11/gdkclipboard-x11.c
@@ -47,6 +47,8 @@ struct _GdkX11Clipboard
char *selection;
Atom xselection;
gulong timestamp;
+
+ GTask *store_task;
};
struct _GdkX11ClipboardClass
@@ -124,6 +126,7 @@ handle_targets_done (GObject *stream,
static Atom *
gdk_x11_clipboard_formats_to_atoms (GdkDisplay *display,
+ gboolean include_special,
GdkContentFormats *formats,
gsize *n_atoms);
@@ -139,6 +142,7 @@ handle_targets (GdkX11Clipboard *cb,
gsize n_atoms;
atoms = gdk_x11_clipboard_formats_to_atoms (gdk_clipboard_get_display (clipboard),
+ TRUE,
gdk_clipboard_get_formats (clipboard),
&n_atoms);
print_atoms (cb, "sending targets", atoms, n_atoms);
@@ -192,6 +196,18 @@ handle_timestamp (GdkX11Clipboard *cb,
g_object_unref (stream);
}
+static void
+handle_save_targets (GdkX11Clipboard *cb,
+ const char *target,
+ const char *encoding,
+ int format,
+ GOutputStream *stream)
+{
+ /* Don't do anything */
+
+ g_object_unref (stream);
+}
+
static GInputStream *
text_list_convert (GdkX11Clipboard *cb,
GInputStream *stream,
@@ -267,7 +283,8 @@ static const struct {
{ "TEXT", "text/plain;charset=utf-8", text_list_convert, "STRING", 8, handle_text_list },
{ "STRING", "text/plain;charset=utf-8", text_list_convert, "STRING", 8, handle_text_list },
{ "TARGETS", NULL, NULL, "ATOM", 32, handle_targets },
- { "TIMESTAMP", NULL, NULL, "INTEGER", 32, handle_timestamp }
+ { "TIMESTAMP", NULL, NULL, "INTEGER", 32, handle_timestamp },
+ { "SAVE_TARGETS", NULL, NULL, "NULL", 32, handle_save_targets
}
};
static GSList *
@@ -298,6 +315,7 @@ gdk_x11_clipboard_formats_to_targets (GdkContentFormats *formats)
static Atom *
gdk_x11_clipboard_formats_to_atoms (GdkDisplay *display,
+ gboolean include_special,
GdkContentFormats *formats,
gsize *n_atoms)
{
@@ -307,13 +325,16 @@ gdk_x11_clipboard_formats_to_atoms (GdkDisplay *display,
targets = gdk_x11_clipboard_formats_to_targets (formats);
- for (i = 0; i < G_N_ELEMENTS (special_targets); i++)
+ if (include_special)
{
- if (special_targets[i].mime_type != NULL)
- continue;
+ for (i = 0; i < G_N_ELEMENTS (special_targets); i++)
+ {
+ if (special_targets[i].mime_type != NULL)
+ continue;
- if (special_targets[i].handler)
- targets = g_slist_prepend (targets, (gpointer) g_intern_string (special_targets[i].x_target));
+ if (special_targets[i].handler)
+ targets = g_slist_prepend (targets, (gpointer) g_intern_string (special_targets[i].x_target));
+ }
}
*n_atoms = g_slist_length (targets);
@@ -668,6 +689,36 @@ gdk_x11_clipboard_filter_event (GdkXEvent *xev,
gdk_x11_clipboard_claim_remote (cb, xevent->xselectionclear.time);
return GDK_FILTER_REMOVE;
+ case SelectionNotify:
+ /* This code only checks clipboard manager replies, so... */
+ if (!g_str_equal (cb->selection, "CLIPBOARD"))
+ return GDK_FILTER_CONTINUE;
+
+ /* selection is not for us */
+ if (xevent->xselection.selection != gdk_x11_get_xatom_by_name_for_display (display,
"CLIPBOARD_MANAGER") ||
+ xevent->xselection.target != gdk_x11_get_xatom_by_name_for_display (display, "SAVE_TARGETS"))
+ return GDK_FILTER_CONTINUE;
+
+ /* We already received a selectionNotify before */
+ if (cb->store_task == NULL)
+ {
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: got SelectionNotify for nonexisting task?!\n",
+ cb->selection));
+ return GDK_FILTER_CONTINUE;
+ }
+
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: got SelectionNotify for store task\n",
+ cb->selection));
+
+ if (xevent->xselection.property != None)
+ g_task_return_boolean (cb->store_task, TRUE);
+ else
+ g_task_return_new_error (cb->store_task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Clipboard manager could not store selection."));
+ g_clear_object (&cb->store_task);
+
+ return GDK_FILTER_CONTINUE;
+
case SelectionRequest:
{
GdkX11PendingSelectionNotify *notify;
@@ -790,6 +841,105 @@ gdk_x11_clipboard_claim (GdkClipboard *clipboard,
}
static void
+gdk_x11_clipboard_store_async (GdkClipboard *clipboard,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GdkX11Clipboard *cb = GDK_X11_CLIPBOARD (clipboard);
+ GdkDisplay *display = gdk_clipboard_get_display (clipboard);
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ Atom clipboard_manager, save_targets, property_name;
+ GdkContentProvider *content;
+ GdkContentFormats *formats;
+ Atom *atoms;
+ gsize n_atoms;
+ int error;
+
+ /* clipboard managers don't work on anythig but the clipbpoard selection */
+ if (!g_str_equal (cb->selection, "CLIPBOARD"))
+ {
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: can only store on CLIPBOARD\n",
+ cb->selection));
+ GDK_CLIPBOARD_CLASS (gdk_x11_clipboard_parent_class)->store_async (clipboard,
+ io_priority,
+ cancellable,
+ callback,
+ user_data);
+ return;
+ }
+
+ cb->store_task = g_task_new (clipboard, cancellable, callback, user_data);
+ g_task_set_priority (cb->store_task, io_priority);
+ g_task_set_source_tag (cb->store_task, gdk_x11_clipboard_store_async);
+
+ clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
+ save_targets = gdk_x11_get_xatom_by_name_for_display (display, "SAVE_TARGETS");
+
+ if (XGetSelectionOwner (xdisplay, clipboard_manager) == None)
+ {
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: XGetSelectionOwner (CLIPBOARD_MANAGER) returned None,
aborting.\n",
+ cb->selection));
+ g_task_return_new_error (cb->store_task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Cannot store clipboard. No clipboard manager is active."));
+ g_clear_object (&cb->store_task);
+ return;
+ }
+
+ content = gdk_clipboard_get_content (clipboard);
+ if (content == NULL)
+ {
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: storing empty clipboard: SUCCESS!\n",
+ cb->selection));
+ g_task_return_boolean (cb->store_task, TRUE);
+ g_clear_object (&cb->store_task);
+ return;
+ }
+
+ formats = gdk_content_provider_ref_storable_formats (content);
+ formats = gdk_content_formats_union_serialize_mime_types (formats);
+ atoms = gdk_x11_clipboard_formats_to_atoms (display, FALSE, formats, &n_atoms);
+ print_atoms (cb, "requesting store from clipboard manager", atoms, n_atoms);
+ gdk_content_formats_unref (formats);
+
+ gdk_x11_display_error_trap_push (display);
+
+ if (n_atoms > 0)
+ {
+ property_name = gdk_x11_get_xatom_by_name_for_display (display, "GDK_CLIPBOARD_SAVE_TARGETS");
+
+ XChangeProperty (xdisplay, GDK_X11_DISPLAY (display)->leader_window,
+ property_name, XA_ATOM,
+ 32, PropModeReplace, (guchar *)atoms, n_atoms);
+ }
+ else
+ property_name = None;
+
+ XConvertSelection (xdisplay,
+ clipboard_manager, save_targets, property_name,
+ GDK_X11_DISPLAY (display)->leader_window, cb->timestamp);
+
+ error = gdk_x11_display_error_trap_pop (display);
+ if (error != Success)
+ {
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: X error during ConvertSelection() while storing selection: %d\n",
+ cb->selection, error));
+ }
+}
+
+static gboolean
+gdk_x11_clipboard_store_finish (GdkClipboard *clipboard,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, clipboard), FALSE);
+ g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_x11_clipboard_store_async, FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
gdk_x11_clipboard_read_got_stream (GObject *source,
GAsyncResult *res,
gpointer data)
@@ -939,6 +1089,8 @@ gdk_x11_clipboard_class_init (GdkX11ClipboardClass *class)
object_class->finalize = gdk_x11_clipboard_finalize;
clipboard_class->claim = gdk_x11_clipboard_claim;
+ clipboard_class->store_async = gdk_x11_clipboard_store_async;
+ clipboard_class->store_finish = gdk_x11_clipboard_store_finish;
clipboard_class->read_async = gdk_x11_clipboard_read_async;
clipboard_class->read_finish = gdk_x11_clipboard_read_finish;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]