| Summary: | [Widgets] Windows 7 Jump List items impose "standard" on arguments passed to new instance | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Product: | [Eclipse Project] Platform | Reporter: | Lukasz Milewski <lukasz.milewski> | ||||||||||
| Component: | SWT | Assignee: | Felipe Heidrich <eclipse.felipe> | ||||||||||
| Status: | RESOLVED FIXED | QA Contact: | |||||||||||
| Severity: | minor | ||||||||||||
| Priority: | P3 | CC: | chrriis, eclipse.felipe, markus.kell.r, mik.kersten, remy.suen, shawn.minto, Silenio_Quarti, skovatch | ||||||||||
| Version: | 3.6 | ||||||||||||
| Target Milestone: | 3.7 M6 | ||||||||||||
| Hardware: | PC | ||||||||||||
| OS: | Windows 7 | ||||||||||||
| Whiteboard: | |||||||||||||
| Attachments: |
|
||||||||||||
|
Description
Lukasz Milewski
Right now the jump list only works with the eclipse exe launcher. What are you passing to IShellLink::SetPath ? Actually it works with launcher I'm using (Jar2Exe Wizard), but I have to create a different way to pass arguments (using Windows native calls - if anyone is interested I can collaborate on that subject in different medium - blog or email) to application and already have created a set of arguments and don't really like the idea of relying of ID to determine which item was selected.
Here's a code I've added to TaskBar class, works for me, maybe worth streamlining.
if (item.getData("argument") != null) {
text = (String) item.getData("argument");
} else {
text = Display.LAUNCHER_PREFIX + Display.TASKBAR_EVENT + item.id;
}
That is very cool that you got jump list to work with Jar2Exe. I don't think I can add the setData() support you suggested (we are passed API freeze and jar2exe is not supported by eclipse.org), that said I'd like to help you. Silenio, can you think of anything ? Lukasz, is it possible for you to get Jar2Exe to send opendocuments messages to the swt message window (the same way eclipse.exe does) ? If you can get Jar2Exe to simulate what eclipse.exe you won't need to hack swt. Felipe, it is possible to adapt my code to use the "--launcher...." arguments (though probably will not do it and just compile SWT myself with my changes), but my goal with this issue was to raise awareness that this *API* (awesome if I had do reiterate) although made completely in SWT is very Eclipse centric/dependent, which in my case is not an option(my application uses only SWT). -=-=-=- As for Jar2Exe Wizard intergration, actually there's none ;-) All of my code is written purely in Java (almost, I use JNA), What I did is, mind it's Windows only: First instance 1) Create system-wide Mutex with application name 2) Main window handles WM_COPYDATA message Second instance 1) Look for Mutex, if found 2) Find previous main window 3) Send WM_COPYDATA to handle of previous main window Unfortunately I was forced to do that in Java (mutex and sending WM_COPYDATA) because Jar2Exe Wizard is not supporting that and it's not open source. Additionally I found that SWT is missing some of the required structures and methods to accomplish that, so I've used JNA for that. -=-=-=- Certainly I can wait for fix to this bug till next release (whether it's major or minor) and in the meantime can provide patch, either with additional (missing from my point of view) elements in OS and SWT classes to not use JNA anymore or without it. I see, You re-implemented in Java some of the work that eclipse.exe would do for you. But you changed the way the arguments are handled. Why did you change it ? Is our design wrong ? Or was it just too hard to duplicate all the work eclipse.exe is doing to make the code work. Could not argue with that, although when I worked on that particular thing in my application it was November (actually on December I've made breakthrough with memory allocation using JNA) and launcher didn't support that and frankly I was scared with proposal of using HTTP server for passing thru arguments between instances. Hinted, I've looked at launcher java code and native and must say my approach is much inferior to new Eclipse's just because JVM needs to launch to do the WinAPI magic between instances. Unfortunately for me Jar2Exe is not open-sources so I wasn't able to modify native launch. As for using Eclipse's launcher I'm not using it from two, important for me, reasons, one is I cannot bundle all jars into single exe file (I'm doing application that tries to be as much user friendly as possible and it even means providing one single exe file with couple dll files), inclusion of ini files and tampering that file can potentially render my application useless. Might suspect there are other developers that share my opinion on using Eclipse launcher (de facto is not part of the SWT, but Equinox). Felipe,
As Lukasz mentioned, this SWT API does not work for pure SWT applications. This is very annoying considering how great such feature is.
Currently:
- The exe cannot be an alternate exe.
- The arguments passed to that exe cannot be controlled.
A pure SWT application without a specific launcher ("javaw.exe") should be supported in which case the developer would like to pass "-cp <params> <MainClass>" or "-jar MainJar.jar".
Moreover, I have an application that launches another exe which contains the SWT code, so in case of a task item the first exe should be invoked.
I think the easiest would simply be to allow controlling the exe path and the full argument list that is used to create the Windows link. For example:
item.setData("executable", javaExePath);
item.setData("arguments", new String[] {"-jar", "MainJar.jar", "--link", "1"});
A null "executable" tells SWT to use the launching exe (90% of the use cases) but can be set if another launcher is to be used. This can then be a dedicated exe meant to handle all jump list links, etc.
Please let me know what you think!
(In reply to comment #7) > I think the easiest would simply be to allow controlling the exe path and the > full argument list that is used to create the Windows link. For example: > item.setData("executable", javaExePath); > item.setData("arguments", new String[] {"-jar", "MainJar.jar", "--link", > "1"}); > A null "executable" tells SWT to use the launching exe (90% of the use cases) > but can be set if another launcher is to be used. This can then be a dedicated > exe meant to handle all jump list links, etc. > Please let me know what you think! I am okay with that change. Silenio, do you see any problems ? I see no problem other than this is really Windows specific. All these extra datas attached to the item cannot be used in the cocoa implementation. The way cocoa handles tasks when the app is not running is quite different from Windows and for running apps there is nothing special needed. http://developer.apple.com/library/mac/#documentation/AppKit/Reference/NSDockTilePlugIn_Protocol/Reference/Reference.html We still have not find any way of implementing this feature on GTK (Gnome or KDE). So we do not know what would be necessary. Should we at least use a key that shows that the data is specific to Windows: item.setData("org.eclipse.swt.win32.executable", javaExePath); "org.eclipse.swt.win32.executable" is fine. Maybe there should be "taskbar" in the name too: "org.eclipse.swt.win32.taskbar.executable" "org.eclipse.swt.win32.taskbar.arguments" Maybe there should also be "org.eclipse.swt.win32.taskbar.ico" which when defined would prevent the auto-creation of the ".ico" file by specifying a place on disk where that icon can be found. (In reply to comment #10) > Maybe there should also be "org.eclipse.swt.win32.taskbar.ico" which when > defined would prevent the auto-creation of the ".ico" file by specifying a > place on disk where that icon can be found. The code that creates the default folder where the images are extracted runs before the first menu item is processed. Suppose all menu items have a "org.eclipse.swt.win32.taskbar.ico" set, then that default folder was created for nothing. Besides, who is responsible by creating the "org.eclipse.swt.win32.taskbar.ico" folders (the caller) ? > Suppose all menu items have a > "org.eclipse.swt.win32.taskbar.ico" set, then that default folder was created > for nothing. Indeed, but can't the code be adapted to only create the folder when the item is processed if that folder does not exist? > Besides, who is responsible by creating the > "org.eclipse.swt.win32.taskbar.ico" folders (the caller) ? If "org.eclipse.swt.win32.taskbar.ico" is defined, the developer has to make sure the file exists of course. This allows people to ship their application with their ico files (not a converted file) with all the resolutions and design they like. The developer has many strategies, like shipping their application as a tree containing the ico files, or they have a Windows installer that does the job, or the ico files are auto extracted from the JARs to an appdata subfolder, etc. The code that creates the default folder where the images are extracted runs before the first menu item is processed. Suppose all menu items have a "org.eclipse.swt.win32.taskbar.ico" set, then that default folder was created for nothing. Besides, who is responsible by creating the "org.eclipse.swt.win32.taskbar.ico" folders (the caller) ? Does anyone have the energy/time to make a patch for us ? That would be much appreciated. I'll be able to provide patch against Jump List. (In reply to comment #15) > I'll be able to provide patch against Jump List. Thaank you, please use the names Christopher suggested in comment 10. Created attachment 186943 [details]
TaskBar patch
Created attachment 186944 [details]
TaskBar patch
Previous patch required icon to be set on widget even when external image was set.
(In reply to comment #18) > Created attachment 186944 [details] > TaskBar patch Nice! > Previous patch required icon to be set on widget even when external image was > set. Yes, I was about to mention that and your updated code arrived :) I have a question though: what if an argument has a space in it? You seem to construct a single string containing all the arguments so shouldn't such case be escaped with double quotes (unless they are already present)? Something like: argsBuffer.append((args[i].indexOf(' ') >= 0? '"' + args[i] + '"': args[i]) + " "); > I have a question though: what if an argument has a space in it? You seem to
> construct a single string containing all the arguments so shouldn't such case
> be escaped with double quotes (unless they are already present)?
>
> Something like:
> argsBuffer.append((args[i].indexOf(' ') >= 0? '"' + args[i] + '"': args[i]) + "
> ");
Interesting point. I'll prepare new patch shortly with the change.
> Interesting point. I'll prepare new patch shortly with the change.
It would be good to test because I honestly don't know how jumplists behaves with spaces and double quotes :)
Correction to take into account already escaped strings:
argsBuffer.append((args[i].indexOf(' ') >= 0 && args[i].charAt(0) != '"'? '"' + args[i] + '"': args[i]) + " ");
(In reply to comment #21) > > Interesting point. I'll prepare new patch shortly with the change. > > It would be good to test because I honestly don't know how jumplists behaves > with spaces and double quotes :) I've planed to do that today and post patch/response soon, not sure if I make it by end of today ;-) Here's an example cod for the changes.
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TaskItem;
public class TestTaskBarChanges {
/**
* @param args
*/
public static void main(String[] args) {
final Display d = new Display();
final Shell shell = new Shell(d, SWT.SHELL_TRIM);
shell.setSize(250, 200);
shell.setText("TaskBar changes");
TaskItem item = d.getSystemTaskBar().getItem(null);
Menu menu = new Menu(shell, SWT.NONE);
MenuItem i = new MenuItem(menu, SWT.NONE);
i.setText("Program Files");
i.setData(SWT.TASKBAR_ITEM_EXECUTABLE, "c:\\windows\\explorer.exe");
i.setData(SWT.TASKBAR_ITEM_ARGUMENTS, new String[]{"c:\\program files\\"});
i.setData(SWT.TASKBAR_ITEM_ICON, "c:\\Alarm.ico");
item.setMenu(menu);
shell.open();
while (!shell.isDisposed()) {
if (!d.readAndDispatch())
d.sleep();
}
d.dispose();
}
}
Created attachment 187285 [details]
TaskBar patch
Created attachment 187286 [details]
TaskBar patch
Apologize for bugspam. This patch has a new feature I've accidentally found. When you provide exe file, dll file or ico file that has multiple icons you can use new data argument to specify index of ico file to use.
i.setData(SWT.TASKBAR_ITEM_ICON, "c:\\windows\\explorer.exe");
i.setData(SWT.TASKBAR_ITEM_ICON_INDEX, 1);
This will pick up second icon from explorer.exe
> Apologize for bugspam. No problem for me, I am very pleased with seeing progress. > you can use new data argument to specify index of ico file to use. Very good addition! Multiple icons in a single file are quite common indeed. Felipe, is there any hope to get this included in 3.7? (In reply to comment #26) > Felipe, is there any hope to get this included in 3.7? Sure thing, I'll work on it next week (once M5 is out). The one thing I will have to do is to remove from the patch the constants in SWT. We just can't have constants that are so windows-centric in the SWT class (which is suppose to be platform neutral). What I will do instead is write a F.A.Q entry explainging how to use this support: - Windows only - "Back door" for people who have knowledge in win32 to change the default behaviour Does that make sense to you ? My concern is: Most likely we will never be able to implement these constans anywhere but windows. For that reason, I rather not add them to SWT. > The one thing I will have to do is to remove from the patch the constants in
> SWT.
> Does that make sense to you ?
It makes perfect sense. In fact I had not noticed it was public and in the SWT class. Windows users who want to use these new features would have to know the string to use so I agree with you on the FAQ entry.
I released the code to HEAD:
Here is my test snippet:
package tests;
import java.util.Properties;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
public class TaskbarPlay3 {
public static void main(String[] args) {
String name = args.length > 0 ? args[0] : "Noname";
Display.setAppName("TaskbarPlay"+name);
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText(name);
Properties properties = System.getProperties();
String executable = properties.get("java.home") + "\\bin\\javaw.exe";
StringBuffer buffer = new StringBuffer();
buffer.append("-cp ");
buffer.append(properties.get("java.class.path"));
String libraryPath = (String)properties.get("java.library.path");
if (libraryPath != null) {
buffer.append(" -Djava.library.path=");
buffer.append(libraryPath);
}
buffer.append(" tests.TaskbarPlay3");
buffer.append(" TEST");
Menu menu = new Menu(shell, SWT.POP_UP);
MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
menuItem.setData("org.eclipse.swt.win32.taskbar.executable", executable);
menuItem.setData("org.eclipse.swt.win32.taskbar.arguments", buffer.toString());
menuItem.setData("org.eclipse.swt.win32.taskbar.icon", "C:\\windows\\system32\\shell32.dll");
menuItem.setData("org.eclipse.swt.win32.taskbar.icon.index", "4");
menuItem.setText("TEST");
TaskBar bar = display.getSystemTaskBar();
TaskItem item = bar.getItem(null);
item.setMenu(menu);
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}
Hi Felipe, > I released the code to HEAD: Very good! Welcome addition to SWT :) > Here is my test snippet: > String executable = properties.get("java.home") + "\\bin\\javaw.exe"; Is there a way to get the exe path of the running process with SWT API? That way, applications that do use a custom launcher would not have to fiddle to get the full path to their launcher and same for the ones without launchers (though they would have to do what you did with the Java params). > String libraryPath = (String)properties.get("java.library.path"); Does "swt.library.path" work? If so, shouldn't you also set it if defined? (In reply to comment #31) > Is there a way to get the exe path of the running process with SWT API? That > way, applications that do use a custom launcher would not have to fiddle to get > the full path to their launcher and same for the ones without launchers (though > they would have to do what you did with the Java params). That's the default behavior if you don't specify new data argument Fixed in HEAD FAQ added http://www.eclipse.org/swt/faq.php#jumplist (In reply to comment #31) > > Does "swt.library.path" work? If so, shouldn't you also set it if defined? It should work. Note that it is just my snippet, works fine for me (using SWT from the CVS http://www.eclipse.org/swt/cvs.php). I suppose a real application would set the cp differently, if you put the swt.jar in the classpath than you don't need to bother setting the library path (at least not for the swt dlls). |