6538066: XSelection should be more passive
Summary: Now only XClipboard know about XSelection, and XSelection knows nothing about XClipboard.
Reviewed-by: uta, denis
--- a/jdk/src/solaris/classes/sun/awt/X11/MotifDnDConstants.java Thu Mar 13 17:08:15 2008 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/MotifDnDConstants.java Thu Mar 13 17:14:44 2008 +0300
@@ -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 @@
* @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 @@
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 @@
}
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));
}
--- a/jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java Thu Mar 13 17:08:15 2008 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java Thu Mar 13 17:14:44 2008 +0300
@@ -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 @@
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 @@
// 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());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/awt/X11/OwnershipListener.java Thu Mar 13 17:14:44 2008 +0300
@@ -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);
+}
--- a/jdk/src/solaris/classes/sun/awt/X11/XClipboard.java Thu Mar 13 17:08:15 2008 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XClipboard.java Thu Mar 13 17:14:44 2008 +0300
@@ -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 @@
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 @@
return selection.getSelectionAtom().getAtom();
}
+ @Override
public synchronized Transferable getContents(Object requestor) {
if (contents != null) {
return contents;
@@ -115,62 +120,163 @@
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));
}
}
+ private static int getPollInterval() {
+ synchronized (XClipboard.classLock) {
+ if (pollInterval <= 0) {
+ pollInterval = AccessController.doPrivileged(
+ new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
+ defaultPollInterval));
+ if (pollInterval <= 0) {
+ pollInterval = defaultPollInterval;
+ }
+ }
+ return pollInterval;
+ }
+ }
+
+ private XAtom getTargetsPropertyAtom() {
+ if (null == targetsPropertyAtom) {
+ targetsPropertyAtom =
+ XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selection.getSelectionAtom().getName());
+ }
+ return targetsPropertyAtom;
+ }
+
protected void registerClipboardViewerChecked() {
- if (pollInterval <= 0) {
- pollInterval = ((Integer)AccessController.doPrivileged(
- new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
- defaultPollInterval))).intValue();
- if (pollInterval <= 0) {
- pollInterval = defaultPollInterval;
+ // for XConvertSelection() to be called for the first time in getTargetsDelayed()
+ isSelectionNotifyProcessed = true;
+
+ boolean mustSchedule = false;
+ synchronized (XClipboard.classLock) {
+ 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());
}
}
- selection.initializeSelectionForTrackingChanges();
- boolean mustSchedule = false;
- synchronized (XClipboard.classLock) {
- if (listenedClipboards == null) {
- listenedClipboards = new HashSet(2);
- }
- 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);
+ }
}
--- a/jdk/src/solaris/classes/sun/awt/X11/XDnDConstants.java Thu Mar 13 17:08:15 2008 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDnDConstants.java Thu Mar 13 17:14:44 2008 +0300
@@ -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 @@
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;
--- a/jdk/src/solaris/classes/sun/awt/X11/XSelection.java Thu Mar 13 17:08:15 2008 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XSelection.java Thu Mar 13 17:14:44 2008 +0300
@@ -32,9 +32,6 @@
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 @@
/**
* 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 @@
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 @@
/* 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 @@
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 @@
* @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 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
{
// 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 @@
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 @@
byte[] data = null;
synchronized (lock) {
- SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout();
-
WindowPropertyGetter dataGetter =
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
selectionPropertyAtom, 0, MAX_LENGTH,
@@ -381,7 +318,7 @@
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 @@
incrDataGetter.getActualFormat());
}
- count = (int)incrDataGetter.getNumberOfItems();
+ count = incrDataGetter.getNumberOfItems();
if (count == 0) {
break;
@@ -491,7 +428,7 @@
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 @@
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 @@
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 @@
}
}
- 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;
+ }
+
+ boolean conversionSucceeded = false;
+
+ // 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();
}
- long propertyAtom = xse.get_property();
- long[] formats = null;
+ 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 (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);
+ 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 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.