--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,1195 @@
+/*
+ * Copyright 2002-2007 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.awt.X11;
+
+import java.awt.*;
+
+import java.awt.event.ComponentEvent;
+import java.awt.event.InvocationEvent;
+import java.awt.event.WindowEvent;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import sun.awt.ComponentAccessor;
+import sun.awt.SunToolkit;
+
+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 final static Logger iconLog = Logger.getLogger("sun.awt.X11.icon.XDecoratedPeer");
+
+ private static XAtom resize_request = new XAtom("_SUN_AWT_RESIZE_REQUEST", false);
+
+ // 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);
+ }
+
+ XDecoratedPeer(XCreateWindowParams params) {
+ super(params);
+ }
+
+ public long getShell() {
+ return window;
+ }
+
+ public long getContentWindow() {
+ return (content == null) ? window : content.getWindow();
+ }
+
+ void preInit(XCreateWindowParams params) {
+ super.preInit(params);
+ if (!resize_request.isInterned()) {
+ resize_request.intern(false);
+ }
+ winAttr.initialFocus = true;
+
+ currentInsets = new Insets(0,0,0,0); // replacemenet for wdata->top, left, bottom, right
+
+ 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
+ Long eventMask = (Long)params.get(EVENT_MASK);
+ params.add(EVENT_MASK, Long.valueOf(eventMask.longValue() & ~(FocusChangeMask | KeyPressMask | KeyReleaseMask)));
+ }
+
+ void postInit(XCreateWindowParams params) {
+ 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);
+ content = createContent(dimensions);
+ content.initialize();
+ if (warningWindow != null) {
+ warningWindow.toFront();
+ }
+ focusProxy = createFocusProxy();
+ }
+
+ void setIconHints(java.util.List<XIconInfo> icons) {
+ if (!XWM.getWM().setNetWMIcon(this, icons)) {
+ if (icons.size() > 0) {
+ if (iconWindow == null) {
+ iconWindow = new XIconWindow(this);
+ }
+ iconWindow.setIconImages(icons);
+ }
+ }
+ }
+
+ 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(XlibWrapper.PMinSize | (isLocationByPlatform()?0:(XlibWrapper.PPosition | XlibWrapper.USPosition)),
+ getX(), getY(), minWidth, minHeight);
+ if (isVisible()) {
+ Rectangle bounds = getShellBounds();
+ int nw = (bounds.width < minWidth) ? minWidth : bounds.width;
+ int nh = (bounds.height < minHeight) ? minHeight : bounds.height;
+ if (nw != bounds.width || nh != bounds.height) {
+ setShellSize(new Rectangle(0, 0, nw, nh));
+ }
+ }
+ } else {
+ boolean isMinSizeSet = isMinSizeSet();
+ XWM.removeSizeHints(this, XlibWrapper.PMinSize);
+ /* Some WMs need remap to redecorate the window */
+ if (isMinSizeSet && isShowing() && XWM.needRemap(this)) {
+ /*
+ * Do the re/mapping at the Xlib level. Since we essentially
+ * work around a WM bug we don't want this hack to be exposed
+ * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
+ */
+ xSetVisible(false);
+ XToolkit.XSync();
+ xSetVisible(true);
+ }
+ }
+ }
+ }
+
+ XContentWindow createContent(WindowDimensions dims) {
+ Rectangle rec = dims.getBounds();
+ // Fix for - set the location of the content window to the (-left inset, -top inset)
+ Insets ins = dims.getInsets();
+ if (ins != null) {
+ rec.x = -ins.left;
+ rec.y = -ins.top;
+ } else {
+ rec.x = 0;
+ rec.y = 0;
+ }
+ return new XContentWindow(this, rec);
+ }
+
+ XFocusProxyWindow createFocusProxy() {
+ return new XFocusProxyWindow(this);
+ }
+
+ protected XAtomList getWMProtocols() {
+ XAtomList protocols = super.getWMProtocols();
+ protocols.add(wm_delete_window);
+ protocols.add(wm_take_focus);
+ return protocols;
+ }
+
+ public Graphics getGraphics() {
+ return getGraphics(content.surfaceData,
+ ComponentAccessor.getForeground(target),
+ ComponentAccessor.getBackground(target),
+ ComponentAccessor.getFont_NoClientCode(target));
+ }
+
+ public void setTitle(String title) {
+ if (log.isLoggable(Level.FINE)) log.fine("Title is " + title);
+ winAttr.title = title;
+ updateWMName();
+ }
+
+ protected String getWMName() {
+ if (winAttr.title == null || winAttr.title.trim().equals("")) {
+ return " ";
+ } else {
+ return winAttr.title;
+ }
+ }
+
+ void updateWMName() {
+ super.updateWMName();
+ String name = getWMName();
+ XToolkit.awtLock();
+ try {
+ if (name == null || name.trim().equals("")) {
+ name = "Java";
+ }
+ XAtom iconNameAtom = XAtom.get(XAtom.XA_WM_ICON_NAME);
+ iconNameAtom.setProperty(getWindow(), name);
+ XAtom netIconNameAtom = XAtom.get("_NET_WM_ICON_NAME");
+ netIconNameAtom.setPropertyUTF8(getWindow(), name);
+ } finally {
+ XToolkit.awtUnlock();
+ }
+ }
+
+ // NOTE: This method may be called by privileged threads.
+ // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
+ public void handleIconify() {
+ postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED));
+ }
+
+ // NOTE: This method may be called by privileged threads.
+ // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
+ public void handleDeiconify() {
+ postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED));
+ }
+
+ public void handleFocusEvent(XEvent xev) {
+ super.handleFocusEvent(xev);
+ XFocusChangeEvent xfe = xev.get_xfocus();
+
+ // If we somehow received focus events forward it instead to proxy
+ // FIXME: Shouldn't we instead check for inferrior?
+ focusLog.finer("Received focus event on shell: " + xfe);
+// focusProxy.xRequestFocus();
+ }
+
+/***************************************************************************************
+ * I N S E T S C O D E
+ **************************************************************************************/
+
+ protected boolean isInitialReshape() {
+ return false;
+ }
+
+ 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);
+ }
+
+ void add(Insets i1, Insets i2) {
+ i1.left += i2.left;
+ i1.top += i2.top;
+ i1.right += i2.right;
+ i1.bottom += i2.bottom;
+ }
+ boolean isNull(Insets i) {
+ return (i == null) || ((i.left | i.top | i.right | i.bottom) == 0);
+ }
+ Insets copy(Insets i) {
+ return new Insets(i.top, i.left, i.bottom, i.right);
+ }
+
+ 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() == winAttr.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)) {
+ /*
+ * Actual insets account for menubar/warning label,
+ * so we can't assign directly but must adjust them.
+ */
+ add(currentInsets, correction);
+ 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 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 (insLog.isLoggable(Level.FINER)) insLog.finer("Dimensions before reparent: " + dimensions);
+
+ dimensions.setInsets(getRealInsets());
+ insets_corrected = true;
+
+ if (isMaximized()) {
+ return;
+ }
+
+ if ((getHints().get_flags() & (USPosition | 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()) {
+ return new Insets(0, 0, 0, 0);
+ } else {
+ if (currentInsets.top > 0) {
+ /* 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);
+ insets = copy(currentInsets);
+ }
+
+ public void revalidate() {
+ XToolkit.executeOnEventHandlerThread(target, new Runnable() {
+ public void run() {
+ target.invalidate();
+ target.validate();
+ }
+ });
+ }
+
+ Insets getRealInsets() {
+ if (isNull(insets)) {
+ applyGuessedInsets();
+ }
+ return insets;
+ }
+
+ public Insets getInsets() {
+ Insets in = copy(getRealInsets());
+ in.top += getMenuBarHeight() + getWarningWindowHeight();
+ 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
+ int getInputMethodHeight() {
+ return 0;
+ }
+
+ void updateSizeHints(WindowDimensions dims) {
+ Rectangle rec = dims.getClientRect();
+ checkShellRect(rec);
+ updateSizeHints(rec.x, rec.y, rec.width, rec.height);
+ }
+
+ void updateSizeHints() {
+ 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);
+ }
+ 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();
+ 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 {
+ setShellSize(shellRect);
+ }
+ } else {
+ 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
+ dims.setLocation(x, y);
+ break;
+ case SET_SIZE:
+ // Set size sets bounds size. However, until the window is mapped we
+ // 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);
+ }
+
+ /**
+ * @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() != winAttr.AWT_DECOR_NONE) {
+ insLog.fine("- visible but not reparented, skipping");
+ return;
+ }
+ //Last chance to correct insets
+ if (!insets_corrected && getDecorations() != winAttr.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();
+ }
+
+ private void checkShellRectSize(Rectangle shellRect) {
+ if (shellRect.width < 0) {
+ shellRect.width = 1;
+ }
+ if (shellRect.height < 0) {
+ shellRect.height = 1;
+ }
+ }
+
+ private void checkShellRectPos(Rectangle shellRect) {
+ int wm = XWM.getWMID();
+ if (wm == XWM.MOTIF_WM || wm == XWM.CDE_WM) {
+ if (shellRect.x == 0 && shellRect.y == 0) {
+ shellRect.x = shellRect.y = 1;
+ }
+ }
+ }
+
+ private void checkShellRect(Rectangle shellRect) {
+ checkShellRectSize(shellRect);
+ checkShellRectPos(shellRect);
+ }
+
+ public void setShellBounds(Rectangle rec) {
+ if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell bounds on " +
+ this + " to " + rec);
+ XToolkit.awtLock();
+ try {
+ updateSizeHints(rec.x, rec.y, rec.width, rec.height);
+ XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height);
+ XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y);
+ }
+ finally {
+ XToolkit.awtUnlock();
+ }
+ }
+ public void setShellSize(Rectangle rec) {
+ if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell size on " +
+ this + " to " + rec);
+ XToolkit.awtLock();
+ try {
+ updateSizeHints(rec.x, rec.y, rec.width, rec.height);
+ XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height);
+ }
+ finally {
+ XToolkit.awtUnlock();
+ }
+ }
+ public void setShellPosition(Rectangle rec) {
+ if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell position on " +
+ this + " to " + rec);
+ XToolkit.awtLock();
+ try {
+ updateSizeHints(rec.x, rec.y, rec.width, rec.height);
+ XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y);
+ }
+ finally {
+ XToolkit.awtUnlock();
+ }
+ }
+
+ void initResizability() {
+ setResizable(winAttr.initialResizability);
+ }
+ public void setResizable(boolean resizable) {
+ int fs = winAttr.functions;
+ if (!isResizable() && resizable) {
+ insets = currentInsets = new Insets(0, 0, 0, 0);
+ resetWMSetInsets();
+ if (!isEmbedded()) {
+ setReparented(false);
+ }
+ winAttr.isResizable = resizable;
+ if ((fs & MWM_FUNC_ALL) != 0) {
+ fs &= ~(MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
+ } else {
+ fs |= (MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
+ }
+ winAttr.functions = fs;
+ XWM.setShellResizable(this);
+ } else if (isResizable() && !resizable) {
+ insets = currentInsets = new Insets(0, 0, 0, 0);
+ resetWMSetInsets();
+ if (!isEmbedded()) {
+ setReparented(false);
+ }
+ winAttr.isResizable = resizable;
+ if ((fs & MWM_FUNC_ALL) != 0) {
+ fs |= (MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
+ } else {
+ fs &= ~(MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
+ }
+ winAttr.functions = fs;
+ XWM.setShellNotResizable(this, dimensions, dimensions.getScreenBounds(), false);
+ }
+ }
+
+ Rectangle getShellBounds() {
+ return dimensions.getClientRect();
+ }
+
+ public Rectangle getBounds() {
+ return dimensions.getBounds();
+ }
+
+ public Dimension getSize() {
+ return dimensions.getSize();
+ }
+
+ public int getX() {
+ return dimensions.getLocation().x;
+ }
+
+ public int getY() {
+ return dimensions.getLocation().y;
+ }
+
+ public Point getLocation() {
+ return dimensions.getLocation();
+ }
+
+ public int getAbsoluteX() {
+ // NOTE: returning this peer's location which is shell location
+ return dimensions.getScreenBounds().x;
+ }
+
+ public int getAbsoluteY() {
+ // NOTE: returning this peer's location which is shell location
+ return dimensions.getScreenBounds().y;
+ }
+
+ public int getWidth() {
+ return getSize().width;
+ }
+
+ public int getHeight() {
+ return getSize().height;
+ }
+
+ public WindowDimensions getDimensions() {
+ return dimensions;
+ }
+
+ 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();
+ }
+ }
+
+
+/***************************************************************************************
+ * END OF I N S E T S C O D E
+ **************************************************************************************/
+
+ protected boolean isEventDisabled(XEvent e) {
+ switch (e.get_type()) {
+ // Do not generate MOVED/RESIZED events since we generate them by ourselves
+ case ConfigureNotify:
+ return true;
+ case EnterNotify:
+ case LeaveNotify:
+ // Disable crossing event on outer borders of Frame so
+ // we receive only one set of cross notifications(first set is from content window)
+ return true;
+ default:
+ return super.isEventDisabled(e);
+ }
+ }
+
+ int getDecorations() {
+ return winAttr.decorations;
+ }
+
+ int getFunctions() {
+ return winAttr.functions;
+ }
+
+ public void setVisible(boolean vis) {
+ log.log(Level.FINER, "Setting {0} to visible {1}", new Object[] {this, Boolean.valueOf(vis)});
+ if (vis && !isVisible()) {
+ XWM.setShellDecor(this);
+ super.setVisible(vis);
+ if (winAttr.isResizable) {
+ //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
+ //We need to update frame's minimum size, not to reset it
+ XWM.removeSizeHints(this, XlibWrapper.PMaxSize);
+ updateMinimumSize();
+ }
+ } else {
+ super.setVisible(vis);
+ }
+ }
+
+ protected void suppressWmTakeFocus(boolean doSuppress) {
+ XAtomList protocols = getWMProtocols();
+ if (doSuppress) {
+ protocols.remove(wm_take_focus);
+ } else {
+ protocols.add(wm_take_focus);
+ }
+ wm_protocols.setAtomListProperty(this, protocols);
+ }
+
+ public void dispose() {
+ if (content != null) {
+ content.destroy();
+ }
+ focusProxy.destroy();
+
+ if (iconWindow != null) {
+ iconWindow.destroy();
+ }
+
+ super.dispose();
+ }
+
+ public void handleClientMessage(XEvent xev) {
+ super.handleClientMessage(xev);
+ XClientMessageEvent cl = xev.get_xclient();
+ if ((wm_protocols != null) && (cl.get_message_type() == wm_protocols.getAtom())) {
+ if (cl.get_data(0) == wm_delete_window.getAtom()) {
+ handleQuit();
+ } else if (cl.get_data(0) == wm_take_focus.getAtom()) {
+ handleWmTakeFocus(cl);
+ }
+ } else if (cl.get_message_type() == resize_request.getAtom()) {
+ reshape((int)cl.get_data(0), (int)cl.get_data(1),
+ (int)cl.get_data(2), (int)cl.get_data(3),
+ (int)cl.get_data(4), true);
+ }
+ }
+
+ private void handleWmTakeFocus(XClientMessageEvent cl) {
+ focusLog.log(Level.FINE, "WM_TAKE_FOCUS on {0}", new Object[]{this});
+ requestWindowFocus(cl.get_data(1), true);
+ }
+
+ /**
+ * Requests focus to this decorated top-level by requesting X input focus
+ * to the shell window.
+ */
+ protected void requestXFocus(long time, boolean timeProvided) {
+ // We have proxied focus mechanism - instead of shell the focus is held
+ // by "proxy" - invisible mapped window. When we want to set X input focus to
+ // toplevel set it on proxy instead.
+ if (focusProxy == null) {
+ if (focusLog.isLoggable(Level.FINE)) focusLog.warning("Focus proxy is null for " + this);
+ } else {
+ if (focusLog.isLoggable(Level.FINE)) focusLog.fine("Requesting focus to proxy: " + focusProxy);
+ if (timeProvided) {
+ focusProxy.xRequestFocus(time);
+ } else {
+ focusProxy.xRequestFocus();
+ }
+ }
+ }
+
+ XFocusProxyWindow getFocusProxy() {
+ return focusProxy;
+ }
+
+ public void handleQuit() {
+ postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING));
+ }
+
+ final void dumpMe() {
+ System.err.println(">>> Peer: " + x + ", " + y + ", " + width + ", " + height);
+ }
+
+ final void dumpTarget() {
+ int getWidth = ComponentAccessor.getWidth((Component)target);
+ int getHeight = ComponentAccessor.getHeight((Component)target);
+ int getTargetX = ComponentAccessor.getX((Component)target);
+ int getTargetY = ComponentAccessor.getY((Component)target);
+ System.err.println(">>> Target: " + getTargetX + ", " + getTargetY + ", " + getWidth + ", " + getHeight);
+ }
+
+ final void dumpShell() {
+ dumpWindow("Shell", getShell());
+ }
+ final void dumpContent() {
+ dumpWindow("Content", getContentWindow());
+ }
+ final void dumpParent() {
+ long parent = XlibUtil.getParentWindow(getShell());
+ if (parent != 0)
+ {
+ dumpWindow("Parent", parent);
+ }
+ else
+ {
+ System.err.println(">>> NO PARENT");
+ }
+ }
+
+ final void dumpWindow(String id, long window) {
+ XWindowAttributes pattr = new XWindowAttributes();
+ try {
+ XToolkit.awtLock();
+ try {
+ int status =
+ XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
+ window, pattr.pData);
+ }
+ finally {
+ XToolkit.awtUnlock();
+ }
+ System.err.println(">>>> " + id + ": " + pattr.get_x()
+ + ", " + pattr.get_y() + ", " + pattr.get_width()
+ + ", " + pattr.get_height());
+ } finally {
+ pattr.dispose();
+ }
+ }
+
+ final void dumpAll() {
+ dumpTarget();
+ dumpMe();
+ dumpParent();
+ dumpShell();
+ dumpContent();
+ }
+
+ boolean isMaximized() {
+ return false;
+ }
+
+ boolean isOverrideRedirect() {
+ return false;
+ }
+
+ public boolean requestWindowFocus(long time, boolean timeProvided) {
+ focusLog.fine("Request for decorated window focus");
+ // If this is Frame or Dialog we can't assure focus request success - but we still can try
+ // If this is Window and its owner Frame is active we can be sure request succedded.
+ Window win = (Window)target;
+ Window focusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow();
+ Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
+
+ focusLog.log(Level.FINER, "Current window is: active={0}, focused={1}",
+ new Object[]{ Boolean.valueOf(win == activeWindow),
+ Boolean.valueOf(win == focusedWindow)});
+
+ XWindowPeer toFocus = this;
+ while (toFocus.nextTransientFor != null) {
+ toFocus = toFocus.nextTransientFor;
+ }
+
+ if (this == toFocus) {
+ if (focusAllowedFor()) {
+ if (win == activeWindow && win != focusedWindow) {
+ // Happens when focus is on window child
+ focusLog.fine("Focus is on child window - transfering it back");
+ handleWindowFocusInSync(-1);
+ } else {
+ focusLog.fine("Requesting focus to this window");
+ if (timeProvided) {
+ requestXFocus(time);
+ } else {
+ requestXFocus();
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+ else if (toFocus.focusAllowedFor()) {
+ focusLog.fine("Requesting focus to " + toFocus);
+ if (timeProvided) {
+ toFocus.requestXFocus(time);
+ } else {
+ toFocus.requestXFocus();
+ }
+ return false;
+ }
+ else
+ {
+ // This might change when WM will have property to determine focus policy.
+ // Right now, because policy is unknown we can't be sure we succedded
+ return false;
+ }
+ }
+
+ XWindowPeer actualFocusedWindow = null;
+ void setActualFocusedWindow(XWindowPeer actualFocusedWindow) {
+ synchronized(getStateLock()) {
+ this.actualFocusedWindow = actualFocusedWindow;
+ }
+ }
+
+ boolean requestWindowFocus(XWindowPeer actualFocusedWindow,
+ long time, boolean timeProvided)
+ {
+ setActualFocusedWindow(actualFocusedWindow);
+ return requestWindowFocus(time, timeProvided);
+ }
+ public void handleWindowFocusIn(long serial) {
+ if (null == actualFocusedWindow) {
+ super.handleWindowFocusIn(serial);
+ } else {
+ /*
+ * Fix for 6314575.
+ * If this is a result of clicking on one of the Frame's component
+ * then 'actualFocusedWindow' shouldn't be focused. A decision of focusing
+ * it or not should be made after the appropriate Java mouse event (if any)
+ * is handled by the component where 'actualFocusedWindow' value may be reset.
+ *
+ * The fix is based on the empiric fact consisting in that the component
+ * receives native mouse event nearly at the same time the Frame receives
+ * WM_TAKE_FOCUS (when FocusIn is generated via XSetInputFocus call) but
+ * definetely before the Frame gets FocusIn event (when this method is called).
+ */
+ postEvent(new InvocationEvent(target, new Runnable() {
+ public void run() {
+ XWindowPeer fw = null;
+ synchronized (getStateLock()) {
+ fw = actualFocusedWindow;
+ actualFocusedWindow = null;
+ if (null == fw || !fw.isVisible() || !fw.isFocusableWindow()) {
+ fw = XDecoratedPeer.this;
+ }
+ }
+ fw.handleWindowFocusIn_Dispatch();
+ }
+ }));
+ }
+ }
+
+ public void handleWindowFocusOut(Window oppositeWindow, long serial) {
+ Window actualFocusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow();
+
+ // If the actual focused window is not this decorated window then retain it.
+ if (actualFocusedWindow != null && actualFocusedWindow != target) {
+ Window owner = XWindowPeer.getDecoratedOwner(actualFocusedWindow);
+
+ if (owner != null && owner == target) {
+ setActualFocusedWindow((XWindowPeer) ComponentAccessor.getPeer(actualFocusedWindow));
+ }
+ }
+ super.handleWindowFocusOut(oppositeWindow, serial);
+ }
+
+ private Point queryXLocation()
+ {
+ return XlibUtil.translateCoordinates(
+ getContentWindow(),
+ XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()),
+ new Point(0, 0));
+ }
+}