From 0ea736d03ec30519289ff370c5c1a0802b87822e Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Wed, 24 Sep 2025 11:59:08 -0400 Subject: [PATCH 1/2] Improve support for Arrays of Strings in JNI Generator A number of places in the GTK4 API there is the possibility of passing in arrays of Strings, i.e. Java String[] -> char ** as input argument to C side. This change adds better support to the JNI generator for this use case by converting the jobjectArray (String[]) to char ** on the C side. Part of #2126 Split out of #2538 --- .../eclipse/swt/tools/internal/ASTType.java | 5 ++- .../swt/tools/internal/NativesGenerator.java | 24 ++++++++++ .../swt/tools/internal/ReflectType.java | 5 ++- .../META-INF/MANIFEST.MF | 2 +- .../Eclipse SWT PI/gtk/library/os_custom.c | 45 +++++++++++++++++++ .../Eclipse SWT PI/gtk/library/os_custom.h | 3 ++ .../org.eclipse.swt.tools.feature/feature.xml | 2 +- 7 files changed, 82 insertions(+), 4 deletions(-) diff --git a/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ASTType.java b/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ASTType.java index 1c9cfd55d4e..538e81ea1ed 100644 --- a/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ASTType.java +++ b/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ASTType.java @@ -148,7 +148,10 @@ public String getTypeSignature2() { if (name.equals("Ljava/lang/String;")) return "jstring"; if (name.equals("Ljava/lang/Class;")) return "jclass"; if (isArray()) { - return getComponentType().getTypeSignature2() + "Array"; + if (getComponentType().isPrimitive()) { + return getComponentType().getTypeSignature2() + "Array"; + } + return "jobjectArray"; } return "jobject"; } diff --git a/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/NativesGenerator.java b/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/NativesGenerator.java index 0a5fb323b77..b89572f3a5b 100644 --- a/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/NativesGenerator.java +++ b/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/NativesGenerator.java @@ -299,6 +299,14 @@ boolean generateGetParameter(JNIParameter param, boolean critical, int indent) { output(iStr); output(", NULL)"); } + } else if (componentType.isType("java.lang.String")) { + if (param.getFlag(FLAG_UNICODE)) { + throw new Error("not done"); + } + + output("swt_getArrayOfStringsUTF(env, arg"); + output(iStr); + output(")"); } else { throw new Error("not done"); } @@ -381,6 +389,16 @@ void generateSetParameter(JNIParameter param, boolean critical) { output("0"); } output(");"); + } else if (componentType.isType("java.lang.String")) { + if (param.getFlag(FLAG_UNICODE)) { + throw new Error("not done"); + } + + output("swt_releaseArrayOfStringsUTF(env, arg"); + output(iStr); + output(", lparg"); + output(iStr); + output(");"); } else { throw new Error("not done"); } @@ -452,6 +470,12 @@ boolean generateLocalVars(JNIParameter[] params, JNIType returnType) { output(componentType.getTypeSignature2()); output(" *lparg" + i); output("=NULL;"); + } else if (componentType.isType("java.lang.String")) { + if (param.getFlag(FLAG_UNICODE)) { + output("jchar **lparg" + i + "=NULL"); + } else { + output("char **lparg" + i+ "=NULL"); + } } else { throw new Error("not done"); } diff --git a/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ReflectType.java b/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ReflectType.java index 81d90b458cd..50fd124094f 100644 --- a/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ReflectType.java +++ b/bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ReflectType.java @@ -91,7 +91,10 @@ public String getTypeSignature2() { if (clazz == String.class) return "jstring"; if (clazz == Class.class) return "jclass"; if (clazz.isArray()) { - return getComponentType().getTypeSignature2() + "Array"; + if (getComponentType().isPrimitive()) { + return getComponentType().getTypeSignature2() + "Array"; + } + return "jobjectArray"; } return "jobject"; } diff --git a/bundles/org.eclipse.swt.tools/META-INF/MANIFEST.MF b/bundles/org.eclipse.swt.tools/META-INF/MANIFEST.MF index 8e889fffa57..7798f42e14a 100644 --- a/bundles/org.eclipse.swt.tools/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.swt.tools/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-SymbolicName: org.eclipse.swt.tools; singleton:=true -Bundle-Version: 3.110.800.qualifier +Bundle-Version: 3.110.900.qualifier Bundle-ManifestVersion: 2 Export-Package: org.eclipse.swt.tools.internal; x-internal:=true Bundle-ActivationPolicy: lazy diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c index 94db05631a2..2b26e5a7ff7 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c @@ -2187,3 +2187,48 @@ void swt_debug_on_fatal_warnings() { gtk_parse_args(&argcount, &arg2); } #endif + +/** + * Convert an array of Java strings to an array of char * + */ +char ** +swt_getArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray) { + jsize length = (*env)->GetArrayLength(env, javaArray); + + char **cStrings = (char **)malloc((length + 1) * sizeof(char*)); + if (!cStrings) { + return NULL; + } + + for (jsize i = 0; i < length; i++) { + jstring jstr = (jstring)(*env)->GetObjectArrayElement(env, javaArray, i); + if (jstr) { + const char *utfStr = (*env)->GetStringUTFChars(env, jstr, 0); + + cStrings[i] = strdup(utfStr); + + (*env)->ReleaseStringUTFChars(env, jstr, utfStr); + (*env)->DeleteLocalRef(env, jstr); + } else { + cStrings[i] = NULL; + } + } + + cStrings[length] = NULL; + return cStrings; +} + +/** + * Free the memory allocated by swt_getArrayOfStringsUTF + */ +void +swt_releaseArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray, char **cStrings) { + jsize length = (*env)->GetArrayLength(env, javaArray); + + for (jsize i = 0; i < length; i++) { + if (cStrings[i]) { + free(cStrings[i]); + } + } + free(cStrings); +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h index 03165c29900..e590b15a71e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h @@ -187,4 +187,7 @@ jlong call_accessible_object_function (const char *method_name, const char *meth void swt_set_lock_functions(); void swt_debug_on_fatal_warnings() ; +char **swt_getArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray); +void swt_releaseArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray, char **cStrings); + #endif /* ORG_ECLIPSE_SWT_GTK_OS_CUSTOM_H (include guard, this should be the last line) */ diff --git a/features/org.eclipse.swt.tools.feature/feature.xml b/features/org.eclipse.swt.tools.feature/feature.xml index 145eb4e15b4..06a466f73ae 100644 --- a/features/org.eclipse.swt.tools.feature/feature.xml +++ b/features/org.eclipse.swt.tools.feature/feature.xml @@ -2,7 +2,7 @@ From b300e03742d45a01cd1f47b4d94a4c21a6336ed3 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Thu, 25 Sep 2025 10:58:23 -0400 Subject: [PATCH 2/2] WIP - [GTK4] support Clipboard Fixes #2126 --- .../cocoa/org/eclipse/swt/dnd/Transfer.java | 5 +- .../eclipse/swt/dnd/ByteArrayTransfer.java | 122 +++++- .../gtk/org/eclipse/swt/dnd/Clipboard.java | 104 ++---- .../org/eclipse/swt/dnd/ClipboardProxy.java | 103 +---- .../eclipse/swt/dnd/ClipboardProxyGTK4.java | 136 +++++++ .../org/eclipse/swt/dnd/ContentProviders.java | 313 ++++++++++++++++ .../gtk/org/eclipse/swt/dnd/DragSource.java | 12 +- .../gtk/org/eclipse/swt/dnd/DropTarget.java | 6 +- .../gtk/org/eclipse/swt/dnd/FileTransfer.java | 16 +- .../swt/dnd/GdkContentDeserializer.java | 56 +++ .../eclipse/swt/dnd/GdkContentSerializer.java | 71 ++++ .../gtk/org/eclipse/swt/dnd/HTMLTransfer.java | 20 +- .../org/eclipse/swt/dnd/ImageTransfer.java | 40 +- .../gtk/org/eclipse/swt/dnd/RTFTransfer.java | 41 +- .../gtk/org/eclipse/swt/dnd/TextTransfer.java | 68 ++-- .../gtk/org/eclipse/swt/dnd/Transfer.java | 20 + .../gtk/org/eclipse/swt/dnd/TransferData.java | 165 +++++--- .../gtk/org/eclipse/swt/dnd/URLTransfer.java | 16 +- .../Eclipse SWT PI/gtk/library/atk.c | 2 +- .../Eclipse SWT PI/gtk/library/gtk4.c | 351 ++++++++++++++++++ .../Eclipse SWT PI/gtk/library/gtk4_stats.h | 29 ++ .../Eclipse SWT PI/gtk/library/os.c | 218 +++++++++++ .../Eclipse SWT PI/gtk/library/os_custom.c | 31 ++ .../Eclipse SWT PI/gtk/library/os_stats.h | 19 + .../gtk/org/eclipse/swt/internal/gtk/OS.java | 189 ++++++++++ .../org/eclipse/swt/internal/gtk4/GTK4.java | 148 ++++++++ .../eclipse/swt/internal/AsyncFinishUtil.java | 71 ++++ .../swt/internal/SyncFinishCallback.java | 38 ++ .../eclipse/swt/internal/SyncFinishUtil.java | 106 ++++++ .../swt/tests/junit/ClipboardSwingTester.java | 10 + .../eclipse/swt/tests/junit/SwtTestUtil.java | 34 +- .../Test_org_eclipse_swt_dnd_Clipboard.java | 326 ++++++++++++++++ .../Test_org_eclipse_swt_widgets_Shell.java | 11 +- .../data/clipboard/ClipboardCommands.java | 32 ++ .../data/clipboard/ClipboardCommandsImpl.java | 96 +++++ .../data/clipboard/ClipboardTest.java | 147 ++++++++ 36 files changed, 2842 insertions(+), 330 deletions(-) create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxyGTK4.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ContentProviders.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/GdkContentDeserializer.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/GdkContentSerializer.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/AsyncFinishUtil.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SyncFinishCallback.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SyncFinishUtil.java create mode 100644 tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/ClipboardSwingTester.java create mode 100644 tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_dnd_Clipboard.java create mode 100644 tests/org.eclipse.swt.tests/data/clipboard/ClipboardCommands.java create mode 100644 tests/org.eclipse.swt.tests/data/clipboard/ClipboardCommandsImpl.java create mode 100644 tests/org.eclipse.swt.tests/data/clipboard/ClipboardTest.java diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Transfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Transfer.java index 6950ec5b69f..fcc7bbf7028 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Transfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Transfer.java @@ -136,7 +136,10 @@ public static int registerType(String formatName) { int index = 1; while (index < TYPES.length) { String type = TYPES[index]; - if (type != null && formatName.equals(type)) { + if (type == null) { + break; + } + if (formatName.equals(type)) { return index; } index++; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ByteArrayTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ByteArrayTransfer.java index 7ea790bf899..b41c2a0b4da 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ByteArrayTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ByteArrayTransfer.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.swt.dnd; +import org.eclipse.swt.dnd.TransferData.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gtk.*; @@ -136,6 +137,7 @@ public TransferData[] getSupportedTypes() { @Override public boolean isSupportedType(TransferData transferData){ + if (GTK.GTK4) return isSupportedTypeGTK4(transferData); if (transferData == null) return false; int[] types = getTypeIds(); for (int i = 0; i < types.length; i++) { @@ -144,6 +146,15 @@ public boolean isSupportedType(TransferData transferData){ return false; } +private boolean isSupportedTypeGTK4(TransferData transferData) { + if (transferData == null) return false; + int[] types = getTypeIds(); + for (int i = 0; i < types.length; i++) { + if (transferData.gtk4().type == types[i]) return true; + } + return false; +} + /** * This implementation of javaToNative converts a java * byte[] to a platform specific representation. @@ -156,7 +167,11 @@ public boolean isSupportedType(TransferData transferData){ */ @Override protected void javaToNative (Object object, TransferData transferData) { - transferData.result = 0; + if (GTK.GTK4) { + javaToNativeGTK4(object, transferData); + return; + } + transferData.gtk3().result = 0; if (!checkByteArray(object) || !isSupportedType(transferData)) { DND.error(DND.ERROR_INVALID_DATA); } @@ -165,10 +180,59 @@ protected void javaToNative (Object object, TransferData transferData) { long pValue = OS.g_malloc(buffer.length); if (pValue == 0) return; C.memmove(pValue, buffer, buffer.length); - transferData.length = buffer.length; - transferData.format = 8; - transferData.pValue = pValue; - transferData.result = 1; + transferData.gtk3().length = buffer.length; + transferData.gtk3().format = 8; + transferData.gtk3().pValue = pValue; + transferData.gtk3().result = 1; +} + +private void javaToNativeGTK4(Object object, TransferData transferData) { + if (!checkByteArray(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + byte[] buffer = (byte[]) object; + if (buffer.length == 0) { + return; + } + TransferDataGTK4 data = transferData.gtk4(); + GdkContentSerializer serializer = data.serializer; + + long pValue = OS.g_malloc(buffer.length); + if (pValue == 0) { + return; + } + C.memmove(pValue, buffer, buffer.length); + +// Sync version - this won't work if the other end of the stream is in our process (such as a Clipboard.getContents call). +// long[] error = new long[1]; +// boolean finish = OS.g_output_stream_write_all(serializer.output_stream(), pValue, buffer.length, null, +// serializer.cancellable(), error); +// if (!finish) { +// serializer.return_error(error[0]); +// } else { +// serializer.return_success(); +// } +// Async version: + new AsyncFinishUtil().run(data.display, new AsyncReadyCallback() { + @Override + public void async(long result) { + OS.g_output_stream_write_all_async(serializer.output_stream(), pValue, buffer.length, serializer.priority(), + serializer.cancellable(), result, 0); + } + + @Override + public long await(long result) { + long[] error = new long[1]; + boolean finish = OS.g_output_stream_write_all_finish(serializer.output_stream(), result, null, error); + if (!finish) { + serializer.return_error(error[0]); + } else { + serializer.return_success(); + } + OS.g_free(pValue); + return 0; + } + }); } /** @@ -183,14 +247,56 @@ protected void javaToNative (Object object, TransferData transferData) { */ @Override protected Object nativeToJava(TransferData transferData) { - if ( !isSupportedType(transferData) || transferData.pValue == 0) return null; - int size = transferData.format * transferData.length / 8; + if (GTK.GTK4) return nativeToJavaGTK4(transferData); + if ( !isSupportedType(transferData) || transferData.gtk3().pValue == 0) return null; + int size = transferData.gtk3().format * transferData.gtk3().length / 8; if (size == 0) return null; byte[] buffer = new byte[size]; - C.memmove(buffer, transferData.pValue, size); + C.memmove(buffer, transferData.gtk3().pValue, size); return buffer; } +private Object nativeToJavaGTK4(TransferData transferData) { + TransferDataGTK4 data = transferData.gtk4(); + if (!isSupportedType(transferData) || data.deserializer == null) + return null; + + GdkContentDeserializer deserializer = data.deserializer; + long memoryStream = OS.g_memory_output_stream_new_resizable(); + System.out.println("About to run g_output_stream_splice_async"); + boolean success = new SyncFinishUtil().run(data.display, new SyncFinishCallback() { + @Override + public void async(long result) { + OS.g_output_stream_splice_async(memoryStream, deserializer.input_stream(), + OS.G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | OS.G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + deserializer.priority(), deserializer.cancellable(), result, 0); + } + + @Override + public Boolean await(long result) { + long[] error = new long[1]; + long spliced = OS.g_output_stream_splice_finish(memoryStream, result, null); + if (spliced < 0) { + deserializer.return_error(error[0]); + return false; + } else { + deserializer.return_success(); + return true; + } + } + }); + + if (success) { + long data_size = OS.g_memory_output_stream_get_data_size(memoryStream); + long dataPtr = OS.g_memory_output_stream_get_data(memoryStream); + byte[] buffer = new byte[(int)data_size]; + C.memmove(buffer, dataPtr, data_size); + return buffer; + } + + return null; +} + boolean checkByteArray(Object object) { return (object instanceof byte[] && ((byte[])object).length > 0); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Clipboard.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Clipboard.java index 6cd70304a42..182a9de9299 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Clipboard.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Clipboard.java @@ -15,7 +15,6 @@ import org.eclipse.swt.*; -import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gtk.*; import org.eclipse.swt.internal.gtk3.*; @@ -188,8 +187,13 @@ public void clearContents() { */ public void clearContents(int clipboards) { checkWidget(); - ClipboardProxy proxy = ClipboardProxy._getInstance(display); - proxy.clear(this, clipboards); + if (GTK.GTK4) { + ClipboardProxyGTK4 proxy = ClipboardProxyGTK4._getInstance(display); + proxy.clear(this, clipboards); + } else { + ClipboardProxy proxy = ClipboardProxy._getInstance(display); + proxy.clear(this, clipboards); + } } /** @@ -290,14 +294,12 @@ public Object getContents(Transfer transfer) { * @since 3.1 */ public Object getContents(Transfer transfer, int clipboards) { - checkWidget(); - if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT); - - if(GTK.GTK4) { - Object result = getContents_gtk4(transfer, clipboards); - return result; + if (GTK.GTK4) { + return getContents_gtk4(transfer, clipboards); } + checkWidget(); + if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT); long selection_data = 0; int[] typeIds = transfer.getTypeIds(); boolean textTransfer = transfer.getTypeNames()[0].equals("UTF8_STRING"); @@ -312,9 +314,9 @@ public Object getContents(Transfer transfer, int clipboards) { if (selection_data != 0) { TransferData tdata = new TransferData(); tdata.type = GTK3.gtk_selection_data_get_data_type(selection_data); - tdata.pValue = GTK3.gtk_selection_data_get_data(selection_data); - tdata.length = GTK3.gtk_selection_data_get_length(selection_data); - tdata.format = GTK3.gtk_selection_data_get_format(selection_data); + tdata.gtk3().pValue = GTK3.gtk_selection_data_get_data(selection_data); + tdata.gtk3().length = GTK3.gtk_selection_data_get_length(selection_data); + tdata.gtk3().format = GTK3.gtk_selection_data_get_format(selection_data); result = transfer.nativeToJava(tdata); GTK3.gtk_selection_data_free(selection_data); selection_data = 0; @@ -327,65 +329,11 @@ public Object getContents(Transfer transfer, int clipboards) { } private Object getContents_gtk4(Transfer transfer, int clipboards) { + checkWidget(); + if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT); - long contents = GTK4.gdk_clipboard_get_content(Clipboard.GTKCLIPBOARD); - if(contents == 0) return null; - long value = OS.g_malloc (OS.GValue_sizeof ()); - C.memset (value, 0, OS.GValue_sizeof ()); - - //Pasting of text (TextTransfer/RTFTransfer) - if(transfer.getTypeNames()[0].equals("text/plain") || transfer.getTypeNames()[0].equals("text/rtf")) { - OS.g_value_init(value, OS.G_TYPE_STRING()); - if (!GTK4.gdk_content_provider_get_value (contents, value, null)) return null; - long cStr = OS.g_value_get_string(value); - long [] items_written = new long [1]; - long utf16Ptr = OS.g_utf8_to_utf16(cStr, -1, null, items_written, null); - OS.g_free(cStr); - if (utf16Ptr == 0) return null; - int length = (int)items_written[0]; - char[] buffer = new char[length]; - C.memmove(buffer, utf16Ptr, length * 2); - OS.g_free(utf16Ptr); - String str = new String(buffer); - if(transfer.getTypeNames()[0].equals("text/rtf") && !str.contains("{\\rtf1")) { - return null; - } - if(transfer.getTypeNames()[0].equals("text/plain") && str.contains("{\\rtf1")){ - return null; - } - return str; - } - //Pasting of Image - if(transfer.getTypeIds()[0] == (int)GDK.GDK_TYPE_PIXBUF()) { - ImageData imgData = null; - OS.g_value_init(value, GDK.GDK_TYPE_PIXBUF()); - if (!GTK4.gdk_content_provider_get_value (contents, value, null)) return null; - long pixbufObj = OS.g_value_get_object(value); - if (pixbufObj != 0) { - Image img = Image.gtk_new_from_pixbuf(Display.getCurrent(), SWT.BITMAP, pixbufObj); - imgData = img.getImageData(); - img.dispose(); - } - return imgData; - } - //Pasting of HTML - if(transfer.getTypeNames()[0].equals("text/html")) { - OS.g_value_init(value, OS.G_TYPE_STRING()); - if (!GTK4.gdk_content_provider_get_value (contents, value, null)) return null; - long cStr = OS.g_value_get_string(value); - long [] items_written = new long [1]; - long utf16Ptr = OS.g_utf8_to_utf16(cStr, -1, null, items_written, null); - OS.g_free(cStr); - if (utf16Ptr == 0) return null; - int length = (int)items_written[0]; - char[] buffer = new char[length]; - C.memmove(buffer, utf16Ptr, length * 2); - OS.g_free(utf16Ptr); - String str = new String(buffer); - return str; - } - //TODO: [GTK4] Other cases - return null; + ClipboardProxyGTK4 proxy = ClipboardProxyGTK4._getInstance(display); + return proxy.getData(this, transfer, clipboards); } /** @@ -525,9 +473,16 @@ public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) { DND.error(SWT.ERROR_INVALID_ARGUMENT); } } - ClipboardProxy proxy = ClipboardProxy._getInstance(display); - if (!proxy.setData(this, data, dataTypes, clipboards)) { - DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); + if (GTK.GTK4) { + ClipboardProxyGTK4 proxy = ClipboardProxyGTK4._getInstance(display); + if (!proxy.setData(this, data, dataTypes, clipboards)) { + DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); + } + } else { + ClipboardProxy proxy = ClipboardProxy._getInstance(display); + if (!proxy.setData(this, data, dataTypes, clipboards)) { + DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); + } } } @@ -625,6 +580,7 @@ public String[] getAvailableTypeNames() { if(GTK.GTK4) { long formatsCStr = GTK4.gdk_content_formats_to_string(GTK4.gdk_clipboard_get_formats(Clipboard.GTKCLIPBOARD)); String formatsStr = Converter.cCharPtrToJavaString(formatsCStr, true); + System.out.println(formatsStr); String[] types = formatsStr.split(" "); return types; } @@ -723,4 +679,6 @@ long gtk_clipboard_wait_for_contents(long clipboard, long target) { } return selection_data; } + + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java index fd61b6c8eaa..f93fcb86516 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -14,14 +14,15 @@ package org.eclipse.swt.dnd; -import org.eclipse.swt.*; -import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gtk.*; import org.eclipse.swt.internal.gtk3.*; -import org.eclipse.swt.internal.gtk4.*; import org.eclipse.swt.widgets.*; +/** + * Clipboard proxy used to copy data to the clipboard in GTK3 only + * @see ClipboardProxyGTK4 the GTK4 version + */ class ClipboardProxy { /* Data is not flushed to the clipboard immediately. * This class will remember the data and provide it when requested. @@ -31,7 +32,7 @@ class ClipboardProxy { Object[] primaryClipboardData; Transfer[] primaryClipboardDataTypes; - long clipboardOwner = GTK.GTK4 ? GTK4.gtk_window_new() : GTK3.gtk_window_new(GTK.GTK_WINDOW_TOPLEVEL); + long clipboardOwner = GTK3.gtk_window_new(GTK.GTK_WINDOW_TOPLEVEL); Display display; Clipboard activeClipboard = null; @@ -42,6 +43,9 @@ class ClipboardProxy { static String ID = "CLIPBOARD PROXY OBJECT"; //$NON-NLS-1$ static ClipboardProxy _getInstance(final Display display) { + if (GTK.GTK4) { + throw new UnsupportedOperationException("Illegal attempt to use GTK3 ClipboardProxy on GTK4"); + } ClipboardProxy proxy = (ClipboardProxy) display.getData(ID); if (proxy != null) return proxy; proxy = new ClipboardProxy(display); @@ -55,7 +59,7 @@ static ClipboardProxy _getInstance(final Display display) { return proxy; } -ClipboardProxy(Display display) { +private ClipboardProxy(Display display) { this.display = display; getFunc = new Callback( this, "getFunc", 4); //$NON-NLS-1$ clearFunc = new Callback( this, "clearFunc", 2); //$NON-NLS-1$ @@ -71,11 +75,7 @@ void clear (Clipboard owner, int clipboards) { } void gtk_gdk_clipboard_clear(long clipboard) { - if (GTK.GTK4) { - GDK.gdk_clipboard_set_content(clipboard, 0); - } else { - GTK3.gtk_clipboard_clear(clipboard); - } + GTK3.gtk_clipboard_clear(clipboard); } long clearFunc(long clipboard,long user_data_or_owner){ @@ -95,10 +95,10 @@ long clearFunc(long clipboard,long user_data_or_owner){ void dispose () { if (display == null) return; if (activeClipboard != null) { - if(!GTK.GTK4) GTK3.gtk_clipboard_store(Clipboard.GTKCLIPBOARD); + GTK3.gtk_clipboard_store(Clipboard.GTKCLIPBOARD); } if (activePrimaryClipboard != null) { - if(!GTK.GTK4) GTK3.gtk_clipboard_store(Clipboard.GTKPRIMARYCLIPBOARD); + GTK3.gtk_clipboard_store(Clipboard.GTKPRIMARYCLIPBOARD); } display = null; if (getFunc != null ) getFunc.dispose(); @@ -110,11 +110,7 @@ void dispose () { primaryClipboardData = null; primaryClipboardDataTypes = null; if (clipboardOwner != 0) { - if (GTK.GTK4) { - GTK4.gtk_window_destroy(clipboardOwner); - } else { - GTK3.gtk_widget_destroy(clipboardOwner); - } + GTK3.gtk_widget_destroy(clipboardOwner); } clipboardOwner = 0; } @@ -139,18 +135,15 @@ long getFunc(long clipboard, long selection_data, long info, long user_data_or_o if (index == -1) return 0; Object[] data = (clipboard == Clipboard.GTKCLIPBOARD) ? clipboardData : primaryClipboardData; types[index].javaToNative(data[index], tdata); - if (tdata.format < 8 || tdata.format % 8 != 0) { + if (tdata.gtk3().format < 8 || tdata.gtk3().format % 8 != 0) { return 0; } - GTK3.gtk_selection_data_set(selection_data, tdata.type, tdata.format, tdata.pValue, tdata.length); - OS.g_free(tdata.pValue); + GTK3.gtk_selection_data_set(selection_data, tdata.type, tdata.gtk3().format, tdata.gtk3().pValue, tdata.gtk3().length); + OS.g_free(tdata.gtk3().pValue); return 1; } boolean setData(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) { - - if(GTK.GTK4) return setData_gtk4(owner, data, dataTypes, clipboards); - GtkTargetEntry[] entries = new GtkTargetEntry [0]; long pTargetsList = 0; try { @@ -219,66 +212,4 @@ boolean setData(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipbo if (pTargetsList != 0) OS.g_free(pTargetsList); } } - -private boolean setData_gtk4(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) { - boolean result = false; - long [] providers = new long[0]; - for (int i = 0; i < dataTypes.length; i++) { - Transfer transfer = dataTypes[i]; - String[] typeNames = transfer.getTypeNames(); - //Build the GdkContentProvider for each and store in array - long provider = setProviderFromType(typeNames[0], data[i]); - if(provider != 0) { - long[] tmp = new long [providers.length + 1]; - System.arraycopy(providers, 0, tmp, 0, providers.length); - tmp[providers.length] = provider; - providers = tmp; - } - } - //Build the GdkContentProvider Union - if (providers.length == 0) return false; - long union = GTK4.gdk_content_provider_new_union(providers, providers.length); - - if ((clipboards & DND.CLIPBOARD) != 0){ - clipboardData = data; - clipboardDataTypes = dataTypes; - result = GTK4.gdk_clipboard_set_content(Clipboard.GTKCLIPBOARD, union); - activeClipboard = owner; - } - return result; -} - -private long setProviderFromType(String string, Object data) { - long provider = 0; - - if (data == null ) SWT.error(SWT.ERROR_NULL_ARGUMENT); - else { - if(string.equals("text/plain") || string.equals("text/rtf")) { - long value = OS.g_malloc (OS.GValue_sizeof()); - C.memset (value, 0, OS.GValue_sizeof ()); - OS.g_value_init(value, OS.G_TYPE_STRING()); - OS.g_value_set_string(value, Converter.javaStringToCString((String)data)); - provider = GTK4.gdk_content_provider_new_for_value(value); - } - if(string.equals("PIXBUF")) { - if(!(data instanceof ImageData)) DND.error(DND.ERROR_INVALID_DATA); - ImageData imgData = (ImageData)data; - Image image = new Image(Display.getCurrent(), imgData); - long pixbuf = ImageList.createPixbuf(image); - if (pixbuf != 0) { - provider = GTK4.gdk_content_provider_new_typed(GDK.GDK_TYPE_PIXBUF(), pixbuf); - } - image.dispose(); - } - if(string.equals("text/html")) { - long value = OS.g_malloc (OS.GValue_sizeof()); - C.memset (value, 0, OS.GValue_sizeof ()); - OS.g_value_init(value, OS.G_TYPE_STRING()); - OS.g_value_set_string(value, Converter.javaStringToCString((String)data)); - provider = GTK4.gdk_content_provider_new_for_value(value); - } - - } - return provider; -} } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxyGTK4.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxyGTK4.java new file mode 100644 index 00000000000..46ed9757674 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxyGTK4.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2000, 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import org.eclipse.swt.dnd.ContentProviders.*; +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.gtk.*; +import org.eclipse.swt.internal.gtk4.*; +import org.eclipse.swt.widgets.*; + +/** + * Clipboard proxy used to copy data to the clipboard in GTK4 only + * + * @see ClipboardProxy the GTK3 version + */ +class ClipboardProxyGTK4 { + private static String ID = "CLIPBOARD PROXY OBJECT"; //$NON-NLS-1$ + + private Display display; + private Clipboard activeClipboard = null; + private Clipboard activePrimaryClipboard = null; + private final ContentProviders contentProviders = ContentProviders.getInstance(); + + static ClipboardProxyGTK4 _getInstance(final Display display) { + if (!GTK.GTK4) { + throw new UnsupportedOperationException("Illegal attempt to use GTK4 ClipboardProxy on GTK3"); + } + ClipboardProxyGTK4 proxy = (ClipboardProxyGTK4) display.getData(ID); + if (proxy != null) + return proxy; + proxy = new ClipboardProxyGTK4(display); + display.setData(ID, proxy); + display.disposeExec(() -> { + ClipboardProxyGTK4 clipbordProxy = (ClipboardProxyGTK4) display.getData(ID); + if (clipbordProxy == null) + return; + display.setData(ID, null); + clipbordProxy.dispose(); + }); + return proxy; + } + + private ClipboardProxyGTK4(Display display) { + this.display = display; + } + + void clear(Clipboard owner, int clipboards) { + if ((clipboards & DND.CLIPBOARD) != 0 && activeClipboard == owner) { + gtk_gdk_clipboard_clear(Clipboard.GTKCLIPBOARD); + } + if ((clipboards & DND.SELECTION_CLIPBOARD) != 0 && activePrimaryClipboard == owner) { + gtk_gdk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD); + } + } + + private void gtk_gdk_clipboard_clear(long clipboard) { + // This only clears content if we were owner (i.e. when gdk_clipboard_is_local() + // == true) + GDK.gdk_clipboard_set_content(clipboard, 0); + } + + void dispose() { + if (display == null) { + return; + } + // TODO - before completing disposal, consider storing data to global clipboard + // See + // https://github.com/eclipse-platform/eclipse.platform.swt/issues/2126#issuecomment-3312739514 + display = null; + + } + + boolean setData(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) { + // TODO: free providers + long providers = contentProviders.createContentProviders(data, dataTypes, + CLIPBOARD_TYPE.fromDNDConstants(clipboards), display); + if (providers == 0) { + return false; + } + + boolean result = false; + if ((clipboards & DND.CLIPBOARD) != 0) { + long clipboard = clipboards == DND.SELECTION_CLIPBOARD ? Clipboard.GTKPRIMARYCLIPBOARD + : Clipboard.GTKCLIPBOARD; + result = GTK4.gdk_clipboard_set_content(clipboard, providers); + if (clipboards == DND.SELECTION_CLIPBOARD) { + activePrimaryClipboard = owner; + } else { + activeClipboard = owner; + } + } + return result; + + } + + public Object getData(Clipboard owner, Transfer transfer, int clipboards) { + + long clipboard = clipboards == DND.SELECTION_CLIPBOARD ? Clipboard.GTKPRIMARYCLIPBOARD : Clipboard.GTKCLIPBOARD; + long gType = contentProviders.getGType(transfer); + + System.out.println("About to run gdk_clipboard_read_value_async"); + Object value = new SyncFinishUtil<>().run(display, new SyncFinishCallback<>() { + @Override + public void async(long result) { + GTK4.gdk_clipboard_read_value_async(clipboard, gType, OS.G_PRIORITY_DEFAULT, 0, result, 0); + } + + @Override + public Object await(long result) { + long gvalue = GTK4.gdk_clipboard_read_value_finish(clipboard, result, null); + if (gvalue == 0) { + return null; + } + return contentProviders.getObject(gvalue); + } + }); + + if (value == null) { + // nothing on clipboard, or nothing that can be mapped to transfer's type + return null; + } + + return value; + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ContentProviders.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ContentProviders.java new file mode 100644 index 00000000000..d9605e287ef --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ContentProviders.java @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (c) 2000, 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import java.lang.reflect.*; +import java.util.*; + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.gtk.*; +import org.eclipse.swt.internal.gtk4.*; +import org.eclipse.swt.widgets.*; + +/** + * Manages GdkContentProviders + * and the (de)serializers they rely on + */ +class ContentProviders { + public static enum CLIPBOARD_TYPE { + CLIPBOARD(1), PRIMARYCLIPBOARD(2), DRAG(3); + + private final long sourceId; + private final Map data = new HashMap<>(); + private Display display = null; + + CLIPBOARD_TYPE(long id) { + this.sourceId = id; + } + + /** + * Return the DESTINATION instance matching the clipboards using the constants + * {@link DND#CLIPBOARD} and {@link DND#SELECTION_CLIPBOARD} + */ + public static CLIPBOARD_TYPE fromDNDConstants(int clipboards) { + if (clipboards == DND.CLIPBOARD) + return CLIPBOARD; + if (clipboards == DND.SELECTION_CLIPBOARD) + return PRIMARYCLIPBOARD; + // the clipboards should have been error checked for validity before entering + // this method + throw new RuntimeException("Error - invalid clipboards"); + } + + /** + * Returns the DESTINATION matching the given sourceId + */ + public static CLIPBOARD_TYPE fromSourceId(long sourceId) { + CLIPBOARD_TYPE[] values = CLIPBOARD_TYPE.values(); + for (CLIPBOARD_TYPE destination : values) { + if (destination.sourceId == sourceId) { + return destination; + } + } + return null; + } + } + + /** + * The life-time of the serializers in GTK4 (Gdk) are the life-time of the + * process so we use a singleton to store the mapping data that is needed. + */ + private static ContentProviders instance = new ContentProviders(); + + /* + * The types registered with {@link #registerType(String)} on GTK4. Using + * TreeMap to make the maps sorted to ease debugging + */ + final private Map ID_TO_CONTENTTYPE = new TreeMap<>(); + final private Map CONTENTTYPE_TO_ID = new TreeMap<>(); + // start at 1 because 0 is the null formatName + private int typeIndex = 1; + + // These normally need disposal, but since this class is a singleton it isn't disposed. + Callback gdkContentSerializeFunc; + Callback gdkContentDeserializeFunc; + + /** + * All transfers registered with the GTK serializers + * + * Key is the transfer obtained with {@link #transferKey(Transfer)} + */ + private Map registeredTransfers = new TreeMap<>(); + + private Object lastDeserializedObject; + + private ContentProviders() { + gdkContentSerializeFunc = new Callback(this, "gdkContentSerializeFunc", void.class, new Type[] { long.class }); //$NON-NLS-1$ + gdkContentDeserializeFunc = new Callback(this, "gdkContentDeserializeFunc", void.class, //$NON-NLS-1$ + new Type[] { long.class }); + } + + public static ContentProviders getInstance() { + return instance; + } + + /** + * Called by {@link Transfer#registerType(String)} only + */ + public int registerType(String formatName) { + if (formatName == null) { + return 0; + } + Integer id = CONTENTTYPE_TO_ID.get(formatName); + if (id == null) { + id = typeIndex++; + CONTENTTYPE_TO_ID.put(formatName, id); + ID_TO_CONTENTTYPE.put(id, formatName); + } + return id; + } + + public long createContentProviders(Object[] data, Transfer[] transfers, CLIPBOARD_TYPE id, Display display) { + id.data.clear(); + id.display = display; + long[] providers = new long[transfers.length]; + for (int i = 0; i < transfers.length; i++) { + Transfer transfer = transfers[i]; + registerTransfer(transfer); + + // gvalue represents a data + transfer pair, with the + // gtype we can extract the transfer type, and that + // plus id can extract the data + long gvalue = OS.create_gvalue(transfer.gtype, id.sourceId); + // TODO free gvalue (probably when we free the union of providers, see TODO below) + providers[i] = GTK4.gdk_content_provider_new_for_value(gvalue); + id.data.put(transferKey(transfer), data[i]); + } + + // TODO free union of providers (note that gdk_content_provider_new_union takes + // ownership of providers array) + return GTK4.gdk_content_provider_new_union(providers, providers.length); + } + + void gdkContentSerializeFunc(long pSerializer) { + GdkContentSerializer serializer = new GdkContentSerializer(pSerializer); + + Transfer transfer = getTransfer(serializer); + CLIPBOARD_TYPE fromSourceId = CLIPBOARD_TYPE.fromSourceId(serializer.source_id()); + if (fromSourceId == null) { + // TODO failure here - where did this data come from? How are we asked to + // serialize data + // we didn't start with + // TODO make a GError like this??? or throw exception? Is this only a + // programming error? +// GError *error = g_error_new (G_IO_ERROR, +// G_IO_ERROR_NOT_FOUND, +// "Could not convert data from %s to %s", +// g_type_name (gdk_content_serializer_get_gtype (serializer)), +// gdk_content_serializer_get_mime_type (serializer)); +// serializer.return_error(error); + throw new RuntimeException("this should be unreachable??? - see TODOs above this line"); + } + Object object = fromSourceId.data.get(transferKey(transfer)); + Display display = fromSourceId.display; + String mime_type = serializer.mime_type(); + Integer typeObject = CONTENTTYPE_TO_ID.get(mime_type); + int type = typeObject == null ? 0 : typeObject; + // make a transfer data and call + TransferData transferData = new TransferData(); + transferData.gtk4().display = display; + transferData.gtk4().serializer = serializer; + transferData.gtk4().type = type; + transfer.javaToNative(object, transferData); + } + + private Transfer getTransfer(GdkContentSerializer serializer) { + long gtype = serializer.gtype(); + long namePtr = OS.g_type_name(gtype); + String transferName = Converter.cCharPtrToJavaString(namePtr, false); + Transfer transfer = registeredTransfers.get(transferName); + if (transfer == null) { +// TODO make a GError like this??? or throw exception? Is this only a programming error? +// GError *error = g_error_new (G_IO_ERROR, +// G_IO_ERROR_NOT_FOUND, +// "Could not convert data from %s to %s", +// g_type_name (gdk_content_serializer_get_gtype (serializer)), +// gdk_content_serializer_get_mime_type (serializer)); +// GTK4.gdk_content_serializer_return_error(serializer, namePtr); + throw new RuntimeException("Could not convert data because transfer of id " + transferName + " missing"); + } + return transfer; + } + + void gdkContentDeserializeFunc(long pDeserializer) { + System.out.println("gdkContentDeserializeFunc"); + GdkContentDeserializer deserializer = new GdkContentDeserializer(pDeserializer); + + Transfer transfer = getTransfer(deserializer); + String mime_type = deserializer.mime_type(); + Integer typeObject = CONTENTTYPE_TO_ID.get(mime_type); + int type = typeObject == null ? 0 : typeObject; + // make a transfer data and call + TransferData transferData = new TransferData(); + transferData.gtk4().display = Display.getCurrent(); // TODO where to get display from? Is this OK? + transferData.gtk4().deserializer = deserializer; + transferData.gtk4().type = type; + Object object = transfer.nativeToJava(transferData); + // TODO save object better (see TODO where lastDeserializedObject is read) + this.lastDeserializedObject = object; + } + + private Transfer getTransfer(GdkContentDeserializer deserializer) { + long gtype = deserializer.gtype(); + long namePtr = OS.g_type_name(gtype); + String transferName = Converter.cCharPtrToJavaString(namePtr, false); + Transfer transfer = registeredTransfers.get(transferName); + if (transfer == null) { +// TODO make a GError like this??? or throw exception? Is this only a programming error? +// GError *error = g_error_new (G_IO_ERROR, +// G_IO_ERROR_NOT_FOUND, +// "Could not convert data from %s to %s", +// g_type_name (gdk_content_serializer_get_gtype (serializer)), +// gdk_content_serializer_get_mime_type (serializer)); +// GTK4.gdk_content_serializer_return_error(serializer, namePtr); + throw new RuntimeException("Could not convert data because transfer of id " + transferName + " missing"); + } + return transfer; + } + + private void registerTransfer(Transfer transfer) { + String name = transferKey(transfer); + if (registeredTransfers.containsKey(name)) { + return; + } + registeredTransfers.put(name, transfer); + transfer.gtype = OS.register_gtype_for_name(name); + String[] mimeTypes = transfer.getTypeNames(); + for (int i = 0; i < mimeTypes.length; i++) { + String mimeType = mimeTypes[i]; + GTK4.gdk_content_register_serializer(transfer.gtype, mimeType, gdkContentSerializeFunc.getAddress(), 0, 0); + GTK4.gdk_content_register_deserializer(mimeType, transfer.gtype, gdkContentDeserializeFunc.getAddress(), 0, + 0); + } + } + + private String transferKey(Transfer transfer) { + // The value of the name here is used to help debugging the code. + // The only important thing is that the name is unique which is achieved by + // appending transfer.id + return "SWTTransfer_" + transfer.getClass().getSimpleName() + "_" + transfer.id; + } + + public long getGType(Transfer transfer) { + registerTransfer(transfer); + return transfer.gtype; + } + + public Object getObject(long gvalue) { + + long namePtr = OS.G_VALUE_TYPE_NAME(gvalue); + String transferName = Converter.cCharPtrToJavaString(namePtr, false); + Transfer transfer = registeredTransfers.get(transferName); + if (transfer != null) { + long g_value_get_boxed = OS.g_value_get_boxed(gvalue); + CLIPBOARD_TYPE fromSourceId = CLIPBOARD_TYPE.fromSourceId(g_value_get_boxed); + if (fromSourceId != null) { + Object object = fromSourceId.data.get(transferKey(transfer)); + return object; + } + } + + // TODO support multiple deserialized objects - we should really be able to + // align a + // gvalue in GTK memory to a specific Java object here. For now return the last + // thing deserialized + return lastDeserializedObject; + } + +// private long setProviderFromType(String string, Object data) { +// long provider = 0; +// +// if (data == null) +// SWT.error(SWT.ERROR_NULL_ARGUMENT); +// else { +// if (string.equals("text/plain") || string.equals("text/rtf")) { +// long value = OS.g_malloc(OS.GValue_sizeof()); +// C.memset(value, 0, OS.GValue_sizeof()); +// OS.g_value_init(value, OS.G_TYPE_STRING()); +// OS.g_value_set_string(value, Converter.javaStringToCString((String) data)); +// provider = GTK4.gdk_content_provider_new_for_value(value); +// } +// if (string.equals("PIXBUF")) { +// if (!(data instanceof ImageData)) +// DND.error(DND.ERROR_INVALID_DATA); +// ImageData imgData = (ImageData) data; +// Image image = new Image(Display.getCurrent(), imgData); +// long pixbuf = ImageList.createPixbuf(image); +// if (pixbuf != 0) { +// provider = GTK4.gdk_content_provider_new_typed(GDK.GDK_TYPE_PIXBUF(), pixbuf); +// } +// image.dispose(); +// } +// if (string.equals("text/html")) { +// long value = OS.g_malloc(OS.GValue_sizeof()); +// C.memset(value, 0, OS.GValue_sizeof()); +// OS.g_value_init(value, OS.G_TYPE_STRING()); +// OS.g_value_set_string(value, Converter.javaStringToCString((String) data)); +// provider = GTK4.gdk_content_provider_new_for_value(value); +// } +// +// } +// return provider; +// } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DragSource.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DragSource.java index 07dfbd9addc..dfe937d98f3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DragSource.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DragSource.java @@ -516,9 +516,9 @@ void dragGetData(long widget, long context, long selection_data, int info, int TransferData transferData = new TransferData(); transferData.type = target; - transferData.pValue = data; - transferData.length = length; - transferData.format = format; + transferData.gtk3().pValue = data; + transferData.gtk3().length = length; + transferData.gtk3().format = format; DNDEvent event = new DNDEvent(); event.widget = this; @@ -536,9 +536,9 @@ void dragGetData(long widget, long context, long selection_data, int info, int } if (transfer == null) return; transfer.javaToNative(event.data, transferData); - if (transferData.result != 1) return; - GTK3.gtk_selection_data_set(selection_data, transferData.type, transferData.format, transferData.pValue, transferData.length); - OS.g_free(transferData.pValue); + if (transferData.gtk3().result != 1) return; + GTK3.gtk_selection_data_set(selection_data, transferData.type, transferData.gtk3().format, transferData.gtk3().pValue, transferData.gtk3().length); + OS.g_free(transferData.gtk3().pValue); return; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DropTarget.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DropTarget.java index e82fbca3754..5f641b78e94 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DropTarget.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DropTarget.java @@ -358,9 +358,9 @@ void drag_data_received ( long widget, long context, int x, int y, long selectio long type = GTK3.gtk_selection_data_get_data_type(selection_data); if (data != 0) { transferData.type = type; - transferData.length = length; - transferData.pValue = data; - transferData.format = format; + transferData.gtk3().length = length; + transferData.gtk3().pValue = data; + transferData.gtk3().format = format; for (int i = 0; i < transferAgents.length; i++) { Transfer transfer = transferAgents[i]; if (transfer != null && transfer.isSupportedType(transferData)) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/FileTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/FileTransfer.java index a5682302ef9..670231d580f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/FileTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/FileTransfer.java @@ -69,7 +69,7 @@ public static FileTransfer getInstance () { */ @Override public void javaToNative(Object object, TransferData transferData) { - transferData.result = 0; + transferData.gtk3().result = 0; if (!checkFile(object) || !isSupportedType(transferData)) { DND.error(DND.ERROR_INVALID_DATA); } @@ -119,10 +119,10 @@ public void javaToNative(Object object, TransferData transferData) { long ptr = OS.g_malloc(buffer.length+1); C.memset(ptr, '\0', buffer.length+1); C.memmove(ptr, buffer, buffer.length); - transferData.pValue = ptr; - transferData.length = buffer.length; - transferData.format = 8; - transferData.result = 1; + transferData.gtk3().pValue = ptr; + transferData.gtk3().length = buffer.length; + transferData.gtk3().format = 8; + transferData.gtk3().result = 1; } /** * This implementation of nativeToJava converts a platform specific @@ -137,10 +137,10 @@ public void javaToNative(Object object, TransferData transferData) { */ @Override public Object nativeToJava(TransferData transferData) { - if ( !isSupportedType(transferData) || transferData.pValue == 0 || transferData.length <= 0 ) return null; - int length = transferData.length; + if ( !isSupportedType(transferData) || transferData.gtk3().pValue == 0 || transferData.gtk3().length <= 0 ) return null; + int length = transferData.gtk3().length; byte[] temp = new byte[length]; - C.memmove(temp, transferData.pValue, length); + C.memmove(temp, transferData.gtk3().pValue, length); boolean gnomeList = transferData.type == GNOME_LIST_ID; int sepLength = gnomeList ? 1 : 2; long [] files = new long [0]; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/GdkContentDeserializer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/GdkContentDeserializer.java new file mode 100644 index 00000000000..07d207a3682 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/GdkContentDeserializer.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2000, 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.gtk4.*; + +/** + * Wrapper for GDK class GdkContentDeserializer with convenience methods to aid in + * writing {@link Transfer}s for GTK4 + */ +class GdkContentDeserializer { + + private long deserializer; + + public GdkContentDeserializer(long deserializer) { + this.deserializer = deserializer; + } + + public long gtype() { + return GTK4.gdk_content_deserializer_get_gtype(deserializer); + } + + public String mime_type() { + return Converter.cCharPtrToJavaString(GTK4.gdk_content_deserializer_get_mime_type(deserializer), false); + } + + public long input_stream() { + return GTK4.gdk_content_deserializer_get_input_stream(deserializer); + + } + + public int priority() { + return GTK4.gdk_content_deserializer_get_priority(deserializer); + } + + public long cancellable() { + return GTK4.gdk_content_deserializer_get_cancellable(deserializer); + } + + public void return_success() { + GTK4.gdk_content_deserializer_return_success(deserializer); + } + + public void return_error(long error) { + GTK4.gdk_content_deserializer_return_error(deserializer, error); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/GdkContentSerializer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/GdkContentSerializer.java new file mode 100644 index 00000000000..cbb70233caa --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/GdkContentSerializer.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.swt.dnd; + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.gtk.*; +import org.eclipse.swt.internal.gtk4.*; + +/** + * Wrapper for GDK class GdkContentSerializer with convenience methods to aid in + * writing {@link Transfer}s for GTK4 + */ +class GdkContentSerializer { + private long serializer; + + public GdkContentSerializer(long serializer) { + this.serializer = serializer; + } + + /** + * Return the unboxed value stored in the GValue + * + * This is only suitable for getting the source id when used with GValues + * created by {@link OS#create_gvalue(long, long)} + */ + public long source_id() { + long gvalue = gvalue(); + long source = OS.g_value_get_boxed(gvalue); + return source; + } + + public String mime_type() { + return Converter.cCharPtrToJavaString(GTK4.gdk_content_serializer_get_mime_type(serializer), false); + } + + public long gtype() { + return GTK4.gdk_content_serializer_get_gtype(serializer); + } + + public long gvalue() { + return GTK4.gdk_content_serializer_get_value(serializer); + } + + public long output_stream() { + return GTK4.gdk_content_serializer_get_output_stream(serializer); + } + + public int priority() { + return GTK4.gdk_content_serializer_get_priority(serializer); + } + + public long cancellable() { + return GTK4.gdk_content_serializer_get_cancellable(serializer); + } + + public void return_success() { + GTK4.gdk_content_serializer_return_success(serializer); + } + + public void return_error(long error) { + GTK4.gdk_content_serializer_return_error(serializer, error); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/HTMLTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/HTMLTransfer.java index f9c8e36dfb7..cbd509db19b 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/HTMLTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/HTMLTransfer.java @@ -61,7 +61,7 @@ public static HTMLTransfer getInstance () { */ @Override public void javaToNative (Object object, TransferData transferData){ - transferData.result = 0; + transferData.gtk3().result = 0; if (!checkHTML(object) || !isSupportedType(transferData)) { DND.error(DND.ERROR_INVALID_DATA); } @@ -71,10 +71,10 @@ public void javaToNative (Object object, TransferData transferData){ long pValue = OS.g_malloc(byteCount); if (pValue == 0) return; C.memmove(pValue, utf8, byteCount); - transferData.length = byteCount; - transferData.format = 8; - transferData.pValue = pValue; - transferData.result = 1; + transferData.gtk3().length = byteCount; + transferData.gtk3().format = 8; + transferData.gtk3().pValue = pValue; + transferData.gtk3().result = 1; } /** @@ -89,21 +89,21 @@ public void javaToNative (Object object, TransferData transferData){ */ @Override public Object nativeToJava(TransferData transferData){ - if ( !isSupportedType(transferData) || transferData.pValue == 0 ) return null; + if ( !isSupportedType(transferData) || transferData.gtk3().pValue == 0 ) return null; /* Ensure byteCount is a multiple of 2 bytes */ - int size = (transferData.format * transferData.length / 8) / 2 * 2; + int size = (transferData.gtk3().format * transferData.gtk3().length / 8) / 2 * 2; if (size <= 0) return null; char[] bom = new char[1]; // look for a Byte Order Mark - if (size > 1) C.memmove (bom, transferData.pValue, 2); + if (size > 1) C.memmove (bom, transferData.gtk3().pValue, 2); String string; if (bom[0] == '\ufeff' || bom[0] == '\ufffe') { // utf16 char[] chars = new char [size/2]; - C.memmove (chars, transferData.pValue, size); + C.memmove (chars, transferData.gtk3().pValue, size); string = new String (chars); } else { byte[] utf8 = new byte[size]; - C.memmove(utf8, transferData.pValue, size); + C.memmove(utf8, transferData.gtk3().pValue, size); // convert utf8 byte array to a unicode string char [] unicode = org.eclipse.swt.internal.Converter.mbcsToWcs (utf8); string = new String (unicode); diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ImageTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ImageTransfer.java index a58b0b35631..055e60cfa8a 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ImageTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ImageTransfer.java @@ -40,27 +40,27 @@ public class ImageTransfer extends ByteArrayTransfer { private static ImageTransfer _instance = new ImageTransfer(); private static final String JPEG = "image/jpeg"; //$NON-NLS-1$ - private static final int JPEG_ID = GTK.GTK4 ? 0: registerType(JPEG); + private static final int JPEG_ID = registerType(JPEG); private static final String PNG = "image/png"; //$NON-NLS-1$ - private static final int PNG_ID = GTK.GTK4 ? 0:registerType(PNG); + private static final int PNG_ID = registerType(PNG); private static final String BMP = "image/bmp"; //$NON-NLS-1$ - private static final int BMP_ID = GTK.GTK4 ? 0:registerType(BMP); + private static final int BMP_ID = registerType(BMP); private static final String EPS = "image/eps"; //$NON-NLS-1$ - private static final int EPS_ID = GTK.GTK4 ? 0:registerType(EPS); + private static final int EPS_ID = registerType(EPS); private static final String PCX = "image/pcx"; //$NON-NLS-1$ - private static final int PCX_ID = GTK.GTK4 ? 0:registerType(PCX); + private static final int PCX_ID = registerType(PCX); private static final String PPM = "image/ppm"; //$NON-NLS-1$ - private static final int PPM_ID = GTK.GTK4 ? 0:registerType(PPM); + private static final int PPM_ID = registerType(PPM); private static final String RGB = "image/ppm"; //$NON-NLS-1$ - private static final int RGB_ID = GTK.GTK4 ? 0:registerType(RGB); + private static final int RGB_ID = registerType(RGB); private static final String TGA = "image/tga"; //$NON-NLS-1$ - private static final int TGA_ID = GTK.GTK4 ? 0:registerType(TGA); + private static final int TGA_ID = registerType(TGA); private static final String XBM = "image/xbm"; //$NON-NLS-1$ - private static final int XBM_ID = GTK.GTK4 ? 0:registerType(XBM); + private static final int XBM_ID = registerType(XBM); private static final String XPM = "image/xpm"; //$NON-NLS-1$ - private static final int XPM_ID = GTK.GTK4 ? 0:registerType(XPM); + private static final int XPM_ID = registerType(XPM); private static final String XV = "image/xv"; //$NON-NLS-1$ - private static final int XV_ID = GTK.GTK4 ? 0:registerType(XV); + private static final int XV_ID = registerType(XV); private ImageTransfer() {} @@ -111,14 +111,14 @@ public void javaToNative(Object object, TransferData transferData) { if (type == null) return; GDK.gdk_pixbuf_save_to_bufferv(pixbuf, buffer, len, type, null, null, null); OS.g_object_unref(pixbuf); - transferData.pValue = buffer[0]; - transferData.length = (int)(len[0] + 3) / 4 * 4; - transferData.result = 1; + transferData.gtk3().pValue = buffer[0]; + transferData.gtk3().length = (int)(len[0] + 3) / 4 * 4; + transferData.gtk3().result = 1; // The following value has been changed from 32 to 8 as a simple fix for #146 // See https://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut-16.html where it states: // "The format field is actually important here - the X server uses it to figure out whether the data // needs to be byte-swapped or not. Usually it will be 8 - i.e. a character - or 32 - i.e. a. integer." - transferData.format = 8; + transferData.gtk3().format = 8; } image.dispose(); } @@ -136,10 +136,10 @@ public void javaToNative(Object object, TransferData transferData) { @Override public Object nativeToJava(TransferData transferData) { ImageData imgData = null; - if (transferData.length > 0) { + if (transferData.gtk3().length > 0) { long loader = GDK.gdk_pixbuf_loader_new(); try { - GDK.gdk_pixbuf_loader_write(loader, transferData.pValue, transferData.length, null); + GDK.gdk_pixbuf_loader_write(loader, transferData.gtk3().pValue, transferData.gtk3().length, null); GDK.gdk_pixbuf_loader_close(loader, null); long pixbuf = GDK.gdk_pixbuf_loader_get_pixbuf(loader); if (pixbuf != 0) { @@ -156,17 +156,11 @@ public Object nativeToJava(TransferData transferData) { @Override protected int[] getTypeIds(){ - if(GTK.GTK4) { - return new int[] {(int) GDK.GDK_TYPE_PIXBUF()}; - } return new int[]{PNG_ID, BMP_ID, EPS_ID, JPEG_ID, PCX_ID, PPM_ID, RGB_ID, TGA_ID, XBM_ID, XPM_ID, XV_ID}; } @Override protected String[] getTypeNames(){ - if(GTK.GTK4) { - return new String[]{"PIXBUF"}; - } return new String[]{PNG, BMP, EPS, JPEG, PCX, PPM, RGB, TGA, XBM, XPM, XV}; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/RTFTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/RTFTransfer.java index 586ff586da7..71b9473376c 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/RTFTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/RTFTransfer.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.swt.dnd; +import org.eclipse.swt.dnd.TransferData.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gtk.*; @@ -63,7 +64,11 @@ public static RTFTransfer getInstance () { */ @Override public void javaToNative (Object object, TransferData transferData){ - transferData.result = 0; + if (GTK.GTK4) { + javaToNativeGTK4(object, transferData); + return; + } + transferData.gtk3().result = 0; if (!checkRTF(object) || !isSupportedType(transferData)) { DND.error(DND.ERROR_INVALID_DATA); } @@ -72,10 +77,18 @@ public void javaToNative (Object object, TransferData transferData){ long pValue = OS.g_malloc(buffer.length); if (pValue == 0) return; C.memmove(pValue, buffer, buffer.length); - transferData.length = buffer.length - 1; - transferData.format = 8; - transferData.pValue = pValue; - transferData.result = 1; + transferData.gtk3().length = buffer.length - 1; + transferData.gtk3().format = 8; + transferData.gtk3().pValue = pValue; + transferData.gtk3().result = 1; +} + + +private void javaToNativeGTK4(Object object, TransferData transferData) { + if (!checkRTF(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + super.javaToNative(Converter.wcsToMbcs((String) object, false), transferData); } /** @@ -90,17 +103,29 @@ public void javaToNative (Object object, TransferData transferData){ */ @Override public Object nativeToJava(TransferData transferData){ - if ( !isSupportedType(transferData) || transferData.pValue == 0 ) return null; - int size = transferData.format * transferData.length / 8; + if (GTK.GTK4) return nativeToJavaGTK4(transferData); + + if ( !isSupportedType(transferData) || transferData.gtk3().pValue == 0 ) return null; + int size = transferData.gtk3().format * transferData.gtk3().length / 8; if (size == 0) return null; byte[] buffer = new byte[size]; - C.memmove(buffer, transferData.pValue, size); + C.memmove(buffer, transferData.gtk3().pValue, size); char [] chars = Converter.mbcsToWcs (buffer); String string = new String (chars); int end = string.indexOf('\0'); return (end == -1) ? string : string.substring(0, end); } +private Object nativeToJavaGTK4(TransferData transferData) { + TransferDataGTK4 data = transferData.gtk4(); + if (!isSupportedType(transferData) || data.deserializer == null) return null; + Object buffer = super.nativeToJava(transferData); + if (buffer instanceof byte[] bytes) { + return new String(Converter.mbcsToWcs(bytes)); + } + return null; +} + @Override protected int[] getTypeIds() { if(GTK.GTK4) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/TextTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/TextTransfer.java index a745aa13026..b32be5aee27 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/TextTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/TextTransfer.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.swt.dnd; +import org.eclipse.swt.dnd.TransferData.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gtk.*; @@ -42,11 +43,13 @@ public class TextTransfer extends ByteArrayTransfer { private static final String COMPOUND_TEXT = "COMPOUND_TEXT"; //$NON-NLS-1$ private static final String UTF8_STRING = "UTF8_STRING"; //$NON-NLS-1$ private static final String STRING = "STRING"; //$NON-NLS-1$ + private static final String TEXT_PLAIN = "text/plain"; //RFC-1341 private static final String TEXT_PLAIN_UTF8 = "text/plain;charset=utf-8"; //RFC-1341 - private static final int COMPOUND_TEXT_ID = GTK.GTK4 ? 0 : registerType(COMPOUND_TEXT); - private static final int UTF8_STRING_ID = GTK.GTK4 ? 0 : registerType(UTF8_STRING); - private static final int STRING_ID = GTK.GTK4 ? 0 : registerType(STRING); - private static final int TEXT_PLAIN_UTF8_ID = GTK.GTK4 ? 0 : registerType(TEXT_PLAIN_UTF8); + private static final int COMPOUND_TEXT_ID = registerType(COMPOUND_TEXT); + private static final int UTF8_STRING_ID = registerType(UTF8_STRING); + private static final int STRING_ID = registerType(STRING); + private static final int TEXT_PLAIN_ID = registerType(TEXT_PLAIN); + private static final int TEXT_PLAIN_UTF8_ID = registerType(TEXT_PLAIN_UTF8); private TextTransfer() {} @@ -71,7 +74,11 @@ public static TextTransfer getInstance () { */ @Override public void javaToNative (Object object, TransferData transferData) { - transferData.result = 0; + if (GTK.GTK4) { + javaToNativeGTK4(object, transferData); + return; + } + transferData.gtk3().result = 0; if (!checkText(object) || !isSupportedType(transferData)) { DND.error(DND.ERROR_INVALID_DATA); } @@ -85,32 +92,39 @@ public void javaToNative (Object object, TransferData transferData) { boolean result = GDK.gdk_x11_display_utf8_to_compound_text (GDK.gdk_display_get_default(), utf8, encoding, format, ctext, length); if (!result) return; transferData.type = encoding[0]; - transferData.format = format[0]; - transferData.length = length[0]; - transferData.pValue = ctext[0]; - transferData.result = 1; + transferData.gtk3().format = format[0]; + transferData.gtk3().length = length[0]; + transferData.gtk3().pValue = ctext[0]; + transferData.gtk3().result = 1; } if (transferData.type == UTF8_STRING_ID || transferData.type == TEXT_PLAIN_UTF8_ID) { long pValue = OS.g_malloc(utf8.length); if (pValue == 0) return; C.memmove(pValue, utf8, utf8.length); - transferData.format = 8; - transferData.length = utf8.length - 1; - transferData.pValue = pValue; - transferData.result = 1; + transferData.gtk3().format = 8; + transferData.gtk3().length = utf8.length - 1; + transferData.gtk3().pValue = pValue; + transferData.gtk3().result = 1; } if (transferData.type == STRING_ID) { long string_target = GDK.gdk_utf8_to_string_target(utf8); if (string_target == 0) return; transferData.type = STRING_ID; - transferData.format = 8; - transferData.length = C.strlen(string_target); - transferData.pValue = string_target; - transferData.result = 1; + transferData.gtk3().format = 8; + transferData.gtk3().length = C.strlen(string_target); + transferData.gtk3().pValue = string_target; + transferData.gtk3().result = 1; } } +private void javaToNativeGTK4(Object object, TransferData transferData) { + if (!checkText(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + super.javaToNative(Converter.wcsToMbcs((String) object, false), transferData); +} + /** * This implementation of nativeToJava converts a platform specific * representation of plain text to a java String. @@ -122,9 +136,11 @@ public void javaToNative (Object object, TransferData transferData) { */ @Override public Object nativeToJava(TransferData transferData){ - if (!isSupportedType(transferData) || transferData.pValue == 0) return null; + if (GTK.GTK4) return nativeToJavaGTK4(transferData); + + if (!isSupportedType(transferData) || transferData.gtk3().pValue == 0) return null; long [] list = new long [1]; - int count = GDK.gdk_text_property_to_utf8_list_for_display(GDK.gdk_display_get_default(), transferData.type, transferData.format, transferData.pValue, transferData.length, list); + int count = GDK.gdk_text_property_to_utf8_list_for_display(GDK.gdk_display_get_default(), transferData.type, transferData.gtk3().format, transferData.gtk3().pValue, transferData.gtk3().length, list); if (count == 0) return null; long [] ptr = new long [1]; C.memmove(ptr, list[0], C.PTR_SIZEOF); @@ -139,10 +155,20 @@ public Object nativeToJava(TransferData transferData){ return (end == -1) ? string : string.substring(0, end); } +private Object nativeToJavaGTK4(TransferData transferData) { + TransferDataGTK4 data = transferData.gtk4(); + if (!isSupportedType(transferData) || data.deserializer == null) return null; + Object buffer = super.nativeToJava(transferData); + if (buffer instanceof byte[] bytes) { + return new String(Converter.mbcsToWcs(bytes)); + } + return null; +} + @Override protected int[] getTypeIds() { if(GTK.GTK4) { - return new int[] {(int) OS.G_TYPE_STRING()}; + return new int[] {TEXT_PLAIN_UTF8_ID, TEXT_PLAIN_ID, STRING_ID}; } if (OS.isX11()) { return new int[] {UTF8_STRING_ID, COMPOUND_TEXT_ID, STRING_ID}; @@ -153,7 +179,7 @@ protected int[] getTypeIds() { @Override protected String[] getTypeNames() { if(GTK.GTK4) { - return new String[] {"text/plain", STRING}; + return new String[] {TEXT_PLAIN_UTF8, TEXT_PLAIN, STRING}; } if (OS.isX11()) { return new String[] {UTF8_STRING, COMPOUND_TEXT, STRING}; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Transfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Transfer.java index 5cf4b739982..0f74f298983 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Transfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/Transfer.java @@ -34,6 +34,22 @@ */ public abstract class Transfer { +private static int nextId = 1; +/** + * Unique id of the transfer type. Used by GTK4 implementation to map + * data in the C/GTK side back to Java. + */ +/* package */ final int id; +/** + * GType registered with GDK for this transfer. Every Transfer type + * is associated with a GType so that SWT knows which transfer to use + */ +/* package */ long gtype; + +public Transfer() { + id = nextId++; +} + /** * Returns a list of the platform specific data types that can be converted using * this transfer agent. @@ -133,6 +149,10 @@ public abstract class Transfer { * @return the unique identifier associated with this data type */ public static int registerType(String formatName){ + if (GTK.GTK4) { + return ContentProviders.getInstance().registerType(formatName); + } + if (formatName == null) return GDK.GDK_NONE; byte[] buffer = Converter.wcsToMbcs(formatName, true); return (int)GDK.gdk_atom_intern(buffer, false); diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/TransferData.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/TransferData.java index 3ff822475e1..658ae5b790e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/TransferData.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/TransferData.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -13,6 +13,10 @@ *******************************************************************************/ package org.eclipse.swt.dnd; +import java.util.function.*; + +import org.eclipse.swt.internal.gtk.*; +import org.eclipse.swt.widgets.*; /** * The TransferData class is a platform specific data structure for @@ -46,66 +50,119 @@ public class TransferData { public long type; /** - * Specifies the number of units in pValue. - * (Warning: This field is platform dependent) - *

- * IMPORTANT: This field is not part of the SWT - * public API. It is marked public only so that it can be shared - * within the packages provided by SWT. It is not available on all - * platforms and should never be accessed from application code. - *

- * - * @see TransferData#format for the size of one unit - * - * @noreference This field is not intended to be referenced by clients. + * @noreference This class is not intended to be referenced by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + * @noextend This class is not intended to be subclassed by clients. + * @since 3.132 */ - public int length; + public static class TransferDataGTK3 { + /** + * Specifies the number of units in pValue. + * (Warning: This field is platform dependent) + *

+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *

+ * + * @see TransferDataGTK3#format for the size of one unit + * + * @noreference This field is not intended to be referenced by clients. + */ + public int length; + /** + * Specifies the size in bits of a single unit in pValue. + * (Warning: This field is platform dependent) + *

+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *

+ * + * This is most commonly 8 bits. + * + * @noreference This field is not intended to be referenced by clients. + */ + public int format; + /** + * Pointer to the data being transferred. + * (Warning: This field is platform dependent) + *

+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *

+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long pValue; + /** + * The result field contains the result of converting a + * java data type into a platform specific value. + * (Warning: This field is platform dependent) + *

+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *

+ *

The value of result is 1 if the conversion was successful. + * The value of result is 0 if the conversion failed.

+ * + * @noreference This field is not intended to be referenced by clients. + */ + public int result; + + private TransferDataGTK3() {} + } /** - * Specifies the size in bits of a single unit in pValue. - * (Warning: This field is platform dependent) - *

- * IMPORTANT: This field is not part of the SWT - * public API. It is marked public only so that it can be shared - * within the packages provided by SWT. It is not available on all - * platforms and should never be accessed from application code. - *

- * - * This is most commonly 8 bits. - * - * @noreference This field is not intended to be referenced by clients. + * @noreference This class is not intended to be referenced by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + * @noextend This class is not intended to be subclassed by clients. + * @since 3.132 */ - public int format; + public static class TransferDataGTK4 { + public GdkContentSerializer serializer; + public Display display; + public int type; + public GdkContentDeserializer deserializer; + public Consumer storeObject; + + private TransferDataGTK4() {} + } + + private TransferDataGTK3 gtk3; + + private TransferDataGTK4 gtk4; /** - * Pointer to the data being transferred. - * (Warning: This field is platform dependent) - *

- * IMPORTANT: This field is not part of the SWT - * public API. It is marked public only so that it can be shared - * within the packages provided by SWT. It is not available on all - * platforms and should never be accessed from application code. - *

- * - * @noreference This field is not intended to be referenced by clients. + * @noreference This method is not intended to be referenced by clients. */ - public long pValue; - + public TransferDataGTK3 gtk3() { + if (gtk3 != null) { + return gtk3; + } + if (!GTK.GTK4) { + gtk3 = new TransferDataGTK3(); + return gtk3; + } + throw new UnsupportedOperationException("Illegal attempt to use GTK3 TransferData on GTK4"); + } /** - * The result field contains the result of converting a - * java data type into a platform specific value. - * (Warning: This field is platform dependent) - *

- * IMPORTANT: This field is not part of the SWT - * public API. It is marked public only so that it can be shared - * within the packages provided by SWT. It is not available on all - * platforms and should never be accessed from application code. - *

- *

The value of result is 1 if the conversion was successful. - * The value of result is 0 if the conversion failed.

- * - * @noreference This field is not intended to be referenced by clients. + * @noreference This method is not intended to be referenced by clients. */ - public int result; - + public TransferDataGTK4 gtk4() { + if (gtk4 != null) { + return gtk4; + } + if (GTK.GTK4) { + gtk4 = new TransferDataGTK4(); + return gtk4; + } + throw new UnsupportedOperationException("Illegal attempt to use GTK4 TransferData on GTK3"); + } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/URLTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/URLTransfer.java index 6fdbb76ddd4..35bbab9155c 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/URLTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/URLTransfer.java @@ -62,7 +62,7 @@ public static URLTransfer getInstance () { */ @Override public void javaToNative (Object object, TransferData transferData){ - transferData.result = 0; + transferData.gtk3().result = 0; if (!checkURL(object) || !isSupportedType(transferData)) { DND.error(DND.ERROR_INVALID_DATA); } @@ -74,10 +74,10 @@ public void javaToNative (Object object, TransferData transferData){ long pValue = OS.g_malloc(byteCount); if (pValue == 0) return; C.memmove(pValue, chars, byteCount); - transferData.length = byteCount; - transferData.format = 8; - transferData.pValue = pValue; - transferData.result = 1; + transferData.gtk3().length = byteCount; + transferData.gtk3().format = 8; + transferData.gtk3().pValue = pValue; + transferData.gtk3().result = 1; } /** @@ -92,12 +92,12 @@ public void javaToNative (Object object, TransferData transferData){ */ @Override public Object nativeToJava(TransferData transferData){ - if (!isSupportedType(transferData) || transferData.pValue == 0) return null; + if (!isSupportedType(transferData) || transferData.gtk3().pValue == 0) return null; /* Ensure byteCount is a multiple of 2 bytes */ - int size = (transferData.format * transferData.length / 8) / 2 * 2; + int size = (transferData.gtk3().format * transferData.gtk3().length / 8) / 2 * 2; if (size <= 0) return null; char[] chars = new char [size/2]; - C.memmove (chars, transferData.pValue, size); + C.memmove (chars, transferData.gtk3().pValue, size); String string = new String (chars); int end = string.indexOf('\0'); return (end == -1) ? string : string.substring(0, end); diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/atk.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/atk.c index 5780bf4fe31..053bd0c722f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/atk.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/atk.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2022 IBM Corporation and others. All rights reserved. + * Copyright (c) 2000, 2025 IBM Corporation and others. All rights reserved. * The contents of this file are made available under the terms * of the GNU Lesser General Public License (LGPL) Version 2.1 that * accompanies this distribution (lgpl-v21.txt). The LGPL is also diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c index 3ebcddc354a..71a2db65a1f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c @@ -50,6 +50,77 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1clipboard_1get_1formats) } #endif +#ifndef NO_gdk_1clipboard_1is_1local +JNIEXPORT jboolean JNICALL GTK4_NATIVE(gdk_1clipboard_1is_1local) + (JNIEnv *env, jclass that, jlong arg0) +{ + jboolean rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1clipboard_1is_1local_FUNC); + rc = (jboolean)gdk_clipboard_is_local((GdkClipboard*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1clipboard_1is_1local_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1clipboard_1read_1async +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1clipboard_1read_1async) + (JNIEnv *env, jclass that, jlong arg0, jobjectArray arg1, jint arg2, jlong arg3, jlong arg4, jlong arg5) +{ + char **lparg1=NULL + GTK4_NATIVE_ENTER(env, that, gdk_1clipboard_1read_1async_FUNC); + if (arg1) if ((lparg1 = swt_getArrayOfStringsUTF(env, arg1)) == NULL) goto fail; + gdk_clipboard_read_async((GdkClipboard*)arg0, (const char **)lparg1, (int)arg2, (GCancellable *)arg3, (GAsyncReadyCallback)arg4, (gpointer)arg5); +fail: + if (arg1 && lparg1) swt_releaseArrayOfStringsUTF(env, arg1, lparg1); + GTK4_NATIVE_EXIT(env, that, gdk_1clipboard_1read_1async_FUNC); +} +#endif + +#ifndef NO_gdk_1clipboard_1read_1finish +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1clipboard_1read_1finish) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlongArray arg2, jlongArray arg3) +{ + jlong *lparg2=NULL; + jlong *lparg3=NULL; + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1clipboard_1read_1finish_FUNC); + if (arg2) if ((lparg2 = (*env)->GetLongArrayElements(env, arg2, NULL)) == NULL) goto fail; + if (arg3) if ((lparg3 = (*env)->GetLongArrayElements(env, arg3, NULL)) == NULL) goto fail; + rc = (jlong)gdk_clipboard_read_finish((GdkClipboard*)arg0, (GAsyncResult *)arg1, (const char**)lparg2, (GError **)lparg3); +fail: + if (arg3 && lparg3) (*env)->ReleaseLongArrayElements(env, arg3, lparg3, 0); + if (arg2 && lparg2) (*env)->ReleaseLongArrayElements(env, arg2, lparg2, 0); + GTK4_NATIVE_EXIT(env, that, gdk_1clipboard_1read_1finish_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1clipboard_1read_1value_1async +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1clipboard_1read_1value_1async) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2, jlong arg3, jlong arg4, jlong arg5) +{ + GTK4_NATIVE_ENTER(env, that, gdk_1clipboard_1read_1value_1async_FUNC); + gdk_clipboard_read_value_async((GdkClipboard*)arg0, (GType)arg1, (int)arg2, (GCancellable *)arg3, (GAsyncReadyCallback)arg4, (gpointer)arg5); + GTK4_NATIVE_EXIT(env, that, gdk_1clipboard_1read_1value_1async_FUNC); +} +#endif + +#ifndef NO_gdk_1clipboard_1read_1value_1finish +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1clipboard_1read_1value_1finish) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlongArray arg2) +{ + jlong *lparg2=NULL; + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1clipboard_1read_1value_1finish_FUNC); + if (arg2) if ((lparg2 = (*env)->GetLongArrayElements(env, arg2, NULL)) == NULL) goto fail; + rc = (jlong)gdk_clipboard_read_value_finish((GdkClipboard*)arg0, (GAsyncResult *)arg1, (GError **)lparg2); +fail: + if (arg2 && lparg2) (*env)->ReleaseLongArrayElements(env, arg2, lparg2, 0); + GTK4_NATIVE_EXIT(env, that, gdk_1clipboard_1read_1value_1finish_FUNC); + return rc; +} +#endif + #ifndef NO_gdk_1clipboard_1set JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1clipboard_1set) (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) @@ -86,6 +157,132 @@ JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1clipboard_1set_1text) } #endif +#ifndef NO_gdk_1content_1deserializer_1get_1cancellable +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1get_1cancellable) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1get_1cancellable_FUNC); + rc = (jlong)gdk_content_deserializer_get_cancellable((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1get_1cancellable_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1get_1gtype +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1get_1gtype) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1get_1gtype_FUNC); + rc = (jlong)gdk_content_deserializer_get_gtype((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1get_1gtype_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1get_1input_1stream +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1get_1input_1stream) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1get_1input_1stream_FUNC); + rc = (jlong)gdk_content_deserializer_get_input_stream((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1get_1input_1stream_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1get_1mime_1type +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1get_1mime_1type) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1get_1mime_1type_FUNC); + rc = (jlong)gdk_content_deserializer_get_mime_type((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1get_1mime_1type_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1get_1priority +JNIEXPORT jint JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1get_1priority) + (JNIEnv *env, jclass that, jlong arg0) +{ + jint rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1get_1priority_FUNC); + rc = (jint)gdk_content_deserializer_get_priority((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1get_1priority_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1get_1task_1data +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1get_1task_1data) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1get_1task_1data_FUNC); + rc = (jlong)gdk_content_deserializer_get_task_data((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1get_1task_1data_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1get_1user_1data +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1get_1user_1data) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1get_1user_1data_FUNC); + rc = (jlong)gdk_content_deserializer_get_user_data((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1get_1user_1data_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1get_1value +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1get_1value) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1get_1value_FUNC); + rc = (jlong)gdk_content_deserializer_get_value((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1get_1value_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1return_1error +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1return_1error) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1) +{ + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1return_1error_FUNC); + gdk_content_deserializer_return_error((GdkContentDeserializer*)arg0, (GError*)arg1); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1return_1error_FUNC); +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1return_1success +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1return_1success) + (JNIEnv *env, jclass that, jlong arg0) +{ + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1return_1success_FUNC); + gdk_content_deserializer_return_success((GdkContentDeserializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1return_1success_FUNC); +} +#endif + +#ifndef NO_gdk_1content_1deserializer_1set_1task_1data +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1deserializer_1set_1task_1data) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) +{ + GTK4_NATIVE_ENTER(env, that, gdk_1content_1deserializer_1set_1task_1data_FUNC); + gdk_content_deserializer_set_task_data((GdkContentDeserializer*)arg0, (gpointer)arg1, (GDestroyNotify)arg2); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1deserializer_1set_1task_1data_FUNC); +} +#endif + #ifndef NO_gdk_1content_1formats_1builder_1add_1mime_1type JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1formats_1builder_1add_1mime_1type) (JNIEnv *env, jclass that, jlong arg0, jbyteArray arg1) @@ -208,6 +405,160 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1provider_1new_1union) } #endif +#ifndef NO_gdk_1content_1register_1deserializer +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1register_1deserializer) + (JNIEnv *env, jclass that, jstring arg0, jlong arg1, jlong arg2, jlong arg3, jlong arg4) +{ + const char *lparg0= NULL; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1register_1deserializer_FUNC); + if (arg0) if ((lparg0 = (*env)->GetStringUTFChars(env, arg0, NULL)) == NULL) goto fail; + gdk_content_register_deserializer((const char*)lparg0, (GType)arg1, (GdkContentDeserializeFunc)arg2, (gpointer)arg3, (GDestroyNotify)arg4); +fail: + if (arg0 && lparg0) (*env)->ReleaseStringUTFChars(env, arg0, lparg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1register_1deserializer_FUNC); +} +#endif + +#ifndef NO_gdk_1content_1register_1serializer +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1register_1serializer) + (JNIEnv *env, jclass that, jlong arg0, jstring arg1, jlong arg2, jlong arg3, jlong arg4) +{ + const char *lparg1= NULL; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1register_1serializer_FUNC); + if (arg1) if ((lparg1 = (*env)->GetStringUTFChars(env, arg1, NULL)) == NULL) goto fail; + gdk_content_register_serializer((GType)arg0, (const char*)lparg1, (GdkContentSerializeFunc)arg2, (gpointer)arg3, (GDestroyNotify)arg4); +fail: + if (arg1 && lparg1) (*env)->ReleaseStringUTFChars(env, arg1, lparg1); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1register_1serializer_FUNC); +} +#endif + +#ifndef NO_gdk_1content_1serializer_1get_1cancellable +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1serializer_1get_1cancellable) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1get_1cancellable_FUNC); + rc = (jlong)gdk_content_serializer_get_cancellable((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1get_1cancellable_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1serializer_1get_1gtype +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1serializer_1get_1gtype) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1get_1gtype_FUNC); + rc = (jlong)gdk_content_serializer_get_gtype((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1get_1gtype_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1serializer_1get_1mime_1type +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1serializer_1get_1mime_1type) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1get_1mime_1type_FUNC); + rc = (jlong)gdk_content_serializer_get_mime_type((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1get_1mime_1type_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1serializer_1get_1output_1stream +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1serializer_1get_1output_1stream) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1get_1output_1stream_FUNC); + rc = (jlong)gdk_content_serializer_get_output_stream((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1get_1output_1stream_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1serializer_1get_1priority +JNIEXPORT jint JNICALL GTK4_NATIVE(gdk_1content_1serializer_1get_1priority) + (JNIEnv *env, jclass that, jlong arg0) +{ + jint rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1get_1priority_FUNC); + rc = (jint)gdk_content_serializer_get_priority((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1get_1priority_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1serializer_1get_1task_1data +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1serializer_1get_1task_1data) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1get_1task_1data_FUNC); + rc = (jlong)gdk_content_serializer_get_task_data((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1get_1task_1data_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1serializer_1get_1user_1data +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1serializer_1get_1user_1data) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1get_1user_1data_FUNC); + rc = (jlong)gdk_content_serializer_get_user_data((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1get_1user_1data_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1serializer_1get_1value +JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1serializer_1get_1value) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1get_1value_FUNC); + rc = (jlong)gdk_content_serializer_get_value((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1get_1value_FUNC); + return rc; +} +#endif + +#ifndef NO_gdk_1content_1serializer_1return_1error +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1serializer_1return_1error) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1) +{ + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1return_1error_FUNC); + gdk_content_serializer_return_error((GdkContentSerializer*)arg0, (GError*)arg1); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1return_1error_FUNC); +} +#endif + +#ifndef NO_gdk_1content_1serializer_1return_1success +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1serializer_1return_1success) + (JNIEnv *env, jclass that, jlong arg0) +{ + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1return_1success_FUNC); + gdk_content_serializer_return_success((GdkContentSerializer*)arg0); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1return_1success_FUNC); +} +#endif + +#ifndef NO_gdk_1content_1serializer_1set_1task_1data +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1serializer_1set_1task_1data) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) +{ + GTK4_NATIVE_ENTER(env, that, gdk_1content_1serializer_1set_1task_1data_FUNC); + gdk_content_serializer_set_task_data((GdkContentSerializer*)arg0, (gpointer)arg1, (GDestroyNotify)arg2); + GTK4_NATIVE_EXIT(env, that, gdk_1content_1serializer_1set_1task_1data_FUNC); +} +#endif + #ifndef NO_gdk_1toplevel_1focus JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1toplevel_1focus) (JNIEnv *env, jclass that, jlong arg0, jint arg1) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h index 39dc470cb09..4cd87e8840f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h @@ -22,9 +22,25 @@ typedef enum { gdk_1clipboard_1get_1content_FUNC, gdk_1clipboard_1get_1formats_FUNC, + gdk_1clipboard_1is_1local_FUNC, + gdk_1clipboard_1read_1async_FUNC, + gdk_1clipboard_1read_1finish_FUNC, + gdk_1clipboard_1read_1value_1async_FUNC, + gdk_1clipboard_1read_1value_1finish_FUNC, gdk_1clipboard_1set_FUNC, gdk_1clipboard_1set_1content_FUNC, gdk_1clipboard_1set_1text_FUNC, + gdk_1content_1deserializer_1get_1cancellable_FUNC, + gdk_1content_1deserializer_1get_1gtype_FUNC, + gdk_1content_1deserializer_1get_1input_1stream_FUNC, + gdk_1content_1deserializer_1get_1mime_1type_FUNC, + gdk_1content_1deserializer_1get_1priority_FUNC, + gdk_1content_1deserializer_1get_1task_1data_FUNC, + gdk_1content_1deserializer_1get_1user_1data_FUNC, + gdk_1content_1deserializer_1get_1value_FUNC, + gdk_1content_1deserializer_1return_1error_FUNC, + gdk_1content_1deserializer_1return_1success_FUNC, + gdk_1content_1deserializer_1set_1task_1data_FUNC, gdk_1content_1formats_1builder_1add_1mime_1type_FUNC, gdk_1content_1formats_1builder_1free_1to_1formats_FUNC, gdk_1content_1formats_1builder_1new_FUNC, @@ -34,6 +50,19 @@ typedef enum { gdk_1content_1provider_1new_1for_1value_FUNC, gdk_1content_1provider_1new_1typed_FUNC, gdk_1content_1provider_1new_1union_FUNC, + gdk_1content_1register_1deserializer_FUNC, + gdk_1content_1register_1serializer_FUNC, + gdk_1content_1serializer_1get_1cancellable_FUNC, + gdk_1content_1serializer_1get_1gtype_FUNC, + gdk_1content_1serializer_1get_1mime_1type_FUNC, + gdk_1content_1serializer_1get_1output_1stream_FUNC, + gdk_1content_1serializer_1get_1priority_FUNC, + gdk_1content_1serializer_1get_1task_1data_FUNC, + gdk_1content_1serializer_1get_1user_1data_FUNC, + gdk_1content_1serializer_1get_1value_FUNC, + gdk_1content_1serializer_1return_1error_FUNC, + gdk_1content_1serializer_1return_1success_FUNC, + gdk_1content_1serializer_1set_1task_1data_FUNC, gdk_1toplevel_1focus_FUNC, gdk_1toplevel_1get_1state_FUNC, gdk_1toplevel_1lower_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c index 57579f46e21..ae7076efac8 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c @@ -10079,6 +10079,18 @@ JNIEXPORT jint JNICALL OS_NATIVE(GValue_1sizeof) } #endif +#ifndef NO_G_1IS_1VALUE +JNIEXPORT jboolean JNICALL OS_NATIVE(G_1IS_1VALUE) + (JNIEnv *env, jclass that, jlong arg0) +{ + jboolean rc = 0; + OS_NATIVE_ENTER(env, that, G_1IS_1VALUE_FUNC); + rc = (jboolean)G_IS_VALUE(arg0); + OS_NATIVE_EXIT(env, that, G_1IS_1VALUE_FUNC); + return rc; +} +#endif + #ifndef NO_G_1OBJECT_1CLASS_1CONSTRUCTOR JNIEXPORT jlong JNICALL OS_NATIVE(G_1OBJECT_1CLASS_1CONSTRUCTOR) (JNIEnv *env, jclass that, jlong arg0) @@ -10233,6 +10245,18 @@ JNIEXPORT jlong JNICALL OS_NATIVE(G_1VALUE_1TYPE) } #endif +#ifndef NO_G_1VALUE_1TYPE_1NAME +JNIEXPORT jlong JNICALL OS_NATIVE(G_1VALUE_1TYPE_1NAME) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, G_1VALUE_1TYPE_1NAME_FUNC); + rc = (jlong)G_VALUE_TYPE_NAME(arg0); + OS_NATIVE_EXIT(env, that, G_1VALUE_1TYPE_1NAME_FUNC); + return rc; +} +#endif + #ifndef NO_PANGO_1PIXELS JNIEXPORT jint JNICALL OS_NATIVE(PANGO_1PIXELS) (JNIEnv *env, jclass that, jint arg0) @@ -11478,6 +11502,18 @@ JNIEXPORT jint JNICALL OS_NATIVE(g_1idle_1add) } #endif +#ifndef NO_g_1io_1error_1quark +JNIEXPORT jint JNICALL OS_NATIVE(g_1io_1error_1quark) + (JNIEnv *env, jclass that) +{ + jint rc = 0; + OS_NATIVE_ENTER(env, that, g_1io_1error_1quark_FUNC); + rc = (jint)g_io_error_quark(); + OS_NATIVE_EXIT(env, that, g_1io_1error_1quark_FUNC); + return rc; +} +#endif + #ifndef NO_g_1list_1append JNIEXPORT jlong JNICALL OS_NATIVE(g_1list_1append) (JNIEnv *env, jclass that, jlong arg0, jlong arg1) @@ -11794,6 +11830,78 @@ JNIEXPORT jlong JNICALL OS_NATIVE(g_1memory_1input_1stream_1new_1from_1data) } #endif +#ifndef NO_g_1memory_1output_1stream_1get_1data +JNIEXPORT jlong JNICALL OS_NATIVE(g_1memory_1output_1stream_1get_1data) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1memory_1output_1stream_1get_1data_FUNC); + rc = (jlong)g_memory_output_stream_get_data((GMemoryOutputStream*)arg0); + OS_NATIVE_EXIT(env, that, g_1memory_1output_1stream_1get_1data_FUNC); + return rc; +} +#endif + +#ifndef NO_g_1memory_1output_1stream_1get_1data_1size +JNIEXPORT jlong JNICALL OS_NATIVE(g_1memory_1output_1stream_1get_1data_1size) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1memory_1output_1stream_1get_1data_1size_FUNC); + rc = (jlong)g_memory_output_stream_get_data_size((GMemoryOutputStream*)arg0); + OS_NATIVE_EXIT(env, that, g_1memory_1output_1stream_1get_1data_1size_FUNC); + return rc; +} +#endif + +#ifndef NO_g_1memory_1output_1stream_1get_1size +JNIEXPORT jlong JNICALL OS_NATIVE(g_1memory_1output_1stream_1get_1size) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1memory_1output_1stream_1get_1size_FUNC); + rc = (jlong)g_memory_output_stream_get_size((GMemoryOutputStream*)arg0); + OS_NATIVE_EXIT(env, that, g_1memory_1output_1stream_1get_1size_FUNC); + return rc; +} +#endif + +#ifndef NO_g_1memory_1output_1stream_1new_1resizable +JNIEXPORT jlong JNICALL OS_NATIVE(g_1memory_1output_1stream_1new_1resizable) + (JNIEnv *env, jclass that) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1memory_1output_1stream_1new_1resizable_FUNC); + rc = (jlong)g_memory_output_stream_new_resizable(); + OS_NATIVE_EXIT(env, that, g_1memory_1output_1stream_1new_1resizable_FUNC); + return rc; +} +#endif + +#ifndef NO_g_1memory_1output_1stream_1steal_1as_1bytes +JNIEXPORT jlong JNICALL OS_NATIVE(g_1memory_1output_1stream_1steal_1as_1bytes) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1memory_1output_1stream_1steal_1as_1bytes_FUNC); + rc = (jlong)g_memory_output_stream_steal_as_bytes((GMemoryOutputStream*)arg0); + OS_NATIVE_EXIT(env, that, g_1memory_1output_1stream_1steal_1as_1bytes_FUNC); + return rc; +} +#endif + +#ifndef NO_g_1memory_1output_1stream_1steal_1data +JNIEXPORT jlong JNICALL OS_NATIVE(g_1memory_1output_1stream_1steal_1data) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1memory_1output_1stream_1steal_1data_FUNC); + rc = (jlong)g_memory_output_stream_steal_data((GMemoryOutputStream*)arg0); + OS_NATIVE_EXIT(env, that, g_1memory_1output_1stream_1steal_1data_FUNC); + return rc; +} +#endif + #ifndef NO_g_1menu_1insert_1item JNIEXPORT void JNICALL OS_NATIVE(g_1menu_1insert_1item) (JNIEnv *env, jclass that, jlong arg0, jint arg1, jlong arg2) @@ -12124,6 +12232,80 @@ JNIEXPORT void JNICALL OS_NATIVE(g_1object_1unref) } #endif +#ifndef NO_g_1output_1stream_1splice_1async +JNIEXPORT void JNICALL OS_NATIVE(g_1output_1stream_1splice_1async) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2, jint arg3, jlong arg4, jlong arg5, jlong arg6) +{ + OS_NATIVE_ENTER(env, that, g_1output_1stream_1splice_1async_FUNC); + g_output_stream_splice_async((GOutputStream*)arg0, (GInputStream *)arg1, (GOutputStreamSpliceFlags)arg2, (int)arg3, (GCancellable *)arg4, (GAsyncReadyCallback)arg5, (gpointer)arg6); + OS_NATIVE_EXIT(env, that, g_1output_1stream_1splice_1async_FUNC); +} +#endif + +#ifndef NO_g_1output_1stream_1splice_1finish +JNIEXPORT jlong JNICALL OS_NATIVE(g_1output_1stream_1splice_1finish) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlongArray arg2) +{ + jlong *lparg2=NULL; + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1output_1stream_1splice_1finish_FUNC); + if (arg2) if ((lparg2 = (*env)->GetLongArrayElements(env, arg2, NULL)) == NULL) goto fail; + rc = (jlong)g_output_stream_splice_finish((GOutputStream*)arg0, (GAsyncResult*)arg1, (GError**)lparg2); +fail: + if (arg2 && lparg2) (*env)->ReleaseLongArrayElements(env, arg2, lparg2, 0); + OS_NATIVE_EXIT(env, that, g_1output_1stream_1splice_1finish_FUNC); + return rc; +} +#endif + +#ifndef NO_g_1output_1stream_1write_1all +JNIEXPORT jboolean JNICALL OS_NATIVE(g_1output_1stream_1write_1all) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jlongArray arg3, jlong arg4, jlongArray arg5) +{ + jlong *lparg3=NULL; + jlong *lparg5=NULL; + jboolean rc = 0; + OS_NATIVE_ENTER(env, that, g_1output_1stream_1write_1all_FUNC); + if (arg3) if ((lparg3 = (*env)->GetLongArrayElements(env, arg3, NULL)) == NULL) goto fail; + if (arg5) if ((lparg5 = (*env)->GetLongArrayElements(env, arg5, NULL)) == NULL) goto fail; + rc = (jboolean)g_output_stream_write_all((GOutputStream*)arg0, (void*)arg1, (gsize)arg2, (gsize*)lparg3, (GCancellable*)arg4, (GError**)lparg5); +fail: + if (arg5 && lparg5) (*env)->ReleaseLongArrayElements(env, arg5, lparg5, 0); + if (arg3 && lparg3) (*env)->ReleaseLongArrayElements(env, arg3, lparg3, 0); + OS_NATIVE_EXIT(env, that, g_1output_1stream_1write_1all_FUNC); + return rc; +} +#endif + +#ifndef NO_g_1output_1stream_1write_1all_1async +JNIEXPORT void JNICALL OS_NATIVE(g_1output_1stream_1write_1all_1async) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jint arg3, jlong arg4, jlong arg5, jlong arg6) +{ + OS_NATIVE_ENTER(env, that, g_1output_1stream_1write_1all_1async_FUNC); + g_output_stream_write_all_async((GOutputStream*)arg0, (void*)arg1, (gsize)arg2, (int)arg3, (GCancellable*)arg4, (GAsyncReadyCallback)arg5, (gpointer)arg6); + OS_NATIVE_EXIT(env, that, g_1output_1stream_1write_1all_1async_FUNC); +} +#endif + +#ifndef NO_g_1output_1stream_1write_1all_1finish +JNIEXPORT jboolean JNICALL OS_NATIVE(g_1output_1stream_1write_1all_1finish) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlongArray arg2, jlongArray arg3) +{ + jlong *lparg2=NULL; + jlong *lparg3=NULL; + jboolean rc = 0; + OS_NATIVE_ENTER(env, that, g_1output_1stream_1write_1all_1finish_FUNC); + if (arg2) if ((lparg2 = (*env)->GetLongArrayElements(env, arg2, NULL)) == NULL) goto fail; + if (arg3) if ((lparg3 = (*env)->GetLongArrayElements(env, arg3, NULL)) == NULL) goto fail; + rc = (jboolean)g_output_stream_write_all_finish((GOutputStream*)arg0, (GAsyncResult*)arg1, (gsize*)lparg2, (GError**)lparg3); +fail: + if (arg3 && lparg3) (*env)->ReleaseLongArrayElements(env, arg3, lparg3, 0); + if (arg2 && lparg2) (*env)->ReleaseLongArrayElements(env, arg2, lparg2, 0); + OS_NATIVE_EXIT(env, that, g_1output_1stream_1write_1all_1finish_FUNC); + return rc; +} +#endif + #ifndef NO_g_1quark_1from_1string JNIEXPORT jint JNICALL OS_NATIVE(g_1quark_1from_1string) (JNIEnv *env, jclass that, jbyteArray arg0) @@ -12626,6 +12808,18 @@ JNIEXPORT jboolean JNICALL OS_NATIVE(g_1type_1is_1a) } #endif +#ifndef NO_g_1type_1name +JNIEXPORT jlong JNICALL OS_NATIVE(g_1type_1name) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1type_1name_FUNC); + rc = (jlong)g_type_name((GType)arg0); + OS_NATIVE_EXIT(env, that, g_1type_1name_FUNC); + return rc; +} +#endif + #ifndef NO_g_1type_1parent JNIEXPORT jlong JNICALL OS_NATIVE(g_1type_1parent) (JNIEnv *env, jclass that, jlong arg0) @@ -12851,6 +13045,18 @@ JNIEXPORT jlong JNICALL OS_NATIVE(g_1utf8_1to_1utf16___3BJ_3J_3J_3J) } #endif +#ifndef NO_g_1value_1get_1boxed +JNIEXPORT jlong JNICALL OS_NATIVE(g_1value_1get_1boxed) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1value_1get_1boxed_FUNC); + rc = (jlong)g_value_get_boxed((const GValue *)arg0); + OS_NATIVE_EXIT(env, that, g_1value_1get_1boxed_FUNC); + return rc; +} +#endif + #ifndef NO_g_1value_1get_1double JNIEXPORT jdouble JNICALL OS_NATIVE(g_1value_1get_1double) (JNIEnv *env, jclass that, jlong arg0) @@ -12875,6 +13081,18 @@ JNIEXPORT jfloat JNICALL OS_NATIVE(g_1value_1get_1float) } #endif +#ifndef NO_g_1value_1get_1gtype +JNIEXPORT jlong JNICALL OS_NATIVE(g_1value_1get_1gtype) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + OS_NATIVE_ENTER(env, that, g_1value_1get_1gtype_FUNC); + rc = (jlong)g_value_get_gtype((const GValue *)arg0); + OS_NATIVE_EXIT(env, that, g_1value_1get_1gtype_FUNC); + return rc; +} +#endif + #ifndef NO_g_1value_1get_1int JNIEXPORT jint JNICALL OS_NATIVE(g_1value_1get_1int) (JNIEnv *env, jclass that, jlong arg0) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c index 2b26e5a7ff7..e92dd85a90f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c @@ -2232,3 +2232,34 @@ swt_releaseArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray, char **cString } free(cStrings); } + +static void *string_boxed_copy(void *ptr) { + return ptr; +} + +static void string_boxed_free(void *ptr) { +} + +JNIEXPORT jlong JNICALL OS_NATIVE(register_1gtype_1for_1name) + (JNIEnv *env, jclass that, jstring name) +{ + long rc; + const char *lpname = NULL; + OS_NATIVE_ENTER(env, that, register_1gtype_1for_1name_FUNC) + if (name) lpname= (const char *) (*env)->GetStringUTFChars(env, name, NULL); + rc = g_boxed_type_register_static(lpname, string_boxed_copy, string_boxed_free); + if (name && lpname) (*env)->ReleaseStringUTFChars(env, name, lpname); + OS_NATIVE_EXIT(env, that, register_1gtype_1for_1name_FUNC) + return rc; +} + +JNIEXPORT jlong JNICALL OS_NATIVE(create_1gvalue) + (JNIEnv *env, jclass that, jlong gtype, jlong value) +{ + OS_NATIVE_ENTER(env, that, create_1gvalue_FUNC) + GValue *v = g_new0 (GValue, 1); + g_value_init(v, (GType)gtype); + g_value_take_boxed(v, (void *)value); + OS_NATIVE_EXIT(env, that, create_1gvalue_FUNC) + return (jlong)v; +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h index a83c778d8ee..b83d217a8fe 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h @@ -824,6 +824,7 @@ typedef enum { GPollFD_1sizeof_FUNC, GTypeInfo_1sizeof_FUNC, GValue_1sizeof_FUNC, + G_1IS_1VALUE_FUNC, G_1OBJECT_1CLASS_1CONSTRUCTOR_FUNC, G_1OBJECT_1CLASS_1SET_1CONSTRUCTOR_FUNC, G_1OBJECT_1GET_1CLASS_FUNC, @@ -837,6 +838,7 @@ typedef enum { G_1TYPE_1LONG_FUNC, G_1TYPE_1STRING_FUNC, G_1VALUE_1TYPE_FUNC, + G_1VALUE_1TYPE_1NAME_FUNC, PANGO_1PIXELS_FUNC, PANGO_1TYPE_1FONT_1DESCRIPTION_FUNC, PANGO_1TYPE_1FONT_1FACE_FUNC, @@ -870,6 +872,7 @@ typedef enum { call__JJJJJ_FUNC, call__JJJJJJJ_FUNC, call__JJJJJJJJ_FUNC, + create_1gvalue_FUNC, g_1action_1get_1enabled_FUNC, g_1action_1get_1state_FUNC, g_1action_1map_1add_1action_FUNC, @@ -928,6 +931,7 @@ typedef enum { g_1icon_1new_1for_1string_FUNC, g_1icon_1to_1string_FUNC, g_1idle_1add_FUNC, + g_1io_1error_1quark_FUNC, g_1list_1append_FUNC, g_1list_1data_FUNC, g_1list_1free_FUNC, @@ -954,6 +958,12 @@ typedef enum { g_1main_1context_1wakeup_FUNC, g_1malloc_FUNC, g_1memory_1input_1stream_1new_1from_1data_FUNC, + g_1memory_1output_1stream_1get_1data_FUNC, + g_1memory_1output_1stream_1get_1data_1size_FUNC, + g_1memory_1output_1stream_1get_1size_FUNC, + g_1memory_1output_1stream_1new_1resizable_FUNC, + g_1memory_1output_1stream_1steal_1as_1bytes_FUNC, + g_1memory_1output_1stream_1steal_1data_FUNC, g_1menu_1insert_1item_FUNC, g_1menu_1item_1new_FUNC, g_1menu_1item_1new_1section_FUNC, @@ -978,6 +988,11 @@ typedef enum { g_1object_1set__J_3B_3BJ_FUNC, g_1object_1set_1qdata_FUNC, g_1object_1unref_FUNC, + g_1output_1stream_1splice_1async_FUNC, + g_1output_1stream_1splice_1finish_FUNC, + g_1output_1stream_1write_1all_FUNC, + g_1output_1stream_1write_1all_1async_FUNC, + g_1output_1stream_1write_1all_1finish_FUNC, g_1quark_1from_1string_FUNC, g_1set_1prgname_FUNC, g_1signal_1add_1emission_1hook_FUNC, @@ -1017,6 +1032,7 @@ typedef enum { g_1type_1class_1unref_FUNC, g_1type_1interface_1peek_1parent_FUNC, g_1type_1is_1a_FUNC, + g_1type_1name_FUNC, g_1type_1parent_FUNC, g_1type_1register_1static_FUNC, g_1unsetenv_FUNC, @@ -1031,8 +1047,10 @@ typedef enum { g_1utf8_1strlen_FUNC, g_1utf8_1to_1utf16__JJ_3J_3J_3J_FUNC, g_1utf8_1to_1utf16___3BJ_3J_3J_3J_FUNC, + g_1value_1get_1boxed_FUNC, g_1value_1get_1double_FUNC, g_1value_1get_1float_FUNC, + g_1value_1get_1gtype_FUNC, g_1value_1get_1int_FUNC, g_1value_1get_1int64_FUNC, g_1value_1get_1object_FUNC, @@ -1203,6 +1221,7 @@ typedef enum { pango_1version_FUNC, printerOptionWidgetNewProc_1CALLBACK_FUNC, realpath_FUNC, + register_1gtype_1for_1name_FUNC, strcmp_FUNC, swt_1debug_1on_1fatal_1warnings_FUNC, swt_1fixed_1accessible_1get_1type_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java index c319bbac70b..2731e4e83bb 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java @@ -155,7 +155,85 @@ public static String getEnvironmentalVariable (String envVarName) { } /** Constants */ + /* enum GFileError */ + public static final int G_FILE_ERROR_EXIST = 0; + public static final int G_FILE_ERROR_ISDIR = 1; + public static final int G_FILE_ERROR_ACCES = 2; + public static final int G_FILE_ERROR_NAMETOOLONG = 3; + public static final int G_FILE_ERROR_NOENT = 4; + public static final int G_FILE_ERROR_NOTDIR = 5; + public static final int G_FILE_ERROR_NXIO = 6; + public static final int G_FILE_ERROR_NODEV = 7; + public static final int G_FILE_ERROR_ROFS = 8; + public static final int G_FILE_ERROR_TXTBSY = 9; + public static final int G_FILE_ERROR_FAULT = 10; + public static final int G_FILE_ERROR_LOOP = 11; + public static final int G_FILE_ERROR_NOSPC = 12; + public static final int G_FILE_ERROR_NOMEM = 13; + public static final int G_FILE_ERROR_MFILE = 14; + public static final int G_FILE_ERROR_NFILE = 15; + public static final int G_FILE_ERROR_BADF = 16; + public static final int G_FILE_ERROR_INVAL = 17; + public static final int G_FILE_ERROR_PIPE = 18; + public static final int G_FILE_ERROR_AGAIN = 19; + public static final int G_FILE_ERROR_INTR = 20; public static final int G_FILE_ERROR_IO = 21; + public static final int G_FILE_ERROR_PERM = 22; + public static final int G_FILE_ERROR_NOSYS = 23; + public static final int G_FILE_ERROR_FAILED = 24; + + /* enum GIOErrorEnum */ + public static final int G_IO_ERROR_FAILED = 0; + public static final int G_IO_ERROR_NOT_FOUND = 1; + public static final int G_IO_ERROR_EXISTS = 2; + public static final int G_IO_ERROR_IS_DIRECTORY = 3; + public static final int G_IO_ERROR_NOT_DIRECTORY = 4; + public static final int G_IO_ERROR_NOT_EMPTY = 5; + public static final int G_IO_ERROR_NOT_REGULAR_FILE = 6; + public static final int G_IO_ERROR_NOT_SYMBOLIC_LINK = 7; + public static final int G_IO_ERROR_NOT_MOUNTABLE_FILE = 8; + public static final int G_IO_ERROR_FILENAME_TOO_LONG = 9; + public static final int G_IO_ERROR_INVALID_FILENAME = 10; + public static final int G_IO_ERROR_TOO_MANY_LINKS = 11; + public static final int G_IO_ERROR_NO_SPACE = 12; + public static final int G_IO_ERROR_INVALID_ARGUMENT = 13; + public static final int G_IO_ERROR_PERMISSION_DENIED = 14; + public static final int G_IO_ERROR_NOT_SUPPORTED = 15; + public static final int G_IO_ERROR_NOT_MOUNTED = 16; + public static final int G_IO_ERROR_ALREADY_MOUNTED = 17; + public static final int G_IO_ERROR_CLOSED = 18; + public static final int G_IO_ERROR_CANCELLED = 19; + public static final int G_IO_ERROR_PENDING = 20; + public static final int G_IO_ERROR_READ_ONLY = 21; + public static final int G_IO_ERROR_CANT_CREATE_BACKUP = 22; + public static final int G_IO_ERROR_WRONG_ETAG = 23; + public static final int G_IO_ERROR_TIMED_OUT = 24; + public static final int G_IO_ERROR_WOULD_RECURSE = 25; + public static final int G_IO_ERROR_BUSY = 26; + public static final int G_IO_ERROR_WOULD_BLOCK = 27; + public static final int G_IO_ERROR_HOST_NOT_FOUND = 28; + public static final int G_IO_ERROR_WOULD_MERGE = 29; + public static final int G_IO_ERROR_FAILED_HANDLED = 30; + public static final int G_IO_ERROR_TOO_MANY_OPEN_FILES = 31; + public static final int G_IO_ERROR_NOT_INITIALIZED = 32; + public static final int G_IO_ERROR_ADDRESS_IN_USE = 33; + public static final int G_IO_ERROR_PARTIAL_INPUT = 34; + public static final int G_IO_ERROR_INVALID_DATA = 35; + public static final int G_IO_ERROR_DBUS_ERROR = 36; + public static final int G_IO_ERROR_HOST_UNREACHABLE = 37; + public static final int G_IO_ERROR_NETWORK_UNREACHABLE = 38; + public static final int G_IO_ERROR_CONNECTION_REFUSED = 39; + public static final int G_IO_ERROR_PROXY_FAILED = 40; + public static final int G_IO_ERROR_PROXY_AUTH_FAILED = 41; + public static final int G_IO_ERROR_PROXY_NEED_AUTH = 42; + public static final int G_IO_ERROR_PROXY_NOT_ALLOWED = 43; + public static final int G_IO_ERROR_BROKEN_PIPE = 44; + public static final int G_IO_ERROR_CONNECTION_CLOSED = G_IO_ERROR_BROKEN_PIPE; + public static final int G_IO_ERROR_NOT_CONNECTED = 45; + public static final int G_IO_ERROR_MESSAGE_TOO_LARGE = 46; + public static final int G_IO_ERROR_NO_SUCH_DEVICE = 47; + public static final int G_IO_ERROR_DESTINATION_UNSET = 48; + public static final int G_FILE_TEST_IS_DIR = 1 << 2; public static final int G_FILE_TEST_IS_EXECUTABLE = 1 << 3; public static final int G_SIGNAL_MATCH_DATA = 1 << 4; @@ -165,6 +243,10 @@ public static String getEnvironmentalVariable (String envVarName) { public static final int G_LOG_LEVEL_MASK = 0xfffffffc; public static final int G_APP_INFO_CREATE_NONE = 0; public static final int G_APP_INFO_CREATE_SUPPORTS_URIS = (1 << 1); + public static final int G_OUTPUT_STREAM_SPLICE_NONE = 0; + public static final int G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE = (1 << 0); + public static final int G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET = (1 << 1); + public static final int G_PRIORITY_DEFAULT = 0; public static final int GTK_TYPE_TEXT_BUFFER = 21; public static final int PANGO_ALIGN_LEFT = 0; public static final int PANGO_ALIGN_CENTER = 1; @@ -567,6 +649,33 @@ public static String getEnvironmentalVariable (String envVarName) { /* custom version of g_utf8 for 16 bit */ public static final native long g_utf16_offset_to_utf8_offset(long str, long offset); + /** + * Creates a GType for the given name. The name must be unique for the lifetime + * of the process. + * + * This gives a unique GType to register in GTK4's serializers. + * + * @param name The name of the type - must be unique + * @return the new GType - the data is owned by GTK and must not be freed + * @method flags=no_gen + * @category custom + */ + // TODO this is too generic a name - this method is only for use with ContentProvider + public static final native long register_gtype_for_name(String name); + + /** + * Creates a GValue for the given GType, when that GType was created by + * {@link #register_gtype_for_name(String)} + * + * @param gtype the type created with {@link #register_gtype_for_name(String)} + * @param value a non-zero value to store in the gvalue of type gtype + * @return the new GValue - the data is owned by the caller of the method + * @method flags=no_gen + * @category custom + */ + // TODO this is too generic a name - this method is only for use with ContentProvider + public static final native long create_gvalue(long gtype, long value); + /** CUSTOM_CODE END */ /** @@ -847,6 +956,8 @@ public static boolean isX11 () { /** @method flags=const */ public static final native long G_TYPE_INT64(); public static final native long G_VALUE_TYPE(long value); +public static final native long G_VALUE_TYPE_NAME(long value); +public static final native boolean G_IS_VALUE(long value); public static final native long G_OBJECT_TYPE(long instance); /** @method flags=const */ public static final native long G_TYPE_STRING(); @@ -932,6 +1043,7 @@ public static boolean isX11 () { */ public static final native boolean g_content_type_is_a(long type, byte[] supertype); public static final native int g_file_error_quark(); +public static final native int g_io_error_quark(); /** * @param info cast=(GFileInfo *) */ @@ -1332,6 +1444,11 @@ public static boolean isX11 () { public static final native void g_type_class_unref(long g_class); /** @param iface cast=(gpointer) */ public static final native long g_type_interface_peek_parent(long iface); +/** + * @param g_type cast=(GType) + * @return char * that must be freed + */ +public static final native long g_type_name(long g_type); /** * @param type cast=(GType) * @param is_a_type cast=(GType) @@ -1410,6 +1527,11 @@ public static boolean isX11 () { public static final native void g_value_unset (long value); /** @param value cast=(const GValue *) */ public static final native long g_value_peek_pointer(long value); +/** @param value cast=(const GValue *) */ +public static final native long g_value_get_boxed(long value); +/** @param value cast=(const GValue *) */ +public static final native long g_value_get_gtype(long value); + /** * @param variable cast=(const gchar *),flags=no_out */ @@ -2331,4 +2453,71 @@ public static final native long g_dbus_proxy_new_for_bus_sync(int bus_type, int */ public static final native long g_memory_input_stream_new_from_data(long data, long len, long destroy); +/** + * @param stream cast=(GOutputStream*) + * @param source cast=(GInputStream *) + * @param flags cast=(GOutputStreamSpliceFlags) + * @param io_priority cast=(int) + * @param cancellable cast=(GCancellable *) + * @param callback cast=(GAsyncReadyCallback) + * @param user_data cast=(gpointer) + */ +public static final native void g_output_stream_splice_async(long stream, long source, int flags, int io_priority, long cancellable, long callback, long user_data); +/** + * @param stream cast=(GOutputStream*) + * @param result cast=(GAsyncResult*) + * @param error cast=(GError**) + */ +public static final native long g_output_stream_splice_finish(long stream, long result, long[] error); +/** + * + */ +public static final native long g_memory_output_stream_new_resizable(); +/** + * @param ostream cast=(GMemoryOutputStream*) + */ +public static final native long g_memory_output_stream_get_data(long ostream); +/** + * @param ostream cast=(GMemoryOutputStream*) + */ +public static final native long g_memory_output_stream_get_size(long ostream); +/** + * @param ostream cast=(GMemoryOutputStream*) + */ +public static final native long g_memory_output_stream_get_data_size(long ostream); +/** + * @param ostream cast=(GMemoryOutputStream*) + */ +public static final native long g_memory_output_stream_steal_data(long ostream); +/** + * @param ostream cast=(GMemoryOutputStream*) + */ +public static final native long g_memory_output_stream_steal_as_bytes(long ostream); +/** + * @param stream cast=(GOutputStream*) + * @param buffer cast=(void*) + * @param count cast=(gsize) + * @param bytes_written cast=(gsize*) + * @param cancellable cast=(GCancellable*) + * @param error cast=(GError**) + */ +public static final native boolean g_output_stream_write_all(long stream, long buffer, long count, long[] bytes_written, long cancellable, long[] error); +/** + * @param stream cast=(GOutputStream*) + * @param buffer cast=(void*) + * @param count cast=(gsize) + * @param io_priority cast=(int) + * @param cancellable cast=(GCancellable*) + * @param callback cast=(GAsyncReadyCallback) + * @param user_data cast=(gpointer) + */ +public static final native void g_output_stream_write_all_async(long stream, long buffer, long count, int io_priority, long cancellable, long callback, long user_data); +/** + * + * @param stream cast=(GOutputStream*) + * @param result cast=(GAsyncResult*) + * @param bytes_written cast=(gsize*) + * @param error cast=(GError**) + */ +public static final native boolean g_output_stream_write_all_finish(long stream, long result, long[] bytes_written, long[] error); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java index 48ceb120d5c..6fb27115481 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java @@ -838,6 +838,42 @@ public class GTK4 { * @param clipboard cast=(GdkClipboard*) */ public static final native long gdk_clipboard_get_content(long clipboard); + /** + * @param clipboard cast=(GdkClipboard*) + * @param type cast=(GType) + * @param io_priority cast=(int) + * @param cancellable cast=(GCancellable *) + * @param callback cast=(GAsyncReadyCallback) + * @param user_data cast=(gpointer) + */ + public static final native void gdk_clipboard_read_value_async(long clipboard, long type, int io_priority, long cancellable, long callback, long user_data); + /** + * @param clipboard cast=(GdkClipboard*) + * @param result cast=(GAsyncResult *) + * @param error cast=(GError **) + */ + public static final native long gdk_clipboard_read_value_finish(long clipboard, long result, long[] error); + /** + * @param clipboard cast=(GdkClipboard*) + * @param mime_types cast=(const char **) + * @param io_priority cast=(int) + * @param cancellable cast=(GCancellable *) + * @param callback cast=(GAsyncReadyCallback) + * @param user_data cast=(gpointer) + */ + public static final native void gdk_clipboard_read_async(long clipboard, String[] mime_types, int io_priority, long cancellable, long callback, long user_data); + /** + * @param clipboard cast=(GdkClipboard*) + * @param result cast=(GAsyncResult *) + * @param out_mime_type cast=(const char**) + * @param error cast=(GError **) + */ + public static final native long gdk_clipboard_read_finish(long clipboard, long result, long[] out_mime_type, long[] error); + /** + * @param clipboard cast=(GdkClipboard*) + */ + public static final native boolean gdk_clipboard_is_local(long clipboard); + /** * @param provider cast=(GdkContentProvider *) * @param value cast=(GValue *) @@ -865,6 +901,118 @@ public class GTK4 { */ public static final native long gdk_content_formats_get_gtypes(long formats, long[] n_gtypes); + /** + * @param type cast=(GType) + * @param mime_type cast=(const char*) + * @param serialize cast=(GdkContentSerializeFunc) + * @param data cast=(gpointer) + * @param notify cast=(GDestroyNotify) + */ + public static final native void gdk_content_register_serializer(long type, String mime_type, long serialize, long data, long notify); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native long gdk_content_serializer_get_cancellable(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native long gdk_content_serializer_get_gtype(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native long gdk_content_serializer_get_mime_type(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native long gdk_content_serializer_get_output_stream(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native int gdk_content_serializer_get_priority(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native long gdk_content_serializer_get_task_data(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native long gdk_content_serializer_get_user_data(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native long gdk_content_serializer_get_value(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + * @param error cast=(GError*) + */ + public static final native void gdk_content_serializer_return_error(long serializer, long error); + /** + * @param serializer cast=(GdkContentSerializer*) + */ + public static final native void gdk_content_serializer_return_success(long serializer); + /** + * @param serializer cast=(GdkContentSerializer*) + * @param data cast=(gpointer) + * @param notify cast=(GDestroyNotify) + */ + public static final native void gdk_content_serializer_set_task_data(long serializer, long data, long notify); + /** + * @param mime_type cast=(const char*) + * @param type cast=(GType) + * @param deserialize cast=(GdkContentDeserializeFunc) + * @param data cast=(gpointer) + * @param notify cast=(GDestroyNotify) + */ + public static final native void gdk_content_register_deserializer(String mime_type, long type, long deserialize, long data, long notify); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native long gdk_content_deserializer_get_cancellable(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native long gdk_content_deserializer_get_gtype(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native long gdk_content_deserializer_get_input_stream(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native long gdk_content_deserializer_get_mime_type(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native int gdk_content_deserializer_get_priority(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native long gdk_content_deserializer_get_task_data(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native long gdk_content_deserializer_get_user_data(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native long gdk_content_deserializer_get_value(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + * @param error cast=(GError*) + */ + public static final native void gdk_content_deserializer_return_error(long deserializer, long error); + /** + * @param deserializer cast=(GdkContentDeserializer*) + */ + public static final native void gdk_content_deserializer_return_success(long deserializer); + /** + * @param deserializer cast=(GdkContentDeserializer*) + * @param data cast=(gpointer) + * @param notify cast=(GDestroyNotify) + */ + public static final native void gdk_content_deserializer_set_task_data(long deserializer, long data, long notify); + + public static final native long gtk_gesture_rotate_new(); public static final native long gtk_gesture_zoom_new(); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/AsyncFinishUtil.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/AsyncFinishUtil.java new file mode 100644 index 00000000000..eb6ef6c9adf --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/AsyncFinishUtil.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2020, 2025 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.swt.internal; + +import java.lang.reflect.*; +import java.util.function.*; + +import org.eclipse.swt.widgets.*; + +/** + * This class is an internal class based on {@link SyncDialogUtil} for the + * non-UI and reentrant parts of GTK4, such as the clipboard. + * + * The run method is non-blocking here! + */ + +public class AsyncFinishUtil { + private Callback dialogResponseCallback; + private Function dialogAsyncFinish; + private Long dialogAsyncValue; + + /** + * TODO: Write new javadoc here + */ + public void run(Display display, AsyncReadyCallback callback) { + initializeResponseCallback(); + + dialogAsyncFinish = callback::await; + callback.async(dialogResponseCallback.getAddress()); + } + + /** + * Returns null until await (aka finish) method is called. + * Once await is finished, will have non-null return value from finish method + */ + public Long getDialogAsyncValue() { + return dialogAsyncValue; + } + + /** + * Initializes the response callback and resets the responseID of the dialog to + * the default value. This function should be called before connect the dialog + * to the "response" signal, as this sets up the callback. + */ + private void initializeResponseCallback() { + dialogResponseCallback = new Callback(this, "dialogResponseProc", void.class, + new Type[] { long.class, long.class, long.class }); + dialogAsyncValue = null; + } + + private void disposeResponseCallback() { + dialogResponseCallback.dispose(); + dialogResponseCallback = null; + dialogAsyncFinish = null; + } + + void dialogResponseProc(long dialog, long response, long user_data) { + if (dialogAsyncFinish != null) { + dialogAsyncValue = dialogAsyncFinish.apply(response); + } + disposeResponseCallback(); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SyncFinishCallback.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SyncFinishCallback.java new file mode 100644 index 00000000000..fd4b56e508d --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SyncFinishCallback.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2024 Patrick Ziegler and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Patrick Ziegler - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal; + +/** + * This class implements the GIO AsyncReadyCallback type and is used to + * transform an asynchronous {@code async} and synchronous {@code await} + * operation into a single synchronous {@code run} operation. + */ +public interface SyncFinishCallback { + /** + * This method is responsible for initializes the asynchronous operation + * + * @param callback The callback address to execute when the operation is + * complete. + */ + void async(long callback); + + /** + * This method is called from within the callback function in order to + * finish the executed operation and to return the result. + * + * @param result The generic, asynchronous function result. + * @return The specific result of the operation. + */ + T await(long result); +} \ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SyncFinishUtil.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SyncFinishUtil.java new file mode 100644 index 00000000000..f069ef32c53 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SyncFinishUtil.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2020, 2025 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.swt.internal; + +import java.lang.reflect.*; +import java.util.function.*; + +import org.eclipse.swt.widgets.*; + +/** + * This class is an internal class based on {@link SyncDialogUtil} for the + * non-UI and reentrant parts of GTK4, such as the clipboard. + * + * TODO should "org.eclipse.swt.internal.gtk.dispatchEvent" be set on display so + * that (very?) unrelated events aren't processed until we are done here? We + * need to process some unrelated events because one async operation could be + * writing to a stream another is reading from and they both need to run + * "simultaneously" for the operation to succeed. + */ + +public class SyncFinishUtil { + private Callback dialogResponseCallback; + private Function dialogAsyncFinish; + private T dialogAsyncValue; + private boolean dialogAsyncValueSet; + + /** + * This method implements the {@code AsyncReadyCallback} mechanism that is used + * in GTK4. Most operations within GTK4 are executed asynchronously, where the + * user is given the option to respond to the completion of such an operation + * via a callback method, in order to e.g. process the result or to apply + * additional cleanup tasks.
+ * When calling this method, the asynchronous operation is initiated via the + * {code asyncOpen} parameter. Callers have to ensure that the callback address + * is used as argument for the {@code AsyncReadyCallback} parameter. From within + * the callback routine, the {@code asyncFinish} function is called, receiving + * the {@code AsyncResult} of the callback as argument and returning the + * {@code long} value of the callback function.
+ * This method blocks until the callback method has been called. It is therefore + * essential that callers use the address of the {@link Callback} as address for + * the {@code AsyncReadyCallback} object. + */ + public T run(Display display, SyncFinishCallback callback) { + System.out.println("Running SyncFinishUtil " + this.hashCode()); + initializeResponseCallback(); + + dialogAsyncFinish = callback::await; + System.out.println("Running SyncFinishUtil await " + this.hashCode()); + callback.async(dialogResponseCallback.getAddress()); + + System.out.println("Running SyncFinishUtil readAndDispatch " + this.hashCode()); + while (!display.isDisposed()) { + if (dialogAsyncValueSet) { + break; + } + display.readAndDispatch(); + } + + disposeResponseCallback(); + System.out.println("Running SyncFinishUtil FINISHED " + this.hashCode()); + return dialogAsyncValue; + } + + /** + * Initializes the response callback and resets the responseID of the dialog to + * the default value. This function should be called before connect the dialog + * to the "response" signal, as this sets up the callback. + */ + private void initializeResponseCallback() { + dialogResponseCallback = new Callback(this, "dialogResponseProc", void.class, + new Type[] { long.class, long.class, long.class }); + dialogAsyncValue = null; + dialogAsyncValueSet = false; + } + + private void disposeResponseCallback() { + dialogResponseCallback.dispose(); + dialogResponseCallback = null; + dialogAsyncFinish = null; + } + + /** + * Callback function for the "response" signal in GtkDialog widgets. + * Responsibility of destroying the dialog is the owner of the dialog handle. + * + * Note: Native dialogs are platform dialogs that don't use GtkDialog or + * GtkWindow. + */ + void dialogResponseProc(long dialog, long response, long user_data) { + System.out.println("Running SyncFinishUtil dialogResponseProc " + this.hashCode()); + if (dialogAsyncFinish != null) { + System.out.println("Running SyncFinishUtil apply " + this.hashCode()); + dialogAsyncValue = dialogAsyncFinish.apply(response); + System.out.println("Running SyncFinishUtil dialogAsyncValueSet " + this.hashCode()); + dialogAsyncValueSet = true; + } + } +} diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/ClipboardSwingTester.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/ClipboardSwingTester.java new file mode 100644 index 00000000000..7d6478c7830 --- /dev/null +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/ClipboardSwingTester.java @@ -0,0 +1,10 @@ +package org.eclipse.swt.tests.junit; + +public class ClipboardSwingTester { + + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + +} diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/SwtTestUtil.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/SwtTestUtil.java index cce810b32bc..beb7d4af66e 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/SwtTestUtil.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/SwtTestUtil.java @@ -105,7 +105,8 @@ public class SwtTestUtil { public final static boolean isX11 = isGTK && "x11".equals(System.getProperty("org.eclipse.swt.internal.gdk.backend")); - + public final static boolean isGTK4 = isGTK + && System.getProperty("org.eclipse.swt.internal.gtk.version", "").startsWith("4"); /** * The palette used by images. See {@link #getAllPixels(Image)} and {@link #createImage} @@ -400,13 +401,16 @@ public static void processEvents(int timeoutMs, BooleanSupplier breakCondition) long targetTimestamp = System.currentTimeMillis() + timeoutMs; Display display = Display.getCurrent(); while (!breakCondition.getAsBoolean()) { - if (!display.readAndDispatch()) { - if (System.currentTimeMillis() < targetTimestamp) { - Thread.sleep(50); - } else { + while (display.readAndDispatch()) { + if (System.currentTimeMillis() >= targetTimestamp) { return; } } + if (System.currentTimeMillis() < targetTimestamp) { + Thread.sleep(50); + } else { + return; + } } } @@ -583,18 +587,24 @@ public static boolean hasPixelNotMatching(Image image, Color nonMatchingColor, R } public static Path getPath(String fileName, TemporaryFolder tempFolder) { - Path filePath = tempFolder.getRoot().toPath().resolve("image-resources").resolve(Path.of(fileName)); - if (!Files.isRegularFile(filePath)) { + Path path = tempFolder.getRoot().toPath(); + Path filePath = path.resolve("image-resources").resolve(Path.of(fileName)); + return getPath(fileName, filePath); +} + +public static Path getPath(String sourceFilename, Path destinationPath) { + if (!Files.isRegularFile(destinationPath)) { // Extract resource on the classpath to a temporary file to ensure it's // available as plain file, even if this bundle is packed as jar - try (InputStream inStream = SwtTestUtil.class.getResourceAsStream(fileName)) { - assertNotNull(inStream, "InputStream == null for file " + fileName); - Files.createDirectories(filePath.getParent()); - Files.copy(inStream, filePath); + try (InputStream inStream = SwtTestUtil.class.getResourceAsStream(sourceFilename)) { + assertNotNull(inStream, "InputStream == null for file " + sourceFilename); + Files.createDirectories(destinationPath.getParent()); + Files.copy(inStream, destinationPath); } catch (IOException e) { throw new IllegalArgumentException(e); } } - return filePath; + return destinationPath; } + } diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_dnd_Clipboard.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_dnd_Clipboard.java new file mode 100644 index 00000000000..48b0b32625c --- /dev/null +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_dnd_Clipboard.java @@ -0,0 +1,326 @@ +/******************************************************************************* + * Copyright (c) 2000, 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.junit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.ProcessBuilder.Redirect; +import java.nio.file.Files; +import java.nio.file.Path; +import java.rmi.NotBoundException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.BooleanSupplier; + +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.RTFTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import clipboard.ClipboardCommands; + +/** + * Automated Test Suite for class org.eclipse.swt.dnd.Clipboard + * + * @see org.eclipse.swt.dnd.Clipboard + * @see Test_org_eclipse_swt_custom_StyledText StyledText tests as it also does + * some clipboard tests + */ +public class Test_org_eclipse_swt_dnd_Clipboard { + + private static final int REPEAT_COUNT = 3; + @TempDir + static Path tempFolder; + static int uniqueId = 1; + private Display display; + private Shell shell; + private Clipboard clipboard; + private TextTransfer textTransfer; + private RTFTransfer rtfTransfer; + private ClipboardCommands remote; + private Process remoteClipboardProcess; + + @BeforeEach + public void setUp() { + display = Display.getCurrent(); + if (display == null) { + display = Display.getDefault(); + } + + clipboard = new Clipboard(display); + textTransfer = TextTransfer.getInstance(); + rtfTransfer = RTFTransfer.getInstance(); + } + + /** + * TODO remove all uses of sleep and change them to processEvents with the + * suitable conditional, or entirely remove them + */ + private void sleep() throws InterruptedException { + SwtTestUtil.processEvents(1000, null); + } + + /** + * Note: Wayland backend does not allow access to system clipboard from + * non-focussed windows. So we have to create/open and focus a window here so + * that clipboard operations work. + */ + private void openAndFocusShell() throws InterruptedException { + shell = new Shell(display); + shell.open(); + shell.setFocus(); + sleep(); + } + + /** + * Note: Wayland backend does not allow access to system clipboard from + * non-focussed windows. So we have to open and focus remote here so that + * clipboard operations work. + */ + private void openAndFocusRemote() throws Exception { + startRemoteClipboardCommands(); + remote.setFocus(); + remote.waitUntilReady(); + sleep(); + } + + @AfterEach + public void tearDown() throws Exception { + sleep(); + try { + stopRemoteClipboardCommands(); + } finally { + if (clipboard != null) { + clipboard.dispose(); + } + if (shell != null) { + shell.dispose(); + } + SwtTestUtil.processEvents(); + } + } + + private void startRemoteClipboardCommands() throws Exception { + // TODO: Can I get the jar and run it without extracting it? + // TODO: Can I get all the files without having to list them? + List.of( // + "ClipboardTest", // + "ClipboardCommands", // + "ClipboardCommandsImpl", // + "ClipboardTest$LocalHostOnlySocketFactory" // + ).forEach((f) -> { + // extract the files and put them in the temp directory + SwtTestUtil.getPath("/clipboard/" + f + ".class", tempFolder.resolve("clipboard/" + f + ".class")); + }); + + String javaHome = System.getProperty("java.home"); + String javaExe = javaHome + "/bin/java"; + assertTrue(Files.exists(Path.of(javaExe))); + + ProcessBuilder pb = new ProcessBuilder(javaExe, "clipboard.ClipboardTest").directory(tempFolder.toFile()); + pb.inheritIO(); + pb.redirectOutput(Redirect.PIPE); + remoteClipboardProcess = pb.start(); + + // Read server output to find the port + BufferedReader reader = new BufferedReader(new InputStreamReader(remoteClipboardProcess.getInputStream())); + int port = 0; + String line; + // TODO: add a timeout here + while ((line = reader.readLine()) != null) { + if (line.startsWith(ClipboardCommands.PORT_MESSAGE)) { + String[] parts = line.split(":"); + port = Integer.parseInt(parts[1].trim()); + break; + } + } + assertNotEquals(0, port); + Registry reg = LocateRegistry.getRegistry("127.0.0.1", port); + long stopTime = System.currentTimeMillis() + 1000; + do { + try { + remote = (ClipboardCommands) reg.lookup(ClipboardCommands.ID); + break; + } catch (NotBoundException e) { + // try again because the remote app probably hasn't bound yet + } + } while (System.currentTimeMillis() < stopTime); + + // Run a no-op on the Swing event loop so that we know it is idle + // and we can continue startup + remote.waitUntilReady(); + } + + private void stopRemoteClipboardCommands() throws Exception { + try { + if (remote != null) { + remote.stop(); + remote = null; + } + } finally { + if (remoteClipboardProcess != null) { + try { + remoteClipboardProcess.waitFor(1, TimeUnit.SECONDS); + } finally { + remoteClipboardProcess.destroyForcibly(); + remoteClipboardProcess = null; + } + } + } + } + + /** + * Make sure to always copy/paste unique strings - this ensures that tests run + * under {@link RepeatedTest}s don't false pass because of clipboard value on + * previous iteration. + */ + private String getUniqueTestString() { + return "Hello World " + uniqueId++; + } + + /** + * Test that the remote application clipboard works + */ + @Test + public void test_Remote() throws Exception { + System.err.println("Start test_Remote"); + openAndFocusRemote(); + String helloWorld = getUniqueTestString(); + remote.setContents(helloWorld); + assertEquals(helloWorld, remote.getStringContents()); + } + + /** + * This tests set + get on local clipboard. Remote clipboard can have different + * behaviours and has additional tests. + */ + @RepeatedTest(value = REPEAT_COUNT) + public void test_LocalClipboard() throws Exception { + System.err.println("Start test_LocalClipboard"); + openAndFocusShell(); + + String helloWorld = getUniqueTestString(); + clipboard.setContents(new Object[] { helloWorld }, new Transfer[] { textTransfer }); + assertEquals(helloWorld, clipboard.getContents(textTransfer)); + assertNull(clipboard.getContents(rtfTransfer)); + + helloWorld = getUniqueTestString(); + String helloWorldRtf = "{\\rtf1\\b\\i " + helloWorld + "}"; + clipboard.setContents(new Object[] { helloWorld, helloWorldRtf }, new Transfer[] { textTransfer, rtfTransfer }); + assertEquals(helloWorld, clipboard.getContents(textTransfer)); + assertEquals(helloWorldRtf, clipboard.getContents(rtfTransfer)); + + helloWorld = getUniqueTestString(); + helloWorldRtf = "{\\rtf1\\b\\i " + helloWorld + "}"; + clipboard.setContents(new Object[] { helloWorldRtf }, new Transfer[] { rtfTransfer }); + assertNull(clipboard.getContents(textTransfer)); + assertEquals(helloWorldRtf, clipboard.getContents(rtfTransfer)); + } + + @RepeatedTest(value = REPEAT_COUNT) + public void test_setContents() throws Exception { + try { + System.err.println("Start test_setContents"); + openAndFocusShell(); + String helloWorld = getUniqueTestString(); + + clipboard.setContents(new Object[] { helloWorld }, new Transfer[] { textTransfer }); + sleep(); + + openAndFocusRemote(); + SwtTestUtil.processEvents(1000, () -> helloWorld.equals(runOperationInThread(remote::getStringContents))); + String result = runOperationInThread(remote::getStringContents); + assertEquals(helloWorld, result); + } catch (Exception | AssertionError e) { + if (SwtTestUtil.isGTK4 && !SwtTestUtil.isX11) { + // TODO make the code + test stable + throw new RuntimeException( + "This test is really unstable on wayland backend, at least with Ubuntu 25.04", e); + } + throw e; + } + } + + @RepeatedTest(value = REPEAT_COUNT) + public void test_getContents() throws Exception { + System.err.println("Start test_getContents"); + openAndFocusRemote(); + String helloWorld = getUniqueTestString(); + remote.setContents(helloWorld); + + openAndFocusShell(); + SwtTestUtil.processEvents(1000, () -> { + return helloWorld.equals(clipboard.getContents(textTransfer)); + }); + assertEquals(helloWorld, clipboard.getContents(textTransfer)); + } + + @FunctionalInterface + public interface ExceptionalSupplier { + T get() throws Exception; + } + + /** + * When running some operations, such as requesting remote process read the + * clipboard, we need to have the event queue processing otherwise the remote + * won't be able to read our clipboard contribution. + * + * This method starts the supplier in a new thread and runs the event loop until + * the thread completes. + * + * @throws InterruptedException + */ + private T runOperationInThread(ExceptionalSupplier supplier) throws RuntimeException { + Object[] supplierValue = new Object[1]; + Exception[] supplierException = new Exception[1]; + Runnable task = () -> { + try { + supplierValue[0] = supplier.get(); + } catch (Exception e) { + supplierValue[0] = null; + supplierException[0] = e; + } + }; + Thread thread = new Thread(task, this.getClass().getName() + ".runOperationInThread"); + thread.setDaemon(true); + thread.start(); + BooleanSupplier done = () -> !thread.isAlive(); + try { + SwtTestUtil.processEvents(2000, done); + } catch (InterruptedException e) { + throw new RuntimeException("Failed while running thread", e); + } + assertTrue(done.getAsBoolean()); + if (supplierException[0] != null) { + throw new RuntimeException("Failed while running thread", supplierException[0]); + } + @SuppressWarnings("unchecked") + T result = (T) supplierValue[0]; + return result; + } +} diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java index 6257137905c..dccc2589885 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java @@ -458,7 +458,7 @@ public void test_getImeInputMode() { @Test public void test_getLocation() { //Setting location for Windows is not supported in GTK4 - if (isGTK4()) { + if (SwtTestUtil.isGTK4) { return; } shell.setLocation(10,15); @@ -1007,7 +1007,7 @@ public void test_Issue450_NoShellActivateOnSetFocus() { @Override public void test_setLocationLorg_eclipse_swt_graphics_Point() { //Setting location for Windows is not supported in GTK4 - if (isGTK4()) { + if (SwtTestUtil.isGTK4) { return; } super.test_setLocationLorg_eclipse_swt_graphics_Point(); @@ -1016,14 +1016,9 @@ public void test_setLocationLorg_eclipse_swt_graphics_Point() { @Override public void test_setLocationII() { //Setting location for Windows is not supported in GTK4 - if (isGTK4()) { + if (SwtTestUtil.isGTK4) { return; } super.test_setLocationII(); } - -public static boolean isGTK4() { - String gtkVersion = System.getProperty("org.eclipse.swt.internal.gtk.version", ""); - return SwtTestUtil.isGTK && gtkVersion.startsWith("4"); -} } diff --git a/tests/org.eclipse.swt.tests/data/clipboard/ClipboardCommands.java b/tests/org.eclipse.swt.tests/data/clipboard/ClipboardCommands.java new file mode 100644 index 00000000000..97ec90fc0c0 --- /dev/null +++ b/tests/org.eclipse.swt.tests/data/clipboard/ClipboardCommands.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package clipboard; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface ClipboardCommands extends Remote { + String PORT_MESSAGE = "ClipboardCommands Registry Port: "; + String ID = "ClipboardCommands"; + + void stop() throws RemoteException; + + void setContents(String string) throws RemoteException; + + void setFocus() throws RemoteException; + + String getStringContents() throws RemoteException; + + void waitUntilReady() throws RemoteException; +} diff --git a/tests/org.eclipse.swt.tests/data/clipboard/ClipboardCommandsImpl.java b/tests/org.eclipse.swt.tests/data/clipboard/ClipboardCommandsImpl.java new file mode 100644 index 00000000000..75601593af5 --- /dev/null +++ b/tests/org.eclipse.swt.tests/data/clipboard/ClipboardCommandsImpl.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package clipboard; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.lang.reflect.InvocationTargetException; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; +import java.util.Arrays; + +import javax.swing.SwingUtilities; + +public class ClipboardCommandsImpl extends UnicastRemoteObject implements ClipboardCommands { + private static final long serialVersionUID = 330098269086266134L; + private ClipboardTest clipboardTest; + + protected ClipboardCommandsImpl(ClipboardTest clipboardTest) throws RemoteException { + super(); + this.clipboardTest = clipboardTest; + } + + @Override + public void waitUntilReady() throws RemoteException { + invokeAndWait(() -> { + clipboardTest.log("waitUntilReady()"); + }); + } + + @Override + public void stop() throws RemoteException { + invokeAndWait(() -> { + clipboardTest.log("stop()"); + clipboardTest.dispose(); + }); + } + + @Override + public void setContents(String text) throws RemoteException { + invokeAndWait(() -> { + clipboardTest.log("setContents(\"" + text + "\")"); + StringSelection selection = new StringSelection(text); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); + + }); + } + + @Override + public String getStringContents() throws RemoteException { + String[] data = new String[] { null }; + invokeAndWait(() -> { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + try { + data[0] = (String) clipboard.getData(DataFlavor.stringFlavor); + clipboardTest.log("getStringContents() returned " + data[0]); + } catch (Exception e) { + data[0] = null; + DataFlavor[] availableDataFlavors = clipboard.getAvailableDataFlavors(); + clipboardTest.log("getStringContents() threw " + e.toString() + + " and returned null. The clipboard had availableDataFlavors = " + + Arrays.asList(availableDataFlavors)); + } + }); + return data[0]; + } + + @Override + public void setFocus() throws RemoteException { + invokeAndWait(() -> { + clipboardTest.log("setFocus()"); + clipboardTest.requestFocus(); + }); + } + + private void invokeAndWait(Runnable run) throws RemoteException { + try { + SwingUtilities.invokeAndWait(run); + } catch (InvocationTargetException | InterruptedException e) { + throw new RemoteException("Failed to run in Swing", e); + } + } + +} \ No newline at end of file diff --git a/tests/org.eclipse.swt.tests/data/clipboard/ClipboardTest.java b/tests/org.eclipse.swt.tests/data/clipboard/ClipboardTest.java new file mode 100644 index 00000000000..a0ae199d17d --- /dev/null +++ b/tests/org.eclipse.swt.tests/data/clipboard/ClipboardTest.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2000, 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package clipboard; + +import java.awt.BorderLayout; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.RMISocketFactory; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +import org.eclipse.swt.tests.junit.Test_org_eclipse_swt_dnd_Clipboard; + +/** + * Test program used by {@link Test_org_eclipse_swt_dnd_Clipboard}. + * + * + */ +@SuppressWarnings("serial") +public class ClipboardTest extends JFrame { + private static final class LocalHostOnlySocketFactory extends RMISocketFactory { + @Override + public ServerSocket createServerSocket(int port) throws IOException { + return new ServerSocket(port, 50, InetAddress.getLoopbackAddress()); + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + return new Socket(InetAddress.getLoopbackAddress(), port); + } + } + + private static Registry rmiRegistry; + private JTextArea textArea; + private ClipboardCommands commands; + + public ClipboardTest() throws RemoteException { + super("ClipboardTest"); + commands = new ClipboardCommandsImpl(this); + rmiRegistry.rebind(ClipboardCommands.ID, commands); + + + + textArea = new JTextArea(10, 40); + JScrollPane scrollPane = new JScrollPane(textArea); + + JButton copyButton = new JButton("Copy"); + JButton pasteButton = new JButton("Paste"); + + copyButton.addActionListener(e -> { + String text = textArea.getSelectedText(); + if (text != null) { + StringSelection selection = new StringSelection(text); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); + } + }); + + pasteButton.addActionListener(e -> { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + try { + String data = (String) clipboard.getData(DataFlavor.stringFlavor); + textArea.insert(data, textArea.getCaretPosition()); + } catch (Exception ex) { + JOptionPane.showMessageDialog(ClipboardTest.this, "Could not paste from clipboard", "Error", + JOptionPane.ERROR_MESSAGE); + } + }); + + JPanel buttonPanel = new JPanel(); + buttonPanel.add(copyButton); + buttonPanel.add(pasteButton); + + add(scrollPane, BorderLayout.CENTER); + add(buttonPanel, BorderLayout.SOUTH); + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + pack(); + setLocationRelativeTo(null); // Center on screen + setVisible(true); + } + + public void log(String log) { + textArea.insert(log, textArea.getCaretPosition()); + if (!log.endsWith("\n")) { + textArea.insert("\n", textArea.getCaretPosition()); + } + System.err.println(log); + } + + public static void main(String[] args) throws IOException { + System.setProperty("java.rmi.server.hostname", "127.0.0.1"); + + // Make sure RMI is localhost only + RMISocketFactory.setSocketFactory(new LocalHostOnlySocketFactory()); + int chosenPort = getAvailablePort(); + rmiRegistry = LocateRegistry.createRegistry(chosenPort); + System.out.println(ClipboardCommands.PORT_MESSAGE + chosenPort); + + + + SwingUtilities.invokeLater(() -> { + try { + new ClipboardTest(); + } catch (RemoteException e) { + System.err.println("Failed to start ClipboardTest"); + e.printStackTrace(); + System.exit(1); + } + }); + } + + /** + * Because LocateRegistry requires reflection and/or using sun.* packages to get + * the running port, use ServerSocket to get a free port. + */ + private static int getAvailablePort() throws IOException { + try (var ss = new java.net.ServerSocket(0)) { + return ss.getLocalPort(); + } + } +}