--- old/src/share/classes/sun/awt/datatransfer/SunClipboard.java 2014-07-17 14:35:51.000000000 +0400 +++ /dev/null 2014-07-17 14:35:51.000000000 +0400 @@ -1,451 +0,0 @@ -/* - * Copyright (c) 1999, 2006, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.awt.datatransfer; - -import java.awt.EventQueue; - -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.FlavorTable; -import java.awt.datatransfer.SystemFlavorMap; -import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.ClipboardOwner; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.FlavorListener; -import java.awt.datatransfer.FlavorEvent; -import java.awt.datatransfer.UnsupportedFlavorException; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - -import java.util.Objects; -import java.util.Set; -import java.util.HashSet; - -import java.io.IOException; - -import sun.awt.AppContext; -import sun.awt.PeerEvent; -import sun.awt.SunToolkit; - - -/** - * Serves as a common, helper superclass for the Win32 and X11 system - * Clipboards. - * - * @author Danila Sinopalnikov - * @author Alexander Gerasimov - * - * @since 1.3 - */ -public abstract class SunClipboard extends Clipboard - implements PropertyChangeListener { - - private AppContext contentsContext = null; - - private final Object CLIPBOARD_FLAVOR_LISTENER_KEY; - - /** - * A number of FlavorListeners currently registered - * on this clipboard across all AppContexts. - */ - private volatile int numberOfFlavorListeners = 0; - - /** - * A set of DataFlavors that is available on - * this clipboard. It is used for tracking changes - * of DataFlavors available on this clipboard. - */ - private volatile Set currentDataFlavors; - - - public SunClipboard(String name) { - super(name); - CLIPBOARD_FLAVOR_LISTENER_KEY = new StringBuffer(name + "_CLIPBOARD_FLAVOR_LISTENER_KEY"); - } - - public synchronized void setContents(Transferable contents, - ClipboardOwner owner) { - // 4378007 : Toolkit.getSystemClipboard().setContents(null, null) - // should throw NPE - if (contents == null) { - throw new NullPointerException("contents"); - } - - initContext(); - - final ClipboardOwner oldOwner = this.owner; - final Transferable oldContents = this.contents; - - try { - this.owner = owner; - this.contents = new TransferableProxy(contents, true); - - setContentsNative(contents); - } finally { - if (oldOwner != null && oldOwner != owner) { - EventQueue.invokeLater(() -> oldOwner.lostOwnership(SunClipboard.this, oldContents)); - } - } - } - - private synchronized void initContext() { - final AppContext context = AppContext.getAppContext(); - - if (contentsContext != context) { - // Need to synchronize on the AppContext to guarantee that it cannot - // be disposed after the check, but before the listener is added. - synchronized (context) { - if (context.isDisposed()) { - throw new IllegalStateException("Can't set contents from disposed AppContext"); - } - context.addPropertyChangeListener - (AppContext.DISPOSED_PROPERTY_NAME, this); - } - if (contentsContext != null) { - contentsContext.removePropertyChangeListener - (AppContext.DISPOSED_PROPERTY_NAME, this); - } - contentsContext = context; - } - } - - public synchronized Transferable getContents(Object requestor) { - if (contents != null) { - return contents; - } - return new ClipboardTransferable(this); - } - - - /** - * @return the contents of this clipboard if it has been set from the same - * AppContext as it is currently retrieved or null otherwise - * @since 1.5 - */ - private synchronized Transferable getContextContents() { - AppContext context = AppContext.getAppContext(); - return (context == contentsContext) ? contents : null; - } - - - /** - * @see java.awt.Clipboard#getAvailableDataFlavors - * @since 1.5 - */ - public DataFlavor[] getAvailableDataFlavors() { - Transferable cntnts = getContextContents(); - if (cntnts != null) { - return cntnts.getTransferDataFlavors(); - } - - long[] formats = getClipboardFormatsOpenClose(); - - return DataTransferer.getInstance(). - getFlavorsForFormatsAsArray(formats, getDefaultFlavorTable()); - } - - /** - * @see java.awt.Clipboard#isDataFlavorAvailable - * @since 1.5 - */ - public boolean isDataFlavorAvailable(DataFlavor flavor) { - if (flavor == null) { - throw new NullPointerException("flavor"); - } - - Transferable cntnts = getContextContents(); - if (cntnts != null) { - return cntnts.isDataFlavorSupported(flavor); - } - - long[] formats = getClipboardFormatsOpenClose(); - - return formatArrayAsDataFlavorSet(formats).contains(flavor); - } - - /** - * @see java.awt.Clipboard#getData - * @since 1.5 - */ - public Object getData(DataFlavor flavor) - throws UnsupportedFlavorException, IOException { - if (flavor == null) { - throw new NullPointerException("flavor"); - } - - Transferable cntnts = getContextContents(); - if (cntnts != null) { - return cntnts.getTransferData(flavor); - } - - long format = 0; - byte[] data = null; - Transferable localeTransferable = null; - - try { - openClipboard(null); - - long[] formats = getClipboardFormats(); - Long lFormat = DataTransferer.getInstance(). - getFlavorsForFormats(formats, getDefaultFlavorTable()).get(flavor); - - if (lFormat == null) { - throw new UnsupportedFlavorException(flavor); - } - - format = lFormat.longValue(); - data = getClipboardData(format); - - if (DataTransferer.getInstance().isLocaleDependentTextFormat(format)) { - localeTransferable = createLocaleTransferable(formats); - } - - } finally { - closeClipboard(); - } - - return DataTransferer.getInstance(). - translateBytes(data, flavor, format, localeTransferable); - } - - /** - * The clipboard must be opened. - * - * @since 1.5 - */ - protected Transferable createLocaleTransferable(long[] formats) throws IOException { - return null; - } - - /** - * @throws IllegalStateException if the clipboard has not been opened - */ - public void openClipboard(SunClipboard newOwner) {} - public void closeClipboard() {} - - public abstract long getID(); - - public void propertyChange(PropertyChangeEvent evt) { - if (AppContext.DISPOSED_PROPERTY_NAME.equals(evt.getPropertyName()) && - Boolean.TRUE.equals(evt.getNewValue())) { - final AppContext disposedContext = (AppContext)evt.getSource(); - lostOwnershipLater(disposedContext); - } - } - - protected void lostOwnershipImpl() { - lostOwnershipLater(null); - } - - /** - * Clears the clipboard state (contents, owner and contents context) and - * notifies the current owner that ownership is lost. Does nothing if the - * argument is not null and is not equal to the current - * contents context. - * - * @param disposedContext the AppContext that is disposed or - * null if the ownership is lost because another - * application acquired ownership. - */ - protected void lostOwnershipLater(final AppContext disposedContext) { - final AppContext context = this.contentsContext; - if (context == null) { - return; - } - - final Runnable runnable = new Runnable() { - public void run() { - final SunClipboard sunClipboard = SunClipboard.this; - ClipboardOwner owner = null; - Transferable contents = null; - - synchronized (sunClipboard) { - final AppContext context = sunClipboard.contentsContext; - - if (context == null) { - return; - } - - if (disposedContext == null || context == disposedContext) { - owner = sunClipboard.owner; - contents = sunClipboard.contents; - sunClipboard.contentsContext = null; - sunClipboard.owner = null; - sunClipboard.contents = null; - sunClipboard.clearNativeContext(); - context.removePropertyChangeListener - (AppContext.DISPOSED_PROPERTY_NAME, sunClipboard); - } else { - return; - } - } - if (owner != null) { - owner.lostOwnership(sunClipboard, contents); - } - } - }; - - SunToolkit.postEvent(context, new PeerEvent(this, runnable, - PeerEvent.PRIORITY_EVENT)); - } - - protected abstract void clearNativeContext(); - - protected abstract void setContentsNative(Transferable contents); - - /** - * @since 1.5 - */ - protected long[] getClipboardFormatsOpenClose() { - try { - openClipboard(null); - return getClipboardFormats(); - } finally { - closeClipboard(); - } - } - - /** - * Returns zero-length array (not null) if the number of available formats is zero. - * - * @throws IllegalStateException if formats could not be retrieved - */ - protected abstract long[] getClipboardFormats(); - - protected abstract byte[] getClipboardData(long format) throws IOException; - - - private static Set formatArrayAsDataFlavorSet(long[] formats) { - return (formats == null) ? null : - DataTransferer.getInstance(). - getFlavorsForFormatsAsSet(formats, getDefaultFlavorTable()); - } - - - public synchronized void addFlavorListener(FlavorListener listener) { - if (listener == null) { - return; - } - AppContext appContext = AppContext.getAppContext(); - Set flavorListeners = getFlavorListeners(appContext); - if (flavorListeners == null) { - flavorListeners = new HashSet<>(); - appContext.put(CLIPBOARD_FLAVOR_LISTENER_KEY, flavorListeners); - } - flavorListeners.add(listener); - - if (numberOfFlavorListeners++ == 0) { - long[] currentFormats = null; - try { - openClipboard(null); - currentFormats = getClipboardFormats(); - } catch (IllegalStateException exc) { - } finally { - closeClipboard(); - } - currentDataFlavors = formatArrayAsDataFlavorSet(currentFormats); - - registerClipboardViewerChecked(); - } - } - - public synchronized void removeFlavorListener(FlavorListener listener) { - if (listener == null) { - return; - } - Set flavorListeners = getFlavorListeners(AppContext.getAppContext()); - if (flavorListeners == null){ - //else we throw NullPointerException, but it is forbidden - return; - } - if (flavorListeners.remove(listener) && --numberOfFlavorListeners == 0) { - unregisterClipboardViewerChecked(); - currentDataFlavors = null; - } - } - - @SuppressWarnings("unchecked") - private Set getFlavorListeners(AppContext appContext) { - return (Set)appContext.get(CLIPBOARD_FLAVOR_LISTENER_KEY); - } - - public synchronized FlavorListener[] getFlavorListeners() { - Set flavorListeners = getFlavorListeners(AppContext.getAppContext()); - return flavorListeners == null ? new FlavorListener[0] - : flavorListeners.toArray(new FlavorListener[flavorListeners.size()]); - } - - public boolean areFlavorListenersRegistered() { - return (numberOfFlavorListeners > 0); - } - - protected abstract void registerClipboardViewerChecked(); - - protected abstract void unregisterClipboardViewerChecked(); - - /** - * Checks change of the DataFlavors and, if necessary, - * posts notifications on FlavorEvents to the - * AppContexts' EDTs. - * The parameter formats is null iff we have just - * failed to get formats available on the clipboard. - * - * @param formats data formats that have just been retrieved from - * this clipboard - */ - public void checkChange(long[] formats) { - Set prevDataFlavors = currentDataFlavors; - currentDataFlavors = formatArrayAsDataFlavorSet(formats); - - if (Objects.equals(prevDataFlavors, currentDataFlavors)) { - // we've been able to successfully get available on the clipboard - // DataFlavors this and previous time and they are coincident; - // don't notify - return; - } - - for (AppContext appContext : AppContext.getAppContexts()) { - if (appContext == null || appContext.isDisposed()) { - continue; - } - Set flavorListeners = getFlavorListeners(appContext); - if (flavorListeners != null) { - for (FlavorListener listener : flavorListeners) { - if (listener != null) { - PeerEvent peerEvent = new PeerEvent(this, - () -> listener.flavorsChanged(new FlavorEvent(SunClipboard.this)), - PeerEvent.PRIORITY_EVENT); - SunToolkit.postEvent(appContext, peerEvent); - } - } - } - } - } - - public static FlavorTable getDefaultFlavorTable() { - return (FlavorTable) SystemFlavorMap.getDefaultFlavorMap(); - } -} --- /dev/null 2014-07-17 14:35:51.000000000 +0400 +++ new/src/share/classes/sun/awt/datatransfer/desktop/SunClipboard.java 2014-07-17 14:35:51.000000000 +0400 @@ -0,0 +1,452 @@ +/* + * Copyright (c) 1999, 2006, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.awt.datatransfer.desktop; + +import java.awt.EventQueue; + +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.FlavorTable; +import java.awt.datatransfer.SystemFlavorMap; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorListener; +import java.awt.datatransfer.FlavorEvent; +import java.awt.datatransfer.UnsupportedFlavorException; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import java.util.Objects; +import java.util.Set; +import java.util.HashSet; + +import java.io.IOException; + +import sun.awt.AppContext; +import sun.awt.PeerEvent; +import sun.awt.SunToolkit; +import sun.awt.datatransfer.TransferableProxy; + + +/** + * Serves as a common, helper superclass for the Win32 and X11 system + * Clipboards. + * + * @author Danila Sinopalnikov + * @author Alexander Gerasimov + * + * @since 1.3 + */ +public abstract class SunClipboard extends Clipboard + implements PropertyChangeListener { + + private AppContext contentsContext = null; + + private final Object CLIPBOARD_FLAVOR_LISTENER_KEY; + + /** + * A number of FlavorListeners currently registered + * on this clipboard across all AppContexts. + */ + private volatile int numberOfFlavorListeners = 0; + + /** + * A set of DataFlavors that is available on + * this clipboard. It is used for tracking changes + * of DataFlavors available on this clipboard. + */ + private volatile Set currentDataFlavors; + + + public SunClipboard(String name) { + super(name); + CLIPBOARD_FLAVOR_LISTENER_KEY = new StringBuffer(name + "_CLIPBOARD_FLAVOR_LISTENER_KEY"); + } + + public synchronized void setContents(Transferable contents, + ClipboardOwner owner) { + // 4378007 : Toolkit.getSystemClipboard().setContents(null, null) + // should throw NPE + if (contents == null) { + throw new NullPointerException("contents"); + } + + initContext(); + + final ClipboardOwner oldOwner = this.owner; + final Transferable oldContents = this.contents; + + try { + this.owner = owner; + this.contents = new TransferableProxy(contents, true); + + setContentsNative(contents); + } finally { + if (oldOwner != null && oldOwner != owner) { + EventQueue.invokeLater(() -> oldOwner.lostOwnership(SunClipboard.this, oldContents)); + } + } + } + + private synchronized void initContext() { + final AppContext context = AppContext.getAppContext(); + + if (contentsContext != context) { + // Need to synchronize on the AppContext to guarantee that it cannot + // be disposed after the check, but before the listener is added. + synchronized (context) { + if (context.isDisposed()) { + throw new IllegalStateException("Can't set contents from disposed AppContext"); + } + context.addPropertyChangeListener + (AppContext.DISPOSED_PROPERTY_NAME, this); + } + if (contentsContext != null) { + contentsContext.removePropertyChangeListener + (AppContext.DISPOSED_PROPERTY_NAME, this); + } + contentsContext = context; + } + } + + public synchronized Transferable getContents(Object requestor) { + if (contents != null) { + return contents; + } + return new ClipboardTransferable(this); + } + + + /** + * @return the contents of this clipboard if it has been set from the same + * AppContext as it is currently retrieved or null otherwise + * @since 1.5 + */ + private synchronized Transferable getContextContents() { + AppContext context = AppContext.getAppContext(); + return (context == contentsContext) ? contents : null; + } + + + /** + * @see java.awt.datatransfer.Clipboard#getAvailableDataFlavors + * @since 1.5 + */ + public DataFlavor[] getAvailableDataFlavors() { + Transferable cntnts = getContextContents(); + if (cntnts != null) { + return cntnts.getTransferDataFlavors(); + } + + long[] formats = getClipboardFormatsOpenClose(); + + return DataTransferer.getInstance(). + getFlavorsForFormatsAsArray(formats, getDefaultFlavorTable()); + } + + /** + * @see java.awt.datatransfer.Clipboard#isDataFlavorAvailable + * @since 1.5 + */ + public boolean isDataFlavorAvailable(DataFlavor flavor) { + if (flavor == null) { + throw new NullPointerException("flavor"); + } + + Transferable cntnts = getContextContents(); + if (cntnts != null) { + return cntnts.isDataFlavorSupported(flavor); + } + + long[] formats = getClipboardFormatsOpenClose(); + + return formatArrayAsDataFlavorSet(formats).contains(flavor); + } + + /** + * @see java.awt.datatransfer.Clipboard#getData + * @since 1.5 + */ + public Object getData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + if (flavor == null) { + throw new NullPointerException("flavor"); + } + + Transferable cntnts = getContextContents(); + if (cntnts != null) { + return cntnts.getTransferData(flavor); + } + + long format = 0; + byte[] data = null; + Transferable localeTransferable = null; + + try { + openClipboard(null); + + long[] formats = getClipboardFormats(); + Long lFormat = DataTransferer.getInstance(). + getFlavorsForFormats(formats, getDefaultFlavorTable()).get(flavor); + + if (lFormat == null) { + throw new UnsupportedFlavorException(flavor); + } + + format = lFormat.longValue(); + data = getClipboardData(format); + + if (DataTransferer.getInstance().isLocaleDependentTextFormat(format)) { + localeTransferable = createLocaleTransferable(formats); + } + + } finally { + closeClipboard(); + } + + return DataTransferer.getInstance(). + translateBytes(data, flavor, format, localeTransferable); + } + + /** + * The clipboard must be opened. + * + * @since 1.5 + */ + protected Transferable createLocaleTransferable(long[] formats) throws IOException { + return null; + } + + /** + * @throws IllegalStateException if the clipboard has not been opened + */ + public void openClipboard(SunClipboard newOwner) {} + public void closeClipboard() {} + + public abstract long getID(); + + public void propertyChange(PropertyChangeEvent evt) { + if (AppContext.DISPOSED_PROPERTY_NAME.equals(evt.getPropertyName()) && + Boolean.TRUE.equals(evt.getNewValue())) { + final AppContext disposedContext = (AppContext)evt.getSource(); + lostOwnershipLater(disposedContext); + } + } + + protected void lostOwnershipImpl() { + lostOwnershipLater(null); + } + + /** + * Clears the clipboard state (contents, owner and contents context) and + * notifies the current owner that ownership is lost. Does nothing if the + * argument is not null and is not equal to the current + * contents context. + * + * @param disposedContext the AppContext that is disposed or + * null if the ownership is lost because another + * application acquired ownership. + */ + protected void lostOwnershipLater(final AppContext disposedContext) { + final AppContext context = this.contentsContext; + if (context == null) { + return; + } + + final Runnable runnable = new Runnable() { + public void run() { + final SunClipboard sunClipboard = SunClipboard.this; + ClipboardOwner owner = null; + Transferable contents = null; + + synchronized (sunClipboard) { + final AppContext context = sunClipboard.contentsContext; + + if (context == null) { + return; + } + + if (disposedContext == null || context == disposedContext) { + owner = sunClipboard.owner; + contents = sunClipboard.contents; + sunClipboard.contentsContext = null; + sunClipboard.owner = null; + sunClipboard.contents = null; + sunClipboard.clearNativeContext(); + context.removePropertyChangeListener + (AppContext.DISPOSED_PROPERTY_NAME, sunClipboard); + } else { + return; + } + } + if (owner != null) { + owner.lostOwnership(sunClipboard, contents); + } + } + }; + + SunToolkit.postEvent(context, new PeerEvent(this, runnable, + PeerEvent.PRIORITY_EVENT)); + } + + protected abstract void clearNativeContext(); + + protected abstract void setContentsNative(Transferable contents); + + /** + * @since 1.5 + */ + protected long[] getClipboardFormatsOpenClose() { + try { + openClipboard(null); + return getClipboardFormats(); + } finally { + closeClipboard(); + } + } + + /** + * Returns zero-length array (not null) if the number of available formats is zero. + * + * @throws IllegalStateException if formats could not be retrieved + */ + protected abstract long[] getClipboardFormats(); + + protected abstract byte[] getClipboardData(long format) throws IOException; + + + private static Set formatArrayAsDataFlavorSet(long[] formats) { + return (formats == null) ? null : + DataTransferer.getInstance(). + getFlavorsForFormatsAsSet(formats, getDefaultFlavorTable()); + } + + + public synchronized void addFlavorListener(FlavorListener listener) { + if (listener == null) { + return; + } + AppContext appContext = AppContext.getAppContext(); + Set flavorListeners = getFlavorListeners(appContext); + if (flavorListeners == null) { + flavorListeners = new HashSet<>(); + appContext.put(CLIPBOARD_FLAVOR_LISTENER_KEY, flavorListeners); + } + flavorListeners.add(listener); + + if (numberOfFlavorListeners++ == 0) { + long[] currentFormats = null; + try { + openClipboard(null); + currentFormats = getClipboardFormats(); + } catch (IllegalStateException exc) { + } finally { + closeClipboard(); + } + currentDataFlavors = formatArrayAsDataFlavorSet(currentFormats); + + registerClipboardViewerChecked(); + } + } + + public synchronized void removeFlavorListener(FlavorListener listener) { + if (listener == null) { + return; + } + Set flavorListeners = getFlavorListeners(AppContext.getAppContext()); + if (flavorListeners == null){ + //else we throw NullPointerException, but it is forbidden + return; + } + if (flavorListeners.remove(listener) && --numberOfFlavorListeners == 0) { + unregisterClipboardViewerChecked(); + currentDataFlavors = null; + } + } + + @SuppressWarnings("unchecked") + private Set getFlavorListeners(AppContext appContext) { + return (Set)appContext.get(CLIPBOARD_FLAVOR_LISTENER_KEY); + } + + public synchronized FlavorListener[] getFlavorListeners() { + Set flavorListeners = getFlavorListeners(AppContext.getAppContext()); + return flavorListeners == null ? new FlavorListener[0] + : flavorListeners.toArray(new FlavorListener[flavorListeners.size()]); + } + + public boolean areFlavorListenersRegistered() { + return (numberOfFlavorListeners > 0); + } + + protected abstract void registerClipboardViewerChecked(); + + protected abstract void unregisterClipboardViewerChecked(); + + /** + * Checks change of the DataFlavors and, if necessary, + * posts notifications on FlavorEvents to the + * AppContexts' EDTs. + * The parameter formats is null iff we have just + * failed to get formats available on the clipboard. + * + * @param formats data formats that have just been retrieved from + * this clipboard + */ + public void checkChange(long[] formats) { + Set prevDataFlavors = currentDataFlavors; + currentDataFlavors = formatArrayAsDataFlavorSet(formats); + + if (Objects.equals(prevDataFlavors, currentDataFlavors)) { + // we've been able to successfully get available on the clipboard + // DataFlavors this and previous time and they are coincident; + // don't notify + return; + } + + for (AppContext appContext : AppContext.getAppContexts()) { + if (appContext == null || appContext.isDisposed()) { + continue; + } + Set flavorListeners = getFlavorListeners(appContext); + if (flavorListeners != null) { + for (FlavorListener listener : flavorListeners) { + if (listener != null) { + PeerEvent peerEvent = new PeerEvent(this, + () -> listener.flavorsChanged(new FlavorEvent(SunClipboard.this)), + PeerEvent.PRIORITY_EVENT); + SunToolkit.postEvent(appContext, peerEvent); + } + } + } + } + } + + public static FlavorTable getDefaultFlavorTable() { + return (FlavorTable) SystemFlavorMap.getDefaultFlavorMap(); + } +}