I've encountered a problem that has me stumped.
I confess, I haven't carved a minimal program that demonstrates the
issue, but the program itself is rather
short (~200 lines). So I'll show the whole thing.
The problem manifests when I uncomment the call to
XWriteBitmapToFile from the function X11output.
I show the file with the lines in question commented
with CC+-style // comments.
With the lines uncommented, the program displays
a bitmap to stdout with # for 1 and space for 0, waits
for an enter key and then displays the same bitmap
in an X window, waits for another enter key and
terminates.
With the lines commented-out, the program displays
the ascii version fine, but shows a blank X window.
Any advice?
TIA
compile with -lm -lX11
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#define _XOPEN_SOURCE 601
#include <math.h>
#include <X11/Xlib.h>
typedef struct device {
int w,h;
void *data;
void *private;
void (*putpixel)(struct device *d, int w, int h, int col);
void (*drawline)(struct device *d, int x1, int y1, int x2, int y2,
int col);
void (*output)(struct device *d);
} device;
void ASCIIputpixel(device *d, int x, int y, int col) {
if (0 <= x && x < d->w)
if (0 <= y && y < d->h)
((unsigned char *)d->data)[d->w * y + x] = (col?'#':' ');
}
void simpleDDAdrawline(device *d, int x1, int y1, int x2, int y2, int
col) {
int len, i;
double x, y, xinc, yinc;
len = abs(x2 - x1);
if (abs(y2-y1) > len) len = abs(y2-y1);
xinc = (double)(x2-x1)/len;
yinc = (double)(y2-y1)/len;
x = x1 + 0.5;
y = y1 + 0.5;
for (i = 0; i < len; i++) {
d->putpixel(d, trunc(x), trunc(y), col);
x += xinc;
y += yinc;
}
}
void ASCIIoutput(device *d) {
int i,j;
FILE *f;
f = d->private;
for (i = 0; i < d->h; i++) {
for (j = 0; j < d->w; j++) {
fputc(((unsigned char *)d->data)[d->w*i + j], f);
}
fputc('\n',f);
}
}
device *newASCIIdevice (int w, int h, FILE *f) {
device *d;
int i;
d = malloc(sizeof *d);
d->w = w;
d->h = h;
d->data = malloc( w * h );
for (i=0; i < w * h; i++)
((unsigned char *)d->data)[i] = ' ';
d->private = f;
d->putpixel = ASCIIputpixel;
d->drawline = simpleDDAdrawline;
d->output = ASCIIoutput;
return d;
}
typedef struct Xdata {
Display *dis;
Window win;
} Xdata;
void X11putpixel (device *d, int x, int y, int col) {
if (0 <= x && x < d->w)
if (0 <= y && y < d->h)
if (col)
((unsigned char *)d->data)[y*(int)ceil((double)d->w/8)
+ (x/8)] |= 1<<(x%8);
else
((unsigned char *)d->data)[y*(int)ceil((double)d->w/8)
+ (x/8)] &= ~(1<<(x%8));
}
void X11output (device *d) {
XGCValues values;
GC gc;
Pixmap p;
values.foreground =
WhitePixel( ((Xdata *)d->private)->dis, DefaultScreen( ((Xdata
*)d->private)->dis) );
values.background =
BlackPixel( ((Xdata *)d->private)->dis, DefaultScreen( ((Xdata
*)d->private)->dis) );
gc = XCreateGC(
((Xdata *)d->private)->dis,
((Xdata *)d->private)->win,
(GCForeground | GCBackground), &values);
p = XCreatePixmapFromBitmapData(
((Xdata *)d->private)->dis,
((Xdata *)d->private)->win,
d->data, d->w, d->h,
BlackPixel( ((Xdata *)d->private)->dis, DefaultScreen( ((Xdata
*)d->private)->dis) ),
WhitePixel( ((Xdata *)d->private)->dis, DefaultScreen( ((Xdata
*)d->private)->dis) ),
DefaultDepth( ((Xdata *)d->private)->dis,
DefaultScreen( ((Xdata *)d->private)->dis) )
);
XCopyArea(
((Xdata *)d->private)->dis,
p,
((Xdata *)d->private)->win,
gc,
0, 0, d->w, d->h, 0, 0
);
/*why would the image show up only if the data is also written to
disk?*/
// XWriteBitmapFile( ((Xdata *)d->private)->dis,
// "bmp", p, d->w, d->h, -1, -1);
XFreePixmap( ((Xdata *)d->private)->dis, p);
XFreeGC( ((Xdata *)d->private)->dis, gc);
}
device *newX11device (int w, int h) {
device *d;
XEvent ev;
int i;
d = malloc(sizeof *d);
d->w = w;
d->h = h;
d->data = malloc( ceil((double)w/8) * h);
for (i=0; i < ceil((double)w/8) * h; i++)
((unsigned char *)d->data)[i] = 0;
d->private = malloc(sizeof(Xdata));
((Xdata *)d->private)->dis = XOpenDisplay(NULL);
((Xdata *)d->private)->win = XCreateSimpleWindow(
((Xdata *)d->private)->dis,
RootWindow( ((Xdata *)d->private)->dis, DefaultScreen( ((Xdata
*)d->private)->dis) ),
0, 0, w, h, 0,
BlackPixel( ((Xdata *)d->private)->dis, DefaultScreen( ((Xdata
*)d->private)->dis) ),
WhitePixel( ((Xdata *)d->private)->dis, DefaultScreen( ((Xdata
*)d->private)->dis) )
);
XMapWindow( ((Xdata *)d->private)->dis,
((Xdata *)d->private)->win );
XSelectInput(
((Xdata *)d->private)->dis,
((Xdata *)d->private)->win,
ExposureMask );
/*wait for exposure*/
do {
XNextEvent( ((Xdata *)d->private)->dis, &ev);
} while (ev.type != Expose);
d->putpixel = X11putpixel;
d->drawline = simpleDDAdrawline;
d->output = X11output;
return d;
}
int testdevice(device *d) {
int j,k;
for (j=5; j < 65; j++)
for (k=5; k < 25; k++)
d->putpixel(d, j, k, 1);
d->drawline(d, 10, 6, 50, 15, 0);
d->drawline(d, 8, 18, 45, 8, 0);
d->drawline(d, 36, 16, 31, 6, 0);
d->output(d);
fgetc(stdin);
return 0;
}
int main() {
device *d;
d = newASCIIdevice(70, 30, stdout);
testdevice(d);
d = newX11device(70, 30);
testdevice(d);
return 0;
}
--
egg on face
> With the lines commented-out, the program displays
> the ascii version fine, but shows a blank X window.
> Any advice?
>
> void X11output (device *d) {
I don't have an X system so I can only guess. But probably you're not
allowed to free the GC or the pixmap whilst the X system is drawing,
which it does via some sort of asynchronous pipeline. If you introduce
a delay the GC and bitmap are still in existence whilst the pipeline
complete, if you remove it by not writing to disk the resources vanish
and it is stuck.
Try following the copy area with XFlush(display)
Yes. It dawned on me shortly after I posted.
What's the difference between doing two things
to a piece of data and only doing it once?
Phrased this way, the answer is obvious: twice as
much data, hence buffer may or may not get filled.
--
breakfast burrito
Well, yeah partly. It's definitely an asynchronous protocol operating
either over a network or via ipc. But it is fully buffered. So the
CopyArea call should queue all the pertinent data along with the
instruction. If the window were being displayed down the street,
you wouldn't expect it to require the client to retain the source
bitmap.
On a single machine, the behavior is more difficult to model. But the
single protocol requires the system to behave "as if" the client and
server cannot readily access each other's memory.
But I think all the bitmap data gets trasmitted by the CreatePixmap
call, and CopyArea merely refers to the abstract identifier. But even
though it's all asynchronous, there is still a preservation of the
order
of the requests. The Free cannot begin until CopyArea is done despite
any communication delays.
--
chicken chimichanga
Except in this case, I think the difference is that XWriteBitmapFile()
requests data from the server, which involves an implicit flush.
Bjarni
--
INFORMATION WANTS TO BE FREE