diff --git a/wrlib/Makefile.am b/wrlib/Makefile.am index a82bb9a..3312c27 100644 --- a/wrlib/Makefile.am +++ b/wrlib/Makefile.am @@ -35,6 +35,9 @@ libwraster_la_SOURCES = \ xpixmap.c \ convert.h \ convert.c \ + convert_funcs.h \ + convert_x11.c \ + convert_wl.c \ context.c \ misc.c \ scale.c \ @@ -82,7 +85,7 @@ libwraster_la_SOURCES += load_magick.c endif AM_CFLAGS = @MAGICKFLAGS@ -AM_CPPFLAGS = $(DFLAGS) @HEADER_SEARCH_PATH@ +AM_CPPFLAGS = $(DFLAGS) @HEADER_SEARCH_PATH@ $(PIXMAN_CFLAGS) libwraster_la_LIBADD = @LIBRARY_SEARCH_PATH@ @GFXLIBS@ @MAGICKLIBS@ @XLIBS@ @LIBXMU@ -lm diff --git a/wrlib/context.c b/wrlib/context.c index 80e6bb1..28d785e 100644 --- a/wrlib/context.c +++ b/wrlib/context.c @@ -40,6 +40,7 @@ #include "wraster.h" #include "scale.h" #include "wr_i18n.h" +#include "convert_funcs.h" #ifndef HAVE_FLOAT_MATHFUNC @@ -656,6 +657,9 @@ RContext *RCreateContext(Display * dpy, int screen_number, const RContextAttribu } #endif + context->convert_image = x11_convert_image; + context->convert_image_mask = x11_convert_image_mask; + return context; } @@ -761,5 +765,8 @@ RContext *RCreateContextWayland(int width, int height, (void)width; (void)height; + context->convert_image = wl_convert_image; + context->convert_image_mask = wl_convert_image_mask; + return context; } diff --git a/wrlib/convert.c b/wrlib/convert.c index e7f608c..9346339 100644 --- a/wrlib/convert.c +++ b/wrlib/convert.c @@ -292,7 +292,7 @@ convertTrueColor_generic(RXImage * ximg, RImage * image, } } -static RXImage *image2TrueColor(RContext * ctx, RImage * image) +RXImage *image2TrueColor(RContext * ctx, RImage * image) { RXImage *ximg; unsigned short rmask, gmask, bmask; @@ -481,7 +481,7 @@ convertPseudoColor_to_8(RXImage * ximg, RImage * image, } } -static RXImage *image2PseudoColor(RContext * ctx, RImage * image) +RXImage *image2PseudoColor(RContext * ctx, RImage * image) { RXImage *ximg; register int x, y, r, g, b; @@ -565,7 +565,7 @@ static RXImage *image2PseudoColor(RContext * ctx, RImage * image) /* * For standard colormap */ -static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image) +RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image) { RXImage *ximg; register int x, y, r, g, b; @@ -715,7 +715,7 @@ static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image) return ximg; } -static RXImage *image2GrayScale(RContext * ctx, RImage * image) +RXImage *image2GrayScale(RContext * ctx, RImage * image) { RXImage *ximg; register int x, y, g; @@ -838,7 +838,7 @@ static RXImage *image2GrayScale(RContext * ctx, RImage * image) return ximg; } -static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold) +RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold) { RXImage *ximg; unsigned char *alpha; @@ -862,74 +862,11 @@ static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold) int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap) { - RXImage *ximg = NULL; -#ifdef USE_XSHM - Pixmap tmp; -#endif - assert(context != NULL); assert(image != NULL); assert(pixmap != NULL); - /* Wayland mode: no X11 display, pixmaps are not used */ - if (!context->dpy) { - *pixmap = (Pixmap)0; - return 1; - } - - switch (context->vclass) { - case TrueColor: - ximg = image2TrueColor(context, image); - break; - - case PseudoColor: - case StaticColor: - if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) - ximg = image2StandardPseudoColor(context, image); - else - ximg = image2PseudoColor(context, image); - break; - - case GrayScale: - case StaticGray: - ximg = image2GrayScale(context, image); - break; - } - - if (!ximg) { - return False; - } - - *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth); - -#ifdef USE_XSHM - if (context->flags.use_shared_pixmap && ximg->is_shared) - tmp = R_CreateXImageMappedPixmap(context, ximg); - else - tmp = None; - if (tmp) { - /* - * We have to copy the shm Pixmap into a normal Pixmap because - * otherwise, we would have to control when Pixmaps are freed so - * that we can detach their shm segments. This is a problem if the - * program crash, leaving stale shared memory segments in the - * system (lots of them). But with some work, we can optimize - * things and remove this XCopyArea. This will require - * explicitly freeing all pixmaps when exiting or restarting - * wmaker. - */ - XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0); - XFreePixmap(context->dpy, tmp); - } else { - RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height); - } -#else /* !USE_XSHM */ - RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height); -#endif /* !USE_XSHM */ - - RDestroyXImage(context, ximg); - - return True; + return context->convert_image(context, image, pixmap); } /* make the gc permanent (create with context creation). @@ -937,44 +874,12 @@ int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap) */ int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold) { - GC gc; - XGCValues gcv; - RXImage *ximg = NULL; - assert(context != NULL); assert(image != NULL); assert(pixmap != NULL); assert(mask != NULL); - if (!context->dpy) { - *pixmap = (Pixmap)0; - *mask = (Pixmap)0; - return True; - } - - if (!RConvertImage(context, image, pixmap)) - return False; - - if (image->format == RRGBFormat) { - *mask = None; - return True; - } - - ximg = image2Bitmap(context, image, threshold); - - if (!ximg) { - return False; - } - *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1); - gcv.foreground = context->black; - gcv.background = context->white; - gcv.graphics_exposures = False; - gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv); - RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height); - RDestroyXImage(context, ximg); - XFreeGC(context->dpy, gc); - - return True; + return context->convert_image_mask(context, image, pixmap, mask, threshold); } Bool RGetClosestXColor(RContext * context, const RColor * color, XColor * retColor) diff --git a/wrlib/convert.h b/wrlib/convert.h index a3045e0..2bc00ec 100644 --- a/wrlib/convert.h +++ b/wrlib/convert.h @@ -35,5 +35,11 @@ */ void r_destroy_conversion_tables(void); +/* Internal image-to-XImage converters (used by convert_x11.c) */ +RXImage *image2TrueColor(RContext *ctx, RImage *image); +RXImage *image2PseudoColor(RContext *ctx, RImage *image); +RXImage *image2StandardPseudoColor(RContext *ctx, RImage *image); +RXImage *image2GrayScale(RContext *ctx, RImage *image); +RXImage *image2Bitmap(RContext *ctx, RImage *image, int threshold); #endif diff --git a/wrlib/convert_funcs.h b/wrlib/convert_funcs.h new file mode 100644 index 0000000..5140051 --- /dev/null +++ b/wrlib/convert_funcs.h @@ -0,0 +1,12 @@ +/* convert_funcs.h - backend convert function declarations */ +#ifndef WRLIB_CONVERT_FUNCS_H +#define WRLIB_CONVERT_FUNCS_H + +#include "wraster.h" + +int x11_convert_image(RContext *ctx, RImage *image, Pixmap *pixmap); +int x11_convert_image_mask(RContext *ctx, RImage *image, Pixmap *pixmap, Pixmap *mask, int threshold); +int wl_convert_image(RContext *ctx, RImage *image, Pixmap *pixmap); +int wl_convert_image_mask(RContext *ctx, RImage *image, Pixmap *pixmap, Pixmap *mask, int threshold); + +#endif diff --git a/wrlib/convert_wl.c b/wrlib/convert_wl.c new file mode 100644 index 0000000..b39facd --- /dev/null +++ b/wrlib/convert_wl.c @@ -0,0 +1,58 @@ +/* convert_wl.c - Wayland backend for RImage → pixman_image_t conversion */ + +#include +#include +#include + +#include "wraster.h" + +int wl_convert_image(RContext *context, RImage *image, Pixmap *pixmap) +{ + (void)context; + unsigned int w = image->width; + unsigned int h = image->height; + pixman_image_t *img = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0); + uint32_t *dst = pixman_image_get_data(img); + unsigned char *src = image->data; + int has_alpha = (image->format == RRGBAFormat); + + for (unsigned int i = 0; i < w * h; i++) { + unsigned char r = src[0], g = src[1], b = src[2]; + unsigned char a = has_alpha ? src[3] : 0xFF; + dst[i] = ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; + src += has_alpha ? 4 : 3; + } + + *pixmap = (Pixmap)(uintptr_t)img; + return True; +} + +int wl_convert_image_mask(RContext *context, RImage *image, + Pixmap *pixmap, Pixmap *mask, int threshold) +{ + if (!wl_convert_image(context, image, pixmap)) + return False; + + if (image->format == RRGBFormat) { + *mask = (Pixmap)0; + return True; + } + + /* Create 8-bit alpha mask from image alpha channel */ + unsigned int w = image->width; + unsigned int h = image->height; + pixman_image_t *m = pixman_image_create_bits(PIXMAN_a8, w, h, NULL, 0); + uint8_t *mdst = (uint8_t *)pixman_image_get_data(m); + int stride = pixman_image_get_stride(m); + unsigned char *src = image->data; + + for (unsigned int y = 0; y < h; y++) { + for (unsigned int x = 0; x < w; x++) { + unsigned char a = src[(y * w + x) * 4 + 3]; + mdst[y * stride + x] = (a >= threshold) ? 0xFF : 0x00; + } + } + + *mask = (Pixmap)(uintptr_t)m; + return True; +} diff --git a/wrlib/convert_x11.c b/wrlib/convert_x11.c new file mode 100644 index 0000000..16ff684 --- /dev/null +++ b/wrlib/convert_x11.c @@ -0,0 +1,96 @@ +/* convert_x11.c - X11 backend for RImage → Pixmap conversion */ + +#include +#include +#include +#include +#include + +#include "wraster.h" +#include "convert.h" +#include "xutil.h" + +int x11_convert_image(RContext *context, RImage *image, Pixmap *pixmap) +{ + RXImage *ximg = NULL; +#ifdef USE_XSHM + Pixmap tmp; +#endif + + switch (context->vclass) { + case TrueColor: + ximg = image2TrueColor(context, image); + break; + case PseudoColor: + case StaticColor: + if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) + ximg = image2StandardPseudoColor(context, image); + else + ximg = image2PseudoColor(context, image); + break; + case GrayScale: + case StaticGray: + ximg = image2GrayScale(context, image); + break; + } + + if (!ximg) + return False; + + *pixmap = XCreatePixmap(context->dpy, context->drawable, + image->width, image->height, context->depth); + +#ifdef USE_XSHM + if (context->flags.use_shared_pixmap && ximg->is_shared) + tmp = R_CreateXImageMappedPixmap(context, ximg); + else + tmp = None; + if (tmp) { + XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, + 0, 0, image->width, image->height, 0, 0); + XFreePixmap(context->dpy, tmp); + } else { + RPutXImage(context, *pixmap, context->copy_gc, ximg, + 0, 0, 0, 0, image->width, image->height); + } +#else + RPutXImage(context, *pixmap, context->copy_gc, ximg, + 0, 0, 0, 0, image->width, image->height); +#endif + + RDestroyXImage(context, ximg); + return True; +} + +int x11_convert_image_mask(RContext *context, RImage *image, + Pixmap *pixmap, Pixmap *mask, int threshold) +{ + GC gc; + XGCValues gcv; + RXImage *ximg; + + if (!RConvertImage(context, image, pixmap)) + return False; + + if (image->format == RRGBFormat) { + *mask = None; + return True; + } + + ximg = image2Bitmap(context, image, threshold); + if (!ximg) + return False; + + *mask = XCreatePixmap(context->dpy, context->drawable, + image->width, image->height, 1); + gcv.foreground = context->black; + gcv.background = context->white; + gcv.graphics_exposures = False; + gc = XCreateGC(context->dpy, *mask, + GCForeground | GCBackground | GCGraphicsExposures, &gcv); + RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, + image->width, image->height); + RDestroyXImage(context, ximg); + XFreeGC(context->dpy, gc); + return True; +} diff --git a/wrlib/wraster.h.in b/wrlib/wraster.h.in index b4183f0..95d31c8 100644 --- a/wrlib/wraster.h.in +++ b/wrlib/wraster.h.in @@ -166,6 +166,8 @@ typedef struct RContextAttributes { * we can use, if we should do dithering, and what colors to use for * dithering. */ +typedef struct RImage RImage; + typedef struct RContext { Display *dpy; int screen_number; @@ -203,6 +205,10 @@ typedef struct RContext { __wrlib_deprecated("Flag optimize_for_speed in RContext is not used anymore " "and will be removed in future version, please do not use"); } flags; + + /* Backend conversion vtable (set during context creation) */ + int (*convert_image)(struct RContext *ctx, RImage *image, Pixmap *pixmap); + int (*convert_image_mask)(struct RContext *ctx, RImage *image, Pixmap *pixmap, Pixmap *mask, int threshold); } RContext; @@ -243,13 +249,13 @@ enum RImageFormat { /* * internal 24bit+alpha image representation */ -typedef struct RImage { +struct RImage { unsigned char *data; /* image data RGBA or RGB */ int width, height; /* size of the image */ enum RImageFormat format; RColor background; /* background color */ int refCount; -} RImage; +}; /*