Changes to allow clean app termination even when multiple copies of the

same app are running.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@21788 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2005-10-09 06:39:08 +00:00
parent b5c8c6000c
commit bc81c42dab
6 changed files with 258 additions and 56 deletions

View file

@ -1,3 +1,15 @@
2005-10-09 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSServicesManager.m: Improve handling of port registration
to ensure each application listens on a weel known port and the port
name is readable. If multiple copies of an app are running, name
the extra copies AppCopy1 AppCoppy2 etc.
* Source/NSWorkspace.m: Use advertised port name for the app name so
that other apps can contact it.
* Tools/gclose.m: Triavial utility ... counterpart for gopen ...
close doen an application.
* Tools/GNUmakefile: build gclose
2005-10-08 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSWorkspace.m: Provide private method to post a notification

View file

@ -61,6 +61,7 @@
NSMutableSet *_allDisabled;
NSMutableDictionary *_allServices;
NSTimer *_timer;
NSString *_port;
}
+ (GSServicesManager*) newWithApplication: (NSApplication*)app;
+ (GSServicesManager*) manager;
@ -78,6 +79,7 @@
- (NSString*) item2title: (id<NSMenuItem>)item;
- (void) loadServices;
- (NSDictionary*) menuServices;
- (NSString*) port;
- (void) rebuildServices;
- (void) rebuildServicesMenu;
- (void) registerAsServiceProvider;

View file

@ -120,38 +120,64 @@ NSUnregisterServicesProvider(NSString *name)
void
NSRegisterServicesProvider(id provider, NSString *name)
{
NSPortNameServer *ns;
id namedPort;
if ([name length] == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"NSRegisterServicesProvider() no name provided"];
}
if (provider == nil)
{
[NSException raise: NSInvalidArgumentException
format: @"NSRegisterServicesProvider() no provider"];
}
if (servicesProvider == provider && [providerName isEqual: name])
{
return; // Already registered.
}
ns = [NSPortNameServer systemDefaultPortNameServer];
namedPort = [ns portForName: name];
if ([listenerConnection receivePort] == namedPort)
{
[ns removePortForName: name];
namedPort = nil;
}
if (namedPort != nil)
{
[NSException raise: NSInvalidArgumentException
format: @"NSRegisterServicesProvider() %@ already in use",
name];
}
if (listenerConnection != nil)
{
/*
* Ensure there is no previous listener and nothing else using
* the given port name.
*/
[[NSPortNameServer systemDefaultPortNameServer] removePortForName: name];
[[NSNotificationCenter defaultCenter]
removeObserver: [GSListener class]
name: NSConnectionDidDieNotification
object: listenerConnection];
DESTROY(listenerConnection);
}
if (name != nil && provider != nil)
listenerConnection = [NSConnection newRegisteringAtName: name
withRootObject: [GSListener listener]];
if (listenerConnection != nil)
{
listenerConnection = [NSConnection newRegisteringAtName: name
withRootObject: [GSListener listener]];
if (listenerConnection != nil)
{
RETAIN(listenerConnection);
[[NSNotificationCenter defaultCenter]
addObserver: [GSListener class]
selector: @selector(connectionBecameInvalid:)
name: NSConnectionDidDieNotification
object: listenerConnection];
}
else
{
[NSException raise: NSGenericException
format: @"unable to register %@", name];
}
RETAIN(listenerConnection);
[[NSNotificationCenter defaultCenter]
addObserver: [GSListener class]
selector: @selector(connectionBecameInvalid:)
name: NSConnectionDidDieNotification
object: listenerConnection];
}
else
{
[NSException raise: NSGenericException
format: @"unable to register %@", name];
}
ASSIGN(servicesProvider, provider);
ASSIGN(providerName, name);
}
@ -222,12 +248,15 @@ NSRegisterServicesProvider(id provider, NSString *name)
+ (void) setServicesProvider: (id)anObject
{
NSString *appName;
if (servicesProvider != anObject)
{
appName = [[NSProcessInfo processInfo] processName];
NSRegisterServicesProvider(anObject, appName);
NSString *port = [[GSServicesManager manager] port];
if (port == nil)
{
port = [[NSProcessInfo processInfo] processName];
}
NSRegisterServicesProvider(anObject, port);
}
}
@ -446,7 +475,7 @@ static NSString *disabledName = @".GNUstepDisabled";
{
manager->_application = app;
}
return manager;
return RETAIN(manager);
}
manager = [GSServicesManager alloc];
@ -787,6 +816,16 @@ static NSString *disabledName = @".GNUstepDisabled";
return _title2info;
}
/**
* Returns the 'port' of this application ... this is the name the
* application is registered under so that other apps can connect to
* it to use any services it provides.
*/
- (NSString*) port
{
return _port;
}
- (void) rebuildServices
{
NSDictionary *services;
@ -1006,47 +1045,89 @@ static NSString *disabledName = @".GNUstepDisabled";
@"Application may already be running with this name",
@"Continue", @"Abort", @"Rename");
if (result == NSAlertDefaultReturn || result == NSAlertOtherReturn)
{
if (result == NSAlertOtherReturn)
appName = [[NSProcessInfo processInfo] globallyUniqueString];
[[NSPortNameServer systemDefaultPortNameServer]
removePortForName: appName];
NS_DURING
{
NSRegisterServicesProvider(self, appName);
registered = YES;
}
NS_HANDLER
{
registered = NO;
NSLog(@"Warning: Could not register application due to "
@"exception: %@\n", [localException reason]);
}
NS_ENDHANDLER
if (result == NSAlertOtherReturn)
{
unsigned count = 0;
/*
* Something is seriously wrong - we can't talk to the
* nameserver, so all interaction with the workspace manager
* and/or other applications will fail.
* Give the user a chance to keep on going anyway.
* Try to rename self as a copy.
*/
while (registered == NO && ++count < 100)
{
NSString *tmp;
tmp = [appName stringByAppendingFormat: @"Copy%d", count];
NS_DURING
{
NSRegisterServicesProvider(self, tmp);
registered = YES;
appName = tmp;
}
NS_HANDLER
{
registered = NO;
}
NS_ENDHANDLER
}
}
if (result == NSAlertDefaultReturn)
{
id app;
/*
* Try to terminate the other app and run using normal name.
*/
app = [NSConnection rootProxyForConnectionWithRegisteredName: appName
host: @""];
NS_DURING
{
[app terminate: nil];
}
NS_HANDLER
{
/* maybe it terminated. */
}
NS_ENDHANDLER
NS_DURING
{
NSRegisterServicesProvider(self, appName);
registered = YES;
}
NS_HANDLER
{
registered = NO;
}
NS_ENDHANDLER
}
if (result == NSAlertDefaultReturn || result == NSAlertOtherReturn)
{
if (registered == NO)
{
/*
* Something is seriously wrong - we can't talk to the
* nameserver, so all interaction with the workspace manager
* and/or other applications will fail.
* Give the user a chance to keep on going anyway.
*/
result = NSRunAlertPanel(appName,
@"Unable to register application with ANY name",
@"Abort", @"Continue", nil);
if (result == NSAlertDefaultReturn)
registered = YES;
{
registered = YES;
}
}
}
if (registered == NO)
[[NSApplication sharedApplication] terminate: self];
{
[[NSApplication sharedApplication] terminate: self];
}
}
ASSIGN(_port, appName);
}
/**

View file

@ -1153,9 +1153,10 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
- (NSDictionary*) activeApplication
{
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
NSString *appName = [[GSServicesManager manager] port];
return [NSDictionary dictionaryWithObjectsAndKeys:
[processInfo processName], @"NSApplicationName",
appName, @"NSApplicationName",
[[NSBundle mainBundle] bundlePath], @"NSApplicationPath",
[NSNumber numberWithInt: [processInfo processIdentifier]],
@"NSApplicationProcessIdentifier",

View file

@ -29,10 +29,12 @@ include ../config.make
include ../Version
SUBPROJECTS = $(BUILD_GSND)
TOOL_NAME = make_services set_show_service gopen
TOOL_NAME = make_services set_show_service gopen gclose
SERVICE_NAME = GSspell
# The source files to be compiled
gclose_OBJC_FILES = gclose.m
gopen_OBJC_FILES = gopen.m
make_services_OBJC_FILES = make_services.m

104
Tools/gclose.m Normal file
View file

@ -0,0 +1,104 @@
/* This tool opens the appropriate application from the command line
based on what type of file is being accessed.
Copyright (C) 2001 Free Software Foundation, Inc.
Written by: Gregory Casamento <greg_casamento@yahoo.com>
Created: November 2001
This file is part of the GNUstep Project
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <Foundation/NSArray.h>
#include <Foundation/NSConnection.h>
#include <Foundation/NSHost.h>
#include <Foundation/NSString.h>
#include <Foundation/NSProcessInfo.h>
#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSException.h>
#include <Foundation/NSUserDefaults.h>
#include <AppKit/NSApplication.h>
int
main(int argc, char** argv, char **env_c)
{
CREATE_AUTORELEASE_POOL(pool);
NSEnumerator *argEnumerator = nil;
NSString *arg = nil;
NSString *host = nil;
#ifdef GS_PASS_ARGUMENTS
[NSProcessInfo initializeWithArguments:argv count:argc environment:env_c];
#endif
argEnumerator = [[[NSProcessInfo processInfo] arguments] objectEnumerator];
host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"];
[argEnumerator nextObject]; // skip the first element, which is empty.
while ((arg = [argEnumerator nextObject]) != nil)
{
if ([arg isEqualToString: @"-NSHost"])
{
// skip since this is handled above...
arg = [argEnumerator nextObject];
}
else // no option specified
{
NS_DURING
{
NSString *port;
id app;
if (host == nil)
{
host = @"";
}
else
{
NSHost *h = [NSHost hostWithName: host];
if ([h isEqual: [NSHost currentHost]] == YES)
{
host = @"";
}
}
port = [[arg lastPathComponent] stringByDeletingPathExtension];
/*
* Try to contact a running application.
*/
app = [NSConnection
rootProxyForConnectionWithRegisteredName: port host: host];
NS_DURING
{
[app terminate: nil];
}
NS_HANDLER
{
/* maybe it terminated. */
}
NS_ENDHANDLER
}
NS_HANDLER
{
NSLog(@"Exception while attempting to terminate %@ - %@: %@",
arg, [localException name], [localException reason]);
}
NS_ENDHANDLER
}
}
RELEASE(pool);
exit(EXIT_SUCCESS);
}