I have made quite a bit of good progress I think:

https://github.com/brcolow/openjfx/commit/d92ef24101cf32dfc07b21bdcb575528d8a58eaf

The public API is starting to look much cleaner:

https://github.com/brcolow/openjfx/blob/master/modules/javafx.graphics/src/main/java/javafx/scene/robot/Robot.java

Still a lot to do.

Currently I am running into a JNI UnsatisfiedLinkError for GtkRobot but I
am unsure why:

  java.lang.UnsatisfiedLinkError:
com.sun.glass.ui.gtk.GtkRobot.getScreenCapture(IIII[I)V
        at
javafx.graphics/com.sun.glass.ui.gtk.GtkRobot.getScreenCapture(Native
Method)
        at
javafx.graphics/com.sun.glass.ui.gtk.GtkRobot.getPixelColor(GtkRobot.java:93)

I have the following Java method in GtkRobot.java:

@Override native protected void getScreenCapture(int x, int y, int width,
int height, int[] data);

Which is overriding the abstract method in Robot.java:

protected abstract void getScreenCapture(int x, int y, int width, int
height, int[] data);

and it is implemented in GlassRobot.cpp thusly:

/*
 * Class:     com_sun_glass_ui_gtk_GtkRobot
 * Method:    getScreenCapture
 * Signature: (IIII[I)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot_1getScreenCapture
  (JNIEnv * env, jobject obj, jint x, jint y, jint width, jint height,
jintArray data)
{
    (void)obj;

    GdkPixbuf *screenshot, *tmp;
    GdkWindow *root_window = gdk_get_default_root_window();

    tmp = glass_pixbuf_from_window(root_window, x, y, width, height);
    screenshot = gdk_pixbuf_add_alpha(tmp, FALSE, 0, 0, 0);
    g_object_unref(tmp);

    jint *pixels = (jint
*)convert_BGRA_to_RGBA((int*)gdk_pixbuf_get_pixels(screenshot), width * 4,
height);
    env->SetIntArrayRegion(data, 0, height * width, pixels);
    g_free(pixels);

    g_object_unref(screenshot);
}

Have I somehow messed up the signature? As you can see I removed one of the
"_" prefixes
to "1getScreenCapture" (which seemed to work for the other Robots) as
necessary because
the native method is no longer itself prefixed with "_".

Thanks again.

On Wed, Dec 20, 2017 at 3:05 PM, Kevin Rushforth <kevin.rushfo...@oracle.com
> wrote:

> Sure, no problem. One quick comment is that a common way to solve this is
> by delegating to an implementation class, which would then be sub-classes.
>
>
> -- Kevin
>
>
> Michael Ennen wrote:
>
> I am not trying to be a burden here. I understand that you may not have
> time to hand-hold
> to this degree. I will try and make progress, sorry for the follow up
> question.
>
> On Wed, Dec 20, 2017 at 2:08 PM, Michael Ennen <mike.en...@gmail.com>
> wrote:
>
>> How can Robot call into the implementation when it is a super class of
>> the implementations?
>>
>> On Wed, Dec 20, 2017 at 2:04 PM, Kevin Rushforth <
>> kevin.rushfo...@oracle.com> wrote:
>>
>>>
>>>
>>> Michael Ennen wrote:
>>>
>>> I have a question about how to proceed with the Robot code.
>>>
>>> The base abstract Robot class is: https://github.com/brcolow
>>> /openjfx/blob/master/modules/javafx.graphics/src/main/java/j
>>> avafx/scene/robot/Robot.java
>>>
>>> As you can see for each method, such as "getMouseX()" there is a "_"
>>> prefixed method
>>> which is abstract and a non-prefixed method:
>>>
>>> protected abstract int _getMouseX();
>>>
>>> public int getMouseX() {
>>>     Application.checkEventThread();
>>>     return _getMouseX();
>>> }
>>>
>>> I have copied this from the private Robot API.
>>>
>>> Is there a better way to do this? Would this pass review?
>>>
>>>
>>> Yes there are better ways to do this. No it would not pass review, since
>>> this would be leaking implementation into the public API.
>>>
>>> Rather than copying the public / protected methods from the internal
>>> package, it probably makes more sense to start with what a Robot API should
>>> look like and then have that call into the implementation (suitably
>>> modified so it better matches the public API). For one thing you will then
>>> leave the implementation, including the per-platform code, where it belongs
>>> -- in glass. The Robot API can be informed by the current implementation,
>>> but should not be defined by it.
>>>
>>> -- Kevin
>>>
>>>
>>>
>>> Thanks very much.
>>>
>>>
>>> On Tue, Dec 5, 2017 at 5:29 PM, Kevin Rushforth <
>>> kevin.rushfo...@oracle.com> wrote:
>>>
>>>> Glad you got the build working. You can post back on this thread when
>>>> you are ready.
>>>>
>>>>
>>>> -- Kevin
>>>>
>>>>
>>>> Michael Ennen wrote:
>>>>
>>>> Correction:
>>>>
>>>> Adding ""--add-exports javafx.graphics/javafx.scene.robot=ALL-UNNAMED"
>>>> to buildSrc/addExports.
>>>>
>>>> For posterity :)
>>>>
>>>> On Mon, Dec 4, 2017 at 6:08 PM, Michael Ennen <mike.en...@gmail.com>
>>>> wrote:
>>>>
>>>>> Ah, indeed, missed adding "--add-opens 
>>>>> javafx.graphics/javafx.scene.robot=ALL-UNNAMED"
>>>>> to buildSrc/addExports.
>>>>> Thanks for the guidance on that.
>>>>>
>>>>> I will continue to work on this in the GitHub repo and polish it up
>>>>> (add javadocs, better method signatures, etc.) and
>>>>> even plan on maybe improving the underlying native Robot
>>>>> implementations (for example fixing/improving the
>>>>> way color profiles are handled for MacRobot).
>>>>>
>>>>> I will also take a look at "fixing" JemmyFX to use the new public API
>>>>> (as well as any other place in the JavaFX code
>>>>> base that does).
>>>>>
>>>>> I was expecting that JDK 11 would be the appropriate time frame,
>>>>> especially because it will be the release where
>>>>> private APIs will be totally inaccessible, correct?
>>>>>
>>>>> After I get it in a reasonable state should I post back on this
>>>>> mailing list thread or what would be the appropriate
>>>>> way?
>>>>>
>>>>> Thanks Kevin.
>>>>>
>>>>> On Mon, Dec 4, 2017 at 5:12 PM, Kevin Rushforth <
>>>>> kevin.rushfo...@oracle.com> wrote:
>>>>>
>>>>>> This is a limitation of the the way --patch-modules works. You will
>>>>>> need to add an entry in:
>>>>>>
>>>>>> buildSrc/addExports
>>>>>>
>>>>>> Btw, as for the proposal itself, this might need to be a JEP
>>>>>> depending on the scope. In any case, it could be considered in the JDK 11
>>>>>> time frame, but there are several things that need to be worked out 
>>>>>> before
>>>>>> making Robot a public API, including the fact that the JemmyFX framework 
>>>>>> in
>>>>>> the openjfx/jfx/tests directory uses Robot. Once you get a working
>>>>>> prototype, it would be interesting to discuss it in more detail.
>>>>>>
>>>>>> -- Kevin
>>>>>>
>>>>>>
>>>>>>
>>>>>> Michael Ennen wrote:
>>>>>>
>>>>>> Currently I am stuck with tests not being able to see the new
>>>>>> "javafx.scene.robot" module:
>>>>>>
>>>>>>
>>>>>>
>>>>>> Task :systemTests:compileTestJava
>>>>>>
>>>>>>
>>>>>> C:\Users\brcolow\dev\openjfx\tests\system\src\test\java\test\robot\com\sun\glass\ui\monocle\ModalDialogTest.java:34:
>>>>>> error: package javafx.scene.robot is not visible
>>>>>> import javafx.scene.robot.Robot;
>>>>>>                    ^
>>>>>>   (package javafx.scene.robot is declared in module javafx.graphics, 
>>>>>> which
>>>>>> does not export it)
>>>>>> C:\Users\brcolow\dev\openjfx\tests\system\src\test\java\test\robot\com\sun\glass\ui\monocle\RobotTest.java:33:
>>>>>> error: package javafx.scene.robot is not visible
>>>>>> import javafx.scene.robot.Robot;
>>>>>>
>>>>>> I have added:
>>>>>>
>>>>>>     exports javafx.scene.robot;
>>>>>>
>>>>>> to: modules/javafx.graphics/src/main/java/module-info.java
>>>>>>
>>>>>> But this does not seem to be enough.
>>>>>>
>>>>>> On Sun, Dec 3, 2017 at 4:48 PM, Michael Ennen <mike.en...@gmail.com> 
>>>>>> <mike.en...@gmail.com> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> I am still working on all the necessary changes to actually allow openjfx
>>>>>> to compile.
>>>>>> Tons to learn in that arena and I know the code as it is written won't
>>>>>> totally work.
>>>>>> For example one can no longer:
>>>>>>
>>>>>> #include "com_sun_glass_ui_Robot.h"
>>>>>>
>>>>>> as in openjfx\modules\javafx.graphics\src\main\native-glass\win\Robot.cpp
>>>>>>
>>>>>> But I am not sure how those headers are generated and if I can just 
>>>>>> simply
>>>>>> change
>>>>>> it to "#include javafx_scene_robot_Robot.h" (which I very much doubt).
>>>>>>
>>>>>> On Sun, Dec 3, 2017 at 2:29 PM, Michael Ennen <mike.en...@gmail.com> 
>>>>>> <mike.en...@gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> I have created a (small) proposal (building on the work of Benjamin
>>>>>> Gudehaus) about moving some classes in to the public API so that TestFX 
>>>>>> (a
>>>>>> JavaFX UI testing framework) can continue to work with future JDK 
>>>>>> releases.
>>>>>> The somewhat nicely formatted proposal can be found as a Github gist:
>>>>>> https://gist.github.com/brcolow/26370db6cab0355186d4a1d13b30fc19
>>>>>>
>>>>>> All suggested changes can be found by using Github Compare View:
>>>>>> https://github.com/brcolow/openjfx/compare/4ccdbbbce5234e2c5
>>>>>> e1f4f1cb8f20430feaa53b6...master
>>>>>>
>>>>>> But I have copied it to this email for convenience:
>>>>>>
>>>>>> ----------------------- PROPOSAL -----------------------
>>>>>>
>>>>>> TestFX, the JavaFX GUI testing framework currently requires 4 (four)
>>>>>> classes that are part of the JDK's private API. They are:
>>>>>>
>>>>>> [com.sun.glass.ui.Application](http://hg.openjdk.java.net/op
>>>>>> enjfx/10-dev/rt/file/tip/modules/javafx.graphics/src/main/
>>>>>> java/com/sun/glass/ui/Application.java)
>>>>>> [com.sun.glass.ui.Pixels](http://hg.openjdk.java.net/openjfx
>>>>>> /10-dev/rt/file/tip/modules/javafx.graphics/src/main/java/
>>>>>> com/sun/glass/ui/Pixels.java)
>>>>>> [com.sun.glass.ui.Robot](http://hg.openjdk.java.net/openjfx/
>>>>>> 10-dev/rt/file/tip/modules/javafx.graphics/src/main/java/com
>>>>>> /sun/glass/ui/Robot.java)
>>>>>> [com.sun.javafx.application.ParametersImpl](http://hg.openjdk.java.net/openjfx/10-dev/rt/file/tip/modules/javafx.
>>>>>> graphics/src/main/java/com/sun/javafx/application/ParametersImpl.java 
>>>>>> <http://k.java.net/openjfx/10-dev/rt/file/tip/modules/javafx.graphics/src/main/java/com/sun/javafx/application/ParametersImpl.java>)
>>>>>>
>>>>>> In order to compile the project with Java 9, we use the following flags:
>>>>>>
>>>>>> ```sh
>>>>>> --add-exports javafx.graphics/com.sun.glass.ui=org.testfx
>>>>>> --add-exports javafx.graphics/com.sun.javafx.application=org.testfx
>>>>>> ```
>>>>>>
>>>>>> If the --add-exports flags are disabled in a future Java release TestFX
>>>>>> will require these four classes to be moved into the public API to
>>>>>> continue working.
>>>>>>
>>>>>> While these classes are probably not very useful for applications to use
>>>>>> directly, any JavaFX application wanting to write UI tests will most
>>>>>> likely
>>>>>> use TestFX and thus they will indirectly be using these classes.
>>>>>>
>>>>>> JavaFX internal tests also use these classes for essentially the same
>>>>>> purpose (UI tests).
>>>>>>
>>>>>> ### Details of Usage For Each Private API Class
>>>>>>
>>>>>> #### com.sun.javafx.application.ParametersImpl
>>>>>>
>>>>>> ##### TestFX Usage
>>>>>>
>>>>>> ```java
>>>>>> ParametersImpl parameters = new ParametersImpl(applicationArgs);
>>>>>> ParametersImpl.registerParameters(application, parameters);
>>>>>> ```
>>>>>>
>>>>>> The parameters are set on a constructed Application.
>>>>>>
>>>>>> ##### Suggested Public API Replacement
>>>>>>
>>>>>> `javafx.application.Application`:
>>>>>>
>>>>>> ```java
>>>>>> /**
>>>>>>  * Sets the parameters for this Application.
>>>>>>  *
>>>>>>  * <p>
>>>>>>  * NOTE: this method should not be called from the Application
>>>>>> constructor,
>>>>>>  * as it will return null. It may be called in the init() method or any
>>>>>>  * time after that.
>>>>>>  * </p>
>>>>>>  *
>>>>>>  * @param parameters the parameters to set for this Application
>>>>>>  */
>>>>>> public final Parameters setParameters(String... parameters) {
>>>>>>     ParametersImpl parameters = new ParametersImpl(parameters);
>>>>>>     ParametersImpl.registerParameters(this, parameters);
>>>>>> }
>>>>>> ```
>>>>>>
>>>>>> #### com.sun.glass.ui.Application
>>>>>>
>>>>>> ##### TestFX Usage
>>>>>>
>>>>>> ```java
>>>>>> return Application.GetApplication().createRobot();
>>>>>> ```
>>>>>>
>>>>>> The Application class is used to instantiate a Robot.
>>>>>>
>>>>>> ##### Suggested Public API Replacement
>>>>>>
>>>>>> `javafx.application.Application`:
>>>>>> https://github.com/brcolow/openjfx/blob/master/modules/javaf
>>>>>> x.graphics/src/main/java/javafx/application/Application.java#L527
>>>>>>
>>>>>> #### com.sun.glass.ui.Pixels
>>>>>>
>>>>>> ##### TestFX Usage
>>>>>>
>>>>>> ```java
>>>>>> @Override
>>>>>> public Image getCaptureRegion(Rectangle2D region) {
>>>>>>     return waitForAsyncFx(RETRIEVAL_TIMEOUT_IN_MILLIS, () -> {
>>>>>>         Pixels glassPixels = useRobot().getScreenCapture(
>>>>>>             (int) region.getMinX(), (int) region.getMinY(),
>>>>>>             (int) region.getWidth(), (int) region.getHeight()
>>>>>>         );
>>>>>>         return convertFromGlassPixels(glassPixels);
>>>>>>     });
>>>>>> }
>>>>>>
>>>>>> private Image convertFromGlassPixels(Pixels glassPixels) {
>>>>>>     int width = glassPixels.getWidth();
>>>>>>     int height = glassPixels.getHeight();
>>>>>>     WritableImage image = new WritableImage(width, height);
>>>>>>
>>>>>>     int bytesPerComponent = glassPixels.getBytesPerComponent();
>>>>>>     if (bytesPerComponent == INT_BUFFER_BYTES_PER_COMPONENT) {
>>>>>>         IntBuffer intBuffer = (IntBuffer) glassPixels.getPixels();
>>>>>>         writeIntBufferToImage(intBuffer, image);
>>>>>>     }
>>>>>>
>>>>>>     return image;
>>>>>> }
>>>>>>
>>>>>> private void writeIntBufferToImage(IntBuffer intBuffer,
>>>>>>                                    WritableImage image) {
>>>>>>     PixelWriter pixelWriter = image.getPixelWriter();
>>>>>>     double width = image.getWidth();
>>>>>>     double height = image.getHeight();
>>>>>>
>>>>>>     for (int y = 0; y < height; y++) {
>>>>>>         for (int x = 0; x < width; x++) {
>>>>>>             int argb = intBuffer.get();
>>>>>>             pixelWriter.setArgb(x, y, argb);
>>>>>>         }
>>>>>>     }
>>>>>> }
>>>>>> ```
>>>>>>
>>>>>> Pixels is used to create a screen capture.
>>>>>>
>>>>>> ##### Suggested Public API Replacement
>>>>>>
>>>>>> Bypass needing to expose the Pixels class to the public API by
>>>>>> changing the getScreenCapture method of Robot - that is, changing:
>>>>>>
>>>>>> `public Pixels getScreenCapture(int x, int y, int width, int height)`
>>>>>>
>>>>>> to:
>>>>>>
>>>>>> `public Image getScreenCapture(int x, int y, int width, int height)`
>>>>>>
>>>>>> #### com.sun.glass.ui.Robot
>>>>>>
>>>>>> ##### TestFX Usage
>>>>>>
>>>>>> Essentially every method of Robot is used:
>>>>>>
>>>>>> ```
>>>>>> public void keyPress(int code)
>>>>>> public void keyRelease(int code)
>>>>>> public int getMouseX()
>>>>>> public int getMouseY()
>>>>>> public void mouseMove(int x, int y)
>>>>>> public void mousePress(int buttons)
>>>>>> public void mouseRelease(int buttons)
>>>>>> public void mouseWheel(int wheelAmt)
>>>>>> public int getPixelColor(int x, int y)
>>>>>> public Pixels getScreenCapture(int x, int y, int width, int height)
>>>>>> ```
>>>>>>
>>>>>> ##### Suggested Public API Replacement
>>>>>> https://github.com/brcolow/openjfx/blob/master/modules/javaf
>>>>>> x.graphics/src/main/java/javafx/scene/robot/Robot.java
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Michael Ennen
>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Michael Ennen
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Michael Ennen
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Michael Ennen
>>>>
>>>>
>>>
>>>
>>> --
>>> Michael Ennen
>>>
>>>
>>
>>
>> --
>> Michael Ennen
>>
>
>
>
> --
> Michael Ennen
>
>


-- 
Michael Ennen

Reply via email to