6724890: Deadlock between AWT-EventQueue-1 and AWT-XAWT threads during IDE start
Reviewed-by: art, ant
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package sun.awt.X11;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.InvalidDnDOperationException;
import java.util.Map;
/**
* An abstract class for drag protocols on X11 systems.
* Contains protocol-independent drag source code.
*
* @since 1.5
*/
abstract class XDragSourceProtocol {
private final XDragSourceProtocolListener listener;
private boolean initialized = false;
private long targetWindow = 0;
private long targetProxyWindow = 0;
private int targetProtocolVersion = 0;
private long targetWindowMask = 0;
// Always use the XAWT root window as the drag source window.
static long getDragSourceWindow() {
return XWindow.getXAWTRootWindow().getWindow();
}
protected XDragSourceProtocol(XDragSourceProtocolListener listener) {
if (listener == null) {
throw new NullPointerException("Null XDragSourceProtocolListener");
}
this.listener = listener;
}
protected final XDragSourceProtocolListener getProtocolListener() {
return listener;
}
/**
* Returns the protocol name. The protocol name cannot be null.
*/
public abstract String getProtocolName();
/**
* Initalizes a drag operation with the specified supported drop actions,
* contents and data formats.
*
* @param actions a bitwise mask of <code>DnDConstants</code> that represent
* the supported drop actions.
* @param contents the contents for the drag operation.
* @param formats an array of Atoms that represent the supported data formats.
* @param formats an array of Atoms that represent the supported data formats.
* @throws InvalidDnDOperationException if a drag operation is already
* initialized.
* @throws IllegalArgumentException if some argument has invalid value.
* @throws XException if some X call failed.
*/
public final void initializeDrag(int actions, Transferable contents,
Map formatMap, long[] formats)
throws InvalidDnDOperationException,
IllegalArgumentException, XException {
XToolkit.awtLock();
try {
try {
if (initialized) {
throw new InvalidDnDOperationException("Already initialized");
}
initializeDragImpl(actions, contents, formatMap, formats);
initialized = true;
} finally {
if (!initialized) {
cleanup();
}
}
} finally {
XToolkit.awtUnlock();
}
}
/* The caller must hold AWT_LOCK. */
protected abstract void initializeDragImpl(int actions,
Transferable contents,
Map formatMap, long[] formats)
throws InvalidDnDOperationException, IllegalArgumentException, XException;
/**
* Terminates the current drag operation (if any) and resets the internal
* state of this object.
*
* @throws XException if some X call failed.
*/
public void cleanup() {
initialized = false;
cleanupTargetInfo();
}
/**
* Clears the information on the current drop target.
*
* @throws XException if some X call failed.
*/
public void cleanupTargetInfo() {
targetWindow = 0;
targetProxyWindow = 0;
targetProtocolVersion = 0;
}
/**
* Processes the specified client message event.
*
* @returns true if the event was successfully processed.
*/
public abstract boolean processClientMessage(XClientMessageEvent xclient)
throws XException;
/* The caller must hold AWT_LOCK. */
public final boolean attachTargetWindow(long window, long time) {
assert XToolkit.isAWTLockHeldByCurrentThread();
TargetWindowInfo info = getTargetWindowInfo(window);
if (info == null) {
return false;
} else {
targetWindow = window;
targetProxyWindow = info.getProxyWindow();
targetProtocolVersion = info.getProtocolVersion();
return true;
}
}
/* The caller must hold AWT_LOCK. */
public abstract TargetWindowInfo getTargetWindowInfo(long window);
/* The caller must hold AWT_LOCK. */
public abstract void sendEnterMessage(long[] formats, int sourceAction,
int sourceActions, long time);
/* The caller must hold AWT_LOCK. */
public abstract void sendMoveMessage(int xRoot, int yRoot,
int sourceAction, int sourceActions,
long time);
/* The caller must hold AWT_LOCK. */
public abstract void sendLeaveMessage(long time);
/* The caller must hold AWT_LOCK. */
protected abstract void sendDropMessage(int xRoot, int yRoot,
int sourceAction, int sourceActions,
long time);
public final void initiateDrop(int xRoot, int yRoot,
int sourceAction, int sourceActions,
long time) {
XWindowAttributes wattr = new XWindowAttributes();
try {
XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
targetWindow, wattr.pData);
XToolkit.RESTORE_XERROR_HANDLER();
if (status == 0 ||
(XToolkit.saved_error != null &&
XToolkit.saved_error.get_error_code() != XConstants.Success)) {
throw new XException("XGetWindowAttributes failed");
}
targetWindowMask = wattr.get_your_event_mask();
} finally {
wattr.dispose();
}
XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
XlibWrapper.XSelectInput(XToolkit.getDisplay(), targetWindow,
targetWindowMask |
XConstants.StructureNotifyMask);
XToolkit.RESTORE_XERROR_HANDLER();
if (XToolkit.saved_error != null &&
XToolkit.saved_error.get_error_code() != XConstants.Success) {
throw new XException("XSelectInput failed");
}
sendDropMessage(xRoot, yRoot, sourceAction, sourceActions, time);
}
protected final void finalizeDrop() {
XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
XlibWrapper.XSelectInput(XToolkit.getDisplay(), targetWindow,
targetWindowMask);
XToolkit.RESTORE_XERROR_HANDLER();
}
public abstract boolean processProxyModeEvent(XClientMessageEvent xclient,
long sourceWindow);
protected final long getTargetWindow() {
return targetWindow;
}
protected final long getTargetProxyWindow() {
if (targetProxyWindow != 0) {
return targetProxyWindow;
} else {
return targetWindow;
}
}
protected final int getTargetProtocolVersion() {
return targetProtocolVersion;
}
public static class TargetWindowInfo {
private final long proxyWindow;
private final int protocolVersion;
public TargetWindowInfo(long proxy, int version) {
proxyWindow = proxy;
protocolVersion = version;
}
public long getProxyWindow() {
return proxyWindow;
}
public int getProtocolVersion() {
return protocolVersion;
}
}
}