Showing posts with label Launcher. Show all posts
Showing posts with label Launcher. Show all posts

Friday, May 28, 2010

Opening files in Eclipse from the command line

I ran a query to see all the bugs fixed in the Eclipse Platform in 3.6; it is a long list (4309 and counting). Felipe gets credit for the oldest bug fixed (raised in 2001), but in a close second is bug 4922 (raised only a day later).

This bug is about opening files in eclipse from the command line. Fixing it required a coordinated effort between Platform UI, SWT, and the Equinox launcher. A lot of the credit for what was done goes to Kevin Barnes.

This post is an effort to explain some of the technical details of what is going here.

On the Mac...: On the mac all we do is handle the apple event "kAEOpenDocuments", most of the rest of this post doesn't apply to the mac.

Windows and GTK... Everything below applies to Windows and GTK, though there are some differences in the implementation details.

On Motif... Sorry, this doesn't work on motif.

The Launcher

Everything starts in the eclipse launcher. We added a few new command line options:
  • --launcher.openFile : obvious enough, specifies the file we want to open.
  • --launcher.defaultAction : less obvious, specifies the action to take when the launcher is started without any '-' arguments on the command line. Currently the only support value is "openFile".
  • --launcher.timeout : a timeout value for how long we should spend trying to communicate with an already running eclipse before we give up and just open a new eclipse instance. Default is 60 (seconds).
The first argument is obvious enough, open the specified file in eclipse.
eclipse --launcher.openFile myFile.txt
This is great, but it is a bit much to type on the command line and is not quite enough to make everyone happy. We introduced the "default action" argument. This goes in the eclipse.ini file, the value should be "openFile":
...
-showsplash
org.eclipse.platform
--launcher.defaultAction
openFile
-vmargs
-Xms256m
-Xmx768m
This tells the launcher that if it is called with a command line that only contains arguments that don't start with "-", then those arguments should be treated as if they followed "--launcher.openFile".
eclipse myFile.txt
This is the kind of command line the launcher will receive on windows when you double click a file that is associated with eclipse, or you select files and choose "Open With" or "Send To" Eclipse.

Relative paths will be resolved first against the current working directory, and second against the eclipse program directory.

Talking to SWT

The launcher talks to SWT through the use of a hidden window. The launcher and SWT both need to agree on the name of this window. This allows the launcher to find an already running eclipse and tell it to open the file. Any RCP application will need to ensure they get this right for things to work.

The launcher bases this on its "official name". The official name can be set with the -name argument. If -name is not set, then the official name is derived from the launcher executable, the extension is removed and the first letter is capitalized: rcp.exe becomes Rcp.

SWT bases this on the value set with the Display.setAppName() function. Normally, this is set by the Workbench when it creates the display and the value is the "appName" taken from the product extension point.

Listening to SWT

To take advantage of this, an RCP Application will need to register a listener for the SWT.OpenDocument event. It should register this listener before calling PlatformUI.createAndRunWorkbench so that the listener is in place before the workbench starts running the event loop.

The event loop will start running while the splash screen is still up, so events may arrive before the workbench is ready to actually open an editor for the file. This means that the listener should save the file paths it gets from the OpenDocument events so they can be opened at some later time. WorkbenchAdvisor#eventLoopIdle can be a good place to check for saved open file events.

Implementation details

Here is an overview of the flow of events in the launcher when processing --launcher.openFile on windows.
  1. Get the Official Name. As mentioned above, this is the "-name" argument, or derived from the executable name. For this explanation, we will be using "OfficialName".

  2. Create and lock a mutex named "SWT_Mutex_OfficialName".
    • If multiple files are selected and opened on windows, then a seperate eclipse process will be created for each one. The mutex allows us to ensure only one eclipse instance is actually started.
    • One process will win the race to acquire the mutex, at this point, there will be no eclipse instance running that has the SWT window available. This process will start normally and eventually create the SWT window at which point it will release the mutex.
    • All the other processes wait trying to acquire the mutex, once the original process releases it, they will be able to find the SWT window and post their open file message there.
    • Each process only waits for --launcher.timeout seconds (default 60 seconds) before giving up and just starting its own full eclipse instance.


  3. Find the window named "SWT_Window_OfficialName"
    • If no such window exists, we are the first eclipse instance. In this case, we set a timer to look again later and then proceed with starting eclipse.
    • The timer fires every second for --launcher.timeout seconds.
    • If we don't find the SWT window before the timeout (perhaps it took too long for the workbench to create the display), then we will be unable to open the file.


  4. Send a message to the SWT window
    • Once we've found the SWT window, we create a custom message named "SWT_OPENDOC". We send this message with wParam & lParam specifying a shared memory id.
    • We write to the name of the file to open into shared memory, and when SWT receives the SWT_OPENDOC message, it uses that id to read the shared memory.
    • The launcher has long used shared memory on all platforms for the splash screen, restarts and exit messages.
    • Once SWT reads the file name from shared memory, it posts its own SWT.OpenDocument event.
On GTK, things happen in a similar manner with a few differences:
  1. We use semaphores.
    • Semaphores are not cleaned up automatically if the process exits unexpectedly. So we try to hold the semaphore for as short a time as possible and we install SIGINT and SIGQUIT signal handlers for the time we hold the semaphore.
    • The launcher creates a hidden GTK window named SWT_Window_LauncherOfficalName which is used in the same way as the mutex on windows. This lets us avoid holding the semaphore for an extended time while the first eclipse process starts up.

  2. We use a property instead of a message.
    • The property is named org.eclipse.swt.filePath.message.
    • The value is a colon separate list of file paths to open. Shared memory is not used like it is on windows.

Thursday, September 13, 2007

Eclipse launcher is losing its head

The Eclipse launcher has always required a graphics library (ie GTK, Motif) to show error messages and display the splash screen. It can't even start if the library is not found. This is a problem for people who have headless Eclipse applications that run in places without such luxuries.

I raised a bug to track this issue. Though I should point out that bug is incorrect in its description of the launcher's linking: the launcher is dynamically linked to the graphics libraries, (not statically linked as the bug says). The problem is that these dependencies are resolved at loadtime, not runtime. The fix is to load the graphics libraries at runtime using dlopen and lookup all the functions we need to call using dlsym.

I have created launchers for GTK and Motif that do this and attached them in bugzilla. These changes require more testing before I release them to CVS. People should try them out and give feedback on the bug.


One thing to note is that the Motif version is using a DT_RPATH tag to help find the libXm.so.2 library that ships on linux in the root of Eclipse. Most of what I've read suggests this is obsolete and not a good idea, so that will probably change.

Wednesday, May 02, 2007

Eclipse and the Console

Starting in the warmup to 3.3M7 there is a second launcher on Windows: eclipsec.exe.

The Eclipse launchers in 3.3 have had issues with various aspects of the console on Windows. See some bugs: 146807, 167310, 168726, and 173962.

All of our problems came from the fact that the eclipse.exe was linked as a UI application and not a console application. In 3.2, the console behaviour was tied to using java.exe instead of javaw.exe, but starting in 3.3 M5, the vm is loaded in the eclipse process using the JNI Invocation API.

So just like javaw/java, we now have eclipse/eclipsec. Eclipsec.exe is linked as a console application so that the OS handles allocating the console for us. Using eclipsec.exe does not imply any default arguments, so you still need to specify things like -console and -consoleLog.

Monday, April 23, 2007

Equinox launcher & Swing

The equinox launcher starts the Java VM using the JNI invocation API. Because we are such good friends with SWT (and also because it is easier) the VM was always started on the first thread. This turns out not to be so good when you want to run Swing on the Mac. There was a conversation about it over on EclipseZone.

So I fixed the bug (181698) today by adding a new option to the launcher "--launcher.secondThread". Use it if you want swing to work. This option can be compared to the -XstartOnFirstThread for the java launcher.

Tuesday, December 19, 2006

Equinox Launchers and SWT splash screens

The Eclipse Integration build I20061219-1300 has the new Equinox launchers in it. Read all about them on the wiki, and in my email to the Eclipse-dev mailing list.

This will allow for some potentially cool things to happen in the splash screen.

I have been slowly going crazy getting this stuff working on all the different platforms. There are still problems on linux.x86_64, linux.ppc, and aix.ppc.