nativelibs4java / BridJ

BridJ: blazing fast Java / C / C++ interop
https://code.google.com/archive/p/bridj/
Other
296 stars 77 forks source link

[BridJ] ITaskbarList3 doesn't work with JavaFX stage #47

Open ochafik opened 9 years ago

ochafik commented 9 years ago

From @AnirvanSarkar on January 27, 2015 10:1

ITaskbarList3 works as expected with JFrame but not with JavaFX stage.

For example, the following Swing code displays a progress in taskbar:

import javax.swing.JFrame;
import org.bridj.Pointer;
import org.bridj.cpp.com.COMRuntime;
import org.bridj.cpp.com.shell.ITaskbarList3;
import org.bridj.jawt.JAWTUtils;

public class SwingTaskbar extends JFrame {

    ITaskbarList3 list;
    Pointer<?> hwnd;

    public SwingTaskbar() throws ClassNotFoundException {

        list = COMRuntime.newInstance(ITaskbarList3.class);

    }

    @Override
    protected void finalize() throws Throwable {

        super.finalize();
        list.Release();

    }

    @Override
    public void setVisible(boolean visible) {

        super.setVisible(visible);

        long hwndVal = JAWTUtils.getNativePeerHandle(this);
        hwnd = Pointer.pointerToAddress(hwndVal);
        list.SetProgressValue((Pointer) hwnd, 50, 100);

    }

    public static void main(String[] args) {

        try {

            SwingTaskbar f = new SwingTaskbar();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.pack();
            f.setVisible(true);

        } catch (Throwable ex) {

            ex.printStackTrace();

        }

    }

}

But its JavaFX counterpart doesn't show one:

import javafx.application.Application;
import javafx.stage.Stage;
import org.bridj.Pointer;
import org.bridj.cpp.com.COMRuntime;
import org.bridj.cpp.com.shell.ITaskbarList3;

public class FXTaskbar extends Application {

    ITaskbarList3 list;
    Pointer<?> hwnd;

    @Override
    public void init() throws ClassNotFoundException {

        list = COMRuntime.newInstance(ITaskbarList3.class);

    }

    @Override
    public void stop() {
        list.Release();
    }

    @Override
    public void start(Stage primaryStage) {

        primaryStage.show();

        long hwndVal = com.sun.glass.ui.Window.getWindows().get(0).getNativeWindow();
                //com.sun.glass.ui.Window.getFocusedWindow().getNativeHandle();
        hwnd = Pointer.pointerToAddress(hwndVal);
        list.SetProgressValue((Pointer) hwnd, 50, 100);

    }

    public static void main(String[] args) {
        launch(args);
    }

}
OS: Windows 7
Java Version: 1.8.0_31
BridJ Version: bridj-0.7-20141231.010908-73-windows-only

Copied from original issue: ochafik/nativelibs4java#556

GregoryHlavac commented 9 years ago

I recently found the fix to this when digging into BridJ because I want to do some windows taskbar stuff with an FX application, turns out the COM stuff was being created on the main thread (The one that the VM is launched with) and then the rest of the modification (In the 'start') method was being called on a different thread (The JavaFX application thread) and that was throwing the COM/RPC stuff for a loop.

I'm not sure if this is something to be fixed in BridJ or something that you'll just have to be aware of when trying to use this stuff in JavaFX.

import javafx.application.Application;
import javafx.stage.Stage;
import org.bridj.Pointer;
import org.bridj.cpp.com.COMRuntime;
import org.bridj.cpp.com.shell.ITaskbarList3;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FXTaskbar extends Application
{
  private ExecutorService es;

  ITaskbarList3 list;
  Pointer<?> hwnd;

  @Override
  public void init()
  {
    es = Executors.newSingleThreadExecutor(r -> {
      Thread t = new Thread(r);

      t.setDaemon(true);

      return t;
    });

    es.execute(() -> {
      try
      {
        list = COMRuntime.newInstance(ITaskbarList3.class);
      }
      catch (ClassNotFoundException e)
      {
        e.printStackTrace();
      }
    });
  }

  @Override
  public void stop()
  {
    es.submit(() -> list.Release());
  }

  @Override
  public void start(Stage primaryStage)
  {
    primaryStage.show();
    long hwndVal = com.sun.glass.ui.Window.getWindows().get(0).getNativeWindow();
    //com.sun.glass.ui.Window.getFocusedWindow().getNativeHandle();
    hwnd = Pointer.pointerToAddress(hwndVal);

    es.execute(() -> {
      list.SetProgressState((Pointer) hwnd, ITaskbarList3.TbpFlag.TBPF_ERROR);
      list.SetProgressValue((Pointer) hwnd, 50, 100);
    });
  }

  public static void main(String[] args)
  {
    launch(args);
  }

}
GregoryHlavac commented 9 years ago

@ochafik You can probably close this issue following my answer.