2013-03-11 04:58:03 +01:00
|
|
|
/*
|
|
|
|
* MACDRV Cocoa clipboard code
|
|
|
|
*
|
|
|
|
* Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "macdrv_cocoa.h"
|
|
|
|
#import "cocoa_app.h"
|
2013-03-11 04:58:26 +01:00
|
|
|
#import "cocoa_event.h"
|
2016-10-23 20:03:34 +02:00
|
|
|
#import "cocoa_window.h"
|
2013-03-11 04:58:03 +01:00
|
|
|
|
2020-07-23 00:49:57 +02:00
|
|
|
#if !defined(MAC_OS_X_VERSION_10_14) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_14
|
|
|
|
/* For older SDKs, #define the new names of constants deprecated/renamed in macOS 10.14. */
|
|
|
|
#define NSBitmapImageFileTypeBMP NSBMPFileType
|
|
|
|
#define NSBitmapImageFileTypeGIF NSGIFFileType
|
|
|
|
#define NSBitmapImageFileTypeJPEG NSJPEGFileType
|
|
|
|
#define NSBitmapImageFileTypePNG NSPNGFileType
|
|
|
|
#define NSBitmapImageFileTypeTIFF NSTIFFFileType
|
|
|
|
#endif
|
2013-03-11 04:58:03 +01:00
|
|
|
|
2013-03-11 04:58:21 +01:00
|
|
|
static int owned_change_count = -1;
|
2017-05-30 09:56:25 +02:00
|
|
|
static int change_count = -1;
|
2013-03-11 04:58:21 +01:00
|
|
|
|
2013-03-13 22:52:43 +01:00
|
|
|
static NSArray* BitmapOutputTypes;
|
|
|
|
static NSDictionary* BitmapOutputTypeMap;
|
|
|
|
static dispatch_once_t BitmapOutputTypesInitOnce;
|
|
|
|
|
2016-10-23 20:03:34 +02:00
|
|
|
static NSString* const OwnershipSentinel = @"org.winehq.wine.winemac.pasteboard-ownership-sentinel";
|
|
|
|
|
2013-03-11 04:58:21 +01:00
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* macdrv_is_pasteboard_owner
|
|
|
|
*/
|
2016-10-23 20:03:34 +02:00
|
|
|
int macdrv_is_pasteboard_owner(macdrv_window w)
|
2013-03-11 04:58:21 +01:00
|
|
|
{
|
|
|
|
__block int ret;
|
2016-10-23 20:03:34 +02:00
|
|
|
WineWindow* window = (WineWindow*)w;
|
2013-03-11 04:58:21 +01:00
|
|
|
|
|
|
|
OnMainThread(^{
|
|
|
|
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
|
|
|
ret = ([pb changeCount] == owned_change_count);
|
2016-10-23 20:03:34 +02:00
|
|
|
|
|
|
|
[window.queue discardEventsMatchingMask:event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP)
|
|
|
|
forWindow:window];
|
2013-03-11 04:58:21 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-05-30 09:56:25 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* macdrv_has_pasteboard_changed
|
|
|
|
*/
|
|
|
|
int macdrv_has_pasteboard_changed(void)
|
|
|
|
{
|
|
|
|
__block int new_change_count;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
OnMainThread(^{
|
|
|
|
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
|
|
|
new_change_count = [pb changeCount];
|
|
|
|
});
|
|
|
|
|
|
|
|
ret = (change_count != new_change_count);
|
|
|
|
change_count = new_change_count;
|
|
|
|
return ret;
|
|
|
|
}
|
2013-03-11 04:58:21 +01:00
|
|
|
|
2013-03-11 04:58:03 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* macdrv_copy_pasteboard_types
|
|
|
|
*
|
|
|
|
* Returns an array of UTI strings for the types of data available on
|
|
|
|
* the pasteboard, or NULL on error. The caller is responsible for
|
|
|
|
* releasing the returned array with CFRelease().
|
|
|
|
*/
|
2013-03-13 22:53:04 +01:00
|
|
|
CFArrayRef macdrv_copy_pasteboard_types(CFTypeRef pasteboard)
|
2013-03-11 04:58:03 +01:00
|
|
|
{
|
2013-03-13 22:53:04 +01:00
|
|
|
NSPasteboard* pb = (NSPasteboard*)pasteboard;
|
2013-03-11 04:58:03 +01:00
|
|
|
__block CFArrayRef ret = NULL;
|
|
|
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
|
2013-03-13 22:52:43 +01:00
|
|
|
dispatch_once(&BitmapOutputTypesInitOnce, ^{
|
|
|
|
NSArray* bitmapFileTypes = [NSArray arrayWithObjects:
|
2020-07-23 00:49:57 +02:00
|
|
|
[NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypeTIFF],
|
|
|
|
[NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypePNG],
|
|
|
|
[NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypeBMP],
|
|
|
|
[NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypeGIF],
|
|
|
|
[NSNumber numberWithUnsignedInteger:NSBitmapImageFileTypeJPEG],
|
2013-03-13 22:52:43 +01:00
|
|
|
nil];
|
|
|
|
|
|
|
|
BitmapOutputTypes = [[NSArray alloc] initWithObjects:@"public.tiff", @"public.png",
|
2015-10-07 23:22:27 +02:00
|
|
|
@"com.microsoft.bmp", @"com.compuserve.gif", @"public.jpeg", nil];
|
2013-03-13 22:52:43 +01:00
|
|
|
|
|
|
|
BitmapOutputTypeMap = [[NSDictionary alloc] initWithObjects:bitmapFileTypes
|
|
|
|
forKeys:BitmapOutputTypes];
|
|
|
|
});
|
|
|
|
|
2013-03-11 04:58:03 +01:00
|
|
|
OnMainThread(^{
|
|
|
|
@try
|
|
|
|
{
|
2013-03-13 22:53:04 +01:00
|
|
|
NSPasteboard* local_pb = pb;
|
|
|
|
NSArray* types;
|
|
|
|
|
|
|
|
if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
|
|
|
|
types = [local_pb types];
|
2013-03-13 22:52:43 +01:00
|
|
|
|
|
|
|
// If there are any types understood by NSBitmapImageRep, then we
|
|
|
|
// can offer all of the types that it can output, too. For example,
|
|
|
|
// if TIFF is on the pasteboard, we can offer PNG, BMP, etc. to the
|
|
|
|
// Windows program. We'll convert on demand.
|
|
|
|
if ([types firstObjectCommonWithArray:[NSBitmapImageRep imageTypes]] ||
|
|
|
|
[types firstObjectCommonWithArray:[NSBitmapImageRep imagePasteboardTypes]])
|
|
|
|
{
|
|
|
|
NSMutableArray* newTypes = [BitmapOutputTypes mutableCopy];
|
|
|
|
[newTypes removeObjectsInArray:types];
|
|
|
|
types = [types arrayByAddingObjectsFromArray:newTypes];
|
|
|
|
[newTypes release];
|
|
|
|
}
|
|
|
|
|
2013-03-11 04:58:03 +01:00
|
|
|
ret = (CFArrayRef)[types copy];
|
|
|
|
}
|
|
|
|
@catch (id e)
|
|
|
|
{
|
|
|
|
ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
[pool release];
|
|
|
|
return ret;
|
|
|
|
}
|
2013-03-11 04:58:18 +01:00
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* macdrv_copy_pasteboard_data
|
|
|
|
*
|
|
|
|
* Returns the pasteboard data for a specified type, or NULL on error or
|
|
|
|
* if there's no such type on the pasteboard. The caller is responsible
|
|
|
|
* for releasing the returned data object with CFRelease().
|
|
|
|
*/
|
2013-03-13 22:53:04 +01:00
|
|
|
CFDataRef macdrv_copy_pasteboard_data(CFTypeRef pasteboard, CFStringRef type)
|
2013-03-11 04:58:18 +01:00
|
|
|
{
|
2013-03-13 22:53:04 +01:00
|
|
|
NSPasteboard* pb = (NSPasteboard*)pasteboard;
|
2013-03-11 04:58:18 +01:00
|
|
|
__block NSData* ret = nil;
|
|
|
|
|
|
|
|
OnMainThread(^{
|
|
|
|
@try
|
|
|
|
{
|
2013-03-13 22:53:04 +01:00
|
|
|
NSPasteboard* local_pb = pb;
|
|
|
|
if (!local_pb) local_pb = [NSPasteboard generalPasteboard];
|
|
|
|
if ([local_pb availableTypeFromArray:[NSArray arrayWithObject:(NSString*)type]])
|
|
|
|
ret = [[local_pb dataForType:(NSString*)type] copy];
|
2013-03-13 22:52:43 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
NSNumber* bitmapType = [BitmapOutputTypeMap objectForKey:(NSString*)type];
|
|
|
|
if (bitmapType)
|
|
|
|
{
|
2013-03-13 22:53:04 +01:00
|
|
|
NSArray* reps = [NSBitmapImageRep imageRepsWithPasteboard:local_pb];
|
2013-03-13 22:52:43 +01:00
|
|
|
ret = [NSBitmapImageRep representationOfImageRepsInArray:reps
|
|
|
|
usingType:[bitmapType unsignedIntegerValue]
|
|
|
|
properties:nil];
|
|
|
|
ret = [ret copy];
|
|
|
|
}
|
|
|
|
}
|
2013-03-11 04:58:18 +01:00
|
|
|
}
|
|
|
|
@catch (id e)
|
|
|
|
{
|
|
|
|
ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return (CFDataRef)ret;
|
|
|
|
}
|
2013-03-11 04:58:21 +01:00
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* macdrv_clear_pasteboard
|
|
|
|
*
|
|
|
|
* Takes ownership of the Mac pasteboard and clears it of all data types.
|
|
|
|
*/
|
2016-10-23 20:03:34 +02:00
|
|
|
void macdrv_clear_pasteboard(macdrv_window w)
|
2013-03-11 04:58:21 +01:00
|
|
|
{
|
2016-10-23 20:03:34 +02:00
|
|
|
WineWindow* window = (WineWindow*)w;
|
|
|
|
|
|
|
|
OnMainThread(^{
|
2013-03-11 04:58:21 +01:00
|
|
|
@try
|
|
|
|
{
|
|
|
|
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
2016-10-23 20:03:34 +02:00
|
|
|
owned_change_count = [pb declareTypes:[NSArray arrayWithObject:OwnershipSentinel]
|
|
|
|
owner:window];
|
|
|
|
[window.queue discardEventsMatchingMask:event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP)
|
|
|
|
forWindow:window];
|
2013-03-11 04:58:21 +01:00
|
|
|
}
|
|
|
|
@catch (id e)
|
|
|
|
{
|
|
|
|
ERR(@"Exception discarded while clearing pasteboard: %@\n", e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* macdrv_set_pasteboard_data
|
|
|
|
*
|
|
|
|
* Sets the pasteboard data for a specified type. Replaces any data of
|
2013-03-11 04:58:51 +01:00
|
|
|
* that type already on the pasteboard. If data is NULL, promises the
|
|
|
|
* type.
|
2013-03-11 04:58:21 +01:00
|
|
|
*
|
|
|
|
* Returns 0 on error, non-zero on success.
|
|
|
|
*/
|
2013-03-11 04:58:51 +01:00
|
|
|
int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data, macdrv_window w)
|
2013-03-11 04:58:21 +01:00
|
|
|
{
|
|
|
|
__block int ret = 0;
|
2013-03-11 04:58:51 +01:00
|
|
|
WineWindow* window = (WineWindow*)w;
|
2013-03-11 04:58:21 +01:00
|
|
|
|
|
|
|
OnMainThread(^{
|
|
|
|
@try
|
|
|
|
{
|
|
|
|
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
|
|
|
NSInteger change_count = [pb addTypes:[NSArray arrayWithObject:(NSString*)type]
|
2013-03-11 04:58:51 +01:00
|
|
|
owner:window];
|
2013-03-11 04:58:21 +01:00
|
|
|
if (change_count)
|
|
|
|
{
|
|
|
|
owned_change_count = change_count;
|
|
|
|
if (data)
|
|
|
|
ret = [pb setData:(NSData*)data forType:(NSString*)type];
|
|
|
|
else
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@catch (id e)
|
|
|
|
{
|
|
|
|
ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|