Add support for opening files from arguments

Arguments can supplied in the command line. If the application
is already runnning, they're passed to the running instance from
a pipe. Application receives the files via application:openFile:
or application:openFiles:.
This commit is contained in:
Alberto García Hierro 2013-11-01 20:19:45 +01:00
parent 9ef2b1c8c3
commit fd73436436
3 changed files with 154 additions and 88 deletions

View File

@ -71,12 +71,6 @@ NSString * const NSApplicationDidChangeScreenParametersNotification=@"NSApplicat
id NSApp=nil;
+(void)initialize {
if(self==[NSApplication class]){
[NSClassFromString(@"Win32RunningCopyPipe") performSelector:@selector(startRunningCopyPipe)];
}
}
+(NSApplication *)sharedApplication {
if(NSApp==nil){
@ -408,6 +402,40 @@ id NSApp=nil;
#endif
}
-(BOOL)openFiles
{
BOOL opened = NO;
if(_delegate) {
id nsOpen = [[NSUserDefaults standardUserDefaults] objectForKey:@"NSOpen"];
NSArray *openFiles = nil;
if ([nsOpen isKindOfClass:[NSString class]] && [nsOpen length]) {
openFiles = [NSArray arrayWithObject:nsOpen];
} else if ([nsOpen isKindOfClass:[NSArray class]]) {
openFiles = nsOpen;
}
if ([openFiles count] > 0) {
if ([openFiles count] == 1 && [_delegate respondsToSelector: @selector(application:openFile:)]) {
if([_delegate application: self openFile: [openFiles lastObject]]) {
opened = YES;
}
} else {
if ([_delegate respondsToSelector: @selector(application:openFiles:)]) {
[_delegate application: self openFiles: openFiles];
opened = YES;
} else if ([_delegate respondsToSelector: @selector(application:openFile:)]) {
for (NSString *aFile in openFiles) {
opened |= [_delegate application: self openFile: aFile];
}
}
}
}
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"NSOpen"];
}
return opened;
}
-(void)finishLaunching {
NSAutoreleasePool *pool=[NSAutoreleasePool new];
BOOL needsUntitled=YES;
@ -440,15 +468,9 @@ id NSApp=nil;
objectForKey:@"CFBundleDocumentTypes"];
if([types count] > 0)
controller = [NSDocumentController sharedDocumentController];
if(_delegate && [_delegate respondsToSelector: @selector(application:openFile:)]) {
NSString *openFile = [[NSUserDefaults standardUserDefaults]
stringForKey:@"NSOpen"];
if([openFile length] > 0) {
if([_delegate application: self openFile: openFile])
needsUntitled = NO;
}
if ([self openFiles]) {
needsUntitled = NO;
}
if(needsUntitled && _delegate &&
@ -1267,26 +1289,67 @@ standardAboutPanel] retain];
int NSApplicationMain(int argc, const char *argv[]) {
NSInitializeProcess(argc,(const char **)argv);
{
NSAutoreleasePool *pool=[NSAutoreleasePool new];
NSBundle *bundle=[NSBundle mainBundle];
Class class=[bundle principalClass];
NSString *nibFile=[[bundle infoDictionary] objectForKey:@"NSMainNibFile"];
if(class==Nil)
class=[NSApplication class];
NSAutoreleasePool *pool=[NSAutoreleasePool new];
NSBundle *bundle=[NSBundle mainBundle];
Class class=[bundle principalClass];
NSString *nibFile=[[bundle infoDictionary] objectForKey:@"NSMainNibFile"];
[class sharedApplication];
nibFile=[nibFile stringByDeletingPathExtension];
if(![NSBundle loadNibNamed:nibFile owner:NSApp])
NSLog(@"Unable to load main nib file %@",nibFile);
[pool release];
[NSApp run];
if (argc > 1) {
BOOL noMoreArgs = NO;
BOOL skip = NO;
NSMutableArray *theArguments = [NSMutableArray array];
for (int ii = 1; ii < argc; ii++) {
if (skip) {
skip = NO;
continue;
}
const char *arg = argv[ii];
if (noMoreArgs || arg[0] != '-') {
NSString *anArg = [NSString stringWithCString:arg encoding:NSUTF8StringEncoding];
if ([anArg length]) {
[theArguments addObject:anArg];
continue;
}
}
if (!noMoreArgs) {
if (arg[0] == '-') {
if (arg[1] == '-' && arg[2] == '\0') {
noMoreArgs = YES;
} else if (strcmp(arg, "-NSOpen") != 0) {
skip = YES;
}
}
}
}
if ([theArguments count] > 0) {
id nsOpen;
if ([theArguments count] == 1) {
nsOpen = [theArguments lastObject];
} else {
nsOpen = theArguments;
}
[[NSUserDefaults standardUserDefaults] setObject:nsOpen forKey:@"NSOpen"];
}
}
[NSClassFromString(@"Win32RunningCopyPipe") performSelector:@selector(startRunningCopyPipe)];
if(class==Nil) {
class=[NSApplication class];
}
[class sharedApplication];
nibFile=[nibFile stringByDeletingPathExtension];
if(![NSBundle loadNibNamed:nibFile owner:NSApp]) {
NSLog(@"Unable to load main nib file %@",nibFile);
}
[pool release];
[NSApp run];
return 0;
}

View File

@ -21,7 +21,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
} _state;
OVERLAPPED _readOverlap;
DWORD _readCount;
unichar _readBuffer[65536];
char _readBuffer[65536];
}
+(void)invalidateRunningCopyPipe;

View File

@ -23,37 +23,42 @@ static Win32RunningCopyPipe *_runningCopyPipe=nil;
_readOverlap.hEvent=_event;
if(_state==STATE_CONNECTING){
if(!ConnectNamedPipe(_pipe,&_readOverlap)){
if(GetLastError()!=ERROR_IO_PENDING)
NSLog(@"ConnectNamedPipe failed");
}
}
else {
if(!ReadFile(_pipe,_readBuffer,65536,&_readCount,&_readOverlap)){
if(GetLastError()!=ERROR_IO_PENDING)
NSLog(@"ReadFile failed");
}
if(!ConnectNamedPipe(_pipe, &_readOverlap)){
if(GetLastError()!=ERROR_IO_PENDING) {
NSLog(@"ConnectNamedPipe failed");
}
}
} else {
if(!ReadFile(_pipe,_readBuffer, sizeof(_readBuffer), &_readCount ,&_readOverlap)){
if(GetLastError()!=ERROR_IO_PENDING) {
NSLog(@"ReadFile failed");
}
}
}
}
-(void)handleMonitorIndicatesSignaled:(NSHandleMonitor_win32 *)monitor {
if(!GetOverlappedResult(_pipe,&_readOverlap,&_readCount,TRUE))
NSLog(@"GetOverlappedResult failed %d", GetLastError());
if(!GetOverlappedResult(_pipe,&_readOverlap,&_readCount,TRUE)) {
NSLog(@"GetOverlappedResult failed %d", GetLastError());
}
if(_state==STATE_CONNECTING)
_state=STATE_READING;
else {
NSString *path=[NSString stringWithCharacters:_readBuffer length:_readCount/2];
if(_state==STATE_CONNECTING) {
_state=STATE_READING;
if(!DisconnectNamedPipe(_pipe))
NSLog(@"DisconnectNamedPipe failed");
_state=STATE_CONNECTING;
if([path isEqual:@"@reopen"]) [NSApp _reopen];
else
if([[NSApp delegate] respondsToSelector:@selector(application:openFile:)]){
[[NSApp delegate] application:NSApp openFile:path];
}
} else {
NSData *data = [NSData dataWithBytesNoCopy:_readBuffer length:_readCount freeWhenDone:NO];
NSArray *nsOpen = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if(!DisconnectNamedPipe(_pipe)) {
NSLog(@"DisconnectNamedPipe failed");
}
_state=STATE_CONNECTING;
if([nsOpen count] == 1 && [[nsOpen lastObject] isEqual:@"@reopen"]) {
[NSApp _reopen];
} else {
[[NSUserDefaults standardUserDefaults] setObject:nsOpen forKey:@"NSOpen"];
[NSApp performSelector:@selector(openFiles)];
}
}
[self startReading];
@ -106,40 +111,38 @@ static Win32RunningCopyPipe *_runningCopyPipe=nil;
}
+(void)_startRunningCopyPipe {
if(![self createRunningCopyPipe]){
NSString *path;
if(![self createRunningCopyPipe]) {
NSArray *paths;
if([[NSUserDefaults standardUserDefaults] stringForKey:@"NSUseRunningCopy"]!=nil){
if(![[NSUserDefaults standardUserDefaults] boolForKey:@"NSUseRunningCopy"])
return;
}
if([[NSUserDefaults standardUserDefaults] stringForKey:@"NSUseRunningCopy"]!=nil &&
![[NSUserDefaults standardUserDefaults] boolForKey:@"NSUseRunningCopy"]) {
path=[[NSUserDefaults standardUserDefaults] stringForKey:@"NSOpen"];
if([path length]==0) path=@"@reopen";
//if([path length]>0)
{
HANDLE pipe=CreateFile([[self pipeName] cString],GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
if(pipe==INVALID_HANDLE_VALUE)
return;
else {
unsigned length=[path length];
unichar buffer[length];
DWORD wrote;
[path getCharacters:buffer];
if(!WriteFile(pipe,buffer,length*2,&wrote,NULL)){
NSLog(@"WriteFile failed");
return;
return;
}
}
}
exit(0);
id nsOpen = [[NSUserDefaults standardUserDefaults] objectForKey:@"NSOpen"];
if ([nsOpen isKindOfClass:[NSString class]] && [nsOpen length]) {
paths = [NSArray arrayWithObject:nsOpen];
} else if ([nsOpen isKindOfClass:[NSArray class]] && [nsOpen count]) {
paths = nsOpen;
} else {
paths = [NSArray arrayWithObject:@"@reopen"];
}
HANDLE pipe=CreateFile([[self pipeName] cString],GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
if(pipe==INVALID_HANDLE_VALUE) {
return;
}
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:paths];
DWORD written = 0;
if(!WriteFile(pipe, [data bytes], [data length], &written,NULL) || written != [data length]) {
NSLog(@"WriteFile failed");
}
exit(0);
}
}