libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / gnu / java / awt / peer / gtk / GtkClipboard.java
blobe248b6daf10b8764b428f9529fb5e63267e918f5
1 /* GtkClipboard.java
2 Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.awt.peer.gtk;
41 import gnu.java.lang.CPStringBuilder;
43 import java.awt.Image;
45 import java.awt.datatransfer.Clipboard;
46 import java.awt.datatransfer.ClipboardOwner;
47 import java.awt.datatransfer.DataFlavor;
48 import java.awt.datatransfer.StringSelection;
49 import java.awt.datatransfer.Transferable;
50 import java.awt.datatransfer.UnsupportedFlavorException;
52 import java.io.ByteArrayOutputStream;
53 import java.io.File;
54 import java.io.InputStream;
55 import java.io.IOException;
56 import java.io.ObjectOutputStream;
57 import java.io.Reader;
58 import java.io.Serializable;
59 import java.io.UnsupportedEncodingException;
61 import java.util.List;
62 import java.util.Iterator;
64 public class GtkClipboard extends Clipboard
66 /**
67 * The one and only gtk+ clipboard instance for the CLIPBOARD selection.
69 final static GtkClipboard clipboard = new GtkClipboard("System Clipboard");
71 /**
72 * The one and only gtk+ clipboard instance for the PRIMARY selection.
74 final static GtkClipboard selection = new GtkClipboard("System Selection");
76 // Given to the native side so it can signal special targets that
77 // can be converted to one of the special predefined DataFlavors.
78 static final String stringMimeType
79 = DataFlavor.stringFlavor.getMimeType();
80 static final String imageMimeType
81 = DataFlavor.imageFlavor.getMimeType();
82 static final String filesMimeType
83 = DataFlavor.javaFileListFlavor.getMimeType();
85 // Indicates whether the results of the clipboard selection can be
86 // cached by GtkSelection. True if
87 // gdk_display_supports_selection_notification.
88 static final boolean canCache = initNativeState(clipboard, selection,
89 stringMimeType,
90 imageMimeType,
91 filesMimeType);
93 /**
94 * Creates the clipboard and sets the initial contents to the
95 * current gtk+ selection.
97 private GtkClipboard(String name)
99 super(name);
100 setContents(new GtkSelection(this), null);
104 * Returns the one and only GtkClipboard instance for the CLIPBOARD
105 * selection.
107 static GtkClipboard getClipboardInstance()
109 return clipboard;
113 * Returns the one and only GtkClipboard instance for the PRIMARY
114 * selection.
116 static GtkClipboard getSelectionInstance()
118 return selection;
122 * Sets the GtkSelection facade as new contents of the clipboard.
123 * Called from gtk+ when another application grabs the clipboard and
124 * we loose ownership.
126 * @param cleared If true this is a clear event (someone takes the
127 * clipboard from us) otherwise it is an owner changed event.
129 private synchronized void setSystemContents(boolean cleared)
131 // We need to notify clipboard owner listeners when we were the
132 // owner (the selection was explictly set) and someone takes the
133 // clipboard away from us and asks us the clear any held storage,
134 // or if we weren't the owner of the clipboard to begin with, but
135 // the clipboard contents changed. We could refine this and check
136 // whether the actual available formats did in fact change, but we
137 // assume listeners will check for that anyway (and if possible we
138 // ask to cache the available formats so even if multiple
139 // listeners check after a notification the overhead should be
140 // minimal).
141 boolean owner = ! (contents instanceof GtkSelection);
142 boolean needNotification = (cleared && owner) || (! cleared && ! owner);
143 if (needNotification)
144 GtkClipboardNotifier.announce(this);
148 * Sets the new contents and advertises the available flavors to the
149 * gtk+ clipboard.
151 public synchronized void setContents(Transferable contents,
152 ClipboardOwner owner)
154 super.setContents(contents, owner);
156 if (contents == null)
158 advertiseContent(null, false, false, false);
159 return;
162 // We don't need to do anything for a GtkSelection facade.
163 if (contents instanceof GtkSelection)
164 return;
166 boolean text = false;
167 boolean images = false;
168 boolean files = false;
170 if (contents instanceof StringSelection
171 || contents.isDataFlavorSupported(DataFlavor.stringFlavor)
172 || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor)
173 || contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()))
174 text = true;
176 DataFlavor[] flavors = contents.getTransferDataFlavors();
177 String[] mimeTargets = new String[flavors.length];
178 for (int i = 0; i < flavors.length; i++)
180 DataFlavor flavor = flavors[i];
181 String mimeType = flavor.getMimeType();
182 mimeTargets[i] = mimeType;
184 if (! text)
185 if ("text".equals(flavor.getPrimaryType())
186 || flavor.isRepresentationClassReader())
187 text = true;
189 if (! images && flavors[i].equals(DataFlavor.imageFlavor))
193 Object o = contents.getTransferData(DataFlavor.imageFlavor);
194 if (o instanceof Image)
195 images = true;
197 catch (UnsupportedFlavorException ufe)
200 catch (IOException ioe)
203 catch (ClassCastException cce)
208 if (flavors[i].equals(DataFlavor.javaFileListFlavor))
209 files = true;
212 advertiseContent(mimeTargets, text, images, files);
216 * Advertises new contents to the gtk+ clipboard given a string
217 * array of (mime-type) targets. When the boolean flags text, images
218 * and/or files are set then gtk+ is asked to also advertise the
219 * availability of any text, image or uri/file content types it
220 * supports. If targets is null (and all flags false) then the
221 * selection has explicitly been erased.
223 private native void advertiseContent(String[] targets,
224 boolean text,
225 boolean images,
226 boolean files);
229 * Called by the gtk+ clipboard when an application has requested
230 * text. Return a string representing the current clipboard
231 * contents or null when no text can be provided.
233 private String provideText()
235 Transferable contents = this.contents;
236 if (contents == null || contents instanceof GtkSelection)
237 return null;
239 // Handle StringSelection special since that is just pure text.
240 if (contents instanceof StringSelection)
244 return (String) contents.getTransferData(DataFlavor.stringFlavor);
246 catch (UnsupportedFlavorException ufe)
249 catch (IOException ioe)
252 catch (ClassCastException cce)
257 // Try to get a plain text reader for the current contents and
258 // turn the result into a string.
261 DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor();
262 Reader r = plainText.getReaderForText(contents);
263 if (r != null)
265 CPStringBuilder sb = new CPStringBuilder();
266 char[] cs = new char[1024];
267 int l = r.read(cs);
268 while (l != -1)
270 sb.append(cs, 0, l);
271 l = r.read(cs);
273 return sb.toString();
276 catch (IllegalArgumentException iae)
279 catch (UnsupportedEncodingException iee)
282 catch (UnsupportedFlavorException ufe)
285 catch (IOException ioe)
289 return null;
293 * Called by the gtk+ clipboard when an application has requested an
294 * image. Returns a GtkImage representing the current clipboard
295 * contents or null when no image can be provided.
297 private GtkImage provideImage()
299 Transferable contents = this.contents;
300 if (contents == null || contents instanceof GtkSelection)
301 return null;
305 Object o = contents.getTransferData(DataFlavor.imageFlavor);
306 if( o instanceof GtkImage )
307 return (GtkImage) o;
308 else
309 return new GtkImage(((Image)o).getSource());
311 catch (UnsupportedFlavorException ufe)
314 catch (IOException ioe)
317 catch (ClassCastException cce)
321 return null;
325 * Called by the gtk+ clipboard when an application has requested a
326 * uri-list. Return a string array containing the URIs representing
327 * the current clipboard contents or null when no URIs can be
328 * provided.
330 private String[] provideURIs()
332 Transferable contents = this.contents;
333 if (contents == null || contents instanceof GtkSelection)
334 return null;
338 List list = (List) contents.getTransferData(DataFlavor.javaFileListFlavor);
339 String[] uris = new String[list.size()];
340 int u = 0;
341 Iterator it = list.iterator();
342 while (it.hasNext())
343 uris[u++] = ((File) it.next()).toURI().toString();
344 return uris;
346 catch (UnsupportedFlavorException ufe)
349 catch (IOException ioe)
352 catch (ClassCastException cce)
356 return null;
360 * Called by gtk+ clipboard when an application requests the given
361 * target mime-type. Returns a byte array containing the requested
362 * data, or null when the contents cannot be provided in the
363 * requested target mime-type. Only called after any explicit text,
364 * image or file/uri requests have been handled earlier and failed.
366 private byte[] provideContent(String target)
368 // Sanity check. The callback could be triggered just after we
369 // changed the clipboard.
370 Transferable contents = this.contents;
371 if (contents == null || contents instanceof GtkSelection)
372 return null;
374 // XXX - We are being called from a gtk+ callback. Which means we
375 // should return as soon as possible and not call arbitrary code
376 // that could deadlock or go bonkers. But we don't really know
377 // what DataTransfer contents object we are dealing with. Same for
378 // the other provideXXX() methods.
381 DataFlavor flavor = new DataFlavor(target);
382 Object o = contents.getTransferData(flavor);
384 if (o instanceof byte[])
385 return (byte[]) o;
387 if (o instanceof InputStream)
389 InputStream is = (InputStream) o;
390 ByteArrayOutputStream baos = new ByteArrayOutputStream();
391 byte[] bs = new byte[1024];
392 int l = is.read(bs);
393 while (l != -1)
395 baos.write(bs, 0, l);
396 l = is.read(bs);
398 return baos.toByteArray();
401 if (o instanceof Serializable)
403 ByteArrayOutputStream baos = new ByteArrayOutputStream();
404 ObjectOutputStream oos = new ObjectOutputStream(baos);
405 oos.writeObject(o);
406 oos.close();
407 return baos.toByteArray();
410 catch (ClassNotFoundException cnfe)
413 catch (UnsupportedFlavorException ufe)
416 catch (IOException ioe)
419 catch (ClassCastException cce)
423 return null;
427 * Initializes the gtk+ clipboards and caches any native side
428 * structures needed. Returns whether or not the contents of the
429 * Clipboard can be cached (gdk_display_supports_selection_notification).
431 private static native boolean initNativeState(GtkClipboard clipboard,
432 GtkClipboard selection,
433 String stringTarget,
434 String imageTarget,
435 String filesTarget);