2001-12-17 16:51:51 +00:00
|
|
|
|
/** <title>NSWorkspace</title>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
|
<abstract>Workspace class</abstract>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2001-11-26 20:29:42 +00:00
|
|
|
|
Copyright (C) 1996-1999, 2001 Free Software Foundation, Inc.
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
|
Author: Scott Christley <scottc@net-community.com>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
Date: 1996
|
2002-01-22 18:23:56 +00:00
|
|
|
|
Implementation by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
1998-11-23 21:39:58 +00:00
|
|
|
|
Date: 1998
|
2002-01-22 18:23:56 +00:00
|
|
|
|
Implementation by: Fred Kiefer <FredKiefer@gmx.de>
|
2001-11-26 20:29:42 +00:00
|
|
|
|
Date: 2001
|
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>
|
1999-04-14 14:42:50 +00:00
|
|
|
|
#include <Foundation/NSBundle.h>
|
1998-11-23 21:39:58 +00:00
|
|
|
|
#include <Foundation/NSDictionary.h>
|
2002-01-10 16:33:39 +00:00
|
|
|
|
#include <Foundation/NSHost.h>
|
1998-11-23 21:39:58 +00:00
|
|
|
|
#include <Foundation/NSLock.h>
|
1999-01-07 15:52:42 +00:00
|
|
|
|
#include <Foundation/NSPathUtilities.h>
|
1998-11-23 21:39:58 +00:00
|
|
|
|
#include <Foundation/NSUserDefaults.h>
|
|
|
|
|
#include <Foundation/NSTask.h>
|
|
|
|
|
#include <Foundation/NSException.h>
|
1999-04-08 20:42:46 +00:00
|
|
|
|
#include <Foundation/NSFileManager.h>
|
1999-04-28 11:16:26 +00:00
|
|
|
|
#include <Foundation/NSNotificationQueue.h>
|
1999-10-12 14:33:55 +00:00
|
|
|
|
#include <Foundation/NSDistributedNotificationCenter.h>
|
1999-06-03 04:53:12 +00:00
|
|
|
|
#include <Foundation/NSConnection.h>
|
2001-07-30 21:30:51 +00:00
|
|
|
|
#include <Foundation/NSDebug.h>
|
2001-11-26 20:29:42 +00:00
|
|
|
|
#include <Foundation/NSURL.h>
|
|
|
|
|
#include <AppKit/NSWorkspace.h>
|
|
|
|
|
#include <AppKit/NSApplication.h>
|
|
|
|
|
#include <AppKit/NSImage.h>
|
2001-12-01 21:14:51 +00:00
|
|
|
|
#include <AppKit/NSView.h>
|
|
|
|
|
#include <AppKit/NSWindow.h>
|
|
|
|
|
#include <AppKit/NSScreen.h>
|
2001-11-26 20:29:42 +00:00
|
|
|
|
#include <AppKit/GSServicesManager.h>
|
2002-03-28 03:53:18 +00:00
|
|
|
|
#include <AppKit/GSDisplayServer.h>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2000-04-07 23:49:10 +00:00
|
|
|
|
#define PosixExecutePermission (0111)
|
|
|
|
|
|
1999-10-12 14:33:55 +00:00
|
|
|
|
static NSString *GSWorkspaceNotification = @"GSWorkspaceNotification";
|
|
|
|
|
|
|
|
|
|
@interface _GSWorkspaceCenter: NSNotificationCenter
|
|
|
|
|
{
|
|
|
|
|
NSDistributedNotificationCenter *remote;
|
|
|
|
|
}
|
|
|
|
|
- (void) _handleRemoteNotification: (NSNotification*)aNotification;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation _GSWorkspaceCenter
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
[remote removeObserver: self name: nil object: GSWorkspaceNotification];
|
|
|
|
|
RELEASE(remote);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (self != nil)
|
|
|
|
|
{
|
|
|
|
|
remote = RETAIN([NSDistributedNotificationCenter defaultCenter]);
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NS_DURING
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
|
|
|
|
[remote addObserver: self
|
|
|
|
|
selector: @selector(_handleRemoteNotification:)
|
|
|
|
|
name: nil
|
|
|
|
|
object: GSWorkspaceNotification];
|
|
|
|
|
}
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NS_HANDLER
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
|
|
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
|
|
|
|
|
|
if ([defs boolForKey: @"GSLogWorkspaceTimeout"])
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"NSWorkspace caught exception %@: %@",
|
2000-08-07 22:06:04 +00:00
|
|
|
|
[localException name], [localException reason]);
|
2002-01-10 16:33:39 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NS_ENDHANDLER
|
1999-10-12 14:33:55 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1999-10-19 11:20:22 +00:00
|
|
|
|
* Post notification remotely - since we are listening for distributed
|
|
|
|
|
* notifications, we will observe the notification arriving from the
|
|
|
|
|
* distributed notification center, and it will get sent out locally too.
|
1999-10-12 14:33:55 +00:00
|
|
|
|
*/
|
|
|
|
|
- (void) postNotification: (NSNotification*)aNotification
|
|
|
|
|
{
|
|
|
|
|
NSNotification *rem;
|
|
|
|
|
|
|
|
|
|
rem = [NSNotification notificationWithName: [aNotification name]
|
|
|
|
|
object: GSWorkspaceNotification
|
|
|
|
|
userInfo: [aNotification userInfo]];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NS_DURING
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
|
|
|
|
[remote postNotification: rem];
|
|
|
|
|
}
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NS_HANDLER
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
|
|
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
|
|
|
|
|
|
if ([defs boolForKey: @"GSLogWorkspaceTimeout"])
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"NSWorkspace caught exception %@: %@",
|
2000-08-07 22:06:04 +00:00
|
|
|
|
[localException name], [localException reason]);
|
2002-01-10 16:33:39 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NS_ENDHANDLER
|
1999-10-12 14:33:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) postNotificationName: (NSString*)name
|
|
|
|
|
object: (id)object
|
|
|
|
|
{
|
|
|
|
|
[self postNotification: [NSNotification notificationWithName: name
|
|
|
|
|
object: object]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) postNotificationName: (NSString*)name
|
|
|
|
|
object: (id)object
|
|
|
|
|
userInfo: (NSDictionary*)info
|
|
|
|
|
{
|
|
|
|
|
[self postNotification: [NSNotification notificationWithName: name
|
|
|
|
|
object: object
|
|
|
|
|
userInfo: info]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Forward a notification from a remote application to observers in this
|
|
|
|
|
* application.
|
|
|
|
|
*/
|
|
|
|
|
- (void) _handleRemoteNotification: (NSNotification*)aNotification
|
|
|
|
|
{
|
|
|
|
|
[super postNotification: aNotification];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1998-11-23 21:39:58 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
@interface NSWorkspace (Private)
|
|
|
|
|
|
|
|
|
|
// Icon handling
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) _extIconForApp: (NSString*)appName info: (NSDictionary*)extInfo;
|
|
|
|
|
- (NSImage*) _getImageWithName: (NSString*)name
|
|
|
|
|
alternate: (NSString*)alternate;
|
|
|
|
|
- (NSImage*) folderImage;
|
|
|
|
|
- (NSImage*) unknownFiletypeImage;
|
|
|
|
|
- (NSImage*) rootImage;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
- (NSImage*) _iconForExtension: (NSString*)ext;
|
|
|
|
|
- (BOOL) _extension: (NSString*)ext
|
|
|
|
|
role: (NSString*)role
|
2002-01-22 13:20:20 +00:00
|
|
|
|
app: (NSString**)app;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
|
|
|
|
// application communication
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) _launchApplication: (NSString*)appName
|
|
|
|
|
arguments: (NSArray*)args;
|
|
|
|
|
- (id) _connectApplication: (NSString*)appName;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
- (id) _workspaceApplication;
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
1998-11-23 21:39:58 +00:00
|
|
|
|
@implementation NSWorkspace
|
|
|
|
|
|
1999-04-08 20:42:46 +00:00
|
|
|
|
static NSWorkspace *sharedWorkspace = nil;
|
1998-11-23 21:39:58 +00:00
|
|
|
|
|
1999-04-08 20:42:46 +00:00
|
|
|
|
static NSString *appListPath = nil;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
static NSDictionary *applications = nil;
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
|
static NSString *extPrefPath = nil;
|
|
|
|
|
static NSDictionary *extPreferences = nil;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
// FIXME: Won't work for MINGW
|
1999-04-28 11:16:26 +00:00
|
|
|
|
static NSString *_rootPath = @"/";
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* Class methods
|
|
|
|
|
*/
|
1999-04-08 20:42:46 +00:00
|
|
|
|
+ (void) initialize
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
|
|
|
|
if (self == [NSWorkspace class])
|
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
static BOOL beenHere = NO;
|
1999-04-28 14:22:19 +00:00
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
2001-12-01 21:14:51 +00:00
|
|
|
|
NSString *service;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
NSData *data;
|
|
|
|
|
NSDictionary *dict;
|
1998-11-23 21:39:58 +00:00
|
|
|
|
|
1999-04-08 20:42:46 +00:00
|
|
|
|
[self setVersion: 1];
|
1998-11-23 21:39:58 +00:00
|
|
|
|
|
|
|
|
|
[gnustep_global_lock lock];
|
|
|
|
|
if (beenHere == YES)
|
|
|
|
|
{
|
|
|
|
|
[gnustep_global_lock unlock];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
beenHere = YES;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
service = [[NSSearchPathForDirectoriesInDomains(
|
|
|
|
|
NSUserDirectory, NSUserDomainMask, YES) objectAtIndex: 0]
|
|
|
|
|
stringByAppendingPathComponent: @"Services"];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Load file extension preferences.
|
|
|
|
|
*/
|
2001-12-01 21:14:51 +00:00
|
|
|
|
extPrefPath = [service
|
2001-11-26 20:29:42 +00:00
|
|
|
|
stringByAppendingPathComponent: @".GNUstepExtPrefs"];
|
1999-09-01 11:15:27 +00:00
|
|
|
|
RETAIN(extPrefPath);
|
1999-04-28 14:22:19 +00:00
|
|
|
|
if ([mgr isReadableFileAtPath: extPrefPath] == YES)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
1999-04-28 14:22:19 +00:00
|
|
|
|
data = [NSData dataWithContentsOfFile: extPrefPath];
|
|
|
|
|
if (data)
|
|
|
|
|
{
|
|
|
|
|
dict = [NSDeserializer deserializePropertyListFromData: data
|
|
|
|
|
mutableContainers: NO];
|
1999-09-01 11:15:27 +00:00
|
|
|
|
extPreferences = RETAIN(dict);
|
1999-04-28 14:22:19 +00:00
|
|
|
|
}
|
1998-11-23 21:39:58 +00:00
|
|
|
|
}
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
|
/*
|
|
|
|
|
* Load cached application information.
|
|
|
|
|
*/
|
2001-12-01 21:14:51 +00:00
|
|
|
|
appListPath = [service
|
2001-11-26 20:29:42 +00:00
|
|
|
|
stringByAppendingPathComponent: @".GNUstepAppList"];
|
1999-09-01 11:15:27 +00:00
|
|
|
|
RETAIN(appListPath);
|
1999-04-28 14:22:19 +00:00
|
|
|
|
if ([mgr isReadableFileAtPath: appListPath] == YES)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
1999-04-28 14:22:19 +00:00
|
|
|
|
data = [NSData dataWithContentsOfFile: appListPath];
|
|
|
|
|
if (data)
|
|
|
|
|
{
|
|
|
|
|
dict = [NSDeserializer deserializePropertyListFromData: data
|
|
|
|
|
mutableContainers: NO];
|
1999-09-01 11:15:27 +00:00
|
|
|
|
applications = RETAIN(dict);
|
1999-04-28 14:22:19 +00:00
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
1999-04-24 11:41:41 +00:00
|
|
|
|
[gnustep_global_lock unlock];
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-23 21:39:58 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)zone
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"You may not allocate a workspace directly"];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* Creating a Workspace
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
+ (NSWorkspace*) sharedWorkspace
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
1998-11-23 21:39:58 +00:00
|
|
|
|
if (sharedWorkspace == nil)
|
|
|
|
|
{
|
|
|
|
|
[gnustep_global_lock lock];
|
|
|
|
|
if (sharedWorkspace == nil)
|
|
|
|
|
{
|
|
|
|
|
sharedWorkspace =
|
|
|
|
|
(NSWorkspace*)NSAllocateObject(self, 0, NSDefaultMallocZone());
|
2001-11-26 20:29:42 +00:00
|
|
|
|
[sharedWorkspace init];
|
1998-11-23 21:39:58 +00:00
|
|
|
|
}
|
|
|
|
|
[gnustep_global_lock unlock];
|
|
|
|
|
}
|
|
|
|
|
return sharedWorkspace;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-26 20:29:42 +00:00
|
|
|
|
/*
|
|
|
|
|
* Instance methods
|
|
|
|
|
*/
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Attempt to call dealloc for shared worksapace"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
if (sharedWorkspace != self)
|
|
|
|
|
{
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
return RETAIN(sharedWorkspace);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
2002-01-22 18:23:56 +00:00
|
|
|
|
addObserver: self
|
|
|
|
|
selector: @selector(noteUserDefaultsChanged)
|
|
|
|
|
name: NSUserDefaultsDidChangeNotification
|
|
|
|
|
object: nil];
|
2001-11-26 20:29:42 +00:00
|
|
|
|
|
|
|
|
|
_workspaceCenter = [_GSWorkspaceCenter new];
|
|
|
|
|
_iconMap = [NSMutableDictionary new];
|
2002-01-22 18:23:56 +00:00
|
|
|
|
_launched = [NSMutableDictionary new];
|
2001-11-26 20:29:42 +00:00
|
|
|
|
if (applications == nil)
|
2002-01-22 18:23:56 +00:00
|
|
|
|
{
|
|
|
|
|
[self findApplications];
|
|
|
|
|
}
|
2001-11-26 20:29:42 +00:00
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* Opening Files
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) openFile: (NSString*)fullPath
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return [self openFile: fullPath withApplication: nil];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) openFile: (NSString*)fullPath
|
|
|
|
|
fromImage: (NSImage*)anImage
|
2001-12-01 21:14:51 +00:00
|
|
|
|
at: (NSPoint)point
|
2002-01-22 18:23:56 +00:00
|
|
|
|
inView: (NSView*)aView
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
NSWindow *win = [aView window];
|
|
|
|
|
NSPoint screenLoc = [win convertBaseToScreen:
|
|
|
|
|
[aView convertPoint: point toView: nil]];
|
|
|
|
|
NSSize screenSize = [[win screen] frame].size;
|
|
|
|
|
NSPoint screenCenter = NSMakePoint(screenSize.width / 2,
|
|
|
|
|
screenSize.height / 2);
|
|
|
|
|
|
|
|
|
|
[self slideImage: anImage from: screenLoc to: screenCenter];
|
|
|
|
|
return [self openFile: fullPath];
|
1999-04-24 11:41:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) openFile: (NSString*)fullPath
|
|
|
|
|
withApplication: (NSString*)appName
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return [self openFile: fullPath withApplication: appName andDeactivate: YES];
|
1999-04-24 11:41:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) openFile: (NSString*)fullPath
|
|
|
|
|
withApplication: (NSString*)appName
|
2001-12-01 21:14:51 +00:00
|
|
|
|
andDeactivate: (BOOL)flag
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
id app;
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
if (appName == nil)
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
NSString *ext = [fullPath pathExtension];
|
|
|
|
|
|
2002-01-22 13:20:20 +00:00
|
|
|
|
if ([self _extension: ext role: nil app: &appName] == NO)
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
NSWarnLog(@"No known applications for file extension '%@'", ext);
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
1999-04-24 11:41:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
app = [self _connectApplication: appName];
|
|
|
|
|
if (app == nil)
|
|
|
|
|
{
|
|
|
|
|
NSArray *args;
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
args = [NSArray arrayWithObjects: @"-GSFilePath", fullPath, nil];
|
|
|
|
|
return [self _launchApplication: appName arguments: args];
|
|
|
|
|
}
|
|
|
|
|
else
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
if (flag == NO)
|
2002-01-22 18:23:56 +00:00
|
|
|
|
{
|
|
|
|
|
[app application: NSApp openFileWithoutUI: fullPath];
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
else
|
2002-01-22 18:23:56 +00:00
|
|
|
|
{
|
|
|
|
|
[app application: NSApp openFile: fullPath];
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
NSWarnLog(@"Failed to contact '%@' to open file", appName);
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
1999-04-24 11:41:41 +00:00
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
if (flag)
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
|
|
|
|
[NSApp deactivate];
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return YES;
|
1999-04-24 11:41:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) openTempFile: (NSString*)fullPath
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
id app;
|
|
|
|
|
NSString *appName;
|
|
|
|
|
NSString *ext = [fullPath pathExtension];
|
|
|
|
|
|
2002-01-22 13:20:20 +00:00
|
|
|
|
if ([self _extension: ext role: nil app: &appName] == NO)
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
NSWarnLog(@"No known applications for file extension '%@'", ext);
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
app = [self _connectApplication: appName];
|
|
|
|
|
if (app == nil)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
NSArray *args;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
args = [NSArray arrayWithObjects: @"-GSTempPath", fullPath, nil];
|
|
|
|
|
return [self _launchApplication: appName arguments: args];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NS_DURING
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
[app application: NSApp openTempFile: fullPath];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
NS_HANDLER
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
NSWarnLog(@"Failed to contact '%@' to open temp file", appName);
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
[NSApp deactivate];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) openURL: (NSURL*)url
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
if ([url isFileURL])
|
2002-01-22 18:23:56 +00:00
|
|
|
|
{
|
|
|
|
|
return [self openFile: [url path]];
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
else
|
2002-01-22 18:23:56 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* Manipulating Files
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) performFileOperation: (NSString*)operation
|
|
|
|
|
source: (NSString*)source
|
|
|
|
|
destination: (NSString*)destination
|
|
|
|
|
files: (NSArray*)files
|
|
|
|
|
tag: (int*)tag
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
id app = [self _workspaceApplication];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
if (app == nil)
|
|
|
|
|
return NO;
|
|
|
|
|
else
|
|
|
|
|
// Send the request on to the Workspace application
|
|
|
|
|
return [app performFileOperation: operation
|
|
|
|
|
source: source
|
|
|
|
|
destination: destination
|
|
|
|
|
files: files
|
|
|
|
|
tag: tag];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) selectFile: (NSString*)fullPath
|
|
|
|
|
inFileViewerRootedAtPath: (NSString*)rootFullpath
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
id app = [self _workspaceApplication];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
if (app == nil)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
return NO;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
else
|
|
|
|
|
// Send the request on to the Workspace application
|
|
|
|
|
return [app selectFile: fullPath
|
|
|
|
|
inFileViewerRootedAtPath: rootFullpath];
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* Requesting Information about Files
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSString*) fullPathForApplication: (NSString*)appName
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
NSString *last = [appName lastPathComponent];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
if ([appName isEqual: last])
|
1998-11-23 21:39:58 +00:00
|
|
|
|
{
|
|
|
|
|
NSString *ext = [appName pathExtension];
|
|
|
|
|
|
|
|
|
|
if (ext == nil)
|
|
|
|
|
{
|
|
|
|
|
appName = [appName stringByAppendingPathExtension: @"app"];
|
|
|
|
|
}
|
|
|
|
|
return [applications objectForKey: appName];
|
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) getFileSystemInfoForPath: (NSString*)fullPath
|
|
|
|
|
isRemovable: (BOOL*)removableFlag
|
|
|
|
|
isWritable: (BOOL*)writableFlag
|
|
|
|
|
isUnmountable: (BOOL*)unmountableFlag
|
1999-04-08 20:42:46 +00:00
|
|
|
|
description: (NSString **)description
|
|
|
|
|
type: (NSString **)fileSystemType
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
// FIXME
|
1996-05-30 20:03:15 +00:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) getInfoForFile: (NSString*)fullPath
|
1999-04-08 20:42:46 +00:00
|
|
|
|
application: (NSString **)appName
|
|
|
|
|
type: (NSString **)type
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2002-01-22 09:58:44 +00:00
|
|
|
|
NSFileManager *fm = [NSFileManager defaultManager];
|
|
|
|
|
NSDictionary *attributes;
|
|
|
|
|
NSString *fileType;
|
|
|
|
|
NSString *extension = [fullPath pathExtension];
|
2000-04-07 23:49:10 +00:00
|
|
|
|
|
2001-11-26 20:29:42 +00:00
|
|
|
|
attributes = [fm fileAttributesAtPath: fullPath traverseLink: YES];
|
2002-01-22 09:58:44 +00:00
|
|
|
|
if (attributes != nil)
|
2000-04-07 23:49:10 +00:00
|
|
|
|
{
|
|
|
|
|
fileType = [attributes fileType];
|
|
|
|
|
if ([fileType isEqualToString: NSFileTypeRegular])
|
|
|
|
|
{
|
|
|
|
|
if ([attributes filePosixPermissions] & PosixExecutePermission)
|
|
|
|
|
{
|
|
|
|
|
*type = NSShellCommandFileType;
|
|
|
|
|
*appName = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*type = NSPlainFileType;
|
2002-01-22 09:58:44 +00:00
|
|
|
|
*appName = [self getBestAppInRole: nil forExtension: extension];
|
2000-04-07 23:49:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-01-22 09:58:44 +00:00
|
|
|
|
else if ([fileType isEqualToString: NSFileTypeDirectory])
|
2000-04-07 23:49:10 +00:00
|
|
|
|
{
|
|
|
|
|
if ([extension isEqualToString: @"app"]
|
2002-01-22 09:58:44 +00:00
|
|
|
|
|| [extension isEqualToString: @"debug"]
|
|
|
|
|
|| [extension isEqualToString: @"profile"])
|
2000-04-07 23:49:10 +00:00
|
|
|
|
{
|
|
|
|
|
*type = NSApplicationFileType;
|
|
|
|
|
*appName = nil;
|
|
|
|
|
}
|
|
|
|
|
else if ([extension isEqualToString: @"bundle"])
|
|
|
|
|
{
|
|
|
|
|
*type = NSPlainFileType;
|
|
|
|
|
*appName = nil;
|
|
|
|
|
}
|
|
|
|
|
// the idea here is that if the parent directory's fileSystemNumber
|
|
|
|
|
// differs, this must be a filesystem mount point
|
|
|
|
|
else if ([[fm fileAttributesAtPath:
|
2002-01-22 09:58:44 +00:00
|
|
|
|
[fullPath stringByDeletingLastPathComponent]
|
|
|
|
|
traverseLink: YES] fileSystemNumber]
|
|
|
|
|
!= [attributes fileSystemNumber])
|
2000-04-07 23:49:10 +00:00
|
|
|
|
{
|
|
|
|
|
*type = NSFilesystemFileType;
|
|
|
|
|
*appName = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*type = NSDirectoryFileType;
|
|
|
|
|
*appName = nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// this catches sockets, character special, block special, and
|
|
|
|
|
// unknown file types
|
|
|
|
|
*type = NSPlainFileType;
|
|
|
|
|
*appName = nil;
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) iconForFile: (NSString*)aPath
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
1999-04-24 11:41:41 +00:00
|
|
|
|
NSImage *image = nil;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
NSString *pathExtension = [[aPath pathExtension] lowercaseString];
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
2001-11-26 20:29:42 +00:00
|
|
|
|
if ([self isFilePackageAtPath: aPath])
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
2002-01-22 09:58:44 +00:00
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
|
NSString *iconPath = nil;
|
2001-11-26 20:29:42 +00:00
|
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
|
if ([pathExtension isEqualToString: @"app"]
|
|
|
|
|
|| [pathExtension isEqualToString: @"debug"]
|
|
|
|
|
|| [pathExtension isEqualToString: @"profile"])
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
|
NSBundle *bundle;
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
|
bundle = [NSBundle bundleWithPath: aPath];
|
|
|
|
|
iconPath = [[bundle infoDictionary] objectForKey: @"NSIcon"];
|
|
|
|
|
if (iconPath && [iconPath isAbsolutePath] == NO)
|
|
|
|
|
{
|
1999-09-02 11:28:47 +00:00
|
|
|
|
NSString *file = iconPath;
|
|
|
|
|
|
|
|
|
|
iconPath = [bundle pathForImageResource: file];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If there is no icon in the Resources of the app, try
|
|
|
|
|
* looking directly in the app wrapper.
|
|
|
|
|
*/
|
|
|
|
|
if (iconPath == nil)
|
|
|
|
|
{
|
|
|
|
|
iconPath = [aPath stringByAppendingPathComponent: file];
|
|
|
|
|
if ([mgr isReadableFileAtPath: iconPath] == NO)
|
|
|
|
|
{
|
|
|
|
|
iconPath = nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* If there is no icon specified in the Info.plist for app
|
1999-09-02 08:30:14 +00:00
|
|
|
|
* try 'wrapper/app.tiff'
|
1999-04-28 11:16:26 +00:00
|
|
|
|
*/
|
|
|
|
|
if (iconPath == nil)
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
|
NSString *str;
|
|
|
|
|
|
|
|
|
|
str = [[aPath lastPathComponent] stringByDeletingPathExtension];
|
|
|
|
|
iconPath = [aPath stringByAppendingPathComponent: str];
|
|
|
|
|
iconPath = [iconPath stringByAppendingPathExtension: @"tiff"];
|
|
|
|
|
if ([mgr isReadableFileAtPath: iconPath] == NO)
|
|
|
|
|
{
|
1999-09-02 08:30:14 +00:00
|
|
|
|
iconPath = nil;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-09-02 08:30:14 +00:00
|
|
|
|
}
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
1999-09-02 08:30:14 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we have no iconPath, try 'dir/.dir.tiff' as a
|
|
|
|
|
* possible locations for the directory icon.
|
|
|
|
|
*/
|
|
|
|
|
if (iconPath == nil)
|
|
|
|
|
{
|
|
|
|
|
iconPath = [aPath stringByAppendingPathComponent: @".dir.tiff"];
|
|
|
|
|
if ([mgr isReadableFileAtPath: iconPath] == NO)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
1999-09-02 08:30:14 +00:00
|
|
|
|
iconPath = nil;
|
1999-04-24 11:41:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
1999-09-02 08:30:14 +00:00
|
|
|
|
if (iconPath != nil)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
1999-09-02 08:30:14 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
image = [[NSImage alloc] initWithContentsOfFile: iconPath];
|
|
|
|
|
AUTORELEASE(image);
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"BAD TIFF FILE '%@'", iconPath);
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-24 11:41:41 +00:00
|
|
|
|
if (image == nil)
|
|
|
|
|
{
|
1999-09-02 08:30:14 +00:00
|
|
|
|
image = [self _iconForExtension: pathExtension];
|
|
|
|
|
if (image == nil || image == [self unknownFiletypeImage])
|
|
|
|
|
{
|
|
|
|
|
if ([aPath isEqual: _rootPath])
|
|
|
|
|
image = [self rootImage];
|
|
|
|
|
else
|
|
|
|
|
image = [self folderImage];
|
|
|
|
|
}
|
1999-04-24 11:41:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
else
|
1999-04-24 11:41:41 +00:00
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
|
NSDebugLog(@"pathExtension is '%@'", pathExtension);
|
1999-04-24 11:41:41 +00:00
|
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
|
image = [self _iconForExtension: pathExtension];
|
1999-04-24 11:41:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (image == nil)
|
|
|
|
|
{
|
|
|
|
|
image = [self unknownFiletypeImage];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) iconForFiles: (NSArray*)pathArray
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
static NSImage *multipleFiles = nil;
|
|
|
|
|
|
|
|
|
|
if ([pathArray count] == 1)
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
return [self iconForFile: [pathArray objectAtIndex: 0]];
|
|
|
|
|
}
|
1999-04-24 11:41:41 +00:00
|
|
|
|
if (multipleFiles == nil)
|
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
// FIXME: Icon does not exist
|
1999-04-24 11:41:41 +00:00
|
|
|
|
multipleFiles = [NSImage imageNamed: @"FileIcon_multi"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return multipleFiles;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) iconForFileType: (NSString*)fileType
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
return [self _iconForExtension: fileType];
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) isFilePackageAtPath: (NSString*)fullPath
|
2001-11-26 20:29:42 +00:00
|
|
|
|
{
|
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
|
NSDictionary *attributes;
|
|
|
|
|
NSString *fileType;
|
|
|
|
|
|
|
|
|
|
attributes = [mgr fileAttributesAtPath: fullPath traverseLink: YES];
|
|
|
|
|
fileType = [attributes objectForKey: NSFileType];
|
|
|
|
|
if ([fileType isEqual: NSFileTypeDirectory] == YES)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* Tracking Changes to the File System
|
|
|
|
|
*/
|
1999-04-08 20:42:46 +00:00
|
|
|
|
- (BOOL) fileSystemChanged
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
BOOL flag = _fileSystemChanged;
|
|
|
|
|
|
|
|
|
|
_fileSystemChanged = NO;
|
|
|
|
|
return flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-08 20:42:46 +00:00
|
|
|
|
- (void) noteFileSystemChanged
|
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
_fileSystemChanged = YES;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (void) noteFileSystemChanged: (NSString*)path
|
2001-11-26 20:29:42 +00:00
|
|
|
|
{
|
|
|
|
|
_fileSystemChanged = YES;
|
1999-04-08 20:42:46 +00:00
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Updates Registered Services and File Types
|
1999-09-01 11:15:27 +00:00
|
|
|
|
*/
|
1999-01-07 15:52:42 +00:00
|
|
|
|
- (void) findApplications
|
1998-11-23 21:39:58 +00:00
|
|
|
|
{
|
1999-04-08 20:42:46 +00:00
|
|
|
|
static NSString *path = nil;
|
1999-04-28 14:22:19 +00:00
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
1999-04-08 20:42:46 +00:00
|
|
|
|
NSData *data;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
NSDictionary *dict;
|
1999-04-08 20:42:46 +00:00
|
|
|
|
NSTask *task;
|
1998-11-23 21:39:58 +00:00
|
|
|
|
|
1999-04-08 20:42:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Try to locate and run an executable copy of 'make_services'
|
|
|
|
|
*/
|
|
|
|
|
if (path == nil)
|
2001-11-26 20:29:42 +00:00
|
|
|
|
{
|
2001-12-02 11:44:07 +00:00
|
|
|
|
#ifdef GNUSTEP_BASE_LIBRARY
|
2001-12-01 21:14:51 +00:00
|
|
|
|
path = RETAIN([[NSSearchPathForDirectoriesInDomains(
|
|
|
|
|
GSToolsDirectory, NSSystemDomainMask, YES) objectAtIndex: 0]
|
|
|
|
|
stringByAppendingPathComponent: @"make_services"]);
|
2001-12-02 11:44:07 +00:00
|
|
|
|
#else
|
|
|
|
|
path = RETAIN([[@GNUSTEP_INSTALL_PREFIX
|
|
|
|
|
stringByAppendingPathComponent: @"Tools"]
|
|
|
|
|
stringByAppendingPathComponent: @"make_services"]);
|
|
|
|
|
#endif
|
2001-11-26 20:29:42 +00:00
|
|
|
|
}
|
1999-04-14 14:42:50 +00:00
|
|
|
|
task = [NSTask launchedTaskWithLaunchPath: path
|
|
|
|
|
arguments: nil];
|
1999-04-08 20:42:46 +00:00
|
|
|
|
if (task != nil)
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
[task waitUntilExit];
|
|
|
|
|
}
|
1999-04-28 14:22:19 +00:00
|
|
|
|
if ([mgr isReadableFileAtPath: extPrefPath] == YES)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
1999-04-28 14:22:19 +00:00
|
|
|
|
data = [NSData dataWithContentsOfFile: extPrefPath];
|
|
|
|
|
if (data)
|
|
|
|
|
{
|
|
|
|
|
dict = [NSDeserializer deserializePropertyListFromData: data
|
|
|
|
|
mutableContainers: NO];
|
|
|
|
|
ASSIGN(extPreferences, dict);
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
1998-12-01 14:41:53 +00:00
|
|
|
|
|
1999-04-28 14:22:19 +00:00
|
|
|
|
if ([mgr isReadableFileAtPath: appListPath] == YES)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
1999-04-28 14:22:19 +00:00
|
|
|
|
data = [NSData dataWithContentsOfFile: appListPath];
|
|
|
|
|
if (data)
|
|
|
|
|
{
|
|
|
|
|
dict = [NSDeserializer deserializePropertyListFromData: data
|
|
|
|
|
mutableContainers: NO];
|
|
|
|
|
ASSIGN(applications, dict);
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Invalidate the cache of icons for file extensions.
|
|
|
|
|
*/
|
2001-11-26 20:29:42 +00:00
|
|
|
|
[_iconMap removeAllObjects];
|
1998-11-23 21:39:58 +00:00
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* Launching and Manipulating Applications
|
|
|
|
|
*/
|
1999-04-08 20:42:46 +00:00
|
|
|
|
- (void) hideOtherApplications
|
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
// FIXME
|
1999-04-08 20:42:46 +00:00
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Calls -launchApplication:showIcon:autolaunch: with arguments set to
|
|
|
|
|
* show the icon but not set it up as an autolaunch.
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) launchApplication: (NSString*)appName
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
1998-11-23 21:39:58 +00:00
|
|
|
|
return [self launchApplication: appName
|
|
|
|
|
showIcon: YES
|
|
|
|
|
autolaunch: NO];
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Launches the specified application (unless it is alreeady running)
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) launchApplication: (NSString*)appName
|
1999-04-08 20:42:46 +00:00
|
|
|
|
showIcon: (BOOL)showIcon
|
|
|
|
|
autolaunch: (BOOL)autolaunch
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
id app;
|
1999-10-12 18:20:22 +00:00
|
|
|
|
|
2001-12-01 21:14:51 +00:00
|
|
|
|
app = [self _connectApplication: appName];
|
2001-11-26 20:29:42 +00:00
|
|
|
|
if (app == nil)
|
|
|
|
|
{
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return [self _launchApplication: appName arguments: nil];
|
2001-11-26 20:29:42 +00:00
|
|
|
|
}
|
1999-10-12 18:20:22 +00:00
|
|
|
|
|
1998-11-23 21:39:58 +00:00
|
|
|
|
return YES;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* Unmounting a Device
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) unmountAndEjectDeviceAtPath: (NSString*)path
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2002-01-22 09:58:44 +00:00
|
|
|
|
NSDictionary *userinfo;
|
|
|
|
|
NSTask *task;
|
|
|
|
|
BOOL flag = NO;
|
2001-11-26 20:29:42 +00:00
|
|
|
|
|
|
|
|
|
userinfo = [NSDictionary dictionaryWithObject: path
|
2002-01-22 09:58:44 +00:00
|
|
|
|
forKey: @"NSDevicePath"];
|
|
|
|
|
[_workspaceCenter postNotificationName: NSWorkspaceWillUnmountNotification
|
|
|
|
|
object: self
|
|
|
|
|
userInfo: userinfo];
|
2001-11-26 20:29:42 +00:00
|
|
|
|
|
|
|
|
|
// FIXME This is system specific
|
|
|
|
|
task = [NSTask launchedTaskWithLaunchPath: @"eject"
|
|
|
|
|
arguments: [NSArray arrayWithObject: path]];
|
|
|
|
|
if (task != nil)
|
|
|
|
|
{
|
|
|
|
|
[task waitUntilExit];
|
|
|
|
|
if ([task terminationStatus] != 0)
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2001-11-26 20:29:42 +00:00
|
|
|
|
else
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
flag = YES;
|
|
|
|
|
}
|
2001-11-26 20:29:42 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2001-11-26 20:29:42 +00:00
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
[_workspaceCenter postNotificationName: NSWorkspaceDidUnmountNotification
|
|
|
|
|
object: self
|
|
|
|
|
userInfo: userinfo];
|
2001-11-26 20:29:42 +00:00
|
|
|
|
return flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* Tracking Status Changes for Devices
|
|
|
|
|
*/
|
1999-04-08 20:42:46 +00:00
|
|
|
|
- (void) checkForRemovableMedia
|
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
// FIXME
|
1999-04-08 20:42:46 +00:00
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSArray*) mountNewRemovableMedia
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
// FIXME
|
1996-05-30 20:03:15 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSArray*) mountedRemovableMedia
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2002-01-22 09:58:44 +00:00
|
|
|
|
NSArray *volumes = [self mountedLocalVolumePaths];
|
2001-11-26 20:29:42 +00:00
|
|
|
|
NSMutableArray *names = [NSMutableArray arrayWithCapacity: [volumes count]];
|
2002-01-22 09:58:44 +00:00
|
|
|
|
unsigned i;
|
2001-11-26 20:29:42 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < [volumes count]; i++)
|
|
|
|
|
{
|
|
|
|
|
BOOL removableFlag;
|
|
|
|
|
BOOL writableFlag;
|
|
|
|
|
BOOL unmountableFlag;
|
|
|
|
|
NSString *description;
|
|
|
|
|
NSString *fileSystemType;
|
|
|
|
|
NSString *name = [volumes objectAtIndex: i];
|
|
|
|
|
|
|
|
|
|
if ([self getFileSystemInfoForPath: name
|
|
|
|
|
isRemovable: &removableFlag
|
|
|
|
|
isWritable: &writableFlag
|
|
|
|
|
isUnmountable: &unmountableFlag
|
|
|
|
|
description: &description
|
|
|
|
|
type: &fileSystemType] && removableFlag)
|
|
|
|
|
{
|
|
|
|
|
[names addObject: name];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return names;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
- (NSArray*) mountedLocalVolumePaths
|
2001-11-26 20:29:42 +00:00
|
|
|
|
{
|
|
|
|
|
// FIXME This is system specific
|
2002-01-22 09:58:44 +00:00
|
|
|
|
NSString *mtab = [NSString stringWithContentsOfFile: @"/etc/mtab"];
|
|
|
|
|
NSArray *mounts = [mtab componentsSeparatedByString: @"\n"];
|
2001-11-26 20:29:42 +00:00
|
|
|
|
NSMutableArray *names = [NSMutableArray arrayWithCapacity: [mounts count]];
|
2002-01-22 09:58:44 +00:00
|
|
|
|
unsigned int i;
|
2001-11-26 20:29:42 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < [mounts count]; i++)
|
|
|
|
|
{
|
2002-01-22 09:58:44 +00:00
|
|
|
|
NSArray *parts;
|
|
|
|
|
NSString *type;
|
|
|
|
|
|
|
|
|
|
parts = [[names objectAtIndex: i] componentsSeparatedByString: @" "];
|
|
|
|
|
type = [parts objectAtIndex: 2];
|
|
|
|
|
if ([type isEqualToString: @"proc"] == NO
|
|
|
|
|
&& [type isEqualToString: @"devpts"] == NO
|
|
|
|
|
&& [type isEqualToString: @"shm"] == NO)
|
2001-11-26 20:29:42 +00:00
|
|
|
|
{
|
|
|
|
|
[names addObject: [parts objectAtIndex: 1]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return names;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the workspace notification center
|
1999-09-01 11:15:27 +00:00
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSNotificationCenter*) notificationCenter
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
return _workspaceCenter;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Simply makes a note that the user defaults database has changed.
|
1999-09-01 11:15:27 +00:00
|
|
|
|
*/
|
1999-04-08 20:42:46 +00:00
|
|
|
|
- (void) noteUserDefaultsChanged
|
1998-11-23 21:39:58 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
_userDefaultsChanged = YES;
|
1998-11-23 21:39:58 +00:00
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a flag to say if the defaults database has changed since
|
|
|
|
|
* the last time this method was called.
|
|
|
|
|
*/
|
1999-04-08 20:42:46 +00:00
|
|
|
|
- (BOOL) userDefaultsChanged
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
BOOL hasChanged = _userDefaultsChanged;
|
1999-09-01 11:15:27 +00:00
|
|
|
|
|
2001-11-26 20:29:42 +00:00
|
|
|
|
_userDefaultsChanged = NO;
|
1998-11-23 21:39:58 +00:00
|
|
|
|
return hasChanged;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Animating an Image- slides it from one point on the screen to another.
|
1999-09-01 11:15:27 +00:00
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (void) slideImage: (NSImage*)image
|
1999-04-08 20:42:46 +00:00
|
|
|
|
from: (NSPoint)fromPoint
|
|
|
|
|
to: (NSPoint)toPoint
|
|
|
|
|
{
|
2002-03-28 03:53:18 +00:00
|
|
|
|
[GSCurrentServer() slideImage: image from: fromPoint to: toPoint];
|
1999-04-08 20:42:46 +00:00
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* Requesting Additional Time before Power Off or Logout
|
|
|
|
|
*/
|
1999-04-08 20:42:46 +00:00
|
|
|
|
- (int) extendPowerOffBy: (int)requested
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
// FIXME
|
1996-05-30 20:03:15 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
1999-04-08 20:42:46 +00:00
|
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
|
@implementation NSWorkspace (GNUstep)
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the 'best' application to open a file with the specified extension
|
|
|
|
|
* using the given role. If the role is nil then apps which can edit are
|
|
|
|
|
* preferred but viewers are also acceptable. Uses a user preferred app
|
|
|
|
|
* or picks any good match.
|
|
|
|
|
*/
|
1999-04-28 11:16:26 +00:00
|
|
|
|
- (NSString*) getBestAppInRole: (NSString*)role
|
|
|
|
|
forExtension: (NSString*)ext
|
|
|
|
|
{
|
|
|
|
|
NSString *appName = nil;
|
|
|
|
|
|
2002-01-22 13:20:20 +00:00
|
|
|
|
if ([self _extension: ext role: role app: &appName] == NO)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
{
|
2002-01-22 09:58:44 +00:00
|
|
|
|
appName = nil;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
return appName;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the path set for the icon matching the image by
|
|
|
|
|
* -setBestIcon:forExtension:
|
|
|
|
|
*/
|
1999-04-28 11:16:26 +00:00
|
|
|
|
- (NSString*) getBestIconForExtension: (NSString*)ext
|
|
|
|
|
{
|
|
|
|
|
NSString *iconPath = nil;
|
|
|
|
|
|
|
|
|
|
if (extPreferences != nil)
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *inf;
|
|
|
|
|
|
|
|
|
|
inf = [extPreferences objectForKey: [ext lowercaseString]];
|
|
|
|
|
if (inf != nil)
|
1999-09-01 11:15:27 +00:00
|
|
|
|
{
|
|
|
|
|
iconPath = [inf objectForKey: @"Icon"];
|
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
return iconPath;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Gets the applications cache (generated by the make_services tool)
|
|
|
|
|
* and looks up the special entry that contains a dictionary of all
|
|
|
|
|
* file extensions recognised by GNUstep applications. Then finds
|
|
|
|
|
* the dictionary of applications that can handle our file and
|
|
|
|
|
* returns it.
|
|
|
|
|
*/
|
1999-04-28 11:16:26 +00:00
|
|
|
|
- (NSDictionary*) infoForExtension: (NSString*)ext
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *map;
|
|
|
|
|
|
|
|
|
|
ext = [ext lowercaseString];
|
|
|
|
|
map = [applications objectForKey: @"GSExtensionsMap"];
|
|
|
|
|
return [map objectForKey: ext];
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the application bundle for the named application.
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSBundle*) bundleForApp: (NSString*)appName
|
1999-06-03 04:53:12 +00:00
|
|
|
|
{
|
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
|
|
if (appName == nil)
|
1999-09-01 11:15:27 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1999-06-03 04:53:12 +00:00
|
|
|
|
path = appName;
|
|
|
|
|
appName = [path lastPathComponent];
|
|
|
|
|
if ([appName isEqual: path])
|
|
|
|
|
{
|
|
|
|
|
path = [self fullPathForApplication: appName];
|
|
|
|
|
appName = [[path lastPathComponent] stringByDeletingPathExtension];
|
|
|
|
|
}
|
|
|
|
|
else if ([appName pathExtension] == nil)
|
|
|
|
|
{
|
|
|
|
|
path = [path stringByAppendingPathExtension: @"app"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
appName = [[path lastPathComponent] stringByDeletingPathExtension];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (path == nil)
|
1999-09-01 11:15:27 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1999-06-03 04:53:12 +00:00
|
|
|
|
|
1999-08-19 23:30:03 +00:00
|
|
|
|
return [NSBundle bundleWithPath: path];
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
1999-09-01 11:15:27 +00:00
|
|
|
|
* Returns the application icon for the given app.
|
1999-08-19 23:30:03 +00:00
|
|
|
|
* Or null if none defined or appName is not a valid application name.
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) appIconForApp: (NSString*)appName
|
1999-08-19 23:30:03 +00:00
|
|
|
|
{
|
2001-11-26 20:29:42 +00:00
|
|
|
|
NSBundle *bundle = [self bundleForApp: appName];
|
1999-09-01 11:15:27 +00:00
|
|
|
|
NSString *iconPath;
|
1999-08-19 23:30:03 +00:00
|
|
|
|
|
|
|
|
|
if (bundle == nil)
|
1999-09-01 11:15:27 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1999-08-19 23:30:03 +00:00
|
|
|
|
iconPath = [[bundle infoDictionary] objectForKey: @"NSIcon"];
|
|
|
|
|
|
|
|
|
|
if (![iconPath isAbsolutePath])
|
1999-09-01 11:15:27 +00:00
|
|
|
|
{
|
|
|
|
|
iconPath = [[bundle bundlePath] stringByAppendingPathComponent: iconPath];
|
|
|
|
|
}
|
1999-08-19 23:30:03 +00:00
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
return AUTORELEASE([[NSImage alloc] initWithContentsOfFile: iconPath]);
|
1999-08-19 23:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Requires the path to an application wrapper as an argument, and returns
|
|
|
|
|
* the full path to the executable.
|
1999-09-01 11:15:27 +00:00
|
|
|
|
*/
|
1999-08-19 23:30:03 +00:00
|
|
|
|
- (NSString*) locateApplicationBinary: (NSString*)appName
|
|
|
|
|
{
|
|
|
|
|
NSString *path;
|
|
|
|
|
NSString *file;
|
1999-09-01 11:15:27 +00:00
|
|
|
|
NSBundle *bundle = [self bundleForApp: appName];
|
1999-08-19 23:30:03 +00:00
|
|
|
|
|
|
|
|
|
if (bundle == nil)
|
1999-09-01 11:15:27 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1999-08-19 23:30:03 +00:00
|
|
|
|
path = [bundle bundlePath];
|
1999-06-03 04:53:12 +00:00
|
|
|
|
file = [[bundle infoDictionary] objectForKey: @"NSExecutable"];
|
1999-08-19 23:30:03 +00:00
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
if (file == nil)
|
1999-06-03 04:53:12 +00:00
|
|
|
|
{
|
1999-09-01 11:15:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* If there is no executable specified in the info property-list, then
|
|
|
|
|
* we expect the executable to reside within the app wrapper and to
|
|
|
|
|
* have the same name as the app wrapper but without the extension.
|
|
|
|
|
*/
|
|
|
|
|
file = [path lastPathComponent];
|
|
|
|
|
file = [file stringByDeletingPathExtension];
|
|
|
|
|
path = [path stringByAppendingPathComponent: file];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If there is an executable specified in the info property-list, then
|
|
|
|
|
* it can be either an absolute path, or a path relative to the app
|
|
|
|
|
* wrapper, so we make sure we end up with an absolute path to return.
|
|
|
|
|
*/
|
|
|
|
|
if ([file isAbsolutePath] == YES)
|
1999-06-03 04:53:12 +00:00
|
|
|
|
{
|
1999-09-01 11:15:27 +00:00
|
|
|
|
path = file;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
path = [path stringByAppendingFormat: @"/%@", file];
|
1999-06-03 04:53:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
return path;
|
1999-06-03 04:53:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets up a user preference for which app should be used to open files
|
|
|
|
|
* of the specified extension.
|
|
|
|
|
*/
|
1999-04-28 11:16:26 +00:00
|
|
|
|
- (void) setBestApp: (NSString*)appName
|
|
|
|
|
inRole: (NSString*)role
|
|
|
|
|
forExtension: (NSString*)ext
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *map;
|
|
|
|
|
NSMutableDictionary *inf;
|
|
|
|
|
NSData *data;
|
|
|
|
|
|
|
|
|
|
ext = [ext lowercaseString];
|
2000-04-28 19:35:42 +00:00
|
|
|
|
if (extPreferences != nil)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
map = [extPreferences mutableCopy];
|
|
|
|
|
else
|
|
|
|
|
map = [NSMutableDictionary new];
|
|
|
|
|
|
|
|
|
|
inf = [[map objectForKey: ext] mutableCopy];
|
|
|
|
|
if (inf == nil)
|
|
|
|
|
{
|
|
|
|
|
inf = [NSMutableDictionary new];
|
|
|
|
|
}
|
|
|
|
|
if (appName == nil)
|
|
|
|
|
{
|
|
|
|
|
if (role == nil)
|
|
|
|
|
{
|
|
|
|
|
NSString *iconPath = [inf objectForKey: @"Icon"];
|
|
|
|
|
|
1999-09-01 11:15:27 +00:00
|
|
|
|
RETAIN(iconPath);
|
1999-04-28 11:16:26 +00:00
|
|
|
|
[inf removeAllObjects];
|
|
|
|
|
if (iconPath)
|
|
|
|
|
{
|
|
|
|
|
[inf setObject: iconPath forKey: @"Icon"];
|
1999-09-01 11:15:27 +00:00
|
|
|
|
RELEASE(iconPath);
|
1999-04-28 11:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[inf removeObjectForKey: role];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[inf setObject: appName forKey: (role ? role : @"Editor")];
|
|
|
|
|
}
|
|
|
|
|
[map setObject: inf forKey: ext];
|
1999-09-01 11:15:27 +00:00
|
|
|
|
RELEASE(inf);
|
|
|
|
|
RELEASE(extPreferences);
|
2000-04-28 19:35:42 +00:00
|
|
|
|
extPreferences = map;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
data = [NSSerializer serializePropertyList: extPreferences];
|
|
|
|
|
[data writeToFile: extPrefPath atomically: YES];
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 09:58:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets up a user preference for which icon should be used to
|
|
|
|
|
* represent the specified file extension.
|
|
|
|
|
*/
|
1999-04-28 11:16:26 +00:00
|
|
|
|
- (void) setBestIcon: (NSString*)iconPath forExtension: (NSString*)ext
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *map;
|
|
|
|
|
NSMutableDictionary *inf;
|
|
|
|
|
NSData *data;
|
|
|
|
|
|
|
|
|
|
ext = [ext lowercaseString];
|
2000-04-28 19:35:42 +00:00
|
|
|
|
if (extPreferences != nil)
|
1999-04-28 11:16:26 +00:00
|
|
|
|
map = [extPreferences mutableCopy];
|
|
|
|
|
else
|
|
|
|
|
map = [NSMutableDictionary new];
|
|
|
|
|
|
|
|
|
|
inf = [[map objectForKey: ext] mutableCopy];
|
|
|
|
|
if (inf == nil)
|
|
|
|
|
inf = [NSMutableDictionary new];
|
|
|
|
|
if (iconPath)
|
|
|
|
|
[inf setObject: iconPath forKey: @"Icon"];
|
|
|
|
|
else
|
|
|
|
|
[inf removeObjectForKey: @"Icon"];
|
|
|
|
|
[map setObject: inf forKey: ext];
|
1999-09-01 11:15:27 +00:00
|
|
|
|
RELEASE(inf);
|
|
|
|
|
RELEASE(extPreferences);
|
2000-04-28 19:35:42 +00:00
|
|
|
|
extPreferences = map;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
data = [NSSerializer serializePropertyList: extPreferences];
|
|
|
|
|
[data writeToFile: extPrefPath atomically: YES];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSWorkspace (Private)
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) _extIconForApp: (NSString*)appName info: (NSDictionary*)extInfo
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
NSDictionary *typeInfo = [extInfo objectForKey: appName];
|
2002-01-22 09:58:44 +00:00
|
|
|
|
NSString *file = [typeInfo objectForKey: @"NSIcon"];
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
|
|
|
|
if (file)
|
|
|
|
|
{
|
|
|
|
|
if ([file isAbsolutePath] == NO)
|
|
|
|
|
{
|
|
|
|
|
NSString *iconPath;
|
|
|
|
|
NSBundle *bundle;
|
|
|
|
|
|
|
|
|
|
bundle = [self bundleForApp: appName];
|
|
|
|
|
iconPath = [bundle pathForImageResource: file];
|
|
|
|
|
/*
|
|
|
|
|
* If the icon is not in the Resources of the app, try looking
|
|
|
|
|
* directly in the app wrapper.
|
|
|
|
|
*/
|
|
|
|
|
if (iconPath == nil)
|
|
|
|
|
{
|
|
|
|
|
iconPath = [[bundle bundlePath] stringByAppendingPathComponent: file];
|
|
|
|
|
}
|
|
|
|
|
file = iconPath;
|
|
|
|
|
}
|
|
|
|
|
if ([[NSFileManager defaultManager] isReadableFileAtPath: file] == YES)
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([[NSImage alloc] initWithContentsOfFile: file]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) _getImageWithName: (NSString*)name
|
|
|
|
|
alternate: (NSString*)alternate
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
NSImage *image = nil;
|
|
|
|
|
|
|
|
|
|
image = [NSImage imageNamed: name];
|
|
|
|
|
if (image == nil)
|
|
|
|
|
image = [NSImage imageNamed: alternate];
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Returns the default icon to display for a directory */
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) folderImage
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
static NSImage *image = nil;
|
|
|
|
|
|
|
|
|
|
if (image == nil)
|
|
|
|
|
{
|
|
|
|
|
image = RETAIN([self _getImageWithName: @"Folder.tiff"
|
|
|
|
|
alternate: @"common_Folder.tiff"]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Returns the default icon to display for a directory */
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) unknownFiletypeImage
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
static NSImage *image = nil;
|
|
|
|
|
|
|
|
|
|
if (image == nil)
|
|
|
|
|
{
|
|
|
|
|
image = RETAIN([self _getImageWithName: @"Unknown.tiff"
|
|
|
|
|
alternate: @"common_Unknown.tiff"]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Returns the default icon to display for a directory */
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (NSImage*) rootImage
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
|
|
|
|
static NSImage *image = nil;
|
|
|
|
|
|
|
|
|
|
if (image == nil)
|
|
|
|
|
{
|
|
|
|
|
image = RETAIN([self _getImageWithName: @"Root_PC.tiff"
|
|
|
|
|
alternate: @"common_Root_PC.tiff"]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSImage*) _iconForExtension: (NSString*)ext
|
|
|
|
|
{
|
|
|
|
|
NSImage *icon = nil;
|
|
|
|
|
|
|
|
|
|
if (ext == nil || [ext isEqualToString: @""])
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* extensions are case-insensitive - convert to lowercase.
|
|
|
|
|
*/
|
|
|
|
|
ext = [ext lowercaseString];
|
|
|
|
|
if ((icon = [_iconMap objectForKey: ext]) == nil)
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *prefs;
|
|
|
|
|
NSDictionary *extInfo;
|
|
|
|
|
NSString *iconPath;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If there is a user-specified preference for an image -
|
|
|
|
|
* try to use that one.
|
|
|
|
|
*/
|
|
|
|
|
prefs = [extPreferences objectForKey: ext];
|
|
|
|
|
iconPath = [prefs objectForKey: @"Icon"];
|
|
|
|
|
if (iconPath)
|
|
|
|
|
{
|
|
|
|
|
icon = [[NSImage alloc] initWithContentsOfFile: iconPath];
|
|
|
|
|
AUTORELEASE(icon);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (icon == nil && (extInfo = [self infoForExtension: ext]) != nil)
|
|
|
|
|
{
|
|
|
|
|
NSString *appName;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If there are any application preferences given, try to use the
|
|
|
|
|
* icon for this file that is used by the preferred app.
|
|
|
|
|
*/
|
|
|
|
|
if (prefs)
|
|
|
|
|
{
|
|
|
|
|
if ((appName = [extInfo objectForKey: @"Editor"]) != nil)
|
|
|
|
|
{
|
|
|
|
|
icon = [self _extIconForApp: appName info: extInfo];
|
|
|
|
|
}
|
|
|
|
|
if (icon == nil
|
|
|
|
|
&& (appName = [extInfo objectForKey: @"Viewer"]) != nil)
|
|
|
|
|
{
|
|
|
|
|
icon = [self _extIconForApp: appName info: extInfo];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (icon == nil)
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Still no icon - try all the apps that handle this file
|
|
|
|
|
* extension.
|
|
|
|
|
*/
|
|
|
|
|
enumerator = [extInfo keyEnumerator];
|
|
|
|
|
while (icon == nil && (appName = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
icon = [self _extIconForApp: appName info: extInfo];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Nothing found at all - use the unknowntype icon.
|
|
|
|
|
*/
|
|
|
|
|
if (icon == nil)
|
|
|
|
|
{
|
|
|
|
|
icon = [self unknownFiletypeImage];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set the icon in the cache for next time.
|
|
|
|
|
*/
|
|
|
|
|
if (icon != nil)
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
[_iconMap setObject: icon forKey: ext];
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
}
|
|
|
|
|
return icon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) _extension: (NSString*)ext
|
|
|
|
|
role: (NSString*)role
|
|
|
|
|
app: (NSString**)app
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
NSString *appName = nil;
|
2002-01-22 13:20:20 +00:00
|
|
|
|
NSDictionary *apps = [self infoForExtension: ext];
|
2001-12-01 21:14:51 +00:00
|
|
|
|
NSDictionary *prefs;
|
|
|
|
|
NSDictionary *info;
|
|
|
|
|
|
|
|
|
|
ext = [ext lowercaseString];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Look for the name of the preferred app in this role.
|
|
|
|
|
* A 'nil' roll is a wildcard - find the preferred Editor or Viewer.
|
|
|
|
|
*/
|
|
|
|
|
prefs = [extPreferences objectForKey: ext];
|
|
|
|
|
if (role == nil || [role isEqualToString: @"Editor"])
|
|
|
|
|
{
|
|
|
|
|
appName = [prefs objectForKey: @"Editor"];
|
|
|
|
|
if (appName != nil)
|
|
|
|
|
{
|
|
|
|
|
info = [apps objectForKey: appName];
|
|
|
|
|
if (info != nil)
|
|
|
|
|
{
|
|
|
|
|
if (app != 0)
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
*app = appName;
|
|
|
|
|
}
|
2002-01-22 13:20:20 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
else if ([self locateApplicationBinary: appName] != nil)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Return the preferred application even though it doesn't
|
|
|
|
|
* say it opens this type of file ... preferences overrule.
|
|
|
|
|
*/
|
|
|
|
|
if (app != 0)
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
2002-01-22 13:20:20 +00:00
|
|
|
|
*app = appName;
|
2002-01-22 09:58:44 +00:00
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (role == nil || [role isEqualToString: @"Viewer"])
|
|
|
|
|
{
|
|
|
|
|
appName = [prefs objectForKey: @"Viewer"];
|
|
|
|
|
if (appName != nil)
|
|
|
|
|
{
|
|
|
|
|
info = [apps objectForKey: appName];
|
|
|
|
|
if (info != nil)
|
|
|
|
|
{
|
|
|
|
|
if (app != 0)
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
|
|
|
|
*app = appName;
|
|
|
|
|
}
|
2002-01-22 13:20:20 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
else if ([self locateApplicationBinary: appName] != nil)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Return the preferred application even though it doesn't
|
|
|
|
|
* say it opens this type of file ... preferences overrule.
|
|
|
|
|
*/
|
|
|
|
|
if (app != 0)
|
2002-01-22 09:58:44 +00:00
|
|
|
|
{
|
2002-01-22 13:20:20 +00:00
|
|
|
|
*app = appName;
|
2002-01-22 09:58:44 +00:00
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Go through the dictionary of apps that know about this file type and
|
|
|
|
|
* determine the best application to open the file by examining the
|
|
|
|
|
* type information for each app.
|
|
|
|
|
* The 'NSRole' field specifies what the app can do with the file - if it
|
|
|
|
|
* is missing, we assume an 'Editor' role.
|
|
|
|
|
*/
|
2002-01-22 09:58:44 +00:00
|
|
|
|
if (apps == nil || [apps count] == 0)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
enumerator = [apps keyEnumerator];
|
|
|
|
|
|
|
|
|
|
if (role == nil)
|
|
|
|
|
{
|
|
|
|
|
BOOL found = NO;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the requested role is 'nil', we can accept an app that is either
|
|
|
|
|
* an Editor (preferred) or a Viewer.
|
|
|
|
|
*/
|
|
|
|
|
while ((appName = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
NSString *str;
|
|
|
|
|
|
|
|
|
|
info = [apps objectForKey: appName];
|
|
|
|
|
str = [info objectForKey: @"NSRole"];
|
|
|
|
|
if (str == nil || [str isEqualToString: @"Editor"])
|
|
|
|
|
{
|
|
|
|
|
if (app != 0)
|
2002-01-22 13:20:20 +00:00
|
|
|
|
{
|
|
|
|
|
*app = appName;
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
else if ([str isEqualToString: @"Viewer"])
|
|
|
|
|
{
|
|
|
|
|
if (app != 0)
|
2002-01-22 13:20:20 +00:00
|
|
|
|
{
|
|
|
|
|
*app = appName;
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
found = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while ((appName = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
NSString *str;
|
|
|
|
|
|
|
|
|
|
info = [apps objectForKey: appName];
|
|
|
|
|
str = [info objectForKey: @"NSRole"];
|
|
|
|
|
if ((str == nil && [role isEqualToString: @"Editor"])
|
|
|
|
|
|| [str isEqualToString: role])
|
|
|
|
|
{
|
|
|
|
|
if (app != 0)
|
2002-01-22 13:20:20 +00:00
|
|
|
|
{
|
|
|
|
|
*app = appName;
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-10 16:33:39 +00:00
|
|
|
|
/**
|
|
|
|
|
* Launch an application ... if there is a workspace application, ask it
|
|
|
|
|
* to perform the launch for us. Otherwise we try to launch the app
|
|
|
|
|
* ourself as long as it is on the same host as we are.
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (BOOL) _launchApplication: (NSString*)appName
|
|
|
|
|
arguments: (NSArray*)args
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
2002-01-10 16:33:39 +00:00
|
|
|
|
id app = nil;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
2002-01-10 16:33:39 +00:00
|
|
|
|
// app = [self _workspaceApplication];
|
|
|
|
|
if (app != nil)
|
|
|
|
|
{
|
|
|
|
|
return [app _launchApplication: appName arguments: args];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2002-01-22 18:23:56 +00:00
|
|
|
|
NSTask *task;
|
2002-01-10 16:33:39 +00:00
|
|
|
|
NSString *path;
|
|
|
|
|
NSDictionary *userinfo;
|
|
|
|
|
NSString *host;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
2002-01-10 16:33:39 +00:00
|
|
|
|
path = [self locateApplicationBinary: appName];
|
|
|
|
|
if (path == nil)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
2002-01-10 16:33:39 +00:00
|
|
|
|
/*
|
|
|
|
|
* Try to ensure that apps we launch display in this workspace
|
|
|
|
|
* ie they have the same -NSHost specification.
|
|
|
|
|
*/
|
|
|
|
|
host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"];
|
|
|
|
|
if (host != nil)
|
|
|
|
|
{
|
|
|
|
|
NSHost *h;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
2002-01-10 16:33:39 +00:00
|
|
|
|
h = [NSHost hostWithName: host];
|
|
|
|
|
if ([h isEqual: [NSHost currentHost]] == NO)
|
|
|
|
|
{
|
|
|
|
|
if ([args containsObject: @"-NSHost"] == NO)
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray *a;
|
|
|
|
|
|
|
|
|
|
if (args == nil)
|
|
|
|
|
{
|
|
|
|
|
a = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
a = AUTORELEASE([args mutableCopy]);
|
|
|
|
|
}
|
|
|
|
|
[a insertObject: @"-NSHost" atIndex: 0];
|
|
|
|
|
[a insertObject: host atIndex: 1];
|
|
|
|
|
args = a;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* App being launched, send
|
|
|
|
|
* NSWorkspaceWillLaunchApplicationNotification
|
|
|
|
|
*/
|
|
|
|
|
userinfo = [NSDictionary dictionaryWithObject:
|
|
|
|
|
[[appName lastPathComponent] stringByDeletingPathExtension]
|
|
|
|
|
forKey: @"NSApplicationName"];
|
|
|
|
|
[_workspaceCenter
|
|
|
|
|
postNotificationName: NSWorkspaceWillLaunchApplicationNotification
|
|
|
|
|
object: self
|
|
|
|
|
userInfo: userinfo];
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
task = [NSTask launchedTaskWithLaunchPath: path arguments: args];
|
|
|
|
|
if (task == nil)
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* The NSWorkspaceDidLaunchApplicationNotification will be
|
|
|
|
|
* sent by the started application itself.
|
|
|
|
|
*/
|
2002-01-22 18:23:56 +00:00
|
|
|
|
[_launched setObject: task forKey: appName];
|
2002-01-10 16:33:39 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
- (id) _connectApplication: (NSString*)appName
|
2001-12-01 21:14:51 +00:00
|
|
|
|
{
|
2002-01-10 16:33:39 +00:00
|
|
|
|
NSString *host;
|
|
|
|
|
NSString *port;
|
2002-01-22 18:23:56 +00:00
|
|
|
|
NSDate *when = nil;
|
|
|
|
|
BOOL done = NO;
|
2002-01-10 16:33:39 +00:00
|
|
|
|
id app = nil;
|
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
while (done == NO)
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
2002-01-22 18:23:56 +00:00
|
|
|
|
host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"];
|
|
|
|
|
if (host == nil)
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
|
|
|
|
host = @"";
|
|
|
|
|
}
|
2002-01-22 18:23:56 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSHost *h;
|
|
|
|
|
|
|
|
|
|
h = [NSHost hostWithName: host];
|
|
|
|
|
if ([h isEqual: [NSHost currentHost]] == YES)
|
|
|
|
|
{
|
|
|
|
|
host = @"";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
port = [appName stringByDeletingPathExtension];
|
|
|
|
|
/*
|
|
|
|
|
* Try to contact a running application.
|
|
|
|
|
*/
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
app = [NSConnection rootProxyForConnectionWithRegisteredName: port
|
|
|
|
|
host: host];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
/* Fatal error in DO */
|
|
|
|
|
app = nil;
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
|
|
|
|
|
done = YES;
|
|
|
|
|
if (app == nil)
|
|
|
|
|
{
|
|
|
|
|
NSTask *task = [_launched objectForKey: appName];
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
2002-01-22 18:23:56 +00:00
|
|
|
|
if (task != nil && [task isRunning] == YES)
|
|
|
|
|
{
|
|
|
|
|
if (when == nil)
|
|
|
|
|
{
|
|
|
|
|
when = [[NSDate alloc] init];
|
|
|
|
|
done = NO;
|
|
|
|
|
}
|
|
|
|
|
else if ([when timeIntervalSinceNow] > 5.0)
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
DESTROY(when);
|
|
|
|
|
result = NSRunAlertPanel(appName,
|
|
|
|
|
@"Application seems to have hung",
|
|
|
|
|
@"Continue", @"Terminate", @"Wait");
|
|
|
|
|
|
|
|
|
|
if (result == NSAlertDefaultReturn)
|
|
|
|
|
{
|
|
|
|
|
done = YES;
|
|
|
|
|
}
|
|
|
|
|
else if (result == NSAlertOtherReturn)
|
|
|
|
|
{
|
|
|
|
|
done = NO;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[task terminate];
|
|
|
|
|
[_launched removeObjectForKey: appName];
|
|
|
|
|
done = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (done == NO)
|
|
|
|
|
{
|
|
|
|
|
NSDate *limit;
|
|
|
|
|
|
|
|
|
|
limit = [[NSDate alloc] initWithTimeIntervalSinceNow: 0.5];
|
|
|
|
|
[[NSRunLoop currentRunLoop] runUntilDate: limit];
|
|
|
|
|
RELEASE(limit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TEST_RELEASE(when);
|
2001-12-01 21:14:51 +00:00
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) _workspaceApplication
|
|
|
|
|
{
|
2002-01-10 16:33:39 +00:00
|
|
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
|
NSString *appName;
|
|
|
|
|
id app;
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
|
|
|
|
/* What Workspace application? */
|
2001-12-07 23:02:55 +00:00
|
|
|
|
appName = [defs stringForKey: @"GSWorkspaceApplication"];
|
2001-12-01 21:14:51 +00:00
|
|
|
|
if (appName == nil)
|
2002-01-10 16:33:39 +00:00
|
|
|
|
{
|
|
|
|
|
appName = @"GSWorkspace";
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
|
|
|
|
|
app = [self _connectApplication: appName];
|
|
|
|
|
if (app == nil)
|
|
|
|
|
{
|
2002-01-10 16:33:39 +00:00
|
|
|
|
NSString *host;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* We don't use -_launchApplication:arguents: here as that method
|
|
|
|
|
* calls -_workspaceApplication, and would cause recursion.
|
|
|
|
|
*/
|
|
|
|
|
host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"];
|
|
|
|
|
if (host == nil)
|
|
|
|
|
{
|
|
|
|
|
host = @"";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSHost *h;
|
|
|
|
|
|
|
|
|
|
h = [NSHost hostWithName: host];
|
|
|
|
|
if ([h isEqual: [NSHost currentHost]] == YES)
|
|
|
|
|
{
|
|
|
|
|
host = @"";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* We can only launch a workspace app if we are displaying to the
|
|
|
|
|
* local host (since if we are displaying on another host we want
|
|
|
|
|
* to to talk to the workspace app on that host too).
|
|
|
|
|
*/
|
|
|
|
|
if ([host isEqual: @""] == YES)
|
|
|
|
|
{
|
|
|
|
|
if ([self _launchApplication: appName arguments: nil] == YES)
|
|
|
|
|
{
|
|
|
|
|
app = [self _connectApplication: appName];
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-12-01 21:14:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|