6538066: XSelection should be more passive
Now only XClipboard know about XSelection, and XSelection knows nothing about XClipboard. Reviewed-by: uta, denis
This commit is contained in:
parent
205971fd7c
commit
dc0d619ccb
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* 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
|
||||
@ -39,6 +39,8 @@ import sun.misc.Unsafe;
|
||||
* @since 1.5
|
||||
*/
|
||||
class MotifDnDConstants {
|
||||
// utility class can not be instantiated
|
||||
private MotifDnDConstants() {}
|
||||
// Note that offsets in all native structures below do not depend on the
|
||||
// architecture.
|
||||
private static final Unsafe unsafe = XlibWrapper.unsafe;
|
||||
@ -55,8 +57,7 @@ class MotifDnDConstants {
|
||||
XAtom.get("XmTRANSFER_SUCCESS");
|
||||
static final XAtom XA_XmTRANSFER_FAILURE =
|
||||
XAtom.get("XmTRANSFER_FAILURE");
|
||||
static final XSelection MotifDnDSelection =
|
||||
new XSelection(XA_MOTIF_ATOM_0, null);
|
||||
static final XSelection MotifDnDSelection = new XSelection(XA_MOTIF_ATOM_0);
|
||||
|
||||
public static final byte MOTIF_DND_PROTOCOL_VERSION = 0;
|
||||
|
||||
@ -231,6 +232,9 @@ class MotifDnDConstants {
|
||||
}
|
||||
|
||||
public static final class Swapper {
|
||||
// utility class can not be instantiated
|
||||
private Swapper() {}
|
||||
|
||||
public static short swap(short s) {
|
||||
return (short)(((s & 0xFF00) >>> 8) | ((s & 0xFF) << 8));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* 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
|
||||
@ -933,7 +933,7 @@ class MotifDnDDropTargetProtocol extends XDropTargetProtocol {
|
||||
|
||||
XSelection selection = XSelection.getSelection(selectionAtom);
|
||||
if (selection == null) {
|
||||
selection = new XSelection(selectionAtom, null);
|
||||
selection = new XSelection(selectionAtom);
|
||||
}
|
||||
|
||||
return selection.getData(format, time_stamp);
|
||||
@ -1056,7 +1056,7 @@ class MotifDnDDropTargetProtocol extends XDropTargetProtocol {
|
||||
// the original structure can be freed before this
|
||||
// SunDropTargetEvent is dispatched.
|
||||
if (xclient != null) {
|
||||
int size = new XClientMessageEvent(nativeCtxt).getSize();
|
||||
int size = XClientMessageEvent.getSize();
|
||||
|
||||
nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());
|
||||
|
||||
|
30
jdk/src/solaris/classes/sun/awt/X11/OwnershipListener.java
Normal file
30
jdk/src/solaris/classes/sun/awt/X11/OwnershipListener.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 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;
|
||||
|
||||
interface OwnershipListener {
|
||||
public void ownershipChanged(final boolean isOwner);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* 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
|
||||
@ -26,30 +26,32 @@
|
||||
package sun.awt.X11;
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
|
||||
import java.util.SortedMap;
|
||||
import java.util.Set;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashSet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.security.AccessController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import sun.awt.UNIXToolkit;
|
||||
import sun.awt.datatransfer.DataTransferer;
|
||||
import sun.awt.datatransfer.SunClipboard;
|
||||
import sun.awt.datatransfer.ClipboardTransferable;
|
||||
|
||||
import sun.security.action.GetIntegerAction;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A class which interfaces with the X11 selection service in order to support
|
||||
* data transfer via Clipboard operations.
|
||||
*/
|
||||
public class XClipboard extends SunClipboard implements Runnable {
|
||||
public final class XClipboard extends SunClipboard implements OwnershipListener
|
||||
{
|
||||
private final XSelection selection;
|
||||
// Time of calling XConvertSelection().
|
||||
private long convertSelectionTime;
|
||||
// The flag used not to call XConvertSelection() if the previous SelectionNotify
|
||||
// has not been processed by checkChange().
|
||||
private volatile boolean isSelectionNotifyProcessed;
|
||||
// The property in which the owner should place requested targets
|
||||
// when tracking changes of available data flavors (practically targets).
|
||||
private volatile XAtom targetsPropertyAtom;
|
||||
|
||||
private static final Object classLock = new Object();
|
||||
|
||||
@ -57,31 +59,33 @@ public class XClipboard extends SunClipboard implements Runnable {
|
||||
|
||||
private static int pollInterval;
|
||||
|
||||
private static Set listenedClipboards;
|
||||
|
||||
private static Map<Long, XClipboard> targetsAtom2Clipboard;
|
||||
|
||||
/**
|
||||
* Creates a system clipboard object.
|
||||
*/
|
||||
public XClipboard(String name, String selectionName) {
|
||||
super(name);
|
||||
selection = new XSelection(XAtom.get(selectionName), this);
|
||||
selection = new XSelection(XAtom.get(selectionName));
|
||||
selection.registerOwershipListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The action to be run when we lose ownership
|
||||
/*
|
||||
* NOTE: This method may be called by privileged threads.
|
||||
* DO NOT INVOKE CLIENT CODE ON THIS THREAD!
|
||||
*/
|
||||
public void run() {
|
||||
lostOwnershipImpl();
|
||||
public void ownershipChanged(final boolean isOwner) {
|
||||
if (isOwner) {
|
||||
checkChangeHere(contents);
|
||||
} else {
|
||||
lostOwnershipImpl();
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void setContentsNative(Transferable contents) {
|
||||
SortedMap formatMap = DataTransferer.getInstance().getFormatsForTransferable
|
||||
(contents, DataTransferer.adaptFlavorMap(flavorMap));
|
||||
long[] formats =
|
||||
DataTransferer.getInstance().keysToLongArray(formatMap);
|
||||
long[] formats = DataTransferer.keysToLongArray(formatMap);
|
||||
|
||||
if (!selection.setOwner(contents, formatMap, formats,
|
||||
XToolkit.getCurrentServerTime())) {
|
||||
@ -94,6 +98,7 @@ public class XClipboard extends SunClipboard implements Runnable {
|
||||
return selection.getSelectionAtom().getAtom();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Transferable getContents(Object requestor) {
|
||||
if (contents != null) {
|
||||
return contents;
|
||||
@ -115,62 +120,163 @@ public class XClipboard extends SunClipboard implements Runnable {
|
||||
return selection.getData(format, XToolkit.getCurrentServerTime());
|
||||
}
|
||||
|
||||
// Called on the toolkit thread under awtLock.
|
||||
public void checkChange(long[] formats) {
|
||||
if (!selection.isOwner()) {
|
||||
super.checkChange(formats);
|
||||
}
|
||||
}
|
||||
|
||||
void checkChangeHere(Transferable contents) {
|
||||
private void checkChangeHere(Transferable contents) {
|
||||
if (areFlavorListenersRegistered()) {
|
||||
super.checkChange(DataTransferer.getInstance().
|
||||
checkChange(DataTransferer.getInstance().
|
||||
getFormatsForTransferableAsArray(contents, flavorMap));
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerClipboardViewerChecked() {
|
||||
if (pollInterval <= 0) {
|
||||
pollInterval = ((Integer)AccessController.doPrivileged(
|
||||
new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
|
||||
defaultPollInterval))).intValue();
|
||||
private static int getPollInterval() {
|
||||
synchronized (XClipboard.classLock) {
|
||||
if (pollInterval <= 0) {
|
||||
pollInterval = defaultPollInterval;
|
||||
pollInterval = AccessController.doPrivileged(
|
||||
new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
|
||||
defaultPollInterval));
|
||||
if (pollInterval <= 0) {
|
||||
pollInterval = defaultPollInterval;
|
||||
}
|
||||
}
|
||||
return pollInterval;
|
||||
}
|
||||
selection.initializeSelectionForTrackingChanges();
|
||||
}
|
||||
|
||||
private XAtom getTargetsPropertyAtom() {
|
||||
if (null == targetsPropertyAtom) {
|
||||
targetsPropertyAtom =
|
||||
XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selection.getSelectionAtom().getName());
|
||||
}
|
||||
return targetsPropertyAtom;
|
||||
}
|
||||
|
||||
protected void registerClipboardViewerChecked() {
|
||||
// for XConvertSelection() to be called for the first time in getTargetsDelayed()
|
||||
isSelectionNotifyProcessed = true;
|
||||
|
||||
boolean mustSchedule = false;
|
||||
synchronized (XClipboard.classLock) {
|
||||
if (listenedClipboards == null) {
|
||||
listenedClipboards = new HashSet(2);
|
||||
if (targetsAtom2Clipboard == null) {
|
||||
targetsAtom2Clipboard = new HashMap<Long, XClipboard>(2);
|
||||
}
|
||||
mustSchedule = targetsAtom2Clipboard.isEmpty();
|
||||
targetsAtom2Clipboard.put(getTargetsPropertyAtom().getAtom(), this);
|
||||
if (mustSchedule) {
|
||||
XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(),
|
||||
new SelectionNotifyHandler());
|
||||
}
|
||||
mustSchedule = listenedClipboards.isEmpty();
|
||||
listenedClipboards.add(this);
|
||||
}
|
||||
if (mustSchedule) {
|
||||
XToolkit.schedule(new CheckChangeTimerTask(), pollInterval);
|
||||
XToolkit.schedule(new CheckChangeTimerTask(), XClipboard.getPollInterval());
|
||||
}
|
||||
}
|
||||
|
||||
private static class CheckChangeTimerTask implements Runnable {
|
||||
public void run() {
|
||||
for (Iterator iter = listenedClipboards.iterator(); iter.hasNext();) {
|
||||
XClipboard clpbrd = (XClipboard)iter.next();
|
||||
clpbrd.selection.getTargetsDelayed();
|
||||
for (XClipboard clpbrd : targetsAtom2Clipboard.values()) {
|
||||
clpbrd.getTargetsDelayed();
|
||||
}
|
||||
synchronized (XClipboard.classLock) {
|
||||
if (listenedClipboards != null && !listenedClipboards.isEmpty()) {
|
||||
XToolkit.schedule(this, pollInterval);
|
||||
if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) {
|
||||
XToolkit.schedule(this, XClipboard.getPollInterval());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SelectionNotifyHandler implements XEventDispatcher {
|
||||
public void dispatchEvent(XEvent ev) {
|
||||
if (ev.get_type() == XlibWrapper.SelectionNotify) {
|
||||
final XSelectionEvent xse = ev.get_xselection();
|
||||
XClipboard clipboard = null;
|
||||
synchronized (XClipboard.classLock) {
|
||||
if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) {
|
||||
XToolkit.removeEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this);
|
||||
return;
|
||||
}
|
||||
final long propertyAtom = xse.get_property();
|
||||
clipboard = targetsAtom2Clipboard.get(propertyAtom);
|
||||
}
|
||||
if (null != clipboard) {
|
||||
clipboard.checkChange(xse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void unregisterClipboardViewerChecked() {
|
||||
selection.deinitializeSelectionForTrackingChanges();
|
||||
isSelectionNotifyProcessed = false;
|
||||
synchronized (XClipboard.classLock) {
|
||||
listenedClipboards.remove(this);
|
||||
targetsAtom2Clipboard.remove(getTargetsPropertyAtom().getAtom());
|
||||
}
|
||||
}
|
||||
|
||||
// checkChange() will be called on SelectionNotify
|
||||
private void getTargetsDelayed() {
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (isSelectionNotifyProcessed || curTime >= (convertSelectionTime + UNIXToolkit.getDatatransferTimeout()))
|
||||
{
|
||||
convertSelectionTime = curTime;
|
||||
XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
|
||||
selection.getSelectionAtom().getAtom(),
|
||||
XDataTransferer.TARGETS_ATOM.getAtom(),
|
||||
getTargetsPropertyAtom().getAtom(),
|
||||
XWindow.getXAWTRootWindow().getWindow(),
|
||||
XlibWrapper.CurrentTime);
|
||||
isSelectionNotifyProcessed = false;
|
||||
}
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tracks changes of available formats.
|
||||
* NOTE: This method may be called by privileged threads.
|
||||
* DO NOT INVOKE CLIENT CODE ON THIS THREAD!
|
||||
*/
|
||||
private void checkChange(XSelectionEvent xse) {
|
||||
final long propertyAtom = xse.get_property();
|
||||
if (propertyAtom != getTargetsPropertyAtom().getAtom()) {
|
||||
// wrong atom
|
||||
return;
|
||||
}
|
||||
|
||||
final XAtom selectionAtom = XAtom.get(xse.get_selection());
|
||||
final XSelection changedSelection = XSelection.getSelection(selectionAtom);
|
||||
|
||||
if (null == changedSelection || changedSelection != selection) {
|
||||
// unknown selection - do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
isSelectionNotifyProcessed = true;
|
||||
|
||||
if (selection.isOwner()) {
|
||||
// selection is owner - do not need formats
|
||||
return;
|
||||
}
|
||||
|
||||
long[] formats = null;
|
||||
|
||||
if (propertyAtom == XlibWrapper.None) {
|
||||
// We treat None property atom as "empty selection".
|
||||
formats = new long[0];
|
||||
} else {
|
||||
WindowPropertyGetter targetsGetter =
|
||||
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
|
||||
XAtom.get(propertyAtom), 0,
|
||||
XSelection.MAX_LENGTH, true,
|
||||
XlibWrapper.AnyPropertyType);
|
||||
try {
|
||||
targetsGetter.execute();
|
||||
formats = XSelection.getFormats(targetsGetter);
|
||||
} finally {
|
||||
targetsGetter.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
checkChange(formats);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* 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
|
||||
@ -48,8 +48,7 @@ class XDnDConstants {
|
||||
static final XAtom XA_XdndStatus = XAtom.get("XdndStatus");
|
||||
static final XAtom XA_XdndFinished = XAtom.get("XdndFinished");
|
||||
|
||||
static final XSelection XDnDSelection =
|
||||
new XSelection(XA_XdndSelection, null);
|
||||
static final XSelection XDnDSelection = new XSelection(XA_XdndSelection);
|
||||
|
||||
public static final int XDND_MIN_PROTOCOL_VERSION = 3;
|
||||
public static final int XDND_PROTOCOL_VERSION = 5;
|
||||
|
@ -32,9 +32,6 @@ import java.io.IOException;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
import sun.awt.SunToolkit;
|
||||
@ -45,7 +42,7 @@ import sun.awt.datatransfer.DataTransferer;
|
||||
/**
|
||||
* A class which interfaces with the X11 selection service.
|
||||
*/
|
||||
public class XSelection {
|
||||
public final class XSelection {
|
||||
|
||||
/* Maps atoms to XSelection instances. */
|
||||
private static final Hashtable<XAtom, XSelection> table = new Hashtable<XAtom, XSelection>();
|
||||
@ -69,8 +66,6 @@ public class XSelection {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
}
|
||||
/* The selection timeout. */
|
||||
private static long SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout();
|
||||
|
||||
/* The PropertyNotify event handler for incremental data transfer. */
|
||||
private static final XEventDispatcher incrementalTransferHandler =
|
||||
@ -84,11 +79,6 @@ public class XSelection {
|
||||
|
||||
/* The X atom for the underlying selection. */
|
||||
private final XAtom selectionAtom;
|
||||
/*
|
||||
* XClipboard.run() is to be called when we lose ownership.
|
||||
* XClipbioard.checkChange() is to be called when tracking changes of flavors.
|
||||
*/
|
||||
private final XClipboard clipboard;
|
||||
|
||||
/*
|
||||
* Owner-related variables - protected with synchronized (this).
|
||||
@ -109,17 +99,8 @@ public class XSelection {
|
||||
private long ownershipTime = 0;
|
||||
// True if we are the owner of this selection.
|
||||
private boolean isOwner;
|
||||
// The property in which the owner should place requested targets
|
||||
// when tracking changes of available data flavors (practically targets).
|
||||
private volatile XAtom targetsPropertyAtom;
|
||||
// A set of these property atoms.
|
||||
private static volatile Set targetsPropertyAtoms;
|
||||
// The flag used not to call XConvertSelection() if the previous SelectionNotify
|
||||
// has not been processed by checkChange().
|
||||
private volatile boolean isSelectionNotifyProcessed;
|
||||
// Time of calling XConvertSelection().
|
||||
private long convertSelectionTime;
|
||||
|
||||
private OwnershipListener ownershipListener = null;
|
||||
private final Object stateLock = new Object();
|
||||
|
||||
static {
|
||||
XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(),
|
||||
@ -141,12 +122,11 @@ public class XSelection {
|
||||
* @param clpbrd the corresponding clipoboard
|
||||
* @exception NullPointerException if atom is <code>null</code>.
|
||||
*/
|
||||
public XSelection(XAtom atom, XClipboard clpbrd) {
|
||||
public XSelection(XAtom atom) {
|
||||
if (atom == null) {
|
||||
throw new NullPointerException("Null atom");
|
||||
}
|
||||
selectionAtom = atom;
|
||||
clipboard = clpbrd;
|
||||
table.put(selectionAtom, this);
|
||||
}
|
||||
|
||||
@ -154,25 +134,9 @@ public class XSelection {
|
||||
return selectionAtom;
|
||||
}
|
||||
|
||||
void initializeSelectionForTrackingChanges() {
|
||||
targetsPropertyAtom = XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selectionAtom.getName());
|
||||
if (targetsPropertyAtoms == null) {
|
||||
targetsPropertyAtoms = Collections.synchronizedSet(new HashSet(2));
|
||||
}
|
||||
targetsPropertyAtoms.add(Long.valueOf(targetsPropertyAtom.getAtom()));
|
||||
// for XConvertSelection() to be called for the first time in getTargetsDelayed()
|
||||
isSelectionNotifyProcessed = true;
|
||||
}
|
||||
|
||||
void deinitializeSelectionForTrackingChanges() {
|
||||
if (targetsPropertyAtoms != null && targetsPropertyAtom != null) {
|
||||
targetsPropertyAtoms.remove(Long.valueOf(targetsPropertyAtom.getAtom()));
|
||||
}
|
||||
isSelectionNotifyProcessed = false;
|
||||
}
|
||||
|
||||
public synchronized boolean setOwner(Transferable contents, Map formatMap,
|
||||
long[] formats, long time) {
|
||||
long[] formats, long time)
|
||||
{
|
||||
long owner = XWindow.getXAWTRootWindow().getWindow();
|
||||
long selection = selectionAtom.getAtom();
|
||||
|
||||
@ -192,15 +156,12 @@ public class XSelection {
|
||||
XlibWrapper.XSetSelectionOwner(XToolkit.getDisplay(),
|
||||
selection, owner, time);
|
||||
if (XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(),
|
||||
selection) != owner) {
|
||||
|
||||
selection) != owner)
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
isOwner = true;
|
||||
if (clipboard != null) {
|
||||
clipboard.checkChangeHere(contents);
|
||||
}
|
||||
setOwnerProp(true);
|
||||
return true;
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
@ -217,7 +178,7 @@ public class XSelection {
|
||||
do {
|
||||
DataTransferer.getInstance().processDataConversionRequests();
|
||||
XToolkit.awtLockWait(250);
|
||||
} while (propertyGetter == dataGetter && System.currentTimeMillis() < startTime + SELECTION_TIMEOUT);
|
||||
} while (propertyGetter == dataGetter && System.currentTimeMillis() < startTime + UNIXToolkit.getDatatransferTimeout());
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
@ -232,11 +193,9 @@ public class XSelection {
|
||||
throw new Error("UNIMPLEMENTED");
|
||||
}
|
||||
|
||||
long[] formats = null;
|
||||
long[] targets = null;
|
||||
|
||||
synchronized (lock) {
|
||||
SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout();
|
||||
|
||||
WindowPropertyGetter targetsGetter =
|
||||
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
|
||||
selectionPropertyAtom, 0, MAX_LENGTH,
|
||||
@ -267,15 +226,15 @@ public class XSelection {
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
formats = getFormats(targetsGetter);
|
||||
targets = getFormats(targetsGetter);
|
||||
} finally {
|
||||
targetsGetter.dispose();
|
||||
}
|
||||
}
|
||||
return formats;
|
||||
return targets;
|
||||
}
|
||||
|
||||
private static long[] getFormats(WindowPropertyGetter targetsGetter) {
|
||||
static long[] getFormats(WindowPropertyGetter targetsGetter) {
|
||||
long[] formats = null;
|
||||
|
||||
if (targetsGetter.isExecuted() && !targetsGetter.isDisposed() &&
|
||||
@ -285,7 +244,7 @@ public class XSelection {
|
||||
{
|
||||
// we accept property with TARGETS type to be compatible with old jdks
|
||||
// see 6607163
|
||||
int count = (int)targetsGetter.getNumberOfItems();
|
||||
int count = targetsGetter.getNumberOfItems();
|
||||
if (count > 0) {
|
||||
long atoms = targetsGetter.getData();
|
||||
formats = new long[count];
|
||||
@ -299,26 +258,6 @@ public class XSelection {
|
||||
return formats != null ? formats : new long[0];
|
||||
}
|
||||
|
||||
// checkChange() will be called on SelectionNotify
|
||||
void getTargetsDelayed() {
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (isSelectionNotifyProcessed || curTime >= convertSelectionTime + SELECTION_TIMEOUT) {
|
||||
convertSelectionTime = curTime;
|
||||
XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
|
||||
getSelectionAtom().getAtom(),
|
||||
XDataTransferer.TARGETS_ATOM.getAtom(),
|
||||
targetsPropertyAtom.getAtom(),
|
||||
XWindow.getXAWTRootWindow().getWindow(),
|
||||
XlibWrapper.CurrentTime);
|
||||
isSelectionNotifyProcessed = false;
|
||||
}
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Requests the selection data in the specified format and returns
|
||||
* the data provided by the owner.
|
||||
@ -331,8 +270,6 @@ public class XSelection {
|
||||
byte[] data = null;
|
||||
|
||||
synchronized (lock) {
|
||||
SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout();
|
||||
|
||||
WindowPropertyGetter dataGetter =
|
||||
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
|
||||
selectionPropertyAtom, 0, MAX_LENGTH,
|
||||
@ -381,7 +318,7 @@ public class XSelection {
|
||||
dataGetter.getActualFormat());
|
||||
}
|
||||
|
||||
int count = (int)dataGetter.getNumberOfItems();
|
||||
int count = dataGetter.getNumberOfItems();
|
||||
|
||||
if (count <= 0) {
|
||||
throw new IOException("INCR data is missed.");
|
||||
@ -457,7 +394,7 @@ public class XSelection {
|
||||
incrDataGetter.getActualFormat());
|
||||
}
|
||||
|
||||
count = (int)incrDataGetter.getNumberOfItems();
|
||||
count = incrDataGetter.getNumberOfItems();
|
||||
|
||||
if (count == 0) {
|
||||
break;
|
||||
@ -491,7 +428,7 @@ public class XSelection {
|
||||
dataGetter.getActualFormat());
|
||||
}
|
||||
|
||||
int count = (int)dataGetter.getNumberOfItems();
|
||||
int count = dataGetter.getNumberOfItems();
|
||||
if (count > 0) {
|
||||
data = new byte[count];
|
||||
long ptr = dataGetter.getData();
|
||||
@ -513,11 +450,14 @@ public class XSelection {
|
||||
return isOwner;
|
||||
}
|
||||
|
||||
public void lostOwnership() {
|
||||
isOwner = false;
|
||||
if (clipboard != null) {
|
||||
clipboard.run();
|
||||
}
|
||||
// To be MT-safe this method should be called under awtLock.
|
||||
private void setOwnerProp(boolean f) {
|
||||
isOwner = f;
|
||||
fireOwnershipChanges(isOwner);
|
||||
}
|
||||
|
||||
private void lostOwnership() {
|
||||
setOwnerProp(false);
|
||||
}
|
||||
|
||||
public synchronized void reset() {
|
||||
@ -597,125 +537,39 @@ public class XSelection {
|
||||
|
||||
private void handleSelectionRequest(XSelectionRequestEvent xsre) {
|
||||
long property = xsre.get_property();
|
||||
long requestor = xsre.get_requestor();
|
||||
long requestTime = xsre.get_time();
|
||||
long format = xsre.get_target();
|
||||
int dataFormat = 0;
|
||||
final long requestor = xsre.get_requestor();
|
||||
final long requestTime = xsre.get_time();
|
||||
final long format = xsre.get_target();
|
||||
boolean conversionSucceeded = false;
|
||||
|
||||
if (ownershipTime != 0 &&
|
||||
(requestTime == XlibWrapper.CurrentTime ||
|
||||
requestTime >= ownershipTime)) {
|
||||
|
||||
property = xsre.get_property();
|
||||
|
||||
(requestTime == XlibWrapper.CurrentTime || requestTime >= ownershipTime))
|
||||
{
|
||||
// Handle MULTIPLE requests as per ICCCM.
|
||||
if (format == XDataTransferer.MULTIPLE_ATOM.getAtom()) {
|
||||
// The property cannot be 0 for a MULTIPLE request.
|
||||
if (property != 0) {
|
||||
// First retrieve the list of requested targets.
|
||||
WindowPropertyGetter wpg =
|
||||
new WindowPropertyGetter(requestor, XAtom.get(property), 0,
|
||||
MAX_LENGTH, false,
|
||||
XlibWrapper.AnyPropertyType);
|
||||
try {
|
||||
wpg.execute();
|
||||
|
||||
if (wpg.getActualFormat() == 32 &&
|
||||
(wpg.getNumberOfItems() % 2) == 0) {
|
||||
long count = wpg.getNumberOfItems() / 2;
|
||||
long pairsPtr = wpg.getData();
|
||||
boolean writeBack = false;
|
||||
for (int i = 0; i < count; i++) {
|
||||
long target = Native.getLong(pairsPtr, 2*i);
|
||||
long prop = Native.getLong(pairsPtr, 2*i + 1);
|
||||
|
||||
if (!convertAndStore(requestor, target, prop)) {
|
||||
// To report failure, we should replace the
|
||||
// target atom with 0 in the MULTIPLE property.
|
||||
Native.putLong(pairsPtr, 2*i, 0);
|
||||
writeBack = true;
|
||||
}
|
||||
}
|
||||
if (writeBack) {
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
XlibWrapper.XChangeProperty(XToolkit.getDisplay(), requestor,
|
||||
property,
|
||||
wpg.getActualType(),
|
||||
wpg.getActualFormat(),
|
||||
XlibWrapper.PropModeReplace,
|
||||
wpg.getData(),
|
||||
wpg.getNumberOfItems());
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
}
|
||||
conversionSucceeded = true;
|
||||
}
|
||||
} finally {
|
||||
wpg.dispose();
|
||||
}
|
||||
}
|
||||
conversionSucceeded = handleMultipleRequest(requestor, property);
|
||||
} else {
|
||||
|
||||
// Support for obsolete clients as per ICCCM.
|
||||
if (property == 0) {
|
||||
if (property == XlibWrapper.None) {
|
||||
property = format;
|
||||
}
|
||||
|
||||
if (format == XDataTransferer.TARGETS_ATOM.getAtom()) {
|
||||
long nativeDataPtr = 0;
|
||||
int count = 0;
|
||||
dataFormat = 32;
|
||||
|
||||
// Use a local copy to avoid synchronization.
|
||||
long[] formatsLocal = formats;
|
||||
|
||||
if (formatsLocal == null) {
|
||||
throw new IllegalStateException("Not an owner.");
|
||||
}
|
||||
|
||||
count = formatsLocal.length;
|
||||
|
||||
try {
|
||||
if (count > 0) {
|
||||
nativeDataPtr = Native.allocateLongArray(count);
|
||||
Native.put(nativeDataPtr, formatsLocal);
|
||||
}
|
||||
|
||||
conversionSucceeded = true;
|
||||
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
XlibWrapper.XChangeProperty(XToolkit.getDisplay(), requestor,
|
||||
property, XAtom.XA_ATOM, dataFormat,
|
||||
XlibWrapper.PropModeReplace,
|
||||
nativeDataPtr, count);
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
} finally {
|
||||
if (nativeDataPtr != 0) {
|
||||
XlibWrapper.unsafe.freeMemory(nativeDataPtr);
|
||||
nativeDataPtr = 0;
|
||||
}
|
||||
}
|
||||
conversionSucceeded = handleTargetsRequest(property, requestor);
|
||||
} else {
|
||||
conversionSucceeded = convertAndStore(requestor, format,
|
||||
property);
|
||||
conversionSucceeded = convertAndStore(requestor, format, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!conversionSucceeded) {
|
||||
// Zero property indicates conversion failure.
|
||||
property = 0;
|
||||
// None property indicates conversion failure.
|
||||
property = XlibWrapper.None;
|
||||
}
|
||||
|
||||
XSelectionEvent xse = new XSelectionEvent();
|
||||
try {
|
||||
xse.set_type((int)XlibWrapper.SelectionNotify);
|
||||
xse.set_type(XlibWrapper.SelectionNotify);
|
||||
xse.set_send_event(true);
|
||||
xse.set_requestor(requestor);
|
||||
xse.set_selection(selectionAtom.getAtom());
|
||||
@ -735,40 +589,123 @@ public class XSelection {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkChange(XSelectionEvent xse) {
|
||||
if (targetsPropertyAtoms == null || targetsPropertyAtoms.isEmpty()) {
|
||||
// We are not tracking changes.
|
||||
return;
|
||||
private boolean handleMultipleRequest(final long requestor, long property) {
|
||||
if (XlibWrapper.None == property) {
|
||||
// The property cannot be None for a MULTIPLE request.
|
||||
return false;
|
||||
}
|
||||
|
||||
long propertyAtom = xse.get_property();
|
||||
long[] formats = null;
|
||||
boolean conversionSucceeded = false;
|
||||
|
||||
if (propertyAtom == XlibWrapper.None) {
|
||||
// We threat None property atom as "empty selection".
|
||||
formats = new long[0];
|
||||
} else if (!targetsPropertyAtoms.contains(Long.valueOf(propertyAtom))) {
|
||||
return;
|
||||
} else {
|
||||
WindowPropertyGetter targetsGetter =
|
||||
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
|
||||
XAtom.get(propertyAtom), 0, MAX_LENGTH,
|
||||
true, XlibWrapper.AnyPropertyType);
|
||||
// First retrieve the list of requested targets.
|
||||
WindowPropertyGetter wpg =
|
||||
new WindowPropertyGetter(requestor, XAtom.get(property),
|
||||
0, MAX_LENGTH, false,
|
||||
XlibWrapper.AnyPropertyType);
|
||||
try {
|
||||
wpg.execute();
|
||||
|
||||
if (wpg.getActualFormat() == 32 && (wpg.getNumberOfItems() % 2) == 0) {
|
||||
final long count = wpg.getNumberOfItems() / 2;
|
||||
final long pairsPtr = wpg.getData();
|
||||
boolean writeBack = false;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
long target = Native.getLong(pairsPtr, 2 * i);
|
||||
long prop = Native.getLong(pairsPtr, 2 * i + 1);
|
||||
|
||||
if (!convertAndStore(requestor, target, prop)) {
|
||||
// To report failure, we should replace the
|
||||
// target atom with 0 in the MULTIPLE property.
|
||||
Native.putLong(pairsPtr, 2 * i, 0);
|
||||
writeBack = true;
|
||||
}
|
||||
}
|
||||
if (writeBack) {
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
|
||||
requestor,
|
||||
property,
|
||||
wpg.getActualType(),
|
||||
wpg.getActualFormat(),
|
||||
XlibWrapper.PropModeReplace,
|
||||
wpg.getData(),
|
||||
wpg.getNumberOfItems());
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
}
|
||||
conversionSucceeded = true;
|
||||
}
|
||||
} finally {
|
||||
wpg.dispose();
|
||||
}
|
||||
|
||||
return conversionSucceeded;
|
||||
}
|
||||
|
||||
private boolean handleTargetsRequest(long property, long requestor)
|
||||
throws IllegalStateException
|
||||
{
|
||||
boolean conversionSucceeded = false;
|
||||
// Use a local copy to avoid synchronization.
|
||||
long[] formatsLocal = formats;
|
||||
|
||||
if (formatsLocal == null) {
|
||||
throw new IllegalStateException("Not an owner.");
|
||||
}
|
||||
|
||||
long nativeDataPtr = 0;
|
||||
|
||||
try {
|
||||
final int count = formatsLocal.length;
|
||||
final int dataFormat = 32;
|
||||
|
||||
if (count > 0) {
|
||||
nativeDataPtr = Native.allocateLongArray(count);
|
||||
Native.put(nativeDataPtr, formatsLocal);
|
||||
}
|
||||
|
||||
conversionSucceeded = true;
|
||||
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
targetsGetter.execute();
|
||||
formats = getFormats(targetsGetter);
|
||||
XlibWrapper.XChangeProperty(XToolkit.getDisplay(), requestor,
|
||||
property, XAtom.XA_ATOM, dataFormat,
|
||||
XlibWrapper.PropModeReplace,
|
||||
nativeDataPtr, count);
|
||||
} finally {
|
||||
targetsGetter.dispose();
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
} finally {
|
||||
if (nativeDataPtr != 0) {
|
||||
XlibWrapper.unsafe.freeMemory(nativeDataPtr);
|
||||
nativeDataPtr = 0;
|
||||
}
|
||||
}
|
||||
return conversionSucceeded;
|
||||
}
|
||||
|
||||
XAtom selectionAtom = XAtom.get(xse.get_selection());
|
||||
XSelection selection = getSelection(selectionAtom);
|
||||
if (selection != null) {
|
||||
selection.isSelectionNotifyProcessed = true;
|
||||
if (selection.clipboard != null) {
|
||||
selection.clipboard.checkChange(formats);
|
||||
}
|
||||
private void fireOwnershipChanges(final boolean isOwner) {
|
||||
OwnershipListener l = null;
|
||||
synchronized (stateLock) {
|
||||
l = ownershipListener;
|
||||
}
|
||||
if (null != l) {
|
||||
l.ownershipChanged(isOwner);
|
||||
}
|
||||
}
|
||||
|
||||
void registerOwershipListener(OwnershipListener l) {
|
||||
synchronized (stateLock) {
|
||||
ownershipListener = l;
|
||||
}
|
||||
}
|
||||
|
||||
void unregisterOwnershipListener() {
|
||||
synchronized (stateLock) {
|
||||
ownershipListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -776,10 +713,9 @@ public class XSelection {
|
||||
public void dispatchEvent(XEvent ev) {
|
||||
switch (ev.get_type()) {
|
||||
case XlibWrapper.SelectionNotify: {
|
||||
XSelectionEvent xse = ev.get_xselection();
|
||||
checkChange(xse);
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
XSelectionEvent xse = ev.get_xselection();
|
||||
// Ignore the SelectionNotify event if it is not the response to our last request.
|
||||
if (propertyGetter != null && xse.get_time() == lastRequestServerTime) {
|
||||
// The property will be None in case of convertion failure.
|
||||
|
Loading…
x
Reference in New Issue
Block a user