mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
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
This commit is contained in:
parent
535ce00abb
commit
5c009c20ab
@ -248,6 +248,9 @@ struct _MetaDisplay
|
|||||||
|
|
||||||
MetaSoundPlayer *sound_player;
|
MetaSoundPlayer *sound_player;
|
||||||
|
|
||||||
|
MetaSelectionSource *selection_source;
|
||||||
|
GBytes *saved_clipboard;
|
||||||
|
gchar *saved_clipboard_mimetype;
|
||||||
MetaSelection *selection;
|
MetaSelection *selection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
#include "core/frame.h"
|
#include "core/frame.h"
|
||||||
#include "core/keybindings-private.h"
|
#include "core/keybindings-private.h"
|
||||||
#include "core/main-private.h"
|
#include "core/main-private.h"
|
||||||
|
#include "core/meta-clipboard-manager.h"
|
||||||
#include "core/meta-workspace-manager-private.h"
|
#include "core/meta-workspace-manager-private.h"
|
||||||
#include "core/util-private.h"
|
#include "core/util-private.h"
|
||||||
#include "core/window-private.h"
|
#include "core/window-private.h"
|
||||||
@ -725,6 +726,7 @@ meta_display_open (void)
|
|||||||
display->bell = meta_bell_new (display);
|
display->bell = meta_bell_new (display);
|
||||||
|
|
||||||
display->selection = meta_selection_new (display);
|
display->selection = meta_selection_new (display);
|
||||||
|
meta_clipboard_manager_init (display);
|
||||||
|
|
||||||
if (meta_should_autostart_x11_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->workspace_manager);
|
||||||
g_clear_object (&display->sound_player);
|
g_clear_object (&display->sound_player);
|
||||||
|
|
||||||
|
meta_clipboard_manager_shutdown (display);
|
||||||
|
|
||||||
g_object_unref (display);
|
g_object_unref (display);
|
||||||
the_display = NULL;
|
the_display = NULL;
|
||||||
|
|
||||||
|
167
src/core/meta-clipboard-manager.c
Normal file
167
src/core/meta-clipboard-manager.c
Normal file
@ -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);
|
||||||
|
}
|
30
src/core/meta-clipboard-manager.h
Normal file
30
src/core/meta-clipboard-manager.h
Normal file
@ -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 */
|
@ -329,6 +329,8 @@ mutter_sources = [
|
|||||||
'core/meta-accel-parse.h',
|
'core/meta-accel-parse.h',
|
||||||
'core/meta-border.c',
|
'core/meta-border.c',
|
||||||
'core/meta-border.h',
|
'core/meta-border.h',
|
||||||
|
'core/meta-clipboard-manager.c',
|
||||||
|
'core/meta-clipboard-manager.h',
|
||||||
'core/meta-close-dialog.c',
|
'core/meta-close-dialog.c',
|
||||||
'core/meta-close-dialog-default.c',
|
'core/meta-close-dialog-default.c',
|
||||||
'core/meta-close-dialog-default-private.h',
|
'core/meta-close-dialog-default-private.h',
|
||||||
|
Loading…
Reference in New Issue
Block a user