24#import <AppKit/AppKit.h>
25#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
27#include "client_cliprdr_file_apple.h"
29static const char s_mime_uri_list[] =
"text/uri-list";
30static const char s_mime_text_utf8[] =
"text/plain;charset=utf-8";
32static NSArray<NSURL *> *get_file_urls(
void)
34 NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
35 NSDictionary *options = @{NSPasteboardURLReadingFileURLsOnlyKey: @YES};
36 return [pasteboard readObjectsForClasses:@[[NSURL class]] options:options];
39char *cliprdr_file_apple_get_uri_list(
size_t *size)
43 NSMutableString *list = [NSMutableString string];
45 for (NSURL *url in get_file_urls())
48 NSURL *path_url = [url filePathURL];
51 [list appendFormat:@"%@\r\n", [path_url absoluteString]];
54 if ([list length] == 0)
57 char *data = strdup([list UTF8String]);
64static cliprdr_file_apple_provide_file_fkt s_file_fkt = NULL;
65static void *s_file_userdata = NULL;
66static cliprdr_file_context_data_fkt s_data_fkt = NULL;
67static void *s_data_userdata = NULL;
68static NSUInteger s_generation = 0;
69static NSMutableArray *s_providers = nil;
70static unsigned s_download_serial = 0;
72@interface CliprdrFileProvider : NSObject <NSPasteboardItemDataProvider>
73@property(nonatomic)
size_t index;
74@property(nonatomic) NSUInteger generation;
76@property(nonatomic, strong) NSDictionary<NSPasteboardType, NSString *> *mimeTypes;
79@implementation CliprdrFileProvider
81- (void)pasteboard:(NSPasteboard *)pasteboard
82 item:(NSPasteboardItem *)item
83 provideDataForType:(NSPasteboardType)type
85 if (
self.generation != s_generation)
88 if ([type isEqualToString:NSPasteboardTypeFileURL])
93 char *path = s_file_fkt(s_file_userdata,
self.index);
97 NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:path]];
99 [item setString:[url absoluteString] forType:NSPasteboardTypeFileURL];
103 NSString *mime =
self.mimeTypes[type];
104 if (!mime || !s_data_fkt)
108 const void *data = s_data_fkt(s_data_userdata, [mime UTF8String], &size);
112 if ([type isEqualToString:NSPasteboardTypeString])
115 NSString *text = [[NSString alloc] initWithBytes:data
117 encoding:NSUTF8StringEncoding];
119 [item setString:text forType:type];
122 [item setData:[NSData dataWithBytes:data length:size] forType:type];
130API_AVAILABLE(macos(11.0))
131static NSDictionary<NSPasteboardType, NSString *> *get_item_types(const
char **mime_types,
134 NSMutableDictionary<NSPasteboardType, NSString *> *types = [NSMutableDictionary dictionary];
136 for (
size_t i = 0; i < mime_count; i++)
138 const char *mime = mime_types[i];
139 if (!mime || (strcmp(mime, s_mime_uri_list) == 0))
142 if (strncmp(mime,
"text/", 5) == 0)
144 types[NSPasteboardTypeString] = @(s_mime_text_utf8);
148 NSString *mime_type = [NSString stringWithUTF8String:mime];
149 UTType *uttype = mime_type ? [UTType typeWithMIMEType:mime_type] : nil;
150 if (uttype && !types[uttype.identifier])
151 types[uttype.identifier] = mime_type;
156BOOL cliprdr_file_apple_offer(
size_t count, cliprdr_file_apple_provide_file_fkt file_fkt,
157 void *file_userdata,
const char **mime_types,
size_t mime_count,
158 cliprdr_file_context_data_fkt data_fkt,
void *data_userdata)
160 if (@available(macOS 11.0, *))
164 s_file_fkt = file_fkt;
165 s_file_userdata = file_userdata;
166 s_data_fkt = data_fkt;
167 s_data_userdata = data_userdata;
170 NSDictionary<NSPasteboardType, NSString *> *mimeTypes =
171 get_item_types(mime_types, mime_count);
174 s_providers = [NSMutableArray array];
175 NSMutableArray *items = [NSMutableArray array];
176 for (
size_t i = 0; i < count; i++)
178 CliprdrFileProvider *provider = [CliprdrFileProvider new];
180 provider.generation = s_generation;
181 [s_providers addObject:provider];
183 NSMutableArray<NSPasteboardType> *types =
184 [NSMutableArray arrayWithObject:NSPasteboardTypeFileURL];
187 provider.mimeTypes = mimeTypes;
188 [types addObjectsFromArray:[mimeTypes allKeys]];
191 NSPasteboardItem *item = [NSPasteboardItem new];
192 if (![item setDataProvider:provider forTypes:types])
194 [items addObject:item];
197 NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
200 [pasteboard prepareForNewContentsWithOptions:NSPasteboardContentsCurrentHostOnly];
201 return [pasteboard writeObjects:items];
207static NSString *download_root(
void)
209 NSString *name = [NSString stringWithFormat:@"freerdp-clipboard-%d", getpid()];
210 return [NSTemporaryDirectory() stringByAppendingPathComponent:name];
213char *cliprdr_file_apple_new_download_dir(
void)
217 NSFileManager *fm = [NSFileManager defaultManager];
218 NSString *root = download_root();
221 if (s_download_serial >= 2)
223 NSString *old = [NSString stringWithFormat:@"%u", s_download_serial - 2];
224 [fm removeItemAtPath:[root stringByAppendingPathComponent:old] error:nil];
227 NSString *name = [NSString stringWithFormat:@"%u", s_download_serial++];
228 NSString *dir = [root stringByAppendingPathComponent:name];
229 NSDictionary *attributes = @{NSFilePosixPermissions: @0700};
230 if (![fm createDirectoryAtPath:dir
231 withIntermediateDirectories:YES
232 attributes:attributes
235 return strdup([dir fileSystemRepresentation]);
239void cliprdr_file_apple_detach(
void)
244 s_file_userdata = NULL;
246 s_data_userdata = NULL;
249 [[NSFileManager defaultManager] removeItemAtPath:download_root() error:nil];