Initial revision
From-SVN: r104578
This commit is contained in:
parent
acff2da93c
commit
9b044d1951
495 changed files with 82760 additions and 0 deletions
664
libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java
Normal file
664
libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java
Normal file
|
@ -0,0 +1,664 @@
|
|||
/* GtkClipboard.java - Class representing gtk+ clipboard selection.
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import gnu.classpath.Pointer;
|
||||
|
||||
import java.awt.datatransfer.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
import java.awt.Image;
|
||||
|
||||
/**
|
||||
* Class representing the gtk+ clipboard selection. This is used when
|
||||
* another program owns the clipboard. Whenever the system clipboard
|
||||
* selection changes we create a new instance to notify the program
|
||||
* that the available flavors might have changed. When requested it
|
||||
* (lazily) caches the targets, and (text, image, or files/uris)
|
||||
* clipboard contents.
|
||||
*
|
||||
* XXX - should only cache when
|
||||
* gdk_display_supports_selection_notification is true.
|
||||
*/
|
||||
public class GtkSelection implements Transferable
|
||||
{
|
||||
/**
|
||||
* Static lock used for requests of mimetypes and contents retrieval.
|
||||
*/
|
||||
static private Object requestLock = new Object();
|
||||
|
||||
/**
|
||||
* Whether a request for mimetypes, text, images, uris or byte[] is
|
||||
* currently in progress. Should only be tested or set with
|
||||
* requestLock held. When true no other requests should be made till
|
||||
* it is false again.
|
||||
*/
|
||||
private boolean requestInProgress;
|
||||
|
||||
/**
|
||||
* Indicates a requestMimeTypes() call was made and the
|
||||
* corresponding mimeTypesAvailable() callback was triggered.
|
||||
*/
|
||||
private boolean mimeTypesDelivered;
|
||||
|
||||
/**
|
||||
* Set and returned by getTransferDataFlavors. Only valid when
|
||||
* mimeTypesDelivered is true.
|
||||
*/
|
||||
private DataFlavor[] dataFlavors;
|
||||
|
||||
/**
|
||||
* Indicates a requestText() call was made and the corresponding
|
||||
* textAvailable() callback was triggered.
|
||||
*/
|
||||
private boolean textDelivered;
|
||||
|
||||
/**
|
||||
* Set as response to a requestText() call and possibly returned by
|
||||
* getTransferData() for text targets. Only valid when textDelivered
|
||||
* is true.
|
||||
*/
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* Indicates a requestImage() call was made and the corresponding
|
||||
* imageAvailable() callback was triggered.
|
||||
*/
|
||||
private boolean imageDelivered;
|
||||
|
||||
/**
|
||||
* Set as response to a requestImage() call and possibly returned by
|
||||
* getTransferData() for image targets. Only valid when
|
||||
* imageDelivered is true and image is null.
|
||||
*/
|
||||
private Pointer imagePointer;
|
||||
|
||||
/**
|
||||
* Cached image value. Only valid when imageDelivered is
|
||||
* true. Created from imagePointer.
|
||||
*/
|
||||
private Image image;
|
||||
|
||||
/**
|
||||
* Indicates a requestUris() call was made and the corresponding
|
||||
* urisAvailable() callback was triggered.
|
||||
*/
|
||||
private boolean urisDelivered;
|
||||
|
||||
/**
|
||||
* Set as response to a requestURIs() call. Only valid when
|
||||
* urisDelivered is true
|
||||
*/
|
||||
private List uris;
|
||||
|
||||
/**
|
||||
* Indicates a requestBytes(String) call was made and the
|
||||
* corresponding bytesAvailable() callback was triggered.
|
||||
*/
|
||||
private boolean bytesDelivered;
|
||||
|
||||
/**
|
||||
* Set as response to a requestBytes(String) call. Only valid when
|
||||
* bytesDelivered is true.
|
||||
*/
|
||||
private byte[] bytes;
|
||||
|
||||
/**
|
||||
* Should only be created by the GtkClipboard class.
|
||||
*/
|
||||
GtkSelection()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of mime-type strings from the gtk+ clipboard and
|
||||
* transforms them into an array of DataFlavors.
|
||||
*/
|
||||
public DataFlavor[] getTransferDataFlavors()
|
||||
{
|
||||
DataFlavor[] result;
|
||||
synchronized (requestLock)
|
||||
{
|
||||
// Did we request already and cache the result?
|
||||
if (mimeTypesDelivered)
|
||||
result = (DataFlavor[]) dataFlavors.clone();
|
||||
else
|
||||
{
|
||||
// Wait till there are no pending requests.
|
||||
while (requestInProgress)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
// If nobody else beat us and cached the result we try
|
||||
// ourselves to get it.
|
||||
if (! mimeTypesDelivered)
|
||||
{
|
||||
requestInProgress = true;
|
||||
requestMimeTypes();
|
||||
while (! mimeTypesDelivered)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
requestInProgress = false;
|
||||
}
|
||||
result = dataFlavors;
|
||||
if (! GtkClipboard.canCache)
|
||||
{
|
||||
dataFlavors = null;
|
||||
mimeTypesDelivered = false;
|
||||
}
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that sets the available DataFlavors[]. Note that this
|
||||
* should not call any code that could need the main gdk lock.
|
||||
*/
|
||||
private void mimeTypesAvailable(String[] mimeTypes)
|
||||
{
|
||||
synchronized (requestLock)
|
||||
{
|
||||
if (mimeTypes == null)
|
||||
dataFlavors = new DataFlavor[0];
|
||||
else
|
||||
{
|
||||
// Most likely the mimeTypes include text in which case we add an
|
||||
// extra element.
|
||||
ArrayList flavorsList = new ArrayList(mimeTypes.length + 1);
|
||||
for (int i = 0; i < mimeTypes.length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mimeTypes[i] == GtkClipboard.stringMimeType)
|
||||
{
|
||||
// XXX - Fix DataFlavor.getTextPlainUnicodeFlavor()
|
||||
// and also add it to the list.
|
||||
flavorsList.add(DataFlavor.stringFlavor);
|
||||
flavorsList.add(DataFlavor.plainTextFlavor);
|
||||
}
|
||||
else if (mimeTypes[i] == GtkClipboard.imageMimeType)
|
||||
flavorsList.add(DataFlavor.imageFlavor);
|
||||
else if (mimeTypes[i] == GtkClipboard.filesMimeType)
|
||||
flavorsList.add(DataFlavor.javaFileListFlavor);
|
||||
else
|
||||
{
|
||||
// We check the target to prevent duplicates
|
||||
// of the "magic" targets above.
|
||||
DataFlavor target = new DataFlavor(mimeTypes[i]);
|
||||
if (! flavorsList.contains(target))
|
||||
flavorsList.add(target);
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException cnfe)
|
||||
{
|
||||
cnfe.printStackTrace();
|
||||
}
|
||||
catch (NullPointerException npe)
|
||||
{
|
||||
npe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
dataFlavors = new DataFlavor[flavorsList.size()];
|
||||
flavorsList.toArray(dataFlavors);
|
||||
}
|
||||
|
||||
mimeTypesDelivered = true;
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the available data flavors for this selection and checks
|
||||
* that at least one of them is equal to the given DataFlavor.
|
||||
*/
|
||||
public boolean isDataFlavorSupported(DataFlavor flavor)
|
||||
{
|
||||
DataFlavor[] dfs = getTransferDataFlavors();
|
||||
for (int i = 0; i < dfs.length; i++)
|
||||
if (flavor.equals(dfs[i]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that tests whether we already have the text for the
|
||||
* current gtk+ selection on the clipboard and if not requests it
|
||||
* and waits till it is available.
|
||||
*/
|
||||
private String getText()
|
||||
{
|
||||
String result;
|
||||
synchronized (requestLock)
|
||||
{
|
||||
// Did we request already and cache the result?
|
||||
if (textDelivered)
|
||||
result = text;
|
||||
else
|
||||
{
|
||||
// Wait till there are no pending requests.
|
||||
while (requestInProgress)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
// If nobody else beat us we try ourselves to get and
|
||||
// caching the result.
|
||||
if (! textDelivered)
|
||||
{
|
||||
requestInProgress = true;
|
||||
requestText();
|
||||
while (! textDelivered)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
requestInProgress = false;
|
||||
}
|
||||
result = text;
|
||||
if (! GtkClipboard.canCache)
|
||||
{
|
||||
text = null;
|
||||
textDelivered = false;
|
||||
}
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that sets the available text on the clipboard. Note that
|
||||
* this should not call any code that could need the main gdk lock.
|
||||
*/
|
||||
private void textAvailable(String text)
|
||||
{
|
||||
synchronized (requestLock)
|
||||
{
|
||||
this.text = text;
|
||||
textDelivered = true;
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that tests whether we already have an image for the
|
||||
* current gtk+ selection on the clipboard and if not requests it
|
||||
* and waits till it is available.
|
||||
*/
|
||||
private Image getImage()
|
||||
{
|
||||
Image result;
|
||||
synchronized (requestLock)
|
||||
{
|
||||
// Did we request already and cache the result?
|
||||
if (imageDelivered)
|
||||
result = image;
|
||||
else
|
||||
{
|
||||
// Wait till there are no pending requests.
|
||||
while (requestInProgress)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
// If nobody else beat us we try ourselves to get and
|
||||
// caching the result.
|
||||
if (! imageDelivered)
|
||||
{
|
||||
requestInProgress = true;
|
||||
requestImage();
|
||||
while (! imageDelivered)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
requestInProgress = false;
|
||||
}
|
||||
if (imagePointer != null)
|
||||
image = new GtkImage(imagePointer);
|
||||
imagePointer = null;
|
||||
result = image;
|
||||
if (! GtkClipboard.canCache)
|
||||
{
|
||||
image = null;
|
||||
imageDelivered = false;
|
||||
}
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that sets the available image on the clipboard. Note
|
||||
* that this should not call any code that could need the main gdk
|
||||
* lock. Note that we get a Pointer to a GdkPixbuf which we cannot
|
||||
* turn into a real GtkImage at this point. That will be done on the
|
||||
* "user thread" in getImage().
|
||||
*/
|
||||
private void imageAvailable(Pointer pointer)
|
||||
{
|
||||
synchronized (requestLock)
|
||||
{
|
||||
this.imagePointer = pointer;
|
||||
imageDelivered = true;
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that test whether we already have a list of
|
||||
* URIs/Files and if not requests them and waits till they are
|
||||
* available.
|
||||
*/
|
||||
private List getURIs()
|
||||
{
|
||||
List result;
|
||||
synchronized (requestLock)
|
||||
{
|
||||
// Did we request already and cache the result?
|
||||
if (urisDelivered)
|
||||
result = uris;
|
||||
else
|
||||
{
|
||||
// Wait till there are no pending requests.
|
||||
while (requestInProgress)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
// If nobody else beat us we try ourselves to get and
|
||||
// caching the result.
|
||||
if (! urisDelivered)
|
||||
{
|
||||
requestInProgress = true;
|
||||
requestURIs();
|
||||
while (! urisDelivered)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
requestInProgress = false;
|
||||
}
|
||||
result = uris;
|
||||
if (! GtkClipboard.canCache)
|
||||
{
|
||||
uris = null;
|
||||
urisDelivered = false;
|
||||
}
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that sets the available File list. Note that this should
|
||||
* not call any code that could need the main gdk lock.
|
||||
*/
|
||||
private void urisAvailable(String[] uris)
|
||||
{
|
||||
synchronized (requestLock)
|
||||
{
|
||||
if (uris != null && uris.length != 0)
|
||||
{
|
||||
ArrayList list = new ArrayList(uris.length);
|
||||
for (int i = 0; i < uris.length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
URI uri = new URI(uris[i]);
|
||||
if (uri.getScheme().equals("file"))
|
||||
list.add(new File(uri));
|
||||
}
|
||||
catch (URISyntaxException use)
|
||||
{
|
||||
}
|
||||
}
|
||||
this.uris = list;
|
||||
}
|
||||
|
||||
urisDelivered = true;
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that requests a byte[] for the given target
|
||||
* mime-type flavor and waits till it is available. Note that unlike
|
||||
* the other get methods this one doesn't cache the result since
|
||||
* there are possibly many targets.
|
||||
*/
|
||||
private byte[] getBytes(String target)
|
||||
{
|
||||
byte[] result;
|
||||
synchronized (requestLock)
|
||||
{
|
||||
// Wait till there are no pending requests.
|
||||
while (requestInProgress)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
// Request bytes and wait till they are available.
|
||||
requestInProgress = true;
|
||||
requestBytes(target);
|
||||
while (! bytesDelivered)
|
||||
{
|
||||
try
|
||||
{
|
||||
requestLock.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
result = bytes;
|
||||
bytes = null;
|
||||
bytesDelivered = false;
|
||||
requestInProgress = false;
|
||||
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that sets the available byte array on the
|
||||
* clipboard. Note that this should not call any code that could
|
||||
* need the main gdk lock.
|
||||
*/
|
||||
private void bytesAvailable(byte[] bytes)
|
||||
{
|
||||
synchronized (requestLock)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
bytesDelivered = true;
|
||||
requestLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public Object getTransferData(DataFlavor flavor)
|
||||
throws UnsupportedFlavorException
|
||||
{
|
||||
// Note the fall throughs for the "magic targets" if they fail we
|
||||
// try one more time through getBytes().
|
||||
if (flavor.equals(DataFlavor.stringFlavor))
|
||||
{
|
||||
String text = getText();
|
||||
if (text != null)
|
||||
return text;
|
||||
}
|
||||
|
||||
if (flavor.equals(DataFlavor.plainTextFlavor))
|
||||
{
|
||||
String text = getText();
|
||||
if (text != null)
|
||||
return new StringBufferInputStream(text);
|
||||
}
|
||||
|
||||
if (flavor.equals(DataFlavor.imageFlavor))
|
||||
{
|
||||
Image image = getImage();
|
||||
if (image != null)
|
||||
return image;
|
||||
}
|
||||
|
||||
if (flavor.equals(DataFlavor.javaFileListFlavor))
|
||||
{
|
||||
List uris = getURIs();
|
||||
if (uris != null)
|
||||
return uris;
|
||||
}
|
||||
|
||||
byte[] bytes = getBytes(flavor.getMimeType());
|
||||
if (bytes == null)
|
||||
throw new UnsupportedFlavorException(flavor);
|
||||
|
||||
if (flavor.isMimeTypeSerializedObject())
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
return ois.readObject();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
catch (ClassNotFoundException cnfe)
|
||||
{
|
||||
cnfe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (flavor.isRepresentationClassInputStream())
|
||||
return new ByteArrayInputStream(bytes);
|
||||
|
||||
// XXX, need some more conversions?
|
||||
|
||||
throw new UnsupportedFlavorException(flavor);
|
||||
}
|
||||
|
||||
/*
|
||||
* Requests text, Image or an byte[] for a particular target from the
|
||||
* other application. These methods return immediately. When the
|
||||
* content is available the contentLock will be notified through
|
||||
* textAvailable, imageAvailable, urisAvailable or bytesAvailable and the
|
||||
* appropriate field is set.
|
||||
*/
|
||||
private native void requestText();
|
||||
private native void requestImage();
|
||||
private native void requestURIs();
|
||||
private native void requestBytes(String target);
|
||||
|
||||
/* Similar to the above but for requesting the supported targets. */
|
||||
private native void requestMimeTypes();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue