IDEA will restart automatically from now on Mac OS X Snow Leo
authorAlexey Pegov <alexey.pegov@jetbrains.com>
Wed, 16 Jun 2010 15:22:15 +0000 (19:22 +0400)
committerAlexey Pegov <alexey.pegov@jetbrains.com>
Wed, 16 Jun 2010 15:22:15 +0000 (19:22 +0400)
bin/mac/relaunch [new file with mode: 0755]
native/macrestarter/relaunch.m [new file with mode: 0644]
platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java
platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java [new file with mode: 0644]

diff --git a/bin/mac/relaunch b/bin/mac/relaunch
new file mode 100755 (executable)
index 0000000..f66c7b8
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 (file)
index 0000000..4b59689
--- /dev/null
@@ -0,0 +1,66 @@
+// gcc -Wall -arch i386 -arch ppc -mmacosx-version-min=10.4 -Os -framework AppKit -o relaunch relaunch.m
+
+#import <AppKit/AppKit.h>
+
+@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
index 1e156a0ec12c311d6a11c202082342d0365e80f5..2ce9771ad5edb654de92059d0510aa5204f6f2e9 100644 (file)
@@ -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 (file)
index 0000000..73dbc2f
--- /dev/null
@@ -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);
+    }
+  }
+}