Re: Relaunching an application
Re: Relaunching an application
- Subject: Re: Relaunching an application
- From: "Steven Degutis" <email@hidden>
- Date: Mon, 3 Mar 2008 19:48:26 -0600
I've come up with an applucation design that works better than my
previous suggestion of psuedo-polling launchedApplications. Rather,
the relaunch application subscribes to NSWorkspace's notification
center, and waits until it gaurantees that its owner-Application has
terminated. If you want the entire program plus a demo program which
uses this, go to:
http://they.dontexist.org/relaunch.zip (source is included, plus a
universal binary of the demo in action, feel free to use it all you
want)
Here is the entire code for relaunch.app:
#import <Cocoa/Cocoa.h>
@interface tizzy : NSObject {
NSString *appPath;
}
- (void) gotQuitMessage:(NSNotification*)theNotification;
@end
#import "tizzy.h"
@implementation tizzy
// in the .nib this object must be included (though feel free to
delete the NSWindow in there)
// though im sure theres non-GUI workarounds, too
- (id) init { // create the appPath which we are waiting for to quit
if (self = [super init]) {
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:@selector(gotQuitMessage:)
name:NSWorkspaceDidTerminateApplicationNotification object:nil];
appPath = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0];
// we are relaunching whatever application this one lies inside of
// so we use a loop to get rid of everything except BigApp.app in this:
// BigApp.app/Contents/Resources/relauncher.app/Contents/MacOS/relauncher
at least)
int i; for (i = 0; i < 6; i++) appPath = [appPath
stringByDeletingLastPathComponent]; (
[appPath retain];
}
return self;
}
// when we get the notification, relaunch the app at appPath and quit this one!
// unfortunately, i still cant figure out how to give focus to that
"parent" application.
- (void) gotQuitMessage:(NSNotification*)theNotification {
NSString *theQuittingApp = [[theNotification userInfo]
valueForKey:@"NSApplicationPath"];
if ([appPath isEqualToString:theQuittingApp]) {
[[NSWorkspace sharedWorkspace] launchApplication:appPath];
[NSApp terminate:self];
}
}
@end
On Mon, Mar 3, 2008 at 4:22 PM, Michael Ash <email@hidden> wrote:
> On Mon, Mar 3, 2008 at 2:43 PM, Steven Degutis <email@hidden> wrote:
> > Perhaps a small application like relaunch.app could be imbedded into
> > your relaunchable application, where all it pretty much does is serve
> > as a buffer by relaunching your application reliably (through Cocoa
> > methods) after your app calls it the same way you mentioned above.
> >
> > [[NSWorkspace sharedWorkspace] launchApplication:relauncherExecutablePath];
> > [NSApp terminate:self];
> >
> > Then the relaunch.app program uses a method which calls itself
> > continuously (like a loop that wont make your app unresponsive), which
> > does a check to see if the original app is still running using
> > NSWorkspace's -launchedApplications, and only after it sees your app
> > end, then it will run the app again and terminate itself. This ensures
> > that your app opens only after it ends first. And doing this would be
> > quite easy, using two methods, -awakeFromNib and your custom method
> > -hasAppEnded. The former would launch the second one immediately, and
> > do nothing else, and the second one would do the check, and at the
> > end, if it is still running (hasnt quit and run the new app) it would
> > launch itself with [self performSelector:@selector(hasAppEnded)
> > withObject:nil afterDelay:1.0]; or something. This is what I would do
> > anyway. 1.0 might be too long or too short for a real application,
> > though.
>
> The best way is to write a little program like this (error checking
> removed for brevity, typed in mail client, caveat emptor):
>
> int main(int argc, char **argv)
> {
> char dummy;
> read(STDIN_FILENO, &dummy, 1);
>
> [NSAutoreleasePool new];
> NSURL *url = [NSURL fileURLWithPath:[NSString
> stringWithUTF8String:argv[1]]];
> LSOpenCFURLRef((CFURLRef)url, NULL);
>
> return 0;
> }
>
> Then invoke it using an NSTask in the main app:
>
> NSTask *task = [[NSTask alloc] init];
> [task setLaunchPath:pathToHelper];
> [task setArguments:[NSArray arrayWithObject:[[NSBundle mainBundle]
> bundlePath]]];
> [task setStandardInput:[NSPipe pipe]];
> [task launch];
>
> And then quit the app. The subtask will block in the read waiting for
> data on the pipe which will never come. When your app terminates, the
> write end of the pipe closes, unblocking the read in the subtask. The
> subtask then relaunches your app using the URL you gave it as a
> parameter. It's fast, easy to use, and requires no polling or messy
> shell scripts.
>
> Mike
>
>
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden