Updates for keeping track of launched/active applications when there is no

workspace manager process.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@22371 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2006-01-27 12:44:01 +00:00
parent 584ab86e01
commit b83359120b
3 changed files with 255 additions and 52 deletions

View file

@ -1,3 +1,11 @@
2006-01-27 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSApplication.m: pass more informative user info in
notifications.
* Source/NSWorkspace.m: implement filesystem based fallback mechanisms
for tracking launched and active appplications when there is no
workspace manager process to do it.
2006-01-22 Fred Kiefer <FredKiefer@gmx.de> 2006-01-22 Fred Kiefer <FredKiefer@gmx.de>
* Source/NSPopupButtonCell.m (-synchronizeTitleAndSelectedItem): * Source/NSPopupButtonCell.m (-synchronizeTitleAndSelectedItem):

View file

@ -341,6 +341,7 @@ struct _NSModalSession {
@interface NSApplication (Private) @interface NSApplication (Private)
- _appIconInit; - _appIconInit;
- (NSDictionary*) _notificationUserInfo;
- (void) _openDocument: (NSString*)name; - (void) _openDocument: (NSString*)name;
- (void) _windowDidBecomeKey: (NSNotification*) notification; - (void) _windowDidBecomeKey: (NSNotification*) notification;
- (void) _windowDidBecomeMain: (NSNotification*) notification; - (void) _windowDidBecomeMain: (NSNotification*) notification;
@ -913,7 +914,6 @@ static NSSize scaledIconSizeForSize(NSSize imageSize)
NSString *mainModelFile; NSString *mainModelFile;
NSString *appIconFile; NSString *appIconFile;
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
NSString *filePath; NSString *filePath;
NSArray *windows_list; NSArray *windows_list;
unsigned count; unsigned count;
@ -1039,11 +1039,11 @@ static NSSize scaledIconSizeForSize(NSSize imageSize)
[self terminate: self]; [self terminate: self];
} }
else if (![defs boolForKey: @"autolaunch"] else if (![defs boolForKey: @"autolaunch"]
&& [_delegate respondsToSelector: && [_delegate respondsToSelector:
@selector(applicationShouldOpenUntitledFile:)] @selector(applicationShouldOpenUntitledFile:)]
&& ([_delegate applicationShouldOpenUntitledFile: self]) && ([_delegate applicationShouldOpenUntitledFile: self])
&& [_delegate respondsToSelector: && [_delegate respondsToSelector:
@selector(applicationOpenUntitledFile:)]) @selector(applicationOpenUntitledFile:)])
{ {
[_delegate applicationOpenUntitledFile: self]; [_delegate applicationOpenUntitledFile: self];
} }
@ -1053,14 +1053,21 @@ static NSSize scaledIconSizeForSize(NSSize imageSize)
object: self]; object: self];
NS_DURING NS_DURING
[[workspace notificationCenter] {
postNotificationName: NSWorkspaceDidLaunchApplicationNotification NSWorkspace *workspace;
object: workspace
userInfo: [workspace activeApplication]]; workspace = [NSWorkspace sharedWorkspace];
[[workspace notificationCenter]
postNotificationName: NSWorkspaceDidLaunchApplicationNotification
object: workspace
userInfo: [self _notificationUserInfo]];
}
NS_HANDLER NS_HANDLER
NSLog (_(@"Problem during launch app notification: %@"), {
[localException reason]); NSLog (_(@"Problem during launch app notification: %@"),
[localException raise]; [localException reason]);
[localException raise];
}
NS_ENDHANDLER NS_ENDHANDLER
} }
@ -1168,7 +1175,8 @@ static NSSize scaledIconSizeForSize(NSSize imageSize)
} }
[nc postNotificationName: NSApplicationDidBecomeActiveNotification [nc postNotificationName: NSApplicationDidBecomeActiveNotification
object: self]; object: self
userInfo: [self _notificationUserInfo]];
} }
} }
@ -1230,7 +1238,8 @@ static NSSize scaledIconSizeForSize(NSSize imageSize)
} }
[nc postNotificationName: NSApplicationDidResignActiveNotification [nc postNotificationName: NSApplicationDidResignActiveNotification
object: self]; object: self
userInfo: [self _notificationUserInfo]];
} }
} }
@ -3046,7 +3055,7 @@ image.</p><p>See Also: -applicationIconImage</p>
{ {
if (shouldTerminate) if (shouldTerminate)
{ {
NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
[nc postNotificationName: NSApplicationWillTerminateNotification [nc postNotificationName: NSApplicationWillTerminateNotification
object: self]; object: self];
@ -3063,7 +3072,7 @@ image.</p><p>See Also: -applicationIconImage</p>
[[workspace notificationCenter] [[workspace notificationCenter]
postNotificationName: NSWorkspaceDidTerminateApplicationNotification postNotificationName: NSWorkspaceDidTerminateApplicationNotification
object: workspace object: workspace
userInfo: [workspace activeApplication]]; userInfo: [self _notificationUserInfo]];
/* Destroy the main run loop pool (this also destroys any nested /* Destroy the main run loop pool (this also destroys any nested
pools which might have been created inside this one). */ pools which might have been created inside this one). */
@ -3286,6 +3295,21 @@ image.</p><p>See Also: -applicationIconImage</p>
return self; return self;
} }
- (NSDictionary*) _notificationUserInfo
{
NSNumber *processIdentifier;
NSDictionary *userInfo;
processIdentifier = [NSNumber numberWithInt:
[[NSProcessInfo processInfo] processIdentifier]];
userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
[(GSServicesManager*)_listener port], @"NSApplicationName",
[[NSBundle mainBundle] bundlePath], @"NSApplicationPath",
processIdentifier, @"NSApplicationPprocessIdentifier",
nil];
return userInfo;
}
- (void) _openDocument: (NSString*)filePath - (void) _openDocument: (NSString*)filePath
{ {
[_listener application: self openFile: filePath]; [_listener application: self openFile: filePath];

View file

@ -45,6 +45,7 @@
#include <Foundation/NSDictionary.h> #include <Foundation/NSDictionary.h>
#include <Foundation/NSHost.h> #include <Foundation/NSHost.h>
#include <Foundation/NSLock.h> #include <Foundation/NSLock.h>
#include <Foundation/NSDistributedLock.h>
#include <Foundation/NSPathUtilities.h> #include <Foundation/NSPathUtilities.h>
#include <Foundation/NSUserDefaults.h> #include <Foundation/NSUserDefaults.h>
#include <Foundation/NSTask.h> #include <Foundation/NSTask.h>
@ -78,10 +79,128 @@ static NSImage *unknownTool = nil;
static NSString *GSWorkspaceNotification = @"GSWorkspaceNotification"; static NSString *GSWorkspaceNotification = @"GSWorkspaceNotification";
static NSArray *GSLaunched(NSDictionary *info, NSString *mode)
{
static NSString *path = nil;
static NSDistributedLock *lock = nil;
NSMutableArray *apps = nil;
BOOL toBecomeActive;
BOOL toResignActive;
BOOL toLaunch;
BOOL toTerminate;
toBecomeActive = [mode isEqualToString:
NSApplicationDidBecomeActiveNotification];
toResignActive = [mode isEqualToString:
NSApplicationDidResignActiveNotification];
toLaunch = [mode isEqualToString:
NSWorkspaceDidLaunchApplicationNotification];
toTerminate = [mode isEqualToString:
NSWorkspaceDidTerminateApplicationNotification];
if (path == nil)
{
path = [NSTemporaryDirectory()
stringByAppendingPathComponent: @"GSLaunchedApplications"];
RETAIN(path);
lock = [[NSDistributedLock alloc] initWithPath:
[path stringByAppendingPathExtension: @"lock"]];
}
if ([lock tryLock] == NO)
{
if ([[lock lockDate] timeIntervalSinceNow] < -20.0)
{
NS_DURING
{
[lock breakLock];
}
NS_HANDLER
{
NSLog(@"Unable to break lock %@ ... %@", lock, localException);
}
NS_ENDHANDLER
}
if ([lock tryLock] == NO)
{
NSLog(@"Unable to obtain lock %@", lock);
return nil;
}
}
if ([[NSFileManager defaultManager] isReadableFileAtPath: path] == YES)
{
apps = [NSMutableArray arrayWithContentsOfFile: path];
}
if (apps == nil)
{
apps = [NSMutableArray arrayWithCapacity: 1];
}
if (info != nil)
{
NSString *name = [info objectForKey: @"NSApplicationName"];
unsigned i = [apps count];
BOOL modified = NO;
BOOL wasActive = NO;
while (i-- > 0)
{
NSDictionary *oldInfo;
NSString *oldName;
oldInfo = [apps objectAtIndex: i];
oldName = [oldInfo objectForKey: @"NSApplicationName"];
if ([name isEqualToString: oldName] == YES)
{
if ([oldInfo objectForKey: @"GSApplicationActive"] != nil)
{
wasActive = YES;
}
[apps removeObjectAtIndex: i];
modified = YES;
}
else if (toBecomeActive == YES
&& [oldInfo objectForKey: @"GSApplicationActive"] != nil)
{
NSMutableDictionary *m = [oldInfo mutableCopy];
[m removeObjectForKey: @"GSApplicationActive"];
[apps replaceObjectAtIndex: i withObject: m];
RELEASE(m);
modified = YES;
}
}
if (toTerminate == NO)
{
if (toBecomeActive == YES
|| (toResignActive == NO && wasActive == YES))
{
NSMutableDictionary *m = [info mutableCopy];
[m setObject: @"YES" forKey: @"GSApplicationActive"];
info = AUTORELEASE(m);
}
[apps addObject: info];
modified = YES;
}
if (modified == YES)
{
[apps writeToFile: path atomically: YES];
}
}
[lock unlock];
return apps;
}
@interface _GSWorkspaceCenter: NSNotificationCenter @interface _GSWorkspaceCenter: NSNotificationCenter
{ {
NSDistributedNotificationCenter *remote; NSDistributedNotificationCenter *remote;
} }
- (void) _handleApplicationNotification: (NSNotification*)aNotification;
- (void) _handleRemoteNotification: (NSNotification*)aNotification; - (void) _handleRemoteNotification: (NSNotification*)aNotification;
- (void) _postLocal: (NSString*)name userInfo: (NSDictionary*)info; - (void) _postLocal: (NSString*)name userInfo: (NSDictionary*)info;
@end @end
@ -90,6 +209,14 @@ static NSString *GSWorkspaceNotification = @"GSWorkspaceNotification";
- (void) dealloc - (void) dealloc
{ {
[[NSNotificationCenter defaultCenter]
removeObserver: self
name: NSApplicationDidBecomeActiveNotification
object: nil];
[[NSNotificationCenter defaultCenter]
removeObserver: self
name: NSApplicationDidResignActiveNotification
object: nil];
[remote removeObserver: self name: nil object: GSWorkspaceNotification]; [remote removeObserver: self name: nil object: GSWorkspaceNotification];
RELEASE(remote); RELEASE(remote);
[super dealloc]; [super dealloc];
@ -100,6 +227,17 @@ static NSString *GSWorkspaceNotification = @"GSWorkspaceNotification";
self = [super init]; self = [super init];
if (self != nil) if (self != nil)
{ {
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_handleApplicationNotification:)
name: NSApplicationDidResignActiveNotification
object: nil];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_handleApplicationNotification:)
name: NSApplicationDidBecomeActiveNotification
object: nil];
remote = RETAIN([NSDistributedNotificationCenter defaultCenter]); remote = RETAIN([NSDistributedNotificationCenter defaultCenter]);
NS_DURING NS_DURING
{ {
@ -135,10 +273,21 @@ static NSString *GSWorkspaceNotification = @"GSWorkspaceNotification";
- (void) postNotification: (NSNotification*)aNotification - (void) postNotification: (NSNotification*)aNotification
{ {
NSNotification *rem; NSNotification *rem;
NSString *name = [aNotification name];
NSDictionary *info = [aNotification userInfo];
rem = [NSNotification notificationWithName: [aNotification name] if ([name isEqual: NSWorkspaceDidTerminateApplicationNotification] == YES)
{
GSLaunched(info, name);
}
if ([name isEqual: NSWorkspaceDidLaunchApplicationNotification] == YES)
{
GSLaunched(info, name);
}
rem = [NSNotification notificationWithName: name
object: GSWorkspaceNotification object: GSWorkspaceNotification
userInfo: [aNotification userInfo]]; userInfo: info];
NS_DURING NS_DURING
{ {
[remote postNotification: rem]; [remote postNotification: rem];
@ -176,6 +325,17 @@ static NSString *GSWorkspaceNotification = @"GSWorkspaceNotification";
userInfo: info]]; userInfo: info]];
} }
- (void) _handleApplicationNotification: (NSNotification*)aNotification
{
NSString *name = [aNotification name];
if ([name isEqualToString: NSApplicationDidBecomeActiveNotification] == YES
|| [name isEqualToString: NSApplicationDidResignActiveNotification] == YES)
{
GSLaunched([aNotification userInfo], name);
}
}
/* /*
* Forward a notification from a remote application to observers in this * Forward a notification from a remote application to observers in this
* application. * application.
@ -215,7 +375,8 @@ static NSString *GSWorkspaceNotification = @"GSWorkspaceNotification";
// application communication // application communication
- (BOOL) _launchApplication: (NSString*)appName - (BOOL) _launchApplication: (NSString*)appName
arguments: (NSArray*)args; arguments: (NSArray*)args
locally: (BOOL)locally;
- (id) _connectApplication: (NSString*)appName; - (id) _connectApplication: (NSString*)appName;
- (id) _workspaceApplication; - (id) _workspaceApplication;
@ -517,7 +678,7 @@ static NSString *_rootPath = @"/";
NSArray *args; NSArray *args;
args = [NSArray arrayWithObjects: @"-GSFilePath", fullPath, nil]; args = [NSArray arrayWithObjects: @"-GSFilePath", fullPath, nil];
return [self _launchApplication: appName arguments: args]; return [self _launchApplication: appName arguments: args locally: NO];
} }
else else
{ {
@ -564,7 +725,7 @@ static NSString *_rootPath = @"/";
NSArray *args; NSArray *args;
args = [NSArray arrayWithObjects: @"-GSTempPath", fullPath, nil]; args = [NSArray arrayWithObjects: @"-GSTempPath", fullPath, nil];
return [self _launchApplication: appName arguments: args]; return [self _launchApplication: appName arguments: args locally: NO];
} }
else else
{ {
@ -1135,7 +1296,7 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
{ {
args = [NSArray arrayWithObjects: @"-autolaunch", @"YES", nil]; args = [NSArray arrayWithObjects: @"-autolaunch", @"YES", nil];
} }
return [self _launchApplication: appName arguments: args]; return [self _launchApplication: appName arguments: args locally: NO];
} }
else else
{ {
@ -1152,9 +1313,29 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
*/ */
- (NSDictionary*) activeApplication - (NSDictionary*) activeApplication
{ {
NSProcessInfo *processInfo = [NSProcessInfo processInfo]; NSProcessInfo *processInfo;
NSString *appName = [[GSServicesManager manager] port]; NSString *appName;
NSArray *apps = GSLaunched(nil, nil);
unsigned i = [apps count];
/*
* Try to find actrive app in launched applications.
*/
while (i-- > 0)
{
NSDictionary *info = [apps objectAtIndex: i];
if ([info objectForKey: @"GSApplicationActive"] != nil)
{
return info;
}
}
/*
* Should never get here ... but assume this is the active app.
*/
processInfo = [NSProcessInfo processInfo];
appName = [[GSServicesManager manager] port];
return [NSDictionary dictionaryWithObjectsAndKeys: return [NSDictionary dictionaryWithObjectsAndKeys:
appName, @"NSApplicationName", appName, @"NSApplicationName",
[[NSBundle mainBundle] bundlePath], @"NSApplicationPath", [[NSBundle mainBundle] bundlePath], @"NSApplicationPath",
@ -1164,24 +1345,14 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
} }
/** /**
* Returns an array listing all the applications know to have been * Returns an array listing all the applications known to have been
* launched. * launched. Each entry in the array is a dictionary providing
* the name, path and process identfier of an application.<br />
* NB. The contents of this array are not guaranteed to be up to date.
*/ */
- (NSArray*) launchedApplications - (NSArray*) launchedApplications
{ {
NSDictionary *dict; return GSLaunched(nil, nil);
NSString *app;
NSMutableArray *apps = [NSMutableArray array];
NSEnumerator *enumerator = [_launched keyEnumerator];
while ((app = [enumerator nextObject]) != nil)
{
dict = [NSDictionary dictionaryWithObject: app
forKey: @"NSApplicationName"];
[apps addObject: dict];
}
return apps;
} }
/* /*
@ -2071,19 +2242,21 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
} }
/** /**
* Launch an application ... if there is a workspace application, ask it * Launch an application ... if there is a workspace application and
* to perform the launch for us. Otherwise we try to launch the app * we have not been specifically asked to launch locally, ask the
* ourself as long as it is on the same host as we are. * workspace application 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.
*/ */
- (BOOL) _launchApplication: (NSString*)appName - (BOOL) _launchApplication: (NSString*)appName
arguments: (NSArray*)args arguments: (NSArray*)args
locally: (BOOL)locally
{ {
id app = nil; id app;
// app = [self _workspaceApplication]; if (locally == NO && (app = [self _workspaceApplication]) != nil)
if (app != nil)
{ {
return [app _launchApplication: appName arguments: args]; return [app _launchApplication: appName arguments: args locally: YES];
} }
else else
{ {
@ -2267,10 +2440,6 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
{ {
NSString *host; NSString *host;
/**
* We don't use -_launchApplication:arguents: here as that method
* calls -_workspaceApplication, and would cause recursion.
*/
host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"]; host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"];
if (host == nil) if (host == nil)
{ {
@ -2293,7 +2462,9 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
*/ */
if ([host isEqual: @""] == YES) if ([host isEqual: @""] == YES)
{ {
if ([self _launchApplication: appName arguments: nil] == YES) if ([self _launchApplication: appName
arguments: nil
locally: YES] == YES)
{ {
app = [self _connectApplication: appName]; app = [self _connectApplication: appName];
} }