Menu

How to poll a TrayIcon

Help
Thubb
2007-03-05
2013-04-26
1 2 > >> (Page 1 of 2)
  • Thubb

    Thubb - 2007-03-05

    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

     
    • Marc DENTY

      Marc DENTY - 2007-03-06

      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

       
    • Thubb

      Thubb - 2007-03-06

      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

       
    • Thubb

      Thubb - 2007-03-06

      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

       
      • Marc DENTY

        Marc DENTY - 2007-03-06

        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

         
    • Thubb

      Thubb - 2007-03-06

      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

       
    • Thubb

      Thubb - 2007-03-06

      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).

       
      • Marc DENTY

        Marc DENTY - 2007-03-06

        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

         
    • Thubb

      Thubb - 2007-03-06

      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

       
    • Thubb

      Thubb - 2007-03-06

      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!!!

       
      • Marc DENTY

        Marc DENTY - 2007-03-06

        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

         
    • Thubb

      Thubb - 2007-03-06

      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.

       
    • Thubb

      Thubb - 2007-03-06

      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??

       
      • Marc DENTY

        Marc DENTY - 2007-03-06

        Hi,

        You're now member of JNative project.
        Congratulations and welcome on board.

        Regards,

        --Marc

         
    • Marc DENTY

      Marc DENTY - 2007-03-06

      Hi,

      Please do not commit any Netbeans specific files into CVS.

      Regards,

      --Marc

       
    • Thubb

      Thubb - 2007-03-06

      Sure!

      Do you also make use of SVN or only CVS?

       
      • Marc DENTY

        Marc DENTY - 2007-03-06

        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

         
    • Marc DENTY

      Marc DENTY - 2007-03-06

      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

       
    • Thubb

      Thubb - 2007-03-06

      I am using JNative 1.3.1

       
    • Thubb

      Thubb - 2007-03-06

      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...

       
      • Marc DENTY

        Marc DENTY - 2007-03-07

        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...

         
    • Thubb

      Thubb - 2007-03-07

      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... ;)

       
    • Thubb

      Thubb - 2007-03-12

      I have testes the WindowProc now with the v1.3 dll but the same problems happen here...

       
    • Thubb

      Thubb - 2007-03-12

      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...

       
1 2 > >> (Page 1 of 2)

Log in to post a comment.

MongoDB Logo MongoDB