[gtk/wip/chergert/quartz4u: 122/142] macos: implement basic clipboard reading
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/quartz4u: 122/142] macos: implement basic clipboard reading
- Date: Tue, 23 Jun 2020 18:40:02 +0000 (UTC)
commit 8daf9e8f0ced1a72d0fee5c12863397a9917f87e
Author: Christian Hergert <chergert redhat com>
Date: Thu Jun 11 10:20:47 2020 -0700
macos: implement basic clipboard reading
Still need to finish writing here, and we won't be implementing
primary_clipboard unless we find that is necessary later.
gdk/macos/gdkmacosclipboard-private.h | 45 +++++
gdk/macos/gdkmacosclipboard.c | 319 ++++++++++++++++++++++++++++++++++
gdk/macos/gdkmacosdisplay.c | 12 ++
gdk/macos/meson.build | 1 +
4 files changed, 377 insertions(+)
---
diff --git a/gdk/macos/gdkmacosclipboard-private.h b/gdk/macos/gdkmacosclipboard-private.h
new file mode 100644
index 0000000000..aae2727120
--- /dev/null
+++ b/gdk/macos/gdkmacosclipboard-private.h
@@ -0,0 +1,45 @@
+/*
+ * 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
+ */
+
+#ifndef __GDK_MACOS_CLIPBOARD_PRIVATE_H__
+#define __GDK_MACOS_CLIPBOARD_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+
+#include "gdkclipboardprivate.h"
+#include "gdkmacosdisplay-private.h"
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_MACOS_CLIPBOARD (_gdk_macos_clipboard_get_type())
+
+G_DECLARE_FINAL_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK, MACOS_CLIPBOARD, GdkClipboard)
+
+GdkClipboard *_gdk_macos_clipboard_new (GdkMacosDisplay *display);
+
+@interface GdkMacosClipboardOwner : NSObject
+{
+ GdkClipboard *clipboard;
+}
+
+@end
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_CLIPBOARD_PRIVATE_H__ */
diff --git a/gdk/macos/gdkmacosclipboard.c b/gdk/macos/gdkmacosclipboard.c
new file mode 100644
index 0000000000..dd16222a59
--- /dev/null
+++ b/gdk/macos/gdkmacosclipboard.c
@@ -0,0 +1,319 @@
+/*
+ * 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 "gdkmacosutils-private.h"
+
+struct _GdkMacosClipboard
+{
+ GdkClipboard parent_instance;
+ NSPasteboard *pasteboard;
+ GdkMacosClipboardOwner *owner;
+};
+
+G_DEFINE_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK_TYPE_CLIPBOARD)
+
+static void
+populate_content_formats (GdkContentFormatsBuilder *builder,
+ NSPasteboardType type)
+{
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+
+ if ([type isEqualToString:NSPasteboardTypeString] ||
+ [type isEqualToString:NSStringPboardType])
+ gdk_content_formats_builder_add_mime_type (builder, "text/plain;charset=utf-8");
+ else if ([type isEqualToString:NSPasteboardTypeURL] ||
+ [type isEqualToString:NSPasteboardTypeFileURL])
+ gdk_content_formats_builder_add_mime_type (builder, "text/uri-list");
+ else if ([type isEqualToString:NSPasteboardTypeColor])
+ gdk_content_formats_builder_add_mime_type (builder, "application/x-color");
+ else if ([type isEqualToString:NSPasteboardTypeTIFF])
+ gdk_content_formats_builder_add_mime_type (builder, "image/tiff");
+ else if ([type isEqualToString:NSPasteboardTypePNG])
+ gdk_content_formats_builder_add_mime_type (builder, "image/png");
+
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static GdkContentFormats *
+load_offer_formats (GdkMacosClipboard *self)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkContentFormatsBuilder *builder;
+ GdkContentFormats *formats;
+
+ g_assert (GDK_IS_MACOS_CLIPBOARD (self));
+
+ builder = gdk_content_formats_builder_new ();
+ for (NSPasteboardType type in [self->pasteboard types])
+ populate_content_formats (builder, type);
+ formats = gdk_content_formats_builder_free_to_formats (builder);
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return g_steal_pointer (&formats);
+}
+
+static void
+_gdk_macos_clipboard_load_contents (GdkMacosClipboard *self)
+{
+ GdkContentFormats *formats;
+
+ g_assert (GDK_IS_MACOS_CLIPBOARD (self));
+
+ formats = load_offer_formats (self);
+ gdk_clipboard_claim_remote (GDK_CLIPBOARD (self), formats);
+ gdk_content_formats_unref (formats);
+}
+
+static gboolean
+_gdk_macos_clipboard_claim (GdkClipboard *clipboard,
+ GdkContentFormats *formats,
+ gboolean local,
+ GdkContentProvider *provider)
+{
+ g_assert (GDK_IS_CLIPBOARD (clipboard));
+ g_assert (formats != NULL);
+ g_assert (!provider || GDK_IS_CONTENT_PROVIDER (provider));
+
+ return GDK_CLIPBOARD_CLASS (_gdk_macos_clipboard_parent_class)->claim (clipboard, formats, local,
provider);
+}
+
+static GInputStream *
+create_stream_from_nsdata (NSData *data)
+{
+ const guint8 *bytes = [data bytes];
+ gsize len = [data length];
+
+ return g_memory_input_stream_new_from_data (g_memdup (bytes, len), len, g_free);
+}
+
+static void
+_gdk_macos_clipboard_read_async (GdkClipboard *clipboard,
+ GdkContentFormats *formats,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkContentFormats *offer_formats = NULL;
+ NSPasteboard *pasteboard;
+ const gchar *mime_type;
+ GInputStream *stream = NULL;
+ GTask *task = NULL;
+
+ g_assert (GDK_IS_MACOS_CLIPBOARD (clipboard));
+ g_assert (formats != NULL);
+
+ task = g_task_new (clipboard, cancellable, callback, user_data);
+ g_task_set_source_tag (task, _gdk_macos_clipboard_read_async);
+ g_task_set_priority (task, io_priority);
+
+ pasteboard = [NSPasteboard generalPasteboard];
+ offer_formats = load_offer_formats (GDK_MACOS_CLIPBOARD (clipboard));
+ mime_type = gdk_content_formats_match_mime_type (formats, offer_formats);
+
+ if (mime_type == NULL)
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "%s",
+ _("No compatible transfer format found"));
+ goto cleanup;
+ }
+
+ if (strcmp (mime_type, "text/plain;charset=utf-8") == 0)
+ {
+ NSString *nsstr = [pasteboard stringForType:NSPasteboardTypeString];
+
+ if (nsstr != NULL)
+ {
+ const char *str = [nsstr UTF8String];
+ stream = g_memory_input_stream_new_from_data (g_strdup (str),
+ strlen (str),
+ g_free);
+ }
+ }
+ else if (strcmp (mime_type, "text/uri-list") == 0)
+ {
+#if 0
+ if ([[pasteboard types] containsObject:NSPasteboardTypeFileURL])
+ {
+ GString *str = g_string_new (NULL);
+ NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType];
+ gsize n_files = [files count];
+ gchar **uris;
+
+ for (gsize i = 0; i < n_files; ++i)
+ {
+ NSString* uriString = [files objectAtIndex:i];
+ uriString = [@"file://" stringByAppendingString:uriString];
+ uriString = [uriString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ uris[i] = (gchar *) [uriString cStringUsingEncoding:NSUTF8StringEncoding];
+ }
+ uris[i] = NULL;
+ gtk_selection_data_set_uris (selection_data, uris);
+ g_free (uris);
+ }
+#endif
+ }
+ else if (strcmp (mime_type, "application/x-color") == 0)
+ {
+ NSColorSpace *colorspace;
+ NSColor *nscolor;
+ guint16 color[4];
+
+ colorspace = [NSColorSpace genericRGBColorSpace];
+ nscolor = [[NSColor colorFromPasteboard:pasteboard]
+ colorUsingColorSpace:colorspace];
+
+ color[0] = 0xffff * [nscolor redComponent];
+ color[1] = 0xffff * [nscolor greenComponent];
+ color[2] = 0xffff * [nscolor blueComponent];
+ color[3] = 0xffff * [nscolor alphaComponent];
+
+ stream = g_memory_input_stream_new_from_data (g_memdup (&color, sizeof color),
+ sizeof color,
+ g_free);
+ }
+ else if (strcmp (mime_type, "image/tiff") == 0)
+ {
+ NSData *data = [pasteboard dataForType:NSPasteboardTypeTIFF];
+ stream = create_stream_from_nsdata (data);
+ }
+ else if (strcmp (mime_type, "image/png") == 0)
+ {
+ NSData *data = [pasteboard dataForType:NSPasteboardTypePNG];
+ stream = create_stream_from_nsdata (data);
+ }
+
+ if (stream != NULL)
+ {
+ g_task_set_task_data (task, g_strdup (mime_type), g_free);
+ g_task_return_pointer (task, g_steal_pointer (&stream), g_object_unref);
+ }
+ else
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Failed to decode contents with mime-type of '%s'"),
+ mime_type);
+ }
+
+cleanup:
+ g_clear_object (&task);
+ g_clear_pointer (&offer_formats, gdk_content_formats_unref);
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+static GInputStream *
+_gdk_macos_clipboard_read_finish (GdkClipboard *clipboard,
+ GAsyncResult *result,
+ const gchar **out_mime_type,
+ GError **error)
+{
+ GTask *task = (GTask *)result;
+
+ g_assert (GDK_IS_MACOS_CLIPBOARD (clipboard));
+ g_assert (G_IS_TASK (task));
+
+ if (out_mime_type != NULL)
+ *out_mime_type = g_strdup (g_task_get_task_data (task));
+
+ return g_task_propagate_pointer (task, error);
+}
+
+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);
+}
+
+@implementation GdkMacosClipboardOwner
+
+-(void)pasteboard:(NSPasteboard *)pb provideDataForType:(NSString *)type
+{
+ //[pb setData:data forType:type];
+}
+
+@end
diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c
index 65c2fa1967..3e44452f45 100644
--- a/gdk/macos/gdkmacosdisplay.c
+++ b/gdk/macos/gdkmacosdisplay.c
@@ -27,6 +27,7 @@
#include "gdkeventsprivate.h"
#include "gdkdisplaylinksource.h"
+#include "gdkmacosclipboard-private.h"
#include "gdkmacoscairocontext-private.h"
#include "gdkmacoseventsource-private.h"
#include "gdkmacosdisplay-private.h"
@@ -597,6 +598,14 @@ gdk_macos_display_get_keymap (GdkDisplay *display)
return GDK_KEYMAP (self->keymap);
}
+static void
+gdk_macos_display_load_clipboard (GdkMacosDisplay *self)
+{
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ GDK_DISPLAY (self)->clipboard = _gdk_macos_clipboard_new (self);
+}
+
static void
gdk_macos_display_finalize (GObject *object)
{
@@ -612,6 +621,7 @@ gdk_macos_display_finalize (GObject *object)
CFSTR ("NSUserDefaultsDidChangeNotification"),
NULL);
+ g_clear_object (&GDK_DISPLAY (self)->clipboard);
g_clear_pointer (&self->frame_source, g_source_unref);
g_clear_object (&self->monitors);
g_clear_pointer (&self->name, g_free);
@@ -682,6 +692,8 @@ _gdk_macos_display_open (const gchar *display_name)
self->keymap = _gdk_macos_keymap_new (self);
gdk_macos_display_load_seat (self);
+ gdk_macos_display_load_clipboard (self);
+
/* Load CVDisplayLink before monitors to access refresh rates */
gdk_macos_display_load_display_link (self);
_gdk_macos_display_reload_monitors (self);
diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build
index e534e1f581..56a1604f52 100644
--- a/gdk/macos/meson.build
+++ b/gdk/macos/meson.build
@@ -4,6 +4,7 @@ gdk_macos_sources = files([
'gdkdisplaylinksource.c',
'GdkMacosWindow.c',
'gdkmacoscairocontext.c',
+ 'gdkmacosclipboard.c',
'gdkmacoscursor.c',
'gdkmacosdevice.c',
'gdkmacosdisplay.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]