Skip to content

Commit 9e3ae28

Browse files
committed
Add getContentsAsync methods to Clipboard
Obtaining data from the clipboard is fundamentally an asynchronous operation, the event loop, at least at the OS level, needs to run for the data to become available. This PR proposes new API that provides asynchronous equivalents of getContents methods called getContentsAsync that return CompleteableFutures. This new API will allow SWT API consumers to interact better with the clipboard when the OS (window system) API is actually implemented in an asynchronous manner. GTK3 and cocoa provides API that spins the event loop as needed so that a synchronous looking API can be provided to the user of the API. For example, in SWT we use gtk_clipboard_wait_for_contents which spins the loop in the GTK library itself [here](https://gitlab.gnome.org/GNOME/gtk/-/blob/716458e86a222f43e64f7a4feda37749f3469ee4/gtk/gtkclipboard.c#L1436) GTK4 does not provide such an API and leaves it to the user of the API to spin the event loop. Win32 is somewhat of a hybrid. The API appears synchronous, but SWT needs to spin in a couple of places, such as [getData](https://github.com/eclipse-platform/eclipse.platform.swt/blob/63e8925dc77db3b93ef521dc6cf2bd6ded7bab64/bundles/org.eclipse.swt/Eclipse%20SWT%20Drag%20and%20Drop/win32/org/eclipse/swt/dnd/Transfer.java#L46) Part of #2598 and #2126
1 parent 03cc46e commit 9e3ae28

File tree

5 files changed

+377
-54
lines changed

5 files changed

+377
-54
lines changed

bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Clipboard.java

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*******************************************************************************/
1414
package org.eclipse.swt.dnd;
1515

16+
import java.util.concurrent.*;
1617

1718
import org.eclipse.swt.*;
1819
import org.eclipse.swt.internal.cocoa.*;
@@ -199,6 +200,10 @@ public void dispose () {
199200
* clipboard. Refer to the specific subclass of <code>Transfer</code> to
200201
* determine the type of object returned.
201202
*
203+
* <p>This method may iterate the event loop to be able to complete. Use
204+
* {@link #getContentsAsync(Transfer)} to have control over when the event
205+
* loop runs.</p>
206+
*
202207
* <p>The following snippet shows text and RTF text being retrieved from the
203208
* clipboard:</p>
204209
*
@@ -225,6 +230,7 @@ public void dispose () {
225230
* </ul>
226231
*
227232
* @see Transfer
233+
* @see #getContentsAsync(Transfer)
228234
*/
229235
public Object getContents(Transfer transfer) {
230236
return getContents(transfer, DND.CLIPBOARD);
@@ -235,6 +241,10 @@ public Object getContents(Transfer transfer) {
235241
* clipboard. Refer to the specific subclass of <code>Transfer</code> to
236242
* determine the type of object returned.
237243
*
244+
* <p>This method may iterate the event loop to be able to complete. Use
245+
* {@link #getContentsAsync(Transfer, int)} to have control over when the event
246+
* loop runs.</p>
247+
*
238248
* <p>The following snippet shows text and RTF text being retrieved from the
239249
* clipboard:</p>
240250
*
@@ -270,6 +280,7 @@ public Object getContents(Transfer transfer) {
270280
* @see Transfer
271281
* @see DND#CLIPBOARD
272282
* @see DND#SELECTION_CLIPBOARD
283+
* @see #getContentsAsync(Transfer, int)
273284
*
274285
* @since 3.1
275286
*/
@@ -308,6 +319,90 @@ public Object getContents(Transfer transfer, int clipboards) {
308319
return null;
309320
}
310321

322+
/**
323+
* Retrieve the data of the specified type currently available on the system
324+
* clipboard. Refer to the specific subclass of <code>Transfer</code> to
325+
* determine the type of object returned.
326+
*
327+
* <p>This method is asynchronous and may require the SWT event loop to
328+
* iterate before the future will complete.</p>
329+
*
330+
* <p>The following snippet shows text being retrieved from the clipboard:</p>
331+
*
332+
* <pre><code>
333+
* Clipboard clipboard = new Clipboard(display);
334+
* TextTransfer textTransfer = TextTransfer.getInstance();
335+
* CompletableFuture&lt;Object&gt; future = clipboard.getContentsAsync(textTransfer);
336+
* future.thenAccept(textData -&gt; System.out.println("Text is "+textData));
337+
* clipboard.dispose();
338+
* </code></pre>
339+
*
340+
* @param transfer the transfer agent for the type of data being requested
341+
* @return the future whose value will resolve to the data obtained from the
342+
* clipboard or will resolve to null if no data of this type is available
343+
*
344+
* @exception SWTException <ul>
345+
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
346+
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
347+
* </ul>
348+
* @exception IllegalArgumentException <ul>
349+
* <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
350+
* </ul>
351+
*
352+
* @see Transfer
353+
* @since 3.132
354+
*/
355+
public CompletableFuture<Object> getContentsAsync(Transfer transfer) {
356+
return getContentsAsync(transfer, DND.CLIPBOARD);
357+
}
358+
359+
/**
360+
* Retrieve the data of the specified type currently available on the specified
361+
* clipboard. Refer to the specific subclass of <code>Transfer</code> to
362+
* determine the type of object returned.
363+
*
364+
* <p>This method is asynchronous and may require the SWT event loop to
365+
* iterate before the future will complete.</p>
366+
*
367+
* <p>The following snippet shows text being retrieved from the clipboard:</p>
368+
*
369+
* <pre><code>
370+
* Clipboard clipboard = new Clipboard(display);
371+
* TextTransfer textTransfer = TextTransfer.getInstance();
372+
* CompletableFuture&lt;Object&gt; future = clipboard.getContentsAsync(textTransfer, DND.CLIPBOARD);
373+
* future.thenAccept(textData -&gt; System.out.println("Text is "+textData));
374+
* clipboard.dispose();
375+
* </code></pre>
376+
*
377+
* <p>The clipboards value is either one of the clipboard constants defined in
378+
* class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
379+
* (that is, using the <code>int</code> "|" operator) two or more
380+
* of those <code>DND</code> clipboard constants.</p>
381+
*
382+
* @param transfer the transfer agent for the type of data being requested
383+
* @param clipboards on which to look for data
384+
*
385+
* @return the future whose value will resolve to the data obtained from the
386+
* clipboard or will resolve to null if no data of this type is available
387+
*
388+
* @exception SWTException <ul>
389+
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
390+
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
391+
* </ul>
392+
* @exception IllegalArgumentException <ul>
393+
* <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
394+
* </ul>
395+
*
396+
* @see Transfer
397+
* @see DND#CLIPBOARD
398+
* @see DND#SELECTION_CLIPBOARD
399+
*
400+
* @since 3.132
401+
*/
402+
public CompletableFuture<Object> getContentsAsync(Transfer transfer, int clipboards) {
403+
return CompletableFuture.completedFuture(getContents(transfer, clipboards));
404+
}
405+
311406
/**
312407
* Returns <code>true</code> if the clipboard has been disposed,
313408
* and <code>false</code> otherwise.

bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Clipboard.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
package org.eclipse.swt.dnd;
1515

1616

17+
import java.util.concurrent.*;
18+
1719
import org.eclipse.swt.*;
1820
import org.eclipse.swt.graphics.*;
1921
import org.eclipse.swt.internal.*;
@@ -215,6 +217,10 @@ public void dispose () {
215217
* clipboard. Refer to the specific subclass of <code>Transfer</code> to
216218
* determine the type of object returned.
217219
*
220+
* <p>This method may iterate the event loop to be able to complete. Use
221+
* {@link #getContentsAsync(Transfer)} to have control over when the event
222+
* loop runs.</p>
223+
*
218224
* <p>The following snippet shows text and RTF text being retrieved from the
219225
* clipboard:</p>
220226
*
@@ -241,6 +247,7 @@ public void dispose () {
241247
* </ul>
242248
*
243249
* @see Transfer
250+
* @see #getContentsAsync(Transfer)
244251
*/
245252
public Object getContents(Transfer transfer) {
246253
return getContents(transfer, DND.CLIPBOARD);
@@ -251,6 +258,10 @@ public Object getContents(Transfer transfer) {
251258
* clipboard. Refer to the specific subclass of <code>Transfer</code> to
252259
* determine the type of object returned.
253260
*
261+
* <p>This method may iterate the event loop to be able to complete. Use
262+
* {@link #getContentsAsync(Transfer, int)} to have control over when the event
263+
* loop runs.</p>
264+
*
254265
* <p>The following snippet shows text and RTF text being retrieved from the
255266
* clipboard:</p>
256267
*
@@ -286,6 +297,7 @@ public Object getContents(Transfer transfer) {
286297
* @see Transfer
287298
* @see DND#CLIPBOARD
288299
* @see DND#SELECTION_CLIPBOARD
300+
* @see #getContentsAsync(Transfer, int)
289301
*
290302
* @since 3.1
291303
*/
@@ -326,6 +338,90 @@ public Object getContents(Transfer transfer, int clipboards) {
326338
return result;
327339
}
328340

341+
/**
342+
* Retrieve the data of the specified type currently available on the system
343+
* clipboard. Refer to the specific subclass of <code>Transfer</code> to
344+
* determine the type of object returned.
345+
*
346+
* <p>This method is asynchronous and may require the SWT event loop to
347+
* iterate before the future will complete.</p>
348+
*
349+
* <p>The following snippet shows text being retrieved from the clipboard:</p>
350+
*
351+
* <pre><code>
352+
* Clipboard clipboard = new Clipboard(display);
353+
* TextTransfer textTransfer = TextTransfer.getInstance();
354+
* CompletableFuture&lt;Object&gt; future = clipboard.getContentsAsync(textTransfer);
355+
* future.thenAccept(textData -&gt; System.out.println("Text is "+textData));
356+
* clipboard.dispose();
357+
* </code></pre>
358+
*
359+
* @param transfer the transfer agent for the type of data being requested
360+
* @return the future whose value will resolve to the data obtained from the
361+
* clipboard or will resolve to null if no data of this type is available
362+
*
363+
* @exception SWTException <ul>
364+
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
365+
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
366+
* </ul>
367+
* @exception IllegalArgumentException <ul>
368+
* <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
369+
* </ul>
370+
*
371+
* @see Transfer
372+
* @since 3.132
373+
*/
374+
public CompletableFuture<Object> getContentsAsync(Transfer transfer) {
375+
return getContentsAsync(transfer, DND.CLIPBOARD);
376+
}
377+
378+
/**
379+
* Retrieve the data of the specified type currently available on the specified
380+
* clipboard. Refer to the specific subclass of <code>Transfer</code> to
381+
* determine the type of object returned.
382+
*
383+
* <p>This method is asynchronous and may require the SWT event loop to
384+
* iterate before the future will complete.</p>
385+
*
386+
* <p>The following snippet shows text being retrieved from the clipboard:</p>
387+
*
388+
* <pre><code>
389+
* Clipboard clipboard = new Clipboard(display);
390+
* TextTransfer textTransfer = TextTransfer.getInstance();
391+
* CompletableFuture&lt;Object&gt; future = clipboard.getContentsAsync(textTransfer, DND.CLIPBOARD);
392+
* future.thenAccept(textData -&gt; System.out.println("Text is "+textData));
393+
* clipboard.dispose();
394+
* </code></pre>
395+
*
396+
* <p>The clipboards value is either one of the clipboard constants defined in
397+
* class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
398+
* (that is, using the <code>int</code> "|" operator) two or more
399+
* of those <code>DND</code> clipboard constants.</p>
400+
*
401+
* @param transfer the transfer agent for the type of data being requested
402+
* @param clipboards on which to look for data
403+
*
404+
* @return the future whose value will resolve to the data obtained from the
405+
* clipboard or will resolve to null if no data of this type is available
406+
*
407+
* @exception SWTException <ul>
408+
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
409+
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
410+
* </ul>
411+
* @exception IllegalArgumentException <ul>
412+
* <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
413+
* </ul>
414+
*
415+
* @see Transfer
416+
* @see DND#CLIPBOARD
417+
* @see DND#SELECTION_CLIPBOARD
418+
*
419+
* @since 3.132
420+
*/
421+
public CompletableFuture<Object> getContentsAsync(Transfer transfer, int clipboards) {
422+
return CompletableFuture.completedFuture(getContents(transfer, clipboards));
423+
}
424+
329425
private Object getContents_gtk4(Transfer transfer, int clipboards) {
330426

331427
long contents = GTK4.gdk_clipboard_get_content(Clipboard.GTKCLIPBOARD);

0 commit comments

Comments
 (0)