diff --git a/bin/mac/relaunch b/bin/mac/relaunch new file mode 100755 index 000000000000..f66c7b8b54f3 Binary files /dev/null and b/bin/mac/relaunch differ diff --git a/native/macrestarter/relaunch.m b/native/macrestarter/relaunch.m new file mode 100644 index 000000000000..4b596895a9fa --- /dev/null +++ b/native/macrestarter/relaunch.m @@ -0,0 +1,66 @@ +// gcc -Wall -arch i386 -arch ppc -mmacosx-version-min=10.4 -Os -framework AppKit -o relaunch relaunch.m + +#import + +@interface TerminationListener : NSObject +{ + const char *executablePath; + pid_t parentProcessId; +} + +- (void) relaunch; + +@end + +@implementation TerminationListener + +- (id) initWithExecutablePath:(const char *)execPath parentProcessId:(pid_t)ppid +{ + self = [super init]; + if (self != nil) { + executablePath = execPath; + parentProcessId = ppid; + + // This adds the input source required by the run loop + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidTerminate:) name:NSWorkspaceDidTerminateApplicationNotification object:nil]; + if (getppid() == 1) { + // ppid is launchd (1) => parent terminated already + [self relaunch]; + } + } + return self; +} + +- (void) applicationDidTerminate:(NSNotification *)notification +{ + if (parentProcessId == [[[notification userInfo] valueForKey:@"NSApplicationProcessIdentifier"] intValue]) { + // parent just terminated + [self relaunch]; + } +} + +- (void) relaunch +{ + // [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(actualLaunch) userInfo:nil repeats:NO]; + // NSDate *future = [NSDate dateWithTimeIntervalSinceNow: 5.0 ]; + // [NSThread sleepUntilDate:future]; + + [[NSWorkspace sharedWorkspace] launchApplication:[NSString stringWithUTF8String:executablePath]]; + exit(0); +} + +@end + +int main (int argc, const char * argv[]) +{ + if (argc != 3) return EXIT_FAILURE; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [[[TerminationListener alloc] initWithExecutablePath:argv[1] parentProcessId:atoi(argv[2])] autorelease]; + [[NSApplication sharedApplication] run]; + + [pool release]; + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 1e156a0ec12c..2ce9771ad5ed 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -1090,16 +1090,19 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application } public boolean isRestartCapable() { - return SystemInfo.isWindows; + return SystemInfo.isWindows || SystemInfo.isMacOSSnowLeopard; } public void restart() { - if (SystemInfo.isWindows) { - Win32Restarter.restart(); + if (SystemInfo.isWindows) { + Win32Restarter.restart(); + } + else if (SystemInfo.isMacOSSnowLeopard) { + MacRestarter.restart(); } else { - exit(); - } + exit(); + } } public boolean isSaving() { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java new file mode 100644 index 000000000000..73dbc2f8d58d --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.application.impl; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationEx; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.mac.foundation.Foundation; +import com.intellij.ui.mac.foundation.ID; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +/** + * User: spLeaner + */ +public class MacRestarter { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.application.impl.MacRestarter"); + + private MacRestarter() { + } + + @SuppressWarnings({"RedundantArrayCreation"}) + public static void restart() { + final ID autoReleasePool = Foundation.invoke("NSAutoreleasePool", "new"); + final ID app = Foundation.invoke("NSRunningApplication", "currentApplication"); + final ID executableURL = Foundation.invoke(app, Foundation.createSelector("executableURL")); + final ID stringURL = Foundation.invoke(executableURL, Foundation.createSelector("absoluteString")); + + try { + final String executablePath = Foundation.toStringViaUTF8(stringURL); + final URL url = new URL(executablePath); + final String path = url.getPath(); + if (path.contains(".app")) { + final int appIndex = path.indexOf(".app"); + final String appPath = path.substring(0, appIndex + 4); + final String relaunchPath = path.substring(0, path.lastIndexOf('/')) + "/../../bin/relaunch"; + final long processId = Foundation.invoke(app, Foundation.createSelector("processIdentifier")).longValue(); + + final ID args = Foundation.invoke(Foundation.getClass("NSArray"), Foundation.createSelector("arrayWithObjects:"), + new Object[]{Foundation.cfString(appPath), Foundation.cfString(String.valueOf(processId))}); + + Foundation.invoke(Foundation.getClass("NSTask"), Foundation.createSelector("launchedTaskWithLaunchPath:arguments:"), + Foundation.cfString(relaunchPath), args); + } + } + catch (MalformedURLException e) { + LOG.error(e); + } + finally { + Foundation.invoke(autoReleasePool, Foundation.createSelector("release")); + ((ApplicationEx)ApplicationManager.getApplication()).exit(true); + } + } +}