8150954: Taking screenshots on x11 composite desktop produce wrong result

The AWT Robot X11 code that takes screenshots uses the default root window, which may not contain the final composited desktop.

Reviewed-by: alexsch, ssadetsky
This commit is contained in:
Mario Torre 2016-07-11 16:52:50 +02:00
parent 653531139e
commit c584705096
3 changed files with 100 additions and 9 deletions
jdk
make/mapfiles/libawt_xawt
src/java.desktop/unix
classes/sun/awt/X11
native/libawt_xawt/awt

@ -164,6 +164,7 @@ SUNWprivate_1.1 {
Java_sun_awt_X11_XRobotPeer_mouseReleaseImpl;
Java_sun_awt_X11_XRobotPeer_mouseWheelImpl;
Java_sun_awt_X11_XRobotPeer_setup;
Java_sun_awt_X11_XRobotPeer_loadNativeLibraries;
Java_sun_awt_X11_XToolkit_getNumberOfButtonsImpl;
Java_java_awt_Component_initIDs;
Java_java_awt_Container_initIDs;

@ -35,8 +35,16 @@ import sun.awt.X11GraphicsEnvironment;
class XRobotPeer implements RobotPeer {
private static volatile boolean isGtkSupported;
static final boolean tryGtk;
static {
loadNativeLibraries();
tryGtk = Boolean.getBoolean("awt.robot.gtk");
}
private static boolean isGtkSupported = false;
private static volatile boolean useGtk;
private X11GraphicsConfig xgc = null;
/*
* native implementation uses some static shared data (pipes, processes)
* so use a class lock to synchronize native method calls
@ -49,13 +57,14 @@ class XRobotPeer implements RobotPeer {
setup(tk.getNumberOfButtons(),
AWTAccessor.getInputEventAccessor().getButtonDownMasks());
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (!isGtkSupported) {
if (toolkit instanceof UNIXToolkit
&& ((UNIXToolkit) toolkit).loadGTK()) {
boolean isGtkSupported = false;
if (tryGtk) {
if (tk instanceof UNIXToolkit && ((UNIXToolkit) tk).loadGTK()) {
isGtkSupported = true;
}
}
useGtk = (tryGtk && isGtkSupported);
}
@Override
@ -104,7 +113,7 @@ class XRobotPeer implements RobotPeer {
public int getRGBPixel(int x, int y) {
int pixelArray[] = new int[1];
getRGBPixelsImpl(xgc, x, y, 1, 1, xgc.getScale(), pixelArray,
isGtkSupported);
useGtk);
return pixelArray[0];
}
@ -112,11 +121,12 @@ class XRobotPeer implements RobotPeer {
public int [] getRGBPixels(Rectangle bounds) {
int pixelArray[] = new int[bounds.width*bounds.height];
getRGBPixelsImpl(xgc, bounds.x, bounds.y, bounds.width, bounds.height,
xgc.getScale(), pixelArray, isGtkSupported);
xgc.getScale(), pixelArray, useGtk);
return pixelArray;
}
private static synchronized native void setup(int numberOfButtons, int[] buttonDownMasks);
private static native void loadNativeLibraries();
private static synchronized native void mouseMoveImpl(X11GraphicsConfig xgc, int x, int y);
private static synchronized native void mousePressImpl(int buttons);

@ -27,6 +27,9 @@
#error This file should not be included in headless library
#endif
#include "jvm_md.h"
#include <dlfcn.h>
#include "awt_p.h"
#include "awt_GraphicsEnv.h"
#define XK_MISCELLANY
@ -50,11 +53,46 @@
#include <sys/socket.h>
#endif
static Bool (*compositeQueryExtension) (Display*, int*, int*);
static Status (*compositeQueryVersion) (Display*, int*, int*);
static Window (*compositeGetOverlayWindow) (Display *, Window);
extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs;
static jint * masks;
static jint num_buttons;
static void *xCompositeHandle;
static const char* XCOMPOSITE = JNI_LIB_NAME("Xcomposite");
static const char* XCOMPOSITE_VERSIONED = VERSIONED_JNI_LIB_NAME("Xcomposite", "1");
static Bool checkXCompositeFunctions(void) {
return (compositeQueryExtension != NULL &&
compositeQueryVersion != NULL &&
compositeGetOverlayWindow != NULL);
}
static void initXCompositeFunctions(void) {
if (xCompositeHandle == NULL) {
xCompositeHandle = dlopen(XCOMPOSITE, RTLD_LAZY | RTLD_GLOBAL);
if (xCompositeHandle == NULL) {
xCompositeHandle = dlopen(XCOMPOSITE_VERSIONED, RTLD_LAZY | RTLD_GLOBAL);
}
}
//*(void **)(&asyncGetCallTraceFunction)
if (xCompositeHandle != NULL) {
*(void **)(&compositeQueryExtension) = dlsym(xCompositeHandle, "XCompositeQueryExtension");
*(void **)(&compositeQueryVersion) = dlsym(xCompositeHandle, "XCompositeQueryVersion");
*(void **)(&compositeGetOverlayWindow) = dlsym(xCompositeHandle, "XCompositeGetOverlayWindow");
}
if (xCompositeHandle && !checkXCompositeFunctions()) {
dlclose(xCompositeHandle);
}
}
static int32_t isXTestAvailable() {
int32_t major_opcode, first_event, first_error;
int32_t event_basep, error_basep, majorp, minorp;
@ -89,6 +127,35 @@ static int32_t isXTestAvailable() {
return isXTestAvailable;
}
static Bool hasXCompositeOverlayExtension(Display *display) {
int xoverlay = False;
int eventBase, errorBase;
if (checkXCompositeFunctions() &&
compositeQueryExtension(display, &eventBase, &errorBase))
{
int major = 0;
int minor = 0;
compositeQueryVersion(display, &major, &minor);
if (major > 0 || minor >= 3) {
xoverlay = True;
}
}
return xoverlay;
}
static jboolean isXCompositeDisplay(Display *display, int screenNumber) {
char NET_WM_CM_Sn[25];
snprintf(NET_WM_CM_Sn, sizeof(NET_WM_CM_Sn), "_NET_WM_CM_S%d\0", screenNumber);
Atom managerSelection = XInternAtom(display, NET_WM_CM_Sn, 0);
Window owner = XGetSelectionOwner(display, managerSelection);
return owner != 0;
}
static XImage *getWindowImage(Display * display, Window window,
int32_t x, int32_t y,
@ -211,7 +278,7 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
jint jheight,
jint scale,
jintArray pixelArray,
jboolean isGtkSupported) {
jboolean useGtk) {
XImage *image;
jint *ary; /* Array of jints for sending pixel values back
* to parent process.
@ -238,6 +305,14 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
rootWindow = XRootWindow(awt_display, adata->awt_visInfo.screen);
if (!useGtk) {
if (hasXCompositeOverlayExtension(awt_display) &&
isXCompositeDisplay(awt_display, adata->awt_visInfo.screen))
{
rootWindow = compositeGetOverlayWindow(awt_display, rootWindow);
}
}
if (!XGetWindowAttributes(awt_display, rootWindow, &attr)
|| sx + swidth <= attr.x
|| attr.x + attr.width <= sx
@ -262,7 +337,7 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
int index;
if (isGtkSupported) {
if (useGtk) {
gtk->gdk_threads_enter();
gtk_failed = gtk->get_drawable_data(env, pixelArray, x, y, width,
height, jwidth, dx, dy, scale);
@ -454,3 +529,8 @@ Java_sun_awt_X11_XRobotPeer_mouseWheelImpl (JNIEnv *env,
AWT_UNLOCK();
}
JNIEXPORT void JNICALL
Java_sun_awt_X11_XRobotPeer_loadNativeLibraries (JNIEnv *env, jclass cls) {
initXCompositeFunctions();
}