提交 6aa2288b 编写于 作者: S son

6538066: XSelection should be more passive

Summary: Now only XClipboard know about XSelection, and XSelection knows nothing about XClipboard.
Reviewed-by: uta, denis
上级 7b0264f6
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -39,6 +39,8 @@ import sun.misc.Unsafe; ...@@ -39,6 +39,8 @@ import sun.misc.Unsafe;
* @since 1.5 * @since 1.5
*/ */
class MotifDnDConstants { class MotifDnDConstants {
// utility class can not be instantiated
private MotifDnDConstants() {}
// Note that offsets in all native structures below do not depend on the // Note that offsets in all native structures below do not depend on the
// architecture. // architecture.
private static final Unsafe unsafe = XlibWrapper.unsafe; private static final Unsafe unsafe = XlibWrapper.unsafe;
...@@ -55,8 +57,7 @@ class MotifDnDConstants { ...@@ -55,8 +57,7 @@ class MotifDnDConstants {
XAtom.get("XmTRANSFER_SUCCESS"); XAtom.get("XmTRANSFER_SUCCESS");
static final XAtom XA_XmTRANSFER_FAILURE = static final XAtom XA_XmTRANSFER_FAILURE =
XAtom.get("XmTRANSFER_FAILURE"); XAtom.get("XmTRANSFER_FAILURE");
static final XSelection MotifDnDSelection = static final XSelection MotifDnDSelection = new XSelection(XA_MOTIF_ATOM_0);
new XSelection(XA_MOTIF_ATOM_0, null);
public static final byte MOTIF_DND_PROTOCOL_VERSION = 0; public static final byte MOTIF_DND_PROTOCOL_VERSION = 0;
...@@ -231,6 +232,9 @@ class MotifDnDConstants { ...@@ -231,6 +232,9 @@ class MotifDnDConstants {
} }
public static final class Swapper { public static final class Swapper {
// utility class can not be instantiated
private Swapper() {}
public static short swap(short s) { public static short swap(short s) {
return (short)(((s & 0xFF00) >>> 8) | ((s & 0xFF) << 8)); return (short)(((s & 0xFF00) >>> 8) | ((s & 0xFF) << 8));
} }
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -933,7 +933,7 @@ class MotifDnDDropTargetProtocol extends XDropTargetProtocol { ...@@ -933,7 +933,7 @@ class MotifDnDDropTargetProtocol extends XDropTargetProtocol {
XSelection selection = XSelection.getSelection(selectionAtom); XSelection selection = XSelection.getSelection(selectionAtom);
if (selection == null) { if (selection == null) {
selection = new XSelection(selectionAtom, null); selection = new XSelection(selectionAtom);
} }
return selection.getData(format, time_stamp); return selection.getData(format, time_stamp);
...@@ -1056,7 +1056,7 @@ class MotifDnDDropTargetProtocol extends XDropTargetProtocol { ...@@ -1056,7 +1056,7 @@ class MotifDnDDropTargetProtocol extends XDropTargetProtocol {
// the original structure can be freed before this // the original structure can be freed before this
// SunDropTargetEvent is dispatched. // SunDropTargetEvent is dispatched.
if (xclient != null) { if (xclient != null) {
int size = new XClientMessageEvent(nativeCtxt).getSize(); int size = XClientMessageEvent.getSize();
nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize()); nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());
......
/*
* 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);
}
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -26,30 +26,32 @@ ...@@ -26,30 +26,32 @@
package sun.awt.X11; package sun.awt.X11;
import java.awt.datatransfer.Transferable; import java.awt.datatransfer.Transferable;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.Set;
import java.util.Iterator;
import java.util.HashSet;
import java.io.IOException; import java.io.IOException;
import java.security.AccessController; 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.DataTransferer;
import sun.awt.datatransfer.SunClipboard; import sun.awt.datatransfer.SunClipboard;
import sun.awt.datatransfer.ClipboardTransferable; import sun.awt.datatransfer.ClipboardTransferable;
import sun.security.action.GetIntegerAction; import sun.security.action.GetIntegerAction;
/** /**
* A class which interfaces with the X11 selection service in order to support * A class which interfaces with the X11 selection service in order to support
* data transfer via Clipboard operations. * data transfer via Clipboard operations.
*/ */
public class XClipboard extends SunClipboard implements Runnable { public final class XClipboard extends SunClipboard implements OwnershipListener
{
private final XSelection selection; 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(); private static final Object classLock = new Object();
...@@ -57,31 +59,33 @@ public class XClipboard extends SunClipboard implements Runnable { ...@@ -57,31 +59,33 @@ public class XClipboard extends SunClipboard implements Runnable {
private static int pollInterval; private static int pollInterval;
private static Set listenedClipboards; private static Map<Long, XClipboard> targetsAtom2Clipboard;
/** /**
* Creates a system clipboard object. * Creates a system clipboard object.
*/ */
public XClipboard(String name, String selectionName) { public XClipboard(String name, String selectionName) {
super(name); 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. * NOTE: This method may be called by privileged threads.
* DO NOT INVOKE CLIENT CODE ON THIS THREAD! * DO NOT INVOKE CLIENT CODE ON THIS THREAD!
*/ */
public void run() { public void ownershipChanged(final boolean isOwner) {
if (isOwner) {
checkChangeHere(contents);
} else {
lostOwnershipImpl(); lostOwnershipImpl();
} }
}
protected synchronized void setContentsNative(Transferable contents) { protected synchronized void setContentsNative(Transferable contents) {
SortedMap formatMap = DataTransferer.getInstance().getFormatsForTransferable SortedMap formatMap = DataTransferer.getInstance().getFormatsForTransferable
(contents, DataTransferer.adaptFlavorMap(flavorMap)); (contents, DataTransferer.adaptFlavorMap(flavorMap));
long[] formats = long[] formats = DataTransferer.keysToLongArray(formatMap);
DataTransferer.getInstance().keysToLongArray(formatMap);
if (!selection.setOwner(contents, formatMap, formats, if (!selection.setOwner(contents, formatMap, formats,
XToolkit.getCurrentServerTime())) { XToolkit.getCurrentServerTime())) {
...@@ -94,6 +98,7 @@ public class XClipboard extends SunClipboard implements Runnable { ...@@ -94,6 +98,7 @@ public class XClipboard extends SunClipboard implements Runnable {
return selection.getSelectionAtom().getAtom(); return selection.getSelectionAtom().getAtom();
} }
@Override
public synchronized Transferable getContents(Object requestor) { public synchronized Transferable getContents(Object requestor) {
if (contents != null) { if (contents != null) {
return contents; return contents;
...@@ -115,62 +120,163 @@ public class XClipboard extends SunClipboard implements Runnable { ...@@ -115,62 +120,163 @@ public class XClipboard extends SunClipboard implements Runnable {
return selection.getData(format, XToolkit.getCurrentServerTime()); return selection.getData(format, XToolkit.getCurrentServerTime());
} }
// Called on the toolkit thread under awtLock. private void checkChangeHere(Transferable contents) {
public void checkChange(long[] formats) {
if (!selection.isOwner()) {
super.checkChange(formats);
}
}
void checkChangeHere(Transferable contents) {
if (areFlavorListenersRegistered()) { if (areFlavorListenersRegistered()) {
super.checkChange(DataTransferer.getInstance(). checkChange(DataTransferer.getInstance().
getFormatsForTransferableAsArray(contents, flavorMap)); getFormatsForTransferableAsArray(contents, flavorMap));
} }
} }
protected void registerClipboardViewerChecked() { private static int getPollInterval() {
synchronized (XClipboard.classLock) {
if (pollInterval <= 0) { if (pollInterval <= 0) {
pollInterval = ((Integer)AccessController.doPrivileged( pollInterval = AccessController.doPrivileged(
new GetIntegerAction("awt.datatransfer.clipboard.poll.interval", new GetIntegerAction("awt.datatransfer.clipboard.poll.interval",
defaultPollInterval))).intValue(); defaultPollInterval));
if (pollInterval <= 0) { if (pollInterval <= 0) {
pollInterval = defaultPollInterval; pollInterval = defaultPollInterval;
} }
} }
selection.initializeSelectionForTrackingChanges(); return pollInterval;
}
}
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; boolean mustSchedule = false;
synchronized (XClipboard.classLock) { synchronized (XClipboard.classLock) {
if (listenedClipboards == null) { if (targetsAtom2Clipboard == null) {
listenedClipboards = new HashSet(2); 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) { if (mustSchedule) {
XToolkit.schedule(new CheckChangeTimerTask(), pollInterval); XToolkit.schedule(new CheckChangeTimerTask(), XClipboard.getPollInterval());
} }
} }
private static class CheckChangeTimerTask implements Runnable { private static class CheckChangeTimerTask implements Runnable {
public void run() { public void run() {
for (Iterator iter = listenedClipboards.iterator(); iter.hasNext();) { for (XClipboard clpbrd : targetsAtom2Clipboard.values()) {
XClipboard clpbrd = (XClipboard)iter.next(); clpbrd.getTargetsDelayed();
clpbrd.selection.getTargetsDelayed(); }
synchronized (XClipboard.classLock) {
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) { synchronized (XClipboard.classLock) {
if (listenedClipboards != null && !listenedClipboards.isEmpty()) { if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) {
XToolkit.schedule(this, pollInterval); 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() { protected void unregisterClipboardViewerChecked() {
selection.deinitializeSelectionForTrackingChanges(); isSelectionNotifyProcessed = false;
synchronized (XClipboard.classLock) { 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);
}
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -48,8 +48,7 @@ class XDnDConstants { ...@@ -48,8 +48,7 @@ class XDnDConstants {
static final XAtom XA_XdndStatus = XAtom.get("XdndStatus"); static final XAtom XA_XdndStatus = XAtom.get("XdndStatus");
static final XAtom XA_XdndFinished = XAtom.get("XdndFinished"); static final XAtom XA_XdndFinished = XAtom.get("XdndFinished");
static final XSelection XDnDSelection = static final XSelection XDnDSelection = new XSelection(XA_XdndSelection);
new XSelection(XA_XdndSelection, null);
public static final int XDND_MIN_PROTOCOL_VERSION = 3; public static final int XDND_MIN_PROTOCOL_VERSION = 3;
public static final int XDND_PROTOCOL_VERSION = 5; public static final int XDND_PROTOCOL_VERSION = 5;
......
...@@ -32,9 +32,6 @@ import java.io.IOException; ...@@ -32,9 +32,6 @@ import java.io.IOException;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import sun.awt.AppContext; import sun.awt.AppContext;
import sun.awt.SunToolkit; import sun.awt.SunToolkit;
...@@ -45,7 +42,7 @@ import sun.awt.datatransfer.DataTransferer; ...@@ -45,7 +42,7 @@ import sun.awt.datatransfer.DataTransferer;
/** /**
* A class which interfaces with the X11 selection service. * A class which interfaces with the X11 selection service.
*/ */
public class XSelection { public final class XSelection {
/* Maps atoms to XSelection instances. */ /* Maps atoms to XSelection instances. */
private static final Hashtable<XAtom, XSelection> table = new Hashtable<XAtom, XSelection>(); private static final Hashtable<XAtom, XSelection> table = new Hashtable<XAtom, XSelection>();
...@@ -69,8 +66,6 @@ public class XSelection { ...@@ -69,8 +66,6 @@ public class XSelection {
XToolkit.awtUnlock(); XToolkit.awtUnlock();
} }
} }
/* The selection timeout. */
private static long SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout();
/* The PropertyNotify event handler for incremental data transfer. */ /* The PropertyNotify event handler for incremental data transfer. */
private static final XEventDispatcher incrementalTransferHandler = private static final XEventDispatcher incrementalTransferHandler =
...@@ -84,11 +79,6 @@ public class XSelection { ...@@ -84,11 +79,6 @@ public class XSelection {
/* The X atom for the underlying selection. */ /* The X atom for the underlying selection. */
private final XAtom selectionAtom; 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). * Owner-related variables - protected with synchronized (this).
...@@ -109,17 +99,8 @@ public class XSelection { ...@@ -109,17 +99,8 @@ public class XSelection {
private long ownershipTime = 0; private long ownershipTime = 0;
// True if we are the owner of this selection. // True if we are the owner of this selection.
private boolean isOwner; private boolean isOwner;
// The property in which the owner should place requested targets private OwnershipListener ownershipListener = null;
// when tracking changes of available data flavors (practically targets). private final Object stateLock = new Object();
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;
static { static {
XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(),
...@@ -141,12 +122,11 @@ public class XSelection { ...@@ -141,12 +122,11 @@ public class XSelection {
* @param clpbrd the corresponding clipoboard * @param clpbrd the corresponding clipoboard
* @exception NullPointerException if atom is <code>null</code>. * @exception NullPointerException if atom is <code>null</code>.
*/ */
public XSelection(XAtom atom, XClipboard clpbrd) { public XSelection(XAtom atom) {
if (atom == null) { if (atom == null) {
throw new NullPointerException("Null atom"); throw new NullPointerException("Null atom");
} }
selectionAtom = atom; selectionAtom = atom;
clipboard = clpbrd;
table.put(selectionAtom, this); table.put(selectionAtom, this);
} }
...@@ -154,25 +134,9 @@ public class XSelection { ...@@ -154,25 +134,9 @@ public class XSelection {
return selectionAtom; 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, public synchronized boolean setOwner(Transferable contents, Map formatMap,
long[] formats, long time) { long[] formats, long time)
{
long owner = XWindow.getXAWTRootWindow().getWindow(); long owner = XWindow.getXAWTRootWindow().getWindow();
long selection = selectionAtom.getAtom(); long selection = selectionAtom.getAtom();
...@@ -192,15 +156,12 @@ public class XSelection { ...@@ -192,15 +156,12 @@ public class XSelection {
XlibWrapper.XSetSelectionOwner(XToolkit.getDisplay(), XlibWrapper.XSetSelectionOwner(XToolkit.getDisplay(),
selection, owner, time); selection, owner, time);
if (XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(), if (XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(),
selection) != owner) { selection) != owner)
{
reset(); reset();
return false; return false;
} }
isOwner = true; setOwnerProp(true);
if (clipboard != null) {
clipboard.checkChangeHere(contents);
}
return true; return true;
} finally { } finally {
XToolkit.awtUnlock(); XToolkit.awtUnlock();
...@@ -217,7 +178,7 @@ public class XSelection { ...@@ -217,7 +178,7 @@ public class XSelection {
do { do {
DataTransferer.getInstance().processDataConversionRequests(); DataTransferer.getInstance().processDataConversionRequests();
XToolkit.awtLockWait(250); XToolkit.awtLockWait(250);
} while (propertyGetter == dataGetter && System.currentTimeMillis() < startTime + SELECTION_TIMEOUT); } while (propertyGetter == dataGetter && System.currentTimeMillis() < startTime + UNIXToolkit.getDatatransferTimeout());
} finally { } finally {
XToolkit.awtUnlock(); XToolkit.awtUnlock();
} }
...@@ -232,11 +193,9 @@ public class XSelection { ...@@ -232,11 +193,9 @@ public class XSelection {
throw new Error("UNIMPLEMENTED"); throw new Error("UNIMPLEMENTED");
} }
long[] formats = null; long[] targets = null;
synchronized (lock) { synchronized (lock) {
SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout();
WindowPropertyGetter targetsGetter = WindowPropertyGetter targetsGetter =
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(), new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
selectionPropertyAtom, 0, MAX_LENGTH, selectionPropertyAtom, 0, MAX_LENGTH,
...@@ -267,15 +226,15 @@ public class XSelection { ...@@ -267,15 +226,15 @@ public class XSelection {
} finally { } finally {
XToolkit.awtUnlock(); XToolkit.awtUnlock();
} }
formats = getFormats(targetsGetter); targets = getFormats(targetsGetter);
} finally { } finally {
targetsGetter.dispose(); targetsGetter.dispose();
} }
} }
return formats; return targets;
} }
private static long[] getFormats(WindowPropertyGetter targetsGetter) { static long[] getFormats(WindowPropertyGetter targetsGetter) {
long[] formats = null; long[] formats = null;
if (targetsGetter.isExecuted() && !targetsGetter.isDisposed() && if (targetsGetter.isExecuted() && !targetsGetter.isDisposed() &&
...@@ -285,7 +244,7 @@ public class XSelection { ...@@ -285,7 +244,7 @@ public class XSelection {
{ {
// we accept property with TARGETS type to be compatible with old jdks // we accept property with TARGETS type to be compatible with old jdks
// see 6607163 // see 6607163
int count = (int)targetsGetter.getNumberOfItems(); int count = targetsGetter.getNumberOfItems();
if (count > 0) { if (count > 0) {
long atoms = targetsGetter.getData(); long atoms = targetsGetter.getData();
formats = new long[count]; formats = new long[count];
...@@ -299,26 +258,6 @@ public class XSelection { ...@@ -299,26 +258,6 @@ public class XSelection {
return formats != null ? formats : new long[0]; 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 * Requests the selection data in the specified format and returns
* the data provided by the owner. * the data provided by the owner.
...@@ -331,8 +270,6 @@ public class XSelection { ...@@ -331,8 +270,6 @@ public class XSelection {
byte[] data = null; byte[] data = null;
synchronized (lock) { synchronized (lock) {
SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout();
WindowPropertyGetter dataGetter = WindowPropertyGetter dataGetter =
new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(), new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(),
selectionPropertyAtom, 0, MAX_LENGTH, selectionPropertyAtom, 0, MAX_LENGTH,
...@@ -381,7 +318,7 @@ public class XSelection { ...@@ -381,7 +318,7 @@ public class XSelection {
dataGetter.getActualFormat()); dataGetter.getActualFormat());
} }
int count = (int)dataGetter.getNumberOfItems(); int count = dataGetter.getNumberOfItems();
if (count <= 0) { if (count <= 0) {
throw new IOException("INCR data is missed."); throw new IOException("INCR data is missed.");
...@@ -457,7 +394,7 @@ public class XSelection { ...@@ -457,7 +394,7 @@ public class XSelection {
incrDataGetter.getActualFormat()); incrDataGetter.getActualFormat());
} }
count = (int)incrDataGetter.getNumberOfItems(); count = incrDataGetter.getNumberOfItems();
if (count == 0) { if (count == 0) {
break; break;
...@@ -491,7 +428,7 @@ public class XSelection { ...@@ -491,7 +428,7 @@ public class XSelection {
dataGetter.getActualFormat()); dataGetter.getActualFormat());
} }
int count = (int)dataGetter.getNumberOfItems(); int count = dataGetter.getNumberOfItems();
if (count > 0) { if (count > 0) {
data = new byte[count]; data = new byte[count];
long ptr = dataGetter.getData(); long ptr = dataGetter.getData();
...@@ -513,11 +450,14 @@ public class XSelection { ...@@ -513,11 +450,14 @@ public class XSelection {
return isOwner; return isOwner;
} }
public void lostOwnership() { // To be MT-safe this method should be called under awtLock.
isOwner = false; private void setOwnerProp(boolean f) {
if (clipboard != null) { isOwner = f;
clipboard.run(); fireOwnershipChanges(isOwner);
} }
private void lostOwnership() {
setOwnerProp(false);
} }
public synchronized void reset() { public synchronized void reset() {
...@@ -597,50 +537,95 @@ public class XSelection { ...@@ -597,50 +537,95 @@ public class XSelection {
private void handleSelectionRequest(XSelectionRequestEvent xsre) { private void handleSelectionRequest(XSelectionRequestEvent xsre) {
long property = xsre.get_property(); long property = xsre.get_property();
long requestor = xsre.get_requestor(); final long requestor = xsre.get_requestor();
long requestTime = xsre.get_time(); final long requestTime = xsre.get_time();
long format = xsre.get_target(); final long format = xsre.get_target();
int dataFormat = 0;
boolean conversionSucceeded = false; boolean conversionSucceeded = false;
if (ownershipTime != 0 && if (ownershipTime != 0 &&
(requestTime == XlibWrapper.CurrentTime || (requestTime == XlibWrapper.CurrentTime || requestTime >= ownershipTime))
requestTime >= ownershipTime)) { {
property = xsre.get_property();
// Handle MULTIPLE requests as per ICCCM. // Handle MULTIPLE requests as per ICCCM.
if (format == XDataTransferer.MULTIPLE_ATOM.getAtom()) { if (format == XDataTransferer.MULTIPLE_ATOM.getAtom()) {
// The property cannot be 0 for a MULTIPLE request. conversionSucceeded = handleMultipleRequest(requestor, property);
if (property != 0) { } else {
// Support for obsolete clients as per ICCCM.
if (property == XlibWrapper.None) {
property = format;
}
if (format == XDataTransferer.TARGETS_ATOM.getAtom()) {
conversionSucceeded = handleTargetsRequest(property, requestor);
} else {
conversionSucceeded = convertAndStore(requestor, format, property);
}
}
}
if (!conversionSucceeded) {
// None property indicates conversion failure.
property = XlibWrapper.None;
}
XSelectionEvent xse = new XSelectionEvent();
try {
xse.set_type(XlibWrapper.SelectionNotify);
xse.set_send_event(true);
xse.set_requestor(requestor);
xse.set_selection(selectionAtom.getAtom());
xse.set_target(format);
xse.set_property(property);
xse.set_time(requestTime);
XToolkit.awtLock();
try {
XlibWrapper.XSendEvent(XToolkit.getDisplay(), requestor, false,
XlibWrapper.NoEventMask, xse.pData);
} finally {
XToolkit.awtUnlock();
}
} finally {
xse.dispose();
}
}
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. // First retrieve the list of requested targets.
WindowPropertyGetter wpg = WindowPropertyGetter wpg =
new WindowPropertyGetter(requestor, XAtom.get(property), 0, new WindowPropertyGetter(requestor, XAtom.get(property),
MAX_LENGTH, false, 0, MAX_LENGTH, false,
XlibWrapper.AnyPropertyType); XlibWrapper.AnyPropertyType);
try { try {
wpg.execute(); wpg.execute();
if (wpg.getActualFormat() == 32 && if (wpg.getActualFormat() == 32 && (wpg.getNumberOfItems() % 2) == 0) {
(wpg.getNumberOfItems() % 2) == 0) { final long count = wpg.getNumberOfItems() / 2;
long count = wpg.getNumberOfItems() / 2; final long pairsPtr = wpg.getData();
long pairsPtr = wpg.getData();
boolean writeBack = false; boolean writeBack = false;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
long target = Native.getLong(pairsPtr, 2*i); long target = Native.getLong(pairsPtr, 2 * i);
long prop = Native.getLong(pairsPtr, 2*i + 1); long prop = Native.getLong(pairsPtr, 2 * i + 1);
if (!convertAndStore(requestor, target, prop)) { if (!convertAndStore(requestor, target, prop)) {
// To report failure, we should replace the // To report failure, we should replace the
// target atom with 0 in the MULTIPLE property. // target atom with 0 in the MULTIPLE property.
Native.putLong(pairsPtr, 2*i, 0); Native.putLong(pairsPtr, 2 * i, 0);
writeBack = true; writeBack = true;
} }
} }
if (writeBack) { if (writeBack) {
XToolkit.awtLock(); XToolkit.awtLock();
try { try {
XlibWrapper.XChangeProperty(XToolkit.getDisplay(), requestor, XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
requestor,
property, property,
wpg.getActualType(), wpg.getActualType(),
wpg.getActualFormat(), wpg.getActualFormat(),
...@@ -656,19 +641,14 @@ public class XSelection { ...@@ -656,19 +641,14 @@ public class XSelection {
} finally { } finally {
wpg.dispose(); wpg.dispose();
} }
}
} else {
// Support for obsolete clients as per ICCCM. return conversionSucceeded;
if (property == 0) {
property = format;
} }
if (format == XDataTransferer.TARGETS_ATOM.getAtom()) { private boolean handleTargetsRequest(long property, long requestor)
long nativeDataPtr = 0; throws IllegalStateException
int count = 0; {
dataFormat = 32; boolean conversionSucceeded = false;
// Use a local copy to avoid synchronization. // Use a local copy to avoid synchronization.
long[] formatsLocal = formats; long[] formatsLocal = formats;
...@@ -676,9 +656,12 @@ public class XSelection { ...@@ -676,9 +656,12 @@ public class XSelection {
throw new IllegalStateException("Not an owner."); throw new IllegalStateException("Not an owner.");
} }
count = formatsLocal.length; long nativeDataPtr = 0;
try { try {
final int count = formatsLocal.length;
final int dataFormat = 32;
if (count > 0) { if (count > 0) {
nativeDataPtr = Native.allocateLongArray(count); nativeDataPtr = Native.allocateLongArray(count);
Native.put(nativeDataPtr, formatsLocal); Native.put(nativeDataPtr, formatsLocal);
...@@ -701,74 +684,28 @@ public class XSelection { ...@@ -701,74 +684,28 @@ public class XSelection {
nativeDataPtr = 0; nativeDataPtr = 0;
} }
} }
} else { return conversionSucceeded;
conversionSucceeded = convertAndStore(requestor, format,
property);
}
}
}
if (!conversionSucceeded) {
// Zero property indicates conversion failure.
property = 0;
} }
XSelectionEvent xse = new XSelectionEvent(); private void fireOwnershipChanges(final boolean isOwner) {
try { OwnershipListener l = null;
xse.set_type((int)XlibWrapper.SelectionNotify); synchronized (stateLock) {
xse.set_send_event(true); l = ownershipListener;
xse.set_requestor(requestor);
xse.set_selection(selectionAtom.getAtom());
xse.set_target(format);
xse.set_property(property);
xse.set_time(requestTime);
XToolkit.awtLock();
try {
XlibWrapper.XSendEvent(XToolkit.getDisplay(), requestor, false,
XlibWrapper.NoEventMask, xse.pData);
} finally {
XToolkit.awtUnlock();
}
} finally {
xse.dispose();
} }
if (null != l) {
l.ownershipChanged(isOwner);
} }
private static void checkChange(XSelectionEvent xse) {
if (targetsPropertyAtoms == null || targetsPropertyAtoms.isEmpty()) {
// We are not tracking changes.
return;
} }
long propertyAtom = xse.get_property(); void registerOwershipListener(OwnershipListener l) {
long[] formats = null; synchronized (stateLock) {
ownershipListener = l;
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);
try {
targetsGetter.execute();
formats = getFormats(targetsGetter);
} finally {
targetsGetter.dispose();
} }
} }
XAtom selectionAtom = XAtom.get(xse.get_selection()); void unregisterOwnershipListener() {
XSelection selection = getSelection(selectionAtom); synchronized (stateLock) {
if (selection != null) { ownershipListener = null;
selection.isSelectionNotifyProcessed = true;
if (selection.clipboard != null) {
selection.clipboard.checkChange(formats);
}
} }
} }
...@@ -776,10 +713,9 @@ public class XSelection { ...@@ -776,10 +713,9 @@ public class XSelection {
public void dispatchEvent(XEvent ev) { public void dispatchEvent(XEvent ev) {
switch (ev.get_type()) { switch (ev.get_type()) {
case XlibWrapper.SelectionNotify: { case XlibWrapper.SelectionNotify: {
XSelectionEvent xse = ev.get_xselection();
checkChange(xse);
XToolkit.awtLock(); XToolkit.awtLock();
try { try {
XSelectionEvent xse = ev.get_xselection();
// Ignore the SelectionNotify event if it is not the response to our last request. // Ignore the SelectionNotify event if it is not the response to our last request.
if (propertyGetter != null && xse.get_time() == lastRequestServerTime) { if (propertyGetter != null && xse.get_time() == lastRequestServerTime) {
// The property will be None in case of convertion failure. // The property will be None in case of convertion failure.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册