Skip to content

Commit

Permalink
Merge pull request #102 from jwharm/development
Browse files Browse the repository at this point in the history
Merge 0.10.1 changes to Main
  • Loading branch information
jwharm authored Jun 1, 2024
2 parents 177ac24 + 9235bb6 commit 0441999
Show file tree
Hide file tree
Showing 11 changed files with 457 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dependencies {
}

group = 'io.github.jwharm.javagi'
version = '0.10.0'
version = '0.10.1'

java {
if (! System.getenv('CI')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,15 @@ private MethodSpec parentAccessor() {

return MethodSpec.methodBuilder("asParent")
.addJavadoc("""
Returns this instance as if it were its parent type. This is mostly
synonymous to the Java {@code super} keyword, but will set the native
typeclass function pointers to the parent type. When overriding a native
virtual method in Java, "chaining up" with {@code super.methodName()}
doesn't work, because it invokes the overridden function pointer again.
To chain up, call {@code asParent().methodName()}. This will call the
native function pointer of this virtual method in the typeclass of the
parent type.
""")
Returns this instance as if it were its parent type. This is mostly
synonymous to the Java {@code super} keyword, but will set the native
typeclass function pointers to the parent type. When overriding a native
virtual method in Java, "chaining up" with {@code super.methodName()}
doesn't work, because it invokes the overridden function pointer again.
To chain up, call {@code asParent().methodName()}. This will call the
native function pointer of this virtual method in the typeclass of the
parent type.
""")
.addModifiers(Modifier.PROTECTED)
.returns(cls.typeName())
.addStatement("$T _parent = new $T(handle())", cls.typeName(), className)
Expand All @@ -153,10 +153,11 @@ protected MethodSpec memoryAddressConstructor() {
.addModifiers(Modifier.PUBLIC)
.addJavadoc("""
Create a $L proxy instance for the provided memory address.
@param address the memory address of the native object
""", name())
.addParameter(MemorySegment.class, "address")
.addStatement("super(address == null ? null : $T.reinterpret(address, getMemoryLayout().byteSize()))",
.addStatement("super($T.reinterpret(address, getMemoryLayout().byteSize()))",
ClassNames.INTEROP);

/*
Expand All @@ -181,10 +182,10 @@ protected MethodSpec memoryAddressConstructor() {
protected MethodSpec paramSpecGetTypeMethod() {
return MethodSpec.methodBuilder("getType")
.addJavadoc("""
Get the GType of the $L class
@return always {@link $T#PARAM}
""", cls.cType(), ClassNames.TYPES)
Get the GType of the $L class
@return always {@link $T#PARAM}
""", cls.cType(), ClassNames.TYPES)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(ClassNames.GTYPE)
.addStatement("return $T.PARAM", ClassNames.TYPES)
Expand All @@ -194,11 +195,11 @@ protected MethodSpec paramSpecGetTypeMethod() {
private MethodSpec gobjectConstructor() {
return MethodSpec.methodBuilder("newInstance")
.addJavadoc("""
Creates a new GObject instance of the provided GType.
@param objectType the GType of the new GObject
@return the newly created GObject instance
""")
Creates a new GObject instance of the provided GType.
@param objectType the GType of the new GObject
@return the newly created GObject instance
""")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(TypeVariableName.get("T", ClassNames.GOBJECT))
.returns(TypeVariableName.get("T"))
Expand All @@ -213,15 +214,15 @@ private MethodSpec gobjectConstructor() {
private MethodSpec gobjectConstructorVarargs() {
return MethodSpec.methodBuilder("newInstance")
.addJavadoc("""
Creates a new GObject instance of the provided GType and with the
provided property values.
@param objectType the GType of the new GObject
@param propertyNamesAndValues pairs of property names and values
(Strings and Objects)
@return the newly created GObject instance
@throws IllegalArgumentException invalid property name
""")
Creates a new GObject instance of the provided GType and with the
provided property values.
@param objectType the GType of the new GObject
@param propertyNamesAndValues pairs of property names and values
(Strings and Objects)
@return the newly created GObject instance
@throws IllegalArgumentException invalid property name
""")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(TypeVariableName.get("T", ClassNames.GOBJECT))
.returns(TypeVariableName.get("T"))
Expand All @@ -236,12 +237,12 @@ private MethodSpec gobjectConstructorVarargs() {
private MethodSpec gobjectGetProperty() {
return MethodSpec.methodBuilder("getProperty")
.addJavadoc("""
Get a property of an object.
@param propertyName the name of the property to get
@return the property value
@throws IllegalArgumentException invalid property name
""")
Get a property of an object.
@param propertyName the name of the property to get
@return the property value
@throws IllegalArgumentException invalid property name
""")
.addModifiers(Modifier.PUBLIC)
.returns(Object.class)
.addParameter(String.class, "propertyName")
Expand All @@ -253,12 +254,12 @@ private MethodSpec gobjectGetProperty() {
private MethodSpec gobjectSetProperty() {
return MethodSpec.methodBuilder("setProperty")
.addJavadoc("""
Set a property of an object.
@param propertyName the name of the property to set
@param value the new property value
@throws IllegalArgumentException invalid property name
""")
Set a property of an object.
@param propertyName the name of the property to set
@param value the new property value
@throws IllegalArgumentException invalid property name
""")
.addModifiers(Modifier.PUBLIC)
.addParameter(String.class, "propertyName")
.addParameter(Object.class, "value")
Expand All @@ -270,14 +271,14 @@ private MethodSpec gobjectSetProperty() {
private MethodSpec gobjectConnect() {
return MethodSpec.methodBuilder("connect")
.addJavadoc("""
Connect a callback to a signal for this object. The handler will be
called before the default handler of the signal.
@param detailedSignal a string of the form "signal-name::detail"
@param callback the callback to connect
@return a SignalConnection object to track, block and disconnect the
signal connection
""")
Connect a callback to a signal for this object. The handler will be
called before the default handler of the signal.
@param detailedSignal a string of the form "signal-name::detail"
@param callback the callback to connect
@return a SignalConnection object to track, block and disconnect the
signal connection
""")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(TypeVariableName.get("T"))
.returns(ClassNames.SIGNAL_CONNECTION)
Expand All @@ -290,15 +291,15 @@ private MethodSpec gobjectConnect() {
private MethodSpec gobjectConnectAfter() {
return MethodSpec.methodBuilder("connect")
.addJavadoc("""
Connect a callback to a signal for this object.
@param detailedSignal a string of the form "signal-name::detail"
@param callback the callback to connect
@param after whether the handler should be called before or
after the default handler of the signal
@return a SignalConnection object to track, block and disconnect the
signal connection
""")
Connect a callback to a signal for this object.
@param detailedSignal a string of the form "signal-name::detail"
@param callback the callback to connect
@param after whether the handler should be called before or
after the default handler of the signal
@return a SignalConnection object to track, block and disconnect the
signal connection
""")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(TypeVariableName.get("T"))
.returns(ClassNames.SIGNAL_CONNECTION)
Expand All @@ -317,15 +318,15 @@ private MethodSpec gobjectConnectAfter() {
private MethodSpec gobjectEmit() {
return MethodSpec.methodBuilder("emit")
.addJavadoc("""
Emits a signal from this object.
@param detailedSignal a string of the form "signal-name::detail"
@param params the parameters to emit for this signal
@return the return value of the signal, or {@code null} if the signal
has no return value
@throws IllegalArgumentException if a signal with this name is not found
for the object
""")
Emits a signal from this object.
@param detailedSignal a string of the form "signal-name::detail"
@param params the parameters to emit for this signal
@return the return value of the signal, or {@code null} if the signal
has no return value
@throws IllegalArgumentException if a signal with this name is not found
for the object
""")
.addModifiers(Modifier.PUBLIC)
.returns(Object.class)
.addParameter(String.class, "detailedSignal")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ protected MethodSpec memoryAddressConstructor() {
MethodSpec.Builder builder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addJavadoc("""
Create a $L proxy instance for the provided memory address.
@param address the memory address of the native object
""", name())
Create a $L proxy instance for the provided memory address.
@param address the memory address of the native object
""", name())
.addParameter(MemorySegment.class, "address");

if (rt instanceof Record rec && rec.isOpaque()
Expand Down Expand Up @@ -179,7 +179,7 @@ private TypeName getInterfaceSuperclass(Interface i) {
if (target instanceof Class)
return target.typeName();
}
return ClassNames.TYPE_INSTANCE;
return ClassNames.GOBJECT;
}

public boolean hasDowncallHandles() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ boolean checkNull() {
|| target instanceof FlaggedType));
}

String doFree() {
return switch(v) {
case Parameter p when p.transferOwnership() == TransferOwnership.FULL -> "true";
case ReturnValue rv when rv.transferOwnership() == TransferOwnership.FULL -> "true";
default -> "false";
};
}

TypeName getType() {
return getType(true);
}
Expand Down Expand Up @@ -261,8 +269,12 @@ PartialStatement marshalNativeToJava(String identifier, boolean upcall) {
return marshalNativeToJava(type, identifier, upcall);
}

if (array != null && array.anyType() instanceof Array)
return PartialStatement.of("null /* unsupported */");
if (array != null && array.anyType() instanceof Array inner
&& inner.anyType() instanceof Type t
&& t.isString())
return PartialStatement.of(
"$interop:T.getStrvArrayFrom(" + identifier + ", " + doFree() + ")",
"interop", ClassNames.INTEROP);

if (array != null && array.anyType() instanceof Type arrayType)
return marshalNativeToJavaArray(
Expand All @@ -277,12 +289,7 @@ PartialStatement marshalNativeToJava(String identifier, boolean upcall) {
PartialStatement marshalNativeToJava(Type type,
String identifier,
boolean upcall) {
String free = switch(v) {
case Parameter p when p.transferOwnership() == TransferOwnership.FULL -> "true";
case ReturnValue rv when rv.transferOwnership() == TransferOwnership.FULL -> "true";
default -> "false";
};

String free = doFree();
String targetTypeTag = target == null ? null : type.toTypeTag();

boolean isTypeClass = target instanceof Record
Expand Down Expand Up @@ -376,12 +383,7 @@ PartialStatement marshalNativeToJava(Type type,
private PartialStatement marshalNativeToJavaArray(Type type,
String size,
String identifier) {
String free = switch(v) {
case Parameter p when p.transferOwnership() == TransferOwnership.FULL -> "true";
case ReturnValue rv when rv.transferOwnership() == TransferOwnership.FULL -> "true";
default -> "false";
};

String free = doFree();
RegisteredType target = type.get();
String targetTypeTag = target != null ? type.toTypeTag() : null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ public GirElement patch(GirElement element, String namespace) {
return r;
}

/*
* g_strfreev is nicely specified in the Gir file to take an array
* of Strings. However, this makes Java-GI generate code to allocate
* a new memory segment from a Java String[] parameter. So we patch
* it to expect a pointer (a MemorySegment parameter in Java).
*/
if (element instanceof Function f
&& "g_strfreev".equals(f.callableAttrs().cIdentifier())) {
Parameter current = f.parameters().parameters().getFirst();
Parameter replacement = current.withChildren(
current.infoElements().doc(),
new Type(Map.of("name", "gpointer", "c:type", "gpointer"),
Collections.emptyList()));
return f.withChildren(
f.infoElements().doc(),
f.infoElements().sourcePosition(),
f.returnValue(),
f.parameters().withChildren(replacement));
}

/*
* GLib.List and GLib.SList are not generated from the gir data.
* Java-GI provides custom List and SList classes that implement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public static String toJavaBaseType(String name) {
case "gshort", "gushort", "gint16", "guint16" -> "short";
case "gint", "guint", "gint32", "guint32", "gunichar" -> "int";
case "gint64", "gssize", "gsize", "goffset", "guint64", "gintptr",
"guintptr", "glong", "gulong" -> "long";
"guintptr", "glong", "gulong", "time_t" -> "long";
case "gdouble", "long double" -> "double";
case "gfloat" -> "float";
case "none" -> "void";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.github.jwharm.javagi.test.gio;

import org.gnome.gio.DesktopAppInfo;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
* Get a String[][] array from a Gio function, and check that it contains
* usable data.
*/
public class StrvArrayTest {

@Test
public void testStrvArrayToJava() {
String[][] array = DesktopAppInfo.search("gnome");
assertNotNull(array);
String result = "";
for (String[] inner : array) {
assertNotNull(inner);
for (String str : inner) {
if (str.contains("org.gnome"))
result = str;
}
}
assertNotEquals("", result);
}
}
Loading

0 comments on commit 0441999

Please sign in to comment.