/* * Copyright (c) 2002, 2010, Oracle and/or its affiliates. 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.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 sun.util.logging.PlatformLogger; import sun.awt.AWTAccessor; import sun.awt.SunToolkit; abstract class XDecoratedPeer extends XWindowPeer { private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XDecoratedPeer"); private static final PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XDecoratedPeer"); private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XDecoratedPeer"); private static final PlatformLogger iconLog = PlatformLogger.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); } 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); 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.fine("Initial dimensions {0}", 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() & ~(XConstants.FocusChangeMask | XConstants.KeyPressMask | XConstants.KeyReleaseMask))); } void postInit(XCreateWindowParams params) { // The size hints must be set BEFORE mapping the window (see 6895647) updateSizeHints(dimensions); // The super method maps the window if it's visible on the shared level super.postInit(params); // The lines that follow need to be in a postInit, so they // happen after the X window is created. initResizability(); XWM.requestWMExtents(getWindow()); content = XContentWindow.createContent(this); if (warningWindow != null) { warningWindow.toFront(); } focusProxy = createFocusProxy(); } void setIconHints(java.util.List 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(XUtilConstants.PMinSize | (isLocationByPlatform()?0:(XUtilConstants.PPosition | XUtilConstants.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, XUtilConstants.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); } } } } 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() { AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); return getGraphics(content.surfaceData, compAccessor.getForeground(target), compAccessor.getBackground(target), compAccessor.getFont(target)); } public void setTitle(String title) { if (log.isLoggable(PlatformLogger.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; } 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.finer("FRAME_EXTENTS: {0}", 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(PlatformLogger.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.finer("wm-provided insets {0}", 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.finer("correctWM {0}", correctWM); } else { insLog.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.finest("Corrention {0}", 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(PlatformLogger.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(); AWTAccessor.getComponentAccessor().setLocation((Component)target, loc.x, 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(PlatformLogger.FINEST)) { insLog.finest("Get insets returns {0}", 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(PlatformLogger.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.fine("- not reparented({0}) or not visible({1}), default reshape", 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(AWTAccessor.getComponentAccessor().getX((Component)target), AWTAccessor.getComponentAccessor().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(PlatformLogger.FINE)) insLog.fine("For the operation {0} new dimensions are {1}", 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.fine("Configure notify {0}", 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(PlatformLogger.FINE)) { insLog.fine("reparented={0}, visible={1}, WM={2}, decorations={3}", 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(PlatformLogger.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 = AWTAccessor.getComponentAccessor().getBounds((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 { // ICCCM 4.1.5 states that a real ConfigureNotify will be sent when // a window is resized but the client can not tell if the window was // moved or not. The client should consider the position as unkown // and use TranslateCoordinates to find the actual position. // // TODO this should be the default for every case. switch (XWM.getWMID()) { case XWM.CDE_WM: case XWM.MOTIF_WM: case XWM.METACITY_WM: case XWM.MUTTER_WM: case XWM.SAWFISH_WM: { Point xlocation = queryXLocation(); if (log.isLoggable(PlatformLogger.FINE)) log.fine("New X location: {0}", 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.finer("Insets are {0}, new dimensions {1}", 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) { shellRect.width = Math.max(MIN_SIZE, shellRect.width); shellRect.height = Math.max(MIN_SIZE, shellRect.height); } 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(PlatformLogger.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(PlatformLogger.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(PlatformLogger.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) { 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); } winAttr.functions = fs; XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), 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; } final 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(PlatformLogger.FINE)) insLog.fine("getLocationOnScreen {0} not reparented: {1} ", 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 XConstants.ConfigureNotify: return true; case XConstants.EnterNotify: case XConstants.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.finer("Setting {0} to visible {1}", 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, XUtilConstants.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); } } } private void handleWmTakeFocus(XClientMessageEvent cl) { focusLog.fine("WM_TAKE_FOCUS on {0}", 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(PlatformLogger.FINE)) focusLog.warning("Focus proxy is null for " + this); } else { if (focusLog.isLoggable(PlatformLogger.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() { AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); int getWidth = compAccessor.getWidth((Component)target); int getHeight = compAccessor.getHeight((Component)target); int getTargetX = compAccessor.getX((Component)target); int getTargetY = compAccessor.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; } @Override boolean isOverrideRedirect() { return Window.Type.POPUP.equals(getWindowType()); } 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 focusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow(); Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow); focusLog.finer("Current window is: active={0}, focused={1}", Boolean.valueOf(target == activeWindow), Boolean.valueOf(target == focusedWindow)); XWindowPeer toFocus = this; while (toFocus.nextTransientFor != null) { toFocus = toFocus.nextTransientFor; } if (toFocus == null || !toFocus.focusAllowedFor()) { // 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; } if (this == toFocus) { if (isWMStateNetHidden()) { focusLog.fine("The window is unmapped, so rejecting the request"); return false; } if (target == activeWindow && target != focusedWindow) { // Happens when an owned window is currently focused focusLog.fine("Focus is on child window - transfering it back to the owner"); handleWindowFocusInSync(-1); return true; } Window realNativeFocusedWindow = XWindowPeer.getNativeFocusedWindow(); focusLog.finest("Real native focused window: " + realNativeFocusedWindow + "\nKFM's focused window: " + focusedWindow); // See 6522725, 6613426, 8009224 if (target == realNativeFocusedWindow && XWM.getWMID() != XWM.ENLIGHTEN_WM) { focusLog.fine("The window is already natively focused."); return true; } } focusLog.fine("Requesting focus to " + (this == toFocus ? "this window" : toFocus)); if (timeProvided) { toFocus.requestXFocus(time); } else { toFocus.requestXFocus(); } return (this == toFocus); } 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.getInstance().getCurrentFocusedWindow(); // 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) AWTAccessor.getComponentAccessor().getPeer(actualFocusedWindow)); } } super.handleWindowFocusOut(oppositeWindow, serial); } private Point queryXLocation() { return XlibUtil.translateCoordinates( getContentWindow(), XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()), new Point(0, 0)); } }