/[classpath]/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java
ViewVC logotype

Diff of /classpath/gnu/java/awt/peer/gtk/GtkClipboard.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.5.2.4 by gnu_andrew, Tue Aug 2 20:12:09 2005 UTC revision 1.5.2.5 by gnu_andrew, Sat Sep 10 15:31:37 2005 UTC
# Line 38  exception statement from your version. * Line 38  exception statement from your version. *
38    
39  package gnu.java.awt.peer.gtk;  package gnu.java.awt.peer.gtk;
40    
41  import java.awt.datatransfer.Clipboard;  import java.awt.Image;
42  import java.awt.datatransfer.ClipboardOwner;  import java.awt.datatransfer.*;
43  import java.awt.datatransfer.DataFlavor;  
44  import java.awt.datatransfer.StringSelection;  import java.io.*;
45  import java.awt.datatransfer.Transferable;  
46  import java.io.IOException;  import java.util.List;
47  import java.io.InputStream;  import java.util.Iterator;
 import java.io.InputStreamReader;  
48    
49  public class GtkClipboard extends Clipboard  public class GtkClipboard extends Clipboard
50  {  {
   /* 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 ();  
51    
52    static boolean hasSelection = false;    // Given to the native side so it can signal special targets that
53      // can be converted to one of the special predefined DataFlavors.
54      static final String stringMimeType;
55      static final String imageMimeType;
56      static final String filesMimeType;
57    
58      // Indicates whether the results of the clipboard selection can be
59      // cached by GtkSelection. True if
60      // gdk_display_supports_selection_notification.
61      static final boolean canCache;
62    
63      static
64      {
65        stringMimeType = DataFlavor.stringFlavor.getMimeType();
66        imageMimeType = DataFlavor.imageFlavor.getMimeType();
67        filesMimeType = DataFlavor.javaFileListFlavor.getMimeType();
68    
69        canCache = initNativeState(stringMimeType, imageMimeType, filesMimeType);
70      }
71    
72    protected GtkClipboard()    /**
73       * The one and only gtk+ clipboard instance.
74       */
75      private static GtkClipboard instance = new GtkClipboard();
76    
77      /**
78       * Creates the clipboard and sets the initial contents to the
79       * current gtk+ selection.
80       */
81      private GtkClipboard()
82    {    {
83      super("System Clipboard");      super("System Clipboard");
84      initNativeState();      setContents(new GtkSelection(), null);
85    }    }
86    
87    public Transferable getContents(Object requestor)    /**
88       * Returns the one and only GtkClipboard instance.
89       */
90    
91      static GtkClipboard getInstance()
92    {    {
93      synchronized (this)      return instance;
94      }
95    
96      /**
97       * Sets the GtkSelection facade as new contents of the clipboard.
98       * Called from gtk+ when another application grabs the clipboard and
99       * we loose ownership.
100       */
101      private static void setSystemContents()
102      {
103        GtkClipboardNotifier.announce();
104      }
105    
106      /**
107       * Sets the new contents and advertises the available flavors to the
108       * gtk+ clipboard.
109       */
110      public synchronized void setContents(Transferable contents,
111                                           ClipboardOwner owner)
112      {
113        super.setContents(contents, owner);
114    
115        if (contents == null)
116        {        {
117          if (hasSelection)          advertiseContent(null, false, false, false);
118            return contents;          return;
119        }        }
120    
121      /* Java doesn't own the selection, so we need to ask X11 */      // We don't need to do anything for a GtkSelection facade.
122      // XXX: Does this hold with Swing too ?      if (contents instanceof GtkSelection)
123      synchronized (selectionLock)        return;
124    
125        boolean text = false;
126        boolean images = false;
127        boolean files = false;
128    
129        if (contents instanceof StringSelection
130            || contents.isDataFlavorSupported(DataFlavor.stringFlavor)
131            || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor)
132            || contents.isDataFlavorSupported(DataFlavor
133                                              .getTextPlainUnicodeFlavor()))
134          text = true;
135    
136        DataFlavor[] flavors = contents.getTransferDataFlavors();
137        String[] mimeTargets = new String[flavors.length];
138        for (int i = 0; i < flavors.length; i++)
139        {        {
140          requestStringConversion();          DataFlavor flavor = flavors[i];
141                    String mimeType = flavor.getMimeType();
142          try          mimeTargets[i] = mimeType;
143    
144            if (! text)
145              if ("text".equals(flavor.getPrimaryType())
146                  || flavor.isRepresentationClassReader())
147                text = true;
148    
149            // XXX - We only support automatic image conversion for
150            // GtkImages at the moment. So explicitly check that we have
151            // one.
152            if (! images && flavors[i].equals(DataFlavor.imageFlavor))
153            {            {
154              selectionLock.wait(SELECTION_RECEIVED_TIMEOUT);              try
155            }                {
156          catch (InterruptedException e)                  Object o = contents.getTransferData(DataFlavor.imageFlavor);
157            {                  if (o instanceof GtkImage)
158              return null;                    images = true;
159                  }
160                catch (UnsupportedFlavorException ufe)
161                  {
162                  }
163                catch (IOException ioe)
164                  {
165                  }
166                catch (ClassCastException cce)
167                  {
168                  }
169            }            }
170            
171          return selection == null ? null : new StringSelection(selection);          if (flavors[i].equals(DataFlavor.javaFileListFlavor))
172              files = true;
173        }        }
174    
175        advertiseContent(mimeTargets, text, images, files);
176    }    }
177    
178    void stringSelectionReceived(String newSelection)    /**
179       * Advertises new contents to the gtk+ clipboard given a string
180       * array of (mime-type) targets. When the boolean flags text, images
181       * and/or files are set then gtk+ is asked to also advertise the
182       * availability of any text, image or uri/file content types it
183       * supports. If targets is null (and all flags false) then the
184       * selection has explicitly been erased.
185       */
186      private native void advertiseContent(String[] targets,
187                                           boolean text,
188                                           boolean images,
189                                           boolean files);
190      
191      /**
192       * Called by the gtk+ clipboard when an application has requested
193       * text.  Return a string representing the current clipboard
194       * contents or null when no text can be provided.
195       */
196      private String provideText()
197    {    {
198      synchronized (selectionLock)      Transferable contents = this.contents;
199        if (contents == null || contents instanceof GtkSelection)
200          return null;
201    
202        // Handle StringSelection special since that is just pure text.
203        if (contents instanceof StringSelection)
204        {        {
205          selection = newSelection;          try
206          selectionLock.notify();            {
207                return (String) contents.getTransferData(DataFlavor.stringFlavor);
208              }
209            catch (UnsupportedFlavorException ufe)
210              {
211              }
212            catch (IOException ioe)
213              {
214              }
215            catch (ClassCastException cce)
216              {
217              }
218        }        }
   }  
   
   /* convert Java clipboard data into a String suitable for sending  
      to another application */  
   synchronized String stringSelectionHandler() throws IOException  
   {  
     String selection = null;  
219    
220        // Try to get a plain text reader for the current contents and
221        // turn the result into a string.
222      try      try
223        {        {
224          if (contents.isDataFlavorSupported(DataFlavor.stringFlavor))          DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor();
225            selection = (String)contents.getTransferData(DataFlavor.stringFlavor);          Reader r = plainText.getReaderForText(contents);
226          else if (contents.isDataFlavorSupported(DataFlavor.plainTextFlavor))          if (r != null)
227            {            {
228              StringBuffer sbuf = new StringBuffer();              StringBuffer sb = new StringBuffer();
229              InputStreamReader reader;              char[] cs = new char[1024];
230              char readBuf[] = new char[512];              int l = r.read(cs);
231              int numChars;              while (l != -1)
232                            {
233              reader = new InputStreamReader                  sb.append(cs, 0, l);
234                ((InputStream)                  l = r.read(cs);
                contents.getTransferData(DataFlavor.plainTextFlavor), "UNICODE");  
             
             while (true)  
               {  
                 numChars = reader.read(readBuf);  
                 if (numChars == -1)  
                   break;  
                 sbuf.append(readBuf, 0, numChars);  
235                }                }
236                          return sb.toString();
             selection = new String(sbuf);  
237            }            }
238        }        }
239      catch (Exception e)      catch (IllegalArgumentException iae)
240          {
241          }
242        catch (UnsupportedEncodingException iee)
243          {
244          }
245        catch (UnsupportedFlavorException ufe)
246        {        {
247        }        }
248            catch (IOException ioe)
249      return selection;        {
250          }
251    
252        return null;
253    }    }
254    
255    public synchronized void setContents(Transferable contents,    /**
256                                         ClipboardOwner owner)     * Called by the gtk+ clipboard when an application has requested an
257       * image.  Returns a GtkImage representing the current clipboard
258       * contents or null when no image can be provided.
259       */
260      private GtkImage provideImage()
261    {    {
262      selectionGet();      Transferable contents = this.contents;
263        if (contents == null || contents instanceof GtkSelection)
264          return null;
265    
266      this.contents = contents;      try
267      this.owner = owner;        {
268            return (GtkImage) contents.getTransferData(DataFlavor.imageFlavor);
269          }
270        catch (UnsupportedFlavorException ufe)
271          {
272          }
273        catch (IOException ioe)
274          {
275          }
276        catch (ClassCastException cce)
277          {
278          }
279    
280      hasSelection = true;      return null;
281    }    }
282    
283    synchronized void selectionClear()    /**
284       * Called by the gtk+ clipboard when an application has requested a
285       * uri-list.  Return a string array containing the URIs representing
286       * the current clipboard contents or null when no URIs can be
287       * provided.
288       */
289      private String[] provideURIs()
290    {    {
291      hasSelection = false;      Transferable contents = this.contents;
292        if (contents == null || contents instanceof GtkSelection)
293          return null;
294    
295      if (owner != null)      try
296        {        {
297          owner.lostOwnership(this, contents);          List list = (List) contents.getTransferData
298          owner = null;            (DataFlavor.javaFileListFlavor);
299          contents = null;          String[] uris = new String[list.size()];
300            int u = 0;
301            Iterator it = list.iterator();
302            while (it.hasNext())
303              uris[u++] = ((File) it.next()).toURI().toString();
304            return uris;
305        }        }
306        catch (UnsupportedFlavorException ufe)
307          {
308          }
309        catch (IOException ioe)
310          {
311          }
312        catch (ClassCastException cce)
313          {
314          }
315    
316        return null;
317      }
318    
319      /**
320       * Called by gtk+ clipboard when an application requests the given
321       * target mime-type. Returns a byte array containing the requested
322       * data, or null when the contents cannot be provided in the
323       * requested target mime-type. Only called after any explicit text,
324       * image or file/uri requests have been handled earlier and failed.
325       */
326      private byte[] provideContent(String target)
327      {
328        // Sanity check. The callback could be triggered just after we
329        // changed the clipboard.
330        Transferable contents = this.contents;
331        if (contents == null || contents instanceof GtkSelection)
332          return null;
333    
334        // XXX - We are being called from a gtk+ callback. Which means we
335        // should return as soon as possible and not call arbitrary code
336        // that could deadlock or go bonkers. But we don't really know
337        // what DataTransfer contents object we are dealing with. Same for
338        // the other provideXXX() methods.
339        try
340          {
341            DataFlavor flavor = new DataFlavor(target);
342            Object o = contents.getTransferData(flavor);
343    
344            if (o instanceof byte[])
345              return (byte[]) o;
346    
347            if (o instanceof InputStream)
348              {
349                InputStream is = (InputStream) o;
350                ByteArrayOutputStream baos = new ByteArrayOutputStream();
351                byte[] bs = new byte[1024];
352                int l = is.read(bs);
353                while (l != -1)
354                  {
355                    baos.write(bs, 0, l);
356                    l = is.read(bs);
357                  }
358                return baos.toByteArray();
359              }
360    
361            if (o instanceof Serializable)
362              {
363                ByteArrayOutputStream baos = new ByteArrayOutputStream();
364                ObjectOutputStream oos = new ObjectOutputStream(baos);
365                oos.writeObject(o);
366                oos.close();
367                return baos.toByteArray();
368              }
369          }
370        catch (ClassNotFoundException cnfe)
371          {
372          }
373        catch (UnsupportedFlavorException ufe)
374          {
375          }
376        catch (IOException ioe)
377          {
378          }
379        catch (ClassCastException cce)
380          {
381          }
382    
383        return null;
384    }    }
385    
386    native void initNativeState();    /**
387    static native void requestStringConversion();     * Initializes the gtk+ clipboard and caches any native side
388    static native void selectionGet();     * structures needed. Returns whether or not the contents of the
389       * Clipboard can be cached (gdk_display_supports_selection_notification).
390       */
391      private static native boolean initNativeState(String stringTarget,
392                                                    String imageTarget,
393                                                    String filesTarget);
394  }  }

Legend:
Removed from v.1.5.2.4  
changed lines
  Added in v.1.5.2.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26