wrlib: split RConvertImage into X11/Wayland backends
RConvertImage and RConvertImageMask now dispatch through function pointers on RContext, set during context creation: - RCreateContext sets x11_convert_image/x11_convert_image_mask - RCreateContextWayland sets wl_convert_image/wl_convert_image_mask The Wayland backend creates pixman_image_t from RImage RGBA data instead of returning NULL pixmaps, fixing the SIGSEGV in the exit dialog when compositing the application icon. X11 code moved to convert_x11.c, Wayland code in convert_wl.c. No dpy guards in the middle layer.
This commit is contained in:
parent
3edf25e0b4
commit
685eb42ecc
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
109
wrlib/convert.c
109
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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/* convert_wl.c - Wayland backend for RImage → pixman_image_t conversion */
|
||||
|
||||
#include <config.h>
|
||||
#include <pixman-1/pixman.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/* convert_x11.c - X11 backend for RImage → Pixmap conversion */
|
||||
|
||||
#include <config.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue