/*
* Copyright (c) 2003, 2014, 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 sun.awt.*;
import java.util.*;
import sun.util.logging.PlatformLogger;
public class XBaseWindow {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XBaseWindow");
private static final PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XBaseWindow");
private static final PlatformLogger eventLog = PlatformLogger.getLogger("sun.awt.X11.event.XBaseWindow");
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XBaseWindow");
private static final PlatformLogger grabLog = PlatformLogger.getLogger("sun.awt.X11.grab.XBaseWindow");
public static final String
PARENT_WINDOW = "parent window", // parent window, Long
BOUNDS = "bounds", // bounds of the window, Rectangle
OVERRIDE_REDIRECT = "overrideRedirect", // override_redirect setting, Boolean
EVENT_MASK = "event mask", // event mask, Integer
VALUE_MASK = "value mask", // value mask, Long
BORDER_PIXEL = "border pixel", // border pixel value, Integer
COLORMAP = "color map", // color map, Long
DEPTH = "visual depth", // depth, Integer
VISUAL_CLASS = "visual class", // visual class, Integer
VISUAL = "visual", // visual, Long
EMBEDDED = "embedded", // is embedded?, Boolean
DELAYED = "delayed", // is creation delayed?, Boolean
PARENT = "parent", // parent peer
BACKGROUND_PIXMAP = "pixmap", // background pixmap
VISIBLE = "visible", // whether it is visible by default
SAVE_UNDER = "save under", // save content under this window
BACKING_STORE = "backing store", // enables double buffering
BIT_GRAVITY = "bit gravity"; // copy old content on geometry change
private XCreateWindowParams delayedParams;
Set<Long> children = new HashSet<Long>();
long window;
boolean visible;
boolean mapped;
boolean embedded;
Rectangle maxBounds;
volatile XBaseWindow parentWindow;
private boolean disposed;
private long screen;
private XSizeHints hints;
private XWMHints wmHints;
final static int MIN_SIZE = 1;
final static int DEF_LOCATION = 1;
private static XAtom wm_client_leader;
static enum InitialiseState {
INITIALISING,
NOT_INITIALISED,
INITIALISED,
FAILED_INITIALISATION
};
private InitialiseState initialising;
int x;
int y;
int width;
int height;
void awtLock() {
XToolkit.awtLock();
}
void awtUnlock() {
XToolkit.awtUnlock();
}
void awtLockNotifyAll() {
XToolkit.awtLockNotifyAll();
}
void awtLockWait() throws InterruptedException {
XToolkit.awtLockWait();
}
// To prevent errors from overriding obsolete methods
protected final void init(long parentWindow, Rectangle bounds) {}
protected final void preInit() {}
protected final void postInit() {}
// internal lock for synchronizing state changes and paint calls, initialized in preInit.
// the order with other locks: AWTLock -> stateLock
static class StateLock extends Object { }
protected StateLock state_lock;
/**
* Called for delayed inits during construction
*/
void instantPreInit(XCreateWindowParams params) {
state_lock = new StateLock();
initialising = InitialiseState.NOT_INITIALISED;
}
/**
* Called before window creation, descendants should override to initialize the data,
* initialize params.
*/
void preInit(XCreateWindowParams params) {
state_lock = new StateLock();
initialising = InitialiseState.NOT_INITIALISED;
embedded = Boolean.TRUE.equals(params.get(EMBEDDED));
visible = Boolean.TRUE.equals(params.get(VISIBLE));
Object parent = params.get(PARENT);
if (parent instanceof XBaseWindow) {
parentWindow = (XBaseWindow)parent;
} else {
Long parentWindowID = (Long)params.get(PARENT_WINDOW);
if (parentWindowID != null) {
parentWindow = XToolkit.windowToXWindow(parentWindowID);
}
}
Long eventMask = (Long)params.get(EVENT_MASK);
if (eventMask != null) {
long mask = eventMask.longValue();
mask |= XConstants.SubstructureNotifyMask;
params.put(EVENT_MASK, mask);
}
screen = -1;
}
/**
* Called after window creation, descendants should override to initialize Window
* with class-specific values and perform post-initialization actions.
*/
void postInit(XCreateWindowParams params) {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("WM name is " + getWMName());
}
updateWMName();
// Set WM_CLIENT_LEADER property
initClientLeader();
}
/**
* Creates window using parameters <code>params</code>
* If params contain flag DELAYED doesn't do anything.
* Note: Descendants can call this method to create the window
* at the time different to instance construction.
*/
protected final void init(XCreateWindowParams params) {
awtLock();
initialising = InitialiseState.INITIALISING;
awtUnlock();
try {
if (!Boolean.TRUE.equals(params.get(DELAYED))) {
preInit(params);
create(params);
postInit(params);
} else {
instantPreInit(params);
delayedParams = params;
}
awtLock();
initialising = InitialiseState.INITIALISED;
awtLockNotifyAll();
awtUnlock();
} catch (RuntimeException re) {
awtLock();
initialising = InitialiseState.FAILED_INITIALISATION;
awtLockNotifyAll();
awtUnlock();
throw re;
} catch (Throwable t) {
log.warning("Exception during peer initialization", t);
awtLock();
initialising = InitialiseState.FAILED_INITIALISATION;
awtLockNotifyAll();
awtUnlock();
}
}
public boolean checkInitialised() {
awtLock();
try {
switch (initialising) {
case INITIALISED:
return true;
case INITIALISING:
try {
while (initialising != InitialiseState.INITIALISED) {
awtLockWait();
}
} catch (InterruptedException ie) {
return false;
}
return true;
case NOT_INITIALISED:
case FAILED_INITIALISATION:
return false;
default:
return false;
}
} finally {
awtUnlock();
}
}
/*
* Creates an invisible InputOnly window without an associated Component.
*/
XBaseWindow() {
this(new XCreateWindowParams());
}
/**
* Creates normal child window
*/
XBaseWindow(long parentWindow, Rectangle bounds) {
this(new XCreateWindowParams(new Object[] {
BOUNDS, bounds,
PARENT_WINDOW, Long.valueOf(parentWindow)}));
}
/**
* Creates top-level window
*/
XBaseWindow(Rectangle bounds) {
this(new XCreateWindowParams(new Object[] {
BOUNDS, bounds
}));
}
public XBaseWindow (XCreateWindowParams params) {
init(params);
}
/* This create is used by the XEmbeddedFramePeer since it has to create the window
as a child of the netscape window. This netscape window is passed in as wid */
XBaseWindow(long parentWindow) {
this(new XCreateWindowParams(new Object[] {
PARENT_WINDOW, Long.valueOf(parentWindow),
EMBEDDED, Boolean.TRUE
}));
}
/**
* Verifies that all required parameters are set. If not, sets them to default values.
* Verifies values of critical parameters, adjust their values when needed.
* @throws IllegalArgumentException if params is null
*/
protected void checkParams(XCreateWindowParams params) {
if (params == null) {
throw new IllegalArgumentException("Window creation parameters are null");
}
params.putIfNull(PARENT_WINDOW, Long.valueOf(XToolkit.getDefaultRootWindow()));
params.putIfNull(BOUNDS, new Rectangle(DEF_LOCATION, DEF_LOCATION, MIN_SIZE, MIN_SIZE));
params.putIfNull(DEPTH, Integer.valueOf((int)XConstants.CopyFromParent));
params.putIfNull(VISUAL, Long.valueOf(XConstants.CopyFromParent));
params.putIfNull(VISUAL_CLASS, Integer.valueOf(XConstants.InputOnly));
params.putIfNull(VALUE_MASK, Long.valueOf(XConstants.CWEventMask));
Rectangle bounds = (Rectangle)params.get(BOUNDS);
bounds.width = Math.max(MIN_SIZE, bounds.width);
bounds.height = Math.max(MIN_SIZE, bounds.height);
Long eventMaskObj = (Long)params.get(EVENT_MASK);
long eventMask = eventMaskObj != null ? eventMaskObj.longValue() : 0;
// We use our own synthetic grab see XAwtState.getGrabWindow()
// (see X vol. 1, 8.3.3.2)
eventMask |= XConstants.PropertyChangeMask | XConstants.OwnerGrabButtonMask;
params.put(EVENT_MASK, Long.valueOf(eventMask));
}
/**
* Creates window with parameters specified by <code>params</code>
* @see #init
*/
private final void create(XCreateWindowParams params) {
XToolkit.awtLock();
try {
XSetWindowAttributes xattr = new XSetWindowAttributes();
try {
checkParams(params);
long value_mask = ((Long)params.get(VALUE_MASK)).longValue();
Long eventMask = (Long)params.get(EVENT_MASK);
xattr.set_event_mask(eventMask.longValue());
value_mask |= XConstants.CWEventMask;
Long border_pixel = (Long)params.get(BORDER_PIXEL);
if (border_pixel != null) {
xattr.set_border_pixel(border_pixel.longValue());
value_mask |= XConstants.CWBorderPixel;
}
Long colormap = (Long)params.get(COLORMAP);
if (colormap != null) {
xattr.set_colormap(colormap.longValue());
value_mask |= XConstants.CWColormap;
}
Long background_pixmap = (Long)params.get(BACKGROUND_PIXMAP);
if (background_pixmap != null) {
xattr.set_background_pixmap(background_pixmap.longValue());
value_mask |= XConstants.CWBackPixmap;
}
Long parentWindow = (Long)params.get(PARENT_WINDOW);
Rectangle bounds = (Rectangle)params.get(BOUNDS);
Integer depth = (Integer)params.get(DEPTH);
Integer visual_class = (Integer)params.get(VISUAL_CLASS);
Long visual = (Long)params.get(VISUAL);
Boolean overrideRedirect = (Boolean)params.get(OVERRIDE_REDIRECT);
if (overrideRedirect != null) {
xattr.set_override_redirect(overrideRedirect.booleanValue());
value_mask |= XConstants.CWOverrideRedirect;
}
Boolean saveUnder = (Boolean)params.get(SAVE_UNDER);
if (saveUnder != null) {
xattr.set_save_under(saveUnder.booleanValue());
value_mask |= XConstants.CWSaveUnder;
}
Integer backingStore = (Integer)params.get(BACKING_STORE);
if (backingStore != null) {
xattr.set_backing_store(backingStore.intValue());
value_mask |= XConstants.CWBackingStore;
}
Integer bitGravity = (Integer)params.get(BIT_GRAVITY);
if (bitGravity != null) {
xattr.set_bit_gravity(bitGravity.intValue());
value_mask |= XConstants.CWBitGravity;
}
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("Creating window for " + this + " with the following attributes: \n" + params);
}
window = XlibWrapper.XCreateWindow(XToolkit.getDisplay(),
parentWindow.longValue(),
bounds.x, bounds.y, // location
bounds.width, bounds.height, // size
0, // border
depth.intValue(), // depth
visual_class.intValue(), // class
visual.longValue(), // visual
value_mask, // value mask
xattr.pData); // attributes
if (window == 0) {
throw new IllegalStateException("Couldn't create window because of wrong parameters. Run with NOISY_AWT to see details");
}
XToolkit.addToWinMap(window, this);
} finally {
xattr.dispose();
}
} finally {
XToolkit.awtUnlock();
}
}
public XCreateWindowParams getDelayedParams() {
return delayedParams;
}
protected String getWMName() {
return XToolkit.getCorrectXIDString(getClass().getName());
}
protected void initClientLeader() {
XToolkit.awtLock();
try {
if (wm_client_leader == null) {
wm_client_leader = XAtom.get("WM_CLIENT_LEADER");
}
wm_client_leader.setWindowProperty(this, getXAWTRootWindow());
} finally {
XToolkit.awtUnlock();
}
}
static XRootWindow getXAWTRootWindow() {
return XRootWindow.getInstance();
}
void destroy() {
XToolkit.awtLock();
try {
if (hints != null) {
XlibWrapper.XFree(hints.pData);
hints = null;
}
XToolkit.removeFromWinMap(getWindow(), this);
XlibWrapper.XDestroyWindow(XToolkit.getDisplay(), getWindow());
if (XPropertyCache.isCachingSupported()) {
XPropertyCache.clearCache(window);
}
window = -1;
if( !isDisposed() ) {
setDisposed( true );
}
XAwtState.getGrabWindow(); // Magic - getGrabWindow clear state if grabbing window is disposed of.
} finally {
XToolkit.awtUnlock();
}
}
void flush() {
XToolkit.awtLock();
try {
XlibWrapper.XFlush(XToolkit.getDisplay());
} finally {
XToolkit.awtUnlock();
}
}
/**
* Helper function to set W
*/
public final void setWMHints(XWMHints hints) {
XToolkit.awtLock();
try {
XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData);
} finally {
XToolkit.awtUnlock();
}
}
public XWMHints getWMHints() {
if (wmHints == null) {
wmHints = new XWMHints(XlibWrapper.XAllocWMHints());
// XlibWrapper.XGetWMHints(XToolkit.getDisplay(),
// getWindow(),
// wmHints.pData);
}
return wmHints;
}
/*
* Call this method under AWTLock.
* The lock should be acquired untill all operations with XSizeHints are completed.
*/
public XSizeHints getHints() {
if (hints == null) {
long p_hints = XlibWrapper.XAllocSizeHints();
hints = new XSizeHints(p_hints);
// XlibWrapper.XGetWMNormalHints(XToolkit.getDisplay(), getWindow(), p_hints, XlibWrapper.larg1);
// TODO: Shouldn't we listen for WM updates on this property?
}
return hints;
}
public void setSizeHints(long flags, int x, int y, int width, int height) {
if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(flags));
}
XToolkit.awtLock();
try {
XSizeHints hints = getHints();
// Note: if PPosition is not set in flags this means that
// we want to reset PPosition in hints. This is necessary
// for locationByPlatform functionality
if ((flags & XUtilConstants.PPosition) != 0) {
hints.set_x(x);
hints.set_y(y);
}
if ((flags & XUtilConstants.PSize) != 0) {
hints.set_width(width);
hints.set_height(height);
} else if ((hints.get_flags() & XUtilConstants.PSize) != 0) {
flags |= XUtilConstants.PSize;
}
if ((flags & XUtilConstants.PMinSize) != 0) {
hints.set_min_width(width);
hints.set_min_height(height);
} else if ((hints.get_flags() & XUtilConstants.PMinSize) != 0) {
flags |= XUtilConstants.PMinSize;
//Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
//We don't need to reset minimum size if it's already set
}
if ((flags & XUtilConstants.PMaxSize) != 0) {
if (maxBounds != null) {
if (maxBounds.width != Integer.MAX_VALUE) {
hints.set_max_width(maxBounds.width);
} else {
hints.set_max_width(XToolkit.getDefaultScreenWidth());
}
if (maxBounds.height != Integer.MAX_VALUE) {
hints.set_max_height(maxBounds.height);
} else {
hints.set_max_height(XToolkit.getDefaultScreenHeight());
}
} else {
hints.set_max_width(width);
hints.set_max_height(height);
}
} else if ((hints.get_flags() & XUtilConstants.PMaxSize) != 0) {
flags |= XUtilConstants.PMaxSize;
if (maxBounds != null) {
if (maxBounds.width != Integer.MAX_VALUE) {
hints.set_max_width(maxBounds.width);
} else {
hints.set_max_width(XToolkit.getDefaultScreenWidth());
}
if (maxBounds.height != Integer.MAX_VALUE) {
hints.set_max_height(maxBounds.height);
} else {
hints.set_max_height(XToolkit.getDefaultScreenHeight());
}
} else {
// Leave intact
}
}
flags |= XUtilConstants.PWinGravity;
hints.set_flags(flags);
hints.set_win_gravity(XConstants.NorthWestGravity);
if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("Setting hints, resulted flags " + XlibWrapper.hintsToString(flags) +
", values " + hints);
}
XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(), getWindow(), hints.pData);
} finally {
XToolkit.awtUnlock();
}
}
public boolean isMinSizeSet() {
XSizeHints hints = getHints();
long flags = hints.get_flags();
return ((flags & XUtilConstants.PMinSize) == XUtilConstants.PMinSize);
}
/**
* This lock object can be used to protect instance data from concurrent access
* by two threads. If both state lock and AWT lock are taken, AWT Lock should be taken first.
*/
Object getStateLock() {
return state_lock;
}
public long getWindow() {
return window;
}
public long getContentWindow() {
return window;
}
public XBaseWindow getContentXWindow() {
return XToolkit.windowToXWindow(getContentWindow());
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
public Dimension getSize() {
return new Dimension(width, height);
}
public void toFront() {
XToolkit.awtLock();
try {
XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow());
} finally {
XToolkit.awtUnlock();
}
}
public void xRequestFocus(long time) {
XToolkit.awtLock();
try {
if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
focusLog.finer("XSetInputFocus on " + Long.toHexString(getWindow()) + " with time " + time);
}
XlibWrapper.XSetInputFocus2(XToolkit.getDisplay(), getWindow(), time);
} finally {
XToolkit.awtUnlock();
}
}
public void xRequestFocus() {
XToolkit.awtLock();
try {
if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
focusLog.finer("XSetInputFocus on " + Long.toHexString(getWindow()));
}
XlibWrapper.XSetInputFocus(XToolkit.getDisplay(), getWindow());
} finally {
XToolkit.awtUnlock();
}
}
public static long xGetInputFocus() {
XToolkit.awtLock();
try {
return XlibWrapper.XGetInputFocus(XToolkit.getDisplay());
} finally {
XToolkit.awtUnlock();
}
}
public void xSetVisible(boolean visible) {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("Setting visible on " + this + " to " + visible);
}
XToolkit.awtLock();
try {
this.visible = visible;
if (visible) {
XlibWrapper.XMapWindow(XToolkit.getDisplay(), getWindow());
}
else {
XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), getWindow());
}
XlibWrapper.XFlush(XToolkit.getDisplay());
} finally {
XToolkit.awtUnlock();
}
}
boolean isMapped() {
return mapped;
}
void updateWMName() {
String name = getWMName();
XToolkit.awtLock();
try {
if (name == null) {
name = " ";
}
XAtom nameAtom = XAtom.get(XAtom.XA_WM_NAME);
nameAtom.setProperty(getWindow(), name);
XAtom netNameAtom = XAtom.get("_NET_WM_NAME");
netNameAtom.setPropertyUTF8(getWindow(), name);
} finally {
XToolkit.awtUnlock();
}
}
void setWMClass(String[] cl) {
if (cl.length != 2) {
throw new IllegalArgumentException("WM_CLASS_NAME consists of exactly two strings");
}
XToolkit.awtLock();
try {
XAtom xa = XAtom.get(XAtom.XA_WM_CLASS);
xa.setProperty8(getWindow(), cl[0] + '\0' + cl[1]);
} finally {
XToolkit.awtUnlock();
}
}
boolean isVisible() {
return visible;
}
static long getScreenOfWindow(long window) {
XToolkit.awtLock();
try {
return XlibWrapper.getScreenOfWindow(XToolkit.getDisplay(), window);
} finally {
XToolkit.awtUnlock();
}
}
long getScreenNumber() {
XToolkit.awtLock();
try {
return XlibWrapper.XScreenNumberOfScreen(getScreen());
} finally {
XToolkit.awtUnlock();
}
}
long getScreen() {
if (screen == -1) { // Not initialized
screen = getScreenOfWindow(window);
}
return screen;
}
public void xSetBounds(Rectangle bounds) {
xSetBounds(bounds.x, bounds.y, bounds.width, bounds.height);
}
public void xSetBounds(int x, int y, int width, int height) {
if (getWindow() == 0) {
insLog.warning("Attempt to resize uncreated window");
throw new IllegalStateException("Attempt to resize uncreated window");
}
if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
insLog.fine("Setting bounds on " + this + " to (" + x + ", " + y + "), " + width + "x" + height);
}
width = Math.max(MIN_SIZE, width);
height = Math.max(MIN_SIZE, height);
XToolkit.awtLock();
try {
XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getWindow(), x,y,width,height);
} finally {
XToolkit.awtUnlock();
}
}
/**
* Translate coordinates from one window into another. Optimized
* for XAWT - uses cached data when possible. Preferable over
* pure XTranslateCoordinates.
* @return coordinates relative to dst, or null if error happened
*/
static Point toOtherWindow(long src, long dst, int x, int y) {
Point rpt = new Point(0, 0);
// Check if both windows belong to XAWT - then no X calls are necessary
XBaseWindow srcPeer = XToolkit.windowToXWindow(src);
XBaseWindow dstPeer = XToolkit.windowToXWindow(dst);
if (srcPeer != null && dstPeer != null) {
// (x, y) is relative to src
rpt.x = x + srcPeer.getAbsoluteX() - dstPeer.getAbsoluteX();
rpt.y = y + srcPeer.getAbsoluteY() - dstPeer.getAbsoluteY();
} else if (dstPeer != null && XlibUtil.isRoot(src, dstPeer.getScreenNumber())) {
// from root into peer
rpt.x = x - dstPeer.getAbsoluteX();
rpt.y = y - dstPeer.getAbsoluteY();
} else if (srcPeer != null && XlibUtil.isRoot(dst, srcPeer.getScreenNumber())) {
// from peer into root
rpt.x = x + srcPeer.getAbsoluteX();
rpt.y = y + srcPeer.getAbsoluteY();
} else {
rpt = XlibUtil.translateCoordinates(src, dst, new Point(x, y));
}
return rpt;
}
/*
* Convert to global coordinates.
*/
Rectangle toGlobal(Rectangle rec) {
Point p = toGlobal(rec.getLocation());
Rectangle newRec = new Rectangle(rec);
if (p != null) {
newRec.setLocation(p);
}
return newRec;
}
Point toGlobal(Point pt) {
Point p = toGlobal(pt.x, pt.y);
if (p != null) {
return p;
} else {
return new Point(pt);
}
}
Point toGlobal(int x, int y) {
long root;
XToolkit.awtLock();
try {
root = XlibWrapper.RootWindow(XToolkit.getDisplay(),
getScreenNumber());
} finally {
XToolkit.awtUnlock();
}
Point p = toOtherWindow(getContentWindow(), root, x, y);
if (p != null) {
return p;
} else {
return new Point(x, y);
}
}
/*
* Convert to local coordinates.
*/
Point toLocal(Point pt) {
Point p = toLocal(pt.x, pt.y);
if (p != null) {
return p;
} else {
return new Point(pt);
}
}
Point toLocal(int x, int y) {
long root;
XToolkit.awtLock();
try {
root = XlibWrapper.RootWindow(XToolkit.getDisplay(),
getScreenNumber());
} finally {
XToolkit.awtUnlock();
}
Point p = toOtherWindow(root, getContentWindow(), x, y);
if (p != null) {
return p;
} else {
return new Point(x, y);
}
}
/**
* We should always grab both keyboard and pointer to control event flow
* on popups. This also simplifies synthetic grab implementation.
* The active grab overrides activated automatic grab.
*/
public boolean grabInput() {
if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
grabLog.fine("Grab input on {0}", this);
}
XToolkit.awtLock();
try {
if (XAwtState.getGrabWindow() == this &&
XAwtState.isManualGrab())
{
grabLog.fine(" Already Grabbed");
return true;
}
//6273031: PIT. Choice drop down does not close once it is right clicked to show a popup menu
//remember previous window having grab and if it's not null ungrab it.
XBaseWindow prevGrabWindow = XAwtState.getGrabWindow();
final int eventMask = (int) (XConstants.ButtonPressMask | XConstants.ButtonReleaseMask
| XConstants.EnterWindowMask | XConstants.LeaveWindowMask | XConstants.PointerMotionMask
| XConstants.ButtonMotionMask);
final int ownerEvents = 1;
//6714678: IDE (Netbeans, Eclipse, JDeveloper) Debugger hangs
//process on Linux
//The user must pass the sun.awt.disablegrab property to disable
//taking grabs. This prevents hanging of the GUI when a breakpoint
//is hit while a popup window taking the grab is open.
if (!XToolkit.getSunAwtDisableGrab()) {
int ptrGrab = XlibWrapper.XGrabPointer(XToolkit.getDisplay(),
getContentWindow(), ownerEvents, eventMask, XConstants.GrabModeAsync,
XConstants.GrabModeAsync, XConstants.None, (XWM.isMotif() ? XToolkit.arrowCursor : XConstants.None),
XConstants.CurrentTime);
// Check grab results to be consistent with X server grab
if (ptrGrab != XConstants.GrabSuccess) {
XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), XConstants.CurrentTime);
XAwtState.setGrabWindow(null);
grabLog.fine(" Grab Failure - mouse");
return false;
}
int keyGrab = XlibWrapper.XGrabKeyboard(XToolkit.getDisplay(),
getContentWindow(), ownerEvents, XConstants.GrabModeAsync, XConstants.GrabModeAsync,
XConstants.CurrentTime);
if (keyGrab != XConstants.GrabSuccess) {
XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), XConstants.CurrentTime);
XlibWrapper.XUngrabKeyboard(XToolkit.getDisplay(), XConstants.CurrentTime);
XAwtState.setGrabWindow(null);
grabLog.fine(" Grab Failure - keyboard");
return false;
}
}
if (prevGrabWindow != null) {
prevGrabWindow.ungrabInputImpl();
}
XAwtState.setGrabWindow(this);
grabLog.fine(" Grab - success");
return true;
} finally {
XToolkit.awtUnlock();
}
}
static void ungrabInput() {
XToolkit.awtLock();
try {
XBaseWindow grabWindow = XAwtState.getGrabWindow();
if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
grabLog.fine("UnGrab input on {0}", grabWindow);
}
if (grabWindow != null) {
grabWindow.ungrabInputImpl();
if (!XToolkit.getSunAwtDisableGrab()) {
XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), XConstants.CurrentTime);
XlibWrapper.XUngrabKeyboard(XToolkit.getDisplay(), XConstants.CurrentTime);
}
XAwtState.setGrabWindow(null);
// we need to call XFlush() here to force ungrab
// see 6384219 for details
XlibWrapper.XFlush(XToolkit.getDisplay());
}
} finally {
XToolkit.awtUnlock();
}
}
// called from ungrabInput, used in popup windows to hide theirselfs in ungrabbing
void ungrabInputImpl() {
}
static void checkSecurity() {
if (XToolkit.isSecurityWarningEnabled() && XToolkit.isToolkitThread()) {
StackTraceElement stack[] = (new Throwable()).getStackTrace();
log.warning(stack[1] + ": Security violation: calling user code on toolkit thread");
}
}
public Set<Long> getChildren() {
synchronized (getStateLock()) {
return new HashSet<Long>(children);
}
}
// -------------- Event handling ----------------
public void handleMapNotifyEvent(XEvent xev) {
mapped = true;
}
public void handleUnmapNotifyEvent(XEvent xev) {
mapped = false;
}
public void handleReparentNotifyEvent(XEvent xev) {
if (eventLog.isLoggable(PlatformLogger.Level.FINER)) {
XReparentEvent msg = xev.get_xreparent();
eventLog.finer(msg.toString());
}
}
public void handlePropertyNotify(XEvent xev) {
XPropertyEvent msg = xev.get_xproperty();
if (XPropertyCache.isCachingSupported()) {
XPropertyCache.clearCache(window, XAtom.get(msg.get_atom()));
}
if (eventLog.isLoggable(PlatformLogger.Level.FINER)) {
eventLog.finer("{0}", msg);
}
}
public void handleDestroyNotify(XEvent xev) {
XAnyEvent xany = xev.get_xany();
if (xany.get_window() == getWindow()) {
XToolkit.removeFromWinMap(getWindow(), this);
if (XPropertyCache.isCachingSupported()) {
XPropertyCache.clearCache(getWindow());
}
}
if (xany.get_window() != getWindow()) {
synchronized (getStateLock()) {
children.remove(xany.get_window());
}
}
}
public void handleCreateNotify(XEvent xev) {
XAnyEvent xany = xev.get_xany();
if (xany.get_window() != getWindow()) {
synchronized (getStateLock()) {
children.add(xany.get_window());
}
}
}
public void handleClientMessage(XEvent xev) {
if (eventLog.isLoggable(PlatformLogger.Level.FINER)) {
XClientMessageEvent msg = xev.get_xclient();
eventLog.finer(msg.toString());
}
}
public void handleVisibilityEvent(XEvent xev) {
}
public void handleKeyPress(XEvent xev) {
}
public void handleKeyRelease(XEvent xev) {
}
public void handleExposeEvent(XEvent xev) {
}
/**
* Activate automatic grab on first ButtonPress,
* deactivate on full mouse release
*/
public void handleButtonPressRelease(XEvent xev) {
XButtonEvent xbe = xev.get_xbutton();
/*
* Ignore the buttons above 20 due to the bit limit for
* InputEvent.BUTTON_DOWN_MASK.
* One more bit is reserved for FIRST_HIGH_BIT.
*/
if (xbe.get_button() > SunToolkit.MAX_BUTTONS_SUPPORTED) {
return;
}
int buttonState = 0;
buttonState = xbe.get_state() & XConstants.ALL_BUTTONS_MASK;
switch (xev.get_type()) {
case XConstants.ButtonPress:
if (buttonState == 0) {
XWindowPeer parent = getToplevelXWindow();
// See 6385277, 6981400.
if (parent != null && parent.isFocusableWindow()) {
// A click in a client area drops the actual focused window retaining.
parent.setActualFocusedWindow(null);
parent.requestWindowFocus(xbe.get_time(), true);
}
XAwtState.setAutoGrabWindow(this);
}
break;
case XConstants.ButtonRelease:
if (isFullRelease(buttonState, xbe.get_button())) {
XAwtState.setAutoGrabWindow(null);
}
break;
}
}
public void handleMotionNotify(XEvent xev) {
}
public void handleXCrossingEvent(XEvent xev) {
}
public void handleConfigureNotifyEvent(XEvent xev) {
XConfigureEvent xe = xev.get_xconfigure();
if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
insLog.finer("Configure, {0}", xe);
}
x = xe.get_x();
y = xe.get_y();
width = xe.get_width();
height = xe.get_height();
}
/**
* Checks ButtonRelease released all Mouse buttons
*/
static boolean isFullRelease(int buttonState, int button) {
final int buttonsNumber = XToolkit.getNumberOfButtonsForMask();
if (button < 0 || button > buttonsNumber) {
return buttonState == 0;
} else {
return buttonState == XlibUtil.getButtonMask(button);
}
}
static boolean isGrabbedEvent(XEvent ev, XBaseWindow target) {
switch (ev.get_type()) {
case XConstants.ButtonPress:
case XConstants.ButtonRelease:
case XConstants.MotionNotify:
case XConstants.KeyPress:
case XConstants.KeyRelease:
return true;
case XConstants.LeaveNotify:
case XConstants.EnterNotify:
// We shouldn't dispatch this events to the grabbed components (see 6317481)
// But this logic is important if the grabbed component is top-level (see realSync)
return (target instanceof XWindowPeer);
default:
return false;
}
}
/**
* Dispatches event to the grab Window or event source window depending
* on whether the grab is active and on the event type
*/
static void dispatchToWindow(XEvent ev) {
XBaseWindow target = XAwtState.getGrabWindow();
if (target == null || !isGrabbedEvent(ev, target)) {
target = XToolkit.windowToXWindow(ev.get_xany().get_window());
}
if (target != null && target.checkInitialised()) {
target.dispatchEvent(ev);
}
}
public void dispatchEvent(XEvent xev) {
if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
eventLog.finest(xev.toString());
}
int type = xev.get_type();
if (isDisposed()) {
return;
}
switch (type)
{
case XConstants.VisibilityNotify:
handleVisibilityEvent(xev);
break;
case XConstants.ClientMessage:
handleClientMessage(xev);
break;
case XConstants.Expose :
case XConstants.GraphicsExpose :
handleExposeEvent(xev);
break;
case XConstants.ButtonPress:
case XConstants.ButtonRelease:
handleButtonPressRelease(xev);
break;
case XConstants.MotionNotify:
handleMotionNotify(xev);
break;
case XConstants.KeyPress:
handleKeyPress(xev);
break;
case XConstants.KeyRelease:
handleKeyRelease(xev);
break;
case XConstants.EnterNotify:
case XConstants.LeaveNotify:
handleXCrossingEvent(xev);
break;
case XConstants.ConfigureNotify:
handleConfigureNotifyEvent(xev);
break;
case XConstants.MapNotify:
handleMapNotifyEvent(xev);
break;
case XConstants.UnmapNotify:
handleUnmapNotifyEvent(xev);
break;
case XConstants.ReparentNotify:
handleReparentNotifyEvent(xev);
break;
case XConstants.PropertyNotify:
handlePropertyNotify(xev);
break;
case XConstants.DestroyNotify:
handleDestroyNotify(xev);
break;
case XConstants.CreateNotify:
handleCreateNotify(xev);
break;
}
}
protected boolean isEventDisabled(XEvent e) {
return false;
}
int getX() {
return x;
}
int getY() {
return y;
}
int getWidth() {
return width;
}
int getHeight() {
return height;
}
void setDisposed(boolean d) {
disposed = d;
}
boolean isDisposed() {
return disposed;
}
public int getAbsoluteX() {
XBaseWindow pw = getParentWindow();
if (pw != null) {
return pw.getAbsoluteX() + getX();
} else {
// Overridden for top-levels as their (x,y) is Java (x, y), not native location
return getX();
}
}
public int getAbsoluteY() {
XBaseWindow pw = getParentWindow();
if (pw != null) {
return pw.getAbsoluteY() + getY();
} else {
return getY();
}
}
public XBaseWindow getParentWindow() {
return parentWindow;
}
public XWindowPeer getToplevelXWindow() {
XBaseWindow bw = this;
while (bw != null && !(bw instanceof XWindowPeer)) {
bw = bw.getParentWindow();
}
return (XWindowPeer)bw;
}
public String toString() {
return super.toString() + "(" + Long.toString(getWindow(), 16) + ")";
}
/**
* Returns whether the given point is inside of the window. Coordinates are local.
*/
public boolean contains(int x, int y) {
return x >= 0 && y >= 0 && x < getWidth() && y < getHeight();
}
/**
* Returns whether the given point is inside of the window. Coordinates are global.
*/
public boolean containsGlobal(int x, int y) {
return x >= getAbsoluteX() && y >= getAbsoluteY() && x < (getAbsoluteX()+getWidth()) && y < (getAbsoluteY()+getHeight());
}
}