From ceff6d3cb81ca0787256f2bf7d7b3bdca280e7ec Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Wed, 17 Jun 2026 20:18:44 +0200 Subject: [PATCH] Initial prototype for taking screenshots with GTK4 #874 Based on the SWT implementation. --- .../org/eclipse/wb/internal/os/linux/GDK.java | 2 +- .../eclipse/wb/internal/os/linux/GObject.java | 22 ++++ .../org/eclipse/wb/internal/os/linux/GTK.java | 2 +- .../wb/internal/os/linux/GtkWidget.java | 14 +-- .../org/eclipse/wb/internal/os/linux/OS.java | 40 ++++++ .../wb/internal/os/linux/OSSupportLinux.java | 3 +- .../wb/internal/os/linux/ScreenshotMaker.java | 26 +++- .../internal/os/linux/cairo/CairoContext.java | 17 +++ .../os/linux/gtk3/GTK3ScreenshotMaker.java | 27 ---- .../wb/internal/os/linux/gtk3/GdkWindow.java | 8 +- .../wb/internal/os/linux/gtk4/GTK4.java | 119 ++++++++++++++++++ .../os/linux/gtk4/GTK4ScreenshotMaker.java | 77 ++++++++++++ .../internal/os/linux/gtk4/GdkPaintable.java | 23 ++++ .../internal/os/linux/gtk4/GdkSnapshot.java | 23 ++++ .../internal/os/linux/gtk4/GskRenderNode.java | 19 +++ .../internal/os/linux/gtk4/GtkPaintable.java | 45 +++++++ .../internal/os/linux/gtk4/GtkSnapshot.java | 21 ++++ 17 files changed, 445 insertions(+), 43 deletions(-) create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GObject.java create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/OS.java create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GTK4.java create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GTK4ScreenshotMaker.java create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GdkPaintable.java create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GdkSnapshot.java create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GskRenderNode.java create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GtkPaintable.java create mode 100644 org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GtkSnapshot.java diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GDK.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GDK.java index f0eba986f..59017fb8a 100644 --- a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GDK.java +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GDK.java @@ -29,7 +29,7 @@ public class GDK extends Native { static { if (isGtk4()) { - GDK = SymbolLookup.libraryLookup("libgdk-4.so.0", Arena.ofAuto()); + GDK = GTK.GTK; } else { GDK = SymbolLookup.libraryLookup("libgdk-3.so.0", Arena.ofAuto()); } diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GObject.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GObject.java new file mode 100644 index 000000000..0912d5f7a --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GObject.java @@ -0,0 +1,22 @@ +package org.eclipse.wb.internal.os.linux; + +import java.lang.foreign.MemorySegment; + +/** + * The base type system and object class + */ +public class GObject { + private final MemorySegment segment; + + protected GObject(long handle) { + this(handle == 0L ? MemorySegment.NULL : MemorySegment.ofAddress(handle)); + } + + protected GObject(MemorySegment segment) { + this.segment = segment; + } + + public MemorySegment segment() { + return segment; + } +} diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GTK.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GTK.java index b888a7c70..76239f783 100644 --- a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GTK.java +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GTK.java @@ -26,7 +26,7 @@ public abstract class GTK extends Native { static { if (isGtk4()) { - GTK = SymbolLookup.libraryLookup("libgtk-4.so.0", Arena.ofAuto()); + GTK = SymbolLookup.libraryLookup("libgtk-4.so.1", Arena.ofAuto()); } else { GTK = SymbolLookup.libraryLookup("libgtk-3.so.0", Arena.ofAuto()); } diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GtkWidget.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GtkWidget.java index fac3dd0d5..e70b9e818 100644 --- a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GtkWidget.java +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/GtkWidget.java @@ -16,33 +16,27 @@ import org.eclipse.swt.widgets.Widget; -import java.lang.foreign.MemorySegment; import java.util.Objects; /** * GtkWidget is the base class all widgets in GTK+ derive from. It manages the * widget lifecycle, states and style. */ -public class GtkWidget { - private final MemorySegment segment; +public class GtkWidget extends GObject { protected GtkWidget(long handle) { - segment = handle == 0L ? MemorySegment.NULL : MemorySegment.ofAddress(handle); - } - - public MemorySegment segment() { - return segment; + super(handle); } @Override public int hashCode() { - return Objects.hash(segment.address()); + return Objects.hash(segment().address()); } @Override public boolean equals(Object o) { if (o instanceof GtkWidget other) { - return segment.address() == other.segment.address(); + return segment().address() == other.segment().address(); } return false; } diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/OS.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/OS.java new file mode 100644 index 000000000..a17a9c4f1 --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/OS.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which 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.wb.internal.os.linux; + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; + +/** + * This class contains native functions for various libraries. + */ +public class OS extends Native { + + protected static final SymbolLookup GOBJECT; + + static { + GOBJECT = SymbolLookup.libraryLookup("libgobject-2.0.so.0", Arena.ofAuto()); + } + + private static class InstanceHolder { + private static final MethodHandle g_object_unref = createHandle(GOBJECT, "g_object_unref", + FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)); + } + + public static void g_object_unref(GObject object) { + runSafe(() -> InstanceHolder.g_object_unref.invoke(object.segment())); + } +} diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/OSSupportLinux.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/OSSupportLinux.java index 5501b4862..4eb854f5c 100644 --- a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/OSSupportLinux.java +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/OSSupportLinux.java @@ -17,6 +17,7 @@ import org.eclipse.wb.internal.os.linux.gtk3.GTK3; import org.eclipse.wb.internal.os.linux.gtk3.GTK3ScreenshotMaker; import org.eclipse.wb.internal.os.linux.gtk3.GtkWindow; +import org.eclipse.wb.internal.os.linux.gtk4.GTK4ScreenshotMaker; import org.eclipse.wb.internal.swt.VisualDataMockupProvider; import org.eclipse.wb.os.OSSupport; @@ -44,7 +45,7 @@ public final class OSSupportLinux extends OSSupport { private static Version SWT_VERSION_3_126 = new Version(3, 126, 0); private final VisualDataMockupProvider mockupProvider = new VisualDataMockupProvider(); - private final ScreenshotMaker screenshotMaker = new GTK3ScreenshotMaker(); + private final ScreenshotMaker screenshotMaker = GTK.isGtk4() ? new GTK4ScreenshotMaker() : new GTK3ScreenshotMaker(); private Shell m_eclipseShell; //////////////////////////////////////////////////////////////////////////// diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/ScreenshotMaker.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/ScreenshotMaker.java index 9ae5e4ded..3634b1f29 100644 --- a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/ScreenshotMaker.java +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/ScreenshotMaker.java @@ -26,6 +26,7 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Widget; import java.lang.foreign.MemorySegment; import java.util.HashMap; @@ -148,7 +149,30 @@ private void makeShots0(final Shell shell) { * model. Can be null. * @return the GdkPixmap* or cairo_surface_t* of {@link Shell}. */ - protected abstract Image makeShot(Shell shell, BiConsumer callback); + protected final Image makeShot(Shell shell, BiConsumer callback) { + return traverse(shell, callback); + } + + private Image traverse(Widget widget, BiConsumer callback) { + Image image = getImageSurface(GtkWidget.from(widget), callback); + if (image == null) { + return null; + } + if (widget instanceof Composite composite) { + for (Control childWidget : composite.getChildren()) { + Image childImage = traverse(childWidget, callback); + if (childImage == null) { + continue; + } + if (callback == null) { + childImage.dispose(); + } + } + } + return image; + } + + protected abstract Image getImageSurface(GtkWidget widget, BiConsumer callback); private boolean bindImage(final Control control, final Image image) { if (control.getData(OSSupport.WBP_NEED_IMAGE) != null && control.getData(OSSupport.WBP_IMAGE) == null) { diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/cairo/CairoContext.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/cairo/CairoContext.java index 6d35703dc..84e03daa0 100644 --- a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/cairo/CairoContext.java +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/cairo/CairoContext.java @@ -12,6 +12,10 @@ *******************************************************************************/ package org.eclipse.wb.internal.os.linux.cairo; +import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils; + +import org.eclipse.swt.graphics.GC; + import java.lang.foreign.MemorySegment; /** @@ -22,5 +26,18 @@ * and all drawing with cairo is always done to a cairo_t object. */ public record CairoContext(MemorySegment segment) { + /** + * Creates a new CairoContext instance associated with the GC object. + * + * @param gc The context to paint on. + * @return The Cairo context backed by the given GC. + */ + public static CairoContext from(GC gc) { + long handle = getHandleValue(gc, "handle"); + return new CairoContext(MemorySegment.ofAddress(handle)); + } + private static long getHandleValue(GC gc, String fieldName) { + return ReflectionUtils.getFieldLong(gc, fieldName); + } } diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk3/GTK3ScreenshotMaker.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk3/GTK3ScreenshotMaker.java index 615532eab..fbb35b445 100644 --- a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk3/GTK3ScreenshotMaker.java +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk3/GTK3ScreenshotMaker.java @@ -27,10 +27,6 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Widget; import java.util.function.BiConsumer; @@ -40,29 +36,6 @@ public class GTK3ScreenshotMaker extends ScreenshotMaker { @Override - protected Image makeShot(Shell shell, BiConsumer callback) { - return traverse(shell, callback); - } - - private Image traverse(Widget widget, BiConsumer callback) { - Image image = getImageSurface(GtkWidget.from(widget), callback); - if (image == null) { - return null; - } - if (widget instanceof Composite composite) { - for (Control childWidget : composite.getChildren()) { - Image childImage = traverse(childWidget, callback); - if (childImage == null) { - continue; - } - if (callback == null) { - childImage.dispose(); - } - } - } - return image; - } - protected Image getImageSurface(GtkWidget widget, BiConsumer callback) { GdkWindow window = GTK3.gtk_widget_get_window(widget); if (!GDK3.gdk_window_is_visible(window)) { diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk3/GdkWindow.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk3/GdkWindow.java index 38392d28d..2a8fad4e5 100644 --- a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk3/GdkWindow.java +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk3/GdkWindow.java @@ -12,11 +12,15 @@ *******************************************************************************/ package org.eclipse.wb.internal.os.linux.gtk3; +import org.eclipse.wb.internal.os.linux.GObject; + import java.lang.foreign.MemorySegment; /** * A GDK window. */ -public record GdkWindow(MemorySegment segment) { - +public class GdkWindow extends GObject { + protected GdkWindow(MemorySegment segment) { + super(segment); + } } diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GTK4.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GTK4.java new file mode 100644 index 000000000..4d51f33a2 --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GTK4.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which 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.wb.internal.os.linux.gtk4; + +import org.eclipse.wb.internal.os.linux.GTK; +import org.eclipse.wb.internal.os.linux.GtkWidget; +import org.eclipse.wb.internal.os.linux.cairo.CairoContext; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; + +/** + * The GTK toolkit compatible with GTK 4.x + */ +public class GTK4 extends GTK { + + private static class InstanceHolder { + private static final MethodHandle gtk_widget_get_height = createHandle(GTK, "gtk_widget_get_height", + FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS)); + + private static final MethodHandle gtk_widget_get_width = createHandle(GTK, "gtk_widget_get_width", + FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS)); + + private static final MethodHandle gtk_widget_paintable_new = createHandle(GTK, "gtk_widget_paintable_new", + FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS)); + + private static final MethodHandle gtk_snapshot_new = createHandle(GTK, "gtk_snapshot_new", + FunctionDescriptor.of(ValueLayout.ADDRESS)); + + private static final MethodHandle gtk_snapshot_free_to_node = createHandle(GTK, "gtk_snapshot_free_to_node", + FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS)); + + private static final MethodHandle gsk_render_node_draw = createHandle(GTK, "gsk_render_node_draw", + FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS)); + + private static final MethodHandle gsk_render_node_unref = createHandle(GTK, "gsk_render_node_unref", + FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)); + + private static final MethodHandle gdk_paintable_snapshot = createHandle(GTK, "gdk_paintable_snapshot", + FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_DOUBLE, ValueLayout.JAVA_DOUBLE)); + } + + /** + * Returns the content height of the widget. This function returns the height + * passed to its size-allocate implementation, which is the height you should be + * using in Gtk.WidgetClass.snapshot. + * + * For pointer events, see gtk_widget_contains(). + * + * To learn more about widget sizes, see the coordinate system . + * + * @param widget + * @return The height of {@code widget}. + */ + public static int gtk_widget_get_height(GtkWidget widget) { + return (int) callSafe(() -> InstanceHolder.gtk_widget_get_height.invoke(widget.segment())); + } + + /** + * Returns the content width of the widget. This function returns the width + * passed to its size-allocate implementation, which is the width you should be + * using in Gtk.WidgetClass.snapshot. + * + * For pointer events, see gtk_widget_contains(). + * + * To learn more about widget sizes, see the coordinate system . + * + * @param widget + * @return The width of {@code widget}. + */ + public static int gtk_widget_get_width(GtkWidget widget) { + return (int) callSafe(() -> InstanceHolder.gtk_widget_get_width.invoke(widget.segment())); + } + + public static GtkPaintable gtk_widget_paintable_new(GtkWidget widget) { + MemorySegment segment = (MemorySegment) callSafe(() -> InstanceHolder.gtk_widget_paintable_new.invoke(widget.segment())); + return new GtkPaintable(segment); + } + + public static GtkSnapshot gtk_snapshot_new() { + MemorySegment segment = (MemorySegment) callSafe(() -> InstanceHolder.gtk_snapshot_new.invoke()); + return new GtkSnapshot(segment); + } + + public static GskRenderNode gtk_snapshot_free_to_node(GtkSnapshot snapshot) { + MemorySegment segment = (MemorySegment) callSafe(() -> InstanceHolder.gtk_snapshot_free_to_node.invoke(snapshot.segment())); + return new GskRenderNode(segment); + } + + public static void gsk_render_node_draw(GskRenderNode node, CairoContext cr) { + runSafe(() -> InstanceHolder.gsk_render_node_draw.invoke(node.segment(), cr.segment())); + } + + public static void gsk_render_node_unref(GskRenderNode node) { + runSafe(() -> InstanceHolder.gsk_render_node_unref.invoke(node.segment())); + } + + public static void gdk_paintable_snapshot(GdkPaintable paintable, GdkSnapshot snapshot, double width, double height) { + runSafe(() -> InstanceHolder.gdk_paintable_snapshot.invoke(paintable.segment(), snapshot.segment(), width, height)); + } +} diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GTK4ScreenshotMaker.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GTK4ScreenshotMaker.java new file mode 100644 index 000000000..036706f52 --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GTK4ScreenshotMaker.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which 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.wb.internal.os.linux.gtk4; + +import org.eclipse.wb.internal.os.linux.GtkWidget; +import org.eclipse.wb.internal.os.linux.OS; +import org.eclipse.wb.internal.os.linux.ScreenshotMaker; +import org.eclipse.wb.internal.os.linux.cairo.CairoContext; + +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +import java.lang.foreign.MemorySegment; +import java.util.function.BiConsumer; + +public class GTK4ScreenshotMaker extends ScreenshotMaker { + + @Override + protected Image getImageSurface(GtkWidget widget, BiConsumer callback) { + GtkPaintable widgetPaintable = GTK4.gtk_widget_paintable_new(widget); + if (MemorySegment.NULL.equals(widgetPaintable.segment())) { + return null; + } + + int width = GTK4.gtk_widget_get_width(widget); + int height = GTK4.gtk_widget_get_height(widget); + + Image image = new Image(Display.getCurrent(), width, height); + + GtkSnapshot snapshot = GTK4.gtk_snapshot_new(); + if (MemorySegment.NULL.equals(snapshot.segment())) { + return image; + } + + GC gc = new GC(image); + + try { + GTK4.gdk_paintable_snapshot(widgetPaintable, snapshot, width, height); + + GskRenderNode renderNode = GTK4.gtk_snapshot_free_to_node(snapshot); + snapshot = null; // freed by gtk_snapshot_free_to_node + + if (MemorySegment.NULL.equals(renderNode.segment())) { + return image; + } + + try { + GTK4.gsk_render_node_draw(renderNode, CairoContext.from(gc)); + GTK4.gsk_render_node_unref(renderNode); + } finally { + gc.dispose(); + } + + return image; + } finally { + gc.dispose(); + + callback.accept(widget, image); + if (snapshot != null) { + OS.g_object_unref(snapshot); + } + + OS.g_object_unref(widgetPaintable); + } + } +} diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GdkPaintable.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GdkPaintable.java new file mode 100644 index 000000000..def76143f --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GdkPaintable.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which 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.wb.internal.os.linux.gtk4; + +import org.eclipse.wb.internal.os.linux.GObject; + +import java.lang.foreign.MemorySegment; + +public class GdkPaintable extends GObject { + public GdkPaintable(MemorySegment segment) { + super(segment); + } +} diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GdkSnapshot.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GdkSnapshot.java new file mode 100644 index 000000000..4adb3a0cb --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GdkSnapshot.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which 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.wb.internal.os.linux.gtk4; + +import org.eclipse.wb.internal.os.linux.GObject; + +import java.lang.foreign.MemorySegment; + +public class GdkSnapshot extends GObject { + public GdkSnapshot(MemorySegment segment) { + super(segment); + } +} diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GskRenderNode.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GskRenderNode.java new file mode 100644 index 000000000..02a8f3508 --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GskRenderNode.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which 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.wb.internal.os.linux.gtk4; + +import java.lang.foreign.MemorySegment; + +public record GskRenderNode(MemorySegment segment) { + +} diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GtkPaintable.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GtkPaintable.java new file mode 100644 index 000000000..6daf01812 --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GtkPaintable.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which 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.wb.internal.os.linux.gtk4; + +import java.lang.foreign.MemorySegment; + +/** + * A {@code GdkPaintable} that displays the contents of a widget. + * + * {@code GtkWidgetPaintable} will also take care of the widget not being in a + * state where it can be drawn (like when it isn’t shown) and just draw nothing + * or where it does not have a size (like when it is hidden) and report no size + * in that case. + * + * Of course, {@code GtkWidgetPaintable} allows you to monitor widgets for size + * changes by emitting the GdkPaintable::invalidate-size + * signal whenever the size of the widget changes as well as for visual changes + * by emitting the GdkPaintable::invalidate-contents + * signal whenever the widget changes. + * + * You can use a {@code GtkWidgetPaintable} everywhere a {@code GdkPaintable} is + * allowed, including using it on a {@code GtkPicture} (or one of its parents) + * that it was set on itself via gtk_picture_set_paintable(). The paintable will + * take care of recursion when this happens. If you do this however, ensure that + * the GtkPicture:can-shrink property is + * set to {@code TRUE} or you might end up with an infinitely growing widget. + * + */ +public class GtkPaintable extends GdkPaintable { + public GtkPaintable(MemorySegment segment) { + super(segment); + } +} diff --git a/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GtkSnapshot.java b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GtkSnapshot.java new file mode 100644 index 000000000..66112130d --- /dev/null +++ b/org.eclipse.wb.os.linux/src_java24/org/eclipse/wb/internal/os/linux/gtk4/GtkSnapshot.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which 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.wb.internal.os.linux.gtk4; + +import java.lang.foreign.MemorySegment; + +public class GtkSnapshot extends GdkSnapshot { + public GtkSnapshot(MemorySegment segment) { + super(segment); + } +}