Skip to content

Commit 291d6fe

Browse files
committed
PoC - Use Foreign Function & Memory API for GTK3 OS Support
1 parent 2a992fe commit 291d6fe

File tree

22 files changed

+1335
-2
lines changed

22 files changed

+1335
-2
lines changed

org.eclipse.wb.os.linux/.classpath

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<classpath>
3-
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/>
3+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-24"/>
44
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
55
<classpathentry kind="src" path="src"/>
6+
<classpathentry kind="src" path="src_java24">
7+
<attributes>
8+
<attribute name="release" value="24"/>
9+
</attributes>
10+
</classpathentry>
611
<classpathentry kind="output" path="bin"/>
712
</classpath>

org.eclipse.wb.os.linux/META-INF/MANIFEST.MF

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Bundle-ActivationPolicy: lazy
1818
Bundle-Localization: plugin
1919
Import-Package: org.apache.commons.io;version="[2.16.1,3.0.0)",
2020
org.apache.commons.lang3;version="[3.14.0,4.0.0)",
21+
org.apache.commons.lang3.function;version="[3.14.0,4.0.0)",
2122
org.eclipse.wb.os
2223
Automatic-Module-Name: org.eclipse.wb.os.linux
2324
Provide-Capability: wbp;type=os
25+
Multi-Release: true

org.eclipse.wb.os.linux/build.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
source.. = src/
1+
source.. = src/,\
2+
src_java24/
23
output.. = bin/
34
bin.includes = META-INF/,\
45
.,\
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Patrick Ziegler and others.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* https://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Patrick Ziegler - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.wb.internal.os.linux;
14+
15+
import java.lang.foreign.Arena;
16+
import java.lang.foreign.MemoryLayout;
17+
import java.lang.foreign.MemorySegment;
18+
import java.lang.foreign.StructLayout;
19+
import java.lang.foreign.ValueLayout;
20+
21+
/**
22+
* A GdkRectangle data type for representing rectangles.
23+
*
24+
* GdkRectangle is identical to cairo_rectangle_t. Together with Cairo’s
25+
* cairo_region_t data type, these are the central types for representing sets
26+
* of pixels.
27+
*
28+
* The intersection of two rectangles can be computed with
29+
* gdk_rectangle_intersect(); to find the union of two rectangles use
30+
* gdk_rectangle_union().
31+
*
32+
* The cairo_region_t type provided by Cairo is usually used for managing
33+
* non-rectangular clipping of graphical operations.
34+
*
35+
* The Graphene library has a number of other data types for regions and volumes
36+
* in 2D and 3D.
37+
*/
38+
public sealed class GdkRectangle permits GtkAllocation {
39+
private static final StructLayout LAYOUT = MemoryLayout.structLayout( //
40+
ValueLayout.JAVA_INT.withName("x"), //
41+
ValueLayout.JAVA_INT.withName("y"), //
42+
ValueLayout.JAVA_INT.withName("width"), //
43+
ValueLayout.JAVA_INT.withName("height"));
44+
45+
private final MemorySegment segment;
46+
47+
public GdkRectangle(Arena arena) {
48+
segment = arena.allocate(LAYOUT);
49+
}
50+
51+
public final int x() {
52+
return segment.get(ValueLayout.JAVA_INT, 0);
53+
}
54+
55+
public final int y() {
56+
return segment.get(ValueLayout.JAVA_INT, 4);
57+
}
58+
59+
public final int width() {
60+
return segment.get(ValueLayout.JAVA_INT, 8);
61+
}
62+
63+
public final int height() {
64+
return segment.get(ValueLayout.JAVA_INT, 12);
65+
}
66+
67+
public final MemorySegment segment() {
68+
return segment;
69+
}
70+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Patrick Ziegler and others.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* https://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Patrick Ziegler - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.wb.internal.os.linux;
14+
15+
import java.lang.foreign.Arena;
16+
17+
/**
18+
* A GtkAllocation-struct of a widget represents region which has been allocated
19+
* to the widget by its parent. It is a subregion of its parents allocation.
20+
*/
21+
public final class GtkAllocation extends GdkRectangle {
22+
public GtkAllocation(Arena arena) {
23+
super(arena);
24+
}
25+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Patrick Ziegler and others.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* https://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Patrick Ziegler - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.wb.internal.os.linux;
14+
15+
import org.eclipse.wb.os.OSRuntimeException;
16+
17+
/**
18+
* Wrapper for all exceptions thrown while accessing native code.
19+
*/
20+
public class GtkRuntimeException extends OSRuntimeException {
21+
private static final long serialVersionUID = 1L;
22+
23+
public GtkRuntimeException(Throwable t) {
24+
super(t);
25+
}
26+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Patrick Ziegler and others.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* https://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Patrick Ziegler - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.wb.internal.os.linux;
14+
15+
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
16+
17+
import org.eclipse.swt.widgets.Shell;
18+
import org.eclipse.swt.widgets.Widget;
19+
20+
/**
21+
* GtkWidget is the base class all widgets in GTK+ derive from. It manages the
22+
* widget lifecycle, states and style.
23+
*/
24+
public record GtkWidget(long handle) {
25+
26+
public GtkWidget(Widget widget) {
27+
this(getHandle(widget));
28+
}
29+
30+
/**
31+
* @return the handle value of the {@link Widget} using reflection.
32+
*/
33+
private static long getHandle(Widget widget) {
34+
long widgetHandle = getHandleValue(widget, "fixedHandle");
35+
if (widgetHandle == 0) {
36+
// may be null, roll back to "handle"
37+
if (widget instanceof Shell) {
38+
widgetHandle = getHandleValue(widget, "shellHandle");
39+
} else {
40+
widgetHandle = getHandleValue(widget, "handle");
41+
}
42+
}
43+
return widgetHandle;
44+
}
45+
46+
/**
47+
* @return the widget as native pointer for native handles. Note: returns 0 if
48+
* handle cannot be obtained.
49+
*/
50+
private static long getHandleValue(Object widget, String fieldName) {
51+
if (ReflectionUtils.getFieldObject(widget, fieldName) instanceof Long longValue) {
52+
return longValue;
53+
}
54+
// field might be shadowed (e.g. in ImageBasedFrame)
55+
return 0L;
56+
}
57+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Patrick Ziegler and others.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* https://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Patrick Ziegler - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.wb.internal.os.linux;
14+
15+
import org.apache.commons.lang3.function.FailableRunnable;
16+
import org.apache.commons.lang3.function.FailableSupplier;
17+
18+
import java.lang.foreign.FunctionDescriptor;
19+
import java.lang.foreign.Linker;
20+
import java.lang.foreign.MemorySegment;
21+
import java.lang.foreign.SymbolLookup;
22+
import java.lang.invoke.MethodHandle;
23+
24+
public class Native {
25+
26+
protected static class NativeHolder {
27+
private static final Linker LINKER = Linker.nativeLinker();
28+
29+
protected static MethodHandle createHandle(SymbolLookup sl, String name, FunctionDescriptor descriptor) {
30+
MemorySegment symbol = sl.find(name).orElseThrow(UnsatisfiedLinkError::new);
31+
return LINKER.downcallHandle(symbol, descriptor);
32+
}
33+
}
34+
35+
protected static Object callSafe(FailableSupplier<Object, Throwable> s) {
36+
try {
37+
return s.get();
38+
} catch (Error e) {
39+
throw e;
40+
} catch (Throwable t) {
41+
throw new GtkRuntimeException(t);
42+
}
43+
}
44+
45+
protected static void runSafe(FailableRunnable<Throwable> r) {
46+
try {
47+
r.run();
48+
} catch (Error e) {
49+
throw e;
50+
} catch (Throwable t) {
51+
throw new GtkRuntimeException(t);
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)