--- old/make/sun/xawt/mapfile-vers 2009-08-11 19:21:07.000000000 +0400 +++ new/make/sun/xawt/mapfile-vers 2009-08-11 19:21:06.000000000 +0400 @@ -96,6 +96,7 @@ Java_sun_awt_X11_XlibWrapper_SetBitmapShape; Java_sun_awt_X11_XlibWrapper_XConfigureWindow; Java_sun_awt_X11_XlibWrapper_SetZOrder; + Java_sun_awt_X11_XlibWrapper_CheckIfEvent; Java_sun_awt_X11_XToolkit_initIDs; Java_sun_awt_X11_XWindow_getNativeColor; Java_sun_awt_X11_XWindow_getWMInsets; --- old/src/share/classes/java/awt/Component.java 2009-08-11 19:21:08.000000000 +0400 +++ new/src/share/classes/java/awt/Component.java 2009-08-11 19:21:07.000000000 +0400 @@ -658,6 +658,14 @@ return objectLock; } + /** + * Indicates if the window has been packed via pack(). + * + * Note that this field belongs to the Window class, but it cannot be + * moved to that class because it is not transient, and therefore must + * stay at the Component class for backward-compatibility purposes. + * The field SHOULD NOT be used anywhere outside of the Window class. + */ boolean isPacked = false; /** @@ -1556,8 +1564,6 @@ */ @Deprecated public void hide() { - isPacked = false; - if (visible) { clearCurrentFocusCycleRootOnHide(); clearMostRecentFocusOwnerOnHide(); @@ -2114,10 +2120,6 @@ this.width = width; this.height = height; - if (resized) { - isPacked = false; - } - boolean needNotify = true; mixOnReshaping(); if (peer != null) { --- old/src/share/classes/java/awt/Window.java 2009-08-11 19:21:09.000000000 +0400 +++ new/src/share/classes/java/awt/Window.java 2009-08-11 19:21:09.000000000 +0400 @@ -764,7 +764,7 @@ setClientSize(newSize.width, newSize.height); } - if(beforeFirstShow) { + if (beforeFirstShow) { isPacked = true; } @@ -866,7 +866,12 @@ height = minSize.height; } } - super.reshape(x, y, width, height); + synchronized (getTreeLock()) { + if (this.width != width || this.height != height) { + isPacked = false; + } + super.reshape(x, y, width, height); + } } void setClientSize(int w, int h) { @@ -1014,7 +1019,10 @@ * {@link #setVisible(boolean)}. */ @Deprecated + @Override public void hide() { + isPacked = false; + synchronized(ownedWindowList) { for (int i = 0; i < ownedWindowList.size(); i++) { Window child = ownedWindowList.elementAt(i).get(); @@ -3797,6 +3805,10 @@ { return window.calculateSecurityWarningPosition(x, y, w, h); } + + public boolean isPacked(Window window) { + return window.isPacked; + } }); // WindowAccessor } // static --- old/src/share/classes/sun/awt/AWTAccessor.java 2009-08-11 19:21:11.000000000 +0400 +++ new/src/share/classes/sun/awt/AWTAccessor.java 2009-08-11 19:21:10.000000000 +0400 @@ -153,6 +153,10 @@ */ Point2D calculateSecurityWarningPosition(Window window, double x, double y, double w, double h); + /** + * Indicates whether the window has been packed via pack(). + */ + boolean isPacked(Window window); } /* --- old/src/share/classes/sun/awt/ComponentAccessor.java 2009-08-11 19:21:12.000000000 +0400 +++ new/src/share/classes/sun/awt/ComponentAccessor.java 2009-08-11 19:21:11.000000000 +0400 @@ -70,7 +70,6 @@ private static Field fieldBackground; private static Field fieldForeground; private static Field fieldFont; - private static Field fieldPacked; private static Field fieldIgnoreRepaint; private static Field fieldPeer; private static Field fieldVisible; @@ -115,8 +114,6 @@ fieldParent = componentClass.getDeclaredField("parent"); fieldParent.setAccessible(true); - fieldPacked = componentClass.getDeclaredField("isPacked"); - fieldPacked.setAccessible(true); fieldIgnoreRepaint = componentClass.getDeclaredField("ignoreRepaint"); fieldIgnoreRepaint.setAccessible(true); @@ -252,17 +249,6 @@ return 0; } - public static boolean getIsPacked(Component c) { - try { - return fieldPacked.getBoolean(c); - } - catch (IllegalAccessException e) - { - log.log(Level.FINE, "Unable to access the Component object", e); - } - return false; - } - public static Container getParent_NoClientCode(Component c) { Container parent=null; --- old/src/solaris/classes/sun/awt/X11/WindowDimensions.java 2009-08-11 19:21:13.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/WindowDimensions.java 2009-08-11 19:21:12.000000000 +0400 @@ -73,7 +73,7 @@ public WindowDimensions(final WindowDimensions dims) { this.loc = new Point(dims.loc); this.size = new Dimension(dims.size); - this.insets = (dims.insets != null)?((Insets)dims.insets.clone()):new Insets(0, 0, 0, 0); + this.insets = cloneOrZero(dims.insets); this.isClientSizeSet = dims.isClientSizeSet; } @@ -116,7 +116,7 @@ } public Insets getInsets() { - return (Insets)insets.clone(); + return cloneOrZero(insets); } public Rectangle getBounds() { if (isClientSizeSet) { @@ -145,7 +145,7 @@ } public void setInsets(Insets in) { - insets = (in != null)?((Insets)in.clone()):new Insets(0, 0, 0, 0); + insets = cloneOrZero(in); if (!isClientSizeSet) { if (size.width < (insets.left+insets.right)) { size.width = (insets.left+insets.right); @@ -177,4 +177,9 @@ public int hashCode() { return ((insets == null)? (0):(insets.hashCode())) ^ getClientRect().hashCode() ^ getBounds().hashCode(); } + + private static Insets cloneOrZero(Insets insets) { + return insets == null ? new Insets(0, 0, 0, 0) : + (Insets)insets.clone(); + } } --- old/src/solaris/classes/sun/awt/X11/XBaseWindow.java 2009-08-11 19:21:14.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XBaseWindow.java 2009-08-11 19:21:14.000000000 +0400 @@ -59,7 +59,7 @@ private XCreateWindowParams delayedParams; Set children = new HashSet(); - long window; + long window = XConstants.None; boolean visible; boolean mapped; boolean embedded; @@ -332,7 +332,13 @@ } Long parentWindow = (Long)params.get(PARENT_WINDOW); + Rectangle bounds = (Rectangle)params.get(BOUNDS); + this.x = bounds.x; + this.y = bounds.y; + this.width = bounds.width; + this.height = bounds.height; + Integer depth = (Integer)params.get(DEPTH); Integer visual_class = (Integer)params.get(VISUAL_CLASS); Long visual = (Long)params.get(VISUAL); @@ -923,10 +929,14 @@ // -------------- Event handling ---------------- public void handleMapNotifyEvent(XEvent xev) { - mapped = true; + if (xev.get_xany().get_window() == getWindow()) { + mapped = true; + } } public void handleUnmapNotifyEvent(XEvent xev) { - mapped = false; + if (xev.get_xany().get_window() == getWindow()) { + mapped = false; + } } public void handleReparentNotifyEvent(XEvent xev) { if (eventLog.isLoggable(Level.FINER)) { @@ -1026,6 +1036,11 @@ XConfigureEvent xe = xev.get_xconfigure(); insLog.log(Level.FINER, "Configure, {0}", new Object[] {xe}); + + if (xe.get_window() != getWindow()) { + return; + } + x = xe.get_x(); y = xe.get_y(); width = xe.get_width(); --- old/src/solaris/classes/sun/awt/X11/XComponentPeer.java 2009-08-11 19:21:15.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XComponentPeer.java 2009-08-11 19:21:15.000000000 +0400 @@ -800,15 +800,6 @@ public void endValidate() { } - - /** - * DEPRECATED: Replaced by getInsets(). - */ - - public Insets insets() { - return getInsets(); - } - // Returns true if we are inside begin/endLayout and // are waiting for native painting public boolean isPaintPending() { --- old/src/solaris/classes/sun/awt/X11/XContentWindow.java 2009-08-11 19:21:16.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XContentWindow.java 2009-08-11 19:21:16.000000000 +0400 @@ -105,8 +105,12 @@ } } - // Coordinates are that of the shell - void setContentBounds(WindowDimensions dims) { + /** + * Sets content window bounds. + * + * @return whether a COMPONENT_RESIZED event has been sent + */ + boolean setContentBounds(WindowDimensions dims) { XToolkit.awtLock(); try { // Bounds of content window are of the same size as bounds of Java window and with @@ -127,10 +131,11 @@ insLog.fine("Sending RESIZED"); handleResize(newBounds); } + validateSurface(); + return needHandleResize; } finally { XToolkit.awtUnlock(); } - validateSurface(); } // NOTE: This method may be called by privileged threads. --- old/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java 2009-08-11 19:21:18.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java 2009-08-11 19:21:17.000000000 +0400 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. 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 @@ -33,6 +33,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import sun.awt.AWTAccessor; import sun.awt.ComponentAccessor; import sun.awt.SunToolkit; @@ -42,15 +43,19 @@ private static final Logger focusLog = Logger.getLogger("sun.awt.X11.focus.XDecoratedPeer"); private static final Logger iconLog = Logger.getLogger("sun.awt.X11.icon.XDecoratedPeer"); - // Set to true when we get the first ConfigureNotify after being - // reparented - indicates that WM has adopted the top-level. - boolean configure_seen; - boolean insets_corrected; - XIconWindow iconWindow; - WindowDimensions dimensions; + + /** + * The dimensions of the window. + * + * The entity encapsulates information about the bounds and the insets of + * the window. The value is initialized in the preInit() method with the + * bounds of the window as known on the shared level. Further updates + * should be performed with the reportReshape() method only. + */ + protected WindowDimensions dimensions; + XContentWindow content; - Insets currentInsets; XFocusProxyWindow focusProxy; XDecoratedPeer(Window target) { @@ -73,11 +78,8 @@ super.preInit(params); winAttr.initialFocus = true; - currentInsets = new Insets(0,0,0,0); - applyGuessedInsets(); - Rectangle bounds = (Rectangle)params.get(BOUNDS); - dimensions = new WindowDimensions(bounds, getRealInsets(), false); + dimensions = new WindowDimensions(bounds, getNativeInsets(), false); params.put(BOUNDS, dimensions.getClientRect()); insLog.log(Level.FINE, "Initial dimensions {0}", new Object[] { dimensions }); @@ -93,7 +95,6 @@ // happen after the X window is created. initResizability(); updateSizeHints(dimensions); - XWM.requestWMExtents(getWindow()); content = XContentWindow.createContent(this); @@ -116,14 +117,13 @@ public void updateMinimumSize() { super.updateMinimumSize(); - updateMinSizeHints(); + updateMinSizeHints(getNativeInsets()); } - private void updateMinSizeHints() { + private void updateMinSizeHints(Insets insets) { if (isResizable()) { Dimension minimumSize = getTargetMinimumSize(); if (minimumSize != null) { - Insets insets = getRealInsets(); int minWidth = minimumSize.width - insets.left - insets.right; int minHeight = minimumSize.height - insets.top - insets.bottom; if (minWidth < 0) minWidth = 0; @@ -231,208 +231,276 @@ * I N S E T S C O D E **************************************************************************************/ - protected boolean isInitialReshape() { - return false; + + /** + * Current native insets of the window on the desktop. + * When it's noticed the insets might have been changed (like when we + * receive a ReparentNotify), the value must be reset to null by the + * setNativeInsets(null) call. + * + * Synchronization: the awtLock is used. This should have been the state + * lock instead, but the retrieveNativeInsets() uses the awtLock, and the + * later must be always taken before the state lock. + * + * The field MUST NOT be used directly. Use get/setNativeInsets() instead. + */ + private Insets nativeInsets = null; + + /** + * Gets the current native insets. + * This method may only return null if the fallBackToDefault is false. + */ + private Insets getNativeInsets(boolean retrieve, boolean fallBackToDefault) { + if (isTargetUndecorated() || isEmbedded() || !XWM.isRunning()) + { + return (Insets)ZERO_INSETS.clone(); + } + if (getWindow() == XConstants.None) { + return getDefaultInsets(); + } + XToolkit.awtLock(); + try { + if (nativeInsets == null && retrieve) { + retrieveNativeInsets(); + } + return nativeInsets == null ? + (fallBackToDefault ? getDefaultInsets() : null) : + (Insets)nativeInsets.clone(); + } finally { + XToolkit.awtUnlock(); + } + } + + /** + * Gets the current native insets. + */ + public Insets getNativeInsets() { + return getNativeInsets(true, true); + } + + @Override + public Insets getInsets() { + Insets insets = getNativeInsets(); + insets.top += getMenuBarHeight(); + if (insLog.isLoggable(Level.FINEST)) { + insLog.log(Level.FINEST, "Get insets returns {0}", + new Object[] {insets}); + } + return insets; } - private static Insets difference(Insets i1, Insets i2) { - return new Insets(i1.top-i2.top, i1.left - i2.left, i1.bottom-i2.bottom, i1.right-i2.right); + /** + * Returns the insets that the window probably will get. + */ + private Insets getDefaultInsets() { + Insets insets = XWM.getWM().getDefaultInsets(); + return (Insets)(insets == null ? DEFAULT_INSETS : insets).clone(); } - private static boolean isNull(Insets i) { - return (i == null) || ((i.left | i.top | i.right | i.bottom) == 0); + /** + * Get rid of insane insets. + * The operation is performed in place - the given object gets modified. + */ + private static Insets sanitize(Insets insets) { + //XXX: Perhaps using the marginal values instead of the default would + // make more sense? + if (insets.top > 64 || insets.top < 0) { + insets.top = DEFAULT_INSETS.top; + } + if (insets.left > 32 || insets.left < 0) { + insets.left = DEFAULT_INSETS.left; + } + if (insets.right > 32 || insets.right < 0) { + insets.right = DEFAULT_INSETS.right; + } + if (insets.bottom > 32 || insets.bottom < 0) { + insets.bottom = DEFAULT_INSETS.bottom; + } + return insets; } - private static Insets copy(Insets i) { - return new Insets(i.top, i.left, i.bottom, i.right); + private void setNativeInsets(Insets insets) { + XToolkit.awtLock(); + try { + nativeInsets = insets == null ? null : + sanitize((Insets)insets.clone()); + } finally { + XToolkit.awtUnlock(); + } } - // insets which we get from WM (e.g from _NET_FRAME_EXTENTS) - private Insets wm_set_insets; + public static final Insets DEFAULT_INSETS = new Insets(25, 5, 5, 5); + public static final Insets ZERO_INSETS = new Insets(0, 0, 0, 0); - private Insets getWMSetInsets(XAtom changedAtom) { - if (isEmbedded()) { - return null; + /** + * Retrieve the current insets of the window. + * + * This method must only be called by the getNativeInsets() method. DO NOT + * call this method directly. If the insets need to be updated, nullify + * them using the setNativeInsets(null) method. + */ + private void retrieveNativeInsets() { + long window = getWindow(); + + if (XWM.requestWMExtents(window)) { + XWM.waitForExtentsUpdateEvent(); } - if (wm_set_insets != null) { - return wm_set_insets; + // Some WMs may provide the extents via a property, but do not require + // a request to update them. Hence try getting them unconditionally. + // We could use the XEvent returned by the waitForExtentsUpdateEvent() + // above, though that doesn't seem to make much sense. + Insets insets = XWM.getInsetsFromExtents(window); + if (insets != null) { + setNativeInsets(insets); + return; } - if (changedAtom == null) { - wm_set_insets = XWM.getInsetsFromExtents(getWindow()); - } else { - wm_set_insets = XWM.getInsetsFromProp(getWindow(), changedAtom); + // The window manager is unable to report any extents, so we need to + // calculate them ourselves. + Rectangle winRect = XlibUtil.getWindowGeometry( + window, XlibWrapper.larg1); + if (winRect == null) { + // Some error occured + return; + } + // The root window must be got immediately after the previous + // getWindowGeometry() call. + long root = Native.getWindow(XlibWrapper.larg1); + + long parent = getNativeParent(); + if (parent == XConstants.None || parent == root) { + // Non-reparenting WM. Assume the insets are zero. + setNativeInsets(ZERO_INSETS); + return; } - insLog.log(Level.FINER, "FRAME_EXTENTS: {0}", new Object[]{wm_set_insets}); + Rectangle parentRect = XlibUtil.getWindowGeometry(parent); + if (parentRect == null) { + // Some error again + return; + } - if (wm_set_insets != null) { - wm_set_insets = copy(wm_set_insets); + long grand_parent = XlibUtil.getParentWindow(parent); + if (grand_parent == XConstants.None || grand_parent == root || + (winRect.x != 0 || winRect.y != 0 || + winRect.width != parentRect.width || + winRect.height != parentRect.height)) + { + // Single-reparenting WM + // Either there's no a valid grand-parent, or the direct parent + // has greater bounds than the window itself. + setNativeInsets(calculateInsets(winRect, parentRect)); + } else { + // Double-reparenting WM + // There's a valid grand-parent. The bounds of the direct + // parent are equal to the bounds of the window itself. + Rectangle grandParentRect = XlibUtil.getWindowGeometry( + grand_parent); + if (grandParentRect == null) { + // One more error condition. This time we fall back to the + // single-reparenting case, though this will produce + // ZERO_INSETS actually... + setNativeInsets(calculateInsets(winRect, parentRect)); + } else { + setNativeInsets(calculateInsets(parentRect, grandParentRect)); + } } - return wm_set_insets; } - private void resetWMSetInsets() { - wm_set_insets = null; + /** + * Calculates the insets for the given interior and exterior rectangles. + * Only positive insets are allowed. If the interior rectangle is bigger + * than the exterior one, the negative inset values will be ignored, + * and zero value used instead. + */ + private static Insets calculateInsets(Rectangle interior, Rectangle exterior) { + return new Insets( + Math.max(interior.y, 0), + Math.max(interior.x, 0), + Math.max(exterior.height - interior.height - interior.y, 0), + Math.max(exterior.width - interior.width - interior.x, 0)); + } + + /** + * Applies the new insets. + */ + private void setInsets(Insets insets) { + setNativeInsets(insets); + + WindowDimensions dims = new WindowDimensions(dimensions); + dims.setInsets(insets); + reportOrAdjust(dims, false); } + @Override public void handlePropertyNotify(XEvent xev) { super.handlePropertyNotify(xev); XPropertyEvent ev = xev.get_xproperty(); - if (ev.get_atom() == XWM.XA_KDE_NET_WM_FRAME_STRUT.getAtom() - || ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom()) - { - getWMSetInsets(XAtom.get(ev.get_atom())); + if (XWM.isExtentsPropertyAtom(ev.get_atom())) { + Insets insets = XWM.getInsetsFromProp(getWindow(), + XAtom.get(ev.get_atom())); + if (insLog.isLoggable(Level.FINE)) { + insLog.fine("" + insets); + } + if (insets != null) { + setInsets(insets); + } } } - long reparent_serial = 0; + // The serial of the last received ReparentNotify event + private long reparentNotifySerial = 0; + + // The number of processed ConfigureNotify events with the same serial + // as reparentNotifySerial. + private int numOfConfigureNotifyJustAfterReparentNotify = 0; + @Override public void handleReparentNotifyEvent(XEvent xev) { + super.handleReparentNotifyEvent(xev); + XReparentEvent xe = xev.get_xreparent(); - if (insLog.isLoggable(Level.FINE)) insLog.fine(xe.toString()); - reparent_serial = xe.get_serial(); - XToolkit.awtLock(); - try { - long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()); + if (insLog.isLoggable(Level.FINE)) { + insLog.fine(xe.toString()); + } - if (isEmbedded()) { - setReparented(true); - insets_corrected = true; - return; - } - Component t = (Component)target; - if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) { - setReparented(true); - insets_corrected = true; - reshape(dimensions, SET_SIZE, false); - } else if (xe.get_parent() == root) { - configure_seen = false; - insets_corrected = false; - - /* - * We can be repareted to root for two reasons: - * . setVisible(false) - * . WM exited - */ - if (isVisible()) { /* WM exited */ - /* Work around 4775545 */ - XWM.getWM().unshadeKludge(this); - insLog.fine("- WM exited"); - } else { - insLog.fine(" - reparent due to hide"); - } - } else { /* reparented to WM frame, figure out our insets */ - setReparented(true); - insets_corrected = false; - - // Check if we have insets provided by the WM - Insets correctWM = getWMSetInsets(null); - if (correctWM != null) { - insLog.log(Level.FINER, "wm-provided insets {0}", new Object[]{correctWM}); - // If these insets are equal to our current insets - no actions are necessary - Insets dimInsets = dimensions.getInsets(); - if (correctWM.equals(dimInsets)) { - insLog.finer("Insets are the same as estimated - no additional reshapes necessary"); - no_reparent_artifacts = true; - insets_corrected = true; - applyGuessedInsets(); - return; - } - } else { - correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent()); + if (xe.get_window() != getWindow()) { + return; + } - if (correctWM != null) { - insLog.log(Level.FINER, "correctWM {0}", new Object[] {correctWM}); - } else { - insLog.log(Level.FINER, "correctWM insets are not available, waiting for configureNotify"); - } + if (!isParented()) { + if (isVisible()) { + // Either the WM or the embedder exited + XWM.getWM().unshadeKludge(this); + if (!isEmbedded()) { + XWM.reset(); } + setInsets(null); + } //else: The window just got hidden + } else { + // We just got parented: prepare stuff to recalculate the insets, + // and to readjust the bounds if needed + reparentNotifySerial = xe.get_serial(); + numOfConfigureNotifyJustAfterReparentNotify = 0; - if (correctWM != null) { - handleCorrectInsets(correctWM); - } - } - } finally { - XToolkit.awtUnlock(); + setNativeInsets(null); + needToAdjustBounds(); } } - protected void handleCorrectInsets(Insets correctWM) { - XToolkit.awtLock(); - try { - /* - * Ok, now see if we need adjust window size because - * initial insets were wrong (most likely they were). - */ - Insets correction = difference(correctWM, currentInsets); - insLog.log(Level.FINEST, "Corrention {0}", new Object[] {correction}); - if (!isNull(correction)) { - currentInsets = copy(correctWM); - applyGuessedInsets(); - - //Fix for 6318109: PIT: Min Size is not honored properly when a - //smaller size is specified in setSize(), XToolkit - //update minimum size hints - updateMinSizeHints(); - } - if (insLog.isLoggable(Level.FINER)) insLog.finer("Dimensions before reparent: " + dimensions); - - dimensions.setInsets(getRealInsets()); - insets_corrected = true; - - if (isMaximized()) { - return; - } - - /* - * If this window has been sized by a pack() we need - * to keep the interior geometry intact. Since pack() - * computed width and height with wrong insets, we - * must adjust the target dimensions appropriately. - */ - if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) { - reshape(dimensions, SET_BOUNDS, false); - } else { - reshape(dimensions, SET_SIZE, false); - } - } finally { - XToolkit.awtUnlock(); - } + protected boolean isInitialReshape() { + return false; } - public void handleMoved(WindowDimensions dims) { - Point loc = dims.getLocation(); + public void handleMoved(Point loc) { ComponentAccessor.setX((Component)target, loc.x); ComponentAccessor.setY((Component)target, loc.y); postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); } - protected Insets guessInsets() { - if (isEmbedded() || isTargetUndecorated()) { - return new Insets(0, 0, 0, 0); - } else { - if (!isNull(currentInsets)) { - /* insets were set on wdata by System Properties */ - return copy(currentInsets); - } else { - Insets res = getWMSetInsets(null); - if (res == null) { - res = XWM.getWM().guessInsets(this); - } - return res; - } - } - } - - private void applyGuessedInsets() { - Insets guessed = guessInsets(); - currentInsets = copy(guessed); - } - public void revalidate() { XToolkit.executeOnEventHandlerThread(target, new Runnable() { public void run() { @@ -442,22 +510,6 @@ }); } - Insets getRealInsets() { - if (isNull(currentInsets)) { - applyGuessedInsets(); - } - return currentInsets; - } - - public Insets getInsets() { - Insets in = copy(getRealInsets()); - in.top += getMenuBarHeight(); - if (insLog.isLoggable(Level.FINEST)) { - insLog.log(Level.FINEST, "Get insets returns {0}", new Object[] {in}); - } - return in; - } - boolean gravityBug() { return XWM.configureGravityBuggy(); } @@ -479,110 +531,137 @@ // Coordinates are that of the target // Called only on Toolkit thread - public void reshape(WindowDimensions newDimensions, int op, - boolean userReshape) + private void reshape(WindowDimensions newDimensions, int op) { if (insLog.isLoggable(Level.FINE)) { - insLog.fine("Reshaping " + this + " to " + newDimensions + " op " + op + " user reshape " + userReshape); - } - if (userReshape) { - // We handle only userReshape == true cases. It means that - // if the window manager or any other part of the windowing - // system sets inappropriate size for this window, we can - // do nothing but accept it. - Rectangle newBounds = newDimensions.getBounds(); - Insets insets = newDimensions.getInsets(); - // Inherit isClientSizeSet from newDimensions - if (newDimensions.isClientSizeSet()) { - newBounds = new Rectangle(newBounds.x, newBounds.y, - newBounds.width - insets.left - insets.right, - newBounds.height - insets.top - insets.bottom); - } - newDimensions = new WindowDimensions(newBounds, insets, newDimensions.isClientSizeSet()); + insLog.fine("Reshaping " + this + " to " + newDimensions + + "; op " + operationToString(op)); } XToolkit.awtLock(); try { - if (!isReparented() || !isVisible()) { - insLog.log(Level.FINE, "- not reparented({0}) or not visible({1}), default reshape", - new Object[] {Boolean.valueOf(isReparented()), Boolean.valueOf(visible)}); - - // Fix for 6323293. - // This actually is needed to preserve compatibility with previous releases - - // some of licensees are expecting componentMoved event on invisible one while - // its location changes. - Point oldLocation = getLocation(); - - Point newLocation = new Point(ComponentAccessor.getX((Component)target), - ComponentAccessor.getY((Component)target)); - - if (!newLocation.equals(oldLocation)) { - handleMoved(newDimensions); - } - - dimensions = new WindowDimensions(newDimensions); - updateSizeHints(dimensions); - Rectangle client = dimensions.getClientRect(); + if (!isVisible()) { + Rectangle client = newDimensions.getClientRect(); checkShellRect(client); setShellBounds(client); - if (content != null && - !content.getSize().equals(newDimensions.getSize())) - { - reconfigureContentWindow(newDimensions); - } - return; + + reportReshape(newDimensions); + } else { + requestReshape(newDimensions, op); } + } finally { + XToolkit.awtUnlock(); + } + } - int wm = XWM.getWMID(); - updateChildrenSizes(); - applyGuessedInsets(); + /** + * Sets window dimensions and propagates the changes to the target sending + * corresponding events if needed. + * + * MUST be invoked under the AWTLock. + */ + private void reportReshape(WindowDimensions newDims) { + if (insLog.isLoggable(Level.FINE)) { + insLog.fine("" + newDims); + } - Rectangle shellRect = newDimensions.getClientRect(); + final Insets insets = newDims.getInsets(); + if (!insets.equals(dimensions.getInsets())) { + // Recalculate the minimum size of the client area + updateMinSizeHints(insets); + } - if (gravityBug()) { - Insets in = newDimensions.getInsets(); - shellRect.translate(in.left, in.top); - } + // If the client area size changes, we need to revalidate the target. + // This may happen in the XContentWindow.setContentBounds(). If this + // does not happen there, we need to dispatch the operation here. + final boolean needRevalidate = + !dimensions.getClientSize().equals(newDims.getClientSize()); - if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) { - shellRect.setLocation(0, 0); - } + checkIfOnNewScreen(newDims.getBounds()); + + Point oldLocation = getLocation(); + dimensions = newDims; + if (!getLocation().equals(oldLocation)) { + handleMoved(getLocation()); + } - checkShellRectSize(shellRect); - if (!isEmbedded()) { - checkShellRectPos(shellRect); + if (!reconfigureContentWindow(dimensions) && needRevalidate) { + revalidate(); + } + + updateChildrenSizes(); + repositionSecurityWarning(); + } + + private void reportOrAdjust(WindowDimensions newDims, + boolean handlingConfigureNotify) + { + if (dimensions.equals(newDims) && !areBoundsAdjusting()) { + // If nothing has changed and we're already adjusted, return + if (insLog.isLoggable(Level.FINE)) { + insLog.fine("Ignored: nothing changed: " + newDims); } + return; + } + if (adjustBounds(newDims, handlingConfigureNotify)) { + // We expect another ConfigureNotify + return; + } + + reportReshape(newDims); + } + + /** + * Requests the system to reshape the window. + * + * MUST be invoked under the AWTLock. + */ + private void requestReshape(WindowDimensions newDimensions, int op) { + if (insLog.isLoggable(Level.FINE)) { + insLog.fine("Request reshape: " + newDimensions + "; op: " + + operationToString(op)); + } - op = op & ~NO_EMBEDDED_CHECK; + Rectangle shellRect = newDimensions.getClientRect(); - if (op == SET_LOCATION) { - setShellPosition(shellRect); - } else if (isResizable()) { - if (op == SET_BOUNDS) { - setShellBounds(shellRect); - } else { - setShellSize(shellRect); - } + if (gravityBug()) { + Insets in = newDimensions.getInsets(); + shellRect.translate(in.left, in.top); + } + + if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) { + shellRect.setLocation(0, 0); + } + + checkShellRectSize(shellRect); + if (!isEmbedded()) { + checkShellRectPos(shellRect); + } + + op = op & ~NO_EMBEDDED_CHECK; + + if (op == SET_LOCATION) { + setShellPosition(shellRect); + } else if (isResizable()) { + if (op == SET_BOUNDS) { + setShellBounds(shellRect); } else { - XWM.setShellNotResizable(this, newDimensions, shellRect, true); - if (op == SET_BOUNDS) { - setShellPosition(shellRect); - } + setShellSize(shellRect); + } + } else { + XWM.setShellNotResizable(this, newDimensions, shellRect, true); + if (op == SET_BOUNDS) { + setShellPosition(shellRect); } - - reconfigureContentWindow(newDimensions); - } finally { - XToolkit.awtUnlock(); } } + // This method gets overriden in XFramePeer & XDialogPeer. + abstract boolean isTargetUndecorated(); + /** - * @param x, y, width, heith - dimensions of the window with insets + * @see java.awt.peer.ComponentPeer#setBounds */ - private void reshape(int x, int y, int width, int height, int operation, - boolean userReshape) - { - Rectangle newRec; - boolean setClient = false; + public void setBounds(int x, int y, int width, int height, int operation) { WindowDimensions dims = new WindowDimensions(dimensions); switch (operation & (~NO_EMBEDDED_CHECK)) { case SET_LOCATION: @@ -597,10 +676,14 @@ break; case SET_CLIENT_SIZE: { // Sets client rect size. Width and height contain insets. - Insets in = currentInsets; + // Also update the insets to the latest known value to decrease + // (or even eliminate) the bounds adjustment after showing + // the window. + Insets in = getNativeInsets(); width -= in.left+in.right; height -= in.top+in.bottom; dims.setClientSize(width, height); + dims.setInsets(in); break; } case SET_BOUNDS: @@ -609,160 +692,270 @@ dims.setSize(width, height); break; } - if (insLog.isLoggable(Level.FINE)) insLog.log(Level.FINE, "For the operation {0} new dimensions are {1}", - new Object[] {operationToString(operation), dims}); + reshape(dims, operation); + validateSurface(); + } - reshape(dims, operation, userReshape); + /** + * Sets the content window bounds. + * + * @return whether a COMPONENT_RESIZED has been sent + */ + boolean reconfigureContentWindow(WindowDimensions dims) { + if (content == null) { + insLog.fine("WARNING: Content window is null"); + return false; + } + return content.setContentBounds(dims); } - // This method gets overriden in XFramePeer & XDialogPeer. - abstract boolean isTargetUndecorated(); + /** + * Indicates if the adjustBounds() needs to be invoked. + * Synchronization: state lock. + */ + private boolean areBoundsAdjusted = false; /** - * @see java.awt.peer.ComponentPeer#setBounds + * Forces the system to re-adjust the bounds of the window after it has + * been finally adopted by the windowing system. */ - public void setBounds(int x, int y, int width, int height, int op) { - // TODO: Rewrite with WindowDimensions - reshape(x, y, width, height, op, true); - validateSurface(); + private void needToAdjustBounds() { + synchronized (getStateLock()) { + areBoundsAdjusted = false; + } } - // Coordinates are that of the shell - void reconfigureContentWindow(WindowDimensions dims) { - if (content == null) { - insLog.fine("WARNING: Content window is null"); - return; + /** + * Indicates if the window bounds has not yet been finally configured by + * the X server/window manager. + */ + public boolean areBoundsAdjusting() { + synchronized (getStateLock()) { + return !areBoundsAdjusted; } - content.setContentBounds(dims); } - boolean no_reparent_artifacts = false; - public void handleConfigureNotifyEvent(XEvent xev) { - assert (SunToolkit.isAWTLockHeldByCurrentThread()); - XConfigureEvent xe = xev.get_xconfigure(); - insLog.log(Level.FINE, "Configure notify {0}", new Object[] {xe}); + // XXX: Perhaps the following two might be replaced with Window.isSizeSet, + // isLocationSet? Just like we have Window.isPacked... + /** + * Indicates if the size hints of the window specify a position requested + * by the user's code. + */ + private boolean isUserSpecifiedPositionSet() { + return (getHints().get_flags() & + (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0; + } + + /** + * Indicates if the size hints of the window specify a position requested + * by the user's code. + */ + private boolean isUserSpecifiedSizeSet() { + return (getHints().get_flags() & + (XUtilConstants.USSize | XUtilConstants.PSize)) != 0; + } - // XXX: should really only consider synthetic events, but - if (isReparented()) { - configure_seen = true; + /** + * Adjust the bounds of the window. + * + * @return true if an adjustment has taken place. false if the new bounds + * are OK. + */ + private boolean adjustBounds(WindowDimensions newDims, + boolean handlingConfigureNotify) + { + synchronized (getStateLock()) { + if (areBoundsAdjusted) { + return false; + } + // We have to adjust bounds upon showing once. + // We also may adjust them several times before showing - e.g. + // when we receive the PropertyNotify event with the extents. + if (handlingConfigureNotify && isVisible()) { + insLog.log(Level.FINE, "Final adjustment"); + areBoundsAdjusted = true; + } + } + + if (isMaximized()) { + return false; } - if (!isMaximized() - && (xe.get_serial() == reparent_serial || xe.get_window() != getShell()) - && !no_reparent_artifacts) + int operation = 0; + boolean isPacked = AWTAccessor.getWindowAccessor(). + isPacked((Window)target); + + if (!newDims.getClientSize().equals(dimensions.getClientSize()) + && isPacked) { - insLog.fine("- reparent artifact, skipping"); - return; + // The client area size calculated via pack() needs to be preserved + operation = SET_SIZE; + } else + if (!newDims.getSize().equals(dimensions.getSize()) + && isUserSpecifiedSizeSet()) + { + // The size set via setSize()/setBounds() needs to be preserved + operation = SET_SIZE; } - no_reparent_artifacts = false; - /** - * When there is a WM we receive some CN before being visible and after. - * We should skip all CN which are before being visible, because we assume - * the gravity is in action while it is not yet. - * - * When there is no WM we receive CN only _before_ being visible. - * We should process these CNs. - */ - if (!isVisible() && XWM.getWMID() != XWM.NO_WM) { - insLog.fine(" - not visible, skipping"); - return; + if (isUserSpecifiedPositionSet() && + !newDims.getLocation().equals(dimensions.getLocation())) + { + // The user also requested a specific position + if (operation == 0) { + operation = SET_LOCATION; + } else { + operation = SET_BOUNDS; + } } - /* - * Some window managers configure before we are reparented and - * the send event flag is set! ugh... (Enlighetenment for one, - * possibly MWM as well). If we haven't been reparented yet - * this is just the WM shuffling us into position. Ignore - * it!!!! or we wind up in a bogus location. - */ - int runningWM = XWM.getWMID(); + if (operation == 0) { + insLog.fine("No adjustment needed"); + return false; + } + + WindowDimensions dims = new WindowDimensions( + dimensions.getLocation(), + isPacked ? dimensions.getClientSize() : dimensions.getSize(), + newDims.getInsets(), + isPacked); + if (insLog.isLoggable(Level.FINE)) { - insLog.log(Level.FINE, "reparented={0}, visible={1}, WM={2}, decorations={3}", - new Object[] {isReparented(), isVisible(), runningWM, getDecorations()}); + insLog.fine("Request: " + dims + "; operation=" + + operationToString(operation)); } - if (!isReparented() && isVisible() && runningWM != XWM.NO_WM - && !XWM.isNonReparentingWM() - && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { - insLog.fine("- visible but not reparented, skipping"); + requestReshape(dims, operation); + return true; + } + + @Override + public void handleConfigureNotifyEvent(XEvent xev) { + // Note: we don't call super because the XWindowPeer immediately calls + // the checkIfOnNewScreen() assuming the bounds are correct. This + // is not always correct for decorated peers. + + XConfigureEvent xe = xev.get_xconfigure(); + + // Due to the SubstructureNotifyMask we should process only those + // events that belong to us. + if (xe.get_window() != getWindow()) { return; } - //Last chance to correct insets - if (!insets_corrected && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { - long parent = XlibUtil.getParentWindow(window); - Insets correctWM = (parent != -1) ? XWM.getWM().getInsets(this, window, parent) : null; - if (insLog.isLoggable(Level.FINER)) { - if (correctWM != null) { - insLog.finer("Configure notify - insets : " + correctWM); - } else { - insLog.finer("Configure notify - insets are still not available"); - } - } - if (correctWM != null) { - handleCorrectInsets(correctWM); - } else { - //Only one attempt to correct insets is made (to lower risk) - //if insets are still not available we simply set the flag - insets_corrected = true; - } + + if (insLog.isLoggable(Level.FINE)) { + insLog.fine("" + xe); + insLog.fine("XWM.isRunning: " + XWM.isRunning()); } - updateChildrenSizes(); + // If there's a WM we have to ignore some events + if (XWM.isRunning()) { + // Ignore any events until after we become visible + if (!isVisible()) { + insLog.fine("Ignored: Not visible yet"); + needToAdjustBounds(); + return; + } - // Bounds of the window - Rectangle targetBounds = new Rectangle(ComponentAccessor.getX((Component)target), - ComponentAccessor.getY((Component)target), - ComponentAccessor.getWidth((Component)target), - ComponentAccessor.getHeight((Component)target)); - - Point newLocation = targetBounds.getLocation(); - if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) { - // Location, Client size + insets - newLocation = new Point(xe.get_x() - currentInsets.left, xe.get_y() - currentInsets.top); - } else { - // CDE/MWM/Metacity/Sawfish bug: if shell is resized using - // top or left border, we don't receive synthetic - // ConfigureNotify, only the one from X with zero - // coordinates. This is the workaround to get real - // location, 6261336 - switch (XWM.getWMID()) { - case XWM.CDE_WM: - case XWM.MOTIF_WM: - case XWM.METACITY_WM: - case XWM.SAWFISH_WM: - { - Point xlocation = queryXLocation(); - if (log.isLoggable(Level.FINE)) log.log(Level.FINE, "New X location: {0}", new Object[]{xlocation}); - if (xlocation != null) { - newLocation = xlocation; - } - break; + // We have not yet been parented by the WM + if (mayBeReparented() && !isTargetUndecorated()) { + insLog.fine("Ignored: Not parented yet"); + needToAdjustBounds(); + return; + } + + // Just after reparenting we can receive a synthetic and/or real + // event(s). Since sometimes we need to adjust the bounds of the + // frame, we need to process only one of the events. Justification: + // 1. Both events carry the same information: one from the X + // server, the other from the WM. + // 2. The adjustment operation is performed only once upon + // processing the first ConfigureNotify event that is not + // ignored. + // 3. If the first event causes the adjustment to happen, the + // second event will be considered as a normal, not ignored + // event that may generate Java events and set incorrect + // (not-yet-adjusted) bounds to the frame. + // So generally, if the adjustment is needed, the first + // ConfigureNotify that we should really process is the one caused + // by the adjustment operation. So we process only the first + // ConfigureNotify event having the same serial that the preceeding + // ReparentNotify. + // + // There's one exception however: we do not ignore the events for + // maximized frames. The real ConfigureNotify that we would like to + // act upon usually is the third one (it carries the correct + // maximized bounds). However, it has the same serial (which is + // obvious), and what's worse - we can't reliably determine if the + // window manager/X server send us exactly two events before that, + // or maybe one of them might be not sent at all - and in this case + // we would need to process the second event, not the third. So we + // just process everything for a maximized frame. This does produce + // absolutely meaningless bounds dancing (with events sent to the + // user space), but at least this is backward-compatible and quite + // reliable. Should we find a way to detect and process only the + // very last of ConfigureNotify events sent with the same serial, + // we would like to use this approach instead of the current + // processing of the very first event only. + if (xe.get_serial() == reparentNotifySerial && !isMaximized()) + { + if (++numOfConfigureNotifyJustAfterReparentNotify > 1) { + insLog.fine("Ignored: serial matches the ReparentNotify"); + return; } - default: - break; } } - WindowDimensions newDimensions = - new WindowDimensions(newLocation, - new Dimension(xe.get_width(), xe.get_height()), - copy(currentInsets), - true); - - insLog.log(Level.FINER, "Insets are {0}, new dimensions {1}", - new Object[] {currentInsets, newDimensions}); - - checkIfOnNewScreen(newDimensions.getBounds()); - - Point oldLocation = getLocation(); - dimensions = newDimensions; - if (!newLocation.equals(oldLocation)) { - handleMoved(newDimensions); - } - reconfigureContentWindow(newDimensions); - updateChildrenSizes(); + // At this point we can calculate some reliable insets + Insets insets = getNativeInsets(); - repositionSecurityWarning(); + // Note that in some cases this kind of event may be caused by the + // changed insets (like if the theme changes, or something). However + // it's difficult if at all possible to identify this situation, and + // not confuse it with a regular reconfiguration w/o introducing some + // serious performance degradation. So we only support changing the + // insets: + // a. when a reparenting WM exits/gets replaced. + // b. when the window gets hidden/shown. + // c. if the WM is smart enough to send the PropertyNotify + // events with the updated extents. + + // x, y, width, height hold the coordinates of the whole frame + // including the decorations. + int x; + int y; + + if (xe.get_send_event() || !isParented()) { + // If the event is synthetic or we're not parented, the coordinates + // are relative to the root window. + x = xe.get_x() - insets.left; + y = xe.get_y() - insets.top; + } else { + // The event is real and we're parented - the coordinates are + // relative to the parent + Point loc = null; + if (XWM.isNoSyntheticConfigureNotifyOnLeftTopResize()) { + // there's a bug in the WM, so ask the X server + loc = queryXLocation(); + } + if (loc == null) { + // consider the current location unchanged + // TODO: this may not be true... perhaps querying X in all cases is worthwhile? + // after all: we already do this for Metacity which is quite common, + // so we should not worry much about the performance. + loc = getLocation(); + } + + x = loc.x; + y = loc.y; + } + + int width = xe.get_width() + insets.left + insets.right; + int height = xe.get_height() + insets.top + insets.bottom; + + // Now apply the new bounds + WindowDimensions d = new WindowDimensions( + new Rectangle(x, y, width, height), insets, false); + reportOrAdjust(d, true); } private void checkShellRectSize(Rectangle shellRect) { @@ -832,11 +1025,7 @@ public void setResizable(boolean resizable) { int fs = winAttr.functions; if (!isResizable() && resizable) { - currentInsets = new Insets(0, 0, 0, 0); - resetWMSetInsets(); - if (!isEmbedded()) { - setReparented(false); - } + setNativeInsets(null); winAttr.isResizable = resizable; if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); @@ -846,11 +1035,7 @@ winAttr.functions = fs; XWM.setShellResizable(this); } else if (isResizable() && !resizable) { - currentInsets = new Insets(0, 0, 0, 0); - resetWMSetInsets(); - if (!isEmbedded()) { - setReparented(false); - } + setNativeInsets(null); winAttr.isResizable = resizable; if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); @@ -911,13 +1096,14 @@ public Point getLocationOnScreen() { XToolkit.awtLock(); try { - if (configure_seen) { + if (!areBoundsAdjusting()) { return toGlobal(0,0); } else { Point location = target.getLocation(); - if (insLog.isLoggable(Level.FINE)) + if (insLog.isLoggable(Level.FINE)) { insLog.log(Level.FINE, "getLocationOnScreen {0} not reparented: {1} ", new Object[] {this, location}); + } return location; } } finally { @@ -1057,7 +1243,7 @@ } final void dumpParent() { long parent = XlibUtil.getParentWindow(getShell()); - if (parent != 0) + if (parent != XConstants.None) { dumpWindow("Parent", parent); } @@ -1100,7 +1286,6 @@ } boolean isOverrideRedirect() { -// return false; return ((XToolkit)Toolkit.getDefaultToolkit()).isOverrideRedirect((Window)target); } --- old/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java 2009-08-11 19:21:19.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java 2009-08-11 19:21:18.000000000 +0400 @@ -81,7 +81,7 @@ window = XlibUtil.getParentWindow(window); - } while (window != 0); + } while (window != XConstants.None); return window; } --- old/src/solaris/classes/sun/awt/X11/XEmbedClientHelper.java 2009-08-11 19:21:20.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XEmbedClientHelper.java 2009-08-11 19:21:20.000000000 +0400 @@ -104,8 +104,8 @@ server = getEmbedder(embedded, msg); // Check if window is reparented. If not - it was created with // parent and so we should update it here. - if (!embedded.isReparented()) { - embedded.setReparented(true); + if (!embedded.isParented()) { + embedded.setNativeParent(server); embedded.updateSizeHints(); } embedded.notifyStarted(); --- old/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java 2009-08-11 19:21:21.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java 2009-08-11 19:21:21.000000000 +0400 @@ -163,7 +163,7 @@ } if (!getLocation().equals(oldBounds.getLocation())) { - handleMoved(dimensions); + handleMoved(dimensions.getLocation()); } reconfigureContentWindow(dimensions); } --- old/src/solaris/classes/sun/awt/X11/XlibUtil.java 2009-08-11 19:21:22.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XlibUtil.java 2009-08-11 19:21:22.000000000 +0400 @@ -100,16 +100,45 @@ } /** - * Returns the bounds of the given window, in absolute coordinates + * Returns the bounds of the given window relative to its parent. */ - static Rectangle getWindowGeometry(long window) + public static Rectangle getWindowGeometry(long window) { + XToolkit.awtLock(); + try { + return getWindowGeometry(window, XlibWrapper.larg1); + } finally { + XToolkit.awtUnlock(); + } + } + + /** + * Returns the bounds of the given window relative to its parent. + * The unsafe memory pointed to by the rootWindowBuffer will + * contain the root window of the given window. + * WARNING: DO NOT USE XlibWrapper.larg[2..7] as the rootWindowBuffer! + * Only larg1 or larg8 can be used, or some other allocated memory block. + * + * @throws IllegalArgumentException if the rootWindowBuffer refers to + * unsupported values. + */ + public static Rectangle getWindowGeometry(long window, long rootWindowBuffer) { + if (rootWindowBuffer == XlibWrapper.larg2 || + rootWindowBuffer == XlibWrapper.larg3 || + rootWindowBuffer == XlibWrapper.larg4 || + rootWindowBuffer == XlibWrapper.larg5 || + rootWindowBuffer == XlibWrapper.larg6 || + rootWindowBuffer == XlibWrapper.larg7) + { + throw new IllegalArgumentException( + "The rootWindowBuffer should not refer to XlibWrapper.larg[2..7]"); + } XToolkit.awtLock(); try { int res = XlibWrapper.XGetGeometry(XToolkit.getDisplay(), window, - XlibWrapper.larg1, // root_return + rootWindowBuffer, // root_return XlibWrapper.larg2, // x_return XlibWrapper.larg3, // y_return XlibWrapper.larg4, // width_return @@ -210,7 +239,7 @@ { if (qt.execute() == 0) { - return 0; + return XConstants.None; } else { --- old/src/solaris/classes/sun/awt/X11/XlibWrapper.java 2009-08-11 19:21:23.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XlibWrapper.java 2009-08-11 19:21:23.000000000 +0400 @@ -599,8 +599,6 @@ } isBuildInternal = getBuildInternal(); - -// System.loadLibrary("mawt"); } static int getDataModel() { @@ -648,4 +646,39 @@ } static native void PrintXErrorEvent(long display, long event_ptr); + + /** + * The interface to be implemented by a predicate object used with the + * CheckIfEvent() method. + */ + public static interface CheckEventPredicate { + + /** + * Returns true if the event matches some criteria, false otherwise. + */ + boolean doesMatch(XEvent event); + } + + /** + * Invokes the XCheckIfEvent(). + * The returned event (if any) MUST BE disposed by the caller. + * + * @return the matched event or null if no match found. + */ + public static XEvent CheckIfEvent(long display, CheckEventPredicate predicate) { + XEvent ev = new XEvent(); + + if (CheckIfEvent(display, ev, ev.pData, predicate)) { + return ev; + } else { + ev.dispose(); + return null; + } + } + + /* + * NOTE: The passed event_return MUST be equal to the event.pData. + */ + private static native boolean CheckIfEvent(long display, XEvent event, + long event_return, CheckEventPredicate predicate); } --- old/src/solaris/classes/sun/awt/X11/XPanelPeer.java 2009-08-11 19:21:25.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XPanelPeer.java 2009-08-11 19:21:24.000000000 +0400 @@ -123,13 +123,6 @@ } } - /** - * DEPRECATED: Replaced by getInsets(). - */ - public Insets insets() { - return getInsets(); - } - public void dispose() { if (embedder != null) { embedder.deinstall(); --- old/src/solaris/classes/sun/awt/X11/XWindow.java 2009-08-11 19:21:26.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XWindow.java 2009-08-11 19:21:25.000000000 +0400 @@ -281,12 +281,84 @@ return new String[] {XToolkit.getCorrectXIDString(getClass().getName()), XToolkit.getAWTAppClassName()}; } - void setReparented(boolean newValue) { - reparented = newValue; + /** + * Current native parent of this window. + * + * Synchronization: state lock. + */ + private long nativeParent = XConstants.None; + + /** + * Get the current native parent window of this window as reported via + * the ReparentNotify. + */ + public final long getNativeParent() { + synchronized (getStateLock()) { + return nativeParent; + } + } + + /** + * Sets the current native parent of the window. + * Primarily intended to be called from the handleReparentNotifyEvent(). + */ + public void setNativeParent(long parent) { + synchronized (getStateLock()) { + nativeParent = parent; + } + } + + @Override + public void handleReparentNotifyEvent(XEvent xev) { + super.handleReparentNotifyEvent(xev); + + XReparentEvent xe = xev.get_xreparent(); + + if (xe.get_window() != getWindow()) { + return; + } + + setNativeParent(xe.get_parent()); + } + + /** + * Returns the root window of the current window. + */ + public final long getRootWindow() { + if (getWindow() == XConstants.None) { + return XConstants.None; + } + XToolkit.awtLock(); + try { + XlibUtil.getWindowGeometry(getWindow(), XlibWrapper.larg1); + return Native.getWindow(XlibWrapper.larg1); + } finally { + XToolkit.awtUnlock(); + } } - boolean isReparented() { - return reparented; + /** + * Indicates whether the window is currently parented or not. + */ + public final boolean isParented() { + long nativeParent = getNativeParent(); + return nativeParent != XConstants.None && + nativeParent != getRootWindow(); + } + + /** + * Indicates if this window has not yet been parented by the window + * manager. + * + * If the window is not expected to be parented at all (like if the WM is + * non-reparenting, or this is an OverrideRedirect window), this method + * returns false. + */ + public boolean mayBeReparented() { + return + XWM.isRunning() && + !XWM.isNonReparentingWM() && + !isParented(); } static long getParentWindowID(Component target) { @@ -994,17 +1066,21 @@ public void doLayout(int x, int y, int width, int height) {} public void handleConfigureNotifyEvent(XEvent xev) { - Rectangle oldBounds = getBounds(); + XConfigureEvent xe = xev.get_xconfigure(); + if (xe.get_window() != getWindow()) { + return; + } + + Rectangle oldBounds = getBounds(); super.handleConfigureNotifyEvent(xev); insLog.log(Level.FINER, "Configure, {0}, event disabled: {1}", - new Object[] {xev.get_xconfigure(), isEventDisabled(xev)}); + new Object[] {xe, isEventDisabled(xev)}); if (isEventDisabled(xev)) { return; } -// if ( Check if it's a resize, a move, or a stacking order change ) -// { + Rectangle bounds = getBounds(); if (!bounds.getSize().equals(oldBounds.getSize())) { postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_RESIZED)); @@ -1012,7 +1088,6 @@ if (!bounds.getLocation().equals(oldBounds.getLocation())) { postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_MOVED)); } -// } } public void handleMapNotifyEvent(XEvent xev) { @@ -1021,6 +1096,11 @@ if (isEventDisabled(xev)) { return; } + + if (xev.get_xany().get_window() != getWindow()) { + return; + } + ComponentEvent ce; ce = new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_SHOWN); @@ -1032,6 +1112,10 @@ if (isEventDisabled(xev)) { return; } + if (xev.get_xany().get_window() != getWindow()) { + return; + } + ComponentEvent ce; ce = new ComponentEvent(target, ComponentEvent.COMPONENT_HIDDEN); @@ -1402,7 +1486,7 @@ Object wpeer = XToolkit.targetToPeer(comp); if (wpeer == null || !(wpeer instanceof XDecoratedPeer) - || ((XDecoratedPeer)wpeer).configure_seen) + || !((XDecoratedPeer)wpeer).areBoundsAdjusting()) { return toGlobal(0, 0); } --- old/src/solaris/classes/sun/awt/X11/XWindowPeer.java 2009-08-11 19:21:27.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XWindowPeer.java 2009-08-11 19:21:27.000000000 +0400 @@ -129,8 +129,6 @@ void preInit(XCreateWindowParams params) { target = (Component)params.get(TARGET); - params.put(REPARENTED, - Boolean.valueOf(isOverrideRedirect() || isSimpleWindow())); super.preInit(params); params.putIfNull(BIT_GRAVITY, Integer.valueOf(XConstants.NorthWestGravity)); @@ -517,13 +515,6 @@ oldState, newState)); } - /** - * DEPRECATED: Replaced by getInsets(). - */ - public Insets insets() { - return getInsets(); - } - boolean isAutoRequestFocus() { if (XToolkit.isToolkitThread()) { return WindowAccessor.isAutoRequestFocus((Window)target); @@ -714,6 +705,10 @@ // TODO: We create an XConfigureEvent every time we override // handleConfigureNotify() - too many! XConfigureEvent xe = xev.get_xconfigure(); + if (xe.get_window() != getWindow()) { + return; + } + checkIfOnNewScreen(new Rectangle(xe.get_x(), xe.get_y(), xe.get_width(), @@ -1177,6 +1172,10 @@ } public void handleMapNotifyEvent(XEvent xev) { + if (xev.get_xany().get_window() != getWindow()) { + return; + } + // See 6480534. isUnhiding |= isWMStateNetHidden(); @@ -1211,6 +1210,9 @@ } public void handleUnmapNotifyEvent(XEvent xev) { + if (xev.get_xany().get_window() != getWindow()) { + return; + } super.handleUnmapNotifyEvent(xev); // On Metacity UnmapNotify comes before PropertyNotify (for _NET_WM_STATE_HIDDEN). @@ -1297,11 +1299,20 @@ } } - void setReparented(boolean newValue) { - super.setReparented(newValue); + @Override + public boolean mayBeReparented() { + return + !isOverrideRedirect() && + !isSimpleWindow() && + super.mayBeReparented(); + } + + @Override + public void setNativeParent(long parent) { + super.setNativeParent(parent); XToolkit.awtLock(); try { - if (isReparented() && delayedModalBlocking) { + if (!mayBeReparented() && delayedModalBlocking) { addToTransientFors((XDialogPeer) ComponentAccessor.getPeer(modalBlocker)); delayedModalBlocking = false; } @@ -1391,7 +1402,7 @@ log.log(Level.FINE, "{0} is blocked by {1}", new Object[] { this, blockerPeer}); modalBlocker = d; - if (isReparented() || XWM.isNonReparentingWM()) { + if (!mayBeReparented()) { addToTransientFors(blockerPeer, javaToplevels); } else { delayedModalBlocking = true; @@ -1402,7 +1413,7 @@ } modalBlocker = null; - if (isReparented() || XWM.isNonReparentingWM()) { + if (!mayBeReparented()) { removeFromTransientFors(); } else { delayedModalBlocking = false; --- old/src/solaris/classes/sun/awt/X11/XWM.java 2009-08-11 19:21:28.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XWM.java 2009-08-11 19:21:28.000000000 +0400 @@ -30,10 +30,10 @@ */ package sun.awt.X11; -import sun.misc.Unsafe; import java.awt.Insets; import java.awt.Frame; import java.awt.Rectangle; +import java.security.AccessController; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; @@ -42,6 +42,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import sun.misc.Unsafe; +import sun.security.action.GetIntegerAction; + /** * Class incapsulating knowledge about window managers in general * Descendants should provide some information about specific window manager. @@ -136,8 +139,6 @@ int WMID; - static final Insets zeroInsets = new Insets(0, 0, 0, 0); - static final Insets defaultInsets = new Insets(25, 5, 5, 5); XWM(int WMID) { this.WMID = WMID; @@ -149,21 +150,6 @@ } - static Insets normalize(Insets insets) { - if (insets.top > 64 || insets.top < 0) { - insets.top = 28; - } - if (insets.left > 32 || insets.left < 0) { - insets.left = 6; - } - if (insets.right > 32 || insets.right < 0) { - insets.right = 6; - } - if (insets.bottom > 32 || insets.bottom < 0) { - insets.bottom = 6; - } - return insets; - } static XNETProtocol g_net_protocol = null; static XWINProtocol g_win_protocol = null; @@ -281,6 +267,7 @@ XToolkit.getDefaultRootWindow(), XConstants.CWEventMask, substruct.pData); + XToolkit.XSync(); XToolkit.RESTORE_XERROR_HANDLER(); /* @@ -560,16 +547,32 @@ */ static boolean isMetacity() { return isNetWMName("Metacity"); -// || ( -// XA_NET_SUPPORTING_WM_CHECK. -// getIntProperty(XToolkit.getDefaultRootWindow(), XA_NET_SUPPORTING_WM_CHECK. -// getIntProperty(XToolkit.getDefaultRootWindow(), XAtom.XA_CARDINAL)) == 0); } - static boolean isNonReparentingWM() { + //XXX: Perhaps we need to consider OTHER_WM as non-reparenting also? + public static boolean isNonReparentingWM() { return (XWM.getWMID() == XWM.COMPIZ_WM || XWM.getWMID() == XWM.LG3D_WM); } + /** + * Indicates if the window manager does not send a synthetic + * ConfigureNotify when the user resizes the window using the left or top + * border of the window. + * In that cases we receive a real event only. + * See 6261336. + */ + public static boolean isNoSyntheticConfigureNotifyOnLeftTopResize() { + switch (XWM.getWMID()) { + case XWM.CDE_WM: + case XWM.MOTIF_WM: + case XWM.METACITY_WM: + case XWM.SAWFISH_WM: + return true; + default: + return false; + } + } + /* * Prepare IceWM check. * @@ -683,24 +686,41 @@ /* * Make an educated guess about running window manager. - * XXX: ideally, we should detect wm restart. + * XXX: would be nice to synchronize access to these variables. */ - static int awt_wmgr = XWM.UNDETERMINED_WM; - static XWM wm; + private static int awt_wmgr = XWM.UNDETERMINED_WM; + private static XWM wm; static XWM getWM() { if (wm == null) { - wm = new XWM(awt_wmgr = getWMID()/*XWM.OTHER_WM*/); + wm = new XWM(awt_wmgr = getWMID()); } return wm; } + + /** + * Indicates if there's currently a window manager running. + */ + public static boolean isRunning() { + return XWM.getWMID() != XWM.NO_WM; + } + + /** + * Resets the currently detected window manager. + * Must be called whenever we detect that the currently running window + * manager exits. + */ + public static void reset() { + awt_wmgr = XWM.UNDETERMINED_WM; + g_net_protocol = null; + g_win_protocol = null; + wm = null; + } + + static int getWMID() { if (insLog.isLoggable(Level.FINEST)) { insLog.finest("awt_wmgr = " + awt_wmgr); } - /* - * Ideally, we should support cases when a different WM is started - * during a Java app lifetime. - */ if (awt_wmgr != XWM.UNDETERMINED_WM) { return awt_wmgr; @@ -966,7 +986,8 @@ XToolkit.awtLock(); try { Rectangle shellBounds = window.getShellBounds(); - shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top); + Insets insets = window.getNativeInsets(); + shellBounds.translate(-insets.left, -insets.top); window.updateSizeHints(window.getDimensions()); requestWMExtents(window.getWindow()); XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(), @@ -1048,6 +1069,7 @@ case XWM.CDE_WM: return false; default: + //XXX: so what about compiz? return false; } } @@ -1264,30 +1286,23 @@ } } - HashMap storedInsets = new HashMap(); - Insets guessInsets(XDecoratedPeer window) { - Insets res = (Insets)storedInsets.get(window.getClass()); - if (res == null) { - switch (WMID) { - case ENLIGHTEN_WM: - res = new Insets(19, 4, 4, 4); - break; - case CDE_WM: - res = new Insets(28, 6, 6, 6); - break; - case NO_WM: - case LG3D_WM: - res = zeroInsets; - break; - case MOTIF_WM: - case OPENLOOK_WM: - default: - res = defaultInsets; - } + /** + * Returns the "default" insets for the currently running window manager. + */ + public final Insets getDefaultInsets() { + switch (WMID) { + case ENLIGHTEN_WM: + return new Insets(19, 4, 4, 4); + case CDE_WM: + return new Insets(28, 6, 6, 6); + case NO_WM: + case LG3D_WM: + return XDecoratedPeer.ZERO_INSETS; + default: + return null; } - if (insLog.isLoggable(Level.FINEST)) insLog.finest("WM guessed insets: " + res); - return res; } + /* * Some buggy WMs ignore window gravity when processing * ConfigureRequest and position window as if the gravity is Static. @@ -1401,11 +1416,13 @@ } /** - * Asks WM to fill Frame Extents (insets) for the window. + * Asks the WM to fill Frame Extents (insets) for the window. + * + * @return true if a request has been actually sent, false otherwise. */ - public static void requestWMExtents(long window) { + public static boolean requestWMExtents(long window) { if (window == XConstants.None) { // not initialized - return; + return false; } log.fine("Requesting FRAME_EXTENTS"); @@ -1425,6 +1442,7 @@ false, XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask, msg.getPData()); + return true; } if (getWMID() == XWM.KDE2_WM) { msg.set_message_type(XA_KDE_NET_WM_FRAME_STRUT.getAtom()); @@ -1432,204 +1450,99 @@ false, XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask, msg.getPData()); + return true; } - // XXX: should we wait for response? XIfEvent() would be useful here :) } finally { XToolkit.awtUnlock(); msg.dispose(); } + return false; } - /* syncTopLEvelPos() is necessary to insure that the window manager has in - * fact moved us to our final position relative to the reParented WM window. - * We have noted a timing window which our shell has not been moved so we - * screw up the insets thinking they are 0,0. Wait (for a limited period of - * time to let the WM hava a chance to move us. - * @param window window ID of the shell, assuming it is the window - * which will NOT have zero coordinates after the complete - * reparenting + /** + * Indicates if the given atom represents a property containing the extents + * of a frame. */ - boolean syncTopLevelPos(long window, XWindowAttributes attrs) { - int tries = 0; - XToolkit.awtLock(); - try { - do { - XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), window, attrs.pData); - if (attrs.get_x() != 0 || attrs.get_y() != 0) { - return true; - } - tries++; - XToolkit.XSync(); - } while (tries < 50); - } - finally { - XToolkit.awtUnlock(); - } - return false; + public static boolean isExtentsPropertyAtom(long atom) { + return atom == XA_KDE_NET_WM_FRAME_STRUT.getAtom() + || atom == XA_NET_FRAME_EXTENTS.getAtom() + || atom == XA_E_FRAME_SIZE.getAtom(); } - Insets getInsets(XDecoratedPeer win, long window, long parent) { - /* - * Unfortunately the concept of "insets" borrowed to AWT - * from Win32 is *absolutely*, *unbelievably* foreign to - * X11. Few WMs provide the size of frame decor - * (i.e. insets) in a property they set on the client - * window, so we check if we can get away with just - * peeking at it. [Future versions of wm-spec might add a - * standardized hint for this]. - * - * Otherwise we do some special casing. Actually the - * fallback code ("default" case) seems to cover most of - * the existing WMs (modulo Reparent/Configure order - * perhaps?). - * - * Fallback code tries to account for the two most common cases: - * - * . single reparenting - * parent window is the WM frame - * [twm, olwm, sawfish] - * - * . double reparenting - * parent is a lining exactly the size of the client - * grandpa is the WM frame - * [mwm, e!, kwin, fvwm2 ... ] - */ - Insets correctWM = XWM.getInsetsFromExtents(window); - insLog.log(Level.FINER, "Got insets from property: {0}", correctWM); + // Synchronization: XWM.class + private static Integer syncDelay = null; - if (correctWM == null) { - correctWM = new Insets(0,0,0,0); + /** + * Retrieves the synchronization delay in milliseconds. + * + * Sending a request to the window manager and doing XSync(), we do not + * immediately get the requested result because the window manager is not + * the X server, but a separate process. An example of such request is the + * _NET_REQUEST_FRAME_EXTENTS: the _NET_FRAME_EXTENTS window property may + * be updated with a delay after the request has been dispatched to the X + * server via the XSync() method. + * + * To wait for the response we need a delay value. This method is supposed + * to return a reasonable value for such delay. The default value is + * considered fine when running on a local display. However, for + * connections over TCP, SSH, or other types of connections, the delay may + * have to be increased. For such purposes there's a private system + * property: sun.awt.wmsyncdelay that may be set to an integer value + * representing the number of milliseconds to wait for a window manager's + * reposnse. + */ + public static synchronized long getSyncDelay() { + if (syncDelay == null) { + syncDelay = AccessController.doPrivileged( + new GetIntegerAction("sun.awt.wmsyncdelay", 150)); + } + return syncDelay; + } + + private static XlibWrapper.CheckEventPredicate + checkExtentsUpdateEventPredicate = + new XlibWrapper.CheckEventPredicate() { + public boolean doesMatch(XEvent event) { + return event.get_type() == XConstants.PropertyNotify + && isExtentsPropertyAtom(event.get_xproperty().get_atom()); + } + }; - correctWM.top = -1; - correctWM.left = -1; + /** + * Waits for a PropertyNotify containing the requested frame extents. + * + * @return the PropertyNotify event, or null if nothing got dispatched + */ + public static XEvent waitForExtentsUpdateEvent() { + final long TRIES = 5; + long timeout = getSyncDelay(); + if (timeout < TRIES) { + timeout = TRIES; + } + final long delay = timeout / TRIES; - XWindowAttributes lwinAttr = new XWindowAttributes(); - XWindowAttributes pattr = new XWindowAttributes(); + XEvent event = null; + do { + XToolkit.awtLock(); try { - switch (XWM.getWMID()) { - /* should've been done in awt_wm_getInsetsFromProp */ - case XWM.ENLIGHTEN_WM: { - /* enlightenment does double reparenting */ - syncTopLevelPos(parent, lwinAttr); - correctWM.left = lwinAttr.get_x(); - correctWM.top = lwinAttr.get_y(); - /* - * Now get the actual dimensions of the parent window - * resolve the difference. We can't rely on the left - * to be equal to right or bottom... Enlightment - * breaks that assumption. - */ - XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), - XlibUtil.getParentWindow(parent), - pattr.pData); - correctWM.right = pattr.get_width() - - (lwinAttr.get_width() + correctWM.left); - correctWM.bottom = pattr.get_height() - - (lwinAttr.get_height() + correctWM.top); - - break; - } - case XWM.ICE_WM: // for 1.2.2. - case XWM.KDE2_WM: /* should've been done in getInsetsFromProp */ - case XWM.CDE_WM: - case XWM.MOTIF_WM: { - /* these are double reparenting too */ - if (syncTopLevelPos(parent, lwinAttr)) { - correctWM.top = lwinAttr.get_y(); - correctWM.left = lwinAttr.get_x(); - correctWM.right = correctWM.left; - correctWM.bottom = correctWM.left; - } else { - return null; - } - break; - } - case XWM.SAWFISH_WM: - case XWM.OPENLOOK_WM: { - /* single reparenting */ - syncTopLevelPos(window, lwinAttr); - correctWM.top = lwinAttr.get_y(); - correctWM.left = lwinAttr.get_x(); - correctWM.right = correctWM.left; - correctWM.bottom = correctWM.left; - break; - } - case XWM.OTHER_WM: - default: { /* this is very similar to the E! case above */ - insLog.log(Level.FINEST, "Getting correct insets for OTHER_WM/default, parent: {0}", parent); - syncTopLevelPos(parent, lwinAttr); - int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), - window, lwinAttr.pData); - status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), - parent, pattr.pData); - if (lwinAttr.get_root() == parent) { - insLog.finest("our parent is root so insets should be zero"); - correctWM = new Insets(0, 0, 0, 0); - break; - } - - /* - * Check for double-reparenting WM. - * - * If the parent is exactly the same size as the - * top-level assume taht it's the "lining" window and - * that the grandparent is the actual frame (NB: we - * have already handled undecorated windows). - * - * XXX: what about timing issues that syncTopLevelPos - * is supposed to work around? - */ - if (lwinAttr.get_x() == 0 && lwinAttr.get_y() == 0 - && lwinAttr.get_width()+2*lwinAttr.get_border_width() == pattr.get_width() - && lwinAttr.get_height()+2*lwinAttr.get_border_width() == pattr.get_height()) - { - insLog.log(Level.FINEST, "Double reparenting detected, pattr({2})={0}, lwinAttr({3})={1}", - new Object[] {lwinAttr, pattr, parent, window}); - lwinAttr.set_x(pattr.get_x()); - lwinAttr.set_y(pattr.get_y()); - lwinAttr.set_border_width(lwinAttr.get_border_width()+pattr.get_border_width()); - - final long grand_parent = XlibUtil.getParentWindow(parent); - - if (grand_parent == lwinAttr.get_root()) { - // This is not double-reparenting in a - // general sense - we simply don't have - // correct insets - return null to try to - // get insets later - return null; - } else { - parent = grand_parent; - XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), - parent, - pattr.pData); - } - } - /* - * XXX: To be absolutely correct, we'd need to take - * parent's border-width into account too, but the - * rest of the code is happily unaware about border - * widths and inner/outer distinction, so for the time - * being, just ignore it. - */ - insLog.log(Level.FINEST, "Attrs before calculation: pattr({2})={0}, lwinAttr({3})={1}", - new Object[] {lwinAttr, pattr, parent, window}); - correctWM = new Insets(lwinAttr.get_y() + lwinAttr.get_border_width(), - lwinAttr.get_x() + lwinAttr.get_border_width(), - pattr.get_height() - (lwinAttr.get_y() + lwinAttr.get_height() + 2*lwinAttr.get_border_width()), - pattr.get_width() - (lwinAttr.get_x() + lwinAttr.get_width() + 2*lwinAttr.get_border_width())); - break; - } /* default */ - } /* switch (runningWM) */ + XToolkit.XSync(); + event = XlibWrapper.CheckIfEvent(XToolkit.getDisplay(), + checkExtentsUpdateEventPredicate); } finally { - lwinAttr.dispose(); - pattr.dispose(); + XToolkit.awtUnlock(); } - } - if (storedInsets.get(win.getClass()) == null) { - storedInsets.put(win.getClass(), correctWM); - } - return correctWM; + if (event != null) { + break; + } + try { + Thread.sleep(delay); + } catch (InterruptedException ex) { + } + } while ((timeout -= delay) > 0); + + return event; } + boolean isDesktopWindow( long w ) { if (g_net_protocol != null) { XAtomList wtype = XAtom.get("_NET_WM_WINDOW_TYPE").getAtomListPropertyList( w ); --- old/src/solaris/native/sun/awt/awt_Component.h 2009-08-11 19:21:30.000000000 +0400 +++ new/src/solaris/native/sun/awt/awt_Component.h 2009-08-11 19:21:29.000000000 +0400 @@ -34,7 +34,6 @@ jfieldID peer; jfieldID background; jfieldID foreground; - jfieldID isPacked; jfieldID graphicsConfig; jfieldID name; jfieldID isProxyActive; --- old/src/solaris/native/sun/xawt/XlibWrapper.c 2009-08-11 19:21:31.000000000 +0400 +++ new/src/solaris/native/sun/xawt/XlibWrapper.c 2009-08-11 19:21:30.000000000 +0400 @@ -2163,3 +2163,43 @@ (*env)->ReleaseIntArrayElements(env, bitmap, values, JNI_ABORT); } +typedef struct { + JNIEnv *env; + jobject predicateObject; + jmethodID predicateMID; + + jobject event; +} CheckIfEventStruct; + +static Bool +check_if_event_predicate(Display* dpy, XEvent* event, char* arg) { + CheckIfEventStruct * data = (CheckIfEventStruct *)arg; + //NOTE: event == data->event.pData + + return (Bool)((*(data->env))->CallBooleanMethod(data->env, + data->predicateObject, data->predicateMID, + data->event)); +} + +JNIEXPORT jboolean JNICALL +Java_sun_awt_X11_XlibWrapper_CheckIfEvent +(JNIEnv *env, jclass clazz, jlong display, jobject event, jlong event_return, jobject predicate) +{ + //NOTE: event_return == event.pData + + AWT_CHECK_HAVE_LOCK(); + + CheckIfEventStruct data; + + data.env = env; + data.predicateObject = predicate; + data.predicateMID = (*env)->GetMethodID(env, + (*env)->GetObjectClass(env, predicate), + "doesMatch", "(Lsun/awt/X11/XEvent;)Z"); + data.event = event; + + return (jboolean)XCheckIfEvent((Display *)jlong_to_ptr(display), + (XEvent *)jlong_to_ptr(event_return), check_if_event_predicate, + (char*)&data); +} + --- old/src/solaris/native/sun/xawt/XToolkit.c 2009-08-11 19:21:32.000000000 +0400 +++ new/src/solaris/native/sun/xawt/XToolkit.c 2009-08-11 19:21:31.000000000 +0400 @@ -162,7 +162,6 @@ componentIDs.y = (*env)->GetFieldID(env, cls, "y", "I"); componentIDs.width = (*env)->GetFieldID(env, cls, "width", "I"); componentIDs.height = (*env)->GetFieldID(env, cls, "height", "I"); - componentIDs.isPacked = (*env)->GetFieldID(env, cls, "isPacked", "Z"); componentIDs.peer = (*env)->GetFieldID(env, cls, "peer", "Ljava/awt/peer/ComponentPeer;"); componentIDs.background =