8014212: Robot captures black screen
authorazvegint
Tue, 11 Aug 2015 16:32:13 +0300
changeset 32282 9c9ff2c42e0d
parent 32281 99ae1f6dd69b
child 32283 1a96ab120a48
8014212: Robot captures black screen Reviewed-by: alexsch, serb
jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java
jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c
jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c
jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h
jdk/test/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java
jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java
jdk/test/javax/swing/JComponent/6683775/bug6683775.java
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java	Mon Aug 10 14:42:07 2015 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java	Tue Aug 11 16:32:13 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,15 +25,16 @@
 package sun.awt.X11;
 
 import java.awt.*;
-import java.awt.event.InputEvent;
 import java.awt.peer.*;
 
 import sun.awt.AWTAccessor;
 import sun.awt.SunToolkit;
+import sun.awt.UNIXToolkit;
 import sun.awt.X11GraphicsConfig;
 
 class XRobotPeer implements RobotPeer {
 
+    private static volatile boolean isGtkSupported;
     private X11GraphicsConfig   xgc = null;
     /*
      * native implementation uses some static shared data (pipes, processes)
@@ -44,46 +45,65 @@
     XRobotPeer(GraphicsConfiguration gc) {
         this.xgc = (X11GraphicsConfig)gc;
         SunToolkit tk = (SunToolkit)Toolkit.getDefaultToolkit();
-        setup(tk.getNumberOfButtons(), AWTAccessor.getInputEventAccessor().getButtonDownMasks());
+        setup(tk.getNumberOfButtons(),
+                AWTAccessor.getInputEventAccessor().getButtonDownMasks());
+
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
+        if (!isGtkSupported) {
+            if (toolkit instanceof UNIXToolkit
+                    && ((UNIXToolkit) toolkit).loadGTK()) {
+                isGtkSupported = true;
+            }
+        }
     }
 
+    @Override
     public void dispose() {
         // does nothing
     }
 
+    @Override
     public void mouseMove(int x, int y) {
         mouseMoveImpl(xgc, x, y);
     }
 
+    @Override
     public void mousePress(int buttons) {
         mousePressImpl(buttons);
     }
 
+    @Override
     public void mouseRelease(int buttons) {
         mouseReleaseImpl(buttons);
     }
 
+    @Override
     public void mouseWheel(int wheelAmt) {
-    mouseWheelImpl(wheelAmt);
+        mouseWheelImpl(wheelAmt);
     }
 
+    @Override
     public void keyPress(int keycode) {
         keyPressImpl(keycode);
     }
 
+    @Override
     public void keyRelease(int keycode) {
         keyReleaseImpl(keycode);
     }
 
+    @Override
     public int getRGBPixel(int x, int y) {
         int pixelArray[] = new int[1];
-        getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray);
+        getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray, isGtkSupported);
         return pixelArray[0];
     }
 
+    @Override
     public int [] getRGBPixels(Rectangle bounds) {
         int pixelArray[] = new int[bounds.width*bounds.height];
-        getRGBPixelsImpl(xgc, bounds.x, bounds.y, bounds.width, bounds.height, pixelArray);
+        getRGBPixelsImpl(xgc, bounds.x, bounds.y, bounds.width, bounds.height,
+                            pixelArray, isGtkSupported);
         return pixelArray;
     }
 
@@ -97,5 +117,6 @@
     private static native synchronized void keyPressImpl(int keycode);
     private static native synchronized void keyReleaseImpl(int keycode);
 
-    private static native synchronized void getRGBPixelsImpl(X11GraphicsConfig xgc, int x, int y, int width, int height, int pixelArray[]);
+    private static native synchronized void getRGBPixelsImpl(X11GraphicsConfig xgc,
+            int x, int y, int width, int height, int pixelArray[], boolean isGtkSupported);
 }
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c	Mon Aug 10 14:42:07 2015 +0200
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c	Tue Aug 11 16:32:13 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,8 @@
 #include "wsutils.h"
 #include "list.h"
 #include "multiVis.h"
+#include "gtk2_interface.h"
+
 #if defined(__linux__) || defined(MACOSX)
 #include <sys/socket.h>
 #endif
@@ -204,63 +206,135 @@
 Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
                              jclass cls,
                              jobject xgc,
-                             jint x,
-                             jint y,
-                             jint width,
-                             jint height,
-                             jintArray pixelArray) {
-
+                             jint jx,
+                             jint jy,
+                             jint jwidth,
+                             jint jheight,
+                             jintArray pixelArray,
+                             jboolean isGtkSupported) {
     XImage *image;
     jint *ary;               /* Array of jints for sending pixel values back
                               * to parent process.
                               */
     Window rootWindow;
+    XWindowAttributes attr;
     AwtGraphicsConfigDataPtr adata;
 
-    DTRACE_PRINTLN6("RobotPeer: getRGBPixelsImpl(%lx, %d, %d, %d, %d, %x)", xgc, x, y, width, height, pixelArray);
-
-    AWT_LOCK();
+    DTRACE_PRINTLN6("RobotPeer: getRGBPixelsImpl(%lx, %d, %d, %d, %d, %x)", xgc, jx, jy, jwidth, jheight, pixelArray);
 
-    /* avoid a lot of work for empty rectangles */
-    if ((width * height) == 0) {
-        AWT_UNLOCK();
+    if (jwidth <= 0 || jheight <= 0) {
         return;
     }
-    DASSERT(width * height > 0); /* only allow positive size */
 
     adata = (AwtGraphicsConfigDataPtr) JNU_GetLongFieldAsPtr(env, xgc, x11GraphicsConfigIDs.aData);
     DASSERT(adata != NULL);
 
+    AWT_LOCK();
+
     rootWindow = XRootWindow(awt_display, adata->awt_visInfo.screen);
-    image = getWindowImage(awt_display, rootWindow, x, y, width, height);
 
-    /* Array to use to crunch around the pixel values */
-    if (!IS_SAFE_SIZE_MUL(width, height) ||
-        !(ary = (jint *) SAFE_SIZE_ARRAY_ALLOC(malloc, width * height, sizeof (jint))))
-    {
-        JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
-        XDestroyImage(image);
+    if (!XGetWindowAttributes(awt_display, rootWindow, &attr)
+            || jx + jwidth <= attr.x
+            || attr.x + attr.width <= jx
+            || jy + jheight <= attr.y
+            || attr.y + attr.height <= jy) {
+
         AWT_UNLOCK();
-        return;
+        return; // Does not intersect with root window
     }
-    /* convert to Java ARGB pixels */
-    for (y = 0; y < height; y++) {
-        for (x = 0; x < width; x++) {
-            jint pixel = (jint) XGetPixel(image, x, y); /* Note ignore upper
-                                                         * 32-bits on 64-bit
-                                                         * OSes.
-                                                         */
+
+    gboolean gtk_failed = TRUE;
+    jint _x, _y;
+
+    jint x = MAX(jx, attr.x);
+    jint y = MAX(jy, attr.y);
+    jint width = MIN(jx + jwidth, attr.x + attr.width) - x;
+    jint height = MIN(jy + jheight, attr.y + attr.height) - y;
+
+
+    int dx = attr.x > jx ? attr.x - jx : 0;
+    int dy = attr.y > jy ? attr.y - jy : 0;
+
+    int index;
+
+    if (isGtkSupported) {
+        GdkPixbuf *pixbuf;
+        GdkWindow *root = (*fp_gdk_get_default_root_window)();
+
+        pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(NULL, root, NULL,
+                                                    x, y, 0, 0, width, height);
+
+        if (pixbuf) {
+            int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf);
+            int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf);
 
-            pixel |= 0xff000000; /* alpha - full opacity */
+            if ((*fp_gdk_pixbuf_get_width)(pixbuf) == width
+                    && (*fp_gdk_pixbuf_get_height)(pixbuf) == height
+                    && (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf) == 8
+                    && (*fp_gdk_pixbuf_get_colorspace)(pixbuf) == GDK_COLORSPACE_RGB
+                    && nchan >= 3
+                    ) {
+                guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf);
+
+                ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL);
+                if (!ary) {
+                    (*fp_g_object_unref)(pixbuf);
+                    AWT_UNLOCK();
+                    return;
+                }
 
-            ary[(y * width) + x] = pixel;
+                for (_y = 0; _y < height; _y++) {
+                    for (_x = 0; _x < width; _x++) {
+                        p = pix + _y * stride + _x * nchan;
+
+                        index = (_y + dy) * jwidth + (_x + dx);
+                        ary[index] = 0xff000000
+                                        | (p[0] << 16)
+                                        | (p[1] << 8)
+                                        | (p[2]);
+
+                    }
+                }
+                (*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0);
+                if ((*env)->ExceptionCheck(env)) {
+                    (*fp_g_object_unref)(pixbuf);
+                    AWT_UNLOCK();
+                    return;
+                }
+                gtk_failed = FALSE;
+            }
+            (*fp_g_object_unref)(pixbuf);
         }
     }
-    (*env)->SetIntArrayRegion(env, pixelArray, 0, height * width, ary);
-    free(ary);
+
+    if (gtk_failed) {
+        image = getWindowImage(awt_display, rootWindow, x, y, width, height);
+
+        ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL);
+
+        if (!ary) {
+            XDestroyImage(image);
+            AWT_UNLOCK();
+            return;
+        }
 
-    XDestroyImage(image);
+        /* convert to Java ARGB pixels */
+        for (_y = 0; _y < height; _y++) {
+            for (_x = 0; _x < width; _x++) {
+                jint pixel = (jint) XGetPixel(image, _x, _y); /* Note ignore upper
+                                                               * 32-bits on 64-bit
+                                                               * OSes.
+                                                               */
+                pixel |= 0xff000000; /* alpha - full opacity */
 
+                index = (_y + dy) * jwidth + (_x + dx);
+                ary[index] = pixel;
+            }
+        }
+
+        XDestroyImage(image);
+        (*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0);
+    }
     AWT_UNLOCK();
 }
 
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c	Mon Aug 10 14:42:07 2015 +0200
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c	Tue Aug 11 16:32:13 2015 +0300
@@ -203,9 +203,6 @@
         gint, gint, gint, gint);
 static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace,
         gboolean has_alpha, int bits_per_sample, int width, int height);
-static GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest,
-        GdkDrawable *src, GdkColormap *cmap, int src_x, int src_y,
-        int dest_x, int dest_y, int width, int height);
 static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable,
         gint* width, gint* height);
 
@@ -646,6 +643,8 @@
         fp_g_object_set = dl_symbol("g_object_set");
 
         /* GDK */
+        fp_gdk_get_default_root_window =
+            dl_symbol("gdk_get_default_root_window");
         fp_gdk_pixmap_new = dl_symbol("gdk_pixmap_new");
         fp_gdk_pixbuf_get_from_drawable =
             dl_symbol("gdk_pixbuf_get_from_drawable");
@@ -670,6 +669,8 @@
                 dl_symbol("gdk_pixbuf_get_bits_per_sample");
         fp_gdk_pixbuf_get_n_channels =
                 dl_symbol("gdk_pixbuf_get_n_channels");
+        fp_gdk_pixbuf_get_colorspace =
+                dl_symbol("gdk_pixbuf_get_colorspace");
 
         /* GTK painting */
         fp_gtk_init_check = dl_symbol("gtk_init_check");
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h	Mon Aug 10 14:42:07 2015 +0200
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h	Tue Aug 11 16:32:13 2015 +0300
@@ -772,6 +772,8 @@
 
 void (*fp_g_free)(gpointer mem);
 void (*fp_g_object_unref)(gpointer object);
+GdkWindow *(*fp_gdk_get_default_root_window) (void);
+
 int (*fp_gdk_pixbuf_get_bits_per_sample)(const GdkPixbuf *pixbuf);
 guchar *(*fp_gdk_pixbuf_get_pixels)(const GdkPixbuf *pixbuf);
 gboolean (*fp_gdk_pixbuf_get_has_alpha)(const GdkPixbuf *pixbuf);
@@ -780,6 +782,13 @@
 int (*fp_gdk_pixbuf_get_rowstride)(const GdkPixbuf *pixbuf);
 int (*fp_gdk_pixbuf_get_width)(const GdkPixbuf *pixbuf);
 GdkPixbuf *(*fp_gdk_pixbuf_new_from_file)(const char *filename, GError **error);
+GdkColorspace (*fp_gdk_pixbuf_get_colorspace)(const GdkPixbuf *pixbuf);
+
+GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest,
+        GdkDrawable *src, GdkColormap *cmap, int src_x, int src_y,
+        int dest_x, int dest_y, int width, int height);
+
+
 void (*fp_gtk_widget_destroy)(GtkWidget *widget);
 void (*fp_gtk_window_present)(GtkWindow *window);
 void (*fp_gtk_window_move)(GtkWindow *window, gint x, gint y);
--- a/jdk/test/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java	Mon Aug 10 14:42:07 2015 +0200
+++ b/jdk/test/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java	Tue Aug 11 16:32:13 2015 +0300
@@ -46,11 +46,8 @@
     private static Robot robot;
 
     public ShapeNotSetSometimes() throws Exception {
-        EventQueue.invokeAndWait(new Runnable() {
-            public void run() {
-                initializeGUI();
-            }
-        });
+        EventQueue.invokeAndWait(this::initializeGUI);
+        robot.waitForIdle();
     }
 
     private void initializeGUI() {
@@ -119,7 +116,7 @@
     public static void main(String[] args) throws Exception {
         robot = new Robot();
 
-        for(int i = 0; i < 100; i++) {
+        for(int i = 0; i < 50; i++) {
             System.out.println("Attempt " + i);
             new ShapeNotSetSometimes().doTest();
         }
@@ -134,11 +131,7 @@
         robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
         robot.delay(500);
 
-        EventQueue.invokeAndWait(new Runnable() {
-            public void run() {
-                window.requestFocus();
-            }
-        });
+        EventQueue.invokeAndWait(window::requestFocus);
 
         robot.waitForIdle();
         try {
--- a/jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java	Mon Aug 10 14:42:07 2015 +0200
+++ b/jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java	Tue Aug 11 16:32:13 2015 +0300
@@ -100,12 +100,10 @@
         if (!paintComponentCalled) {
             throw new RuntimeException("Test FAILED: panel's paintComponent() method is not called");
         }
+        Thread.sleep(1500);
 
         Color newColor1 = r.getPixelColor(100, 100);
-        // unfortunately, robot.getPixelColor() doesn't work for some unknown reason
-        // Color newColor2 = r.getPixelColor(200, 200);
-        BufferedImage bim = r.createScreenCapture(new Rectangle(200, 200, 1, 1));
-        Color newColor2 = new Color(bim.getRGB(0, 0));
+        Color newColor2 = r.getPixelColor(200, 200);
 
         // Frame must be transparent at (100, 100) in screen coords
         if (!color1.equals(newColor1)) {
--- a/jdk/test/javax/swing/JComponent/6683775/bug6683775.java	Mon Aug 10 14:42:07 2015 +0200
+++ b/jdk/test/javax/swing/JComponent/6683775/bug6683775.java	Tue Aug 11 16:32:13 2015 +0300
@@ -31,13 +31,15 @@
 */
 
 import com.sun.awt.AWTUtilities;
-import sun.awt.SunToolkit;
 
 import javax.swing.*;
 import java.awt.*;
 import java.awt.image.BufferedImage;
 
 public class bug6683775 {
+    static final int LOC = 100,
+            SIZE = 200;
+
     public static void main(String[] args) throws Exception {
         GraphicsConfiguration gc = getGC();
        if (!AWTUtilities.isTranslucencySupported(
@@ -45,39 +47,37 @@
                 || gc == null) {
             return;
         }
-        SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
         Robot robot = new Robot();
         final JFrame testFrame = new JFrame(gc);
 
-        SwingUtilities.invokeLater(new Runnable() {
-            public void run() {
-                JFrame backgroundFrame = new JFrame("Background frame");
-                backgroundFrame.setUndecorated(true);
-                JPanel panel = new JPanel();
-                panel.setBackground(Color.RED);
-                backgroundFrame.add(panel);
-                backgroundFrame.setSize(200, 200);
-                backgroundFrame.setVisible(true);
+        SwingUtilities.invokeAndWait(() -> {
+            JFrame backgroundFrame = new JFrame("Background frame");
+            backgroundFrame.setUndecorated(true);
+            JPanel panel = new JPanel();
+            panel.setBackground(Color.RED);
+            backgroundFrame.add(panel);
+            backgroundFrame.setBounds(LOC, LOC, SIZE, SIZE);
+            backgroundFrame.setVisible(true);
 
-                testFrame.setUndecorated(true);
-                JPanel p = new JPanel();
-                p.setOpaque(false);
-                testFrame.add(p);
-                AWTUtilities.setWindowOpaque(testFrame, false);
-                testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-                testFrame.setSize(400, 400);
-                testFrame.setLocation(0, 0);
-                testFrame.setVisible(true);
-            }
+            testFrame.setUndecorated(true);
+            JPanel p = new JPanel();
+            p.setOpaque(false);
+            testFrame.add(p);
+            AWTUtilities.setWindowOpaque(testFrame, false);
+            testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+            testFrame.setBounds(LOC, LOC, SIZE, SIZE);
+            testFrame.setVisible(true);
         });
 
-        toolkit.realSync();
+        robot.waitForIdle();
+        Thread.sleep(1500);
 
         //robot.getPixelColor() didn't work right for some reason
-        BufferedImage capture = robot.createScreenCapture(new Rectangle(100, 100));
+        BufferedImage capture =
+                robot.createScreenCapture(new Rectangle(LOC, LOC, SIZE, SIZE));
 
         int redRGB = Color.RED.getRGB();
-        if (redRGB != capture.getRGB(10, 10)) {
+        if (redRGB != capture.getRGB(SIZE/2, SIZE/2)) {
             throw new RuntimeException("Transparent frame is not transparent!");
         }
     }