mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-06-01 13:11:55 +00:00
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:
parent
b4c8d9c768
commit
d3fe0c73a5
6 changed files with 258 additions and 56 deletions
12
ChangeLog
12
ChangeLog
|
@ -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>
|
2005-10-08 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/NSWorkspace.m: Provide private method to post a notification
|
* Source/NSWorkspace.m: Provide private method to post a notification
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
NSMutableSet *_allDisabled;
|
NSMutableSet *_allDisabled;
|
||||||
NSMutableDictionary *_allServices;
|
NSMutableDictionary *_allServices;
|
||||||
NSTimer *_timer;
|
NSTimer *_timer;
|
||||||
|
NSString *_port;
|
||||||
}
|
}
|
||||||
+ (GSServicesManager*) newWithApplication: (NSApplication*)app;
|
+ (GSServicesManager*) newWithApplication: (NSApplication*)app;
|
||||||
+ (GSServicesManager*) manager;
|
+ (GSServicesManager*) manager;
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
- (NSString*) item2title: (id<NSMenuItem>)item;
|
- (NSString*) item2title: (id<NSMenuItem>)item;
|
||||||
- (void) loadServices;
|
- (void) loadServices;
|
||||||
- (NSDictionary*) menuServices;
|
- (NSDictionary*) menuServices;
|
||||||
|
- (NSString*) port;
|
||||||
- (void) rebuildServices;
|
- (void) rebuildServices;
|
||||||
- (void) rebuildServicesMenu;
|
- (void) rebuildServicesMenu;
|
||||||
- (void) registerAsServiceProvider;
|
- (void) registerAsServiceProvider;
|
||||||
|
|
|
@ -120,38 +120,64 @@ NSUnregisterServicesProvider(NSString *name)
|
||||||
void
|
void
|
||||||
NSRegisterServicesProvider(id provider, NSString *name)
|
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)
|
if (listenerConnection != nil)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Ensure there is no previous listener and nothing else using
|
|
||||||
* the given port name.
|
|
||||||
*/
|
|
||||||
[[NSPortNameServer systemDefaultPortNameServer] removePortForName: name];
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
removeObserver: [GSListener class]
|
removeObserver: [GSListener class]
|
||||||
name: NSConnectionDidDieNotification
|
name: NSConnectionDidDieNotification
|
||||||
object: listenerConnection];
|
object: listenerConnection];
|
||||||
DESTROY(listenerConnection);
|
DESTROY(listenerConnection);
|
||||||
}
|
}
|
||||||
if (name != nil && provider != nil)
|
|
||||||
|
listenerConnection = [NSConnection newRegisteringAtName: name
|
||||||
|
withRootObject: [GSListener listener]];
|
||||||
|
if (listenerConnection != nil)
|
||||||
{
|
{
|
||||||
listenerConnection = [NSConnection newRegisteringAtName: name
|
RETAIN(listenerConnection);
|
||||||
withRootObject: [GSListener listener]];
|
[[NSNotificationCenter defaultCenter]
|
||||||
if (listenerConnection != nil)
|
addObserver: [GSListener class]
|
||||||
{
|
selector: @selector(connectionBecameInvalid:)
|
||||||
RETAIN(listenerConnection);
|
name: NSConnectionDidDieNotification
|
||||||
[[NSNotificationCenter defaultCenter]
|
object: listenerConnection];
|
||||||
addObserver: [GSListener class]
|
|
||||||
selector: @selector(connectionBecameInvalid:)
|
|
||||||
name: NSConnectionDidDieNotification
|
|
||||||
object: listenerConnection];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[NSException raise: NSGenericException
|
|
||||||
format: @"unable to register %@", name];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[NSException raise: NSGenericException
|
||||||
|
format: @"unable to register %@", name];
|
||||||
|
}
|
||||||
|
|
||||||
ASSIGN(servicesProvider, provider);
|
ASSIGN(servicesProvider, provider);
|
||||||
ASSIGN(providerName, name);
|
ASSIGN(providerName, name);
|
||||||
}
|
}
|
||||||
|
@ -222,12 +248,15 @@ NSRegisterServicesProvider(id provider, NSString *name)
|
||||||
|
|
||||||
+ (void) setServicesProvider: (id)anObject
|
+ (void) setServicesProvider: (id)anObject
|
||||||
{
|
{
|
||||||
NSString *appName;
|
|
||||||
|
|
||||||
if (servicesProvider != anObject)
|
if (servicesProvider != anObject)
|
||||||
{
|
{
|
||||||
appName = [[NSProcessInfo processInfo] processName];
|
NSString *port = [[GSServicesManager manager] port];
|
||||||
NSRegisterServicesProvider(anObject, appName);
|
|
||||||
|
if (port == nil)
|
||||||
|
{
|
||||||
|
port = [[NSProcessInfo processInfo] processName];
|
||||||
|
}
|
||||||
|
NSRegisterServicesProvider(anObject, port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,7 +475,7 @@ static NSString *disabledName = @".GNUstepDisabled";
|
||||||
{
|
{
|
||||||
manager->_application = app;
|
manager->_application = app;
|
||||||
}
|
}
|
||||||
return manager;
|
return RETAIN(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
manager = [GSServicesManager alloc];
|
manager = [GSServicesManager alloc];
|
||||||
|
@ -787,6 +816,16 @@ static NSString *disabledName = @".GNUstepDisabled";
|
||||||
return _title2info;
|
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
|
- (void) rebuildServices
|
||||||
{
|
{
|
||||||
NSDictionary *services;
|
NSDictionary *services;
|
||||||
|
@ -1006,47 +1045,89 @@ static NSString *disabledName = @".GNUstepDisabled";
|
||||||
@"Application may already be running with this name",
|
@"Application may already be running with this name",
|
||||||
@"Continue", @"Abort", @"Rename");
|
@"Continue", @"Abort", @"Rename");
|
||||||
|
|
||||||
if (result == NSAlertDefaultReturn || result == NSAlertOtherReturn)
|
if (result == NSAlertOtherReturn)
|
||||||
{
|
{
|
||||||
if (result == NSAlertOtherReturn)
|
unsigned count = 0;
|
||||||
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
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Something is seriously wrong - we can't talk to the
|
* Try to rename self as a copy.
|
||||||
* nameserver, so all interaction with the workspace manager
|
|
||||||
* and/or other applications will fail.
|
|
||||||
* Give the user a chance to keep on going anyway.
|
|
||||||
*/
|
*/
|
||||||
|
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)
|
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,
|
result = NSRunAlertPanel(appName,
|
||||||
@"Unable to register application with ANY name",
|
@"Unable to register application with ANY name",
|
||||||
@"Abort", @"Continue", nil);
|
@"Abort", @"Continue", nil);
|
||||||
|
|
||||||
if (result == NSAlertDefaultReturn)
|
if (result == NSAlertDefaultReturn)
|
||||||
registered = YES;
|
{
|
||||||
|
registered = YES;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (registered == NO)
|
if (registered == NO)
|
||||||
[[NSApplication sharedApplication] terminate: self];
|
{
|
||||||
|
[[NSApplication sharedApplication] terminate: self];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ASSIGN(_port, appName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1153,9 +1153,10 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
|
||||||
- (NSDictionary*) activeApplication
|
- (NSDictionary*) activeApplication
|
||||||
{
|
{
|
||||||
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
|
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
|
||||||
|
NSString *appName = [[GSServicesManager manager] port];
|
||||||
|
|
||||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[processInfo processName], @"NSApplicationName",
|
appName, @"NSApplicationName",
|
||||||
[[NSBundle mainBundle] bundlePath], @"NSApplicationPath",
|
[[NSBundle mainBundle] bundlePath], @"NSApplicationPath",
|
||||||
[NSNumber numberWithInt: [processInfo processIdentifier]],
|
[NSNumber numberWithInt: [processInfo processIdentifier]],
|
||||||
@"NSApplicationProcessIdentifier",
|
@"NSApplicationProcessIdentifier",
|
||||||
|
|
|
@ -29,10 +29,12 @@ include ../config.make
|
||||||
include ../Version
|
include ../Version
|
||||||
|
|
||||||
SUBPROJECTS = $(BUILD_GSND)
|
SUBPROJECTS = $(BUILD_GSND)
|
||||||
TOOL_NAME = make_services set_show_service gopen
|
TOOL_NAME = make_services set_show_service gopen gclose
|
||||||
SERVICE_NAME = GSspell
|
SERVICE_NAME = GSspell
|
||||||
|
|
||||||
# The source files to be compiled
|
# The source files to be compiled
|
||||||
|
gclose_OBJC_FILES = gclose.m
|
||||||
|
|
||||||
gopen_OBJC_FILES = gopen.m
|
gopen_OBJC_FILES = gopen.m
|
||||||
|
|
||||||
make_services_OBJC_FILES = make_services.m
|
make_services_OBJC_FILES = make_services.m
|
||||||
|
|
104
Tools/gclose.m
Normal file
104
Tools/gclose.m
Normal 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);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue