summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2018-11-19 19:57:15 +0100
committerCarlos Garnacho <carlosg@gnome.org>2019-05-02 16:22:45 +0200
commit5c009c20ab493fd610928d4581c52f0d448bea61 (patch)
treefac2695c513ee9c25350e2eaf2f21a9ba9ceb68f /src
parent535ce00abb91819b6e5bbde237e6606fe93271c8 (diff)
downloadmutter-5c009c20ab493fd610928d4581c52f0d448bea61.tar.gz
core: Add clipboard manager
This is a simple clipboard manager implementation on top of MetaSelection. It will inspect the clipboard content for UTF-8 text and image data whenever any other selection source claims ownership, and claim it for itself whenever the clipboard goes unowned. The stored text has a maximum size of 4MB and images 200MB, to prevent the compositor from allocating indefinite amounts of memory. This is not quite a X11 clipboard manager, but also works there. https://gitlab.gnome.org/GNOME/mutter/merge_requests/320
Diffstat (limited to 'src')
-rw-r--r--src/core/display-private.h3
-rw-r--r--src/core/display.c4
-rw-r--r--src/core/meta-clipboard-manager.c167
-rw-r--r--src/core/meta-clipboard-manager.h30
-rw-r--r--src/meson.build2
5 files changed, 206 insertions, 0 deletions
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 6a378ee98..421dc8e6c 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -248,6 +248,9 @@ struct _MetaDisplay
MetaSoundPlayer *sound_player;
+ MetaSelectionSource *selection_source;
+ GBytes *saved_clipboard;
+ gchar *saved_clipboard_mimetype;
MetaSelection *selection;
};
diff --git a/src/core/display.c b/src/core/display.c
index 903024269..ce882826f 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -57,6 +57,7 @@
#include "core/frame.h"
#include "core/keybindings-private.h"
#include "core/main-private.h"
+#include "core/meta-clipboard-manager.h"
#include "core/meta-workspace-manager-private.h"
#include "core/util-private.h"
#include "core/window-private.h"
@@ -725,6 +726,7 @@ meta_display_open (void)
display->bell = meta_bell_new (display);
display->selection = meta_selection_new (display);
+ meta_clipboard_manager_init (display);
if (meta_should_autostart_x11_display ())
{
@@ -965,6 +967,8 @@ meta_display_close (MetaDisplay *display,
g_clear_object (&display->workspace_manager);
g_clear_object (&display->sound_player);
+ meta_clipboard_manager_shutdown (display);
+
g_object_unref (display);
the_display = NULL;
diff --git a/src/core/meta-clipboard-manager.c b/src/core/meta-clipboard-manager.c
new file mode 100644
index 000000000..432d845f4
--- /dev/null
+++ b/src/core/meta-clipboard-manager.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include "config.h"
+
+#include "core/meta-clipboard-manager.h"
+#include "core/meta-selection-source-memory.h"
+
+#define MAX_TEXT_SIZE (4 * 1024 * 1024) /* 4MB */
+#define MAX_IMAGE_SIZE (200 * 1024 * 1024) /* 200MB */
+
+/* Supported mimetype globs, from least to most preferred */
+static struct {
+ const char *mimetype_glob;
+ ssize_t max_transfer_size;
+} supported_mimetypes[] = {
+ { "text/plain", MAX_TEXT_SIZE },
+ { "text/plain;charset=utf-8", MAX_TEXT_SIZE },
+ { "image/*", MAX_IMAGE_SIZE },
+};
+
+static gboolean
+mimetype_match (const char *mimetype,
+ int *idx,
+ gssize *max_transfer_size)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (supported_mimetypes); i++)
+ {
+ if (g_pattern_match_simple (supported_mimetypes[i].mimetype_glob, mimetype))
+ {
+ *max_transfer_size = supported_mimetypes[i].max_transfer_size;
+ *idx = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+transfer_cb (MetaSelection *selection,
+ GAsyncResult *result,
+ GOutputStream *output)
+{
+ MetaDisplay *display = meta_get_display ();
+ GError *error = NULL;
+
+ if (!meta_selection_transfer_finish (selection, result, &error))
+ {
+ g_warning ("Failed to store clipboard: %s", error->message);
+ g_error_free (error);
+ g_object_unref (output);
+ return;
+ }
+
+ g_output_stream_close (output, NULL, NULL);
+ display->saved_clipboard =
+ g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output));
+ g_object_unref (output);
+}
+
+static void
+owner_changed_cb (MetaSelection *selection,
+ MetaSelectionType selection_type,
+ MetaSelectionSource *new_owner,
+ MetaDisplay *display)
+{
+ if (selection_type != META_SELECTION_CLIPBOARD)
+ return;
+
+ if (new_owner && new_owner != display->selection_source)
+ {
+ GOutputStream *output;
+ GList *mimetypes, *l;
+ int best_idx = -1;
+ const char *best = NULL;
+ ssize_t transfer_size = -1;
+
+ /* New selection source, find the best mimetype in order to
+ * keep a copy of it.
+ */
+ g_clear_object (&display->selection_source);
+ g_clear_pointer (&display->saved_clipboard_mimetype, g_free);
+ g_clear_pointer (&display->saved_clipboard, g_bytes_unref);
+
+ mimetypes = meta_selection_get_mimetypes (selection, selection_type);
+
+ for (l = mimetypes; l; l = l->next)
+ {
+ gssize max_transfer_size;
+ int idx;
+
+ if (!mimetype_match (l->data, &idx, &max_transfer_size))
+ continue;
+
+ if (best_idx < idx)
+ {
+ best_idx = idx;
+ best = l->data;
+ transfer_size = max_transfer_size;
+ }
+ }
+
+ if (best_idx < 0)
+ return;
+
+ display->saved_clipboard_mimetype = g_strdup (best);
+ output = g_memory_output_stream_new_resizable ();
+ meta_selection_transfer_async (selection,
+ META_SELECTION_CLIPBOARD,
+ best,
+ transfer_size,
+ output,
+ NULL,
+ (GAsyncReadyCallback) transfer_cb,
+ output);
+ }
+ else if (!new_owner && display->saved_clipboard)
+ {
+ /* Old owner is gone, time to take over */
+ new_owner = meta_selection_source_memory_new (display->saved_clipboard_mimetype,
+ display->saved_clipboard);
+ g_set_object (&display->selection_source, new_owner);
+ meta_selection_set_owner (selection, selection_type, new_owner);
+ }
+}
+
+void
+meta_clipboard_manager_init (MetaDisplay *display)
+{
+ MetaSelection *selection;
+
+ selection = meta_display_get_selection (display);
+ g_signal_connect_after (selection, "owner-changed",
+ G_CALLBACK (owner_changed_cb), display);
+}
+
+void
+meta_clipboard_manager_shutdown (MetaDisplay *display)
+{
+ MetaSelection *selection;
+
+ g_clear_pointer (&display->saved_clipboard, g_bytes_unref);
+ g_clear_pointer (&display->saved_clipboard_mimetype, g_free);
+ selection = meta_display_get_selection (display);
+ g_signal_handlers_disconnect_by_func (selection, owner_changed_cb, display);
+}
diff --git a/src/core/meta-clipboard-manager.h b/src/core/meta-clipboard-manager.h
new file mode 100644
index 000000000..2ba130f9b
--- /dev/null
+++ b/src/core/meta-clipboard-manager.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef META_CLIPBOARD_MANAGER_H
+#define META_CLIPBOARD_MANAGER_H
+
+#include "core/display-private.h"
+
+void meta_clipboard_manager_init (MetaDisplay *display);
+void meta_clipboard_manager_shutdown (MetaDisplay *display);
+
+#endif /* META_CLIPBOARD_MANAGER_H */
diff --git a/src/meson.build b/src/meson.build
index 61214f70f..0e5cd0aa0 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -329,6 +329,8 @@ mutter_sources = [
'core/meta-accel-parse.h',
'core/meta-border.c',
'core/meta-border.h',
+ 'core/meta-clipboard-manager.c',
+ 'core/meta-clipboard-manager.h',
'core/meta-close-dialog.c',
'core/meta-close-dialog-default.c',
'core/meta-close-dialog-default-private.h',