winedbg: Don't dereference possibly NULL thread pointer.
[wine/zf.git] / dlls / winemac.drv / cocoa_clipboard.m
blob30f3097c3d21cb984e9b6ea7e7bafe5e7c5fd427
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"
24 #import "cocoa_window.h"
26 #if !defined(MAC_OS_X_VERSION_10_14) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_14
27 /* For older SDKs, #define the new names of constants deprecated/renamed in macOS 10.14. */
28 #define NSBitmapImageFileTypeBMP        NSBMPFileType
29 #define NSBitmapImageFileTypeGIF        NSGIFFileType
30 #define NSBitmapImageFileTypeJPEG       NSJPEGFileType
31 #define NSBitmapImageFileTypePNG        NSPNGFileType
32 #define NSBitmapImageFileTypeTIFF       NSTIFFFileType
33 #endif
35 static int owned_change_count = -1;
36 static int change_count = -1;
38 static NSArray* BitmapOutputTypes;
39 static NSDictionary* BitmapOutputTypeMap;
40 static dispatch_once_t BitmapOutputTypesInitOnce;
42 static NSString* const OwnershipSentinel = @"org.winehq.wine.winemac.pasteboard-ownership-sentinel";
45 /***********************************************************************
46  *              macdrv_is_pasteboard_owner
47  */
48 int macdrv_is_pasteboard_owner(macdrv_window w)
50     __block int ret;
51     WineWindow* window = (WineWindow*)w;
53     OnMainThread(^{
54         NSPasteboard* pb = [NSPasteboard generalPasteboard];
55         ret = ([pb changeCount] == owned_change_count);
57         [window.queue discardEventsMatchingMask:event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP)
58                                       forWindow:window];
59     });
61     return ret;
64 /***********************************************************************
65  *              macdrv_has_pasteboard_changed
66  */
67 int macdrv_has_pasteboard_changed(void)
69     __block int new_change_count;
70     int ret;
72     OnMainThread(^{
73         NSPasteboard* pb = [NSPasteboard generalPasteboard];
74         new_change_count = [pb changeCount];
75     });
77     ret = (change_count != new_change_count);
78     change_count = new_change_count;
79     return ret;
82 /***********************************************************************
83  *              macdrv_copy_pasteboard_types
84  *
85  * Returns an array of UTI strings for the types of data available on
86  * the pasteboard, or NULL on error.  The caller is responsible for
87  * releasing the returned array with CFRelease().
88  */
89 CFArrayRef macdrv_copy_pasteboard_types(CFTypeRef pasteboard)
91     NSPasteboard* pb = (NSPasteboard*)pasteboard;
92     __block CFArrayRef ret = NULL;
93     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
95     dispatch_once(&BitmapOutputTypesInitOnce, ^{
96         NSArray* bitmapFileTypes = [NSArray arrayWithObjects:
97                                     [NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypeTIFF],
98                                     [NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypePNG],
99                                     [NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypeBMP],
100                                     [NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypeGIF],
101                                     [NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypeJPEG],
102                                     nil];
104         BitmapOutputTypes = [[NSArray alloc] initWithObjects:@"public.tiff", @"public.png",
105                              @"com.microsoft.bmp", @"com.compuserve.gif", @"public.jpeg", nil];
107         BitmapOutputTypeMap = [[NSDictionary alloc] initWithObjects:bitmapFileTypes
108                                                             forKeys:BitmapOutputTypes];
109     });
111     OnMainThread(^{
112         @try
113         {
114             NSPasteboard* local_pb = pb;
115             NSArray* types;
117             if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
118             types = [local_pb types];
120             // If there are any types understood by NSBitmapImageRep, then we
121             // can offer all of the types that it can output, too.  For example,
122             // if TIFF is on the pasteboard, we can offer PNG, BMP, etc. to the
123             // Windows program.  We'll convert on demand.
124             if ([types firstObjectCommonWithArray:[NSBitmapImageRep imageTypes]] ||
125                 [types firstObjectCommonWithArray:[NSBitmapImageRep imagePasteboardTypes]])
126             {
127                 NSMutableArray* newTypes = [BitmapOutputTypes mutableCopy];
128                 [newTypes removeObjectsInArray:types];
129                 types = [types arrayByAddingObjectsFromArray:newTypes];
130                 [newTypes release];
131             }
133             ret = (CFArrayRef)[types copy];
134         }
135         @catch (id e)
136         {
137             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
138         }
139     });
141     [pool release];
142     return ret;
146 /***********************************************************************
147  *              macdrv_copy_pasteboard_data
149  * Returns the pasteboard data for a specified type, or NULL on error or
150  * if there's no such type on the pasteboard.  The caller is responsible
151  * for releasing the returned data object with CFRelease().
152  */
153 CFDataRef macdrv_copy_pasteboard_data(CFTypeRef pasteboard, CFStringRef type)
155     NSPasteboard* pb = (NSPasteboard*)pasteboard;
156     __block NSData* ret = nil;
158     OnMainThread(^{
159         @try
160         {
161             NSPasteboard* local_pb = pb;
162             if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
163             if ([local_pb availableTypeFromArray:[NSArray arrayWithObject:(NSString*)type]])
164                 ret = [[local_pb dataForType:(NSString*)type] copy];
165             else
166             {
167                 NSNumber* bitmapType = [BitmapOutputTypeMap objectForKey:(NSString*)type];
168                 if (bitmapType)
169                 {
170                     NSArray* reps = [NSBitmapImageRep imageRepsWithPasteboard:local_pb];
171                     ret = [NSBitmapImageRep representationOfImageRepsInArray:reps
172                                                                    usingType:[bitmapType unsignedIntegerValue]
173                                                                   properties:nil];
174                     ret = [ret copy];
175                 }
176             }
177         }
178         @catch (id e)
179         {
180             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
181         }
182     });
184     return (CFDataRef)ret;
188 /***********************************************************************
189  *              macdrv_clear_pasteboard
191  * Takes ownership of the Mac pasteboard and clears it of all data types.
192  */
193 void macdrv_clear_pasteboard(macdrv_window w)
195     WineWindow* window = (WineWindow*)w;
197     OnMainThread(^{
198         @try
199         {
200             NSPasteboard* pb = [NSPasteboard generalPasteboard];
201             owned_change_count = [pb declareTypes:[NSArray arrayWithObject:OwnershipSentinel]
202                                             owner:window];
203             [window.queue discardEventsMatchingMask:event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP)
204                                           forWindow:window];
205         }
206         @catch (id e)
207         {
208             ERR(@"Exception discarded while clearing pasteboard: %@\n", e);
209         }
210     });
214 /***********************************************************************
215  *              macdrv_set_pasteboard_data
217  * Sets the pasteboard data for a specified type.  Replaces any data of
218  * that type already on the pasteboard.  If data is NULL, promises the
219  * type.
221  * Returns 0 on error, non-zero on success.
222  */
223 int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data, macdrv_window w)
225     __block int ret = 0;
226     WineWindow* window = (WineWindow*)w;
228     OnMainThread(^{
229         @try
230         {
231             NSPasteboard* pb = [NSPasteboard generalPasteboard];
232             NSInteger change_count = [pb addTypes:[NSArray arrayWithObject:(NSString*)type]
233                                             owner:window];
234             if (change_count)
235             {
236                 owned_change_count = change_count;
237                 if (data)
238                     ret = [pb setData:(NSData*)data forType:(NSString*)type];
239                 else
240                     ret = 1;
241             }
242         }
243         @catch (id e)
244         {
245             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
246         }
247     });
249     return ret;