0001: /*
0002: * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025: package sun.awt.X11;
0026:
0027: import java.awt.*;
0028:
0029: import java.awt.event.ComponentEvent;
0030: import java.awt.event.InvocationEvent;
0031: import java.awt.event.WindowEvent;
0032:
0033: import java.util.logging.Level;
0034: import java.util.logging.Logger;
0035:
0036: import sun.awt.ComponentAccessor;
0037: import sun.awt.SunToolkit;
0038:
0039: class XDecoratedPeer extends XWindowPeer {
0040: private static final Logger log = Logger
0041: .getLogger("sun.awt.X11.XDecoratedPeer");
0042: private static final Logger insLog = Logger
0043: .getLogger("sun.awt.X11.insets.XDecoratedPeer");
0044: private static final Logger focusLog = Logger
0045: .getLogger("sun.awt.X11.focus.XDecoratedPeer");
0046: private final static Logger iconLog = Logger
0047: .getLogger("sun.awt.X11.icon.XDecoratedPeer");
0048:
0049: private static XAtom resize_request = new XAtom(
0050: "_SUN_AWT_RESIZE_REQUEST", false);
0051:
0052: // Set to true when we get the first ConfigureNotify after being
0053: // reparented - indicates that WM has adopted the top-level.
0054: boolean configure_seen;
0055: boolean insets_corrected;
0056:
0057: XIconWindow iconWindow;
0058: WindowDimensions dimensions;
0059: XContentWindow content;
0060: Insets currentInsets;
0061: XFocusProxyWindow focusProxy;
0062:
0063: XDecoratedPeer(Window target) {
0064: super (target);
0065: }
0066:
0067: XDecoratedPeer(XCreateWindowParams params) {
0068: super (params);
0069: }
0070:
0071: public long getShell() {
0072: return window;
0073: }
0074:
0075: public long getContentWindow() {
0076: return (content == null) ? window : content.getWindow();
0077: }
0078:
0079: void preInit(XCreateWindowParams params) {
0080: super .preInit(params);
0081: if (!resize_request.isInterned()) {
0082: resize_request.intern(false);
0083: }
0084: winAttr.initialFocus = true;
0085:
0086: currentInsets = new Insets(0, 0, 0, 0); // replacemenet for wdata->top, left, bottom, right
0087:
0088: applyGuessedInsets();
0089: Rectangle bounds = (Rectangle) params.get(BOUNDS);
0090: dimensions = new WindowDimensions(bounds, getRealInsets(),
0091: false);
0092: params.put(BOUNDS, dimensions.getClientRect());
0093: insLog.log(Level.FINE, "Initial dimensions {0}",
0094: new Object[] { dimensions });
0095:
0096: // Deny default processing of these events on the shell - proxy will take care of
0097: // them instead
0098: Long eventMask = (Long) params.get(EVENT_MASK);
0099: params.add(EVENT_MASK, Long.valueOf(eventMask.longValue()
0100: & ~(FocusChangeMask | KeyPressMask | KeyReleaseMask)));
0101: }
0102:
0103: void postInit(XCreateWindowParams params) {
0104: super .postInit(params);
0105: // The lines that follow need to be in a postInit, so they
0106: // happen after the X window is created.
0107: initResizability();
0108: updateSizeHints(dimensions);
0109: content = createContent(dimensions);
0110: content.initialize();
0111: if (warningWindow != null) {
0112: warningWindow.toFront();
0113: }
0114: focusProxy = createFocusProxy();
0115: }
0116:
0117: void setIconHints(java.util.List<XIconInfo> icons) {
0118: if (!XWM.getWM().setNetWMIcon(this , icons)) {
0119: if (icons.size() > 0) {
0120: if (iconWindow == null) {
0121: iconWindow = new XIconWindow(this );
0122: }
0123: iconWindow.setIconImages(icons);
0124: }
0125: }
0126: }
0127:
0128: public void updateMinimumSize() {
0129: super .updateMinimumSize();
0130: updateMinSizeHints();
0131: }
0132:
0133: private void updateMinSizeHints() {
0134: if (isResizable()) {
0135: Dimension minimumSize = getTargetMinimumSize();
0136: if (minimumSize != null) {
0137: Insets insets = getRealInsets();
0138: int minWidth = minimumSize.width - insets.left
0139: - insets.right;
0140: int minHeight = minimumSize.height - insets.top
0141: - insets.bottom;
0142: if (minWidth < 0)
0143: minWidth = 0;
0144: if (minHeight < 0)
0145: minHeight = 0;
0146: setSizeHints(
0147: XlibWrapper.PMinSize
0148: | (isLocationByPlatform() ? 0
0149: : (XlibWrapper.PPosition | XlibWrapper.USPosition)),
0150: getX(), getY(), minWidth, minHeight);
0151: if (isVisible()) {
0152: Rectangle bounds = getShellBounds();
0153: int nw = (bounds.width < minWidth) ? minWidth
0154: : bounds.width;
0155: int nh = (bounds.height < minHeight) ? minHeight
0156: : bounds.height;
0157: if (nw != bounds.width || nh != bounds.height) {
0158: setShellSize(new Rectangle(0, 0, nw, nh));
0159: }
0160: }
0161: } else {
0162: boolean isMinSizeSet = isMinSizeSet();
0163: XWM.removeSizeHints(this , XlibWrapper.PMinSize);
0164: /* Some WMs need remap to redecorate the window */
0165: if (isMinSizeSet && isShowing() && XWM.needRemap(this )) {
0166: /*
0167: * Do the re/mapping at the Xlib level. Since we essentially
0168: * work around a WM bug we don't want this hack to be exposed
0169: * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
0170: */
0171: xSetVisible(false);
0172: XToolkit.XSync();
0173: xSetVisible(true);
0174: }
0175: }
0176: }
0177: }
0178:
0179: XContentWindow createContent(WindowDimensions dims) {
0180: Rectangle rec = dims.getBounds();
0181: // Fix for - set the location of the content window to the (-left inset, -top inset)
0182: Insets ins = dims.getInsets();
0183: if (ins != null) {
0184: rec.x = -ins.left;
0185: rec.y = -ins.top;
0186: } else {
0187: rec.x = 0;
0188: rec.y = 0;
0189: }
0190: return new XContentWindow(this , rec);
0191: }
0192:
0193: XFocusProxyWindow createFocusProxy() {
0194: return new XFocusProxyWindow(this );
0195: }
0196:
0197: protected XAtomList getWMProtocols() {
0198: XAtomList protocols = super .getWMProtocols();
0199: protocols.add(wm_delete_window);
0200: protocols.add(wm_take_focus);
0201: return protocols;
0202: }
0203:
0204: public Graphics getGraphics() {
0205: return getGraphics(content.surfaceData, ComponentAccessor
0206: .getForeground(target), ComponentAccessor
0207: .getBackground(target), ComponentAccessor
0208: .getFont_NoClientCode(target));
0209: }
0210:
0211: public void setTitle(String title) {
0212: if (log.isLoggable(Level.FINE))
0213: log.fine("Title is " + title);
0214: winAttr.title = title;
0215: updateWMName();
0216: }
0217:
0218: protected String getWMName() {
0219: if (winAttr.title == null || winAttr.title.trim().equals("")) {
0220: return " ";
0221: } else {
0222: return winAttr.title;
0223: }
0224: }
0225:
0226: void updateWMName() {
0227: super .updateWMName();
0228: String name = getWMName();
0229: XToolkit.awtLock();
0230: try {
0231: if (name == null || name.trim().equals("")) {
0232: name = "Java";
0233: }
0234: XAtom iconNameAtom = XAtom.get(XAtom.XA_WM_ICON_NAME);
0235: iconNameAtom.setProperty(getWindow(), name);
0236: XAtom netIconNameAtom = XAtom.get("_NET_WM_ICON_NAME");
0237: netIconNameAtom.setPropertyUTF8(getWindow(), name);
0238: } finally {
0239: XToolkit.awtUnlock();
0240: }
0241: }
0242:
0243: // NOTE: This method may be called by privileged threads.
0244: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
0245: public void handleIconify() {
0246: postEvent(new WindowEvent((Window) target,
0247: WindowEvent.WINDOW_ICONIFIED));
0248: }
0249:
0250: // NOTE: This method may be called by privileged threads.
0251: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
0252: public void handleDeiconify() {
0253: postEvent(new WindowEvent((Window) target,
0254: WindowEvent.WINDOW_DEICONIFIED));
0255: }
0256:
0257: public void handleFocusEvent(XEvent xev) {
0258: super .handleFocusEvent(xev);
0259: XFocusChangeEvent xfe = xev.get_xfocus();
0260:
0261: // If we somehow received focus events forward it instead to proxy
0262: // FIXME: Shouldn't we instead check for inferrior?
0263: focusLog.finer("Received focus event on shell: " + xfe);
0264: // focusProxy.xRequestFocus();
0265: }
0266:
0267: /***************************************************************************************
0268: * I N S E T S C O D E
0269: **************************************************************************************/
0270:
0271: protected boolean isInitialReshape() {
0272: return false;
0273: }
0274:
0275: Insets difference(Insets i1, Insets i2) {
0276: return new Insets(i1.top - i2.top, i1.left - i2.left, i1.bottom
0277: - i2.bottom, i1.right - i2.right);
0278: }
0279:
0280: void add(Insets i1, Insets i2) {
0281: i1.left += i2.left;
0282: i1.top += i2.top;
0283: i1.right += i2.right;
0284: i1.bottom += i2.bottom;
0285: }
0286:
0287: boolean isNull(Insets i) {
0288: return (i == null)
0289: || ((i.left | i.top | i.right | i.bottom) == 0);
0290: }
0291:
0292: Insets copy(Insets i) {
0293: return new Insets(i.top, i.left, i.bottom, i.right);
0294: }
0295:
0296: long reparent_serial = 0;
0297:
0298: public void handleReparentNotifyEvent(XEvent xev) {
0299: XReparentEvent xe = xev.get_xreparent();
0300: if (insLog.isLoggable(Level.FINE))
0301: insLog.fine(xe.toString());
0302: reparent_serial = xe.get_serial();
0303: XToolkit.awtLock();
0304: try {
0305: long root = XlibWrapper.RootWindow(XToolkit.getDisplay(),
0306: getScreenNumber());
0307:
0308: if (isEmbedded()) {
0309: setReparented(true);
0310: insets_corrected = true;
0311: return;
0312: }
0313: Component t = (Component) target;
0314: if (getDecorations() == winAttr.AWT_DECOR_NONE) {
0315: setReparented(true);
0316: insets_corrected = true;
0317: reshape(dimensions, SET_SIZE, false);
0318: } else if (xe.get_parent() == root) {
0319: configure_seen = false;
0320: insets_corrected = false;
0321:
0322: /*
0323: * We can be repareted to root for two reasons:
0324: * . setVisible(false)
0325: * . WM exited
0326: */
0327: if (isVisible()) { /* WM exited */
0328: /* Work around 4775545 */
0329: XWM.getWM().unshadeKludge(this );
0330: insLog.fine("- WM exited");
0331: } else {
0332: insLog.fine(" - reparent due to hide");
0333: }
0334: } else { /* reparented to WM frame, figure out our insets */
0335: setReparented(true);
0336: insets_corrected = false;
0337:
0338: // Check if we have insets provided by the WM
0339: Insets correctWM = getWMSetInsets(null);
0340: if (correctWM != null) {
0341: insLog.log(Level.FINER, "wm-provided insets {0}",
0342: new Object[] { correctWM });
0343: // If these insets are equal to our current insets - no actions are necessary
0344: Insets dimInsets = dimensions.getInsets();
0345: if (correctWM.equals(dimInsets)) {
0346: insLog
0347: .finer("Insets are the same as estimated - no additional reshapes necessary");
0348: no_reparent_artifacts = true;
0349: insets_corrected = true;
0350: applyGuessedInsets();
0351: return;
0352: }
0353: } else {
0354: correctWM = XWM.getWM().getInsets(this ,
0355: xe.get_window(), xe.get_parent());
0356:
0357: if (correctWM != null) {
0358: insLog.log(Level.FINER, "correctWM {0}",
0359: new Object[] { correctWM });
0360: } else {
0361: insLog
0362: .log(Level.FINER,
0363: "correctWM insets are not available, waiting for configureNotify");
0364: }
0365: }
0366:
0367: if (correctWM != null) {
0368: handleCorrectInsets(correctWM);
0369: }
0370: }
0371: } finally {
0372: XToolkit.awtUnlock();
0373: }
0374: }
0375:
0376: protected void handleCorrectInsets(Insets correctWM) {
0377: XToolkit.awtLock();
0378: try {
0379: /*
0380: * Ok, now see if we need adjust window size because
0381: * initial insets were wrong (most likely they were).
0382: */
0383: Insets correction = difference(correctWM, currentInsets);
0384: insLog.log(Level.FINEST, "Corrention {0}",
0385: new Object[] { correction });
0386: if (!isNull(correction)) {
0387: /*
0388: * Actual insets account for menubar/warning label,
0389: * so we can't assign directly but must adjust them.
0390: */
0391: add(currentInsets, correction);
0392: applyGuessedInsets();
0393:
0394: //Fix for 6318109: PIT: Min Size is not honored properly when a
0395: //smaller size is specified in setSize(), XToolkit
0396: //update minimum size hints
0397: updateMinSizeHints();
0398:
0399: /*
0400: * If this window has been sized by a pack() we need
0401: * to keep the interior geometry intact. Since pack()
0402: * computed width and height with wrong insets, we
0403: * must adjust the target dimensions appropriately.
0404: */
0405: }
0406: if (insLog.isLoggable(Level.FINER))
0407: insLog.finer("Dimensions before reparent: "
0408: + dimensions);
0409:
0410: dimensions.setInsets(getRealInsets());
0411: insets_corrected = true;
0412:
0413: if (isMaximized()) {
0414: return;
0415: }
0416:
0417: if ((getHints().get_flags() & (USPosition | PPosition)) != 0) {
0418: reshape(dimensions, SET_BOUNDS, false);
0419: } else {
0420: reshape(dimensions, SET_SIZE, false);
0421: }
0422: } finally {
0423: XToolkit.awtUnlock();
0424: }
0425: }
0426:
0427: public void handleMoved(WindowDimensions dims) {
0428: Point loc = dims.getLocation();
0429: ComponentAccessor.setX((Component) target, loc.x);
0430: ComponentAccessor.setY((Component) target, loc.y);
0431: postEvent(new ComponentEvent(target,
0432: ComponentEvent.COMPONENT_MOVED));
0433: }
0434:
0435: protected Insets guessInsets() {
0436: if (isEmbedded()) {
0437: return new Insets(0, 0, 0, 0);
0438: } else {
0439: if (currentInsets.top > 0) {
0440: /* insets were set on wdata by System Properties */
0441: return copy(currentInsets);
0442: } else {
0443: Insets res = getWMSetInsets(null);
0444: if (res == null) {
0445: res = XWM.getWM().guessInsets(this );
0446: }
0447: return res;
0448: }
0449: }
0450: }
0451:
0452: private void applyGuessedInsets() {
0453: Insets guessed = guessInsets();
0454: currentInsets = copy(guessed);
0455: insets = copy(currentInsets);
0456: }
0457:
0458: public void revalidate() {
0459: XToolkit.executeOnEventHandlerThread(target, new Runnable() {
0460: public void run() {
0461: target.invalidate();
0462: target.validate();
0463: }
0464: });
0465: }
0466:
0467: Insets getRealInsets() {
0468: if (isNull(insets)) {
0469: applyGuessedInsets();
0470: }
0471: return insets;
0472: }
0473:
0474: public Insets getInsets() {
0475: Insets in = copy(getRealInsets());
0476: in.top += getMenuBarHeight() + getWarningWindowHeight();
0477: if (insLog.isLoggable(Level.FINEST))
0478: insLog.log(Level.FINEST, "Get insets returns {0}",
0479: new Object[] { in });
0480: return in;
0481: }
0482:
0483: boolean gravityBug() {
0484: return XWM.configureGravityBuggy();
0485: }
0486:
0487: // The height of area used to display current active input method
0488: int getInputMethodHeight() {
0489: return 0;
0490: }
0491:
0492: void updateSizeHints(WindowDimensions dims) {
0493: Rectangle rec = dims.getClientRect();
0494: checkShellRect(rec);
0495: updateSizeHints(rec.x, rec.y, rec.width, rec.height);
0496: }
0497:
0498: void updateSizeHints() {
0499: updateSizeHints(dimensions);
0500: }
0501:
0502: // Coordinates are that of the target
0503: // Called only on Toolkit thread
0504: public void reshape(WindowDimensions newDimensions, int op,
0505: boolean userReshape) {
0506: if (insLog.isLoggable(Level.FINE)) {
0507: insLog.fine("Reshaping " + this + " to " + newDimensions
0508: + " op " + op + " user reshape " + userReshape);
0509: }
0510: XToolkit.awtLock();
0511: try {
0512: if (!isReparented() || !isVisible()) {
0513: insLog
0514: .log(
0515: Level.FINE,
0516: "- not reparented({0}) or not visible({1}), default reshape",
0517: new Object[] {
0518: Boolean.valueOf(isReparented()),
0519: Boolean.valueOf(visible) });
0520:
0521: // Fix for 6323293.
0522: // This actually is needed to preserve compatibility with previous releases -
0523: // some of licensees are expecting componentMoved event on invisible one while
0524: // its location changes.
0525: Point oldLocation = getLocation();
0526:
0527: Point newLocation = new Point(ComponentAccessor
0528: .getX((Component) target), ComponentAccessor
0529: .getY((Component) target));
0530:
0531: if (!newLocation.equals(oldLocation)) {
0532: handleMoved(newDimensions);
0533: }
0534:
0535: dimensions = new WindowDimensions(newDimensions);
0536: updateSizeHints(dimensions);
0537: Rectangle client = dimensions.getClientRect();
0538: checkShellRect(client);
0539: setShellBounds(client);
0540: if (content != null
0541: && !content.getSize().equals(
0542: newDimensions.getSize())) {
0543: reconfigureContentWindow(newDimensions);
0544: }
0545: return;
0546: }
0547:
0548: int wm = XWM.getWMID();
0549: updateChildrenSizes();
0550: applyGuessedInsets();
0551:
0552: Rectangle shellRect = newDimensions.getClientRect();
0553:
0554: if (gravityBug()) {
0555: Insets in = newDimensions.getInsets();
0556: shellRect.translate(in.left, in.top);
0557: }
0558:
0559: if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) {
0560: shellRect.setLocation(0, 0);
0561: }
0562:
0563: checkShellRectSize(shellRect);
0564: if (!isEmbedded()) {
0565: checkShellRectPos(shellRect);
0566: }
0567:
0568: op = op & ~NO_EMBEDDED_CHECK;
0569:
0570: if (op == SET_LOCATION) {
0571: setShellPosition(shellRect);
0572: } else if (isResizable()) {
0573: if (op == SET_BOUNDS) {
0574: setShellBounds(shellRect);
0575: } else {
0576: setShellSize(shellRect);
0577: }
0578: } else {
0579: XWM.setShellNotResizable(this , newDimensions,
0580: shellRect, true);
0581: if (op == SET_BOUNDS) {
0582: setShellPosition(shellRect);
0583: }
0584: }
0585:
0586: reconfigureContentWindow(newDimensions);
0587: } finally {
0588: XToolkit.awtUnlock();
0589: }
0590: }
0591:
0592: /**
0593: * @param x, y, width, heith - dimensions of the window with insets
0594: */
0595: private void reshape(int x, int y, int width, int height,
0596: int operation, boolean userReshape) {
0597: Rectangle newRec;
0598: boolean setClient = false;
0599: WindowDimensions dims = new WindowDimensions(dimensions);
0600: switch (operation & (~NO_EMBEDDED_CHECK)) {
0601: case SET_LOCATION:
0602: // Set location always sets bounds location. However, until the window is mapped we
0603: // should use client coordinates
0604: dims.setLocation(x, y);
0605: break;
0606: case SET_SIZE:
0607: // Set size sets bounds size. However, until the window is mapped we
0608: // should use client coordinates
0609: dims.setSize(width, height);
0610: break;
0611: case SET_CLIENT_SIZE: {
0612: // Sets client rect size. Width and height contain insets.
0613: Insets in = currentInsets;
0614: width -= in.left + in.right;
0615: height -= in.top + in.bottom;
0616: dims.setClientSize(width, height);
0617: break;
0618: }
0619: case SET_BOUNDS:
0620: default:
0621: dims.setLocation(x, y);
0622: dims.setSize(width, height);
0623: break;
0624: }
0625: if (insLog.isLoggable(Level.FINE))
0626: insLog
0627: .log(
0628: Level.FINE,
0629: "For the operation {0} new dimensions are {1}",
0630: new Object[] {
0631: operationToString(operation), dims });
0632:
0633: reshape(dims, operation, userReshape);
0634: }
0635:
0636: /**
0637: * @see java.awt.peer.ComponentPeer#setBounds
0638: */
0639: public void setBounds(int x, int y, int width, int height, int op) {
0640: // TODO: Rewrite with WindowDimensions
0641: reshape(x, y, width, height, op, true);
0642: validateSurface();
0643: }
0644:
0645: // Coordinates are that of the shell
0646: void reconfigureContentWindow(WindowDimensions dims) {
0647: if (content == null) {
0648: insLog.fine("WARNING: Content window is null");
0649: return;
0650: }
0651: content.setContentBounds(dims);
0652: }
0653:
0654: boolean no_reparent_artifacts = false;
0655:
0656: public void handleConfigureNotifyEvent(XEvent xev) {
0657: assert (SunToolkit.isAWTLockHeldByCurrentThread());
0658: XConfigureEvent xe = xev.get_xconfigure();
0659: insLog.log(Level.FINE, "Configure notify {0}",
0660: new Object[] { xe });
0661:
0662: // XXX: should really only consider synthetic events, but
0663: if (isReparented()) {
0664: configure_seen = true;
0665: }
0666:
0667: if (!isMaximized()
0668: && (xe.get_serial() == reparent_serial || xe
0669: .get_window() != getShell())
0670: && !no_reparent_artifacts) {
0671: insLog.fine("- reparent artifact, skipping");
0672: return;
0673: }
0674: no_reparent_artifacts = false;
0675:
0676: /**
0677: * When there is a WM we receive some CN before being visible and after.
0678: * We should skip all CN which are before being visible, because we assume
0679: * the gravity is in action while it is not yet.
0680: *
0681: * When there is no WM we receive CN only _before_ being visible.
0682: * We should process these CNs.
0683: */
0684: if (!isVisible() && XWM.getWMID() != XWM.NO_WM) {
0685: insLog.fine(" - not visible, skipping");
0686: return;
0687: }
0688:
0689: /*
0690: * Some window managers configure before we are reparented and
0691: * the send event flag is set! ugh... (Enlighetenment for one,
0692: * possibly MWM as well). If we haven't been reparented yet
0693: * this is just the WM shuffling us into position. Ignore
0694: * it!!!! or we wind up in a bogus location.
0695: */
0696: int runningWM = XWM.getWMID();
0697: if (insLog.isLoggable(Level.FINE)) {
0698: insLog
0699: .log(
0700: Level.FINE,
0701: "reparented={0}, visible={1}, WM={2}, decorations={3}",
0702: new Object[] { isReparented(), isVisible(),
0703: runningWM, getDecorations() });
0704: }
0705: if (!isReparented() && isVisible() && runningWM != XWM.NO_WM
0706: && !XWM.isNonReparentingWM()
0707: && getDecorations() != winAttr.AWT_DECOR_NONE) {
0708: insLog.fine("- visible but not reparented, skipping");
0709: return;
0710: }
0711: //Last chance to correct insets
0712: if (!insets_corrected
0713: && getDecorations() != winAttr.AWT_DECOR_NONE) {
0714: long parent = XlibUtil.getParentWindow(window);
0715: Insets correctWM = (parent != -1) ? XWM.getWM().getInsets(
0716: this , window, parent) : null;
0717: if (insLog.isLoggable(Level.FINER)) {
0718: if (correctWM != null) {
0719: insLog.finer("Configure notify - insets : "
0720: + correctWM);
0721: } else {
0722: insLog
0723: .finer("Configure notify - insets are still not available");
0724: }
0725: }
0726: if (correctWM != null) {
0727: handleCorrectInsets(correctWM);
0728: } else {
0729: //Only one attempt to correct insets is made (to lower risk)
0730: //if insets are still not available we simply set the flag
0731: insets_corrected = true;
0732: }
0733: }
0734:
0735: updateChildrenSizes();
0736:
0737: // Bounds of the window
0738: Rectangle targetBounds = new Rectangle(ComponentAccessor
0739: .getX((Component) target), ComponentAccessor
0740: .getY((Component) target), ComponentAccessor
0741: .getWidth((Component) target), ComponentAccessor
0742: .getHeight((Component) target));
0743:
0744: Point newLocation = targetBounds.getLocation();
0745: if (xe.get_send_event() || runningWM == XWM.NO_WM
0746: || XWM.isNonReparentingWM()) {
0747: // Location, Client size + insets
0748: newLocation = new Point(xe.get_x() - currentInsets.left, xe
0749: .get_y()
0750: - currentInsets.top);
0751: } else {
0752: // CDE/MWM/Metacity/Sawfish bug: if shell is resized using
0753: // top or left border, we don't receive synthetic
0754: // ConfigureNotify, only the one from X with zero
0755: // coordinates. This is the workaround to get real
0756: // location, 6261336
0757: switch (XWM.getWMID()) {
0758: case XWM.CDE_WM:
0759: case XWM.MOTIF_WM:
0760: case XWM.METACITY_WM:
0761: case XWM.SAWFISH_WM: {
0762: Point xlocation = queryXLocation();
0763: if (log.isLoggable(Level.FINE))
0764: log.log(Level.FINE, "New X location: {0}",
0765: new Object[] { xlocation });
0766: if (xlocation != null) {
0767: newLocation = xlocation;
0768: }
0769: break;
0770: }
0771: default:
0772: break;
0773: }
0774: }
0775:
0776: WindowDimensions newDimensions = new WindowDimensions(
0777: newLocation, new Dimension(xe.get_width(), xe
0778: .get_height()), copy(currentInsets), true);
0779:
0780: insLog.log(Level.FINER, "Insets are {0}, new dimensions {1}",
0781: new Object[] { currentInsets, newDimensions });
0782:
0783: checkIfOnNewScreen(newDimensions.getBounds());
0784:
0785: Point oldLocation = getLocation();
0786: dimensions = newDimensions;
0787: if (!newLocation.equals(oldLocation)) {
0788: handleMoved(newDimensions);
0789: }
0790: reconfigureContentWindow(newDimensions);
0791: updateChildrenSizes();
0792: }
0793:
0794: private void checkShellRectSize(Rectangle shellRect) {
0795: if (shellRect.width < 0) {
0796: shellRect.width = 1;
0797: }
0798: if (shellRect.height < 0) {
0799: shellRect.height = 1;
0800: }
0801: }
0802:
0803: private void checkShellRectPos(Rectangle shellRect) {
0804: int wm = XWM.getWMID();
0805: if (wm == XWM.MOTIF_WM || wm == XWM.CDE_WM) {
0806: if (shellRect.x == 0 && shellRect.y == 0) {
0807: shellRect.x = shellRect.y = 1;
0808: }
0809: }
0810: }
0811:
0812: private void checkShellRect(Rectangle shellRect) {
0813: checkShellRectSize(shellRect);
0814: checkShellRectPos(shellRect);
0815: }
0816:
0817: public void setShellBounds(Rectangle rec) {
0818: if (insLog.isLoggable(Level.FINE))
0819: insLog.fine("Setting shell bounds on " + this + " to "
0820: + rec);
0821: XToolkit.awtLock();
0822: try {
0823: updateSizeHints(rec.x, rec.y, rec.width, rec.height);
0824: XlibWrapper.XResizeWindow(XToolkit.getDisplay(),
0825: getShell(), rec.width, rec.height);
0826: XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(),
0827: rec.x, rec.y);
0828: } finally {
0829: XToolkit.awtUnlock();
0830: }
0831: }
0832:
0833: public void setShellSize(Rectangle rec) {
0834: if (insLog.isLoggable(Level.FINE))
0835: insLog.fine("Setting shell size on " + this + " to " + rec);
0836: XToolkit.awtLock();
0837: try {
0838: updateSizeHints(rec.x, rec.y, rec.width, rec.height);
0839: XlibWrapper.XResizeWindow(XToolkit.getDisplay(),
0840: getShell(), rec.width, rec.height);
0841: } finally {
0842: XToolkit.awtUnlock();
0843: }
0844: }
0845:
0846: public void setShellPosition(Rectangle rec) {
0847: if (insLog.isLoggable(Level.FINE))
0848: insLog.fine("Setting shell position on " + this + " to "
0849: + rec);
0850: XToolkit.awtLock();
0851: try {
0852: updateSizeHints(rec.x, rec.y, rec.width, rec.height);
0853: XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(),
0854: rec.x, rec.y);
0855: } finally {
0856: XToolkit.awtUnlock();
0857: }
0858: }
0859:
0860: void initResizability() {
0861: setResizable(winAttr.initialResizability);
0862: }
0863:
0864: public void setResizable(boolean resizable) {
0865: int fs = winAttr.functions;
0866: if (!isResizable() && resizable) {
0867: insets = currentInsets = new Insets(0, 0, 0, 0);
0868: resetWMSetInsets();
0869: if (!isEmbedded()) {
0870: setReparented(false);
0871: }
0872: winAttr.isResizable = resizable;
0873: if ((fs & MWM_FUNC_ALL) != 0) {
0874: fs &= ~(MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
0875: } else {
0876: fs |= (MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
0877: }
0878: winAttr.functions = fs;
0879: XWM.setShellResizable(this );
0880: } else if (isResizable() && !resizable) {
0881: insets = currentInsets = new Insets(0, 0, 0, 0);
0882: resetWMSetInsets();
0883: if (!isEmbedded()) {
0884: setReparented(false);
0885: }
0886: winAttr.isResizable = resizable;
0887: if ((fs & MWM_FUNC_ALL) != 0) {
0888: fs |= (MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
0889: } else {
0890: fs &= ~(MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
0891: }
0892: winAttr.functions = fs;
0893: XWM.setShellNotResizable(this , dimensions, dimensions
0894: .getScreenBounds(), false);
0895: }
0896: }
0897:
0898: Rectangle getShellBounds() {
0899: return dimensions.getClientRect();
0900: }
0901:
0902: public Rectangle getBounds() {
0903: return dimensions.getBounds();
0904: }
0905:
0906: public Dimension getSize() {
0907: return dimensions.getSize();
0908: }
0909:
0910: public int getX() {
0911: return dimensions.getLocation().x;
0912: }
0913:
0914: public int getY() {
0915: return dimensions.getLocation().y;
0916: }
0917:
0918: public Point getLocation() {
0919: return dimensions.getLocation();
0920: }
0921:
0922: public int getAbsoluteX() {
0923: // NOTE: returning this peer's location which is shell location
0924: return dimensions.getScreenBounds().x;
0925: }
0926:
0927: public int getAbsoluteY() {
0928: // NOTE: returning this peer's location which is shell location
0929: return dimensions.getScreenBounds().y;
0930: }
0931:
0932: public int getWidth() {
0933: return getSize().width;
0934: }
0935:
0936: public int getHeight() {
0937: return getSize().height;
0938: }
0939:
0940: public WindowDimensions getDimensions() {
0941: return dimensions;
0942: }
0943:
0944: public Point getLocationOnScreen() {
0945: XToolkit.awtLock();
0946: try {
0947: if (configure_seen) {
0948: return toGlobal(0, 0);
0949: } else {
0950: Point location = target.getLocation();
0951: if (insLog.isLoggable(Level.FINE))
0952: insLog
0953: .log(
0954: Level.FINE,
0955: "getLocationOnScreen {0} not reparented: {1} ",
0956: new Object[] { this , location });
0957: return location;
0958: }
0959: } finally {
0960: XToolkit.awtUnlock();
0961: }
0962: }
0963:
0964: /***************************************************************************************
0965: * END OF I N S E T S C O D E
0966: **************************************************************************************/
0967:
0968: protected boolean isEventDisabled(XEvent e) {
0969: switch (e.get_type()) {
0970: // Do not generate MOVED/RESIZED events since we generate them by ourselves
0971: case ConfigureNotify:
0972: return true;
0973: case EnterNotify:
0974: case LeaveNotify:
0975: // Disable crossing event on outer borders of Frame so
0976: // we receive only one set of cross notifications(first set is from content window)
0977: return true;
0978: default:
0979: return super .isEventDisabled(e);
0980: }
0981: }
0982:
0983: int getDecorations() {
0984: return winAttr.decorations;
0985: }
0986:
0987: int getFunctions() {
0988: return winAttr.functions;
0989: }
0990:
0991: public void setVisible(boolean vis) {
0992: log.log(Level.FINER, "Setting {0} to visible {1}",
0993: new Object[] { this , Boolean.valueOf(vis) });
0994: if (vis && !isVisible()) {
0995: XWM.setShellDecor(this );
0996: super .setVisible(vis);
0997: if (winAttr.isResizable) {
0998: //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
0999: //We need to update frame's minimum size, not to reset it
1000: XWM.removeSizeHints(this , XlibWrapper.PMaxSize);
1001: updateMinimumSize();
1002: }
1003: } else {
1004: super .setVisible(vis);
1005: }
1006: }
1007:
1008: protected void suppressWmTakeFocus(boolean doSuppress) {
1009: XAtomList protocols = getWMProtocols();
1010: if (doSuppress) {
1011: protocols.remove(wm_take_focus);
1012: } else {
1013: protocols.add(wm_take_focus);
1014: }
1015: wm_protocols.setAtomListProperty(this , protocols);
1016: }
1017:
1018: public void dispose() {
1019: if (content != null) {
1020: content.destroy();
1021: }
1022: focusProxy.destroy();
1023:
1024: if (iconWindow != null) {
1025: iconWindow.destroy();
1026: }
1027:
1028: super .dispose();
1029: }
1030:
1031: public void handleClientMessage(XEvent xev) {
1032: super .handleClientMessage(xev);
1033: XClientMessageEvent cl = xev.get_xclient();
1034: if ((wm_protocols != null)
1035: && (cl.get_message_type() == wm_protocols.getAtom())) {
1036: if (cl.get_data(0) == wm_delete_window.getAtom()) {
1037: handleQuit();
1038: } else if (cl.get_data(0) == wm_take_focus.getAtom()) {
1039: handleWmTakeFocus(cl);
1040: }
1041: } else if (cl.get_message_type() == resize_request.getAtom()) {
1042: reshape((int) cl.get_data(0), (int) cl.get_data(1),
1043: (int) cl.get_data(2), (int) cl.get_data(3),
1044: (int) cl.get_data(4), true);
1045: }
1046: }
1047:
1048: private void handleWmTakeFocus(XClientMessageEvent cl) {
1049: focusLog.log(Level.FINE, "WM_TAKE_FOCUS on {0}",
1050: new Object[] { this });
1051: requestWindowFocus(cl.get_data(1), true);
1052: }
1053:
1054: /**
1055: * Requests focus to this decorated top-level by requesting X input focus
1056: * to the shell window.
1057: */
1058: protected void requestXFocus(long time, boolean timeProvided) {
1059: // We have proxied focus mechanism - instead of shell the focus is held
1060: // by "proxy" - invisible mapped window. When we want to set X input focus to
1061: // toplevel set it on proxy instead.
1062: if (focusProxy == null) {
1063: if (focusLog.isLoggable(Level.FINE))
1064: focusLog.warning("Focus proxy is null for " + this );
1065: } else {
1066: if (focusLog.isLoggable(Level.FINE))
1067: focusLog.fine("Requesting focus to proxy: "
1068: + focusProxy);
1069: if (timeProvided) {
1070: focusProxy.xRequestFocus(time);
1071: } else {
1072: focusProxy.xRequestFocus();
1073: }
1074: }
1075: }
1076:
1077: XFocusProxyWindow getFocusProxy() {
1078: return focusProxy;
1079: }
1080:
1081: public void handleQuit() {
1082: postEvent(new WindowEvent((Window) target,
1083: WindowEvent.WINDOW_CLOSING));
1084: }
1085:
1086: final void dumpMe() {
1087: System.err.println(">>> Peer: " + x + ", " + y + ", " + width
1088: + ", " + height);
1089: }
1090:
1091: final void dumpTarget() {
1092: int getWidth = ComponentAccessor.getWidth((Component) target);
1093: int getHeight = ComponentAccessor.getHeight((Component) target);
1094: int getTargetX = ComponentAccessor.getX((Component) target);
1095: int getTargetY = ComponentAccessor.getY((Component) target);
1096: System.err.println(">>> Target: " + getTargetX + ", "
1097: + getTargetY + ", " + getWidth + ", " + getHeight);
1098: }
1099:
1100: final void dumpShell() {
1101: dumpWindow("Shell", getShell());
1102: }
1103:
1104: final void dumpContent() {
1105: dumpWindow("Content", getContentWindow());
1106: }
1107:
1108: final void dumpParent() {
1109: long parent = XlibUtil.getParentWindow(getShell());
1110: if (parent != 0) {
1111: dumpWindow("Parent", parent);
1112: } else {
1113: System.err.println(">>> NO PARENT");
1114: }
1115: }
1116:
1117: final void dumpWindow(String id, long window) {
1118: XWindowAttributes pattr = new XWindowAttributes();
1119: try {
1120: XToolkit.awtLock();
1121: try {
1122: int status = XlibWrapper.XGetWindowAttributes(XToolkit
1123: .getDisplay(), window, pattr.pData);
1124: } finally {
1125: XToolkit.awtUnlock();
1126: }
1127: System.err.println(">>>> " + id + ": " + pattr.get_x()
1128: + ", " + pattr.get_y() + ", " + pattr.get_width()
1129: + ", " + pattr.get_height());
1130: } finally {
1131: pattr.dispose();
1132: }
1133: }
1134:
1135: final void dumpAll() {
1136: dumpTarget();
1137: dumpMe();
1138: dumpParent();
1139: dumpShell();
1140: dumpContent();
1141: }
1142:
1143: boolean isMaximized() {
1144: return false;
1145: }
1146:
1147: boolean isOverrideRedirect() {
1148: return false;
1149: }
1150:
1151: public boolean requestWindowFocus(long time, boolean timeProvided) {
1152: focusLog.fine("Request for decorated window focus");
1153: // If this is Frame or Dialog we can't assure focus request success - but we still can try
1154: // If this is Window and its owner Frame is active we can be sure request succedded.
1155: Window win = (Window) target;
1156: Window focusedWindow = XKeyboardFocusManagerPeer
1157: .getCurrentNativeFocusedWindow();
1158: Window activeWindow = XWindowPeer
1159: .getDecoratedOwner(focusedWindow);
1160:
1161: focusLog.log(Level.FINER,
1162: "Current window is: active={0}, focused={1}",
1163: new Object[] { Boolean.valueOf(win == activeWindow),
1164: Boolean.valueOf(win == focusedWindow) });
1165:
1166: XWindowPeer toFocus = this ;
1167: while (toFocus.nextTransientFor != null) {
1168: toFocus = toFocus.nextTransientFor;
1169: }
1170:
1171: if (this == toFocus) {
1172: if (focusAllowedFor()) {
1173: if (win == activeWindow && win != focusedWindow) {
1174: // Happens when focus is on window child
1175: focusLog
1176: .fine("Focus is on child window - transfering it back");
1177: handleWindowFocusInSync(-1);
1178: } else {
1179: focusLog.fine("Requesting focus to this window");
1180: if (timeProvided) {
1181: requestXFocus(time);
1182: } else {
1183: requestXFocus();
1184: }
1185: }
1186: return true;
1187: } else {
1188: return false;
1189: }
1190: } else if (toFocus.focusAllowedFor()) {
1191: focusLog.fine("Requesting focus to " + toFocus);
1192: if (timeProvided) {
1193: toFocus.requestXFocus(time);
1194: } else {
1195: toFocus.requestXFocus();
1196: }
1197: return false;
1198: } else {
1199: // This might change when WM will have property to determine focus policy.
1200: // Right now, because policy is unknown we can't be sure we succedded
1201: return false;
1202: }
1203: }
1204:
1205: XWindowPeer actualFocusedWindow = null;
1206:
1207: void setActualFocusedWindow(XWindowPeer actualFocusedWindow) {
1208: synchronized (getStateLock()) {
1209: this .actualFocusedWindow = actualFocusedWindow;
1210: }
1211: }
1212:
1213: boolean requestWindowFocus(XWindowPeer actualFocusedWindow,
1214: long time, boolean timeProvided) {
1215: setActualFocusedWindow(actualFocusedWindow);
1216: return requestWindowFocus(time, timeProvided);
1217: }
1218:
1219: public void handleWindowFocusIn(long serial) {
1220: if (null == actualFocusedWindow) {
1221: super .handleWindowFocusIn(serial);
1222: } else {
1223: /*
1224: * Fix for 6314575.
1225: * If this is a result of clicking on one of the Frame's component
1226: * then 'actualFocusedWindow' shouldn't be focused. A decision of focusing
1227: * it or not should be made after the appropriate Java mouse event (if any)
1228: * is handled by the component where 'actualFocusedWindow' value may be reset.
1229: *
1230: * The fix is based on the empiric fact consisting in that the component
1231: * receives native mouse event nearly at the same time the Frame receives
1232: * WM_TAKE_FOCUS (when FocusIn is generated via XSetInputFocus call) but
1233: * definetely before the Frame gets FocusIn event (when this method is called).
1234: */
1235: postEvent(new InvocationEvent(target, new Runnable() {
1236: public void run() {
1237: XWindowPeer fw = null;
1238: synchronized (getStateLock()) {
1239: fw = actualFocusedWindow;
1240: actualFocusedWindow = null;
1241: if (null == fw || !fw.isVisible()
1242: || !fw.isFocusableWindow()) {
1243: fw = XDecoratedPeer.this ;
1244: }
1245: }
1246: fw.handleWindowFocusIn_Dispatch();
1247: }
1248: }));
1249: }
1250: }
1251:
1252: public void handleWindowFocusOut(Window oppositeWindow, long serial) {
1253: Window actualFocusedWindow = XKeyboardFocusManagerPeer
1254: .getCurrentNativeFocusedWindow();
1255:
1256: // If the actual focused window is not this decorated window then retain it.
1257: if (actualFocusedWindow != null
1258: && actualFocusedWindow != target) {
1259: Window owner = XWindowPeer
1260: .getDecoratedOwner(actualFocusedWindow);
1261:
1262: if (owner != null && owner == target) {
1263: setActualFocusedWindow((XWindowPeer) ComponentAccessor
1264: .getPeer(actualFocusedWindow));
1265: }
1266: }
1267: super .handleWindowFocusOut(oppositeWindow, serial);
1268: }
1269:
1270: private Point queryXLocation() {
1271: return XlibUtil.translateCoordinates(getContentWindow(),
1272: XlibWrapper.RootWindow(XToolkit.getDisplay(),
1273: getScreenNumber()), new Point(0, 0));
1274: }
1275: }
|