From 27b016cff2f695150c0e6d416bfe766c864fc32b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=8A?= =?UTF-8?q?=D1=80=20=D0=9A=D1=83=D1=80=D1=82=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Wed, 25 Feb 2026 14:53:46 +0200 Subject: [PATCH] [Gtk4] Implement Control.print Implementation of this method had no port to Gtk 4 api and was causing troubles by calling into no-longer existing 3.x APIs --- .../Eclipse SWT PI/gtk/library/gtk4.c | 66 +++++++++++++++++++ .../Eclipse SWT PI/gtk/library/gtk4_stats.h | 6 ++ .../org/eclipse/swt/internal/gtk4/GTK4.java | 28 ++++++++ .../gtk/org/eclipse/swt/widgets/Control.java | 60 +++++++++++++---- 4 files changed, 148 insertions(+), 12 deletions(-) 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 92f105cd0c6..2947ce2b1b7 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 @@ -601,6 +601,16 @@ JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1serializer_1set_1task_1data) } #endif +#ifndef NO_gdk_1paintable_1snapshot +JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1paintable_1snapshot) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2, jint arg3) +{ + GTK4_NATIVE_ENTER(env, that, gdk_1paintable_1snapshot_FUNC); + gdk_paintable_snapshot((GdkPaintable *)arg0, (GdkSnapshot *)arg1, (double)arg2, (double)arg3); + GTK4_NATIVE_EXIT(env, that, gdk_1paintable_1snapshot_FUNC); +} +#endif + #ifndef NO_gdk_1toplevel_1focus JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1toplevel_1focus) (JNIEnv *env, jclass that, jlong arg0, jint arg1) @@ -682,6 +692,26 @@ JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1toplevel_1size_1set_1size) } #endif +#ifndef NO_gsk_1render_1node_1draw +JNIEXPORT void JNICALL GTK4_NATIVE(gsk_1render_1node_1draw) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1) +{ + GTK4_NATIVE_ENTER(env, that, gsk_1render_1node_1draw_FUNC); + gsk_render_node_draw((GskRenderNode *)arg0, (cairo_t *)arg1); + GTK4_NATIVE_EXIT(env, that, gsk_1render_1node_1draw_FUNC); +} +#endif + +#ifndef NO_gsk_1render_1node_1unref +JNIEXPORT void JNICALL GTK4_NATIVE(gsk_1render_1node_1unref) + (JNIEnv *env, jclass that, jlong arg0) +{ + GTK4_NATIVE_ENTER(env, that, gsk_1render_1node_1unref_FUNC); + gsk_render_node_unref((GskRenderNode *)arg0); + GTK4_NATIVE_EXIT(env, that, gsk_1render_1node_1unref_FUNC); +} +#endif + #ifndef NO_gtk_1box_1append JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1box_1append) (JNIEnv *env, jclass that, jlong arg0, jlong arg1) @@ -2322,6 +2352,30 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1snapshot_1append_1cairo) } #endif +#ifndef NO_gtk_1snapshot_1free_1to_1node +JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1snapshot_1free_1to_1node) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gtk_1snapshot_1free_1to_1node_FUNC); + rc = (jlong)gtk_snapshot_free_to_node((GtkSnapshot *)arg0); + GTK4_NATIVE_EXIT(env, that, gtk_1snapshot_1free_1to_1node_FUNC); + return rc; +} +#endif + +#ifndef NO_gtk_1snapshot_1new +JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1snapshot_1new) + (JNIEnv *env, jclass that) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gtk_1snapshot_1new_FUNC); + rc = (jlong)gtk_snapshot_new(); + GTK4_NATIVE_EXIT(env, that, gtk_1snapshot_1new_FUNC); + return rc; +} +#endif + #ifndef NO_gtk_1style_1context_1add_1provider_1for_1display JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1style_1context_1add_1provider_1for_1display) (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2) @@ -2697,6 +2751,18 @@ JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1widget_1measure) } #endif +#ifndef NO_gtk_1widget_1paintable_1new +JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1widget_1paintable_1new) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + GTK4_NATIVE_ENTER(env, that, gtk_1widget_1paintable_1new_FUNC); + rc = (jlong)gtk_widget_paintable_new((GtkWidget *)arg0); + GTK4_NATIVE_EXIT(env, that, gtk_1widget_1paintable_1new_FUNC); + return rc; +} +#endif + #ifndef NO_gtk_1widget_1pick JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1widget_1pick) (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jdouble arg2, jint arg3) 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 e193dea9029..3203810ff68 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 @@ -66,6 +66,7 @@ typedef enum { gdk_1content_1serializer_1return_1error_FUNC, gdk_1content_1serializer_1return_1success_FUNC, gdk_1content_1serializer_1set_1task_1data_FUNC, + gdk_1paintable_1snapshot_FUNC, gdk_1toplevel_1focus_FUNC, gdk_1toplevel_1get_1state_FUNC, gdk_1toplevel_1lower_FUNC, @@ -73,6 +74,8 @@ typedef enum { gdk_1toplevel_1size_1get_1bounds_FUNC, gdk_1toplevel_1size_1set_1min_1size_FUNC, gdk_1toplevel_1size_1set_1size_FUNC, + gsk_1render_1node_1draw_FUNC, + gsk_1render_1node_1unref_FUNC, gtk_1box_1append_FUNC, gtk_1box_1insert_1child_1after_FUNC, gtk_1box_1prepend_FUNC, @@ -190,6 +193,8 @@ typedef enum { gtk_1shortcut_1controller_1set_1scope_FUNC, gtk_1shortcut_1new_FUNC, gtk_1snapshot_1append_1cairo_FUNC, + gtk_1snapshot_1free_1to_1node_FUNC, + gtk_1snapshot_1new_FUNC, gtk_1style_1context_1add_1provider_1for_1display_FUNC, gtk_1style_1context_1get_1border_FUNC, gtk_1style_1context_1get_1color_FUNC, @@ -218,6 +223,7 @@ typedef enum { gtk_1widget_1insert_1after_FUNC, gtk_1widget_1insert_1before_FUNC, gtk_1widget_1measure_FUNC, + gtk_1widget_1paintable_1new_FUNC, gtk_1widget_1pick_FUNC, gtk_1widget_1set_1cursor_FUNC, gtk_1widget_1set_1focusable_FUNC, 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 afdfa87e44a..a80af50732c 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 @@ -172,6 +172,7 @@ public class GTK4 { /** @param surface cast=(GdkToplevel *) */ public static final native void gdk_toplevel_focus(long surface, int timestamp); + /* GtkDragSource */ public static final native long gtk_drag_source_new(); /** @@ -725,6 +726,10 @@ public class GTK4 { * @param next_sibling cast=(GtkWidget *) */ public static final native void gtk_widget_insert_before(long widget, long parent, long next_sibling); + /** + * @param widget cast=(GtkWidget *) + */ + public static final native long gtk_widget_paintable_new(long widget); /** * @param widget cast=(GtkWidget *) * @param x cast=(double) @@ -738,12 +743,19 @@ public class GTK4 { public static final native long gtk_combo_box_get_child(long combo_box); /* GtkSnapshot */ + + public static final native long gtk_snapshot_new(); /** * @param snapshot cast=(GtkSnapshot *) * @param rect cast=(const graphene_rect_t *) */ public static final native long gtk_snapshot_append_cairo(long snapshot, long rect); + /** + * @param snapshot cast=(GtkSnapshot *) + */ + public static final native long gtk_snapshot_free_to_node(long snapshot); + /* GtkImage */ /** * @param image cast=(GtkImage *) @@ -1087,5 +1099,21 @@ public class GTK4 { public static final native int gtk_widget_get_height(long widget); public static final native long gtk_header_bar_new(); + /** + * @param paintable cast=(GdkPaintable *) + * @param snapshot cast=(GdkSnapshot *) + * @param width cast=(double) + * @param height cast=(double) + */ + public static final native void gdk_paintable_snapshot(long paintable, long snapshot, int width, int height); + /** + * @param renderNode cast=(GskRenderNode *) + * @param cr cast=(cairo_t *) + */ + public static final native void gsk_render_node_draw(long renderNode, long cr); + /** + * @param renderNode cast=(GskRenderNode *) + */ + public static final native void gsk_render_node_unref(long renderNode); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java index 656b19e191f..a2d3ee50217 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java @@ -626,18 +626,54 @@ public boolean print (GC gc) { if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); long topHandle = topHandle (); GTK.gtk_widget_realize (topHandle); - /* - * Feature in GTK: gtk_widget_draw() will only draw if the - * widget's priv->alloc_needed field is set to TRUE. Since - * this field is private and inaccessible, get and set the - * allocation to trigger it to be TRUE. See bug 530969. - */ - GtkAllocation allocation = new GtkAllocation (); - GTK.gtk_widget_get_allocation(topHandle, allocation); - // Prevent allocation warnings - GTK.gtk_widget_get_preferred_size(topHandle, null, null); - GTK3.gtk_widget_size_allocate(topHandle, allocation); - GTK3.gtk_widget_draw(topHandle, gc.handle); + + if (GTK.GTK4) { + /* + * In GTK4 gtk_widget_draw() has been removed. Rendering is now + * done via GtkSnapshot and the GskRenderNode pipeline. Snapshot the widget, + * extract the render node, then draw it onto the GC's Cairo context using + * gsk_render_node_draw(). + */ + + long widgetPaintable = GTK4.gtk_widget_paintable_new(topHandle); + if (widgetPaintable == 0) return false; + try { + int width = GTK4.gtk_widget_get_width(topHandle); + int height = GTK4.gtk_widget_get_height(topHandle); + + long snapshot = GTK4.gtk_snapshot_new(); + if (snapshot == 0) return false; + + try { + GTK4.gdk_paintable_snapshot(widgetPaintable, snapshot, width, height); + + long renderNode = GTK4.gtk_snapshot_free_to_node(snapshot); + snapshot = 0; // freed by gtk_snapshot_free_to_node + + if (renderNode == 0) return false; + + GTK4.gsk_render_node_draw(renderNode, gc.handle); + GTK4.gsk_render_node_unref(renderNode); + } finally { + if (snapshot != 0) OS.g_object_unref(snapshot); + } + } finally { + OS.g_object_unref(widgetPaintable); + } + } else { + /* + * In GTK 3 gtk_widget_draw() will only draw if the + * widget's priv->alloc_needed field is set to TRUE. Since + * this field is private and inaccessible, get and set the + * allocation to trigger it to be TRUE. See bug 530969. + */ + GtkAllocation allocation = new GtkAllocation (); + GTK.gtk_widget_get_allocation(topHandle, allocation); + // Prevent allocation warnings + GTK.gtk_widget_get_preferred_size(topHandle, null, null); + GTK3.gtk_widget_size_allocate(topHandle, allocation); + GTK3.gtk_widget_draw(topHandle, gc.handle); + } return true; }