diff --git a/bin/win/jumplistbridge.dll b/bin/win/jumplistbridge.dll new file mode 100644 index 000000000000..611dd62b41d4 Binary files /dev/null and b/bin/win/jumplistbridge.dll differ diff --git a/bin/win/jumplistbridge64.dll b/bin/win/jumplistbridge64.dll new file mode 100644 index 000000000000..fad8c52f521f Binary files /dev/null and b/bin/win/jumplistbridge64.dll differ diff --git a/platform/platform-impl/src/com/intellij/idea/SocketLock.java b/platform/platform-impl/src/com/intellij/idea/SocketLock.java index 149de23f8e46..ceddbd18d97f 100644 --- a/platform/platform-impl/src/com/intellij/idea/SocketLock.java +++ b/platform/platform-impl/src/com/intellij/idea/SocketLock.java @@ -79,6 +79,12 @@ public class SocketLock { } } + private volatile int acquiredPort = -1; + + public synchronized int getAcquiredPort () { + return acquiredPort; + } + public synchronized ActivateStatus lock(String path, boolean markPort, String... args) { if (LOG.isDebugEnabled()) { LOG.debug("enter: lock(path='" + path + "')"); @@ -194,6 +200,7 @@ public class SocketLock { mySocket = new ServerSocket(i, 50, InetAddress.getByName("127.0.0.1")); port = i; + acquiredPort = port; break; } catch (IOException e) { diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java index 7b01b1874695..5aed4ed72cd7 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java @@ -76,6 +76,10 @@ public class StartupUtil { void start(boolean newConfigFolder); } + public synchronized static int getAcquiredPort() { + return ourLock.getAcquiredPort(); + } + static void prepareAndStart(String[] args, AppStarter appStarter) { boolean newConfigFolder = false; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/SystemDock.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/SystemDock.java index ab3a415a01b3..d8d0344b21e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/SystemDock.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/SystemDock.java @@ -17,6 +17,7 @@ package com.intellij.openapi.wm.impl; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.mac.MacDockDelegate; +import com.intellij.ui.win.WinDockDelegate; /** * @author Denis Fokin @@ -28,6 +29,8 @@ public class SystemDock { static { if (SystemInfo.isMac) { delegate = MacDockDelegate.getInstance(); + } else if (SystemInfo.isWin7OrNewer) { + delegate = WinDockDelegate.getInstance(); } } @@ -36,7 +39,7 @@ public class SystemDock { delegate.updateRecentProjectsMenu(); } - public static interface Delegate { + public interface Delegate { void updateRecentProjectsMenu(); } } diff --git a/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java b/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java new file mode 100644 index 000000000000..2d620b1a750d --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java @@ -0,0 +1,91 @@ +/* + * Copyright 2000-2013 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.ui.win; + +import com.intellij.openapi.application.PathManager; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.concurrent.atomic.AtomicBoolean; + +public class RecentTasks { + + private static AtomicBoolean initialiazed = + new AtomicBoolean(false); + + private final static WeakReference openerThread = + new WeakReference(Thread.currentThread()); + + static { + final String libraryName = (System.getProperty("sun.arch.data.model").contains("64"))? + "jumplistbridge64.dll": + "jumplistbridge.dll"; + + final String binPath = PathManager.getBinPath(); + final String communityBinPath = PathManager.getHomePath() + File.separatorChar + "community" + File.separatorChar + "bin"; + + final String [] libraryPaths = { + binPath, + binPath + File.separatorChar + "win", + communityBinPath, + communityBinPath + File.separatorChar + "win", + }; + + for (String path : libraryPaths) { + final File candidate = new File(path + File.separatorChar + libraryName); + if (candidate.exists()) { + System.load(candidate.getAbsolutePath()); + break; + } + } + } + + private synchronized static void init() { + if (initialiazed.get()) return; + + initialize("JetBrains.JetBrainsNativeAppID"); + initialiazed.set(true); + } + + /** + * Com initialization should be invoked once per process. + * All invocation should be made from the same thread. + * @param applicationId + */ + native private static void initialize (String applicationId); + native private static void addTaskNative (String location, String args, String description); + native private static void clearNative(); + + public synchronized static void clear() { + init(); + checkThread(); + clearNative(); + } + + public synchronized static void addTask(File location, String args, String description) { + init(); + checkThread(); + if (!location.exists()) throw new IllegalArgumentException("Task should be a valid path"); + addTaskNative(location.getAbsolutePath(), args, description); + } + + private static void checkThread() { + Thread t = openerThread.get(); + if (t == null || !t.equals(Thread.currentThread())) + throw new RuntimeException("This class has to be used from the same thread"); + } +} + diff --git a/platform/platform-impl/src/com/intellij/ui/win/SocketControlHelper.java b/platform/platform-impl/src/com/intellij/ui/win/SocketControlHelper.java new file mode 100644 index 000000000000..84372bf5c9cd --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/win/SocketControlHelper.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2013 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.ui.win; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * @author Denis Fokin + */ +public class SocketControlHelper { + + private static final String ACTIVATE_COMMAND = "activate "; + + /* + * args[0] - socket of controlled IDE + * args[1] - project path + */ + public static void main(String[] args) { + final int portNumber = Integer.parseInt(args[0]); + final String pathToProject = new File(args[1]).getAbsolutePath(); + final InetAddress lba = getLoopbackAddress(); + + try { + Socket socket = new Socket(lba, portNumber); + socket.setSoTimeout(300); + DataInputStream in = new DataInputStream(socket.getInputStream()); + DataOutputStream out = new DataOutputStream(socket.getOutputStream()); + try { + + out.writeUTF(ACTIVATE_COMMAND + new File(".").getAbsolutePath() + "\0" + pathToProject); + out.flush(); + String response = in.readUTF(); + if (response.equals("ok")) { + System.err.println("Activated."); + } + } finally { + in.close(); + out.close(); + socket.close(); + } + } catch (IOException ignored) {} + + System.err.println("Activation failed"); + } + + private static InetAddress getLoopbackAddress() { + InetAddress returnValue = null; + try { + returnValue = InetAddress.getByName("127.0.0.1"); + } catch (UnknownHostException uhe) { + uhe.printStackTrace(); + } + return returnValue; + } +} diff --git a/platform/platform-impl/src/com/intellij/ui/win/WinDockDelegate.java b/platform/platform-impl/src/com/intellij/ui/win/WinDockDelegate.java new file mode 100644 index 000000000000..951154f909ff --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/win/WinDockDelegate.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2013 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.ui.win; + +import com.intellij.ide.RecentProjectsManagerBase; +import com.intellij.ide.ReopenProjectAction; +import com.intellij.idea.StartupUtil; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.wm.impl.SystemDock; +import java.io.File; + +/** + * @author Denis Fokin + */ +public class WinDockDelegate implements SystemDock.Delegate { + + private static final Logger LOG = Logger.getInstance("#com.intellij.ui.win.WinDockDelegate"); + + private static final String javaExe = System.getProperty("java.home") + File.separatorChar + "bin" + File.separatorChar + "javaw.exe"; + private static final String argsToExecute = new StringBuilder(" -classpath ").append(PathManager.getJarPathForClass(SocketControlHelper.class)). + append(" com.intellij.ui.win.SocketControlHelper ").append(StartupUtil.getAcquiredPort()) + .append(" ").toString(); + + private static boolean initialized = false; + private static final SystemDock.Delegate instance = new WinDockDelegate(); + + private WinDockDelegate() {} + + public void updateRecentProjectsMenu () { + final AnAction[] recentProjectActions = RecentProjectsManagerBase.getInstance().getRecentProjectsActions(false); + RecentTasks.clear(); + for (final AnAction action : recentProjectActions) { + ReopenProjectAction rpa = ((ReopenProjectAction)action); + RecentTasks.addTask(new File(javaExe), argsToExecute + rpa.getProjectPath(), rpa.getProjectName()); + } + } + synchronized public static SystemDock.Delegate getInstance() { + if (!initialized) { + initialized = true; + } + return instance; + } +}