mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			437 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			437 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* GtkClipboard.java
 | |
|    Copyright (C) 1999, 2005, 2006 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.java.lang.CPStringBuilder;
 | |
| 
 | |
| import java.awt.Image;
 | |
| 
 | |
| 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.awt.datatransfer.UnsupportedFlavorException;
 | |
| 
 | |
| import java.io.ByteArrayOutputStream;
 | |
| import java.io.File;
 | |
| import java.io.InputStream;
 | |
| import java.io.IOException;
 | |
| import java.io.ObjectOutputStream;
 | |
| import java.io.Reader;
 | |
| import java.io.Serializable;
 | |
| import java.io.UnsupportedEncodingException;
 | |
| 
 | |
| import java.util.List;
 | |
| import java.util.Iterator;
 | |
| 
 | |
| public class GtkClipboard extends Clipboard
 | |
| {
 | |
|   /**
 | |
|    * The one and only gtk+ clipboard instance for the CLIPBOARD selection.
 | |
|    */
 | |
|   final static GtkClipboard clipboard = new GtkClipboard("System Clipboard");
 | |
| 
 | |
|   /**
 | |
|    * The one and only gtk+ clipboard instance for the PRIMARY selection.
 | |
|    */
 | |
|   final static GtkClipboard selection = new GtkClipboard("System Selection");
 | |
| 
 | |
|   // 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
 | |
|     = DataFlavor.stringFlavor.getMimeType();
 | |
|   static final String imageMimeType
 | |
|     = DataFlavor.imageFlavor.getMimeType();
 | |
|   static final String filesMimeType
 | |
|     = DataFlavor.javaFileListFlavor.getMimeType();
 | |
| 
 | |
|   // Indicates whether the results of the clipboard selection can be
 | |
|   // cached by GtkSelection. True if
 | |
|   // gdk_display_supports_selection_notification.
 | |
|   static final boolean canCache = initNativeState(clipboard, selection,
 | |
|                                                   stringMimeType,
 | |
|                                                   imageMimeType,
 | |
|                                                   filesMimeType);
 | |
| 
 | |
|   /**
 | |
|    * Creates the clipboard and sets the initial contents to the
 | |
|    * current gtk+ selection.
 | |
|    */
 | |
|   private GtkClipboard(String name)
 | |
|   {
 | |
|     super(name);
 | |
|     setContents(new GtkSelection(this), null);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the one and only GtkClipboard instance for the CLIPBOARD
 | |
|    * selection.
 | |
|    */
 | |
|   static GtkClipboard getClipboardInstance()
 | |
|   {
 | |
|     return clipboard;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the one and only GtkClipboard instance for the PRIMARY
 | |
|    * selection.
 | |
|    */
 | |
|   static GtkClipboard getSelectionInstance()
 | |
|   {
 | |
|     return selection;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the GtkSelection facade as new contents of the clipboard.
 | |
|    * Called from gtk+ when another application grabs the clipboard and
 | |
|    * we loose ownership.
 | |
|    *
 | |
|    * @param cleared If true this is a clear event (someone takes the
 | |
|    * clipboard from us) otherwise it is an owner changed event.
 | |
|    */
 | |
|   private synchronized void setSystemContents(boolean cleared)
 | |
|   {
 | |
|     // We need to notify clipboard owner listeners when we were the
 | |
|     // owner (the selection was explictly set) and someone takes the
 | |
|     // clipboard away from us and asks us the clear any held storage,
 | |
|     // or if we weren't the owner of the clipboard to begin with, but
 | |
|     // the clipboard contents changed. We could refine this and check
 | |
|     // whether the actual available formats did in fact change, but we
 | |
|     // assume listeners will check for that anyway (and if possible we
 | |
|     // ask to cache the available formats so even if multiple
 | |
|     // listeners check after a notification the overhead should be
 | |
|     // minimal).
 | |
|     boolean owner = ! (contents instanceof GtkSelection);
 | |
|     boolean needNotification = (cleared && owner) || (! cleared && ! owner);
 | |
|     if (needNotification)
 | |
|       GtkClipboardNotifier.announce(this);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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)
 | |
|       {
 | |
|         advertiseContent(null, false, false, false);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|     // 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++)
 | |
|       {
 | |
|         DataFlavor flavor = flavors[i];
 | |
|         String mimeType = flavor.getMimeType();
 | |
|         mimeTargets[i] = mimeType;
 | |
| 
 | |
|         if (! text)
 | |
|           if ("text".equals(flavor.getPrimaryType())
 | |
|               || flavor.isRepresentationClassReader())
 | |
|             text = true;
 | |
| 
 | |
|         if (! images && flavors[i].equals(DataFlavor.imageFlavor))
 | |
|           {
 | |
|             try
 | |
|               {
 | |
|                 Object o = contents.getTransferData(DataFlavor.imageFlavor);
 | |
|                 if (o instanceof Image)
 | |
|                   images = true;
 | |
|               }
 | |
|             catch (UnsupportedFlavorException ufe)
 | |
|               {
 | |
|               }
 | |
|             catch (IOException ioe)
 | |
|               {
 | |
|               }
 | |
|             catch (ClassCastException cce)
 | |
|               {
 | |
|               }
 | |
|           }
 | |
| 
 | |
|         if (flavors[i].equals(DataFlavor.javaFileListFlavor))
 | |
|           files = true;
 | |
|       }
 | |
| 
 | |
|     advertiseContent(mimeTargets, text, images, files);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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()
 | |
|   {
 | |
|     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)
 | |
|       {
 | |
|         try
 | |
|           {
 | |
|             return (String) contents.getTransferData(DataFlavor.stringFlavor);
 | |
|           }
 | |
|         catch (UnsupportedFlavorException ufe)
 | |
|           {
 | |
|           }
 | |
|         catch (IOException ioe)
 | |
|           {
 | |
|           }
 | |
|         catch (ClassCastException cce)
 | |
|           {
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     // Try to get a plain text reader for the current contents and
 | |
|     // turn the result into a string.
 | |
|     try
 | |
|       {
 | |
|         DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor();
 | |
|         Reader r = plainText.getReaderForText(contents);
 | |
|         if (r != null)
 | |
|           {
 | |
|             CPStringBuilder sb = new CPStringBuilder();
 | |
|             char[] cs = new char[1024];
 | |
|             int l = r.read(cs);
 | |
|             while (l != -1)
 | |
|               {
 | |
|                 sb.append(cs, 0, l);
 | |
|                 l = r.read(cs);
 | |
|               }
 | |
|             return sb.toString();
 | |
|           }
 | |
|       }
 | |
|     catch (IllegalArgumentException iae)
 | |
|       {
 | |
|       }
 | |
|     catch (UnsupportedEncodingException iee)
 | |
|       {
 | |
|       }
 | |
|     catch (UnsupportedFlavorException ufe)
 | |
|       {
 | |
|       }
 | |
|     catch (IOException ioe)
 | |
|       {
 | |
|       }
 | |
| 
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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
 | |
|       {
 | |
|         Object o = contents.getTransferData(DataFlavor.imageFlavor);
 | |
|         if( o instanceof GtkImage )
 | |
|           return (GtkImage) o;
 | |
|         else
 | |
|           return new GtkImage(((Image)o).getSource());
 | |
|       }
 | |
|     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()
 | |
|   {
 | |
|     Transferable contents = this.contents;
 | |
|     if (contents == null || contents instanceof GtkSelection)
 | |
|       return null;
 | |
| 
 | |
|     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)
 | |
|       {
 | |
|       }
 | |
| 
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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)
 | |
|   {
 | |
|     // 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 (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)
 | |
|       {
 | |
|       }
 | |
|     catch (IOException ioe)
 | |
|       {
 | |
|       }
 | |
|     catch (ClassCastException cce)
 | |
|       {
 | |
|       }
 | |
| 
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Initializes the gtk+ clipboards 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(GtkClipboard clipboard,
 | |
|                                                 GtkClipboard selection,
 | |
|                                                 String stringTarget,
 | |
|                                                 String imageTarget,
 | |
|                                                 String filesTarget);
 | |
| }
 |