/* * Displays a PBM file on the root. Works by selecting for Expose * events on the root rather than by setting the root window's * background-pixmap, thus reducing server memory use at the price of * having a client process around and slower repaints. * * Always displays PBM pixel value 0 as the screen's WhitePixel and PBM * pixel value 1 as the screen's BlackPixel. (These are backwards * because PBM is backwards.) * * Always tiles the root with the given PBM file. It does this by * using XPutImage multiple times. With a small tile, this is very * inefficient; in this case, use a program that sets the background * pixmap instead. */ #include #include #include #include #include #include #include #include #include extern const char *__progname; static char *displayname; static int sync = 0; static int argc; static char **argv; static Display *disp; static Screen *scr; static int width; static int height; static Window rootwin; static int (*preverr)(Display *, XErrorEvent *); static int (*prevIOerr)(Display *); static GC drawgc; static int xsize; static int ysize; static int xbytes; static unsigned char *pic; static XImage *ximg; #define roundup(x,y) ((((x)+(y)-1)/(y))*(y)) static void saveargv(int ac, char **av) { int i; int nc; char *abuf; argc = ac; argv = (char **) malloc((ac+1)*sizeof(char *)); nc = 1; for (i=0;i 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: unrecognized argument `%s'\n",__progname,*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displayname = av[skip]; continue; } if (!strcmp(*av,"-sync")) { sync = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) { exit(1); } } static void setup_image(void) { ximg = XCreateImage(disp,XDefaultVisualOfScreen(scr),1,XYBitmap,0,pic,xsize,ysize,8,xbytes); ximg->byte_order = MSBFirst; ximg->bitmap_unit = 8; ximg->bitmap_bit_order = MSBFirst; ximg->bitmap_pad = 8; ximg->bytes_per_line = xbytes; } static void setup_input(void) { XSelectInput(disp,rootwin,ExposureMask); } static void setup_gc(void) { drawgc = XCreateGC(disp,rootwin,0L,(XGCValues *)0); XSetForeground(disp,drawgc,XBlackPixelOfScreen(scr)); XSetBackground(disp,drawgc,XWhitePixelOfScreen(scr)); } static void setup_expose(void) { Window w; XSetWindowAttributes a; a.background_pixmap = None; a.override_redirect = True; a.cursor = None; w = XCreateWindow(disp,rootwin,0,0,width,height,0,XDefaultDepthOfScreen(scr),InputOutput,XDefaultVisualOfScreen(scr),CWBackPixmap|CWOverrideRedirect|CWCursor,&a); XLowerWindow(disp,w); XMapWindow(disp,w); XDestroyWindow(disp,w); } static void redisp_rect(int yo, int xo, int yf, int yt, int xf, int xt) { XPutImage(disp,rootwin,drawgc,ximg,xf,yf,xf+xo,yf+yo,xt+1-xf,yt+1-yf); } static void redisp_row(int y0, int yo_from, int yo_to, int x_from, int x_to) { if ((x_from/xsize) == (x_to/xsize)) { redisp_rect(y0,(x_from/xsize)*xsize,yo_from,yo_to,x_from%xsize,x_to%xsize); } else { redisp_rect(y0,(x_from/xsize)*xsize,yo_from,yo_to,x_from%xsize,xsize-1); x_from = ((x_from/xsize)+1) * xsize; while (x_to-x_from >= xsize-1) { redisp_rect(y0,x_from,yo_from,yo_to,0,xsize-1); x_from += xsize; } if (x_from <= x_to) { redisp_rect(y0,x_from,yo_from,yo_to,0,x_to-x_from); } } } static void redisplay(int x, int y, int w, int h, int count __attribute__((__unused__))) { if ((y/ysize) == ((y+h-1)/ysize)) { redisp_row((y/ysize)*ysize,y%ysize,(y+h-1)%ysize,x,x+w-1); } else { int y1; redisp_row((y/ysize)*ysize,y%ysize,ysize-1,x,x+w-1); y1 = y + h - 1; y = ((y/ysize)+1) * ysize; while (y1-y >= ysize-1) { redisp_row(y,0,ysize-1,x,x+w-1); y += ysize; } if (y <= y1) { redisp_row(y,0,y1-y,x,x+w-1); } } } static void handle_event(XEvent *e) { switch (e->type) { default: break; case Expose: /* XExposeEvent - xexpose */ if (e->xexpose.window == rootwin) { redisplay(e->xexpose.x,e->xexpose.y,e->xexpose.width,e->xexpose.height,e->xexpose.count); } break; } } static void run(void) { XEvent e; while (1) { XNextEvent(disp,&e); handle_event(&e); } } static int push; static int pushed = 0; static int get(void) { if (pushed) { pushed = 0; return(push); } return(getchar()); } static void unget(int v) { push = v; pushed = 1; } static void noinput(const char *why) { fprintf(stderr,"%s: can't read input: %s\n",__progname,why); exit(1); } static int readn(void) { int c; int v; v = 0; while (1) { c = get(); if (c == '#') do c = get(); while ((c != '\n') && (c != EOF)); if (c == EOF) noinput("unexpected error/eof"); if (isascii(c) && isspace(c)) continue; break; } while (isascii(c) && isdigit(c)) { v = (10 * v) + (c - '0'); c = get(); } unget(c); return(v); } static void readinput(void) { int raw; if (get() != 'P') noinput("bad magic number"); switch (get()) { default: noinput("bad magic number"); break; case '1': raw = 0; break; case '4': raw = 1; break; case '2': case '5': noinput("is a pgm file, not a pbm file"); break; case '3': case '6': noinput("is a ppm file, not a pbm file"); break; } xsize = readn(); ysize = readn(); xbytes = (xsize + 7) / 8; pic = (unsigned char *) malloc(xbytes*ysize); if (! pic) noinput("can't malloc space for it"); if (raw) { get(); fread(pic,1,xbytes*ysize,stdin); } else { int x; int y; int v; unsigned char *pp; v = 0; pp = pic; for (y=0;y> (x & 7); if ((x & 7) == 7) { *pp++ = v; v = 0; } } if (xsize & 7) { *pp++ = v; v = 0; } } } } static Display *open_display(const char *disp) { Display *rv; rv = XOpenDisplay(disp); if (rv == 0) { fprintf(stderr,"%s: can't open display %s\n",__progname,XDisplayName(disp)); exit(1); } return(rv); } static int err(Display *d, XErrorEvent *ee) { return((*preverr)(d,ee)); } static int ioerr(Display *d) { return((*prevIOerr)(d)); } int main(int, char **); int main(int ac, char **av) { saveargv(ac,av); handleargs(ac,av); readinput(); XrmInitialize(); disp = open_display(displayname); if (sync) XSynchronize(disp,True); preverr = XSetErrorHandler(err); prevIOerr = XSetIOErrorHandler(ioerr); scr = XDefaultScreenOfDisplay(disp); width = XWidthOfScreen(scr); height = XHeightOfScreen(scr); rootwin = XRootWindowOfScreen(scr); setup_image(); setup_input(); setup_gc(); setup_expose(); run(); exit(0); }