quartz/tests: Make testpin_{AddRef,Release}() static.
[wine.git] / dlls / winemac.drv / cocoa_clipboard.m
blob39c3b8f872f967760f6a42719e34b192d67b5881
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"
27 static int owned_change_count = -1;
28 static int change_count = -1;
30 static NSArray* BitmapOutputTypes;
31 static NSDictionary* BitmapOutputTypeMap;
32 static dispatch_once_t BitmapOutputTypesInitOnce;
34 static NSString* const OwnershipSentinel = @"org.winehq.wine.winemac.pasteboard-ownership-sentinel";
37 /***********************************************************************
38  *              macdrv_is_pasteboard_owner
39  */
40 int macdrv_is_pasteboard_owner(macdrv_window w)
42     __block int ret;
43     WineWindow* window = (WineWindow*)w;
45     OnMainThread(^{
46         NSPasteboard* pb = [NSPasteboard generalPasteboard];
47         ret = ([pb changeCount] == owned_change_count);
49         [window.queue discardEventsMatchingMask:event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP)
50                                       forWindow:window];
51     });
53     return ret;
56 /***********************************************************************
57  *              macdrv_has_pasteboard_changed
58  */
59 int macdrv_has_pasteboard_changed(void)
61     __block int new_change_count;
62     int ret;
64     OnMainThread(^{
65         NSPasteboard* pb = [NSPasteboard generalPasteboard];
66         new_change_count = [pb changeCount];
67     });
69     ret = (change_count != new_change_count);
70     change_count = new_change_count;
71     return ret;
74 /***********************************************************************
75  *              macdrv_copy_pasteboard_types
76  *
77  * Returns an array of UTI strings for the types of data available on
78  * the pasteboard, or NULL on error.  The caller is responsible for
79  * releasing the returned array with CFRelease().
80  */
81 CFArrayRef macdrv_copy_pasteboard_types(CFTypeRef pasteboard)
83     NSPasteboard* pb = (NSPasteboard*)pasteboard;
84     __block CFArrayRef ret = NULL;
85     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
87     dispatch_once(&BitmapOutputTypesInitOnce, ^{
88         NSArray* bitmapFileTypes = [NSArray arrayWithObjects:
89                                     [NSNumber numberWithUnsignedInteger:NSTIFFFileType],
90                                     [NSNumber numberWithUnsignedInteger:NSPNGFileType],
91                                     [NSNumber numberWithUnsignedInteger:NSBMPFileType],
92                                     [NSNumber numberWithUnsignedInteger:NSGIFFileType],
93                                     [NSNumber numberWithUnsignedInteger:NSJPEGFileType],
94                                     nil];
96         BitmapOutputTypes = [[NSArray alloc] initWithObjects:@"public.tiff", @"public.png",
97                              @"com.microsoft.bmp", @"com.compuserve.gif", @"public.jpeg", nil];
99         BitmapOutputTypeMap = [[NSDictionary alloc] initWithObjects:bitmapFileTypes
100                                                             forKeys:BitmapOutputTypes];
101     });
103     OnMainThread(^{
104         @try
105         {
106             NSPasteboard* local_pb = pb;
107             NSArray* types;
109             if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
110             types = [local_pb types];
112             // If there are any types understood by NSBitmapImageRep, then we
113             // can offer all of the types that it can output, too.  For example,
114             // if TIFF is on the pasteboard, we can offer PNG, BMP, etc. to the
115             // Windows program.  We'll convert on demand.
116             if ([types firstObjectCommonWithArray:[NSBitmapImageRep imageTypes]] ||
117                 [types firstObjectCommonWithArray:[NSBitmapImageRep imagePasteboardTypes]])
118             {
119                 NSMutableArray* newTypes = [BitmapOutputTypes mutableCopy];
120                 [newTypes removeObjectsInArray:types];
121                 types = [types arrayByAddingObjectsFromArray:newTypes];
122                 [newTypes release];
123             }
125             ret = (CFArrayRef)[types copy];
126         }
127         @catch (id e)
128         {
129             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
130         }
131     });
133     [pool release];
134     return ret;
138 /***********************************************************************
139  *              macdrv_copy_pasteboard_data
141  * Returns the pasteboard data for a specified type, or NULL on error or
142  * if there's no such type on the pasteboard.  The caller is responsible
143  * for releasing the returned data object with CFRelease().
144  */
145 CFDataRef macdrv_copy_pasteboard_data(CFTypeRef pasteboard, CFStringRef type)
147     NSPasteboard* pb = (NSPasteboard*)pasteboard;
148     __block NSData* ret = nil;
150     OnMainThread(^{
151         @try
152         {
153             NSPasteboard* local_pb = pb;
154             if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
155             if ([local_pb availableTypeFromArray:[NSArray arrayWithObject:(NSString*)type]])
156                 ret = [[local_pb dataForType:(NSString*)type] copy];
157             else
158             {
159                 NSNumber* bitmapType = [BitmapOutputTypeMap objectForKey:(NSString*)type];
160                 if (bitmapType)
161                 {
162                     NSArray* reps = [NSBitmapImageRep imageRepsWithPasteboard:local_pb];
163                     ret = [NSBitmapImageRep representationOfImageRepsInArray:reps
164                                                                    usingType:[bitmapType unsignedIntegerValue]
165                                                                   properties:nil];
166                     ret = [ret copy];
167                 }
168             }
169         }
170         @catch (id e)
171         {
172             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
173         }
174     });
176     return (CFDataRef)ret;
180 /***********************************************************************
181  *              macdrv_clear_pasteboard
183  * Takes ownership of the Mac pasteboard and clears it of all data types.
184  */
185 void macdrv_clear_pasteboard(macdrv_window w)
187     WineWindow* window = (WineWindow*)w;
189     OnMainThread(^{
190         @try
191         {
192             NSPasteboard* pb = [NSPasteboard generalPasteboard];
193             owned_change_count = [pb declareTypes:[NSArray arrayWithObject:OwnershipSentinel]
194                                             owner:window];
195             [window.queue discardEventsMatchingMask:event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP)
196                                           forWindow:window];
197         }
198         @catch (id e)
199         {
200             ERR(@"Exception discarded while clearing pasteboard: %@\n", e);
201         }
202     });
206 /***********************************************************************
207  *              macdrv_set_pasteboard_data
209  * Sets the pasteboard data for a specified type.  Replaces any data of
210  * that type already on the pasteboard.  If data is NULL, promises the
211  * type.
213  * Returns 0 on error, non-zero on success.
214  */
215 int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data, macdrv_window w)
217     __block int ret = 0;
218     WineWindow* window = (WineWindow*)w;
220     OnMainThread(^{
221         @try
222         {
223             NSPasteboard* pb = [NSPasteboard generalPasteboard];
224             NSInteger change_count = [pb addTypes:[NSArray arrayWithObject:(NSString*)type]
225                                             owner:window];
226             if (change_count)
227             {
228                 owned_change_count = change_count;
229                 if (data)
230                     ret = [pb setData:(NSData*)data forType:(NSString*)type];
231                 else
232                     ret = 1;
233             }
234         }
235         @catch (id e)
236         {
237             ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
238         }
239     });
241     return ret;