1996-05-30 20:03:15 +00:00
|
|
|
/*
|
|
|
|
NSPasteboard.m
|
|
|
|
|
1997-09-01 20:21:07 +00:00
|
|
|
Description... Implementation of class for communicating with the
|
|
|
|
pasteboard server.
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-04-29 10:05:24 +00:00
|
|
|
Copyright (C) 1997,1999 Free Software Foundation, Inc.
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1997-09-01 20:21:07 +00:00
|
|
|
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
Date: 1997
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
|
|
This file is part of the GNUstep GUI Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
1996-10-18 17:14:13 +00:00
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, write to the Free Software Foundation,
|
|
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
1996-05-30 20:03:15 +00:00
|
|
|
*/
|
|
|
|
|
1997-09-23 22:43:24 +00:00
|
|
|
#include <gnustep/gui/config.h>
|
1997-02-18 00:29:25 +00:00
|
|
|
#include <AppKit/NSPasteboard.h>
|
1998-11-18 09:41:47 +00:00
|
|
|
#include <AppKit/NSApplication.h>
|
1998-11-23 21:39:58 +00:00
|
|
|
#include <AppKit/NSWorkspace.h>
|
1997-09-01 20:21:07 +00:00
|
|
|
#include <Foundation/NSArray.h>
|
|
|
|
#include <Foundation/NSData.h>
|
|
|
|
#include <Foundation/NSDictionary.h>
|
|
|
|
#include <Foundation/NSConnection.h>
|
|
|
|
#include <Foundation/NSDistantObject.h>
|
1999-07-29 20:58:04 +00:00
|
|
|
#include <Foundation/NSMapTable.h>
|
1997-09-01 20:21:07 +00:00
|
|
|
#include <Foundation/NSNotification.h>
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <Foundation/NSLock.h>
|
1998-11-18 09:41:47 +00:00
|
|
|
#include <Foundation/NSPortNameServer.h>
|
1997-09-01 20:21:07 +00:00
|
|
|
#include <Foundation/NSProcessInfo.h>
|
|
|
|
#include <Foundation/NSSerialization.h>
|
1997-09-02 09:45:22 +00:00
|
|
|
#include <Foundation/NSUserDefaults.h>
|
1998-11-23 21:39:58 +00:00
|
|
|
#include <Foundation/NSMethodSignature.h>
|
|
|
|
#include <Foundation/NSRunLoop.h>
|
1999-04-14 14:42:50 +00:00
|
|
|
#include <Foundation/NSTask.h>
|
1998-11-23 21:39:58 +00:00
|
|
|
#include <Foundation/NSTimer.h>
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-04-29 10:05:24 +00:00
|
|
|
#include <gnustep/gui/GSPasteboardServer.h>
|
|
|
|
|
1998-11-18 09:41:47 +00:00
|
|
|
#define stringify_it(X) #X
|
1999-04-14 14:42:50 +00:00
|
|
|
#define prog_path(X) stringify_it(X) "/Tools/gpbs"
|
1998-11-18 09:41:47 +00:00
|
|
|
|
1997-09-01 20:21:07 +00:00
|
|
|
@interface NSPasteboard (Private)
|
1999-04-29 10:05:24 +00:00
|
|
|
+ (id<GSPasteboardSvr>) _pbs;
|
|
|
|
+ (NSPasteboard*) _pasteboardWithTarget: (id<GSPasteboardObj>)aTarget
|
1997-09-01 20:21:07 +00:00
|
|
|
name: (NSString*)aName;
|
|
|
|
- (id) _target;
|
|
|
|
@end
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
|
|
@implementation NSPasteboard
|
|
|
|
|
1997-09-01 20:21:07 +00:00
|
|
|
static NSLock *dictionary_lock = nil;
|
|
|
|
static NSMutableDictionary *pasteboards = nil;
|
1999-04-29 10:05:24 +00:00
|
|
|
static id<GSPasteboardSvr> the_server = nil;
|
1999-07-29 20:58:04 +00:00
|
|
|
static NSMapTable *mimeMap = NULL;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
//
|
|
|
|
// Class methods
|
|
|
|
//
|
1999-05-27 18:21:46 +00:00
|
|
|
+ (void) initialize
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
|
|
|
if (self == [NSPasteboard class])
|
|
|
|
{
|
|
|
|
// Initial version
|
1999-05-27 18:21:46 +00:00
|
|
|
[self setVersion: 1];
|
1997-09-01 20:21:07 +00:00
|
|
|
dictionary_lock = [[NSLock alloc] init];
|
1999-05-27 18:21:46 +00:00
|
|
|
pasteboards = [[NSMutableDictionary alloc] initWithCapacity: 8];
|
1997-09-01 20:21:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Special method to use a local server rather than connecting over DO
|
|
|
|
*/
|
|
|
|
+ (void) _localServer: (id<GSPasteboardSvr>)s
|
|
|
|
{
|
|
|
|
the_server = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (id) _lostServer: (NSNotification*)notification
|
1997-09-01 20:21:07 +00:00
|
|
|
{
|
|
|
|
id obj = the_server;
|
|
|
|
|
|
|
|
the_server = nil;
|
1999-06-15 20:02:58 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
removeObserver: self
|
|
|
|
name: NSConnectionDidDieNotification
|
|
|
|
object: [notification object]];
|
1997-09-01 20:21:07 +00:00
|
|
|
[obj release];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1999-04-29 10:05:24 +00:00
|
|
|
+ (id<GSPasteboardSvr>) _pbs
|
1997-09-01 20:21:07 +00:00
|
|
|
{
|
1998-11-18 09:41:47 +00:00
|
|
|
if (the_server == nil)
|
|
|
|
{
|
|
|
|
NSString* host;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1998-11-18 09:41:47 +00:00
|
|
|
host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"];
|
|
|
|
if (host == nil)
|
|
|
|
{
|
|
|
|
host = [[NSProcessInfo processInfo] hostName];
|
|
|
|
}
|
1999-04-29 10:05:24 +00:00
|
|
|
the_server = (id<GSPasteboardSvr>)[NSConnection
|
1998-11-18 09:41:47 +00:00
|
|
|
rootProxyForConnectionWithRegisteredName: PBSNAME
|
|
|
|
host: host];
|
|
|
|
if ([(id)the_server retain])
|
|
|
|
{
|
|
|
|
NSConnection* conn = [(id)the_server connectionForProxy];
|
|
|
|
|
1999-06-15 20:02:58 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserver: self
|
|
|
|
selector: @selector(_lostServer:)
|
|
|
|
name: NSConnectionDidDieNotification
|
|
|
|
object: conn];
|
1998-11-18 09:41:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
static BOOL recursion = NO;
|
|
|
|
|
|
|
|
if (recursion)
|
|
|
|
{
|
|
|
|
NSLog(@"Unable to contact pasteboard server - "
|
|
|
|
@"please ensure that gpbs is running.\n");
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-04-14 14:42:50 +00:00
|
|
|
static NSString *cmd = nil;
|
1998-11-23 21:39:58 +00:00
|
|
|
|
1999-04-14 14:42:50 +00:00
|
|
|
if (cmd == nil)
|
1999-05-27 18:21:46 +00:00
|
|
|
cmd = [NSString stringWithCString:
|
1999-04-14 14:42:50 +00:00
|
|
|
prog_path(GNUSTEP_INSTALL_PREFIX)];
|
|
|
|
[NSTask launchedTaskWithLaunchPath: cmd arguments: nil];
|
1998-11-23 21:39:58 +00:00
|
|
|
[NSTimer scheduledTimerWithTimeInterval: 5.0
|
|
|
|
invocation: nil
|
|
|
|
repeats: NO];
|
1999-05-27 18:21:46 +00:00
|
|
|
[[NSRunLoop currentRunLoop] runUntilDate:
|
1999-04-14 14:42:50 +00:00
|
|
|
[NSDate dateWithTimeIntervalSinceNow: 5.0]];
|
1998-11-18 09:41:47 +00:00
|
|
|
recursion = YES;
|
|
|
|
[self _pbs];
|
|
|
|
recursion = NO;
|
|
|
|
}
|
|
|
|
}
|
1997-10-28 12:56:39 +00:00
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
return the_server;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Creating and Releasing an NSPasteboard Object
|
|
|
|
*/
|
1999-04-29 10:05:24 +00:00
|
|
|
+ (NSPasteboard*) _pasteboardWithTarget: (id<GSPasteboardObj>)aTarget
|
1997-09-01 20:21:07 +00:00
|
|
|
name: (NSString*)aName
|
|
|
|
{
|
|
|
|
NSPasteboard* p = nil;
|
|
|
|
|
|
|
|
[dictionary_lock lock];
|
|
|
|
p = [pasteboards objectForKey: aName];
|
1999-05-27 18:21:46 +00:00
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* It is conceivable that the following may have occurred -
|
|
|
|
* 1. The pasteboard was created on the server
|
|
|
|
* 2. We set up an NSPasteboard to point to it
|
|
|
|
* 3. The pasteboard on the server was destroyed by a [-releaseGlobally]
|
|
|
|
* 4. The named pasteboard was asked for again - resulting in a new
|
|
|
|
* object being created on the server.
|
|
|
|
* If this is the case, our proxy for the object on the server will be
|
|
|
|
* out of date, so we swap it for the newly created one.
|
|
|
|
*/
|
|
|
|
if (p->target != (id)aTarget)
|
|
|
|
{
|
|
|
|
[p->target autorelease];
|
|
|
|
p->target = [(id)aTarget retain];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For a newly created NSPasteboard object, we must make an entry
|
|
|
|
* in the dictionary so we can look it up safely.
|
|
|
|
*/
|
|
|
|
p = [NSPasteboard alloc];
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
p->target = [(id)aTarget retain];
|
|
|
|
p->name = [aName retain];
|
|
|
|
[pasteboards setObject: p forKey: aName];
|
|
|
|
[p autorelease];
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* The [-autorelease] message 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.
|
|
|
|
*/
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
[dictionary_lock unlock];
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
+ (NSPasteboard*) generalPasteboard
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
return [self pasteboardWithName: NSGeneralPboard];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
+ (NSPasteboard*) pasteboardWithName: (NSString*)aName
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
id<GSPasteboardObj> anObj;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
anObj = [[self _pbs] pasteboardWithName: aName];
|
|
|
|
if (anObj)
|
|
|
|
{
|
|
|
|
NSPasteboard *ret;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
ret = [self _pasteboardWithTarget: anObj name: aName];
|
|
|
|
NS_VALRETURN(ret);
|
|
|
|
}
|
1997-10-28 12:21:23 +00:00
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%%", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
+ (NSPasteboard*) pasteboardWithUniqueName
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
id<GSPasteboardObj> anObj;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
anObj = [[self _pbs] pasteboardWithUniqueName];
|
|
|
|
if (anObj)
|
|
|
|
{
|
|
|
|
NSString *aName;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
aName = [anObj name];
|
|
|
|
if (aName)
|
|
|
|
{
|
|
|
|
NSPasteboard *ret;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
ret = [self _pasteboardWithTarget: anObj name: aName];
|
|
|
|
NS_VALRETURN(ret);
|
|
|
|
}
|
|
|
|
}
|
1997-10-28 12:21:23 +00:00
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Getting Data in Different Formats
|
|
|
|
*/
|
|
|
|
+ (NSPasteboard*) pasteboardByFilteringData: (NSData*)data
|
|
|
|
ofType: (NSString*)type
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
id<GSPasteboardObj> anObj;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
anObj = [[self _pbs] pasteboardByFilteringData: data
|
|
|
|
ofType: type
|
|
|
|
isFile: NO];
|
|
|
|
if (anObj)
|
|
|
|
{
|
|
|
|
NSString *aName;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
aName = [anObj name];
|
|
|
|
if (aName)
|
|
|
|
{
|
|
|
|
NSPasteboard *ret;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
ret = [self _pasteboardWithTarget: anObj name: aName];
|
|
|
|
NS_VALRETURN(ret);
|
|
|
|
}
|
|
|
|
}
|
1997-10-28 12:21:23 +00:00
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
+ (NSPasteboard*) pasteboardByFilteringFile: (NSString*)filename
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
NSData *data;
|
|
|
|
NSString *type;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
data = [NSData dataWithContentsOfFile: filename];
|
|
|
|
type = NSCreateFileContentsPboardType([filename pathExtension]);
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
id<GSPasteboardObj> anObj;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
anObj = [[self _pbs] pasteboardByFilteringData: data
|
|
|
|
ofType: type
|
|
|
|
isFile: YES];
|
|
|
|
if (anObj)
|
|
|
|
{
|
|
|
|
NSString *aName;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
aName = [anObj name];
|
|
|
|
if (aName)
|
|
|
|
{
|
|
|
|
NSPasteboard *ret;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
ret = [self _pasteboardWithTarget: anObj name: aName];
|
|
|
|
NS_VALRETURN(ret);
|
|
|
|
}
|
|
|
|
}
|
1997-10-28 12:21:23 +00:00
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
+ (NSPasteboard*) pasteboardByFilteringTypesInPasteboard: (NSPasteboard*)pboard
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
id<GSPasteboardObj> anObj;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
anObj = [pboard _target];
|
|
|
|
if (anObj)
|
|
|
|
{
|
|
|
|
anObj = [[self _pbs] pasteboardByFilteringTypesInPasteboard: anObj];
|
|
|
|
if (anObj)
|
|
|
|
{
|
|
|
|
NSString *aName;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
aName = [anObj name];
|
|
|
|
if (aName)
|
|
|
|
{
|
|
|
|
NSPasteboard *ret;
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
ret = [self _pasteboardWithTarget: anObj
|
|
|
|
name: (NSString*)aName];
|
|
|
|
NS_VALRETURN(ret);
|
|
|
|
}
|
|
|
|
}
|
1997-10-28 12:21:23 +00:00
|
|
|
}
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
1997-10-28 12:21:23 +00:00
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
+ (NSArray*) typesFilterableTo: (NSString*)type
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NSArray* types = nil;
|
|
|
|
|
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
types = [[self _pbs] typesFilterableTo: type];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
types = nil;
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return types;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Instance methods
|
|
|
|
*/
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1997-09-01 20:21:07 +00:00
|
|
|
- (id) _target
|
|
|
|
{
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Creating and Releasing an NSPasteboard Object
|
|
|
|
*/
|
1997-09-01 20:21:07 +00:00
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[target release];
|
|
|
|
[name release];
|
1999-02-16 11:14:37 +00:00
|
|
|
[super dealloc];
|
1997-09-01 20:21:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) releaseGlobally
|
|
|
|
{
|
1998-11-23 21:39:58 +00:00
|
|
|
[target releaseGlobally];
|
|
|
|
[pasteboards removeObjectForKey: name];
|
1997-09-01 20:21:07 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Referring to a Pasteboard by Name
|
|
|
|
*/
|
|
|
|
- (NSString*) name
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
return name;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Writing Data
|
|
|
|
*/
|
|
|
|
- (int) addTypes: (NSArray*)newTypes
|
|
|
|
owner: (id)newOwner
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
count = [target addTypes: newTypes
|
|
|
|
owner: newOwner
|
|
|
|
pasteboard: self
|
|
|
|
oldCount: changeCount];
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
changeCount = count;
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
}
|
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return count;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (int) declareTypes: (NSArray*)newTypes
|
|
|
|
owner: (id)newOwner
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
changeCount = [target declareTypes: newTypes
|
|
|
|
owner: newOwner
|
|
|
|
pasteboard: self];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return changeCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
- (void) release
|
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
if ([self retainCount] == 2)
|
|
|
|
{
|
|
|
|
[dictionary_lock lock];
|
|
|
|
[super retain];
|
|
|
|
[pasteboards removeObjectForKey: name];
|
|
|
|
[super release];
|
|
|
|
[dictionary_lock unlock];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
[super release];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (BOOL) setData: (NSData*)data
|
|
|
|
forType: (NSString*)dataType
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
BOOL ok = NO;
|
|
|
|
|
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
ok = [target setData: data
|
|
|
|
forType: dataType
|
|
|
|
isFile: NO
|
|
|
|
oldCount: changeCount];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
ok = NO;
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return ok;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (BOOL) setPropertyList: (id)propertyList
|
|
|
|
forType: (NSString*)dataType
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
NSData *d = [NSSerializer serializePropertyList: propertyList];
|
1997-09-01 20:21:07 +00:00
|
|
|
|
|
|
|
return [self setData: d forType: dataType];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (BOOL) setString: (NSString*)string
|
|
|
|
forType: (NSString*)dataType
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
return [self setPropertyList: string forType: dataType];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (BOOL) writeFileContents: (NSString*)filename
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
NSData *data;
|
|
|
|
NSString *type;
|
|
|
|
BOOL ok = NO;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
data = [NSData dataWithContentsOfFile: filename];
|
|
|
|
type = NSCreateFileContentsPboardType([filename pathExtension]);
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
ok = [target setData: data
|
|
|
|
forType: type
|
|
|
|
isFile: YES
|
|
|
|
oldCount: changeCount];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
ok = NO;
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return ok;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Determining Types
|
|
|
|
*/
|
|
|
|
- (NSString*) availableTypeFromArray: (NSArray*)types
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NSString *type = nil;
|
|
|
|
|
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
int count = 0;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
type = [target availableTypeFromArray: types
|
|
|
|
changeCount: &count];
|
|
|
|
changeCount = count;
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
type = nil;
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return type;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (NSArray*) types
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NSArray *result = nil;
|
|
|
|
|
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
int count = 0;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
result = [target typesAndChangeCount: &count];
|
|
|
|
changeCount = count;
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
result = nil;
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return result;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Reading Data
|
|
|
|
*/
|
|
|
|
- (int) changeCount
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
int count;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
count = [target changeCount];
|
|
|
|
changeCount = count;
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return changeCount;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (NSData*) dataForType: (NSString*)dataType
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
NSData *d = nil;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
d = [target dataForType: dataType
|
|
|
|
oldCount: changeCount
|
|
|
|
mustBeCurrent: (useHistory == NO) ? YES : NO];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
d = nil;
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
return d;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (id) propertyListForType: (NSString*)dataType
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
NSData *d = [self dataForType: dataType];
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
if (d)
|
|
|
|
return [NSDeserializer deserializePropertyListFromData: d
|
|
|
|
mutableContainers: NO];
|
|
|
|
else
|
|
|
|
return nil;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (NSString*) readFileContentsType: (NSString*)type
|
|
|
|
toFile: (NSString*)filename
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
NSData *d;
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
if (type == nil)
|
|
|
|
{
|
|
|
|
type = NSCreateFileContentsPboardType([filename pathExtension]);
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
d = [self dataForType: type];
|
1999-05-27 18:21:46 +00:00
|
|
|
if ([d writeToFile: filename atomically: NO] == NO)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
return filename;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (NSString*) stringForType: (NSString*)dataType
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1997-09-01 20:21:07 +00:00
|
|
|
return [self propertyListForType: dataType];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
/*
|
|
|
|
* Methods Implemented by the Owner
|
|
|
|
*/
|
|
|
|
- (void) pasteboard: (NSPasteboard*)sender
|
|
|
|
provideDataForType: (NSString*)type
|
|
|
|
{
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (void) pasteboard: (NSPasteboard*)sender
|
|
|
|
provideDataForType: (NSString*)type
|
|
|
|
andVersion: (int)version
|
|
|
|
{
|
|
|
|
}
|
1997-09-11 13:40:01 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
- (void) pasteboardChangedOwner: (NSPasteboard*)sender
|
|
|
|
{
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
|
|
@end
|
1997-09-01 20:21:07 +00:00
|
|
|
|
|
|
|
@implementation NSPasteboard (GNUstepExtensions)
|
|
|
|
|
|
|
|
/*
|
1999-05-27 18:21:46 +00:00
|
|
|
* Once the '[-setChangeCount: ]' message has been sent to an NSPasteboard
|
1997-09-01 20:21:07 +00:00
|
|
|
* the object will gain an extra GNUstep behaviour - when geting data
|
|
|
|
* from the pasteboard, the data need no longer be from the latest
|
|
|
|
* version but may be a version from a previous representation with
|
|
|
|
* the specified change count.
|
|
|
|
*/
|
|
|
|
- (void) setChangeCount: (int)count
|
|
|
|
{
|
|
|
|
useHistory = YES;
|
|
|
|
changeCount = count;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setHistory: (unsigned)length
|
|
|
|
{
|
|
|
|
NS_DURING
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[target setHistory: length];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_HANDLER
|
1999-05-27 18:21:46 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSPasteboardCommunicationException
|
|
|
|
format: @"%@", [localException reason]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
1999-07-29 20:58:04 +00:00
|
|
|
|
|
|
|
+ (void) _initMimeMappings
|
|
|
|
{
|
|
|
|
mimeMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
NSMapInsert(mimeMap, (void *)NSStringPboardType, (void *)@"text/plain");
|
|
|
|
NSMapInsert(mimeMap, (void *)NSFileContentsPboardType,
|
|
|
|
(void *)@"text/plain");
|
|
|
|
NSMapInsert(mimeMap, (void *)NSFilenamesPboardType,
|
|
|
|
(void *)@"text/uri-list");
|
|
|
|
NSMapInsert(mimeMap, (void *)NSPostScriptPboardType,
|
|
|
|
(void *)@"application/postscript");
|
|
|
|
NSMapInsert(mimeMap, (void *)NSTabularTextPboardType,
|
|
|
|
(void *)@"text/tab-separated-values");
|
|
|
|
NSMapInsert(mimeMap, (void *)NSRTFPboardType, (void *)@"text/richtext");
|
|
|
|
NSMapInsert(mimeMap, (void *)NSTIFFPboardType, (void *)@"image/tiff");
|
|
|
|
NSMapInsert(mimeMap, (void *)NSGeneralPboardType, (void *)@"text/plain");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the mapping for pasteboard->mime, or return the original pasteboard
|
|
|
|
type if no mapping is found */
|
|
|
|
+ (NSString *) mimeTypeForPasteboardType: (NSString *)type
|
|
|
|
{
|
|
|
|
NSString *mime;
|
|
|
|
if (mimeMap == NULL)
|
|
|
|
[self _initMimeMappings];
|
|
|
|
mime = NSMapGet(mimeMap, (void *)type);
|
|
|
|
if (mime == nil)
|
|
|
|
mime = type;
|
|
|
|
return mime;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the mapping for mime->pasteboard, or return the original pasteboard
|
|
|
|
type if no mapping is found. This method may not have a one-to-one
|
|
|
|
mapping */
|
|
|
|
+ (NSString *) pasteboardTypeForMimeType: (NSString *)mimeType
|
|
|
|
{
|
|
|
|
BOOL found;
|
|
|
|
NSString *type, *mime;
|
|
|
|
NSMapEnumerator enumerator;
|
|
|
|
|
|
|
|
if (mimeMap == NULL)
|
|
|
|
[self _initMimeMappings];
|
|
|
|
enumerator = NSEnumerateMapTable(mimeMap);
|
|
|
|
while ((found = NSNextMapEnumeratorPair(&enumerator,
|
|
|
|
(void **)(&type), (void **)(&mime))))
|
|
|
|
if ([mimeType isEqual: mime])
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (found == NO)
|
|
|
|
type = mimeType;
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
1997-09-01 20:21:07 +00:00
|
|
|
@end
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
static NSString* contentsPrefix = @"NSTypedFileContentsPboardType: ";
|
|
|
|
static NSString* namePrefix = @"NSTypedFilenamesPboardType: ";
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1998-11-18 09:41:47 +00:00
|
|
|
NSString*
|
|
|
|
NSCreateFileContentsPboardType(NSString *fileType)
|
1997-09-01 20:21:07 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
return [NSString stringWithFormat: @"%@%@", contentsPrefix, fileType];
|
1997-09-01 20:21:07 +00:00
|
|
|
}
|
|
|
|
|
1998-11-18 09:41:47 +00:00
|
|
|
NSString*
|
|
|
|
NSCreateFilenamePboardType(NSString *filename)
|
1997-09-01 20:21:07 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
return [NSString stringWithFormat: @"%@%@", namePrefix, filename];
|
1997-09-01 20:21:07 +00:00
|
|
|
}
|
|
|
|
|
1998-11-18 09:41:47 +00:00
|
|
|
NSString*
|
|
|
|
NSGetFileType(NSString *pboardType)
|
1997-09-01 20:21:07 +00:00
|
|
|
{
|
1999-05-27 18:21:46 +00:00
|
|
|
if ([pboardType hasPrefix: contentsPrefix])
|
|
|
|
{
|
|
|
|
return [pboardType substringFromIndex: [contentsPrefix length]];
|
|
|
|
}
|
|
|
|
if ([pboardType hasPrefix: namePrefix])
|
|
|
|
{
|
|
|
|
return [pboardType substringFromIndex: [namePrefix length]];
|
|
|
|
}
|
1997-09-01 20:21:07 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1998-11-18 09:41:47 +00:00
|
|
|
NSArray*
|
|
|
|
NSGetFileTypes(NSArray *pboardTypes)
|
1997-09-01 20:21:07 +00:00
|
|
|
{
|
|
|
|
NSMutableArray *a = [NSMutableArray arrayWithCapacity: [pboardTypes count]];
|
|
|
|
unsigned int i;
|
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
for (i = 0; i < [pboardTypes count]; i++)
|
|
|
|
{
|
|
|
|
NSString *s = NSGetFileType([pboardTypes objectAtIndex: i]);
|
1997-09-01 20:21:07 +00:00
|
|
|
|
1999-05-27 18:21:46 +00:00
|
|
|
if (s && ! [a containsObject: s])
|
|
|
|
{
|
|
|
|
[a addObject: s];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ([a count] > 0)
|
|
|
|
{
|
|
|
|
return [[a copy] autorelease];
|
1997-09-01 20:21:07 +00:00
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|