/*LINTLIBRARY*/ /* @(#)x11.c 1.9 89/12/11 * * X11 dependent graphics routines used by popi. * written by Rich Burridge - Sun Microsystems. * * Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs. * This version is based on the code in his Prentice Hall book, * "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7, * which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. * * Permission is given to distribute these extensions, as long as these * introductory messages are not removed, and no monies are exchanged. * * No responsibility is taken for any errors or inaccuracies inherent * either to the comments or the code of this program, but if reported * (see README file) then an attempt will be made to fix them. */ #include "popi.h" #include "graphics.h" #include #include #include #include #define BOLD_FONT "helvetica-bold-14" #define DEFFONT "fixed" #define NORMAL_FONT "8x13" #define POPI_BORDER_WIDTH 2 #define FRAME_MASK (KeyPressMask | KeyReleaseMask | ExposureMask) short icon_image[] = { #include "popi.icon" } ; Atom protocol_atom, kill_atom ; Cursor busy_cursor, main_cursor ; Display *dpy ; GC gc, pix_gc ; Pixmap mpr, popi_icon, load_icon() ; Visual *visual ; Window frame, frame_icon ; XColor current_col ; XEvent event ; XFontStruct *bfont, *font, *nfont ; XGCValues gc_val ; XSetWindowAttributes attributes ; XSizeHints size ; XVisualInfo vinfo ; XWMHints wm_hints ; unsigned long gc_mask ; int screen ; unsigned int scr_depth ; unsigned long backgnd, foregnd ; unsigned long palette[CMAPLEN] ; /* 256-byte table for quickly reversing the bits in an unsigned 8-bit char, * used to convert between MSBFirst and LSBFirst image formats. */ char revtable[256] = { 0, -128, 64, -64, 32, -96, 96, -32, 16, -112, 80, -48, 48, -80, 112, -16, 8, -120, 72, -56, 40, -88, 104, -24, 24, -104, 88, -40, 56, -72, 120, -8, 4, -124, 68, -60, 36, -92, 100, -28, 20, -108, 84, -44, 52, -76, 116, -12, 12, -116, 76, -52, 44, -84, 108, -20, 28, -100, 92, -36, 60, -68, 124, -4, 2, -126, 66, -62, 34, -94, 98, -30, 18, -110, 82, -46, 50, -78, 114, -14, 10, -118, 74, -54, 42, -86, 106, -22, 26, -102, 90, -38, 58, -70, 122, -6, 6, -122, 70, -58, 38, -90, 102, -26, 22, -106, 86, -42, 54, -74, 118, -10, 14, -114, 78, -50, 46, -82, 110, -18, 30, -98, 94, -34, 62, -66, 126, -2, 1, -127, 65, -63, 33, -95, 97, -31, 17, -111, 81, -47, 49, -79, 113, -15, 9, -119, 73, -55, 41, -87, 105, -23, 25, -103, 89, -39, 57, -71, 121, -7, 5, -123, 69, -59, 37, -91, 101, -27, 21, -107, 85, -43, 53, -75, 117, -11, 13, -115, 77, -51, 45, -83, 109, -19, 29, -99, 93, -35, 61, -67, 125, -3, 3, -125, 67, -61, 35, -93, 99, -29, 19, -109, 83, -45, 51, -77, 115, -13, 11, -117, 75, -53, 43, -85, 107, -21, 27, -101, 91, -37, 59, -69, 123, -5, 7, -121, 71, -57, 39, -89, 103, -25, 23, -105, 87, -41, 55, -73, 119, -9, 15, -113, 79, -49, 47, -81, 111, -17, 31, -97, 95, -33, 63, -65, 127, -1, } ; cleanup() /* Null routine for the X11 version. */ { } /* This routine needs to be dramatically improved. It should be possible * to avoid copying the data to a separate buffer and creating a pixmap, * and send it direct to the popi frame. */ draw_scanline(line, y) /* Display image scanline on the screen. */ unsigned char *line ; int y ; { XImage *image ; int i ; if (iscolor) { mptr = (unsigned char *) Emalloc(Xsize) ; for (i = 0; i < Xsize; i++) mptr[i] = palette[255 - line[i]] ; image = XCreateImage(dpy, DefaultVisual(dpy, screen), scr_depth, ZPixmap, 0, mptr, Xsize, 1, 8, Xsize) ; mpr = XCreatePixmap(dpy, RootWindow(dpy, screen), (unsigned) image->width, (unsigned) image->height, scr_depth) ; XPutImage(dpy, mpr, pix_gc, image, 0, 0, 0, 0, (unsigned) image->width, (unsigned) image->height) ; XDestroyImage(image) ; } else { mptr = (unsigned char *) Emalloc((Xsize / 8) + 1) ; halftone(line, y) ; for (i = 0; i < (Xsize / 8) + 1; i++) mptr[i] = revtable[mptr[i]] ; mpr = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, screen), mptr, Xsize, 1, foregnd, backgnd, scr_depth) ; free(mptr) ; } XCopyArea(dpy, mpr, frame, gc, 0, 0, Xsize, 1, 0, y+100) ; XFreePixmap(dpy, mpr) ; } drawarea(x, y, width, height, op) int x, y, width, height ; enum op_type op ; { gc_val.function = ops[(int) op] ; XChangeGC(dpy, gc, GCFunction, &gc_val) ; XFillRectangle(dpy, frame, gc, x, y, (unsigned int) width, (unsigned int) height) ; XSync(dpy, 0) ; } drawline(x1, y1, x2, y2) int x1, y1, x2, y2 ; { gc_val.foreground = foregnd ; gc_val.function = GXcopy ; XChangeGC(dpy, gc, GCForeground | GCFunction, &gc_val) ; XDrawLine(dpy, frame, gc, x1, y1, x2, y2) ; } drawtext(x, y, fontno, str) enum font_type fontno ; int x, y ; char *str ; { if (fontno == NFONT) font = nfont ; else if (fontno == BFONT) font = bfont ; gc_val.font = font->fid ; gc_val.function = GXcopy ; XChangeGC(dpy, gc, GCFont | GCFunction, &gc_val) ; XDrawString(dpy, frame, gc, x, y, str, strlen(str)) ; } XFontStruct * get_font(name) char *name ; { XFontStruct *font ; if (!(font = XLoadQueryFont(dpy, name))) if (!(font = XLoadQueryFont(dpy, DEFFONT))) { perror("couldn't get the default font.") ; exit(1) ; } return(font) ; } get_next_char(c) char *c ; { XClientMessageEvent *ev ; XKeyPressedEvent *key_event ; KeySym keysym ; char chs[2] ; for (;;) { if (!XCheckMaskEvent(dpy, ExposureMask, &event)) XNextEvent(dpy, &event) ; switch (event.type) { case ClientMessage : /* Catch ICCCM kill from WM. */ ev = (XClientMessageEvent *) &event ; if (ev->message_type == protocol_atom && ev->data.l[0] == kill_atom) exit(0) ; break ; case Expose : process_expose(&event) ; break ; case KeyPress : key_event = (XKeyPressedEvent *) &event ; (void) XLookupString(key_event, chs, 1, &keysym, (XComposeStatus *) NULL) ; if (keysym == XK_Shift_L || keysym == XK_Shift_R) break ; *c = chs[0] ; return ; } } /*NOTREACHED*/ } init_fonts() { bfont = get_font(BOLD_FONT) ; nfont = get_font(NORMAL_FONT) ; nfont_width = 8 ; } init_ws_type() { if ((dpy = XOpenDisplay(x11_display)) == NULL) { FPRINTF(stderr,"%s: Couldn't open display %s\n", ProgName, (getenv ("DISPLAY") ? getenv("DISPLAY") : x11_display)) ; exit(1) ; } screen = DefaultScreen(dpy) ; if (!geometry) STRCPY(geometry, XGetDefault(dpy, ProgName, "Geometry")) ; foregnd = BlackPixel(dpy, screen) ; backgnd = WhitePixel(dpy, screen) ; scr_depth = DefaultDepth(dpy, screen) ; ops[(int) GCLR] = GXclear ; ops[(int) GSET] = GXset ; return 0 ; } /*ARGSUSED*/ static Bool is_exposed(dpy, ev, window) /* Return True if window is being exposed */ Display *dpy ; XEvent *ev ; char *window ; { if (ev->type == Expose && *((Window *) window) == ev->xkey.window) return True ; return False ; } load_colors() /* Create and load popi color map. */ { u_char red[CMAPLEN], green[CMAPLEN], blue[CMAPLEN] ; int i, numcolors ; iscolor = 0 ; if (DisplayCells(dpy, screen) > 2) { iscolor = 1 ; numcolors = 0 ; for (i = 0; i < CMAPLEN; i++) { current_col.flags = DoRed | DoGreen | DoBlue ; current_col.red = current_col.green = current_col.blue = (unsigned short) ((255 - i) << 8) ; if (XAllocColor(dpy, DefaultColormap(dpy, screen), ¤t_col) == True) palette[numcolors++] = current_col.pixel ; } if (numcolors < 2) { FPRINTF(stderr, "%s: cannot allocate colors.\n", ProgName) ; exit(1) ; } } } Pixmap load_icon(sbuf) short sbuf[] ; { char cbuf[512] ; int i ; for (i = 0; i < 256; i++) { cbuf[i*2+0] = revtable[(sbuf[i] >> 8) & 0xFF] ; cbuf[i*2+1] = revtable[sbuf[i] & 0xFF] ; } return(XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, screen), cbuf, 64, 64, foregnd, backgnd, scr_depth)) ; } make_items(argc, argv) /* Create icon, frame, canvas etc.. */ int argc ; char *argv[] ; { unsigned int h, w ; /* Window dimensions. */ int flags ; int x, y ; /* Window position. */ load_colors() ; popi_icon = load_icon(icon_image) ; size.flags = PMinSize | PMaxSize | PPosition | PSize ; size.x = 0 ; size.y = 0 ; size.max_width = size.min_width = size.width = TWIDTH ; size.max_height = size.min_height = size.height = THEIGHT ; if (strlen(geometry)) { flags = XParseGeometry(geometry, &x, &y, &w, &h) ; if (XValue & flags) { if (XNegative & flags) x = DisplayWidth(dpy, screen) + x - size.width ; size.flags |= USPosition ; size.x = x ; } if (YValue & flags) { if (YNegative & flags) y = DisplayHeight(dpy, screen) + y - size.height ; size.flags |= USPosition ; size.y = y ; } } frame = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), size.x, size.y, size.width, size.height, POPI_BORDER_WIDTH, foregnd, backgnd) ; protocol_atom = XInternAtom(dpy, "WM_PROTOCOLS", False) ; kill_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", False) ; XSetStandardProperties(dpy, frame, "popi", NULL, popi_icon, argv, argc, &size) ; wm_hints.icon_x = ix ; wm_hints.icon_y = iy ; wm_hints.input = True ; wm_hints.icon_pixmap = popi_icon ; wm_hints.flags = IconPositionHint | InputHint | IconPixmapHint ; if (iconic) { wm_hints.initial_state = IconicState ; wm_hints.flags |= StateHint ; } XSetWMHints(dpy, frame, &wm_hints) ; gc_mask = GCFont | GCForeground | GCBackground | GCGraphicsExposures ; gc_val.font = nfont->fid ; gc_val.foreground = foregnd ; gc_val.background = backgnd ; gc_val.graphics_exposures = False ; gc = XCreateGC(dpy, RootWindow(dpy, screen), gc_mask, &gc_val) ; XSetFunction(dpy, gc, GXcopy) ; pix_gc = DefaultGC(dpy, screen) ; main_cursor = XCreateFontCursor(dpy, XC_top_left_arrow) ; busy_cursor = XCreateFontCursor(dpy, XC_coffee_mug) ; } process_expose(event) XExposeEvent *event ; { int doframe ; doframe = 0 ; do { if (event->count == 0) if (event->window == frame) doframe++ ; } while (XCheckMaskEvent(dpy, ExposureMask, event)) ; if (doframe) paint_canvas() ; } set_cursor(type) enum cur_type type ; { switch (type) { case BUSY_CUR : XDefineCursor(dpy, frame, busy_cursor) ; break ; case NORMAL_CUR : XDefineCursor(dpy, frame, main_cursor) ; } } start_tool() { XSelectInput(dpy, frame, FRAME_MASK) ; XMapWindow(dpy, frame) ; }