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)
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
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
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
;
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
67 * The one and only gtk+ clipboard instance for the CLIPBOARD selection.
69 final static GtkClipboard clipboard
= new GtkClipboard("System Clipboard");
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
,
94 * Creates the clipboard and sets the initial contents to the
95 * current gtk+ selection.
97 private GtkClipboard(String name
)
100 setContents(new GtkSelection(this), null);
104 * Returns the one and only GtkClipboard instance for the CLIPBOARD
107 static GtkClipboard
getClipboardInstance()
113 * Returns the one and only GtkClipboard instance for the PRIMARY
116 static GtkClipboard
getSelectionInstance()
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
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
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);
162 // We don't need to do anything for a GtkSelection facade.
163 if (contents
instanceof GtkSelection
)
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()))
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
;
185 if ("text".equals(flavor
.getPrimaryType())
186 || flavor
.isRepresentationClassReader())
189 if (! images
&& flavors
[i
].equals(DataFlavor
.imageFlavor
))
193 Object o
= contents
.getTransferData(DataFlavor
.imageFlavor
);
194 if (o
instanceof Image
)
197 catch (UnsupportedFlavorException ufe
)
200 catch (IOException ioe
)
203 catch (ClassCastException cce
)
208 if (flavors
[i
].equals(DataFlavor
.javaFileListFlavor
))
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
,
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
)
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
);
265 CPStringBuilder sb
= new CPStringBuilder();
266 char[] cs
= new char[1024];
273 return sb
.toString();
276 catch (IllegalArgumentException iae
)
279 catch (UnsupportedEncodingException iee
)
282 catch (UnsupportedFlavorException ufe
)
285 catch (IOException ioe
)
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
)
305 Object o
= contents
.getTransferData(DataFlavor
.imageFlavor
);
306 if( o
instanceof GtkImage
)
309 return new GtkImage(((Image
)o
).getSource());
311 catch (UnsupportedFlavorException ufe
)
314 catch (IOException ioe
)
317 catch (ClassCastException cce
)
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
330 private String
[] provideURIs()
332 Transferable contents
= this.contents
;
333 if (contents
== null || contents
instanceof GtkSelection
)
338 List list
= (List
) contents
.getTransferData(DataFlavor
.javaFileListFlavor
);
339 String
[] uris
= new String
[list
.size()];
341 Iterator it
= list
.iterator();
343 uris
[u
++] = ((File
) it
.next()).toURI().toString();
346 catch (UnsupportedFlavorException ufe
)
349 catch (IOException ioe
)
352 catch (ClassCastException cce
)
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
)
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[])
387 if (o
instanceof InputStream
)
389 InputStream is
= (InputStream
) o
;
390 ByteArrayOutputStream baos
= new ByteArrayOutputStream();
391 byte[] bs
= new byte[1024];
395 baos
.write(bs
, 0, l
);
398 return baos
.toByteArray();
401 if (o
instanceof Serializable
)
403 ByteArrayOutputStream baos
= new ByteArrayOutputStream();
404 ObjectOutputStream oos
= new ObjectOutputStream(baos
);
407 return baos
.toByteArray();
410 catch (ClassNotFoundException cnfe
)
413 catch (UnsupportedFlavorException ufe
)
416 catch (IOException ioe
)
419 catch (ClassCastException cce
)
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
,