1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.dnd.Clipboard;
14 
15 
16 
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.SWTError;
19 import org.eclipse.swt.SWTException;
20 import org.eclipse.swt.internal.Converter;
21 import org.eclipse.swt.internal.gtk.OS;
22 import org.eclipse.swt.widgets.Display;
23 import org.eclipse.swt.dnd.Transfer;
24 import org.eclipse.swt.dnd.TransferData;
25 import org.eclipse.swt.dnd.DND;
26 import org.eclipse.swt.dnd.ClipboardProxy;
27 
28 import java.lang.all;
29 
30 import java.lang.Thread;
31 version(Tango){
32 static import tango.stdc..string;
33 } else { // Phobos
34 }
35 
36 /**
37  * The <code>Clipboard</code> provides a mechanism for transferring data from one
38  * application to another or within an application.
39  *
40  * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
41  *
42  * @see <a href="http://www.eclipse.org/swt/snippets/#clipboard">Clipboard snippets</a>
43  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ClipboardExample</a>
44  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
45  */
46 public class Clipboard {
47 
48     private Display display;
49 
50     static void* GTKCLIPBOARD;
51     static void* GTKPRIMARYCLIPBOARD;
52     private static void* TARGET;
53     private static bool static_this_completed = false;
54     private static void static_this(){
55         if( !static_this_completed ){
56             GTKCLIPBOARD = OS.gtk_clipboard_get( cast(void*)OS.GDK_NONE);
57             auto primary = OS.gdk_atom_intern("PRIMARY".ptr, false);
58             GTKPRIMARYCLIPBOARD = OS.gtk_clipboard_get(primary);
59             TARGET = OS.gdk_atom_intern("TARGETS".ptr, false);
60             static_this_completed = true;
61         }
62     }
63 
64 /**
65  * Constructs a new instance of this class.  Creating an instance of a Clipboard
66  * may cause system resources to be allocated depending on the platform.  It is therefore
67  * mandatory that the Clipboard instance be disposed when no longer required.
68  *
69  * @param display the display on which to allocate the clipboard
70  *
71  * @exception SWTException <ul>
72  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
73  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
74  * </ul>
75  *
76  * @see Clipboard#dispose
77  * @see Clipboard#checkSubclass
78  */
79 public this(Display display) {
80     checkSubclass ();
81     static_this();
82     if (display is null) {
83         display = Display.getCurrent();
84         if (display is null) {
85             display = Display.getDefault();
86         }
87     }
88     if (display.getThread() !is Thread.currentThread()) {
89         DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
90     }
91     this.display = display;
92 }
93 
94 /**
95  * Checks that this class can be subclassed.
96  * <p>
97  * The SWT class library is intended to be subclassed
98  * only at specific, controlled points. This method enforces this
99  * rule unless it is overridden.
100  * </p><p>
101  * <em>IMPORTANT:</em> By providing an implementation of this
102  * method that allows a subclass of a class which does not
103  * normally allow subclassing to be created, the implementer
104  * agrees to be fully responsible for the fact that any such
105  * subclass will likely fail between SWT releases and will be
106  * strongly platform specific. No support is provided for
107  * user-written classes which are implemented in this fashion.
108  * </p><p>
109  * The ability to subclass outside of the allowed SWT classes
110  * is intended purely to enable those not on the SWT development
111  * team to implement patches in order to get around specific
112  * limitations in advance of when those limitations can be
113  * addressed by the team. Subclassing should not be attempted
114  * without an intimate and detailed understanding of the hierarchy.
115  * </p>
116  *
117  * @exception SWTException <ul>
118  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
119  * </ul>
120  */
121 protected void checkSubclass () {
122     String name = this.classinfo.name;
123     String validName = Clipboard.classinfo.name;
124     if ( validName !=/*eq*/ name ) {
125         DND.error (SWT.ERROR_INVALID_SUBCLASS);
126     }
127 }
128 /**
129  * Throws an <code>SWTException</code> if the receiver can not
130  * be accessed by the caller. This may include both checks on
131  * the state of the receiver and more generally on the entire
132  * execution context. This method <em>should</em> be called by
133  * widget implementors to enforce the standard SWT invariants.
134  * <p>
135  * Currently, it is an error to invoke any method (other than
136  * <code>isDisposed()</code>) on a widget that has had its
137  * <code>dispose()</code> method called. It is also an error
138  * to call widget methods from any thread that is different
139  * from the thread that created the widget.
140  * </p><p>
141  * In future releases of SWT, there may be more or fewer error
142  * checks and exceptions may be thrown for different reasons.
143  * </p>
144  *
145  * @exception SWTException <ul>
146  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
147  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
148  * </ul>
149  */
150 protected void checkWidget () {
151     Display display = this.display;
152     if (display is null) DND.error (SWT.ERROR_WIDGET_DISPOSED);
153     if (display.getThread() !is Thread.currentThread ()) DND.error (SWT.ERROR_THREAD_INVALID_ACCESS);
154     if (display.isDisposed()) DND.error(SWT.ERROR_WIDGET_DISPOSED);
155 }
156 
157 /**
158  * If this clipboard is currently the owner of the data on the system clipboard,
159  * clear the contents.  If this clipboard is not the owner, then nothing is done.
160  * Note that there are clipboard assistant applications that take ownership of
161  * data or make copies of data when it is placed on the clipboard.  In these
162  * cases, it may not be possible to clear the clipboard.
163  *
164  * @exception SWTException <ul>
165  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
166  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
167  * </ul>
168  *
169  * @since 3.1
170  */
171 public void clearContents() {
172     clearContents(DND.CLIPBOARD);
173 }
174 
175 /**
176  * If this clipboard is currently the owner of the data on the specified
177  * clipboard, clear the contents.  If this clipboard is not the owner, then
178  * nothing is done.
179  *
180  * <p>Note that there are clipboard assistant applications that take ownership
181  * of data or make copies of data when it is placed on the clipboard.  In these
182  * cases, it may not be possible to clear the clipboard.</p>
183  *
184  * <p>The clipboards value is either one of the clipboard constants defined in
185  * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
186  * (that is, using the <code>int</code> "|" operator) two or more
187  * of those <code>DND</code> clipboard constants.</p>
188  *
189  * @param clipboards to be cleared
190  *
191  * @exception SWTException <ul>
192  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
193  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
194  * </ul>
195  *
196  * @see DND#CLIPBOARD
197  * @see DND#SELECTION_CLIPBOARD
198  *
199  * @since 3.1
200  */
201 public void clearContents(int clipboards) {
202     checkWidget();
203     ClipboardProxy proxy = ClipboardProxy._getInstance(display);
204     proxy.clear(this, clipboards);
205 }
206 
207 /**
208  * Disposes of the operating system resources associated with the clipboard.
209  * The data will still be available on the system clipboard after the dispose
210  * method is called.
211  *
212  * <p>NOTE: On some platforms the data will not be available once the application
213  * has exited or the display has been disposed.</p>
214  *
215  * @exception SWTException <ul>
216  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
217  * </ul>
218  */
219 public void dispose () {
220     if (isDisposed()) return;
221     if (display.getThread() !is Thread.currentThread()) DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
222     display = null;
223 }
224 
225 /**
226  * Retrieve the data of the specified type currently available on the system
227  * clipboard.  Refer to the specific subclass of <code>Transfer</code> to
228  * determine the type of object returned.
229  *
230  * <p>The following snippet shows text and RTF text being retrieved from the
231  * clipboard:</p>
232  *
233  *    <code><pre>
234  *    Clipboard clipboard = new Clipboard(display);
235  *    TextTransfer textTransfer = TextTransfer.getInstance();
236  *    String textData = (String)clipboard.getContents(textTransfer);
237  *    if (textData !is null) System.out.println("Text is "+textData);
238  *    RTFTransfer rtfTransfer = RTFTransfer.getInstance();
239  *    String rtfData = (String)clipboard.getContents(rtfTransfer);
240  *    if (rtfData !is null) System.out.println("RTF Text is "+rtfData);
241  *    clipboard.dispose();
242  *    </code></pre>
243  *
244  * @param transfer the transfer agent for the type of data being requested
245  * @return the data obtained from the clipboard or null if no data of this type is available
246  *
247  * @exception SWTException <ul>
248  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
249  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
250  * </ul>
251  * @exception IllegalArgumentException <ul>
252  *    <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
253  * </ul>
254  *
255  * @see Transfer
256  */
257 public Object getContents(Transfer transfer) {
258     return getContents(transfer, DND.CLIPBOARD);
259 }
260 
261 /**
262  * Retrieve the data of the specified type currently available on the specified
263  * clipboard.  Refer to the specific subclass of <code>Transfer</code> to
264  * determine the type of object returned.
265  *
266  * <p>The following snippet shows text and RTF text being retrieved from the
267  * clipboard:</p>
268  *
269  *    <code><pre>
270  *    Clipboard clipboard = new Clipboard(display);
271  *    TextTransfer textTransfer = TextTransfer.getInstance();
272  *    String textData = (String)clipboard.getContents(textTransfer);
273  *    if (textData !is null) System.out.println("Text is "+textData);
274  *    RTFTransfer rtfTransfer = RTFTransfer.getInstance();
275  *    String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD);
276  *    if (rtfData !is null) System.out.println("RTF Text is "+rtfData);
277  *    clipboard.dispose();
278  *    </code></pre>
279  *
280  * <p>The clipboards value is either one of the clipboard constants defined in
281  * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
282  * (that is, using the <code>int</code> "|" operator) two or more
283  * of those <code>DND</code> clipboard constants.</p>
284  *
285  * @param transfer the transfer agent for the type of data being requested
286  * @param clipboards on which to look for data
287  *
288  * @return the data obtained from the clipboard or null if no data of this type is available
289  *
290  * @exception SWTException <ul>
291  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
292  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
293  * </ul>
294  * @exception IllegalArgumentException <ul>
295  *    <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
296  * </ul>
297  *
298  * @see Transfer
299  * @see DND#CLIPBOARD
300  * @see DND#SELECTION_CLIPBOARD
301  *
302  * @since 3.1
303  */
304 public Object getContents(Transfer transfer, int clipboards) {
305     checkWidget();
306     if (transfer is null) DND.error(SWT.ERROR_NULL_ARGUMENT);
307     GtkSelectionData* selection_data;
308     auto typeIds = transfer.getTypeIds();
309     for (int i = 0; i < typeIds.length; i++) {
310         if ((clipboards & DND.CLIPBOARD) !is 0) {
311             selection_data = gtk_clipboard_wait_for_contents(GTKCLIPBOARD, cast(void*)typeIds[i]);
312         }
313         if (selection_data !is null) break;
314         if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) {
315             selection_data = gtk_clipboard_wait_for_contents(GTKPRIMARYCLIPBOARD, cast(void*)typeIds[i]);
316         }
317     }
318     if (selection_data is null) return null;
319     GtkSelectionData* gtkSelectionData = selection_data;
320     TransferData tdata = new TransferData();
321     tdata.type = gtkSelectionData.type;
322     tdata.pValue = gtkSelectionData.data;
323     tdata.length = gtkSelectionData.length;
324     tdata.format = gtkSelectionData.format;
325     Object result = transfer.nativeToJava(tdata);
326     OS.gtk_selection_data_free(selection_data);
327     return result;
328 }
329 
330 /**
331  * Returns <code>true</code> if the clipboard has been disposed,
332  * and <code>false</code> otherwise.
333  * <p>
334  * This method gets the dispose state for the clipboard.
335  * When a clipboard has been disposed, it is an error to
336  * invoke any other method using the clipboard.
337  * </p>
338  *
339  * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
340  *
341  * @since 3.0
342  */
343 public bool isDisposed () {
344     return (display is null);
345 }
346 
347 /**
348  * Place data of the specified type on the system clipboard.  More than one type
349  * of data can be placed on the system clipboard at the same time.  Setting the
350  * data clears any previous data from the system clipboard, regardless of type.
351  *
352  * <p>NOTE: On some platforms, the data is immediately copied to the system
353  * clipboard but on other platforms it is provided upon request.  As a result,
354  * if the application modifies the data object it has set on the clipboard, that
355  * modification may or may not be available when the data is subsequently
356  * requested.</p>
357  *
358  * <p>The following snippet shows text and RTF text being set on the copy/paste
359  * clipboard:
360  * </p>
361  *
362  * <code><pre>
363  *  Clipboard clipboard = new Clipboard(display);
364  *  String textData = "Hello World";
365  *  String rtfData = "{\\rtf1\\b\\i Hello World}";
366  *  TextTransfer textTransfer = TextTransfer.getInstance();
367  *  RTFTransfer rtfTransfer = RTFTransfer.getInstance();
368  *  Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
369  *  Object[] data = new Object[]{textData, rtfData};
370  *  clipboard.setContents(data, transfers);
371  *  clipboard.dispose();
372  * </code></pre>
373  *
374  * @param data the data to be set in the clipboard
375  * @param dataTypes the transfer agents that will convert the data to its
376  * platform specific format; each entry in the data array must have a
377  * corresponding dataType
378  *
379  * @exception IllegalArgumentException <ul>
380  *    <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
381  *          or the length of data is not the same as the length of dataTypes</li>
382  * </ul>
383  * @exception SWTException <ul>
384  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
385  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
386  * </ul>
387  *  @exception SWTError <ul>
388  *    <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
389  * </ul>
390  *
391  * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
392  * recoverable error, but can not be changed due to backward compatibility.</p>
393  */
394 public void setContents(Object[] data, Transfer[] dataTypes) {
395     setContents(data, dataTypes, DND.CLIPBOARD);
396 }
397 
398 /**
399  * Place data of the specified type on the specified clipboard.  More than one
400  * type of data can be placed on the specified clipboard at the same time.
401  * Setting the data clears any previous data from the specified
402  * clipboard, regardless of type.
403  *
404  * <p>NOTE: On some platforms, the data is immediately copied to the specified
405  * clipboard but on other platforms it is provided upon request.  As a result,
406  * if the application modifies the data object it has set on the clipboard, that
407  * modification may or may not be available when the data is subsequently
408  * requested.</p>
409  *
410  * <p>The clipboards value is either one of the clipboard constants defined in
411  * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
412  * (that is, using the <code>int</code> "|" operator) two or more
413  * of those <code>DND</code> clipboard constants.</p>
414  *
415  * <p>The following snippet shows text and RTF text being set on the copy/paste
416  * clipboard:
417  * </p>
418  *
419  * <code><pre>
420  *  Clipboard clipboard = new Clipboard(display);
421  *  String textData = "Hello World";
422  *  String rtfData = "{\\rtf1\\b\\i Hello World}";
423  *  TextTransfer textTransfer = TextTransfer.getInstance();
424  *  RTFTransfer rtfTransfer = RTFTransfer.getInstance();
425  *  Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
426  *  Object[] data = new Object[]{textData, rtfData};
427  *  clipboard.setContents(data, transfers, DND.CLIPBOARD);
428  *  clipboard.dispose();
429  * </code></pre>
430  *
431  * @param data the data to be set in the clipboard
432  * @param dataTypes the transfer agents that will convert the data to its
433  * platform specific format; each entry in the data array must have a
434  * corresponding dataType
435  * @param clipboards on which to set the data
436  *
437  * @exception IllegalArgumentException <ul>
438  *    <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
439  *          or the length of data is not the same as the length of dataTypes</li>
440  * </ul>
441  * @exception SWTException <ul>
442  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
443  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
444  * </ul>
445  *  @exception SWTError <ul>
446  *    <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
447  * </ul>
448  *
449  * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
450  * recoverable error, but can not be changed due to backward compatibility.</p>
451  *
452  * @see DND#CLIPBOARD
453  * @see DND#SELECTION_CLIPBOARD
454  *
455  * @since 3.1
456  */
457 public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) {
458     checkWidget();
459     if (data is null || dataTypes is null || data.length !is dataTypes.length || data.length is 0) {
460         DND.error(SWT.ERROR_INVALID_ARGUMENT);
461     }
462     for (int i = 0; i < data.length; i++) {
463         if (data[i] is null || dataTypes[i] is null || !dataTypes[i].validate(data[i])) {
464             DND.error(SWT.ERROR_INVALID_ARGUMENT);
465         }
466     }
467     ClipboardProxy proxy = ClipboardProxy._getInstance(display);
468     if (!proxy.setData(this, data, dataTypes, clipboards)) {
469         DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
470     }
471 }
472 
473 /**
474  * Returns an array of the data types currently available on the system
475  * clipboard. Use with Transfer.isSupportedType.
476  *
477  * @return array of data types currently available on the system clipboard
478  *
479  * @exception SWTException <ul>
480  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
481  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
482  * </ul>
483  *
484  * @see Transfer#isSupportedType
485  *
486  * @since 3.0
487  */
488 public TransferData[] getAvailableTypes() {
489     return getAvailableTypes(DND.CLIPBOARD);
490 }
491 
492 /**
493  * Returns an array of the data types currently available on the specified
494  * clipboard. Use with Transfer.isSupportedType.
495  *
496  * <p>The clipboards value is either one of the clipboard constants defined in
497  * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
498  * (that is, using the <code>int</code> "|" operator) two or more
499  * of those <code>DND</code> clipboard constants.</p>
500  *
501  * @param clipboards from which to get the data types
502  * @return array of data types currently available on the specified clipboard
503  *
504  * @exception SWTException <ul>
505  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
506  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
507  * </ul>
508  *
509  * @see Transfer#isSupportedType
510  * @see DND#CLIPBOARD
511  * @see DND#SELECTION_CLIPBOARD
512  *
513  * @since 3.1
514  */
515 public TransferData[] getAvailableTypes(int clipboards) {
516     checkWidget();
517     TransferData[] result = null;
518     if ((clipboards & DND.CLIPBOARD) !is 0) {
519         auto types = getAvailableClipboardTypes();
520         result = new TransferData[types.length];
521         for (int i = 0; i < types.length; i++) {
522             result[i] = new TransferData();
523             result[i].type = types[i];
524         }
525     }
526     if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) {
527         auto types = getAvailablePrimaryTypes();
528         size_t offset = 0;
529         if (result !is null) {
530             TransferData[] newResult = new TransferData[result.length + types.length];
531             System.arraycopy(result,0, newResult, 0, result.length);
532             offset = result.length;
533             result = newResult;
534         } else {
535             result = new TransferData[types.length];
536         }
537         for (size_t i = 0; i < types.length; i++) {
538             result[offset+i] = new TransferData();
539             result[offset+i].type = types[i];
540         }
541     }
542     return result is null ? new TransferData[0] : result;
543 }
544 
545 /**
546  * Returns a platform specific list of the data types currently available on the
547  * system clipboard.
548  *
549  * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer
550  * sub-class.  It should NOT be used within an application because it provides
551  * platform specific information.</p>
552  *
553  * @return a platform specific list of the data types currently available on the
554  * system clipboard
555  *
556  * @exception SWTException <ul>
557  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
558  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
559  * </ul>
560  */
561 public String[] getAvailableTypeNames() {
562     checkWidget();
563     auto types1 = getAvailableClipboardTypes();
564     auto types2 = getAvailablePrimaryTypes();
565     String[] result = new String[types1.length + types2.length];
566     int count = 0;
567     for (int i = 0; i < types1.length; i++) {
568         auto pName = OS.gdk_atom_name(types1[i]);
569         if (pName is null) {
570             continue;
571         }
572         String buffer = fromStringz( pName )._idup();
573         OS.g_free (pName);
574         result[count++] = "GTKCLIPBOARD "~buffer;
575     }
576     for (int i = 0; i < types2.length; i++) {
577         auto pName = OS.gdk_atom_name(types2[i]);
578         if (pName is null) {
579             continue;
580         }
581         String buffer = fromStringz( pName )._idup();
582         OS.g_free (pName);
583         result[count++] = "GTKPRIMARYCLIPBOARD "~buffer;
584     }
585     if (count < result.length){
586         String[] temp = new String[count];
587         System.arraycopy(result, 0, temp, 0, count);
588         result = temp;
589     }
590     return result;
591 }
592 
593 private  void*[] getAvailablePrimaryTypes() {
594     void*[] types;
595     auto selection_data = gtk_clipboard_wait_for_contents(GTKPRIMARYCLIPBOARD, TARGET);
596     if (selection_data !is null) {
597         try {
598             GtkSelectionData* gtkSelectionData = selection_data;
599             if (gtkSelectionData.length !is 0) {
600                 types = cast(void*[])new int[gtkSelectionData.length * 8 / gtkSelectionData.format];
601                 OS.memmove( cast(void*)types.ptr, gtkSelectionData.data, gtkSelectionData.length );
602             }
603         } finally {
604             OS.gtk_selection_data_free(selection_data);
605         }
606     }
607     return types;
608 }
609 private void*[] getAvailableClipboardTypes () {
610     void*[] types;
611     auto selection_data  = gtk_clipboard_wait_for_contents(GTKCLIPBOARD, TARGET);
612     if (selection_data !is null) {
613         try {
614             GtkSelectionData* gtkSelectionData = selection_data;
615             if (gtkSelectionData.length !is 0) {
616                 types = cast(void*[])new int[gtkSelectionData.length * 8 / gtkSelectionData.format];
617                 OS.memmove( cast(void*)types, gtkSelectionData.data, gtkSelectionData.length);
618             }
619         } finally {
620             OS.gtk_selection_data_free(selection_data);
621         }
622     }
623     return types;
624 }
625 
626 GtkSelectionData* gtk_clipboard_wait_for_contents(void* clipboard, void* target) {
627     String key = "org.eclipse.swt.internal.gtk.dispatchEvent";
628     Display display = this.display;
629     ArrayWrapperInt arr = new ArrayWrapperInt( [ OS.GDK_PROPERTY_NOTIFY, OS.GDK_SELECTION_CLEAR, OS.GDK_SELECTION_REQUEST, OS.GDK_SELECTION_NOTIFY ] );
630     display.setData(key, arr );
631     GtkSelectionData* selection_data = OS.gtk_clipboard_wait_for_contents(clipboard, target);
632     display.setData(key, null);
633     return selection_data;
634 }
635 }