This is working pretty well, the TrayIcon is showing! But now how do I poll for events on this TrayIcon?? I tried the "JNative.registerWindowProc"-function (see above code), with the hwnd of my java-window. But when I do this my Java-App "freezes" (no exception, just hangs)...
Any help is welcome!
Best regards
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Is this correct? What is the second parameter for??
Also what means the first parameter at "JNative.createCallback(1, this);"? Could this be any number or does this depend on something??
I simply want to react on mouseclicks on my TrayIcon...
Regards,
Thubb
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Now it "works" (at least it does something and says "registering callback b1678"), but now i get the following exception everytime i do a mouse-move:
java.lang.NoClassDefFoundError: Lorg/xvolks/jnative/JNative;
at sun.awt.windows.WToolkit.eventLoop(Native Method)
at sun.awt.windows.WToolkit.run(WToolkit.java:290)
at java.lang.Thread.run(Thread.java:619)
WTF???
Thubb
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
jwindowkiller.jnative.trayicon.TrayIcon implements the Callback interface and simply does nothing right now in "callback()"
An other question I have is, how to use User32.LoadIcon. Currently I load a default windows icon. How can I load i.e. a local picture on my harddrive or even better, is it possible to pass an Instance of Image or ImageIcon anyhow?
Thubb
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ah and the classpath cannot be a problem, because all other calls to JNative work perfectly (I am using netbeans and integrated the sourcecode via a seperate project into my project).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
As I never did WIN32 coding I am also not very experienced. So what is "BYTE cPlanes, const BYTE *lpbANDbits, and const BYTE *lpbXORbits"? The const BYTE are byte arrays, ok, I can grab the pixels of a Java image with a PixelGrabber, but then I have an int-array. So how can I convert this int array to make it usable in the CreateIcon-function?? And what is "BYTE cPlanes"??
Thank you!
Thubb
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
public static LONG CreateIcon(LONG hInstance, int nWidth, int nHeight, int cPlanes,
int cBitsPixel, int[] lpbANDbits, int[] lpbXORbits)
throws NativeException, IllegalAccessException {
JNative createIcon = new JNative(DLL_NAME, "CreateIcon");
Pointer p = new Pointer(MemoryBlockFactory.createMemoryBlock(lpbXORbits.length*4));
for(int i = 0; i<lpbXORbits.length; i++) {
p.setIntAt(i*4,lpbXORbits[i]);
}
createIcon.setRetVal(Type.INT);
int i = 0;
createIcon.setParameter(i++, hInstance.getValue());
createIcon.setParameter(i++, nWidth);
createIcon.setParameter(i++, nHeight);
createIcon.setParameter(i++, cPlanes);
createIcon.setParameter(i++, cBitsPixel);
createIcon.setParameter(i++, NullPointer.NULL);
createIcon.setParameter(i++, p);
createIcon.invoke();
return new LONG(createIcon.getRetValAsInt());
}
public static int[] grabImage(ImageIcon image) throws Exception {
try {
// Collect pixel data in array
int w = image.getIconWidth();
int h = image.getIconHeight();
int[] pixels = new int[w * h];
PixelGrabber pg = new PixelGrabber(image.getImage(), 0, 0, w, h, pixels, 0, w);
pg.grabPixels();
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
throw new Exception("Error loading icon image");
}
return pixels;
} catch (InterruptedException ex) {
throw ex;
} catch (NullPointerException ex) {
throw ex;
}
}
No problem, this was a topic I wanted to ask you anyway. I would be very glad to contribute code. I already added Registry-Write support and some other Win32-functions I needed for my Application. Now I am trying to get the TrayIcon to work. Still the
java.lang.NoClassDefFoundError: Lorg/xvolks/jnative/JNative;
at sun.awt.windows.WToolkit.eventLoop(Native Method)
at sun.awt.windows.WToolkit.run(WToolkit.java:290)
at java.lang.Thread.run(Thread.java:619)
prevents me from polling for mouseEvents...
Maybe you could again have a look at this? As I said, there is no Classpath problem or something else cuz everything else works fine.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
BTW: to really contribute my code I guess I need to have access to the CVS, because it does not make much sense to copy all the code to the patch-tracker, does it??
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I also added the JNative.jar now to my ClassPath but the error remains. I think the error is somehow caused by the native part of JNative. Normally a NoClassDefFoundError does not look like this:
I agree that's why I asked you in a previous message to test with JNative 1.3 (instead of 1.3.1) to see if the correction of bug was not a new bug.
Regards,
--Marc
P.S. : I now remember that I saw this behavior before : it was the message loop of the application that called our callback in a context that the classloader was unknown. Don't remember exactly perhaps a WM_xxx message clash between Windows and custom messages...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I just found out that the fired MouseEvents of the TrayIcon can somewhat be polled with a Java Mouse(Motion)Listener attached to the JFrame... The generated MouseEvents are not 100% compatible to the java ones (i.e. ClickCount is totally wrong) and also the Listener-methodes are not triggered correctly (MouseMove-Event in mouseClicked-mehode). But I coded a kind of workaround so that I can poll the mouse now somewhat from within java:
public void mouseClicked(MouseEvent e) {
// discard all events that are not related to MouseButton-clicks
if(e.getModifiersEx() == 0) {
e.consume();
return;
}
clickCount++;
// forget previous clickCount if last click was too much time before
if((System.currentTimeMillis() - lastClicked) > 500L) {
clickCount = 1;
}
// discard all clicks that were too fast in a row
if((System.currentTimeMillis() - lastClicked) < 50L) {
clickCount = 0;
} else if(e.getModifiersExText(e.getModifiersEx()).equalsIgnoreCase("button1")) {
if((leftMouseDoubleClick && clickCount > 1) || !leftMouseDoubleClick ) {
if(pMenu != null)
pMenu.setVisible(false);
owner.setVisible(!owner.isVisible());
if(owner.isVisible()) {
owner.toFront();
owner.requestFocus();
}
clickCount = 0;
}
} else if(!pMenu.isVisible() && e.getModifiersExText(e.getModifiersEx()).equalsIgnoreCase("button3")) {
if(pMenu != null) {
pMenu.show(null,e.getXOnScreen(),e.getYOnScreen());
pMenu.setVisible(true);
}
clickCount = 0;
}
lastClicked = System.currentTimeMillis();
e.consume();
}
This works as it should, not very nice, but... ;)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It seems as if the call to registerWindowProc somewhat makes the AWT-Thread stuck. Other threads that I created before this call keep running (like updating a JLabel in a loop) but my JFrame is frozen...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I created a trayicon with JNative from within my Java-App:
try {
NOTIFYICONDATAA iconData = new NOTIFYICONDATAA();
iconData.hWnd = User32.findWindow(null,this.getTitle()).getValue().intValue();
iconData.uID = 100;
iconData.uFlags = NOTIFYICONDATA.NIF_ICON | NOTIFYICONDATA.NIF_MESSAGE | NOTIFYICONDATA.NIF_TIP;
iconData.uCallbackMessage = NOTIFYICONDATA.WM_RBUTTONDBLCLK;
iconData.hIcon = User32.LoadIcon(new LONG(0),100).getValue().intValue();
iconData.szTip = "Test1234";
iconData.uTimeOutOrVersion = NOTIFYICONDATA.NOTIFYICON_VERSION;
Shell32.Shell_NotifyIcon(NOTIFYICONDATA.NIM_ADD,iconData);
Shell32.Shell_NotifyIcon(NOTIFYICONDATA.NIM_SETVERSION, iconData);
JNative.registerWindowProc(User32.findWindow(null,this.getTitle()).getValue().intValue(), new jwindowkiller.jnative.trayicon.TrayIcon());
} catch(Exception e) {
e.printStackTrace();
}
This is working pretty well, the TrayIcon is showing! But now how do I poll for events on this TrayIcon?? I tried the "JNative.registerWindowProc"-function (see above code), with the hwnd of my java-window. But when I do this my Java-App "freezes" (no exception, just hangs)...
Any help is welcome!
Best regards
Thubb,
I am not sure ; but the registerWindowProc() function may be buggy.
Could you use a Callback object to implement your polling function ?
1. Create an object implementing Callback (see line 37 at http://jnative.cvs.sourceforge.net/jnative/JNative/src/java/JNative/org/xvolks/test/callbacks/linux/LinuxCallback.java?view=markup )
2. Call SetWindowLong passing it yourObject.getCallbackAddress()
Please try it and tell us if it worked.
Regards,
--Marc
Erm, what vlaues should I pass to SetWindowLong?
User32.SetWindowLong(new HWND(iconData.hwnd),0,new LONG(new jwindowkiller.jnative.trayicon.TrayIcon().getCallbackAddress()));
Is this correct? What is the second parameter for??
Also what means the first parameter at "JNative.createCallback(1, this);"? Could this be any number or does this depend on something??
I simply want to react on mouseclicks on my TrayIcon...
Regards,
Thubb
Hi,
I am not a Win32 guru, so I guess that zero is ok : see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windowclasses/windowclassreference/windowclassfunctions/setwindowlong.asp
The first parameter of createCallback is the number of arguments of the called back function.
For a WindowProc function this argument should be 4 : see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windowprocedures/windowprocedurereference/windowprocedurefunctions/windowproc.asp
Regards,
--Marc
Ah ok, the second parameter has to be -4.
Now it "works" (at least it does something and says "registering callback b1678"), but now i get the following exception everytime i do a mouse-move:
java.lang.NoClassDefFoundError: Lorg/xvolks/jnative/JNative;
at sun.awt.windows.WToolkit.eventLoop(Native Method)
at sun.awt.windows.WToolkit.run(WToolkit.java:290)
at java.lang.Thread.run(Thread.java:619)
WTF???
Thubb
Hi,
I do not think that the parameter has to be negative.
You placed the callback at a bad place since it repetitively registers itself ?? or is it a bug in the message ;)
the NoClassDefFoundError sounds to be a Classpath or ClassLoader issue.
Regards,
--Marc
I guess I have to set GWL_WNDPROC as second parameter and its value is -4. So I think this is correct.
Current code is as follows and is only called once when my java-app is loaded:
public void setTrayIcon(boolean enable) {
try {
if(enable) {
iconData.hWnd = User32.findWindow(null,this.getTitle()).getValue().intValue();
iconData.uID = 100;
iconData.uFlags = NOTIFYICONDATA.NIF_ICON | NOTIFYICONDATA.NIF_MESSAGE | NOTIFYICONDATA.NIF_TIP;
iconData.uCallbackMessage = NOTIFYICONDATA.WM_LBUTTONDBLCLK;
iconData.hIcon = User32.LoadIcon(new LONG(0),100).getValue().intValue();
iconData.szTip = "Test1234";
iconData.uTimeOutOrVersion = NOTIFYICONDATA.NOTIFYICON_VERSION;
Shell32.Shell_NotifyIcon(NOTIFYICONDATA.NIM_ADD,iconData);
Shell32.Shell_NotifyIcon(NOTIFYICONDATA.NIM_SETVERSION, iconData);
int prevWindowProc = User32.SetWindowLong(new HWND(iconData.hWnd),-4,new LONG(new jwindowkiller.jnative.trayicon.TrayIcon().getCallbackAddress()));
} else {
Shell32.Shell_NotifyIcon(NOTIFYICONDATA.NIM_DELETE, iconData);
}
} catch(Throwable e) {
e.printStackTrace();
}
}
jwindowkiller.jnative.trayicon.TrayIcon implements the Callback interface and simply does nothing right now in "callback()"
An other question I have is, how to use User32.LoadIcon. Currently I load a default windows icon. How can I load i.e. a local picture on my harddrive or even better, is it possible to pass an Instance of Image or ImageIcon anyhow?
Thubb
Ah and the classpath cannot be a problem, because all other calls to JNative work perfectly (I am using netbeans and integrated the sourcecode via a seperate project into my project).
Hi,
Well, as I said before I am not a Win32 guru.
Please test the TestCallback/EnumCallback in org.xvolks.test.callbacks to see if it works or not.
Regards,
--Marc
I am already using an other callback (User32.EnumWindows) in my application which works perfectly.
Any help regarding the Icon load? I found User32.CreateIcon could be useful http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/resources/icons/iconreference/iconfunctions/createicon.asp?frame=true
As I never did WIN32 coding I am also not very experienced. So what is "BYTE cPlanes, const BYTE *lpbANDbits, and const BYTE *lpbXORbits"? The const BYTE are byte arrays, ok, I can grab the pixels of a Java image with a PixelGrabber, but then I have an int-array. So how can I convert this int array to make it usable in the CreateIcon-function?? And what is "BYTE cPlanes"??
Thank you!
Thubb
YES, i got it:
public static LONG CreateIcon(LONG hInstance, int nWidth, int nHeight, int cPlanes,
int cBitsPixel, int[] lpbANDbits, int[] lpbXORbits)
throws NativeException, IllegalAccessException {
JNative createIcon = new JNative(DLL_NAME, "CreateIcon");
Pointer p = new Pointer(MemoryBlockFactory.createMemoryBlock(lpbXORbits.length*4));
for(int i = 0; i<lpbXORbits.length; i++) {
p.setIntAt(i*4,lpbXORbits[i]);
}
createIcon.setRetVal(Type.INT);
int i = 0;
createIcon.setParameter(i++, hInstance.getValue());
createIcon.setParameter(i++, nWidth);
createIcon.setParameter(i++, nHeight);
createIcon.setParameter(i++, cPlanes);
createIcon.setParameter(i++, cBitsPixel);
createIcon.setParameter(i++, NullPointer.NULL);
createIcon.setParameter(i++, p);
createIcon.invoke();
return new LONG(createIcon.getRetValAsInt());
}
public static int[] grabImage(ImageIcon image) throws Exception {
try {
// Collect pixel data in array
int w = image.getIconWidth();
int h = image.getIconHeight();
int[] pixels = new int[w * h];
PixelGrabber pg = new PixelGrabber(image.getImage(), 0, 0, w, h, pixels, 0, w);
pg.grabPixels();
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
throw new Exception("Error loading icon image");
}
return pixels;
} catch (InterruptedException ex) {
throw ex;
} catch (NullPointerException ex) {
throw ex;
}
}
ImageIcon img = Tools.createImageIcon("gui/images/logo.gif");
int[] pixels = grabImage(img);
User32.CreateIcon(new LONG(iconData.hWnd),img.getIconWidth(), img.getIconHeight(), 4, 8, pixels, pixels).getValue().intValue();
Works!!
JNative really blows my mind!!!
Hi,
I am very pleased that JNative worked for you.
If you did generic programming for the tray icon, you may contribute to JNative by sharing your code as a patch see : https://sourceforge.net/tracker/?group_id=156421&atid=799720
Be aware that all code released with JNative goes under LGPL.
Regards,
--Marc
No problem, this was a topic I wanted to ask you anyway. I would be very glad to contribute code. I already added Registry-Write support and some other Win32-functions I needed for my Application. Now I am trying to get the TrayIcon to work. Still the
java.lang.NoClassDefFoundError: Lorg/xvolks/jnative/JNative;
at sun.awt.windows.WToolkit.eventLoop(Native Method)
at sun.awt.windows.WToolkit.run(WToolkit.java:290)
at java.lang.Thread.run(Thread.java:619)
prevents me from polling for mouseEvents...
Maybe you could again have a look at this? As I said, there is no Classpath problem or something else cuz everything else works fine.
BTW: to really contribute my code I guess I need to have access to the CVS, because it does not make much sense to copy all the code to the patch-tracker, does it??
Hi,
You're now member of JNative project.
Congratulations and welcome on board.
Regards,
--Marc
Hi,
Please do not commit any Netbeans specific files into CVS.
Regards,
--Marc
Sure!
Do you also make use of SVN or only CVS?
Hi,
I have planned to move to SVN one day, but did not got time to do that.
We should move to the developper forum now.
--Marc
Hi,
For the NoClassDefFoundError : do you use JNative 1.3.1 or 1.3 ?
Can you test the other version because of [ 1634788 ] Callbacks may not be thread safe
see https://sourceforge.net/tracker/index.php?func=detail&aid=1634788&group_id=156421&atid=799718 for more informations
--Marc
I am using JNative 1.3.1
I also added the JNative.jar now to my ClassPath but the error remains. I think the error is somehow caused by the native part of JNative. Normally a NoClassDefFoundError does not look like this:
java.lang.NoClassDefFoundError: Lorg/xvolks/jnative/JNative;
Usually the called class seperated by dots is displayed...
Hi,
I agree that's why I asked you in a previous message to test with JNative 1.3 (instead of 1.3.1) to see if the correction of bug was not a new bug.
Regards,
--Marc
P.S. : I now remember that I saw this behavior before : it was the message loop of the application that called our callback in a context that the classloader was unknown. Don't remember exactly perhaps a WM_xxx message clash between Windows and custom messages...
I just found out that the fired MouseEvents of the TrayIcon can somewhat be polled with a Java Mouse(Motion)Listener attached to the JFrame... The generated MouseEvents are not 100% compatible to the java ones (i.e. ClickCount is totally wrong) and also the Listener-methodes are not triggered correctly (MouseMove-Event in mouseClicked-mehode). But I coded a kind of workaround so that I can poll the mouse now somewhat from within java:
public void mouseClicked(MouseEvent e) {
// discard all events that are not related to MouseButton-clicks
if(e.getModifiersEx() == 0) {
e.consume();
return;
}
clickCount++;
// forget previous clickCount if last click was too much time before
if((System.currentTimeMillis() - lastClicked) > 500L) {
clickCount = 1;
}
// discard all clicks that were too fast in a row
if((System.currentTimeMillis() - lastClicked) < 50L) {
clickCount = 0;
} else if(e.getModifiersExText(e.getModifiersEx()).equalsIgnoreCase("button1")) {
if((leftMouseDoubleClick && clickCount > 1) || !leftMouseDoubleClick ) {
if(pMenu != null)
pMenu.setVisible(false);
owner.setVisible(!owner.isVisible());
if(owner.isVisible()) {
owner.toFront();
owner.requestFocus();
}
clickCount = 0;
}
} else if(!pMenu.isVisible() && e.getModifiersExText(e.getModifiersEx()).equalsIgnoreCase("button3")) {
if(pMenu != null) {
pMenu.show(null,e.getXOnScreen(),e.getYOnScreen());
pMenu.setVisible(true);
}
clickCount = 0;
}
lastClicked = System.currentTimeMillis();
e.consume();
}
This works as it should, not very nice, but... ;)
I have testes the WindowProc now with the v1.3 dll but the same problems happen here...
It seems as if the call to registerWindowProc somewhat makes the AWT-Thread stuck. Other threads that I created before this call keep running (like updating a JLabel in a loop) but my JFrame is frozen...