From c584705096f8ccd38c0bbc72ce9e89afe2af3e5c Mon Sep 17 00:00:00 2001 From: Mario Torre Date: Mon, 11 Jul 2016 16:52:50 +0200 Subject: [PATCH] 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 --- jdk/make/mapfiles/libawt_xawt/mapfile-vers | 1 + .../unix/classes/sun/awt/X11/XRobotPeer.java | 24 ++++-- .../unix/native/libawt_xawt/awt/awt_Robot.c | 84 ++++++++++++++++++- 3 files changed, 100 insertions(+), 9 deletions(-) diff --git a/jdk/make/mapfiles/libawt_xawt/mapfile-vers b/jdk/make/mapfiles/libawt_xawt/mapfile-vers index b56fad43b4f..461c1ba9f48 100644 --- a/jdk/make/mapfiles/libawt_xawt/mapfile-vers +++ b/jdk/make/mapfiles/libawt_xawt/mapfile-vers @@ -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; 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 368d034687e..10b28cdfafb 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 @@ -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); 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 0e06972207f..41bb1004a91 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 @@ -27,6 +27,9 @@ #error This file should not be included in headless library #endif +#include "jvm_md.h" +#include + #include "awt_p.h" #include "awt_GraphicsEnv.h" #define XK_MISCELLANY @@ -50,11 +53,46 @@ #include #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(); +}