summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--gnu/java/awt/peer/gtk/GtkClipboard.java390
-rw-r--r--gnu/java/awt/peer/gtk/GtkClipboardNotifier.java112
-rw-r--r--gnu/java/awt/peer/gtk/GtkImage.java19
-rw-r--r--gnu/java/awt/peer/gtk/GtkSelection.java664
-rw-r--r--gnu/java/awt/peer/gtk/GtkToolkit.java8
-rw-r--r--include/Makefile.am1
-rw-r--r--include/gnu_java_awt_peer_gtk_GtkClipboard.h7
-rw-r--r--include/gnu_java_awt_peer_gtk_GtkImage.h1
-rw-r--r--include/gnu_java_awt_peer_gtk_GtkSelection.h23
-rw-r--r--native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c772
-rw-r--r--native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c13
12 files changed, 1838 insertions, 192 deletions
diff --git a/ChangeLog b/ChangeLog
index 6d38131d2..dc08abbc0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2005-08-16 Mark Wielaard <mark@klomp.org>
+
+ * gnu/java/awt/peer/gtk/GtkClipboard.java: Reimplemented.
+ * gnu/java/awt/peer/gtk/GtkClipboardNotifier.java: New class.
+ * gnu/java/awt/peer/gtk/GtkSelection.java: New class.
+ * gnu/java/awt/peer/gtk/GtkImage.java (GtkImage(Pointer)): New
+ constructor.
+ (createFromPixbuf): New private native method.
+ * gnu/java/awt/peer/gtk/GtkToolkit.java (systemClipboard): Removed.
+ (getSystemClipboard): Do security check and return
+ GtkClipboard.getInstance().
+ * include/Makefile.am: Add gnu_java_awt_peer_gtk_GtkSelection.h.
+ * include/gnu_java_awt_peer_gtk_GtkClipboard.h: Regenerated.
+ * include/gnu_java_awt_peer_gtk_GtkImage.h: Regenerated.
+ * include/gnu_java_awt_peer_gtk_GtkSelection.h: New header file.
+ * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c:
+ Reimplemented.
+ * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c
+ (Java_gnu_java_awt_peer_gtk_GtkImage_createFromPixbuf): New
+
2005-08-16 Anthony Balkissoon <abalkiss@redhat.com>
* javax/swing/plaf/basic/BasicTableUI.java:
diff --git a/gnu/java/awt/peer/gtk/GtkClipboard.java b/gnu/java/awt/peer/gtk/GtkClipboard.java
index c719cddb5..a502e1fd6 100644
--- a/gnu/java/awt/peer/gtk/GtkClipboard.java
+++ b/gnu/java/awt/peer/gtk/GtkClipboard.java
@@ -38,133 +38,357 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.ClipboardOwner;
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+import java.awt.Image;
+import java.awt.datatransfer.*;
+
+import java.io.*;
+
+import java.util.List;
+import java.util.Iterator;
public class GtkClipboard extends Clipboard
{
- /* the number of milliseconds that we'll wait around for the
- owner of the GDK_SELECTION_PRIMARY selection to convert
- the requested data */
- static final int SELECTION_RECEIVED_TIMEOUT = 5000;
- /* We currently only support transferring of text between applications */
- static String selection;
- static Object selectionLock = new Object ();
+ // Given to the native side so it can signal special targets that
+ // can be converted to one of the special predefined DataFlavors.
+ static final String stringMimeType;
+ static final String imageMimeType;
+ static final String filesMimeType;
+
+ // Indicates whether the results of the clipboard selection can be
+ // cached by GtkSelection. True if
+ // gdk_display_supports_selection_notification.
+ static final boolean canCache;
+
+ static
+ {
+ stringMimeType = DataFlavor.stringFlavor.getMimeType();
+ imageMimeType = DataFlavor.imageFlavor.getMimeType();
+ filesMimeType = DataFlavor.javaFileListFlavor.getMimeType();
+
+ canCache = initNativeState(stringMimeType, imageMimeType, filesMimeType);
+ }
- static boolean hasSelection = false;
+ /**
+ * The one and only gtk+ clipboard instance.
+ */
+ private static GtkClipboard instance = new GtkClipboard();
- protected GtkClipboard()
+ /**
+ * Creates the clipboard and sets the initial contents to the
+ * current gtk+ selection.
+ */
+ private GtkClipboard()
{
super("System Clipboard");
- initNativeState();
+ setContents(new GtkSelection(), null);
+ }
+
+ /**
+ * Returns the one and only GtkClipboard instance.
+ */
+
+ static GtkClipboard getInstance()
+ {
+ return instance;
}
- public Transferable getContents(Object requestor)
+ /**
+ * Sets the GtkSelection facade as new contents of the clipboard.
+ * Called from gtk+ when another application grabs the clipboard and
+ * we loose ownership.
+ */
+ private static void setSystemContents()
{
- synchronized (this)
+ GtkClipboardNotifier.announce();
+ }
+
+ /**
+ * Sets the new contents and advertises the available flavors to the
+ * gtk+ clipboard.
+ */
+ public synchronized void setContents(Transferable contents,
+ ClipboardOwner owner)
+ {
+ super.setContents(contents, owner);
+
+ if (contents == null)
{
- if (hasSelection)
- return contents;
+ advertiseContent(null, false, false, false);
+ return;
}
- /* Java doesn't own the selection, so we need to ask X11 */
- // XXX: Does this hold with Swing too ?
- synchronized (selectionLock)
+ // We don't need to do anything for a GtkSelection facade.
+ if (contents instanceof GtkSelection)
+ return;
+
+ boolean text = false;
+ boolean images = false;
+ boolean files = false;
+
+ if (contents instanceof StringSelection
+ || contents.isDataFlavorSupported(DataFlavor.stringFlavor)
+ || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor)
+ || contents.isDataFlavorSupported(DataFlavor
+ .getTextPlainUnicodeFlavor()))
+ text = true;
+
+ DataFlavor[] flavors = contents.getTransferDataFlavors();
+ String[] mimeTargets = new String[flavors.length];
+ for (int i = 0; i < flavors.length; i++)
{
- requestStringConversion();
-
- try
- {
- selectionLock.wait(SELECTION_RECEIVED_TIMEOUT);
- }
- catch (InterruptedException e)
+ DataFlavor flavor = flavors[i];
+ String mimeType = flavor.getMimeType();
+ mimeTargets[i] = mimeType;
+
+ if (! text)
+ if ("text".equals(flavor.getPrimaryType())
+ || flavor.isRepresentationClassReader())
+ text = true;
+
+ // XXX - We only support automatic image conversion for
+ // GtkImages at the moment. So explicitly check that we have
+ // one.
+ if (! images && flavors[i].equals(DataFlavor.imageFlavor))
{
- return null;
+ try
+ {
+ Object o = contents.getTransferData(DataFlavor.imageFlavor);
+ if (o instanceof GtkImage)
+ images = true;
+ }
+ catch (UnsupportedFlavorException ufe)
+ {
+ }
+ catch (IOException ioe)
+ {
+ }
+ catch (ClassCastException cce)
+ {
+ }
}
-
- return selection == null ? null : new StringSelection(selection);
+
+ if (flavors[i].equals(DataFlavor.javaFileListFlavor))
+ files = true;
}
+
+ advertiseContent(mimeTargets, text, images, files);
}
- void stringSelectionReceived(String newSelection)
+ /**
+ * Advertises new contents to the gtk+ clipboard given a string
+ * array of (mime-type) targets. When the boolean flags text, images
+ * and/or files are set then gtk+ is asked to also advertise the
+ * availability of any text, image or uri/file content types it
+ * supports. If targets is null (and all flags false) then the
+ * selection has explicitly been erased.
+ */
+ private native void advertiseContent(String[] targets,
+ boolean text,
+ boolean images,
+ boolean files);
+
+ /**
+ * Called by the gtk+ clipboard when an application has requested
+ * text. Return a string representing the current clipboard
+ * contents or null when no text can be provided.
+ */
+ private String provideText()
{
- synchronized (selectionLock)
+ Transferable contents = this.contents;
+ if (contents == null || contents instanceof GtkSelection)
+ return null;
+
+ // Handle StringSelection special since that is just pure text.
+ if (contents instanceof StringSelection)
{
- selection = newSelection;
- selectionLock.notify();
+ try
+ {
+ return (String) contents.getTransferData(DataFlavor.stringFlavor);
+ }
+ catch (UnsupportedFlavorException ufe)
+ {
+ }
+ catch (IOException ioe)
+ {
+ }
+ catch (ClassCastException cce)
+ {
+ }
}
- }
-
- /* convert Java clipboard data into a String suitable for sending
- to another application */
- synchronized String stringSelectionHandler() throws IOException
- {
- String selection = null;
+ // Try to get a plain text reader for the current contents and
+ // turn the result into a string.
try
{
- if (contents.isDataFlavorSupported(DataFlavor.stringFlavor))
- selection = (String)contents.getTransferData(DataFlavor.stringFlavor);
- else if (contents.isDataFlavorSupported(DataFlavor.plainTextFlavor))
+ DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor();
+ Reader r = plainText.getReaderForText(contents);
+ if (r != null)
{
- StringBuffer sbuf = new StringBuffer();
- InputStreamReader reader;
- char readBuf[] = new char[512];
- int numChars;
-
- reader = new InputStreamReader
- ((InputStream)
- contents.getTransferData(DataFlavor.plainTextFlavor), "UNICODE");
-
- while (true)
+ StringBuffer sb = new StringBuffer();
+ char[] cs = new char[1024];
+ int l = r.read(cs);
+ while (l != -1)
{
- numChars = reader.read(readBuf);
- if (numChars == -1)
- break;
- sbuf.append(readBuf, 0, numChars);
+ sb.append(cs, 0, l);
+ l = r.read(cs);
}
-
- selection = new String(sbuf);
+ return sb.toString();
}
}
- catch (Exception e)
+ catch (IllegalArgumentException iae)
+ {
+ }
+ catch (UnsupportedEncodingException iee)
{
}
-
- return selection;
+ catch (UnsupportedFlavorException ufe)
+ {
+ }
+ catch (IOException ioe)
+ {
+ }
+
+ return null;
}
- public synchronized void setContents(Transferable contents,
- ClipboardOwner owner)
+ /**
+ * Called by the gtk+ clipboard when an application has requested an
+ * image. Returns a GtkImage representing the current clipboard
+ * contents or null when no image can be provided.
+ */
+ private GtkImage provideImage()
+ {
+ Transferable contents = this.contents;
+ if (contents == null || contents instanceof GtkSelection)
+ return null;
+
+ try
+ {
+ return (GtkImage) contents.getTransferData(DataFlavor.imageFlavor);
+ }
+ catch (UnsupportedFlavorException ufe)
+ {
+ }
+ catch (IOException ioe)
+ {
+ }
+ catch (ClassCastException cce)
+ {
+ }
+
+ return null;
+ }
+
+ /**
+ * Called by the gtk+ clipboard when an application has requested a
+ * uri-list. Return a string array containing the URIs representing
+ * the current clipboard contents or null when no URIs can be
+ * provided.
+ */
+ private String[] provideURIs()
{
- selectionGet();
+ Transferable contents = this.contents;
+ if (contents == null || contents instanceof GtkSelection)
+ return null;
- this.contents = contents;
- this.owner = owner;
+ try
+ {
+ List list = (List) contents.getTransferData
+ (DataFlavor.javaFileListFlavor);
+ String[] uris = new String[list.size()];
+ int u = 0;
+ Iterator it = list.iterator();
+ while (it.hasNext())
+ uris[u++] = ((File) it.next()).toURI().toString();
+ return uris;
+ }
+ catch (UnsupportedFlavorException ufe)
+ {
+ }
+ catch (IOException ioe)
+ {
+ }
+ catch (ClassCastException cce)
+ {
+ }
- hasSelection = true;
+ return null;
}
- synchronized void selectionClear()
+ /**
+ * Called by gtk+ clipboard when an application requests the given
+ * target mime-type. Returns a byte array containing the requested
+ * data, or null when the contents cannot be provided in the
+ * requested target mime-type. Only called after any explicit text,
+ * image or file/uri requests have been handled earlier and failed.
+ */
+ private byte[] provideContent(String target)
{
- hasSelection = false;
+ // Sanity check. The callback could be triggered just after we
+ // changed the clipboard.
+ Transferable contents = this.contents;
+ if (contents == null || contents instanceof GtkSelection)
+ return null;
+
+ // XXX - We are being called from a gtk+ callback. Which means we
+ // should return as soon as possible and not call arbitrary code
+ // that could deadlock or go bonkers. But we don't really know
+ // what DataTransfer contents object we are dealing with. Same for
+ // the other provideXXX() methods.
+ try
+ {
+ DataFlavor flavor = new DataFlavor(target);
+ Object o = contents.getTransferData(flavor);
+
+ if (o instanceof byte[])
+ return (byte[]) o;
+
+ if (o instanceof InputStream)
+ {
+ InputStream is = (InputStream) o;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] bs = new byte[1024];
+ int l = is.read(bs);
+ while (l != -1)
+ {
+ baos.write(bs, 0, l);
+ l = is.read(bs);
+ }
+ return baos.toByteArray();
+ }
- if (owner != null)
+ if (o instanceof Serializable)
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(o);
+ oos.close();
+ return baos.toByteArray();
+ }
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ }
+ catch (UnsupportedFlavorException ufe)
{
- owner.lostOwnership(this, contents);
- owner = null;
- contents = null;
}
+ catch (IOException ioe)
+ {
+ }
+ catch (ClassCastException cce)
+ {
+ }
+
+ return null;
}
- native void initNativeState();
- static native void requestStringConversion();
- static native void selectionGet();
+ /**
+ * Initializes the gtk+ clipboard and caches any native side
+ * structures needed. Returns whether or not the contents of the
+ * Clipboard can be cached (gdk_display_supports_selection_notification).
+ */
+ private static native boolean initNativeState(String stringTarget,
+ String imageTarget,
+ String filesTarget);
}
diff --git a/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java b/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java
new file mode 100644
index 000000000..a470fe171
--- /dev/null
+++ b/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java
@@ -0,0 +1,112 @@
+/* GtkClipboardNotifier.java -- Helper for announcing GtkSelection changes.
+ 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 java.awt.datatransfer.*;
+
+class GtkClipboardNotifier extends Thread
+{
+ /** Whether or not to announce a GtkSelection change. */
+ private static boolean announceChange;
+
+ /**
+ * The one and only instance. All operations are synchronized on
+ * this.
+ */
+ private static GtkClipboardNotifier notifier = new GtkClipboardNotifier();
+
+ /**
+ * Creates a deamon thread that monitors this for change
+ * announcements.
+ */
+ private GtkClipboardNotifier()
+ {
+ super("GtkClipBoardNotifier");
+ setDaemon(true);
+ start();
+ }
+
+ /**
+ * Notifies that a new GtkSelection has to be announced.
+ */
+ static void announce()
+ {
+ synchronized (notifier)
+ {
+ announceChange = true;
+ notifier.notifyAll();
+ }
+ }
+
+ public void run()
+ {
+ final GtkClipboard clipboard = GtkClipboard.getInstance();
+ while (true)
+ {
+ synchronized (this)
+ {
+ while (!announceChange)
+ {
+ try
+ {
+ this.wait();
+ }
+ catch (InterruptedException ie)
+ {
+ // ignore
+ }
+ }
+ announceChange = false;
+ }
+
+ // Do the actual announcement without the lock held. We will
+ // notice a new change after this notification has finished.
+ try
+ {
+ clipboard.setContents(new GtkSelection(), null);
+ }
+ catch (Throwable t)
+ {
+ // should never happen, but might if we have some faulty
+ // listener.
+ t.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/gnu/java/awt/peer/gtk/GtkImage.java b/gnu/java/awt/peer/gtk/GtkImage.java
index ad5988ea2..b1e72bb8c 100644
--- a/gnu/java/awt/peer/gtk/GtkImage.java
+++ b/gnu/java/awt/peer/gtk/GtkImage.java
@@ -241,6 +241,25 @@ public class GtkImage extends Image
}
/**
+ * Package private constructor to create a GtkImage from a given
+ * PixBuf pointer.
+ */
+ GtkImage (Pointer pixbuf)
+ {
+ pixmap = pixbuf;
+ createFromPixbuf();
+ isLoaded = true;
+ observers = null;
+ offScreen = false;
+ props = new Hashtable();
+ }
+
+ /**
+ * Native helper function for constructor that takes a pixbuf Pointer.
+ */
+ private native void createFromPixbuf();
+
+ /**
* Callback from the image consumer.
*/
public void setImage(int width, int height,
diff --git a/gnu/java/awt/peer/gtk/GtkSelection.java b/gnu/java/awt/peer/gtk/GtkSelection.java
new file mode 100644
index 000000000..cb5db04e9
--- /dev/null
+++ b/gnu/java/awt/peer/gtk/GtkSelection.java
@@ -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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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();
+}
diff --git a/gnu/java/awt/peer/gtk/GtkToolkit.java b/gnu/java/awt/peer/gtk/GtkToolkit.java
index 46ff329c4..ef97685a3 100644
--- a/gnu/java/awt/peer/gtk/GtkToolkit.java
+++ b/gnu/java/awt/peer/gtk/GtkToolkit.java
@@ -88,7 +88,6 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
{
Hashtable containers = new Hashtable();
static EventQueue q;
- static Clipboard systemClipboard;
static boolean useGraphics2dSet;
static boolean useGraphics2d;
@@ -136,7 +135,6 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
public GtkToolkit ()
{
- systemClipboard = new GtkClipboard ();
}
public native void beep();
@@ -406,7 +404,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
public Clipboard getSystemClipboard()
{
- return systemClipboard;
+ SecurityManager secman = System.getSecurityManager();
+ if (secman != null)
+ secman.checkSystemClipboardAccess();
+
+ return GtkClipboard.getInstance();
}
/**
diff --git a/include/Makefile.am b/include/Makefile.am
index 7b698e63b..4a920dff6 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -57,6 +57,7 @@ $(top_srcdir)/include/gnu_java_awt_peer_gtk_GtkPanelPeer.h \
$(top_srcdir)/include/gnu_java_awt_peer_gtk_GtkPopupMenuPeer.h \
$(top_srcdir)/include/gnu_java_awt_peer_gtk_GtkScrollPanePeer.h \
$(top_srcdir)/include/gnu_java_awt_peer_gtk_GtkScrollbarPeer.h \
+$(top_srcdir)/include/gnu_java_awt_peer_gtk_GtkSelection.h \
$(top_srcdir)/include/gnu_java_awt_peer_gtk_GtkTextAreaPeer.h \
$(top_srcdir)/include/gnu_java_awt_peer_gtk_GtkTextFieldPeer.h \
$(top_srcdir)/include/gnu_java_awt_peer_gtk_GtkToolkit.h \
diff --git a/include/gnu_java_awt_peer_gtk_GtkClipboard.h b/include/gnu_java_awt_peer_gtk_GtkClipboard.h
index 709a6c00d..6c76ed8dd 100644
--- a/include/gnu_java_awt_peer_gtk_GtkClipboard.h
+++ b/include/gnu_java_awt_peer_gtk_GtkClipboard.h
@@ -10,11 +10,8 @@ extern "C"
{
#endif
-JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkClipboard_initNativeState (JNIEnv *env, jobject);
-JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkClipboard_requestStringConversion (JNIEnv *env, jclass);
-JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkClipboard_selectionGet (JNIEnv *env, jclass);
-#undef gnu_java_awt_peer_gtk_GtkClipboard_SELECTION_RECEIVED_TIMEOUT
-#define gnu_java_awt_peer_gtk_GtkClipboard_SELECTION_RECEIVED_TIMEOUT 5000L
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkClipboard_advertiseContent (JNIEnv *env, jobject, jobjectArray, jboolean, jboolean, jboolean);
+JNIEXPORT jboolean JNICALL Java_gnu_java_awt_peer_gtk_GtkClipboard_initNativeState (JNIEnv *env, jclass, jstring, jstring, jstring);
#ifdef __cplusplus
}
diff --git a/include/gnu_java_awt_peer_gtk_GtkImage.h b/include/gnu_java_awt_peer_gtk_GtkImage.h
index 7aa1827c8..8ac0a75c3 100644
--- a/include/gnu_java_awt_peer_gtk_GtkImage.h
+++ b/include/gnu_java_awt_peer_gtk_GtkImage.h
@@ -18,6 +18,7 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkImage_freePixmap (JNIEnv *e
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkImage_createScaledPixmap (JNIEnv *env, jobject, jobject, jint);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkImage_drawPixelsScaled (JNIEnv *env, jobject, jobject, jint, jint, jint, jint, jint, jint, jint, jboolean);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkImage_drawPixelsScaledFlipped (JNIEnv *env, jobject, jobject, jint, jint, jint, jboolean, jboolean, jint, jint, jint, jint, jint, jint, jint, jint, jboolean);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkImage_createFromPixbuf (JNIEnv *env, jobject);
#ifdef __cplusplus
}
diff --git a/include/gnu_java_awt_peer_gtk_GtkSelection.h b/include/gnu_java_awt_peer_gtk_GtkSelection.h
new file mode 100644
index 000000000..576e0368d
--- /dev/null
+++ b/include/gnu_java_awt_peer_gtk_GtkSelection.h
@@ -0,0 +1,23 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+
+#ifndef __gnu_java_awt_peer_gtk_GtkSelection__
+#define __gnu_java_awt_peer_gtk_GtkSelection__
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkSelection_requestText (JNIEnv *env, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkSelection_requestImage (JNIEnv *env, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkSelection_requestURIs (JNIEnv *env, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkSelection_requestBytes (JNIEnv *env, jobject, jstring);
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkSelection_requestMimeTypes (JNIEnv *env, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gnu_java_awt_peer_gtk_GtkSelection__ */
diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c
index dea9d4cc7..d4d34227e 100644
--- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c
+++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c
@@ -1,5 +1,5 @@
/* gtkclipboard.c
- Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -36,169 +36,739 @@ obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
+#include "jcl.h"
#include "gtkpeer.h"
#include "gnu_java_awt_peer_gtk_GtkClipboard.h"
+#include "gnu_java_awt_peer_gtk_GtkSelection.h"
-static jmethodID stringSelectionReceivedID;
-static jmethodID stringSelectionHandlerID;
-static jmethodID selectionClearID;
+#define OBJECT_TARGET 1
+#define TEXT_TARGET 2
+#define IMAGE_TARGET 3
+#define URI_TARGET 4
-static void selection_received_cb (GtkWidget *, GtkSelectionData *,
- guint, gpointer);
-static void selection_get_cb (GtkWidget *, GtkSelectionData *, guint,
- guint, gpointer);
-static gint selection_clear_cb (GtkWidget *, GdkEventSelection *);
+static GtkClipboard *clipboard;
-static GtkWidget *clipboard;
-static jobject cb_obj;
+/* Simple id to keep track of the selection we are currently managing. */
+static int current_selection = 0;
-JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GtkClipboard_initNativeState (JNIEnv *env,
- jobject obj)
-{
- gdk_threads_enter ();
+/* Whether we "own" the clipboard. And may clear it. */
+static int owner = 0;
- if (!stringSelectionReceivedID)
- {
- jclass gtkclipboard;
+static jclass gtk_clipboard_class;
+static jmethodID setSystemContentsID;
- gtkclipboard = (*env)->FindClass (env,
- "gnu/java/awt/peer/gtk/GtkClipboard");
- stringSelectionReceivedID = (*env)->GetMethodID (env, gtkclipboard,
- "stringSelectionReceived",
- "(Ljava/lang/String;)V");
- stringSelectionHandlerID = (*env)->GetMethodID (env, gtkclipboard,
- "stringSelectionHandler",
- "()Ljava/lang/String;");
- selectionClearID = (*env)->GetMethodID (env, gtkclipboard,
- "selectionClear", "()V");
- }
+static jobject gtk_clipboard_instance = NULL;
+static jmethodID provideContentID;
+static jmethodID provideTextID;
+static jmethodID provideImageID;
+static jmethodID provideURIsID;
- cb_obj = (*env)->NewGlobalRef (env, obj);
+static jstring stringTarget;
+static jstring imageTarget;
+static jstring filesTarget;
- clipboard = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+static void
+cp_gtk_clipboard_owner_change (GtkClipboard *clipboard __attribute__((unused)),
+ GdkEvent *event __attribute__((unused)),
+ gpointer user_data __attribute__((unused)))
+{
+ /* These are only interesting when we are not the owner. Otherwise
+ we will have the set and clear functions doing the updating. */
+ JNIEnv *env = cp_gtk_gdk_env ();
+ if (!owner)
+ (*env)->CallStaticVoidMethod (env, gtk_clipboard_class,
+ setSystemContentsID);
+}
- g_signal_connect (G_OBJECT(clipboard), "selection_received",
- G_CALLBACK (selection_received_cb), NULL);
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_awt_peer_gtk_GtkClipboard_initNativeState (JNIEnv *env,
+ jclass gtkclipboard,
+ jstring string,
+ jstring image,
+ jstring files)
+{
+ GdkDisplay* display;
+ jboolean can_cache;
- g_signal_connect (G_OBJECT(clipboard), "selection_clear_event",
- G_CALLBACK (selection_clear_cb), NULL);
+ gtk_clipboard_class = gtkclipboard;
+ setSystemContentsID = (*env)->GetStaticMethodID (env, gtk_clipboard_class,
+ "setSystemContents",
+ "()V");
+ if (setSystemContentsID == NULL)
+ return JNI_FALSE;
- gtk_selection_add_target (clipboard, GDK_SELECTION_PRIMARY,
- GDK_TARGET_STRING, 0);
+ stringTarget = (*env)->NewGlobalRef(env, string);
+ imageTarget = (*env)->NewGlobalRef(env, image);
+ filesTarget = (*env)->NewGlobalRef(env, files);
- g_signal_connect (G_OBJECT(clipboard), "selection_get",
- G_CALLBACK (selection_get_cb), NULL);
+ gdk_threads_enter ();
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ display = gtk_clipboard_get_display (clipboard);
+ if (gdk_display_supports_selection_notification (display))
+ {
+ g_signal_connect (clipboard, "owner-change",
+ G_CALLBACK (cp_gtk_clipboard_owner_change), NULL);
+ gdk_display_request_selection_notification (display,
+ GDK_SELECTION_CLIPBOARD);
+ can_cache = JNI_TRUE;
+ }
+ else
+ can_cache = JNI_FALSE;
gdk_threads_leave ();
+
+ return can_cache;
+}
+
+static void
+cp_gtk_clipboard_get_func (GtkClipboard *clipboard __attribute__((unused)),
+ GtkSelectionData *selection,
+ guint info,
+ gpointer user_data __attribute__((unused)))
+{
+ JNIEnv *env = cp_gtk_gdk_env ();
+
+ if (info == OBJECT_TARGET)
+ {
+ const gchar *target_name;
+ jstring target_string;
+ jbyteArray bytes;
+ jint len;
+ jbyte *barray;
+
+ target_name = gdk_atom_name (selection->target);
+ if (target_name == NULL)
+ return;
+ target_string = (*env)->NewStringUTF (env, target_name);
+ if (target_string == NULL)
+ return;
+ bytes = (*env)->CallObjectMethod(env,
+ gtk_clipboard_instance,
+ provideContentID,
+ target_string);
+ if (bytes == NULL)
+ return;
+ len = (*env)->GetArrayLength(env, bytes);
+ if (len <= 0)
+ return;
+ barray = (*env)->GetByteArrayElements(env, bytes, NULL);
+ if (barray == NULL)
+ return;
+ gtk_selection_data_set (selection, selection->target, 8,
+ (guchar *) barray, len);
+
+ (*env)->ReleaseByteArrayElements(env, bytes, barray, 0);
+
+ }
+ else if (info == TEXT_TARGET)
+ {
+ jstring string;
+ const gchar *text;
+ int len;
+ string = (*env)->CallObjectMethod(env,
+ gtk_clipboard_instance,
+ provideTextID);
+ if (string == NULL)
+ return;
+ len = (*env)->GetStringUTFLength (env, string);
+ if (len == -1)
+ return;
+ text = (*env)->GetStringUTFChars (env, string, NULL);
+ if (text == NULL)
+ return;
+
+ gtk_selection_data_set_text (selection, text, len);
+ (*env)->ReleaseStringUTFChars (env, string, text);
+ }
+ else if (info == IMAGE_TARGET)
+ {
+ jobject gtkimage;
+ GdkPixbuf *pixbuf = NULL;
+
+ gtkimage = (*env)->CallObjectMethod(env,
+ gtk_clipboard_instance,
+ provideImageID);
+ if (gtkimage == NULL)
+ return;
+
+ pixbuf = cp_gtk_image_get_pixbuf (env, gtkimage);
+ if (pixbuf != NULL)
+ {
+ gtk_selection_data_set_pixbuf (selection, pixbuf);
+
+ /* if the GtkImage is offscreen, this is a temporary pixbuf
+ which should be thrown out. */
+ if(cp_gtk_image_is_offscreen (env, gtkimage) == JNI_TRUE)
+ gdk_pixbuf_unref (pixbuf);
+ }
+ }
+ else if (info == URI_TARGET)
+ {
+ jobjectArray uris;
+ jint count;
+ int i;
+ gchar **list;
+
+ uris = (*env)->CallObjectMethod(env,
+ gtk_clipboard_instance,
+ provideURIsID);
+ if (uris == NULL)
+ return;
+ count = (*env)->GetArrayLength (env, uris);
+ if (count <= 0)
+ return;
+
+ list = (gchar **) JCL_malloc (env, (count + 1) * sizeof (gchar *));
+ for (i = 0; i < count; i++)
+ {
+ const char *text;
+ jstring uri;
+
+ /* Mark NULL in so case of some error we can find the end. */
+ list[i] = NULL;
+ uri = (*env)->GetObjectArrayElement (env, uris, i);
+ if (uri == NULL)
+ break;
+ text = (*env)->GetStringUTFChars (env, uri, NULL);
+ if (text == NULL)
+ break;
+ list[i] = strdup (text);
+ (*env)->ReleaseStringUTFChars (env, uri, text);
+ }
+
+ if (i == count)
+ {
+ list[count] = NULL;
+ gtk_selection_data_set_uris (selection, list);
+ }
+
+ for (i = 0; list[i] != NULL; i++)
+ free (list[i]);
+ JCL_free (env, list);
+ }
+}
+
+static void
+cp_gtk_clipboard_clear_func (GtkClipboard *clipboard __attribute__((unused)),
+ gpointer user_data)
+{
+ if (owner && (int) user_data == current_selection)
+ {
+ JNIEnv *env = cp_gtk_gdk_env();
+ owner = 0;
+ (*env)->CallStaticVoidMethod (env, gtk_clipboard_class,
+ setSystemContentsID);
+ }
}
JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GtkClipboard_requestStringConversion
- (JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused)))
+Java_gnu_java_awt_peer_gtk_GtkClipboard_advertiseContent
+(JNIEnv *env,
+ jobject instance,
+ jobjectArray mime_array,
+ jboolean add_text,
+ jboolean add_images __attribute__((unused)),
+ jboolean add_uris __attribute__((unused)))
{
+ GtkTargetList *target_list;
+ GList *list;
+ GtkTargetEntry *targets;
+ gint n, i;
+
gdk_threads_enter ();
+ target_list = gtk_target_list_new (NULL, 0);
+
+ if (mime_array != NULL)
+ {
+ n = (*env)->GetArrayLength (env, mime_array);
+ for (i = 0; i < n; i++)
+ {
+ const char *text;
+ jstring target;
+ GdkAtom atom;
+
+ target = (*env)->GetObjectArrayElement (env, mime_array, i);
+ if (target == NULL)
+ break;
+ text = (*env)->GetStringUTFChars (env, target, NULL);
+ if (text == NULL)
+ break;
+
+ atom = gdk_atom_intern (text, FALSE);
+ gtk_target_list_add (target_list, atom, 0, OBJECT_TARGET);
+
+ (*env)->ReleaseStringUTFChars (env, target, text);
+ }
+ }
- gtk_selection_convert (clipboard, GDK_SELECTION_PRIMARY,
- GDK_TARGET_STRING, GDK_CURRENT_TIME);
+ /* Add extra targets that gtk+ can provide/translate for us. */
+ if (add_text)
+ gtk_target_list_add_text_targets (target_list, TEXT_TARGET);
+ if (add_images)
+ gtk_target_list_add_image_targets (target_list, IMAGE_TARGET, TRUE);
+ if (add_uris)
+ gtk_target_list_add_uri_targets (target_list, URI_TARGET);
+
+ /* Turn list into a target table. */
+ n = g_list_length (target_list->list);
+ if (n > 0)
+ {
+ targets = g_new (GtkTargetEntry, n);
+ for (list = target_list->list, i = 0;
+ list != NULL;
+ list = list->next, i++)
+ {
+ GtkTargetPair *pair = (GtkTargetPair *) list->data;
+ targets[i].target = gdk_atom_name (pair->target);
+ targets[i].flags = pair->flags;
+ targets[i].info = pair->info;
+ }
+
+ /* Set the targets plus callback functions and ask for the clipboard
+ to be stored when the application exists. */
+ current_selection++;
+ if (gtk_clipboard_set_with_data (clipboard, targets, n,
+ cp_gtk_clipboard_get_func,
+ cp_gtk_clipboard_clear_func,
+ (gpointer) current_selection))
+ {
+ owner = 1;
+ if (gtk_clipboard_instance == NULL)
+ {
+ JNIEnv *env = cp_gtk_gdk_env ();
+ gtk_clipboard_instance = (*env)->NewGlobalRef(env, instance);
+
+ provideContentID
+ = (*env)->GetMethodID (env, gtk_clipboard_class,
+ "provideContent",
+ "(Ljava/lang/String;)[B");
+ if (provideContentID == NULL)
+ return;
+
+ provideTextID
+ = (*env)->GetMethodID (env, gtk_clipboard_class,
+ "provideText", "()Ljava/lang/String;");
+ if (provideTextID == NULL)
+ return;
+
+ provideImageID
+ = (*env)->GetMethodID (env, gtk_clipboard_class,
+ "provideImage",
+ "()Lgnu/java/awt/peer/gtk/GtkImage;");
+ if (provideImageID == NULL)
+ return;
+
+ provideURIsID
+ = (*env)->GetMethodID (env, gtk_clipboard_class,
+ "provideURIs",
+ "()[Ljava/lang/String;");
+ if (provideURIsID == NULL)
+ return;
+ }
+ gtk_clipboard_set_can_store (clipboard, NULL, 0);
+ }
+ else
+ {
+ owner = 0;
+ (*env)->CallStaticVoidMethod (env, gtk_clipboard_class,
+ setSystemContentsID);
+ }
+
+ for (i = 0; i < n; i++)
+ g_free (targets[i].target);
+ g_free (targets);
+ }
+ else if (owner)
+ {
+ gtk_clipboard_clear (clipboard);
+ owner = 0;
+ }
+ gtk_target_list_unref (target_list);
gdk_threads_leave ();
}
+
+/* GtkSelection native methods. Put here for convenience since they
+ need access to the current clipboard. */
+
+static jmethodID mimeTypesAvailableID;
+
+/* Note this is actually just a GtkClipboardReceivedFunc, not a real
+ GtkClipboardTargetsReceivedFunc, see requestMimeTypes. */
static void
-selection_received_cb (GtkWidget *widget __attribute__((unused)),
- GtkSelectionData *selection_data __attribute__((unused)),
- guint time __attribute__((unused)),
- gpointer data __attribute__((unused)))
+cp_gtk_clipboard_targets_received (GtkClipboard *clipboard
+ __attribute__((unused)),
+ GtkSelectionData *target_data,
+ gpointer selection)
{
- /* Check to see if retrieval succeeded */
- if (selection_data->length < 0
- || selection_data->type != GDK_SELECTION_TYPE_STRING)
+ GdkAtom *targets = NULL;
+ gint targets_len = 0;
+ gchar **target_strings = NULL;
+ jobjectArray strings = NULL;
+ int strings_len = 0;
+ gboolean include_text = FALSE;
+ gboolean include_image = FALSE;
+ gboolean include_uris = FALSE;
+ jobject selection_obj = (jobject) selection;
+ JNIEnv *env = cp_gtk_gdk_env ();
+
+ if (target_data != NULL && target_data->length > 0)
{
- gdk_threads_leave ();
+ include_text = gtk_selection_data_targets_include_text (target_data);
+ include_image = gtk_selection_data_targets_include_image (target_data,
+ TRUE);
+ if (gtk_selection_data_get_targets (target_data, &targets, &targets_len))
+ {
+ int i;
+ GdkAtom uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
+ target_strings = g_new (gchar*, targets_len);
+ if (target_strings != NULL)
+ for (i = 0; i < targets_len; i++)
+ {
+ gchar *name = gdk_atom_name (targets[i]);
+ if (strchr (name, '/') != NULL)
+ {
+ target_strings[i] = name;
+ strings_len++;
+ if (! include_uris && targets[i] == uri_list_atom)
+ include_uris = TRUE;
+ }
+ else
+ target_strings[i] = NULL;
+ }
+ }
+
+ if (target_strings != NULL)
+ {
+ int i = 0, j = 0;
+ jclass stringClass;
+
+ if (include_text)
+ strings_len++;
+ if (include_image)
+ strings_len++;
+ if (include_uris)
+ strings_len++;
+
+ stringClass = (*env)->FindClass (env, "java/lang/String");
+ strings = (*env)->NewObjectArray (env, strings_len, stringClass,
+ NULL);
+ if (strings != NULL)
+ {
+ if (include_text)
+ (*env)->SetObjectArrayElement (env, strings, i++,
+ stringTarget);
+ if (include_image)
+ (*env)->SetObjectArrayElement (env, strings, i++,
+ imageTarget);
+ if (include_uris)
+ (*env)->SetObjectArrayElement (env, strings, i++,
+ filesTarget);
+
+ while(i < strings_len)
+ {
+ if (target_strings[j] == NULL)
+ j++;
+ else
+ {
+ jstring string;
+ string = (*env)->NewStringUTF (env,
+ target_strings[j++]);
+ if (string == NULL)
+ break;
+ (*env)->SetObjectArrayElement (env, strings, i++,
+ string);
+ }
+ }
+ }
+
+ for (i = 0; i < targets_len; i++)
+ g_free (target_strings[i]);
+ g_free (target_strings);
+ }
+ }
+
+ (*env)->CallVoidMethod (env, selection_obj,
+ mimeTypesAvailableID,
+ strings);
+ (*env)->DeleteGlobalRef (env, selection_obj);
+}
- (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), cb_obj, stringSelectionReceivedID,
- NULL);
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkSelection_requestMimeTypes
+(JNIEnv *env, jobject selection)
+{
+ jobject selection_obj;
+ selection_obj = (*env)->NewGlobalRef(env, selection);
+ if (selection_obj == NULL)
+ return;
- gdk_threads_enter ();
+ if (mimeTypesAvailableID == NULL)
+ {
+ jclass gtk_selection_class;
+ gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
+ mimeTypesAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
+ "mimeTypesAvailable",
+ "([Ljava/lang/String;)V");
+ if (mimeTypesAvailableID == NULL)
+ return;
}
+
+ /* We would have liked to call gtk_clipboard_request_targets ()
+ since that is more general. But the result of that, an array of
+ GdkAtoms, cannot be used with the
+ gtk_selection_data_targets_include_<x> functions (despite what
+ the name suggests). */
+ gdk_threads_enter ();
+ gtk_clipboard_request_contents (clipboard,
+ gdk_atom_intern ("TARGETS", FALSE),
+ cp_gtk_clipboard_targets_received,
+ (gpointer) selection_obj);
+ gdk_threads_leave ();
+}
+
+
+static jmethodID textAvailableID;
+
+static void
+cp_gtk_clipboard_text_received (GtkClipboard *clipboard
+ __attribute__((unused)),
+ const gchar *text,
+ gpointer selection)
+{
+ jstring string;
+ jobject selection_obj = (jobject) selection;
+
+ JNIEnv *env = cp_gtk_gdk_env ();
+ if (text != NULL)
+ string = (*env)->NewStringUTF (env, text);
else
- {
- char *str = (char *) selection_data->data;
-
- gdk_threads_leave ();
+ string = NULL;
+
+ (*env)->CallVoidMethod (env, selection_obj,
+ textAvailableID,
+ string);
+ (*env)->DeleteGlobalRef (env, selection_obj);
+}
- (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), cb_obj, stringSelectionReceivedID,
- (*cp_gtk_gdk_env())->NewStringUTF (cp_gtk_gdk_env(), str));
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkSelection_requestText
+(JNIEnv *env, jobject selection)
+{
+ jobject selection_obj;
+ selection_obj = (*env)->NewGlobalRef(env, selection);
+ if (selection_obj == NULL)
+ return;
- gdk_threads_enter ();
+ if (textAvailableID == NULL)
+ {
+ jclass gtk_selection_class;
+ gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
+ textAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
+ "textAvailable",
+ "(Ljava/lang/String;)V");
+ if (textAvailableID == NULL)
+ return;
}
- return;
+ gdk_threads_enter ();
+ gtk_clipboard_request_text (clipboard,
+ cp_gtk_clipboard_text_received,
+ (gpointer) selection_obj);
+ gdk_threads_leave ();
}
+static jmethodID imageAvailableID;
+
static void
-selection_get_cb (GtkWidget *widget __attribute__((unused)),
- GtkSelectionData *selection_data,
- guint info __attribute__((unused)),
- guint time __attribute__((unused)),
- gpointer data __attribute__((unused)))
+cp_gtk_clipboard_image_received (GtkClipboard *clipboard
+ __attribute__((unused)),
+ GdkPixbuf *pixbuf,
+ gpointer selection)
{
- jstring jstr;
- const char *utf;
- jsize utflen;
+ jobject pointer = NULL;
+ jobject selection_obj = (jobject) selection;
+ JNIEnv *env = cp_gtk_gdk_env ();
- gdk_threads_leave ();
+ if (pixbuf != NULL)
+ {
+ g_object_ref (pixbuf);
+ pointer = JCL_NewRawDataObject (env, (void *) pixbuf);
+ }
- jstr = (*cp_gtk_gdk_env())->CallObjectMethod (cp_gtk_gdk_env(), cb_obj,
- stringSelectionHandlerID);
+ (*env)->CallVoidMethod (env, selection_obj,
+ imageAvailableID,
+ pointer);
+ (*env)->DeleteGlobalRef (env, selection_obj);
+}
- gdk_threads_enter ();
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkSelection_requestImage (JNIEnv *env, jobject obj)
+{
+ jobject selection_obj;
+ selection_obj = (*env)->NewGlobalRef(env, obj);
+ if (selection_obj == NULL)
+ return;
- if (!jstr)
+ if (imageAvailableID == NULL)
{
- gtk_selection_data_set (selection_data,
- GDK_TARGET_STRING, 8, NULL, 0);
- return;
+ jclass gtk_selection_class;
+ gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
+ imageAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
+ "imageAvailable",
+ "(Lgnu/classpath/Pointer;)V");
+ if (imageAvailableID == NULL)
+ return;
}
- utflen = (*cp_gtk_gdk_env())->GetStringUTFLength (cp_gtk_gdk_env(), jstr);
- utf = (*cp_gtk_gdk_env())->GetStringUTFChars (cp_gtk_gdk_env(), jstr, NULL);
+ gdk_threads_enter ();
+ gtk_clipboard_request_image (clipboard,
+ cp_gtk_clipboard_image_received,
+ (gpointer) selection_obj);
+ gdk_threads_leave ();
+}
- gtk_selection_data_set (selection_data, GDK_TARGET_STRING, 8,
- (const unsigned char*)utf, utflen);
+static jmethodID urisAvailableID;
- (*cp_gtk_gdk_env())->ReleaseStringUTFChars (cp_gtk_gdk_env(), jstr, utf);
+static void
+cp_gtk_clipboard_uris_received (GtkClipboard *clipboard
+ __attribute__((unused)),
+ GtkSelectionData *uri_data,
+ gpointer selection)
+{
+ gchar **uris = NULL;
+ jobjectArray strings = NULL;
+ jobject selection_obj = (jobject) selection;
+ JNIEnv *env = cp_gtk_gdk_env ();
+
+ if (uri_data != NULL)
+ uris = gtk_selection_data_get_uris (uri_data);
+
+ if (uris != NULL)
+ {
+ int len, i;
+ gchar **count = uris;
+ jclass stringClass = (*env)->FindClass (env, "java/lang/String");
+
+ len = 0;
+ while (count[len])
+ len++;
+
+ strings = (*env)->NewObjectArray (env, len, stringClass, NULL);
+ if (strings != NULL)
+ {
+ for (i = 0; i < len; i++)
+ {
+ jstring string = (*env)->NewStringUTF (env, uris[i]);
+ if (string == NULL)
+ break;
+ (*env)->SetObjectArrayElement (env, strings, i, string);
+ }
+ }
+ g_strfreev (uris);
+ }
+
+ (*env)->CallVoidMethod (env, selection_obj,
+ urisAvailableID,
+ strings);
+ (*env)->DeleteGlobalRef (env, selection_obj);
}
JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GtkClipboard_selectionGet
- (JNIEnv *env, jclass clazz __attribute__((unused)))
+Java_gnu_java_awt_peer_gtk_GtkSelection_requestURIs (JNIEnv *env, jobject obj)
{
- GdkWindow *owner;
+ GdkAtom uri_atom;
+ jobject selection_obj;
+ selection_obj = (*env)->NewGlobalRef(env, obj);
+ if (selection_obj == NULL)
+ return;
+
+ if (urisAvailableID == NULL)
+ {
+ jclass gtk_selection_class;
+ gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
+ urisAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
+ "urisAvailable",
+ "([Ljava/lang/String;)V");
+ if (urisAvailableID == NULL)
+ return;
+ }
+ /* There is no real request_uris so we have to make one ourselves. */
gdk_threads_enter ();
+ uri_atom = gdk_atom_intern ("text/uri-list", FALSE);
+ gtk_clipboard_request_contents (clipboard,
+ uri_atom,
+ cp_gtk_clipboard_uris_received,
+ (gpointer) selection_obj);
+ gdk_threads_leave ();
+}
- /* if we already own the clipboard, we need to tell the old data object
- that we're no longer going to be using him */
- owner = gdk_selection_owner_get (GDK_SELECTION_PRIMARY);
- if (owner && owner == clipboard->window)
- (*env)->CallVoidMethod (env, cb_obj, selectionClearID);
-
- gtk_selection_owner_set (clipboard, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
+static jmethodID bytesAvailableID;
- gdk_threads_leave ();
+static void
+cp_gtk_clipboard_bytes_received (GtkClipboard *clipboard
+ __attribute__((unused)),
+ GtkSelectionData *selection_data,
+ gpointer selection)
+{
+ jbyteArray bytes = NULL;
+ jobject selection_obj = (jobject) selection;
+ JNIEnv *env = cp_gtk_gdk_env ();
+
+ if (selection_data != NULL && selection_data->length > 0)
+ {
+ bytes = (*env)->NewByteArray (env, selection_data->length);
+ if (bytes != NULL)
+ (*env)->SetByteArrayRegion(env, bytes, 0, selection_data->length,
+ (jbyte *) selection_data->data);
+ }
+
+ (*env)->CallVoidMethod (env, selection_obj,
+ bytesAvailableID,
+ bytes);
+ (*env)->DeleteGlobalRef (env, selection_obj);
}
-static gint
-selection_clear_cb (GtkWidget *widget __attribute__((unused)),
- GdkEventSelection *event __attribute__((unused)))
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkSelection_requestBytes (JNIEnv *env,
+ jobject obj,
+ jstring target_string)
{
- gdk_threads_leave ();
+ int len;
+ const gchar *target_text;
+ GdkAtom target_atom;
+ jobject selection_obj;
+ selection_obj = (*env)->NewGlobalRef(env, obj);
+ if (selection_obj == NULL)
+ return;
+
+ if (bytesAvailableID == NULL)
+ {
+ jclass gtk_selection_class;
+ gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
+ bytesAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
+ "bytesAvailable",
+ "([B)V");
+ if (bytesAvailableID == NULL)
+ return;
+ }
- (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), cb_obj, selectionClearID);
+ len = (*env)->GetStringUTFLength (env, target_string);
+ if (len == -1)
+ return;
+ target_text = (*env)->GetStringUTFChars (env, target_string, NULL);
+ if (target_text == NULL)
+ return;
gdk_threads_enter ();
+ target_atom = gdk_atom_intern (target_text, FALSE);
+ gtk_clipboard_request_contents (clipboard,
+ target_atom,
+ cp_gtk_clipboard_bytes_received,
+ (gpointer) selection_obj);
+ gdk_threads_leave ();
- return TRUE;
+ (*env)->ReleaseStringUTFChars (env, target_string, target_text);
}
diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c
index b64862c65..772725396 100644
--- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c
+++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c
@@ -97,6 +97,19 @@ Java_gnu_java_awt_peer_gtk_GtkImage_loadPixbuf
return JNI_TRUE;
}
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkImage_createFromPixbuf
+(JNIEnv *env, jobject obj)
+{
+ int width, heigth;
+ GdkPixbuf *pixbuf = (GdkPixbuf *) getData (env, obj);
+ gdk_threads_enter ();
+ width = gdk_pixbuf_get_width (pixbuf);
+ heigth = gdk_pixbuf_get_height (pixbuf);
+ gdk_threads_leave ();
+ setWidthHeight(env, obj, width, heigth);
+}
+
/**
* Returns a copy of the pixel data as a java array.
*/