From c78bdc478d69027f9f9d7a1b4c2794a7dcabc843 Mon Sep 17 00:00:00 2001 From: richard Date: Mon, 23 Nov 1998 21:39:58 +0000 Subject: [PATCH] Preliminary services support. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@3307 72102866-910b-0410-8b05-ffd578937521 --- Source/NSPasteboard.m | 176 ++++++++++++++++++++++++++-- Source/NSWorkspace.m | 261 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 408 insertions(+), 29 deletions(-) diff --git a/Source/NSPasteboard.m b/Source/NSPasteboard.m index 77ec84341..558b9f72c 100644 --- a/Source/NSPasteboard.m +++ b/Source/NSPasteboard.m @@ -30,6 +30,7 @@ #include #include #include +#include #include "../Tools/PasteboardServer.h" #include #include @@ -43,6 +44,10 @@ #include #include #include +#include +#include +#include +#include #define stringify_it(X) #X #define prog_path(X,Y) \ @@ -123,8 +128,15 @@ static id the_server = nil; } else { + NSRunLoop *loop = [NSRunLoop currentRunLoop]; + NSDate *next; + system(prog_path(GNUSTEP_INSTALL_PREFIX, "/gpbs &")); - sleep(5); + [NSTimer scheduledTimerWithTimeInterval: 5.0 + invocation: nil + repeats: NO]; + next = [NSDate dateWithTimeIntervalSinceNow: 5.0]; + [loop runUntilDate: next]; recursion = YES; [self _pbs]; recursion = NO; @@ -383,8 +395,8 @@ static id the_server = nil; - (void) releaseGlobally { - [target releaseGlobally]; - [pasteboards removeObjectForKey: name]; + [target releaseGlobally]; + [pasteboards removeObjectForKey: name]; } // @@ -726,12 +738,9 @@ NSGetFileTypes(NSArray *pboardTypes) return nil; } -void -NSUpdateDynamicServices() -{ - system(prog_path(GNUSTEP_INSTALL_PREFIX, "/make_services")); -} +extern NSDictionary* GSAllServicesDictionary(); +extern NSDictionary* GSApplicationsDictionary(); static NSConnection *listener = nil; @@ -752,3 +761,154 @@ NSRegisterServicesProvider(id provider, NSString *name) [listener retain]; } +BOOL +NSPerformService(NSString *serviceItem, NSPasteboard *pboard) +{ + NSUserDefaults *defs; + NSArray *languages; + NSDictionary *services; + NSDictionary *byLanguage; + NSDictionary *service; + NSString *port; + unsigned end; + unsigned pos; + NSString *timeout; + double seconds; + NSDate *finishBy; + NSString *appPath; + id provider; + NSConnection *connection; + NSString *message; + NSString *selName; + SEL msgSel; + NSString *userData; + IMP msgImp; + NSString *error = nil; + NSDictionary *allServices; + + /* + * Get language preference array. + */ + defs = [NSUserDefaults standardUserDefaults]; + languages = [defs arrayForKey: @"Languages"]; + + /* + * Get dictionary of menu services from workspace manager. + */ + allServices = GSAllServicesDictionary(); + + services = [allServices objectForKey: @"ByService"]; + + /* + * Find service information for a service matching the given menu item + * Search in language preference order. + */ + if (languages) + end = [languages count]; + else + end = 0; + byLanguage = nil; + for (pos = 0; pos < end; pos++) + { + NSString *language = [languages objectAtIndex: pos]; + + byLanguage = [services objectForKey: language]; + if (byLanguage != nil) + break; + } + if (byLanguage == nil) + byLanguage = [services objectForKey: @"default"]; + service = [byLanguage objectForKey: serviceItem]; + + if (service == nil) + return NO; /* No matching service. */ + + port = [service objectForKey: @"NSPortName"]; + timeout = [service objectForKey: @"NSTimeout"]; + if (timeout && [timeout floatValue] > 100) + { + seconds = [timeout floatValue] / 1000.0; + } + else + { + seconds = 30.0; + } + finishBy = [NSDate dateWithTimeIntervalSinceNow: seconds]; + appPath = [service objectForKey: @"ServicePath"]; + userData = [service objectForKey: @"NSUserData"]; + message = [service objectForKey: @"NSMessage"]; + selName = [message stringByAppendingString: @":userData:error:"]; + msgSel = NSSelectorFromString(selName); + + /* + * If there is no selector - we need to generate one with the + * appropriate types. + */ + if (msgSel == 0) + { + NSMethodSignature *sig; + const char *name; + const char *type; + + sig = [NSMethodSignature signatureWithObjCTypes: "v@:@@^@"]; + type = [sig methodType]; + name = [selName cString]; + msgSel = sel_register_typed_name(name, type); + } + + provider = [NSConnection rootProxyForConnectionWithRegisteredName: port + host: @""]; + if (provider == nil) + { + if ([[NSWorkspace sharedWorkspace] launchApplication: appPath] == NO) + { + return NO; /* Unable to launch. */ + } + + provider = [NSConnection rootProxyForConnectionWithRegisteredName: port + host: @""]; + while (provider == nil && [finishBy timeIntervalSinceNow] > 1.0) + { + NSRunLoop *loop = [NSRunLoop currentRunLoop]; + NSDate *next; + + [NSTimer scheduledTimerWithTimeInterval: 1.0 + invocation: nil + repeats: NO]; + next = [NSDate dateWithTimeIntervalSinceNow: 5.0]; + [loop runUntilDate: next]; + provider = [NSConnection + rootProxyForConnectionWithRegisteredName: port + host: @""]; + } + } + + if (provider == nil) + { + return NO; /* Unable to contact. */ + } + connection = [(NSDistantObject*)provider connectionForProxy]; + seconds = [finishBy timeIntervalSinceNow]; + [connection setRequestTimeout: seconds]; + [connection setReplyTimeout: seconds]; + + msgImp = get_imp(fastClass(provider), msgSel); + NS_DURING + { + (*msgImp)(provider, msgSel, pboard, userData, &error); + } + NS_HANDLER + { + [NSException raise: NSPasteboardCommunicationException + format: @"%s", [[localException reason] cString]]; + } + NS_ENDHANDLER + + if (error != nil) + { + NSLog(error); + return NO; + } + + return YES; +} diff --git a/Source/NSWorkspace.m b/Source/NSWorkspace.m index 61b84e4d3..3c75b719d 100644 --- a/Source/NSWorkspace.m +++ b/Source/NSWorkspace.m @@ -7,6 +7,8 @@ Author: Scott Christley Date: 1996 + Implementation: Richard Frith-Macdonald + Date: 1998 This file is part of the GNUstep GUI Library. @@ -28,8 +30,74 @@ #include #include +#include +#include +#include +#include +#include -@implementation NSWorkspace +#define stringify_it(X) #X +#define prog_path(X,Y) \ + stringify_it(X) "/Tools/" GNUSTEP_TARGET_DIR "/" LIBRARY_COMBO Y + +static NSDictionary *allServices = nil; +static NSDictionary *applications = nil; + +NSDictionary* +GSAllServicesDictionary() +{ + if (allServices == nil) + [[NSWorkspace sharedWorkspace] findApplications]; + return allServices; +} + +NSDictionary* +GSApplicationsDictionary() +{ + if (applications == nil) + [[NSWorkspace sharedWorkspace] findApplications]; + return applications; +} + +void +NSUpdateDynamicServices() +{ + [[NSWorkspace sharedWorkspace] findApplications]; +} + +@implementation NSWorkspace + +static NSWorkspace *sharedWorkspace = nil; +static NSNotificationCenter *workspaceCenter = nil; +static BOOL userDefaultsChanged = NO; + +static NSString *cacheName = @".GNUstepServices"; +static NSString *servicesPath = nil; + +static NSString* gnustep_target_dir = +#ifdef GNUSTEP_TARGET_DIR + @GNUSTEP_TARGET_DIR; +#else + nil; +#endif +static NSString* gnustep_target_cpu = +#ifdef GNUSTEP_TARGET_CPU + @GNUSTEP_TARGET_CPU; +#else + nil; +#endif +static NSString* gnustep_target_os = +#ifdef GNUSTEP_TARGET_OS + @GNUSTEP_TARGET_OS; +#else + nil; +#endif +static NSString* library_combo = +#ifdef LIBRARY_COMBO + @LIBRARY_COMBO; +#else + nil; +#endif // // Class methods @@ -38,22 +106,96 @@ { if (self == [NSWorkspace class]) { + static BOOL beenHere; + NSDictionary *env; + // Initial version [self setVersion:1]; + + [gnustep_global_lock lock]; + if (beenHere == YES) + { + [gnustep_global_lock unlock]; + return; + } + + beenHere = YES; + + workspaceCenter = [NSNotificationCenter new]; + env = [[NSProcessInfo processInfo] environment]; + if (env) + { + NSString *str; + + str = [env objectForKey: @"GNUSTEP_USER_ROOT"]; + if (str == nil) + str = [NSString stringWithFormat: @"%@/GNUstep", NSHomeDirectory()]; + str = [str stringByAppendingPathComponent: cacheName]; + servicesPath = [str retain]; + + if ((str = [env objectForKey: @"GNUSTEP_TARGET_DIR"]) != nil) + gnustep_target_dir = [str retain]; + else if ((str = [env objectForKey: @"GNUSTEP_HOST_DIR"]) != nil) + gnustep_target_dir = [str retain]; + + if ((str = [env objectForKey: @"GNUSTEP_TARGET_CPU"]) != nil) + gnustep_target_cpu = [str retain]; + else if ((str = [env objectForKey: @"GNUSTEP_HOST_CPU"]) != nil) + gnustep_target_cpu = [str retain]; + + if ((str = [env objectForKey: @"GNUSTEP_TARGET_OS"]) != nil) + gnustep_target_os = [str retain]; + else if ((str = [env objectForKey: @"GNUSTEP_HOST_OS"]) != nil) + gnustep_target_os = [str retain]; + + if ((str = [env objectForKey: @"LIBRARY_COMBO"]) != nil) + library_combo = [str retain]; + + [gnustep_global_lock unlock]; + } } } ++ (id) allocWithZone: (NSZone*)zone +{ + [NSException raise: NSInvalidArgumentException + format: @"You may not allocate a workspace directly"]; + return nil; +} + // // Creating a Workspace // + (NSWorkspace *)sharedWorkspace { - return nil; + if (sharedWorkspace == nil) + { + [gnustep_global_lock lock]; + if (sharedWorkspace == nil) + { + sharedWorkspace = + (NSWorkspace*)NSAllocateObject(self, 0, NSDefaultMallocZone()); + } + [gnustep_global_lock unlock]; + } + return sharedWorkspace; } // // Instance methods // +- (void) dealloc +{ + [NSException raise: NSInvalidArgumentException + format: @"Attempt to call dealloc for shared worksapace"]; +} + +- (id) init +{ + [NSException raise: NSInvalidArgumentException + format: @"Attempt to call init for shared worksapace"]; + return nil; +} // // Opening Files @@ -65,8 +207,8 @@ - (BOOL)openFile:(NSString *)fullPath fromImage:(NSImage *)anImage -at:(NSPoint)point - inView:(NSView *)aView + at:(NSPoint)point + inView:(NSView *)aView { return NO; } @@ -79,7 +221,7 @@ at:(NSPoint)point - (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName -andDeactivate:(BOOL)flag + andDeactivate:(BOOL)flag { return NO; } @@ -94,9 +236,9 @@ andDeactivate:(BOOL)flag // - (BOOL)performFileOperation:(NSString *)operation source:(NSString *)source -destination:(NSString *)destination - files:(NSArray *)files -tag:(int *)tag + destination:(NSString *)destination + files:(NSArray *)files + tag:(int *)tag { return NO; } @@ -112,22 +254,37 @@ inFileViewerRootedAtPath:(NSString *)rootFullpath // - (NSString *)fullPathForApplication:(NSString *)appName { + NSString *last = [appName lastPathComponent]; + + if (applications == nil) + NSUpdateDynamicServices(); + + if ([appName isEqual: last]) + { + NSString *ext = [appName pathExtension]; + + if (ext == nil) + { + appName = [appName stringByAppendingPathExtension: @"app"]; + } + return [applications objectForKey: appName]; + } return nil; } - (BOOL)getFileSystemInfoForPath:(NSString *)fullPath isRemovable:(BOOL *)removableFlag -isWritable:(BOOL *)writableFlag - isUnmountable:(BOOL *)unmountableFlag -description:(NSString **)description - type:(NSString **)fileSystemType + isWritable:(BOOL *)writableFlag + isUnmountable:(BOOL *)unmountableFlag + description:(NSString **)description + type:(NSString **)fileSystemType { return NO; } - (BOOL)getInfoForFile:(NSString *)fullPath application:(NSString **)appName -type:(NSString **)type + type:(NSString **)type { return NO; } @@ -162,7 +319,20 @@ type:(NSString **)type // Updating Registered Services and File Types // - (void)findApplications -{} +{ + NSData *data; + NSDictionary *newServices; + NSDictionary *dict; + + system(prog_path(GNUSTEP_INSTALL_PREFIX, "/make_services")); + + data = [NSData dataWithContentsOfFile: servicesPath]; + newServices = [NSDeserializer deserializePropertyListFromData: data + mutableContainers: NO]; + ASSIGN(allServices, newServices); + dict = [newServices objectForKey: @"Applications"]; + ASSIGN(applications, dict); +} // // Launching and Manipulating Applications @@ -172,14 +342,59 @@ type:(NSString **)type - (BOOL)launchApplication:(NSString *)appName { - return NO; + return [self launchApplication: appName + showIcon: YES + autolaunch: NO]; } - (BOOL)launchApplication:(NSString *)appName showIcon:(BOOL)showIcon -autolaunch:(BOOL)autolaunch + autolaunch:(BOOL)autolaunch { - return NO; + NSArray *args; + NSTask *task; + NSString *path; + NSString *file; + NSDictionary *info; + + if (appName == nil) + return NO; + + 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) + return NO; + + file = [path stringByAppendingPathComponent: @"Resources/Info-gnustep.plist"]; + info = [NSDictionary dictionaryWithContentsOfFile: file]; + file = [info objectForKey: @"NSExecutable"]; + if (file == nil) + { + file = appName; + } + path = [path stringByAppendingPathComponent: gnustep_target_dir]; + path = [path stringByAppendingPathComponent: library_combo]; + path = [path stringByAppendingPathComponent: appName]; + + args = [NSArray arrayWithObjects: nil]; + task = [NSTask launchedTaskWithLaunchPath: path + arguments: args]; + + return YES; } // @@ -211,18 +426,22 @@ autolaunch:(BOOL)autolaunch // - (NSNotificationCenter *)notificationCenter { - return nil; + return workspaceCenter; } // // Tracking Changes to the User Defaults Database // - (void)noteUserDefaultsChanged -{} +{ + userDefaultsChanged = YES; +} - (BOOL)userDefaultsChanged { - return NO; + BOOL hasChanged = userDefaultsChanged; + userDefaultsChanged = NO; + return hasChanged; } // @@ -230,7 +449,7 @@ autolaunch:(BOOL)autolaunch // - (void)slideImage:(NSImage *)image from:(NSPoint)fromPoint -to:(NSPoint)toPoint + to:(NSPoint)toPoint {} //