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 \
|
xpixmap.c \
|
||||||
convert.h \
|
convert.h \
|
||||||
convert.c \
|
convert.c \
|
||||||
|
convert_funcs.h \
|
||||||
|
convert_x11.c \
|
||||||
|
convert_wl.c \
|
||||||
context.c \
|
context.c \
|
||||||
misc.c \
|
misc.c \
|
||||||
scale.c \
|
scale.c \
|
||||||
|
|
@ -82,7 +85,7 @@ libwraster_la_SOURCES += load_magick.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
AM_CFLAGS = @MAGICKFLAGS@
|
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
|
libwraster_la_LIBADD = @LIBRARY_SEARCH_PATH@ @GFXLIBS@ @MAGICKLIBS@ @XLIBS@ @LIBXMU@ -lm
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@
|
||||||
#include "wraster.h"
|
#include "wraster.h"
|
||||||
#include "scale.h"
|
#include "scale.h"
|
||||||
#include "wr_i18n.h"
|
#include "wr_i18n.h"
|
||||||
|
#include "convert_funcs.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_FLOAT_MATHFUNC
|
#ifndef HAVE_FLOAT_MATHFUNC
|
||||||
|
|
@ -656,6 +657,9 @@ RContext *RCreateContext(Display * dpy, int screen_number, const RContextAttribu
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
context->convert_image = x11_convert_image;
|
||||||
|
context->convert_image_mask = x11_convert_image_mask;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -761,5 +765,8 @@ RContext *RCreateContextWayland(int width, int height,
|
||||||
(void)width;
|
(void)width;
|
||||||
(void)height;
|
(void)height;
|
||||||
|
|
||||||
|
context->convert_image = wl_convert_image;
|
||||||
|
context->convert_image_mask = wl_convert_image_mask;
|
||||||
|
|
||||||
return context;
|
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;
|
RXImage *ximg;
|
||||||
unsigned short rmask, gmask, bmask;
|
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;
|
RXImage *ximg;
|
||||||
register int x, y, r, g, b;
|
register int x, y, r, g, b;
|
||||||
|
|
@ -565,7 +565,7 @@ static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
|
||||||
/*
|
/*
|
||||||
* For standard colormap
|
* For standard colormap
|
||||||
*/
|
*/
|
||||||
static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
|
RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
|
||||||
{
|
{
|
||||||
RXImage *ximg;
|
RXImage *ximg;
|
||||||
register int x, y, r, g, b;
|
register int x, y, r, g, b;
|
||||||
|
|
@ -715,7 +715,7 @@ static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
|
||||||
return ximg;
|
return ximg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RXImage *image2GrayScale(RContext * ctx, RImage * image)
|
RXImage *image2GrayScale(RContext * ctx, RImage * image)
|
||||||
{
|
{
|
||||||
RXImage *ximg;
|
RXImage *ximg;
|
||||||
register int x, y, g;
|
register int x, y, g;
|
||||||
|
|
@ -838,7 +838,7 @@ static RXImage *image2GrayScale(RContext * ctx, RImage * image)
|
||||||
return ximg;
|
return ximg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
|
RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
|
||||||
{
|
{
|
||||||
RXImage *ximg;
|
RXImage *ximg;
|
||||||
unsigned char *alpha;
|
unsigned char *alpha;
|
||||||
|
|
@ -862,74 +862,11 @@ static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
|
||||||
|
|
||||||
int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
|
int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
|
||||||
{
|
{
|
||||||
RXImage *ximg = NULL;
|
|
||||||
#ifdef USE_XSHM
|
|
||||||
Pixmap tmp;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert(context != NULL);
|
assert(context != NULL);
|
||||||
assert(image != NULL);
|
assert(image != NULL);
|
||||||
assert(pixmap != NULL);
|
assert(pixmap != NULL);
|
||||||
|
|
||||||
/* Wayland mode: no X11 display, pixmaps are not used */
|
return context->convert_image(context, image, pixmap);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make the gc permanent (create with context creation).
|
/* 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)
|
int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
|
||||||
{
|
{
|
||||||
GC gc;
|
|
||||||
XGCValues gcv;
|
|
||||||
RXImage *ximg = NULL;
|
|
||||||
|
|
||||||
assert(context != NULL);
|
assert(context != NULL);
|
||||||
assert(image != NULL);
|
assert(image != NULL);
|
||||||
assert(pixmap != NULL);
|
assert(pixmap != NULL);
|
||||||
assert(mask != NULL);
|
assert(mask != NULL);
|
||||||
|
|
||||||
if (!context->dpy) {
|
return context->convert_image_mask(context, image, pixmap, mask, threshold);
|
||||||
*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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool RGetClosestXColor(RContext * context, const RColor * color, XColor * retColor)
|
Bool RGetClosestXColor(RContext * context, const RColor * color, XColor * retColor)
|
||||||
|
|
|
||||||
|
|
@ -35,5 +35,11 @@
|
||||||
*/
|
*/
|
||||||
void r_destroy_conversion_tables(void);
|
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
|
#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
|
* we can use, if we should do dithering, and what colors to use for
|
||||||
* dithering.
|
* dithering.
|
||||||
*/
|
*/
|
||||||
|
typedef struct RImage RImage;
|
||||||
|
|
||||||
typedef struct RContext {
|
typedef struct RContext {
|
||||||
Display *dpy;
|
Display *dpy;
|
||||||
int screen_number;
|
int screen_number;
|
||||||
|
|
@ -203,6 +205,10 @@ typedef struct RContext {
|
||||||
__wrlib_deprecated("Flag optimize_for_speed in RContext is not used anymore "
|
__wrlib_deprecated("Flag optimize_for_speed in RContext is not used anymore "
|
||||||
"and will be removed in future version, please do not use");
|
"and will be removed in future version, please do not use");
|
||||||
} flags;
|
} 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;
|
} RContext;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -243,13 +249,13 @@ enum RImageFormat {
|
||||||
/*
|
/*
|
||||||
* internal 24bit+alpha image representation
|
* internal 24bit+alpha image representation
|
||||||
*/
|
*/
|
||||||
typedef struct RImage {
|
struct RImage {
|
||||||
unsigned char *data; /* image data RGBA or RGB */
|
unsigned char *data; /* image data RGBA or RGB */
|
||||||
int width, height; /* size of the image */
|
int width, height; /* size of the image */
|
||||||
enum RImageFormat format;
|
enum RImageFormat format;
|
||||||
RColor background; /* background color */
|
RColor background; /* background color */
|
||||||
int refCount;
|
int refCount;
|
||||||
} RImage;
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue