2 * MACDRV Cocoa clipboard code
4 * Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc.
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.
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.
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
21 #include "macdrv_cocoa.h"
23 #import "cocoa_event.h"
24 #import "cocoa_window.h"
26 #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
28 #if !defined(MAC_OS_X_VERSION_10_14) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_14
29 /* For older SDKs, #define the new names of constants deprecated/renamed in macOS 10.14. */
30 #define NSBitmapImageFileTypeBMP NSBMPFileType
31 #define NSBitmapImageFileTypeGIF NSGIFFileType
32 #define NSBitmapImageFileTypeJPEG NSJPEGFileType
33 #define NSBitmapImageFileTypePNG NSPNGFileType
34 #define NSBitmapImageFileTypeTIFF NSTIFFFileType
37 static int owned_change_count = -1;
38 static int change_count = -1;
40 static NSDictionary<NSString *, NSNumber *> *BitmapOutputTypeMap;
41 static dispatch_once_t BitmapOutputTypesInitOnce;
43 static NSString* const OwnershipSentinel = @"org.winehq.wine.winemac.pasteboard-ownership-sentinel";
46 /***********************************************************************
47 * macdrv_is_pasteboard_owner
49 int macdrv_is_pasteboard_owner(macdrv_window w)
52 WineWindow* window = (WineWindow*)w;
55 NSPasteboard* pb = [NSPasteboard generalPasteboard];
56 ret = ([pb changeCount] == owned_change_count);
58 [window.queue discardEventsMatchingMask:event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP)
65 /***********************************************************************
66 * macdrv_has_pasteboard_changed
68 int macdrv_has_pasteboard_changed(void)
70 __block int new_change_count;
74 NSPasteboard* pb = [NSPasteboard generalPasteboard];
75 new_change_count = [pb changeCount];
78 ret = (change_count != new_change_count);
79 change_count = new_change_count;
83 /***********************************************************************
84 * macdrv_copy_pasteboard_types
86 * Returns an array of UTI strings for the types of data available on
87 * the pasteboard, or NULL on error. The caller is responsible for
88 * releasing the returned array with CFRelease().
90 CFArrayRef macdrv_copy_pasteboard_types(CFTypeRef pasteboard)
94 NSPasteboard* pb = (NSPasteboard*)pasteboard;
95 __block CFArrayRef ret = NULL;
97 dispatch_once(&BitmapOutputTypesInitOnce, ^{
100 @"public.tiff" : @(NSBitmapImageFileTypeTIFF),
101 @"public.png" : @(NSBitmapImageFileTypePNG),
102 @"com.microsoft.bmp" : @(NSBitmapImageFileTypeBMP),
103 @"com.compuserve.gif" : @(NSBitmapImageFileTypeGIF),
104 @"public.jpeg" : @(NSBitmapImageFileTypeJPEG),
106 [BitmapOutputTypeMap retain];
112 NSPasteboard* local_pb = pb;
115 if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
116 types = [local_pb types];
118 // If there are any types understood by NSBitmapImageRep, then we
119 // can offer all of the types that it can output, too. For example,
120 // if TIFF is on the pasteboard, we can offer PNG, BMP, etc. to the
121 // Windows program. We'll convert on demand.
122 if ([types firstObjectCommonWithArray:[NSBitmapImageRep imageTypes]] ||
123 [types firstObjectCommonWithArray:[NSBitmapImageRep imagePasteboardTypes]])
125 NSMutableArray<NSString *> *newTypes = [[BitmapOutputTypeMap allKeys] mutableCopy];
126 [newTypes removeObjectsInArray:types];
127 types = [types arrayByAddingObjectsFromArray:newTypes];
131 ret = (CFArrayRef)[types copy];
135 ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
144 /***********************************************************************
145 * macdrv_copy_pasteboard_data
147 * Returns the pasteboard data for a specified type, or NULL on error or
148 * if there's no such type on the pasteboard. The caller is responsible
149 * for releasing the returned data object with CFRelease().
151 CFDataRef macdrv_copy_pasteboard_data(CFTypeRef pasteboard, CFStringRef type)
153 NSPasteboard* pb = (NSPasteboard*)pasteboard;
154 __block NSData* ret = nil;
159 NSPasteboard* local_pb = pb;
160 if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
161 if ([local_pb availableTypeFromArray:@[(NSString*)type]])
162 ret = [[local_pb dataForType:(NSString*)type] copy];
165 NSNumber* bitmapType = BitmapOutputTypeMap[(NSString*)type];
168 NSArray* reps = [NSBitmapImageRep imageRepsWithPasteboard:local_pb];
169 ret = [NSBitmapImageRep representationOfImageRepsInArray:reps
170 usingType:[bitmapType unsignedIntegerValue]
178 ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
182 return (CFDataRef)ret;
186 /***********************************************************************
187 * macdrv_clear_pasteboard
189 * Takes ownership of the Mac pasteboard and clears it of all data types.
191 void macdrv_clear_pasteboard(macdrv_window w)
193 WineWindow* window = (WineWindow*)w;
198 NSPasteboard* pb = [NSPasteboard generalPasteboard];
199 owned_change_count = [pb declareTypes:@[OwnershipSentinel]
201 [window.queue discardEventsMatchingMask:event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP)
206 ERR(@"Exception discarded while clearing pasteboard: %@\n", e);
212 /***********************************************************************
213 * macdrv_set_pasteboard_data
215 * Sets the pasteboard data for a specified type. Replaces any data of
216 * that type already on the pasteboard. If data is NULL, promises the
219 * Returns 0 on error, non-zero on success.
221 int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data, macdrv_window w)
224 WineWindow* window = (WineWindow*)w;
229 NSPasteboard* pb = [NSPasteboard generalPasteboard];
230 NSInteger change_count = [pb addTypes:@[(NSString*)type]
234 owned_change_count = change_count;
236 ret = [pb setData:(NSData*)data forType:(NSString*)type];
243 ERR(@"Exception discarded while copying pasteboard types: %@\n", e);