JDK-6903034 : java.awt.Robot.createScreenCapture() doesn't work for translucent windows
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6u24,7
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,linux
  • CPU: generic,x86
  • Submitted: 2009-11-19
  • Updated: 2014-08-11
  • Resolved: 2011-04-21
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b138Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
During investigation of the CR #6848852 it was discovered that method
java.awt.Robot.createScreenCapture() doesn't work if a translucent java window
is shown. It happens only on Linux.

Please use the following regression test to reproduce:
test/javax/swing/JComponent/6683775/bug6683775.java

Note that this test works only if there is no toolbar on the top of the workspace,
to make the test work in this case this line:
BufferedImage capture = robot.createScreenCapture(new Rectangle(100, 100));

should be fixed to capture the rectangle with the backgroundFrame's bounds
TCK team has requested the release team to look at this bug again as it affects TCK tests. Andrey, please look at this bug and give an estimate on what it takes to fix this?

Comments
This fix was backed out from the workspace, see 7043455 for details.
06-08-2013

SUGGESTED FIX --- old/src/solaris/native/sun/awt/awt_Robot.c 2011-03-29 14:38:52.000000000 +0400 +++ new/src/solaris/native/sun/awt/awt_Robot.c 2011-03-29 14:38:52.000000000 +0400 @@ -48,6 +48,7 @@ #ifdef __linux__ #include <sys/socket.h> #endif +#include <dlfcn.h> extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs; @@ -196,6 +197,68 @@ AWT_UNLOCK(); } +static void* xcompositeLibHandle = NULL; + +typedef Status (*T_XCompositeQueryVersion)(Display *dpy, int *major_versionp, int *minor_versionp); +typedef Window (*T_XCompositeGetOverlayWindow)(Display *dpy, Window window); +typedef void (*T_XCompositeReleaseOverlayWindow)(Display *dpy, Window window); + +static T_XCompositeQueryVersion XCompositeQueryVersion = NULL; +static T_XCompositeGetOverlayWindow XCompositeGetOverlayWindow = NULL; +static T_XCompositeReleaseOverlayWindow XCompositeReleaseOverlayWindow = NULL; + +/* + * Returns True only if XCOMPOSITE is of version 0.3 or higher. + * The functions that we need are available since that version. + * + * Must be invoked under AWT_LOCK. + * + * Leaves the library loaded if the version is correct. + */ +static Bool IsXCompositeAvailable() +{ + static Bool xcompositeExtAvailable = False; + static Bool tested = False; + + if (!tested) { + int opcode, eventb, errorb; + + if (XQueryExtension(awt_display, "Composite", &opcode, &eventb, &errorb)) { + xcompositeLibHandle = dlopen("libXcomposite.so.1", RTLD_LAZY | RTLD_GLOBAL); +#ifndef __linux__ /* SOLARIS */ + if (xcompositeLibHandle == NULL) { + xcompositeLibHandle = dlopen("/usr/sfw/lib/libXcomposite.so.1", + RTLD_LAZY | RTLD_GLOBAL); + } +#endif + + if (xcompositeLibHandle) { + int major, minor; + XCompositeQueryVersion = (T_XCompositeQueryVersion)dlsym(xcompositeLibHandle, "XCompositeQueryVersion"); + + if (XCompositeQueryVersion && XCompositeQueryVersion(awt_display, &major, &minor)) { + if (major >= 0 && minor >= 3) { + XCompositeGetOverlayWindow = (T_XCompositeGetOverlayWindow)dlsym(xcompositeLibHandle, "XCompositeGetOverlayWindow"); + XCompositeReleaseOverlayWindow = (T_XCompositeReleaseOverlayWindow)dlsym(xcompositeLibHandle, "XCompositeReleaseOverlayWindow"); + + if (XCompositeGetOverlayWindow && XCompositeReleaseOverlayWindow) { + xcompositeExtAvailable = True; + } + } + } + + if (!xcompositeExtAvailable) { + // Note: we don't unload it if it's version 0.3 or higher and contains necessary functions + dlclose(xcompositeLibHandle); + } + } + } + + tested = True; + } + + return xcompositeExtAvailable; +} JNIEXPORT void JNICALL Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, @@ -211,7 +274,7 @@ jint *ary; /* Array of jints for sending pixel values back * to parent process. */ - Window rootWindow; + Window window; AwtGraphicsConfigDataPtr adata; DTRACE_PRINTLN6("RobotPeer: getRGBPixelsImpl(%lx, %d, %d, %d, %d, %x)", xgc, x, y, width, height, pixelArray); @@ -228,14 +291,24 @@ adata = (AwtGraphicsConfigDataPtr) JNU_GetLongFieldAsPtr(env, xgc, x11GraphicsConfigIDs.aData); DASSERT(adata != NULL); - rootWindow = XRootWindow(awt_display, adata->awt_visInfo.screen); - image = getWindowImage(awt_display, rootWindow, x, y, width, height); + window = XRootWindow(awt_display, adata->awt_visInfo.screen); + + if (IsXCompositeAvailable()) { + // Use 'composite overlay window' instead of the root window. + // See 6903034 for details. + window = XCompositeGetOverlayWindow(awt_display, window); + } + + image = getWindowImage(awt_display, window, x, y, width, height); /* Array to use to crunch around the pixel values */ ary = (jint *) malloc(width * height * sizeof (jint)); if (ary == NULL) { JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); XDestroyImage(image); + if (IsXCompositeAvailable()) { + XCompositeReleaseOverlayWindow(awt_display, window); + } AWT_UNLOCK(); return; } @@ -256,6 +329,9 @@ free(ary); XDestroyImage(image); + if (IsXCompositeAvailable()) { + XCompositeReleaseOverlayWindow(awt_display, window); + } AWT_UNLOCK(); }
29-03-2011

EVALUATION The spec of the composite extension and some details are available at: http://cgit.freedesktop.org/xorg/proto/compositeproto/plain/compositeproto.txt and http://freedesktop.org/wiki/Software/TranslucentWindows?highlight=%28compositing%29%7C%28manager%29
29-03-2011

EVALUATION In case the XCOMPOSITE extension is available, the screenshot should be taken on the 'composite overlay window' (see XCompositeGetOverlayWindow()) rather than the root window of the display. Note that this procedure works fine even if the visual effects are disabled in the User Settings.
28-03-2011

EVALUATION gnome-screenshot, however, works perfectly.
01-10-2010

EVALUATION Unfortunately even the latest xwd utility captures the areas occupied by non-opaqe windows as black rectangles.
01-10-2010

EVALUATION The XRobot uses the GetMultiVisualRegions() and ReadAreaToImage() functions, which have been copied from the xwd source files (see src/solaris/native/sun/awt/awt_Robot.c and multiVis.c). This has happened some time ago, and the old versions might not have been aware of non-opaque windows. We need to try and get newer xwd, and see if it works correctly nowdays.
29-09-2010