Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
Original file line number Diff line number Diff line change
Expand Up @@ -15270,6 +15270,18 @@ JNIEXPORT void JNICALL OS_NATIVE(swt_1fixed_1restack)
}
#endif

#ifndef NO_swt_1scaled_1paintable_1new
JNIEXPORT jlong JNICALL OS_NATIVE(swt_1scaled_1paintable_1new)
(JNIEnv *env, jclass that, jlong arg0, jint arg1, jint arg2)
{
jlong rc = 0;
OS_NATIVE_ENTER(env, that, swt_1scaled_1paintable_1new_FUNC);
rc = (jlong)swt_scaled_paintable_new((GdkTexture*)arg0, arg1, arg2);
OS_NATIVE_EXIT(env, that, swt_1scaled_1paintable_1new_FUNC);
return rc;
}
#endif

#ifndef NO_swt_1set_1lock_1functions
JNIEXPORT void JNICALL OS_NATIVE(swt_1set_1lock_1functions)
(JNIEnv *env, jclass that)
Expand Down
3 changes: 3 additions & 0 deletions bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@
#define NO_swt_1fixed_1add
#define NO_swt_1fixed_1remove

// No GdkPaintable on GTK3
#define NO_swt_1scaled_1paintable_1new

#endif

#include "os_custom.h"
Expand Down
93 changes: 93 additions & 0 deletions bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.c
Original file line number Diff line number Diff line change
Expand Up @@ -2263,3 +2263,96 @@ JNIEXPORT jlong JNICALL OS_NATIVE(content_1providers_1create_1gvalue)
OS_NATIVE_EXIT(env, that, content_1providers_1create_1gvalue_FUNC)
return (jlong)v;
}

#if defined(GTK4)
/*
* SwtScaledPaintable: a GdkPaintable wrapping a GdkTexture that advertises a
* fixed logical (point) intrinsic size. GtkPicture measures a plain GdkTexture
* using its device-pixel size, which inflates widgets at HiDPI. By reporting the
* logical size here while drawing the full-resolution texture, images keep their
* correct logical footprint and render crisply (no down/up-scaling).
*/
#define SWT_TYPE_SCALED_PAINTABLE (swt_scaled_paintable_get_type ())
G_DECLARE_FINAL_TYPE (SwtScaledPaintable, swt_scaled_paintable, SWT, SCALED_PAINTABLE, GObject)

struct _SwtScaledPaintable
{
GObject parent_instance;
GdkTexture* texture;
int width;
int height;
};

static void swt_scaled_paintable_paintable_init (GdkPaintableInterface* iface);

G_DEFINE_TYPE_WITH_CODE (SwtScaledPaintable, swt_scaled_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, swt_scaled_paintable_paintable_init))

static void swt_scaled_paintable_snapshot (GdkPaintable* paintable, GdkSnapshot* snapshot, double width, double height)
{
SwtScaledPaintable* self = SWT_SCALED_PAINTABLE (paintable);
if (self->texture != NULL) {
/* Draw the full device-resolution texture into the (logical) box. */
gdk_paintable_snapshot (GDK_PAINTABLE (self->texture), snapshot, width, height);
}
}

static int swt_scaled_paintable_get_intrinsic_width (GdkPaintable* paintable)
{
return SWT_SCALED_PAINTABLE (paintable)->width;
}

static int swt_scaled_paintable_get_intrinsic_height (GdkPaintable* paintable)
{
return SWT_SCALED_PAINTABLE (paintable)->height;
}

static double swt_scaled_paintable_get_intrinsic_aspect_ratio (GdkPaintable* paintable)
{
SwtScaledPaintable* self = SWT_SCALED_PAINTABLE (paintable);
if (self->height <= 0) return 0.0;
return (double) self->width / (double) self->height;
}

static GdkPaintableFlags swt_scaled_paintable_get_flags (GdkPaintable* paintable)
{
return GDK_PAINTABLE_STATIC_SIZE | GDK_PAINTABLE_STATIC_CONTENTS;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the gdk_paintable_snapshot (GDK_PAINTABLE (self->texture)... ever paint differently or need to invalidate? i.e. is the texture always static contents too?

Ref is this demo from GTK4 which checks the child paintable for static

https://gitlab.gnome.org/GNOME/gtk/-/blob/eddff506651609ff02c641066f51f1c32f1b2fd6/demos/gtk-demo/paintable_emblem.c#L115-121

I am not sure this is wrong as we tend to have the paintables (texture) be rather static and recreated when changed.

}

static void swt_scaled_paintable_paintable_init (GdkPaintableInterface* iface)
{
iface->snapshot = swt_scaled_paintable_snapshot;
iface->get_intrinsic_width = swt_scaled_paintable_get_intrinsic_width;
iface->get_intrinsic_height = swt_scaled_paintable_get_intrinsic_height;
iface->get_intrinsic_aspect_ratio = swt_scaled_paintable_get_intrinsic_aspect_ratio;
iface->get_flags = swt_scaled_paintable_get_flags;
}

static void swt_scaled_paintable_dispose (GObject* object)
{
SwtScaledPaintable* self = SWT_SCALED_PAINTABLE (object);
g_clear_object (&self->texture);
G_OBJECT_CLASS (swt_scaled_paintable_parent_class)->dispose (object);
}

static void swt_scaled_paintable_class_init (SwtScaledPaintableClass* klass)
{
G_OBJECT_CLASS (klass)->dispose = swt_scaled_paintable_dispose;
}

static void swt_scaled_paintable_init (SwtScaledPaintable* self)
{
self->texture = NULL;
self->width = 0;
self->height = 0;
}

GdkPaintable* swt_scaled_paintable_new (GdkTexture* texture, int width, int height)
{
SwtScaledPaintable* self = g_object_new (SWT_TYPE_SCALED_PAINTABLE, NULL);
self->texture = texture != NULL ? g_object_ref (texture) : NULL;
self->width = width;
self->height = height;
return GDK_PAINTABLE (self);
}
#endif /* GTK4 */
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ struct _SwtFixedClass

GType swt_fixed_get_type (void) G_GNUC_CONST;

#if defined(GTK4)
/*
* GdkPaintable that wraps a GdkTexture but advertises a fixed logical (point)
* intrinsic size. Used so GtkPicture measures images in logical points (avoiding
* HiDPI inflation) while still drawing the full device-resolution texture crisply.
*/
GdkPaintable* swt_scaled_paintable_new (GdkTexture* texture, int width, int height);
#endif

#if defined(GTK4)
void swt_fixed_add(SwtFixed* fixed, GtkWidget* widget);
void swt_fixed_remove(SwtFixed* fixed, GtkWidget* widget);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@ typedef enum {
swt_1fixed_1remove_FUNC,
swt_1fixed_1resize_FUNC,
swt_1fixed_1restack_FUNC,
swt_1scaled_1paintable_1new_FUNC,
swt_1set_1lock_1functions_FUNC,
ubuntu_1menu_1proxy_1get_FUNC,
} OS_FUNCS;
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,12 @@ public static String getEnvironmentalVariable (String envVarName) {
/** @category custom */
public static final native long swt_fixed_get_type();

/**
* @param texture cast=(GdkTexture*)
* @category custom
*/
public static final native long swt_scaled_paintable_new(long texture, int width, int height);

/** @category custom */
public static final native long swt_fixed_accessible_get_type();
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,6 @@ public static long createPixbuf(Image image) {
}
}
Cairo.cairo_surface_destroy(surface);
if (GTK.GTK4) {
//Scaling needed as the image surface will be different from the image size depending on the display scale
long scaledPixbuf = GDK.gdk_pixbuf_scale_simple(pixbuf, image.getBounds().width, image.getBounds().height, GDK.GDK_INTERP_BILINEAR);
OS.g_object_unref(pixbuf);
pixbuf = scaledPixbuf;
}

return pixbuf;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1158,8 +1158,11 @@ private 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_picture_set_paintable(imageHandle, texture);
Rectangle bounds = image.getBounds();
long paintable = OS.swt_scaled_paintable_new(texture, bounds.width, bounds.height);
OS.g_object_unref(texture);
GTK4.gtk_picture_set_paintable(imageHandle, paintable);
OS.g_object_unref(paintable);
} else {
GTK3.gtk_image_set_from_surface(imageHandle, image.surface);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,11 @@ public 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_picture_set_paintable(imageHandle, texture);
Rectangle bounds = image.getBounds();
long paintable = OS.swt_scaled_paintable_new(texture, bounds.width, bounds.height);
OS.g_object_unref(texture);
GTK4.gtk_picture_set_paintable(imageHandle, paintable);
OS.g_object_unref(paintable);
} else {
GTK3.gtk_image_set_from_surface(imageHandle, image.surface);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -650,8 +650,11 @@ public 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_picture_set_paintable(imageHandle, texture);
Rectangle bounds = image.getBounds();
long paintable = OS.swt_scaled_paintable_new(texture, bounds.width, bounds.height);
OS.g_object_unref(texture);
GTK4.gtk_picture_set_paintable(imageHandle, paintable);
OS.g_object_unref(paintable);
} else {
GTK3.gtk_image_set_from_surface(imageHandle, image.surface);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -781,8 +781,11 @@ 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_picture_set_paintable(imageHandle, texture);
Rectangle bounds = hotImage.getBounds();
long paintable = OS.swt_scaled_paintable_new(texture, bounds.width, bounds.height);
OS.g_object_unref(texture);
GTK4.gtk_picture_set_paintable(imageHandle, paintable);
OS.g_object_unref(paintable);
}
}
}
Expand Down Expand Up @@ -853,8 +856,11 @@ 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_picture_set_paintable(imageHandle, texture);
Rectangle bounds = image.getBounds();
long paintable = OS.swt_scaled_paintable_new(texture, bounds.width, bounds.height);
OS.g_object_unref(texture);
GTK4.gtk_picture_set_paintable(imageHandle, paintable);
OS.g_object_unref(paintable);
}
}
}
Expand Down Expand Up @@ -1376,24 +1382,22 @@ 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_picture_set_paintable(imageHandle, texture);
OS.g_object_unref(texture);
/*
* Pin the GtkPicture to the image's logical (point) size so it occupies the
* same footprint as the previously used GtkImage. The texture is created
* from a device-scaled pixbuf whose intrinsic size is in pixels; without a
* size request GtkPicture would measure to those pixel dimensions, inflating
* the ToolItem and causing overlaps (e.g. the CTabFolder chevron toolbar).
* Wrap the full-resolution texture in a paintable that reports the image's
* logical (point) size, so the GtkPicture keeps the same footprint as the
* previously used GtkImage and renders crisply at HiDPI.
*/
Rectangle bounds = image.getBounds();
GTK.gtk_widget_set_size_request(imageHandle, bounds.width, bounds.height);
long paintable = OS.swt_scaled_paintable_new(texture, bounds.width, bounds.height);
OS.g_object_unref(texture);
GTK4.gtk_picture_set_paintable(imageHandle, paintable);
OS.g_object_unref(paintable);
} else {
GTK3.gtk_image_set_from_surface(imageHandle, imageList.getSurface(imageIndex));
}
} else {
if(GTK.GTK4) {
GTK4.gtk_picture_set_paintable(imageHandle, 0);
GTK.gtk_widget_set_size_request(imageHandle, -1, -1);
gtk_widget_hide(imageHandle);
} else {
GTK3.gtk_image_set_from_surface(imageHandle, 0);
Expand Down
Loading