src/solaris/classes/sun/awt/X11/XDecoratedPeer.java

Print this page

        

*** 1,7 **** /* ! * Copyright 2002-2008 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this --- 1,7 ---- /* ! * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this
*** 31,58 **** import java.awt.event.WindowEvent; import java.util.logging.Level; import java.util.logging.Logger; import sun.awt.ComponentAccessor; import sun.awt.SunToolkit; abstract class XDecoratedPeer extends XWindowPeer { private static final Logger log = Logger.getLogger("sun.awt.X11.XDecoratedPeer"); private static final Logger insLog = Logger.getLogger("sun.awt.X11.insets.XDecoratedPeer"); 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; XContentWindow content; - Insets currentInsets; XFocusProxyWindow focusProxy; XDecoratedPeer(Window target) { super(target); } --- 31,63 ---- import java.awt.event.WindowEvent; import java.util.logging.Level; import java.util.logging.Logger; + import sun.awt.AWTAccessor; import sun.awt.ComponentAccessor; import sun.awt.SunToolkit; abstract class XDecoratedPeer extends XWindowPeer { private static final Logger log = Logger.getLogger("sun.awt.X11.XDecoratedPeer"); private static final Logger insLog = Logger.getLogger("sun.awt.X11.insets.XDecoratedPeer"); private static final Logger focusLog = Logger.getLogger("sun.awt.X11.focus.XDecoratedPeer"); private static final Logger iconLog = Logger.getLogger("sun.awt.X11.icon.XDecoratedPeer"); XIconWindow iconWindow; ! ! /** ! * 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; XFocusProxyWindow focusProxy; XDecoratedPeer(Window target) { super(target); }
*** 71,85 **** void preInit(XCreateWindowParams params) { 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); params.put(BOUNDS, dimensions.getClientRect()); insLog.log(Level.FINE, "Initial dimensions {0}", new Object[] { dimensions }); // Deny default processing of these events on the shell - proxy will take care of // them instead --- 76,87 ---- void preInit(XCreateWindowParams params) { super.preInit(params); winAttr.initialFocus = true; Rectangle bounds = (Rectangle)params.get(BOUNDS); ! dimensions = new WindowDimensions(bounds, getNativeInsets(), false); params.put(BOUNDS, dimensions.getClientRect()); insLog.log(Level.FINE, "Initial dimensions {0}", new Object[] { dimensions }); // Deny default processing of these events on the shell - proxy will take care of // them instead
*** 91,101 **** super.postInit(params); // The lines that follow need to be in a postInit, so they // happen after the X window is created. initResizability(); updateSizeHints(dimensions); - XWM.requestWMExtents(getWindow()); content = XContentWindow.createContent(this); if (warningWindow != null) { warningWindow.toFront(); --- 93,102 ----
*** 114,131 **** } } public void updateMinimumSize() { super.updateMinimumSize(); ! updateMinSizeHints(); } ! private void updateMinSizeHints() { 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; if (minHeight < 0) minHeight = 0; setSizeHints(XUtilConstants.PMinSize | (isLocationByPlatform()?0:(XUtilConstants.PPosition | XUtilConstants.USPosition)), --- 115,131 ---- } } public void updateMinimumSize() { super.updateMinimumSize(); ! updateMinSizeHints(getNativeInsets()); } ! private void updateMinSizeHints(Insets insets) { if (isResizable()) { Dimension minimumSize = getTargetMinimumSize(); if (minimumSize != null) { int minWidth = minimumSize.width - insets.left - insets.right; int minHeight = minimumSize.height - insets.top - insets.bottom; if (minWidth < 0) minWidth = 0; if (minHeight < 0) minHeight = 0; setSizeHints(XUtilConstants.PMinSize | (isLocationByPlatform()?0:(XUtilConstants.PPosition | XUtilConstants.USPosition)),
*** 229,465 **** /*************************************************************************************** * I N S E T S C O D E **************************************************************************************/ - protected boolean isInitialReshape() { - return false; - } ! 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); ! } ! private static boolean isNull(Insets i) { ! return (i == null) || ((i.left | i.top | i.right | i.bottom) == 0); } ! ! private static Insets copy(Insets i) { ! return new Insets(i.top, i.left, i.bottom, i.right); } ! ! // insets which we get from WM (e.g from _NET_FRAME_EXTENTS) ! private Insets wm_set_insets; ! ! private Insets getWMSetInsets(XAtom changedAtom) { ! if (isEmbedded()) { ! return null; } ! ! if (wm_set_insets != null) { ! return wm_set_insets; } - - if (changedAtom == null) { - wm_set_insets = XWM.getInsetsFromExtents(getWindow()); - } else { - wm_set_insets = XWM.getInsetsFromProp(getWindow(), changedAtom); } ! insLog.log(Level.FINER, "FRAME_EXTENTS: {0}", new Object[]{wm_set_insets}); ! if (wm_set_insets != null) { ! wm_set_insets = copy(wm_set_insets); } ! return wm_set_insets; } ! private void resetWMSetInsets() { ! wm_set_insets = null; } ! 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())); } } ! long reparent_serial = 0; ! ! public void handleReparentNotifyEvent(XEvent 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 (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 (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 (correctWM != null) { ! handleCorrectInsets(correctWM); } } - } finally { - XToolkit.awtUnlock(); } } ! 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(); } } ! public void handleMoved(WindowDimensions dims) { ! Point loc = dims.getLocation(); ! 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() { target.invalidate(); target.validate(); } }); } - 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(); } // The height of area used to display current active input method --- 229,517 ---- /*************************************************************************************** * I N S E T S C O D E **************************************************************************************/ ! /** ! * 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; } ! /** ! * 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(); } ! /** ! * 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 void setNativeInsets(Insets insets) { XToolkit.awtLock(); try { ! nativeInsets = insets == null ? null : ! sanitize((Insets)insets.clone()); ! } finally { ! XToolkit.awtUnlock(); ! } } ! public static final Insets DEFAULT_INSETS = new Insets(25, 5, 5, 5); ! public static final Insets ZERO_INSETS = new Insets(0, 0, 0, 0); ! ! /** ! * 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(); } ! ! // 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; } ! // 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; } ! Rectangle parentRect = XlibUtil.getWindowGeometry(parent); ! if (parentRect == null) { ! // Some error again ! return; } + + 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)); } } } ! /** ! * 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 (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); } } } ! // 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()); } + if (xe.get_window() != getWindow()) { + return; + } ! 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; ! ! setNativeInsets(null); ! needToAdjustBounds(); } } + + protected boolean isInitialReshape() { + return false; } ! public void handleMoved(Point loc) { ! ComponentAccessor.setX((Component)target, loc.x); ! ComponentAccessor.setY((Component)target, loc.y); ! postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); } + public void revalidate() { XToolkit.executeOnEventHandlerThread(target, new Runnable() { public void run() { target.invalidate(); target.validate(); } }); } boolean gravityBug() { return XWM.configureGravityBuggy(); } // The height of area used to display current active input method
*** 477,542 **** updateSizeHints(dimensions); } // Coordinates are that of the target // Called only on Toolkit thread ! public void reshape(WindowDimensions newDimensions, int op, ! boolean userReshape) { 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()); } 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(); ! checkShellRect(client); ! setShellBounds(client); ! if (content != null && ! !content.getSize().equals(newDimensions.getSize())) { ! reconfigureContentWindow(newDimensions); } return; } ! int wm = XWM.getWMID(); ! updateChildrenSizes(); ! applyGuessedInsets(); Rectangle shellRect = newDimensions.getClientRect(); if (gravityBug()) { Insets in = newDimensions.getInsets(); --- 529,627 ---- updateSizeHints(dimensions); } // Coordinates are that of the target // Called only on Toolkit thread ! private void reshape(WindowDimensions newDimensions, int op) { if (insLog.isLoggable(Level.FINE)) { ! insLog.fine("Reshaping " + this + " to " + newDimensions + ! "; op " + operationToString(op)); } XToolkit.awtLock(); try { ! if (!isVisible()) { ! Rectangle client = newDimensions.getClientRect(); ! checkShellRect(client); ! setShellBounds(client); ! ! reportReshape(newDimensions); ! } else { ! requestReshape(newDimensions, op); ! } ! } finally { ! XToolkit.awtUnlock(); ! } ! } ! ! /** ! * 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); ! } ! ! final Insets insets = newDims.getInsets(); ! if (!insets.equals(dimensions.getInsets())) { ! // Recalculate the minimum size of the client area ! updateMinSizeHints(insets); ! } ! ! // 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()); ! ! checkIfOnNewScreen(newDims.getBounds()); ! Point oldLocation = getLocation(); + dimensions = newDims; + if (!getLocation().equals(oldLocation)) { + handleMoved(getLocation()); + } ! 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)); ! } Rectangle shellRect = newDimensions.getClientRect(); if (gravityBug()) { Insets in = newDimensions.getInsets();
*** 566,590 **** XWM.setShellNotResizable(this, newDimensions, shellRect, true); if (op == SET_BOUNDS) { setShellPosition(shellRect); } } - - reconfigureContentWindow(newDimensions); - } finally { - XToolkit.awtUnlock(); - } } /** ! * @param x, y, width, heith - dimensions of the window with insets */ ! private void reshape(int x, int y, int width, int height, int operation, ! boolean userReshape) ! { ! Rectangle newRec; ! boolean setClient = false; WindowDimensions dims = new WindowDimensions(dimensions); switch (operation & (~NO_EMBEDDED_CHECK)) { case SET_LOCATION: // Set location always sets bounds location. However, until the window is mapped we // should use client coordinates --- 651,669 ---- XWM.setShellNotResizable(this, newDimensions, shellRect, true); if (op == SET_BOUNDS) { setShellPosition(shellRect); } } } + // This method gets overriden in XFramePeer & XDialogPeer. + abstract boolean isTargetUndecorated(); + /** ! * @see java.awt.peer.ComponentPeer#setBounds */ ! 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: // Set location always sets bounds location. However, until the window is mapped we // should use client coordinates
*** 595,770 **** // should use client coordinates dims.setSize(width, height); break; case SET_CLIENT_SIZE: { // Sets client rect size. Width and height contain insets. ! Insets in = currentInsets; width -= in.left+in.right; height -= in.top+in.bottom; dims.setClientSize(width, height); break; } case SET_BOUNDS: default: dims.setLocation(x, y); 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, userReshape); } - // This method gets overriden in XFramePeer & XDialogPeer. - abstract boolean isTargetUndecorated(); - /** ! * @see java.awt.peer.ComponentPeer#setBounds */ ! 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(); ! } ! ! // Coordinates are that of the shell ! void reconfigureContentWindow(WindowDimensions dims) { if (content == null) { insLog.fine("WARNING: Content window is null"); ! return; } ! 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: should really only consider synthetic events, but ! if (isReparented()) { ! configure_seen = true; } - - if (!isMaximized() - && (xe.get_serial() == reparent_serial || xe.get_window() != getShell()) - && !no_reparent_artifacts) - { - insLog.fine("- reparent artifact, skipping"); - return; } - 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; } ! /* ! * 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 (insLog.isLoggable(Level.FINE)) { ! insLog.log(Level.FINE, "reparented={0}, visible={1}, WM={2}, decorations={3}", ! new Object[] {isReparented(), isVisible(), runningWM, getDecorations()}); } ! if (!isReparented() && isVisible() && runningWM != XWM.NO_WM ! && !XWM.isNonReparentingWM() ! && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { ! insLog.fine("- visible but not reparented, skipping"); ! 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; } } ! updateChildrenSizes(); ! // 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; } - 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(); ! repositionSecurityWarning(); } private void checkShellRectSize(Rectangle shellRect) { if (shellRect.width < 0) { shellRect.width = 1; --- 674,963 ---- // should use client coordinates dims.setSize(width, height); break; case SET_CLIENT_SIZE: { // Sets client rect size. Width and height contain insets. ! // 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: default: dims.setLocation(x, y); dims.setSize(width, height); break; } ! reshape(dims, operation); ! validateSurface(); } /** ! * 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); } ! /** ! * Indicates if the adjustBounds() needs to be invoked. ! * Synchronization: state lock. ! */ ! private boolean areBoundsAdjusted = false; ! /** ! * Forces the system to re-adjust the bounds of the window after it has ! * been finally adopted by the windowing system. ! */ ! private void needToAdjustBounds() { ! synchronized (getStateLock()) { ! areBoundsAdjusted = false; } } /** ! * Indicates if the window bounds has not yet been finally configured by ! * the X server/window manager. */ ! public boolean areBoundsAdjusting() { ! synchronized (getStateLock()) { ! return !areBoundsAdjusted; ! } } ! // 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; } ! ! /** ! * 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; } ! int operation = 0; ! boolean isPacked = AWTAccessor.getWindowAccessor(). ! isPacked((Window)target); ! if (!newDims.getClientSize().equals(dimensions.getClientSize()) ! && isPacked) { ! // 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; } ! ! if (isUserSpecifiedPositionSet() && ! !newDims.getLocation().equals(dimensions.getLocation())) ! { ! // The user also requested a specific position ! if (operation == 0) { ! operation = SET_LOCATION; ! } else { ! operation = SET_BOUNDS; } } + + 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.fine("Request: " + dims + "; operation=" + ! operationToString(operation)); ! } ! 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; } ! if (insLog.isLoggable(Level.FINE)) { ! insLog.fine("" + xe); ! insLog.fine("XWM.isRunning: " + XWM.isRunning()); ! } ! ! // 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; ! } ! ! // 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; ! } ! } ! } ! ! // At this point we can calculate some reliable insets ! Insets insets = getNativeInsets(); ! ! // 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) { if (shellRect.width < 0) { shellRect.width = 1;
*** 830,858 **** setResizable(winAttr.initialResizability); } public void setResizable(boolean resizable) { int fs = winAttr.functions; if (!isResizable() && resizable) { ! currentInsets = new Insets(0, 0, 0, 0); ! resetWMSetInsets(); ! if (!isEmbedded()) { ! setReparented(false); ! } winAttr.isResizable = resizable; if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); } else { fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); } winAttr.functions = fs; XWM.setShellResizable(this); } else if (isResizable() && !resizable) { ! currentInsets = new Insets(0, 0, 0, 0); ! resetWMSetInsets(); ! if (!isEmbedded()) { ! setReparented(false); ! } winAttr.isResizable = resizable; if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); } else { fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); --- 1023,1043 ---- setResizable(winAttr.initialResizability); } public void setResizable(boolean resizable) { int fs = winAttr.functions; if (!isResizable() && resizable) { ! setNativeInsets(null); winAttr.isResizable = resizable; if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); } else { fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); } winAttr.functions = fs; XWM.setShellResizable(this); } else if (isResizable() && !resizable) { ! setNativeInsets(null); winAttr.isResizable = resizable; if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); } else { fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
*** 909,925 **** } public Point getLocationOnScreen() { XToolkit.awtLock(); try { ! if (configure_seen) { return toGlobal(0,0); } else { Point location = target.getLocation(); ! if (insLog.isLoggable(Level.FINE)) insLog.log(Level.FINE, "getLocationOnScreen {0} not reparented: {1} ", new Object[] {this, location}); return location; } } finally { XToolkit.awtUnlock(); } --- 1094,1111 ---- } public Point getLocationOnScreen() { XToolkit.awtLock(); try { ! if (!areBoundsAdjusting()) { return toGlobal(0,0); } else { Point location = target.getLocation(); ! if (insLog.isLoggable(Level.FINE)) { insLog.log(Level.FINE, "getLocationOnScreen {0} not reparented: {1} ", new Object[] {this, location}); + } return location; } } finally { XToolkit.awtUnlock(); }
*** 1055,1065 **** final void dumpContent() { dumpWindow("Content", getContentWindow()); } final void dumpParent() { long parent = XlibUtil.getParentWindow(getShell()); ! if (parent != 0) { dumpWindow("Parent", parent); } else { --- 1241,1251 ---- final void dumpContent() { dumpWindow("Content", getContentWindow()); } final void dumpParent() { long parent = XlibUtil.getParentWindow(getShell()); ! if (parent != XConstants.None) { dumpWindow("Parent", parent); } else {
*** 1098,1108 **** boolean isMaximized() { return false; } boolean isOverrideRedirect() { - // return false; return ((XToolkit)Toolkit.getDefaultToolkit()).isOverrideRedirect((Window)target); } public boolean requestWindowFocus(long time, boolean timeProvided) { focusLog.fine("Request for decorated window focus"); --- 1284,1293 ----