regedit: Allow importing strings with escaped NULL.
[wine.git] / dlls / winemac.drv / cocoa_clipboard.m
blobb8ca796606484616d22f5f8c9350a10b671e6cdf
1 /*
2  * MACDRV Cocoa clipboard code
3  *
4  * Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
21 #include "macdrv_cocoa.h"
22 #import "cocoa_app.h"
23 #import "cocoa_event.h"
26 static int owned_change_count = -1;
28 static NSArray* BitmapOutputTypes;
29 static NSDictionary* BitmapOutputTypeMap;
30 static dispatch_once_t BitmapOutputTypesInitOnce;
33 /***********************************************************************
34  *              macdrv_is_pasteboard_owner
35  */
36 int macdrv_is_pasteboard_owner(void)
38     __block int ret;
40     OnMainThread(^{
41         NSPasteboard* pb = [NSPasteboard generalPasteboard];
42         ret = ([pb changeCount] == owned_change_count);
43     });
45     return ret;
49 /***********************************************************************
50  *              macdrv_copy_pasteboard_types
51  *
52  * Returns an array of UTI strings for the types of data available on
53  * the pasteboard, or NULL on error.  The caller is responsible for
54  * releasing the returned array with CFRelease().
55  */
56 CFArrayRef macdrv_copy_pasteboard_types(CFTypeRef pasteboard)
58     NSPasteboard* pb = (NSPasteboard*)pasteboard;
59     __block CFArrayRef ret = NULL;
60     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
62     dispatch_once(&BitmapOutputTypesInitOnce, ^{
63         NSArray* bitmapFileTypes = [NSArray arrayWithObjects:
64                                     [NSNumber numberWithUnsignedInteger:NSTIFFFileType],
65                                     [NSNumber numberWithUnsignedInteger:NSPNGFileType],
66                                     [NSNumber numberWithUnsignedInteger:NSBMPFileType],
67                                     [NSNumber numberWithUnsignedInteger:NSGIFFileType],
68                                     [NSNumber numberWithUnsignedInteger:NSJPEGFileType],
69                                     [NSNumber numberWithUnsignedInteger:NSJPEG2000FileType],
70                                     nil];
72         BitmapOutputTypes = [[NSArray alloc] initWithObjects:@"public.tiff", @"public.png",
73                              @"com.microsoft.bmp", @"com.compuserve.gif", @"public.jpeg",
74                              @"public.jpeg-2000", nil];
76         BitmapOutputTypeMap = [[NSDictionary alloc] initWithObjects:bitmapFileTypes
77                                                             forKeys:BitmapOutputTypes];
78     });
80     OnMainThread(^{
81         @try
82         {
83             NSPasteboard* local_pb = pb;
84             NSArray* types;
86             if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
87             types = [local_pb types];
89             // If there are any types understood by NSBitmapImageRep, then we
90             // can offer all of the types that it can output, too.  For example,
91             // if TIFF is on the pasteboard, we can offer PNG, BMP, etc. to the
92             // Windows program.  We'll convert on demand.
93             if ([types firstObjectCommonWithArray:[NSBitmapImageRep imageTypes]] ||
94                 [types firstObjectCommonWithArray:[NSBitmapImageRep imagePasteboardTypes]])
95             {
96                 NSMutableArray* newTypes = [BitmapOutputTypes mutableCopy];
97                 [newTypes removeObjectsInArray:types];
98                 types = [types arrayByAddingObjectsFromArray:newTypes];
99                 [newTypes release];
100             }
102             ret = (CFArrayRef)[types copy];
103         }
104         @catch (id e)
105         {
106             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
107         }
108     });
110     [pool release];
111     return ret;
115 /***********************************************************************
116  *              macdrv_copy_pasteboard_data
118  * Returns the pasteboard data for a specified type, or NULL on error or
119  * if there's no such type on the pasteboard.  The caller is responsible
120  * for releasing the returned data object with CFRelease().
121  */
122 CFDataRef macdrv_copy_pasteboard_data(CFTypeRef pasteboard, CFStringRef type)
124     NSPasteboard* pb = (NSPasteboard*)pasteboard;
125     __block NSData* ret = nil;
127     OnMainThread(^{
128         @try
129         {
130             NSPasteboard* local_pb = pb;
131             if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
132             if ([local_pb availableTypeFromArray:[NSArray arrayWithObject:(NSString*)type]])
133                 ret = [[local_pb dataForType:(NSString*)type] copy];
134             else
135             {
136                 NSNumber* bitmapType = [BitmapOutputTypeMap objectForKey:(NSString*)type];
137                 if (bitmapType)
138                 {
139                     NSArray* reps = [NSBitmapImageRep imageRepsWithPasteboard:local_pb];
140                     ret = [NSBitmapImageRep representationOfImageRepsInArray:reps
141                                                                    usingType:[bitmapType unsignedIntegerValue]
142                                                                   properties:nil];
143                     ret = [ret copy];
144                 }
145             }
146         }
147         @catch (id e)
148         {
149             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
150         }
151     });
153     return (CFDataRef)ret;
157 /***********************************************************************
158  *              macdrv_clear_pasteboard
160  * Takes ownership of the Mac pasteboard and clears it of all data types.
161  */
162 void macdrv_clear_pasteboard(void)
164     OnMainThreadAsync(^{
165         @try
166         {
167             NSPasteboard* pb = [NSPasteboard generalPasteboard];
168             owned_change_count = [pb declareTypes:[NSArray array] owner:nil];
169         }
170         @catch (id e)
171         {
172             ERR(@"Exception discarded while clearing pasteboard: %@\n", e);
173         }
174     });
178 /***********************************************************************
179  *              macdrv_set_pasteboard_data
181  * Sets the pasteboard data for a specified type.  Replaces any data of
182  * that type already on the pasteboard.  If data is NULL, promises the
183  * type.
185  * Returns 0 on error, non-zero on success.
186  */
187 int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data, macdrv_window w)
189     __block int ret = 0;
190     WineWindow* window = (WineWindow*)w;
192     OnMainThread(^{
193         @try
194         {
195             NSPasteboard* pb = [NSPasteboard generalPasteboard];
196             NSInteger change_count = [pb addTypes:[NSArray arrayWithObject:(NSString*)type]
197                                             owner:window];
198             if (change_count)
199             {
200                 owned_change_count = change_count;
201                 if (data)
202                     ret = [pb setData:(NSData*)data forType:(NSString*)type];
203                 else
204                     ret = 1;
205             }
206         }
207         @catch (id e)
208         {
209             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
210         }
211     });
213     return ret;