# HG changeset patch # User son # Date 1205417684 -10800 # Node ID 766ae458aaf107dfb3d8b3f84bddc3ac54b3525e # Parent 9c43d9eb1029dc778df288bfc7e8cfd2d0890616 6538066: XSelection should be more passive Summary: Now only XClipboard know about XSelection, and XSelection knows nothing about XClipboard. Reviewed-by: uta, denis diff -r 9c43d9eb1029 -r 766ae458aaf1 jdk/src/solaris/classes/sun/awt/X11/MotifDnDConstants.java --- 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)); } diff -r 9c43d9eb1029 -r 766ae458aaf1 jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java --- 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()); diff -r 9c43d9eb1029 -r 766ae458aaf1 jdk/src/solaris/classes/sun/awt/X11/OwnershipListener.java --- /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); +} diff -r 9c43d9eb1029 -r 766ae458aaf1 jdk/src/solaris/classes/sun/awt/X11/XClipboard.java --- 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 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(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); + } } diff -r 9c43d9eb1029 -r 766ae458aaf1 jdk/src/solaris/classes/sun/awt/X11/XDnDConstants.java --- 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; diff -r 9c43d9eb1029 -r 766ae458aaf1 jdk/src/solaris/classes/sun/awt/X11/XSelection.java --- 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 table = new Hashtable(); @@ -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 null. */ - 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.