Mailing Lists: Apple Mailing Lists

Image of Mac OS face in stamp
 
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

MacOS TransferListener problem - a patch/fix



Some weeks ago there was discussion on this list about clipboard problems on Mac OS. One of the issues was that FlavorListener did not get called properly.

This indeed seems to be the case. For my own application framework I've implemented a fix while I wait Apple to get their act together (it is still broken on versions I cannot talk about).

I'm sharing it here in case someone finds it useful.

The main idea is that instead of directly calling Toolkit.getSystemClipboard() I
call my MacOSClipboard.getClipboard() which instantiates a 'proxy' clipboard (if it has not already been instantiated) that sits between my application code
and the system clipboard. This 'proxy' clipboard implements calling the
flavor listeners as appropriate. To make it work it needs some help. I call
the MacOSClipboard.fireFlavorsChanged() whenever one of my windows becomes
active because in most real life cases no new data can be placed on the clipboard unless my windows first become de-active and I won't be using it
before one of my windows becomes active. In this way I get notified if some other application places data on the clipboard. Of course I my application
puts data on the clipboard this is directly captured (within the fix) and
reported to FlavorListeners as it appropriate. Thats all that I need to make it
work for me.


An alternative is to use a timer daemon to periodically check the clipboard. To start it call startClipboardDaemon().

Notice that most methods in my code have package visibility because I call this from within my framework code and I do not want application code directly to
call this fix-code.


Of course I only instantiate fix inside a public method within the framework
and only if running on Mac OS.

[SNIP]
	public Clipboard createClipboard() {
		if (Application.inMacOS())
			return MacOSClipboard.getClipboard();
		else
			return Toolkit.getDefaultToolkit().getSystemClipboard();

	}

	static public boolean inMacOS() {
	
		String lcOSName = System.getProperty("os.name").toLowerCase();
		return lcOSName.indexOf("mac os") >= 0;
	}

[SNIP]



Once Apple fixes their stuff I'll just quietly remove this fix.

In this way I can mostly code as if the problem wasn't there and the fix won't
get spread allover the code.


Everyone is of course welcome to change the code as they please.

While on the subject, someone was wondering weather to use a local or system clipboard. My take on this is always to use system clipboard as overhead
implementation wise is minimal and one never knows if the user is running two instances of my application so a local clipboard wont cut it across the JVM boundary.


Hope someone finds this usefull.

br Kusti

MacOSClipboard class source:
//-------------------------------------------------------------------
package jApp;

import java.awt.Toolkit;
import java.awt.datatransfer.*;
import java.util.Timer;
import java.util.TimerTask;
import java.io.IOException;

/*package*/class MacOSClipboard extends Clipboard {
	static private Clipboard m_SystemClipboard;

	static private MacOSClipboard m_MacOSClipboard;

	private static DataFlavor[] m_Flavors;

	static public Clipboard getClipboard() {
		if (m_MacOSClipboard == null)
			m_MacOSClipboard = new MacOSClipboard();
		return m_MacOSClipboard;
	}

	private MacOSClipboard() {
		super(Toolkit.getDefaultToolkit().getSystemClipboard().getName());
		m_SystemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
		m_MacOSClipboard = this;

	}

	@Override
	public synchronized void addFlavorListener(FlavorListener listener) {
		// TODO Auto-generated method stub
		m_SystemClipboard.addFlavorListener(listener);
	}

	@Override
	public DataFlavor[] getAvailableDataFlavors() {
		// TODO Auto-generated method stub
		return m_SystemClipboard.getAvailableDataFlavors();
	}

	@Override
	public synchronized Transferable getContents(Object requestor) {
		// TODO Auto-generated method stub
		return m_SystemClipboard.getContents(requestor);
	}

@Override
public Object getData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return m_SystemClipboard.getData(flavor);
}


	@Override
	public boolean isDataFlavorAvailable(DataFlavor flavor) {
		return m_SystemClipboard.isDataFlavorAvailable(flavor);
	}

	@Override
	public synchronized void removeFlavorListener(FlavorListener listener) {
		m_SystemClipboard.removeFlavorListener(listener);
	}

	@Override
	public synchronized FlavorListener[] getFlavorListeners() {
		return m_SystemClipboard.getFlavorListeners();
	}

	@Override
	public String getName() {
		return m_SystemClipboard.getName();
	}

	@Override
	public synchronized void setContents(Transferable contents, ClipboardOwner owner) {
		final ClipboardOwner realOwner = owner;
		m_SystemClipboard.setContents(contents, new ClipboardOwner() {
			public void lostOwnership(Clipboard clipboard, Transferable contents) {
				realOwner.lostOwnership(clipboard, contents);
				fireFlavorsChanged();
			}
		});
		fireFlavorsChanged();
	}

	static/* packate */void fireFlavorsChanged() {
		for (FlavorListener listener : m_SystemClipboard.getFlavorListeners())
			listener.flavorsChanged(new FlavorEvent(m_SystemClipboard));
		m_Flavors = m_SystemClipboard.getAvailableDataFlavors();
	}

	/* package */boolean isFlavorsChanged() {
		DataFlavor[] current = m_SystemClipboard.getAvailableDataFlavors();
		boolean changed = false;
		if (m_Flavors != null && current.length == m_Flavors.length) {
			for (int i = 0; i < m_Flavors.length; ++i)
				if (!current[i].equals(m_Flavors[i]))
					return true;
			m_Flavors = current;
		} else
			changed = true;
		return true;
	}

	/* package */void startClipboardDaemon(int period) {

		Timer daemon = new Timer(true);
		daemon.schedule(new TimerTask() {
			@Override
			public void run() {
				javax.swing.SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						if (isFlavorsChanged())
							fireFlavorsChanged();
					}
				});
			}
		}, period, period);
	}
}



_______________________________________________
Do not post admin requests to the list. They will be ignored.
Java-dev mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/java-dev/email@hidden

This email sent to email@hidden


Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2007 Apple Inc. All rights reserved.