Compare commits

...

7 Commits

Author SHA1 Message Date
Arjan Molenaar
09918d8ff5 macos: Update docs on UTI mapping 2024-11-08 20:20:35 +01:00
Arjan Molenaar
c3e415e965 macos: Map GdkRGBA to NSColor
Make drag and drop work for colors.
2024-11-07 19:05:59 +01:00
Arjan Molenaar
ec7e0777ec macos: Use org.gtk.internal for GType-based DnD
Use a custom content type, so other apps are not tempted to
accept GTK internal content types.
2024-10-30 19:54:19 +01:00
Arjan Molenaar
5ca4fa6695 macos: Remove custom Dnd/copy mime type mappings 2024-10-30 19:54:19 +01:00
Arjan Molenaar
a3c52870a2 macos: Accept all types for drop data
GTK should figure out if the dragged item will be accepted.
2024-10-30 19:54:19 +01:00
Arjan Molenaar
14bafe7bb5 macos: Inline pasteboard reader code
To increase understandability of the code.
2024-10-30 19:54:19 +01:00
Arjan Molenaar
7d395a65ea macos: Use GLib functions to map mime-type and UTI types
This should provide us more flexibility than the limited fixed
set of supported types.

Although mapping seems to work, apps still only accept the limited
set.

application/x-color and text/uri-list are special cases:
GLib doesn't map them, but they are (pre)defined content types in GTK.
2024-10-30 19:54:19 +01:00
2 changed files with 90 additions and 103 deletions

View File

@@ -9,3 +9,13 @@ or environment variables.
For up-to-date information on building, installation, and bundling, see the
[GTK website](https://www.gtk.org/docs/installations/macos).
## Content types
While GTK uses MIME types, macOS uses Unified Type descriptors.
GTK maps MIME to UTI types.
If you create a macOS app for your application, you can provide
custom UTI/MIME types mappings in the
[Information Property List](https://developer.apple.com/documentation/bundleresources/information_property_list)
for your application.

View File

@@ -24,69 +24,32 @@
#include "gdkdragprivate.h"
#include "gdkmacospasteboard-private.h"
#include "gdkmacosutils-private.h"
enum {
TYPE_STRING,
TYPE_PBOARD,
TYPE_URL,
TYPE_FILE_URL,
TYPE_COLOR,
TYPE_TIFF,
TYPE_PNG,
TYPE_LAST
};
#define PTYPE(k) (get_pasteboard_type(TYPE_##k))
static NSPasteboardType pasteboard_types[TYPE_LAST];
static NSPasteboardType
get_pasteboard_type (int type)
{
static gsize initialized = FALSE;
g_assert (type >= 0);
g_assert (type < TYPE_LAST);
if (g_once_init_enter (&initialized))
{
pasteboard_types[TYPE_PNG] = NSPasteboardTypePNG;
pasteboard_types[TYPE_STRING] = NSPasteboardTypeString;
pasteboard_types[TYPE_TIFF] = NSPasteboardTypeTIFF;
pasteboard_types[TYPE_COLOR] = NSPasteboardTypeColor;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
pasteboard_types[TYPE_PBOARD] = NSStringPboardType;
G_GNUC_END_IGNORE_DEPRECATIONS
pasteboard_types[TYPE_URL] = NSPasteboardTypeURL;
pasteboard_types[TYPE_FILE_URL] = NSPasteboardTypeFileURL;
g_once_init_leave (&initialized, TRUE);
}
return pasteboard_types[type];
}
#include "gdkdebugprivate.h"
const char *
_gdk_macos_pasteboard_from_ns_type (NSPasteboardType type)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
gchar *mime_type;
if ([type isEqualToString:PTYPE(STRING)] ||
[type isEqualToString:PTYPE(PBOARD)])
return g_intern_string ("text/plain;charset=utf-8");
else if ([type isEqualToString:PTYPE(URL)] ||
[type isEqualToString:PTYPE(FILE_URL)])
return g_intern_string ("text/uri-list");
else if ([type isEqualToString:PTYPE(COLOR)])
return g_intern_string ("application/x-color");
else if ([type isEqualToString:PTYPE(TIFF)])
return g_intern_string ("image/tiff");
else if ([type isEqualToString:PTYPE(PNG)])
return g_intern_string ("image/png");
if ([type isEqualToString:NSPasteboardTypeURL] ||
[type isEqualToString:NSPasteboardTypeFileURL])
{
GDK_DEBUG (DND, "From UTI %s to mime-type text/uri-list", [type UTF8String]);
return g_intern_string ("text/uri-list");
}
else if ([type isEqualToString:NSPasteboardTypeColor])
{
GDK_DEBUG (DND, "From UTI %s to mime-type application/x-color", [type UTF8String]);
return g_intern_string ("application/x-color");
}
else if ((mime_type = g_content_type_get_mime_type ([type UTF8String])))
{
const gchar *intern = g_intern_string (mime_type);
GDK_DEBUG (DND, "From UTI %s to mime-type %s", [type UTF8String], mime_type);
g_free (mime_type);
G_GNUC_END_IGNORE_DEPRECATIONS;
return intern;
}
return NULL;
}
@@ -95,30 +58,30 @@ NSPasteboardType
_gdk_macos_pasteboard_to_ns_type (const char *mime_type,
NSPasteboardType *alternate)
{
gchar *uti_str;
if (alternate)
*alternate = NULL;
if (g_strcmp0 (mime_type, "text/plain;charset=utf-8") == 0)
{
return PTYPE(STRING);
}
else if (g_strcmp0 (mime_type, "text/uri-list") == 0)
if (g_strcmp0 (mime_type, "text/uri-list") == 0)
{
if (alternate)
*alternate = PTYPE(URL);
return PTYPE(FILE_URL);
*alternate = NSPasteboardTypeURL;
GDK_DEBUG (DND, "From mime-type %s to UTI public.file-url and public.url", mime_type);
return [NSPasteboardTypeFileURL retain];
}
else if (g_strcmp0 (mime_type, "application/x-color") == 0)
{
return PTYPE(COLOR);
GDK_DEBUG (DND, "From mime-type %s to UTI %s", mime_type, [NSPasteboardTypeColor UTF8String]);
return [NSPasteboardTypeColor retain];
}
else if (g_strcmp0 (mime_type, "image/tiff") == 0)
else if ((uti_str = g_content_type_from_mime_type (mime_type)))
{
return PTYPE(TIFF);
}
else if (g_strcmp0 (mime_type, "image/png") == 0)
{
return PTYPE(PNG);
NSString *uti = [[NSString alloc] initWithUTF8String:uti_str];
GDK_DEBUG (DND, "From mime-type %s to UTI %s", mime_type, uti_str);
g_free (uti_str);
return uti;
}
return nil;
@@ -161,15 +124,6 @@ _gdk_macos_pasteboard_load_formats (NSPasteboard *pasteboard)
return load_offer_formats (pasteboard);
}
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_memdup2 (bytes, len), len, g_free);
}
void
_gdk_macos_pasteboard_read_async (GObject *object,
NSPasteboard *pasteboard,
@@ -185,6 +139,7 @@ _gdk_macos_pasteboard_read_async (GObject *object,
const char *mime_type;
GInputStream *stream = NULL;
GTask *task = NULL;
NSString *uti;
g_assert (G_IS_OBJECT (object));
g_assert (pasteboard != NULL);
@@ -223,7 +178,7 @@ _gdk_macos_pasteboard_read_async (GObject *object,
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
if ([[pasteboard types] containsObject:PTYPE(FILE_URL)])
if ([[pasteboard types] containsObject:NSPasteboardTypeFileURL])
{
GString *str = g_string_new (NULL);
NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType];
@@ -268,15 +223,23 @@ _gdk_macos_pasteboard_read_async (GObject *object,
sizeof color,
g_free);
}
else if (strcmp (mime_type, "image/tiff") == 0)
else if ((uti = _gdk_macos_pasteboard_to_ns_type (mime_type, NULL)))
{
NSData *data = [pasteboard dataForType:PTYPE(TIFF)];
stream = create_stream_from_nsdata (data);
NSData *data = [pasteboard dataForType:uti];
if (data != NULL)
{
const guint8 *bytes = [data bytes];
gsize len = [data length];
stream = g_memory_input_stream_new_from_data (g_memdup2 (bytes, len), len, g_free);
}
[uti release];
}
else if (strcmp (mime_type, "image/png") == 0)
else
{
NSData *data = [pasteboard dataForType:PTYPE(PNG)];
stream = create_stream_from_nsdata (data);
GDK_DEBUG (DND, "No stream for mime-type %s", mime_type);
}
if (stream != NULL)
@@ -320,13 +283,10 @@ _gdk_macos_pasteboard_read_finish (GObject *object,
void
_gdk_macos_pasteboard_register_drag_types (NSWindow *window)
{
[window registerForDraggedTypes:[NSArray arrayWithObjects:PTYPE(STRING),
PTYPE(PBOARD),
PTYPE(URL),
PTYPE(FILE_URL),
PTYPE(COLOR),
PTYPE(TIFF),
PTYPE(PNG),
// TODO: how can GTK tell us what drag types expected?
// Now the app will accept everything.
[window registerForDraggedTypes:[NSArray arrayWithObjects:@"public.item",
@"org.gtk.internal",
nil]];
}
@@ -376,6 +336,7 @@ _gdk_macos_pasteboard_register_drag_types (NSWindow *window)
if ((type = _gdk_macos_pasteboard_to_ns_type (mime_type, &alternate)))
{
[ret addObject:type];
[type release];
if (alternate)
[ret addObject:alternate];
}
@@ -383,9 +344,7 @@ _gdk_macos_pasteboard_register_drag_types (NSWindow *window)
gdk_content_formats_unref (serializable);
/* Default to an url type (think gobject://internal)
* to support internal, GType-based DnD.
*/
/* Support internal, GType-based DnD. */
if ([ret count] == 0)
{
GdkContentFormats *formats;
@@ -395,7 +354,7 @@ _gdk_macos_pasteboard_register_drag_types (NSWindow *window)
gdk_content_formats_get_gtypes (formats, &n_gtypes);
if (n_gtypes)
[ret addObject:PTYPE(URL)];
[ret addObject:@"org.gtk.internal"];
gdk_content_formats_unref (formats);
}
@@ -450,15 +409,33 @@ on_data_ready_cb (GObject *object,
if (ret)
{
gsize size;
gpointer bytes;
g_output_stream_close (G_OUTPUT_STREAM (wr->stream), NULL, NULL);
size = g_memory_output_stream_get_data_size (wr->stream);
bytes = g_memory_output_stream_steal_data (wr->stream);
data = [[NSData alloc] initWithBytesNoCopy:bytes
length:size
deallocator:^(void *alloc, NSUInteger length) { g_free (alloc); }];
if (size == 8 && [wr->type isEqualToString:NSPasteboardTypeColor])
{
guint16 *color;
NSError *nserror = nil;
color = (guint16 *)g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (wr->stream));
NSColor *nscolor = [[NSColor colorWithRed:color[0] / 65535.0
green:color[1] / 65535.0
blue:color[2] / 65535.0
alpha:color[3] / 65535.0]
colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
data = [NSKeyedArchiver archivedDataWithRootObject:nscolor requiringSecureCoding:YES error: &nserror];
if (error)
g_warning ("Encoding color failed");
}
else
{
gpointer bytes = g_memory_output_stream_steal_data (wr->stream);
data = [[NSData alloc] initWithBytesNoCopy:bytes
length:size
deallocator:^(void *alloc, NSUInteger length) { g_free (alloc); }];
}
}
else
{