mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-24 18:31:20 +00:00
filter service fixes
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@34752 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
e45d3a78c6
commit
dd9b7cd6f8
3 changed files with 151 additions and 109 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2012-02-08 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSPasteboard.m: Use an NSMapTable to store pasteboards so we
|
||||
don't have to do the nasty retain count hack to deallocate them.
|
||||
Fix encoding so that filter meta-pasteboards are sent to gpbs by
|
||||
reference rather than bycopy. Add special proxy to avoid data objects
|
||||
being copied to/from pasteboard server when created by filters.
|
||||
* Tools/make_services.m: Fix buggy initialisation of 'verbose' setting.
|
||||
Add check/warning if filter service has non-filename send types.
|
||||
|
||||
2012-02-08 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/NSPasteboard.m (+pasteboardByFilteringFile:): Correct
|
||||
|
|
|
@ -556,6 +556,64 @@
|
|||
static NSString *contentsPrefix = @"NSTypedFileContentsPboardType:";
|
||||
static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
||||
|
||||
/* This is a proxy used to send objects over DO by reference when they
|
||||
* would normally be copied.
|
||||
* The idea is to use such a proxy when a filter sends data to a pasteboard.
|
||||
* Since the filtered data will only be used in the process which sets up
|
||||
* the filter, there's no point sending it on a round trip to the
|
||||
* pasteboard server and back ... instead we encode a GSByrefObject, which
|
||||
* appears as a proxy/reference on the remote system (pasteboard server)
|
||||
* but when the pasteboard server sends it back it decodes locally as the
|
||||
* original data object.
|
||||
*/
|
||||
@interface GSByrefObject : NSObject
|
||||
{
|
||||
NSObject *target;
|
||||
}
|
||||
+ (id) byrefWithObject: (NSObject*)object;
|
||||
@end
|
||||
|
||||
@implementation GSByrefObject
|
||||
|
||||
+ (id) byrefWithObject: (NSObject*)object
|
||||
{
|
||||
GSByrefObject *b = [GSByrefObject new];
|
||||
b->target = [object retain];
|
||||
return [b autorelease];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[target release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) forwardInvocation: (NSInvocation*)anInvocation
|
||||
{
|
||||
[anInvocation invokeWithTarget: target];
|
||||
}
|
||||
|
||||
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
|
||||
{
|
||||
if (class_respondsToSelector(object_getClass(self), aSelector))
|
||||
{
|
||||
return [super methodSignatureForSelector: aSelector];
|
||||
}
|
||||
return [target methodSignatureForSelector: aSelector];
|
||||
}
|
||||
|
||||
/* Encode this proxy as a reference to its target.
|
||||
* That way when the reference is passed back to this process it
|
||||
* will decode as the original target object rather than the proxy.
|
||||
*/
|
||||
- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
|
||||
{
|
||||
return [NSDistantObject proxyWithLocal: target
|
||||
connection: [aCoder connection]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
* A pasteboard class for lazily filtering data
|
||||
*/
|
||||
|
@ -614,52 +672,6 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
/**
|
||||
* GSFiltered instances are encoded differently from standard pasteboards,
|
||||
* they have no names and are instead represented by whatever it is they
|
||||
* are filtering.
|
||||
*/
|
||||
- (void) encodeWithCoder: (NSCoder*)aCoder
|
||||
{
|
||||
if (data != nil)
|
||||
{
|
||||
[aCoder encodeObject: data];
|
||||
[aCoder encodeObject: [originalTypes lastObject]];
|
||||
}
|
||||
else if (file != nil)
|
||||
{
|
||||
[aCoder encodeObject: file];
|
||||
}
|
||||
else
|
||||
{
|
||||
[aCoder encodeObject: pboard];
|
||||
}
|
||||
}
|
||||
|
||||
- (id) initWithCoder: (NSCoder*)aCoder
|
||||
{
|
||||
NSPasteboard *p = nil;
|
||||
id val = [aCoder decodeObject];
|
||||
|
||||
if ([val isKindOfClass: [NSData class]] == YES)
|
||||
{
|
||||
NSString *s = [aCoder decodeObject];
|
||||
|
||||
p = [NSPasteboard pasteboardByFilteringData: val ofType: s];
|
||||
}
|
||||
else if ([val isKindOfClass: [NSString class]] == YES)
|
||||
{
|
||||
p = [NSPasteboard pasteboardByFilteringFile: val];
|
||||
}
|
||||
else
|
||||
{
|
||||
p = [NSPasteboard pasteboardByFilteringTypesInPasteboard: val];
|
||||
}
|
||||
|
||||
RELEASE(self);
|
||||
return RETAIN(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method actually performs any filtering required.
|
||||
*/
|
||||
|
@ -734,6 +746,7 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
|||
NSString *path;
|
||||
NSData *d;
|
||||
NSPipe *p;
|
||||
NSFileHandle *h;
|
||||
NSTask *t;
|
||||
id o;
|
||||
|
||||
|
@ -800,8 +813,8 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
|||
/*
|
||||
* Read all the data that the task writes.
|
||||
*/
|
||||
while ((d = [[p fileHandleForReading] availableData]) != nil
|
||||
&& [d length] > 0)
|
||||
h = [p fileHandleForReading];
|
||||
while ([(d = [h availableData]) length] > 0)
|
||||
{
|
||||
[m appendData: d];
|
||||
}
|
||||
|
@ -811,7 +824,7 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
|||
/*
|
||||
* And send it on.
|
||||
*/
|
||||
[sender setData: m forType: type];
|
||||
[sender setData: [GSByrefObject byrefWithObject: m] forType: type];
|
||||
}
|
||||
else if ([mechanism isEqualToString: @"NSMapFile"] == YES)
|
||||
{
|
||||
|
@ -852,7 +865,7 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
|||
|
||||
d = [NSData dataWithContentsOfFile: filename];
|
||||
|
||||
[sender setData: d forType: type];
|
||||
[sender setData: [GSByrefObject byrefWithObject: d] forType: type];
|
||||
}
|
||||
else if ([mechanism isEqualToString: @"NSIdentity"] == YES)
|
||||
{
|
||||
|
@ -872,7 +885,7 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
|||
{
|
||||
NSData *d = [pboard dataForType: type];
|
||||
|
||||
[sender setData: d forType: type];
|
||||
[sender setData: [GSByrefObject byrefWithObject: d] forType: type];
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1012,7 +1025,8 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
|||
/*
|
||||
* Finally, make it available.
|
||||
*/
|
||||
[sender setData: [tmp dataForType: type] forType: type];
|
||||
[sender setData: [GSByrefObject byrefWithObject: [tmp dataForType: type]]
|
||||
forType: type];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1062,7 +1076,7 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
|
|||
@implementation NSPasteboard
|
||||
|
||||
static NSRecursiveLock *dictionary_lock = nil;
|
||||
static NSMutableDictionary *pasteboards = nil;
|
||||
static NSMapTable *pasteboards = 0;
|
||||
static id<GSPasteboardSvr> the_server = nil;
|
||||
static NSMapTable *mimeMap = NULL;
|
||||
|
||||
|
@ -1091,7 +1105,8 @@ static NSMapTable *mimeMap = NULL;
|
|||
// Initial version
|
||||
[self setVersion: 1];
|
||||
dictionary_lock = [[NSRecursiveLock alloc] init];
|
||||
pasteboards = [[NSMutableDictionary alloc] initWithCapacity: 8];
|
||||
pasteboards = NSCreateMapTable (NSObjectMapKeyCallBacks,
|
||||
NSNonRetainedObjectMapValueCallBacks, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1420,11 +1435,23 @@ static NSMapTable *mimeMap = NULL;
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(target);
|
||||
RELEASE(name);
|
||||
DESTROY(target);
|
||||
[dictionary_lock lock];
|
||||
if (NSMapGet(pasteboards, (void*)name) == (void*)self)
|
||||
{
|
||||
NSMapRemove(pasteboards, (void*)name);
|
||||
}
|
||||
DESTROY(name);
|
||||
[dictionary_lock unlock];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString*) description
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@ %@ %p",
|
||||
[super description], name, target];
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode for DO by using just our name.
|
||||
*/
|
||||
|
@ -1472,7 +1499,10 @@ static NSMapTable *mimeMap = NULL;
|
|||
}
|
||||
[target releaseGlobally];
|
||||
[dictionary_lock lock];
|
||||
[pasteboards removeObjectForKey: name];
|
||||
if (NSMapGet(pasteboards, (void*)name) == (void*)self)
|
||||
{
|
||||
NSMapRemove(pasteboards, (void*)name);
|
||||
}
|
||||
[dictionary_lock unlock];
|
||||
}
|
||||
|
||||
|
@ -1486,33 +1516,16 @@ static NSMapTable *mimeMap = NULL;
|
|||
{
|
||||
return self; // Always encode bycopy.
|
||||
}
|
||||
if ([self class] == [GSFiltered class])
|
||||
{
|
||||
return self; // Always encode bycopy.
|
||||
}
|
||||
return [super replacementObjectForPortCoder: aCoder];
|
||||
}
|
||||
|
||||
/*
|
||||
* Hack to ensure correct release of NSPasteboard objects -
|
||||
* If we are released such that the only thing retaining us
|
||||
* is the pasteboards dictionary, remove us from that dictionary
|
||||
* as well.
|
||||
*/
|
||||
- (oneway void) release
|
||||
{
|
||||
if ([self retainCount] == 2)
|
||||
{
|
||||
[dictionary_lock lock];
|
||||
if ([self retainCount] == 2)
|
||||
{
|
||||
[super retain];
|
||||
[pasteboards removeObjectForKey: name];
|
||||
[super release];
|
||||
}
|
||||
[dictionary_lock unlock];
|
||||
}
|
||||
[super release];
|
||||
/* But ... if this is actually a filter rather than a 'real' pasteboard,
|
||||
* we don't want it copied to the pasteboard server.
|
||||
*/
|
||||
if ([self class] == [GSFiltered class])
|
||||
{
|
||||
return [super replacementObjectForPortCoder: aCoder];
|
||||
}
|
||||
|
||||
return [super replacementObjectForPortCoder: aCoder];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2086,7 +2099,7 @@ description, [cmd stringByDeletingLastPathComponent]);
|
|||
NSPasteboard *p = nil;
|
||||
|
||||
[dictionary_lock lock];
|
||||
p = [pasteboards objectForKey: aName];
|
||||
p = (NSPasteboard*)NSMapGet(pasteboards, (void*)aName);
|
||||
if (p != nil)
|
||||
{
|
||||
/*
|
||||
|
@ -2101,8 +2114,7 @@ description, [cmd stringByDeletingLastPathComponent]);
|
|||
*/
|
||||
if (p->target != (id)aTarget)
|
||||
{
|
||||
AUTORELEASE(p->target);
|
||||
p->target = RETAIN((id)aTarget);
|
||||
ASSIGN(p->target, (id)aTarget);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2114,18 +2126,11 @@ description, [cmd stringByDeletingLastPathComponent]);
|
|||
p = [self alloc];
|
||||
if (p != nil)
|
||||
{
|
||||
p->target = RETAIN((id)aTarget);
|
||||
p->name = RETAIN(aName);
|
||||
[pasteboards setObject: p forKey: aName];
|
||||
AUTORELEASE(p);
|
||||
ASSIGN(p->target, (id)aTarget);
|
||||
ASSIGNCOPY(p->name, aName);
|
||||
NSMapInsert(pasteboards, (void*)p, (void*)p->name);
|
||||
[p autorelease];
|
||||
}
|
||||
/*
|
||||
* The AUTORELEASE ensures that the NSPasteboard object we are
|
||||
* returning will be released once our caller has finished with it.
|
||||
* This is necessary so that our RELEASE method will be called to
|
||||
* remove the NSPasteboard from the 'pasteboards' array when it is not
|
||||
* needed any more.
|
||||
*/
|
||||
}
|
||||
p->changeCount = [p->target changeCount];
|
||||
[dictionary_lock unlock];
|
||||
|
|
|
@ -50,7 +50,7 @@ static NSMutableDictionary *validateService(NSDictionary *service, NSString* pat
|
|||
static NSString *appsName = @".GNUstepAppList";
|
||||
static NSString *cacheName = @".GNUstepServices";
|
||||
|
||||
static int verbose = 0;
|
||||
static int verbose = 1;
|
||||
static NSMutableDictionary *serviceMap;
|
||||
static NSMutableArray *filterList;
|
||||
static NSMutableSet *filterSet;
|
||||
|
@ -162,7 +162,6 @@ main(int argc, char** argv, char **env_c)
|
|||
}
|
||||
if ([[args objectAtIndex: index] isEqual: @"--test"])
|
||||
{
|
||||
verbose = YES;
|
||||
while (++index < [args count])
|
||||
{
|
||||
NSString *file = [args objectAtIndex: index];
|
||||
|
@ -1080,17 +1079,47 @@ validateService(NSDictionary *service, NSString *path, unsigned pos)
|
|||
NSArray *ret;
|
||||
BOOL notPresent = NO;
|
||||
|
||||
snd = [result objectForKey: @"NSSendTypes"];
|
||||
ret = [result objectForKey: @"NSReturnTypes"];
|
||||
str = [result objectForKey: @"NSInputMechanism"];
|
||||
if (str != nil)
|
||||
{
|
||||
if ([str isEqualToString: @"NSUnixStdio"] == NO
|
||||
&& [str isEqualToString: @"NSMapFile"] == NO
|
||||
&& [str isEqualToString: @"NSIdentity"] == NO)
|
||||
{
|
||||
if (verbose > 0)
|
||||
NSLog(@"NSServices entry %u bad input mechanism - %@", pos, path);
|
||||
return nil;
|
||||
}
|
||||
if ([str isEqualToString: @"NSUnixStdio"] == YES
|
||||
|| [str isEqualToString: @"NSMapFile"] == YES)
|
||||
{
|
||||
unsigned i = [snd count];
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
NSString *type;
|
||||
|
||||
str = [snd objectAtIndex: i];
|
||||
/* For UNIX I/O or file mapping, the send type must be a
|
||||
* filename ... which means it must either be the generic
|
||||
* filenames pasteboard type, or one of the pasteboard
|
||||
* types corresponding to names for a particular file type.
|
||||
*/
|
||||
if (NO == [str isEqual: @"NSFilenamesPboardType"]
|
||||
&& NO == [str hasPrefix: @"NSTypedFilenamesPboardType:"])
|
||||
{
|
||||
if (verbose > 0)
|
||||
{
|
||||
NSLog(@"NSServices entry %u bad NSSendTypes "
|
||||
@"(must be file names types) - %@",
|
||||
pos, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ([str isEqualToString: @"NSIdentity"] == NO)
|
||||
{
|
||||
if (verbose > 0)
|
||||
{
|
||||
NSLog(@"NSServices entry %u bad input mechanism - %@",
|
||||
pos, path);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else if ([result objectForKey: @"NSPortName"] == nil)
|
||||
{
|
||||
|
@ -1099,8 +1128,6 @@ validateService(NSDictionary *service, NSString *path, unsigned pos)
|
|||
return nil;
|
||||
}
|
||||
|
||||
snd = [result objectForKey: @"NSSendTypes"];
|
||||
ret = [result objectForKey: @"NSReturnTypes"];
|
||||
if ([snd count] == 0 || [ret count] == 0)
|
||||
{
|
||||
if (verbose > 0)
|
||||
|
|
Loading…
Reference in a new issue