I'm trying to create server-side RGBA pixmap from client side buffer. CreatePixmap & CreateImage work ok for 32 and 24 bit, but XPutImage result in Match Error returned by server
X Error of failed request: BadMatch (invalid parameter attributes)
Major opcode of failed request: 72 (X_PutImage)
Serial number of failed request: 8
Current serial number in output stream: 8
server does support 32 bit pixmaps (xdpyinfo output: https://gist.github.com/2582961). Same behaviour on ubuntu 12.04 (X.Org version: 1.11.3) and OSX with X.app (X.Org version: 1.10.3)
Why following code fails?
#include <stdlib.h>
#include <X11/Xlib.h>
int main(int argc, char **argv)
{
int width = 100;
int height = 100;
int depth = 32; // works fine with depth = 24
int bitmap_pad = 32; // 32 for 24 and 32 bpp, 16, for 15&16
int bytes_per_line = 0; // number of bytes in the client image between the start of one scanline and the start of the next
Display *display=XOpenDisplay(0);
unsigned char *image32=(unsigned char *)malloc(width*height*4);
XImage *img = XCreateImage(display, CopyFromParent, depth, ZPixmap, 0, image32, width, height, bitmap_pad, bytes_per_line);
Pixmap p = XCreatePixmap(display, XDefaultRootWindow(display), width, height, depth);
XPutImage(display, p, DefaultGC(display, 0), img, 0, 0, 0, 0, width, height); // 0, 0, 0, 0 are src x,y and dst x,y
XEvent ev;
while (1) {
XNextEvent(display, &ev);
}
}
Update: It looks like I finally got answer: use GC associated with pixmap instead of DefaultGC (which has depth of root window)
#include <stdlib.h>
#include <X11/Xlib.h>
int main(int argc, char **argv)
{
int width = 100;
int height = 100;
int depth = 32; // works fine with depth = 24
int bitmap_pad = 32; // 32 for 24 and 32 bpp, 16, for 15&16
int bytes_per_line = 0; // number of bytes in the client image between the start of one scanline and the start of the next
Display *display=XOpenDisplay(0);
unsigned char *image32=(unsigned char *)malloc(width*height*4);
XImage *img = XCreateImage(display, CopyFromParent, depth, ZPixmap, 0, image32, width, height, bitmap_pad, bytes_per_line);
Pixmap p = XCreatePixmap(display, XDefaultRootWindow(display), width, height, depth);
XGCValues gcvalues;
GC gc = XCreateGC(display, p, 0, &gcvalues);
XPutImage(display, p, gc, img, 0, 0, 0, 0, width, height); // 0, 0, 0, 0 are src x,y and dst x,y
XEvent ev;
while (1) {
XNextEvent(display, &ev);
}
}
The problem is with DefaultGC()
which return a GC with bit depth of system default screen. If you look at line 53 of your gist paste you see that this is 24:
depth of root window: 24 planes
On line 63 you see that it uses 0x22 as default which is shown in more detail in line 64 to 70:
visual:
visual id: 0x22
class: TrueColor
depth: 24 planes
available colormap entries: 256 per subfield
red, green, blue masks: 0xff0000, 0xff00, 0xff
significant bits in color specification: 8 bits
You could probably do this a bit nicer but as a start you can try this:
Note: This uses system visuals so most probably only support depth of 24 or 32.
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef DEBUG
int dbg = 1;
#else
int dbg = 0;
#endif
/* Return a GC based on depth */
int gc_depth(int depth, Display *dpy, Window scr, Window root, GC *gc)
{
Window win;
Visual *visual;
XVisualInfo vis_info;
XSetWindowAttributes win_attr;
unsigned long win_mask;
if(!XMatchVisualInfo(dpy, scr, depth, TrueColor, &vis_info)) {
fprintf(stderr,
" * ERR: %d depth not supported\n",
depth
);
return 1;
}
visual = vis_info.visual;
win_attr.colormap = XCreateColormap(dpy, root, visual, AllocNone);
win_attr.background_pixel = 0;
win_attr.border_pixel = 0;
win_mask = CWBackPixel | CWColormap | CWBorderPixel;
win = XCreateWindow(
dpy, root,
0, 0,
100, 100, /* dummy size */
0, depth,
InputOutput, visual,
win_mask, &win_attr);
/* To flush out any errors */
if (dbg) XSync(dpy, True);
*gc = XCreateGC(dpy, win, 0, 0);
if (dbg) XSync(dpy, True);
XDestroyWindow(dpy, win);
if (dbg) XSync(dpy, True);
return 0;
}
int main(void)
{
int w = 100;
int h = 100;
int depth = 32;
int bitmap_pad = 32;
int bpl = 0;
Display *dpy;
Window root;
Window scr;
GC gc;
int root_depth;
Pixmap pm;
XImage *img;
unsigned char *buf_img;
if(!(dpy = XOpenDisplay(NULL))) {
fprintf(stderr,
" * ERR: Failed to open display.\n");
return 1;
}
#ifdef DEBUG
/* To get errors in order, slows down
* One can also define int _Xdebug = 1;
* */
XSynchronize(dpy, True);
#endif
root = XDefaultRootWindow(dpy);
scr = XDefaultScreen(dpy);
if ((buf_img = malloc(w * h * 4)) == NULL) {
fprintf(stderr,
" * ERR: Unable to alloacte %d bytes\n",
w * h * 4);
return 1;
}
root_depth = DefaultDepth(dpy, scr);
fprintf(stderr,
"Default depth: %d\n",
root_depth);
/* This should be doen more nice */
if (depth != root_depth) {
if (gc_depth(depth, dpy, scr, root, &gc) != 0)
return 1;
} else {
gc = DefaultGC(dpy, 0);
}
img = XCreateImage(
dpy, CopyFromParent,
depth, ZPixmap,
0, (char *)buf_img,
w, h,
bitmap_pad, bpl);
/* To flush out any errors */
if (dbg) XSync(dpy, True);
pm = XCreatePixmap(
dpy, root,
w, h,
depth);
if (dbg) XSync(dpy, True);
XPutImage(
dpy, pm,
gc, img,
0, 0,
0, 0,
w, h);
if (dbg) XSync(dpy, True);
XFreePixmap(dpy, pm);
XDestroyImage(img);
XFreeGC(dpy, gc);
if (dbg) XSync(dpy, True);
fprintf(stderr,
"OK!\n");
return 0;
}