From b26263591880e9afbcf787c1bb790b308664a147 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: Mon, 25 May 2026 20:02:09 +0300 Subject: [PATCH] [Gtk4] Fix ToolItem image size by using GtkPicture instead of GtkImage GTK4 works in logical points while Cairo works in pixels, causing images to appear smaller at HiDPI scaling. Using GtkPicture (instead of GtkImage) correctly maps the pixbuf to the right display size. This is the same fix applied to Button (https://github.com/eclipse-platform/eclipse.platform.swt/pull/3323 ) and Label (https://github.com/eclipse-platform/eclipse.platform.swt/pull/2766 ) for the same reason. --- .../Eclipse SWT PI/gtk/library/gtk4.c | 10 +++++++++ .../Eclipse SWT PI/gtk/library/gtk4_stats.h | 1 + .../org/eclipse/swt/internal/gtk4/GTK4.java | 10 +++++++++ .../gtk/org/eclipse/swt/widgets/ToolItem.java | 22 ++++++++++++++----- 4 files changed, 38 insertions(+), 5 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 6cac3b925ea..439946d0332 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 @@ -2178,6 +2178,16 @@ JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1picture_1set_1can_1shrink) } #endif +#ifndef NO_gtk_1picture_1set_1content_1fit +JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1picture_1set_1content_1fit) + (JNIEnv *env, jclass that, jlong arg0, jint arg1) +{ + GTK4_NATIVE_ENTER(env, that, gtk_1picture_1set_1content_1fit_FUNC); + gtk_picture_set_content_fit((GtkPicture *)arg0, (GtkContentFit)arg1); + GTK4_NATIVE_EXIT(env, that, gtk_1picture_1set_1content_1fit_FUNC); +} +#endif + #ifndef NO_gtk_1picture_1set_1paintable JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1picture_1set_1paintable) (JNIEnv *env, jclass that, jlong arg0, jlong 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 1a5c5c9312b..12f6b725c3e 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 @@ -178,6 +178,7 @@ typedef enum { gtk_1native_1get_1surface_FUNC, gtk_1picture_1new_FUNC, gtk_1picture_1set_1can_1shrink_FUNC, + gtk_1picture_1set_1content_1fit_FUNC, gtk_1picture_1set_1paintable_FUNC, gtk_1popover_1menu_1bar_1new_1from_1model_FUNC, gtk_1popover_1menu_1get_1menu_1model_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 9147dea5547..fdb35acced1 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 @@ -30,6 +30,11 @@ public class GTK4 { public static final int GTK_PICK_INSENSITIVE = 1; public static final int GTK_PICK_NON_TARGETABLE = 2; + public static final int GTK_CONTENT_FIT_FILL = 0; + public static final int GTK_CONTENT_FIT_CONTAIN = 1; + public static final int GTK_CONTENT_FIT_COVER = 2; + public static final int GTK_CONTENT_FIT_SCALE_DOWN = 3; + public static final native boolean GTK_IS_POPOVER_MENU(long obj); /** @@ -158,6 +163,11 @@ public class GTK4 { public static final native void gtk_picture_set_paintable(long picture, long paintable); /** @param picture cast=(GtkPicture *) */ public static final native void gtk_picture_set_can_shrink(long picture, boolean can_shrink); + /** + * @param picture cast=(GtkPicture *) + * @param content_fit cast=(GtkContentFit) + */ + public static final native void gtk_picture_set_content_fit(long picture, int content_fit); /* GTK Initialization */ public static final native boolean gtk_init_check(); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java index 70e79d5f3b7..9753be821d8 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java @@ -298,8 +298,17 @@ void createHandle (int index) { if (GTK.GTK4) { labelHandle = GTK.gtk_label_new_with_mnemonic(null); if (labelHandle == 0) error(SWT.ERROR_NO_HANDLES); - imageHandle = GTK.gtk_image_new(); + imageHandle = GTK4.gtk_picture_new(); if (imageHandle == 0) error(SWT.ERROR_NO_HANDLES); + /* + * Use SCALE_DOWN content fit so GtkPicture never scales up beyond its + * intrinsic size. This prevents the natural height measurement from being + * proportional to the available width (which caused excess space in the + * image+label GtkBox when the button was wide). + */ + GTK4.gtk_picture_set_content_fit(imageHandle, GTK4.GTK_CONTENT_FIT_SCALE_DOWN); + GTK.gtk_widget_set_halign(imageHandle, GTK.GTK_ALIGN_CENTER); + GTK.gtk_widget_set_valign(imageHandle, GTK.GTK_ALIGN_CENTER); GTK.gtk_widget_set_valign(boxHandle, GTK.GTK_ALIGN_CENTER); @@ -779,7 +788,8 @@ void gtk4_enter_event(long controller, double x, double y, long event) { long pixbuf = ImageList.createPixbuf(hotImage); long texture = GDK.gdk_texture_new_for_pixbuf(pixbuf); OS.g_object_unref(pixbuf); - GTK4.gtk_image_set_from_paintable(imageHandle, texture); + GTK4.gtk_picture_set_paintable(imageHandle, texture); + OS.g_object_unref(texture); } } } @@ -850,7 +860,8 @@ void gtk4_leave_event(long controller, long event) { long pixbuf = ImageList.createPixbuf(image); long texture = GDK.gdk_texture_new_for_pixbuf(pixbuf); OS.g_object_unref(pixbuf); - GTK4.gtk_image_set_from_paintable(imageHandle, texture); + GTK4.gtk_picture_set_paintable(imageHandle, texture); + OS.g_object_unref(texture); } } } @@ -1373,13 +1384,14 @@ void _setImage (Image image) { long pixbuf = ImageList.createPixbuf(image); long texture = GDK.gdk_texture_new_for_pixbuf(pixbuf); OS.g_object_unref(pixbuf); - GTK4.gtk_image_set_from_paintable(imageHandle, texture); + GTK4.gtk_picture_set_paintable(imageHandle, texture); + OS.g_object_unref(texture); } else { GTK3.gtk_image_set_from_surface(imageHandle, imageList.getSurface(imageIndex)); } } else { if(GTK.GTK4) { - GTK4.gtk_image_clear(imageHandle); + GTK4.gtk_picture_set_paintable(imageHandle, 0); gtk_widget_hide(imageHandle); } else { GTK3.gtk_image_set_from_surface(imageHandle, 0);