summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Kareh <[email protected]>2025-10-20 16:50:41 -0400
committerVictor Kareh <[email protected]>2025-10-20 16:50:41 -0400
commit1b68f7eb5cf912a95161584f8829f2dba23f11cc (patch)
tree7129adb79aa6e33744a84e8ccbfd746a1a8176e5
parente89ae9d58dc08737a1eb12d0853ac09709db88e3 (diff)
downloadmate-screensaver-hidpi-face-picture.tar.bz2
mate-screensaver-hidpi-face-picture.tar.xz
gs-lock-plug: Fix HiDPI scaling for user face imageshidpi-face-picture
Uses cairo surfaces to load user face images (~/.face) at the correct scale. This allows us to show a sharp image on HiDPI screens. Fixes #191
-rw-r--r--src/gs-lock-plug.c199
1 files changed, 52 insertions, 147 deletions
diff --git a/src/gs-lock-plug.c b/src/gs-lock-plug.c
index bcb6a86..b0c0913 100644
--- a/src/gs-lock-plug.c
+++ b/src/gs-lock-plug.c
@@ -685,16 +685,18 @@ gs_lock_plug_run (GSLockPlug *plug)
}
static cairo_surface_t *
-surface_from_pixbuf (GdkPixbuf *pixbuf)
+surface_from_pixbuf (GdkPixbuf *pixbuf,
+ double scale)
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create (gdk_pixbuf_get_has_alpha (pixbuf) ?
CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
- gdk_pixbuf_get_width (pixbuf),
- gdk_pixbuf_get_height (pixbuf));
+ gdk_pixbuf_get_width (pixbuf) * scale,
+ gdk_pixbuf_get_height (pixbuf) * scale);
cr = cairo_create (surface);
+ cairo_scale (cr, scale, scale);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
@@ -745,138 +747,26 @@ rounded_rectangle (cairo_t *cr,
cairo_close_path (cr);
}
-/* copied from gnome-screensaver 3.x */
-
-/**
- * go_cairo_convert_data_to_pixbuf:
- * @src: a pointer to pixel data in cairo format
- * @dst: a pointer to pixel data in pixbuf format
- * @width: image width
- * @height: image height
- * @rowstride: data rowstride
- *
- * Converts the pixel data stored in @src in CAIRO_FORMAT_ARGB32 cairo format
- * to GDK_COLORSPACE_RGB pixbuf format and move them
- * to @dst. If @src == @dst, pixel are converted in place.
- **/
-
-static void
-go_cairo_convert_data_to_pixbuf (unsigned char *dst,
- unsigned char const *src,
- int width,
- int height,
- int rowstride)
-{
- int i,j;
- unsigned int t;
- unsigned char a, b, c;
-
- g_return_if_fail (dst != NULL);
-
-#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END
-
- if (src == dst || src == NULL) {
- for (i = 0; i < height; i++) {
- for (j = 0; j < width; j++) {
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- MULT(a, dst[2], dst[3], t);
- MULT(b, dst[1], dst[3], t);
- MULT(c, dst[0], dst[3], t);
- dst[0] = a;
- dst[1] = b;
- dst[2] = c;
-#else
- MULT(a, dst[1], dst[0], t);
- MULT(b, dst[2], dst[0], t);
- MULT(c, dst[3], dst[0], t);
- dst[3] = dst[0];
- dst[0] = a;
- dst[1] = b;
- dst[2] = c;
-#endif
- dst += 4;
- }
- dst += rowstride - width * 4;
- }
- } else {
- for (i = 0; i < height; i++) {
- for (j = 0; j < width; j++) {
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- MULT(dst[0], src[2], src[3], t);
- MULT(dst[1], src[1], src[3], t);
- MULT(dst[2], src[0], src[3], t);
- dst[3] = src[3];
-#else
- MULT(dst[0], src[1], src[0], t);
- MULT(dst[1], src[2], src[0], t);
- MULT(dst[2], src[3], src[0], t);
- dst[3] = src[0];
-#endif
- src += 4;
- dst += 4;
- }
- src += rowstride - width * 4;
- dst += rowstride - width * 4;
- }
- }
-#undef MULT
-}
-
-static void
-cairo_to_pixbuf (guint8 *src_data,
- GdkPixbuf *dst_pixbuf)
-{
- unsigned char *src;
- unsigned char *dst;
- guint w;
- guint h;
- guint rowstride;
-
- w = gdk_pixbuf_get_width (dst_pixbuf);
- h = gdk_pixbuf_get_height (dst_pixbuf);
- rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf);
-
- dst = gdk_pixbuf_get_pixels (dst_pixbuf);
- src = src_data;
-
- go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride);
-}
-
-static GdkPixbuf *
-frame_pixbuf (GdkPixbuf *source)
+static cairo_surface_t *
+frame_surface (cairo_surface_t *source)
{
- GdkPixbuf *dest;
+ cairo_surface_t *dest;
cairo_t *cr;
- cairo_surface_t *surface;
guint w;
guint h;
- guint rowstride;
int frame_width;
double radius;
- guint8 *data;
frame_width = 5;
- w = gdk_pixbuf_get_width (source) + frame_width * 2;
- h = gdk_pixbuf_get_height (source) + frame_width * 2;
+ w = cairo_image_surface_get_width (source) + frame_width * 2;
+ h = cairo_image_surface_get_height (source) + frame_width * 2;
radius = w / 10;
- dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
- TRUE,
- 8,
- w,
- h);
- rowstride = gdk_pixbuf_get_rowstride (dest);
-
- data = g_new0 (guint8, h * rowstride);
-
- surface = cairo_image_surface_create_for_data (data,
- CAIRO_FORMAT_ARGB32,
- w,
- h,
- rowstride);
- cr = cairo_create (surface);
- cairo_surface_destroy (surface);
+ dest = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ w,
+ h);
+ cr = cairo_create (dest);
/* set up image */
cairo_rectangle (cr, 0, 0, w, h);
@@ -893,15 +783,10 @@ frame_pixbuf (GdkPixbuf *source)
cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3);
cairo_fill_preserve (cr);
- surface = surface_from_pixbuf (source);
- cairo_set_source_surface (cr, surface, frame_width, frame_width);
+ cairo_set_source_surface (cr, source, frame_width, frame_width);
cairo_fill (cr);
- cairo_surface_destroy (surface);
-
- cairo_to_pixbuf (data, dest);
cairo_destroy (cr);
- g_free (data);
return dest;
}
@@ -909,14 +794,17 @@ frame_pixbuf (GdkPixbuf *source)
/* end copied from gdm-user.c */
static void
-image_set_from_pixbuf (GtkImage *image,
- GdkPixbuf *source)
+image_set_from_surface (GtkImage *image,
+ cairo_surface_t *source,
+ int scale_factor)
{
- GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
+
+ surface = frame_surface (source);
+ cairo_surface_set_device_scale (surface, scale_factor, scale_factor);
+ gtk_image_set_from_surface (image, surface);
+ cairo_surface_destroy (surface);
- pixbuf = frame_pixbuf (source);
- gtk_image_set_from_pixbuf (image, pixbuf);
- g_object_unref (pixbuf);
}
static gboolean
@@ -975,12 +863,17 @@ check_user_file (const gchar *filename,
static gboolean
set_face_image (GSLockPlug *plug)
{
- GdkPixbuf *pixbuf;
- const char *homedir;
- char *path;
- int icon_size = 96;
- gsize user_max_file = 65536;
- uid_t uid;
+ GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
+ const char *homedir;
+ char *path;
+ int icon_size = 96;
+ gsize user_max_file = 1048576;
+ uid_t uid;
+ int scale_factor;
+ int width;
+ int height;
+ double scale;
homedir = g_get_home_dir ();
uid = getuid ();
@@ -990,10 +883,7 @@ set_face_image (GSLockPlug *plug)
pixbuf = NULL;
if (check_user_file (path, uid, user_max_file, 0, 0))
{
- pixbuf = gdk_pixbuf_new_from_file_at_size (path,
- icon_size,
- icon_size,
- NULL);
+ pixbuf = gdk_pixbuf_new_from_file (path, NULL);
}
g_free (path);
@@ -1003,10 +893,25 @@ set_face_image (GSLockPlug *plug)
return FALSE;
}
- image_set_from_pixbuf (GTK_IMAGE (plug->priv->auth_face_image), pixbuf);
+ scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (plug->priv->auth_face_image));
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ scale = 1.0;
+ if (width > icon_size || height > icon_size)
+ {
+ double scale_x = (double) icon_size / width;
+ double scale_y = (double) icon_size / height;
+ scale = MIN (scale_x, scale_y) * scale_factor;
+ }
+
+ surface = surface_from_pixbuf (pixbuf, scale);
g_object_unref (pixbuf);
+ image_set_from_surface (GTK_IMAGE (plug->priv->auth_face_image), surface, scale_factor);
+ cairo_surface_destroy (surface);
+
return TRUE;
}