gtk/gdk/macos/gdkmacosclipboard.c
Christian Hergert 9c3629653f macos: abstract pasteboard for use in clipboard and drag
This will allow us to share a single NSPasteboardItem and data provider
implementation for both GdkClipboard and GdkDrag.
2023-01-13 20:03:55 +01:00

197 lines
5.8 KiB
C

/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include <glib/gi18n.h>
#include "gdkmacosclipboard-private.h"
#include "gdkmacospasteboard-private.h"
#include "gdkmacosutils-private.h"
#include "gdkprivate.h"
struct _GdkMacosClipboard
{
GdkClipboard parent_instance;
NSPasteboard *pasteboard;
NSInteger last_change_count;
};
G_DEFINE_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK_TYPE_CLIPBOARD)
static void
_gdk_macos_clipboard_load_contents (GdkMacosClipboard *self)
{
GdkContentFormats *formats;
NSInteger change_count;
g_assert (GDK_IS_MACOS_CLIPBOARD (self));
change_count = [self->pasteboard changeCount];
formats = _gdk_macos_pasteboard_load_formats (self->pasteboard);
gdk_clipboard_claim_remote (GDK_CLIPBOARD (self), formats);
gdk_content_formats_unref (formats);
self->last_change_count = change_count;
}
static void
_gdk_macos_clipboard_read_async (GdkClipboard *clipboard,
GdkContentFormats *formats,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
_gdk_macos_pasteboard_read_async (G_OBJECT (clipboard),
GDK_MACOS_CLIPBOARD (clipboard)->pasteboard,
formats,
io_priority,
cancellable,
callback,
user_data);
}
static GInputStream *
_gdk_macos_clipboard_read_finish (GdkClipboard *clipboard,
GAsyncResult *result,
const char **out_mime_type,
GError **error)
{
return _gdk_macos_pasteboard_read_finish (G_OBJECT (clipboard), result, out_mime_type, error);
}
static void
_gdk_macos_clipboard_send_to_pasteboard (GdkMacosClipboard *self,
GdkContentProvider *content)
{
GdkMacosPasteboardItem *item;
NSArray<NSPasteboardItem *> *items;
g_assert (GDK_IS_MACOS_CLIPBOARD (self));
g_assert (GDK_IS_CONTENT_PROVIDER (content));
if (self->pasteboard == NULL)
return;
GDK_BEGIN_MACOS_ALLOC_POOL;
item = [[GdkMacosPasteboardItem alloc] initForClipboard:GDK_CLIPBOARD (self) withContentProvider:content];
items = [NSArray arrayWithObject:item];
[self->pasteboard clearContents];
if ([self->pasteboard writeObjects:items] == NO)
g_warning ("Failed to send clipboard to pasteboard");
self->last_change_count = [self->pasteboard changeCount];
GDK_END_MACOS_ALLOC_POOL;
}
static gboolean
_gdk_macos_clipboard_claim (GdkClipboard *clipboard,
GdkContentFormats *formats,
gboolean local,
GdkContentProvider *provider)
{
GdkMacosClipboard *self = (GdkMacosClipboard *)clipboard;
gboolean ret;
g_assert (GDK_IS_CLIPBOARD (clipboard));
g_assert (formats != NULL);
g_assert (!provider || GDK_IS_CONTENT_PROVIDER (provider));
ret = GDK_CLIPBOARD_CLASS (_gdk_macos_clipboard_parent_class)->claim (clipboard, formats, local, provider);
if (local)
_gdk_macos_clipboard_send_to_pasteboard (self, provider);
return ret;
}
static void
_gdk_macos_clipboard_constructed (GObject *object)
{
GdkMacosClipboard *self = (GdkMacosClipboard *)object;
if (self->pasteboard == nil)
self->pasteboard = [[NSPasteboard generalPasteboard] retain];
G_OBJECT_CLASS (_gdk_macos_clipboard_parent_class)->constructed (object);
}
static void
_gdk_macos_clipboard_finalize (GObject *object)
{
GdkMacosClipboard *self = (GdkMacosClipboard *)object;
if (self->pasteboard != nil)
{
[self->pasteboard release];
self->pasteboard = nil;
}
G_OBJECT_CLASS (_gdk_macos_clipboard_parent_class)->finalize (object);
}
static void
_gdk_macos_clipboard_class_init (GdkMacosClipboardClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkClipboardClass *clipboard_class = GDK_CLIPBOARD_CLASS (klass);
object_class->constructed = _gdk_macos_clipboard_constructed;
object_class->finalize = _gdk_macos_clipboard_finalize;
clipboard_class->claim = _gdk_macos_clipboard_claim;
clipboard_class->read_async = _gdk_macos_clipboard_read_async;
clipboard_class->read_finish = _gdk_macos_clipboard_read_finish;
}
static void
_gdk_macos_clipboard_init (GdkMacosClipboard *self)
{
}
GdkClipboard *
_gdk_macos_clipboard_new (GdkMacosDisplay *display)
{
GdkMacosClipboard *self;
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
self = g_object_new (GDK_TYPE_MACOS_CLIPBOARD,
"display", display,
NULL);
_gdk_macos_clipboard_load_contents (self);
return GDK_CLIPBOARD (self);
}
void
_gdk_macos_clipboard_check_externally_modified (GdkMacosClipboard *self)
{
g_return_if_fail (GDK_IS_MACOS_CLIPBOARD (self));
if ([self->pasteboard changeCount] != self->last_change_count)
_gdk_macos_clipboard_load_contents (self);
}