From 23438be9c4fa8974f5c8cd78712df942ce1b0d06 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 11 Aug 2015 16:32:13 +0300 Subject: [PATCH] 8014212: Robot captures black screen Reviewed-by: alexsch, serb --- .../unix/classes/sun/awt/X11/XRobotPeer.java | 35 ++++- .../unix/native/libawt_xawt/awt/awt_Robot.c | 142 +++++++++++++----- .../native/libawt_xawt/awt/gtk2_interface.c | 7 +- .../native/libawt_xawt/awt/gtk2_interface.h | 9 ++ .../ShapeNotSetSometimes.java | 15 +- .../TranslucentJAppletTest.java | 6 +- .../swing/JComponent/6683775/bug6683775.java | 48 +++--- 7 files changed, 179 insertions(+), 83 deletions(-) diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java index 340c80bee5f..4a3554816d1 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java @@ -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 @@ class XRobotPeer implements RobotPeer { 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 @@ class XRobotPeer implements RobotPeer { 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); } diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c index 89f282c3db4..77aa8840b58 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c @@ -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 #endif @@ -204,63 +206,135 @@ JNIEXPORT void JNICALL 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); + DTRACE_PRINTLN6("RobotPeer: getRGBPixelsImpl(%lx, %d, %d, %d, %d, %x)", xgc, jx, jy, jwidth, jheight, pixelArray); - AWT_LOCK(); - - /* 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. - */ - pixel |= 0xff000000; /* alpha - full opacity */ + gboolean gtk_failed = TRUE; + jint _x, _y; - ary[(y * width) + x] = pixel; + 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); + + 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; + } + + 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); - XDestroyImage(image); + 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; + } + + /* 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(); } diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c index 84e2df3bdf4..6ef926e749a 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c @@ -203,9 +203,6 @@ static void (*fp_gdk_draw_rectangle)(GdkDrawable*, GdkGC*, gboolean, 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 @@ gboolean gtk2_load(JNIEnv *env) 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 @@ gboolean gtk2_load(JNIEnv *env) 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"); diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h index 0150f9347bb..06cf8bd5261 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h @@ -772,6 +772,8 @@ void gtk2_set_range_value(WidgetType widget_type, jdouble value, 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_n_channels)(const GdkPixbuf *pixbuf); 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); diff --git a/jdk/test/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java b/jdk/test/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java index 751b38e338b..af9c3616043 100644 --- a/jdk/test/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java +++ b/jdk/test/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java @@ -46,11 +46,8 @@ public class ShapeNotSetSometimes { 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 class ShapeNotSetSometimes { 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 @@ public class ShapeNotSetSometimes { 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 { diff --git a/jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java b/jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java index 330a08e92fe..de908c47308 100644 --- a/jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java +++ b/jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java @@ -100,12 +100,10 @@ public class TranslucentJAppletTest { 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)) { diff --git a/jdk/test/javax/swing/JComponent/6683775/bug6683775.java b/jdk/test/javax/swing/JComponent/6683775/bug6683775.java index ba627d183af..d0b8eac98f8 100644 --- a/jdk/test/javax/swing/JComponent/6683775/bug6683775.java +++ b/jdk/test/javax/swing/JComponent/6683775/bug6683775.java @@ -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 @@ public class bug6683775 { || 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!"); } }