Skip to content

Commit b300e03

Browse files
committed
WIP - [GTK4] support Clipboard
Fixes #2126
1 parent 0ea736d commit b300e03

36 files changed

+2842
-330
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ public static int registerType(String formatName) {
136136
int index = 1;
137137
while (index < TYPES.length) {
138138
String type = TYPES[index];
139-
if (type != null && formatName.equals(type)) {
139+
if (type == null) {
140+
break;
141+
}
142+
if (formatName.equals(type)) {
140143
return index;
141144
}
142145
index++;

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

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

16+
import org.eclipse.swt.dnd.TransferData.*;
1617
import org.eclipse.swt.internal.*;
1718
import org.eclipse.swt.internal.gtk.*;
1819

@@ -136,6 +137,7 @@ public TransferData[] getSupportedTypes() {
136137

137138
@Override
138139
public boolean isSupportedType(TransferData transferData){
140+
if (GTK.GTK4) return isSupportedTypeGTK4(transferData);
139141
if (transferData == null) return false;
140142
int[] types = getTypeIds();
141143
for (int i = 0; i < types.length; i++) {
@@ -144,6 +146,15 @@ public boolean isSupportedType(TransferData transferData){
144146
return false;
145147
}
146148

149+
private boolean isSupportedTypeGTK4(TransferData transferData) {
150+
if (transferData == null) return false;
151+
int[] types = getTypeIds();
152+
for (int i = 0; i < types.length; i++) {
153+
if (transferData.gtk4().type == types[i]) return true;
154+
}
155+
return false;
156+
}
157+
147158
/**
148159
* This implementation of <code>javaToNative</code> converts a java
149160
* <code>byte[]</code> to a platform specific representation.
@@ -156,7 +167,11 @@ public boolean isSupportedType(TransferData transferData){
156167
*/
157168
@Override
158169
protected void javaToNative (Object object, TransferData transferData) {
159-
transferData.result = 0;
170+
if (GTK.GTK4) {
171+
javaToNativeGTK4(object, transferData);
172+
return;
173+
}
174+
transferData.gtk3().result = 0;
160175
if (!checkByteArray(object) || !isSupportedType(transferData)) {
161176
DND.error(DND.ERROR_INVALID_DATA);
162177
}
@@ -165,10 +180,59 @@ protected void javaToNative (Object object, TransferData transferData) {
165180
long pValue = OS.g_malloc(buffer.length);
166181
if (pValue == 0) return;
167182
C.memmove(pValue, buffer, buffer.length);
168-
transferData.length = buffer.length;
169-
transferData.format = 8;
170-
transferData.pValue = pValue;
171-
transferData.result = 1;
183+
transferData.gtk3().length = buffer.length;
184+
transferData.gtk3().format = 8;
185+
transferData.gtk3().pValue = pValue;
186+
transferData.gtk3().result = 1;
187+
}
188+
189+
private void javaToNativeGTK4(Object object, TransferData transferData) {
190+
if (!checkByteArray(object) || !isSupportedType(transferData)) {
191+
DND.error(DND.ERROR_INVALID_DATA);
192+
}
193+
byte[] buffer = (byte[]) object;
194+
if (buffer.length == 0) {
195+
return;
196+
}
197+
TransferDataGTK4 data = transferData.gtk4();
198+
GdkContentSerializer serializer = data.serializer;
199+
200+
long pValue = OS.g_malloc(buffer.length);
201+
if (pValue == 0) {
202+
return;
203+
}
204+
C.memmove(pValue, buffer, buffer.length);
205+
206+
// Sync version - this won't work if the other end of the stream is in our process (such as a Clipboard.getContents call).
207+
// long[] error = new long[1];
208+
// boolean finish = OS.g_output_stream_write_all(serializer.output_stream(), pValue, buffer.length, null,
209+
// serializer.cancellable(), error);
210+
// if (!finish) {
211+
// serializer.return_error(error[0]);
212+
// } else {
213+
// serializer.return_success();
214+
// }
215+
// Async version:
216+
new AsyncFinishUtil().run(data.display, new AsyncReadyCallback() {
217+
@Override
218+
public void async(long result) {
219+
OS.g_output_stream_write_all_async(serializer.output_stream(), pValue, buffer.length, serializer.priority(),
220+
serializer.cancellable(), result, 0);
221+
}
222+
223+
@Override
224+
public long await(long result) {
225+
long[] error = new long[1];
226+
boolean finish = OS.g_output_stream_write_all_finish(serializer.output_stream(), result, null, error);
227+
if (!finish) {
228+
serializer.return_error(error[0]);
229+
} else {
230+
serializer.return_success();
231+
}
232+
OS.g_free(pValue);
233+
return 0;
234+
}
235+
});
172236
}
173237

174238
/**
@@ -183,14 +247,56 @@ protected void javaToNative (Object object, TransferData transferData) {
183247
*/
184248
@Override
185249
protected Object nativeToJava(TransferData transferData) {
186-
if ( !isSupportedType(transferData) || transferData.pValue == 0) return null;
187-
int size = transferData.format * transferData.length / 8;
250+
if (GTK.GTK4) return nativeToJavaGTK4(transferData);
251+
if ( !isSupportedType(transferData) || transferData.gtk3().pValue == 0) return null;
252+
int size = transferData.gtk3().format * transferData.gtk3().length / 8;
188253
if (size == 0) return null;
189254
byte[] buffer = new byte[size];
190-
C.memmove(buffer, transferData.pValue, size);
255+
C.memmove(buffer, transferData.gtk3().pValue, size);
191256
return buffer;
192257
}
193258

259+
private Object nativeToJavaGTK4(TransferData transferData) {
260+
TransferDataGTK4 data = transferData.gtk4();
261+
if (!isSupportedType(transferData) || data.deserializer == null)
262+
return null;
263+
264+
GdkContentDeserializer deserializer = data.deserializer;
265+
long memoryStream = OS.g_memory_output_stream_new_resizable();
266+
System.out.println("About to run g_output_stream_splice_async");
267+
boolean success = new SyncFinishUtil<Boolean>().run(data.display, new SyncFinishCallback<Boolean>() {
268+
@Override
269+
public void async(long result) {
270+
OS.g_output_stream_splice_async(memoryStream, deserializer.input_stream(),
271+
OS.G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | OS.G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
272+
deserializer.priority(), deserializer.cancellable(), result, 0);
273+
}
274+
275+
@Override
276+
public Boolean await(long result) {
277+
long[] error = new long[1];
278+
long spliced = OS.g_output_stream_splice_finish(memoryStream, result, null);
279+
if (spliced < 0) {
280+
deserializer.return_error(error[0]);
281+
return false;
282+
} else {
283+
deserializer.return_success();
284+
return true;
285+
}
286+
}
287+
});
288+
289+
if (success) {
290+
long data_size = OS.g_memory_output_stream_get_data_size(memoryStream);
291+
long dataPtr = OS.g_memory_output_stream_get_data(memoryStream);
292+
byte[] buffer = new byte[(int)data_size];
293+
C.memmove(buffer, dataPtr, data_size);
294+
return buffer;
295+
}
296+
297+
return null;
298+
}
299+
194300
boolean checkByteArray(Object object) {
195301
return (object instanceof byte[] && ((byte[])object).length > 0);
196302
}

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

Lines changed: 31 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616

1717
import org.eclipse.swt.*;
18-
import org.eclipse.swt.graphics.*;
1918
import org.eclipse.swt.internal.*;
2019
import org.eclipse.swt.internal.gtk.*;
2120
import org.eclipse.swt.internal.gtk3.*;
@@ -188,8 +187,13 @@ public void clearContents() {
188187
*/
189188
public void clearContents(int clipboards) {
190189
checkWidget();
191-
ClipboardProxy proxy = ClipboardProxy._getInstance(display);
192-
proxy.clear(this, clipboards);
190+
if (GTK.GTK4) {
191+
ClipboardProxyGTK4 proxy = ClipboardProxyGTK4._getInstance(display);
192+
proxy.clear(this, clipboards);
193+
} else {
194+
ClipboardProxy proxy = ClipboardProxy._getInstance(display);
195+
proxy.clear(this, clipboards);
196+
}
193197
}
194198

195199
/**
@@ -290,14 +294,12 @@ public Object getContents(Transfer transfer) {
290294
* @since 3.1
291295
*/
292296
public Object getContents(Transfer transfer, int clipboards) {
293-
checkWidget();
294-
if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
295-
296-
if(GTK.GTK4) {
297-
Object result = getContents_gtk4(transfer, clipboards);
298-
return result;
297+
if (GTK.GTK4) {
298+
return getContents_gtk4(transfer, clipboards);
299299
}
300300

301+
checkWidget();
302+
if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
301303
long selection_data = 0;
302304
int[] typeIds = transfer.getTypeIds();
303305
boolean textTransfer = transfer.getTypeNames()[0].equals("UTF8_STRING");
@@ -312,9 +314,9 @@ public Object getContents(Transfer transfer, int clipboards) {
312314
if (selection_data != 0) {
313315
TransferData tdata = new TransferData();
314316
tdata.type = GTK3.gtk_selection_data_get_data_type(selection_data);
315-
tdata.pValue = GTK3.gtk_selection_data_get_data(selection_data);
316-
tdata.length = GTK3.gtk_selection_data_get_length(selection_data);
317-
tdata.format = GTK3.gtk_selection_data_get_format(selection_data);
317+
tdata.gtk3().pValue = GTK3.gtk_selection_data_get_data(selection_data);
318+
tdata.gtk3().length = GTK3.gtk_selection_data_get_length(selection_data);
319+
tdata.gtk3().format = GTK3.gtk_selection_data_get_format(selection_data);
318320
result = transfer.nativeToJava(tdata);
319321
GTK3.gtk_selection_data_free(selection_data);
320322
selection_data = 0;
@@ -327,65 +329,11 @@ public Object getContents(Transfer transfer, int clipboards) {
327329
}
328330

329331
private Object getContents_gtk4(Transfer transfer, int clipboards) {
332+
checkWidget();
333+
if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
330334

331-
long contents = GTK4.gdk_clipboard_get_content(Clipboard.GTKCLIPBOARD);
332-
if(contents == 0) return null;
333-
long value = OS.g_malloc (OS.GValue_sizeof ());
334-
C.memset (value, 0, OS.GValue_sizeof ());
335-
336-
//Pasting of text (TextTransfer/RTFTransfer)
337-
if(transfer.getTypeNames()[0].equals("text/plain") || transfer.getTypeNames()[0].equals("text/rtf")) {
338-
OS.g_value_init(value, OS.G_TYPE_STRING());
339-
if (!GTK4.gdk_content_provider_get_value (contents, value, null)) return null;
340-
long cStr = OS.g_value_get_string(value);
341-
long [] items_written = new long [1];
342-
long utf16Ptr = OS.g_utf8_to_utf16(cStr, -1, null, items_written, null);
343-
OS.g_free(cStr);
344-
if (utf16Ptr == 0) return null;
345-
int length = (int)items_written[0];
346-
char[] buffer = new char[length];
347-
C.memmove(buffer, utf16Ptr, length * 2);
348-
OS.g_free(utf16Ptr);
349-
String str = new String(buffer);
350-
if(transfer.getTypeNames()[0].equals("text/rtf") && !str.contains("{\\rtf1")) {
351-
return null;
352-
}
353-
if(transfer.getTypeNames()[0].equals("text/plain") && str.contains("{\\rtf1")){
354-
return null;
355-
}
356-
return str;
357-
}
358-
//Pasting of Image
359-
if(transfer.getTypeIds()[0] == (int)GDK.GDK_TYPE_PIXBUF()) {
360-
ImageData imgData = null;
361-
OS.g_value_init(value, GDK.GDK_TYPE_PIXBUF());
362-
if (!GTK4.gdk_content_provider_get_value (contents, value, null)) return null;
363-
long pixbufObj = OS.g_value_get_object(value);
364-
if (pixbufObj != 0) {
365-
Image img = Image.gtk_new_from_pixbuf(Display.getCurrent(), SWT.BITMAP, pixbufObj);
366-
imgData = img.getImageData();
367-
img.dispose();
368-
}
369-
return imgData;
370-
}
371-
//Pasting of HTML
372-
if(transfer.getTypeNames()[0].equals("text/html")) {
373-
OS.g_value_init(value, OS.G_TYPE_STRING());
374-
if (!GTK4.gdk_content_provider_get_value (contents, value, null)) return null;
375-
long cStr = OS.g_value_get_string(value);
376-
long [] items_written = new long [1];
377-
long utf16Ptr = OS.g_utf8_to_utf16(cStr, -1, null, items_written, null);
378-
OS.g_free(cStr);
379-
if (utf16Ptr == 0) return null;
380-
int length = (int)items_written[0];
381-
char[] buffer = new char[length];
382-
C.memmove(buffer, utf16Ptr, length * 2);
383-
OS.g_free(utf16Ptr);
384-
String str = new String(buffer);
385-
return str;
386-
}
387-
//TODO: [GTK4] Other cases
388-
return null;
335+
ClipboardProxyGTK4 proxy = ClipboardProxyGTK4._getInstance(display);
336+
return proxy.getData(this, transfer, clipboards);
389337
}
390338

391339
/**
@@ -525,9 +473,16 @@ public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) {
525473
DND.error(SWT.ERROR_INVALID_ARGUMENT);
526474
}
527475
}
528-
ClipboardProxy proxy = ClipboardProxy._getInstance(display);
529-
if (!proxy.setData(this, data, dataTypes, clipboards)) {
530-
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
476+
if (GTK.GTK4) {
477+
ClipboardProxyGTK4 proxy = ClipboardProxyGTK4._getInstance(display);
478+
if (!proxy.setData(this, data, dataTypes, clipboards)) {
479+
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
480+
}
481+
} else {
482+
ClipboardProxy proxy = ClipboardProxy._getInstance(display);
483+
if (!proxy.setData(this, data, dataTypes, clipboards)) {
484+
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
485+
}
531486
}
532487
}
533488

@@ -625,6 +580,7 @@ public String[] getAvailableTypeNames() {
625580
if(GTK.GTK4) {
626581
long formatsCStr = GTK4.gdk_content_formats_to_string(GTK4.gdk_clipboard_get_formats(Clipboard.GTKCLIPBOARD));
627582
String formatsStr = Converter.cCharPtrToJavaString(formatsCStr, true);
583+
System.out.println(formatsStr);
628584
String[] types = formatsStr.split(" ");
629585
return types;
630586
}
@@ -723,4 +679,6 @@ long gtk_clipboard_wait_for_contents(long clipboard, long target) {
723679
}
724680
return selection_data;
725681
}
682+
683+
726684
}

0 commit comments

Comments
 (0)