| 1 | < | /* Copyright (c) 1992 Regents of the University of California */ | 
| 1 | > | /* Copyright (c) 1993 Regents of the University of California */ | 
| 2 |  |  | 
| 3 |  | #ifndef lint | 
| 4 |  | static char SCCSid[] = "$SunId$ LBL"; | 
| 24 |  | #include  <X11/Xlib.h> | 
| 25 |  | #include  <X11/cursorfont.h> | 
| 26 |  | #include  <X11/Xutil.h> | 
| 27 | + | #include  <X11/Xatom.h> | 
| 28 |  |  | 
| 29 |  | #include  "color.h" | 
| 30 |  | #include  "view.h" | 
| 56 |  |  | 
| 57 |  | Window  wind = 0;                       /* our output window */ | 
| 58 |  | unsigned long  ourblack=0, ourwhite=1;  /* black and white for this visual */ | 
| 58 | – | Font  fontid;                           /* our font */ | 
| 59 | – |  | 
| 59 |  | int  maxcolors = 0;                     /* maximum colors */ | 
| 60 |  | int  greyscale = 0;                     /* in grey */ | 
| 61 |  |  | 
| 106 |  |  | 
| 107 |  | extern long  ftell(); | 
| 108 |  |  | 
| 110 | – | extern char  *malloc(), *calloc(); | 
| 111 | – |  | 
| 109 |  | Display  *thedisplay; | 
| 110 | + | Atom  closedownAtom, wmProtocolsAtom; | 
| 111 |  |  | 
| 112 |  |  | 
| 113 |  | main(argc, argv) | 
| 185 |  | if ((scanline = (COLR *)malloc(xmax*sizeof(COLR))) == NULL) | 
| 186 |  | quiterr("out of memory"); | 
| 187 |  |  | 
| 188 | < | init();                 /* get file and open window */ | 
| 188 | > | init(argc, argv);                       /* get file and open window */ | 
| 189 |  |  | 
| 190 |  | for ( ; ; ) | 
| 191 |  | getevent();             /* main loop */ | 
| 212 |  | } | 
| 213 |  |  | 
| 214 |  |  | 
| 215 | < | init()                  /* get data and open window */ | 
| 215 | > | init(argc, argv)                        /* get data and open window */ | 
| 216 | > | int argc; | 
| 217 | > | char **argv; | 
| 218 |  | { | 
| 219 | – | XWMHints        ourxwmhints; | 
| 219 |  | XSetWindowAttributes    ourwinattr; | 
| 220 | < | XSizeHints      oursizhints; | 
| 220 | > | XClassHint      xclshints; | 
| 221 | > | XWMHints        xwmhints; | 
| 222 | > | XSizeHints      xszhints; | 
| 223 | > | XTextProperty   windowName, iconName; | 
| 224 | > | XGCValues       xgcv; | 
| 225 | > | char    *name; | 
| 226 |  | register int    i; | 
| 227 |  |  | 
| 228 |  | if (fname != NULL) { | 
| 229 |  | scanpos = (long *)malloc(ymax*sizeof(long)); | 
| 230 |  | if (scanpos == NULL) | 
| 231 | < | goto memerr; | 
| 231 | > | quiterr("out of memory"); | 
| 232 |  | for (i = 0; i < ymax; i++) | 
| 233 |  | scanpos[i] = -1; | 
| 234 | < | } | 
| 234 | > | name = fname; | 
| 235 | > | } else | 
| 236 | > | name = progname; | 
| 237 | > | /* remove directory prefix from name */ | 
| 238 | > | for (i = strlen(name); i-- > 0; ) | 
| 239 | > | if (name[i] == '/') | 
| 240 | > | break; | 
| 241 | > | name += i+1; | 
| 242 |  | if ((thedisplay = XOpenDisplay(dispname)) == NULL) | 
| 243 |  | quiterr("cannot open display"); | 
| 244 |  | /* get best visual for default screen */ | 
| 246 |  | /* store image */ | 
| 247 |  | getras(); | 
| 248 |  | /* get size and position */ | 
| 249 | < | bzero((char *)&oursizhints, sizeof(oursizhints)); | 
| 250 | < | oursizhints.width = xmax; oursizhints.height = ymax; | 
| 249 | > | xszhints.flags = 0; | 
| 250 | > | xszhints.width = xmax; xszhints.height = ymax; | 
| 251 |  | if (geometry != NULL) { | 
| 252 | < | i = XParseGeometry(geometry, &oursizhints.x, &oursizhints.y, | 
| 253 | < | (unsigned *)&oursizhints.width, | 
| 254 | < | (unsigned *)&oursizhints.height); | 
| 252 | > | i = XParseGeometry(geometry, &xszhints.x, &xszhints.y, | 
| 253 | > | (unsigned *)&xszhints.width, | 
| 254 | > | (unsigned *)&xszhints.height); | 
| 255 |  | if ((i&(WidthValue|HeightValue)) == (WidthValue|HeightValue)) | 
| 256 | < | oursizhints.flags |= USSize; | 
| 256 | > | xszhints.flags |= USSize; | 
| 257 |  | else | 
| 258 | < | oursizhints.flags |= PSize; | 
| 258 | > | xszhints.flags |= PSize; | 
| 259 |  | if ((i&(XValue|YValue)) == (XValue|YValue)) { | 
| 260 | < | oursizhints.flags |= USPosition; | 
| 260 | > | xszhints.flags |= USPosition; | 
| 261 |  | if (i & XNegative) | 
| 262 | < | oursizhints.x += DisplayWidth(thedisplay, | 
| 263 | < | ourscreen)-1-oursizhints.width-2*BORWIDTH; | 
| 262 | > | xszhints.x += DisplayWidth(thedisplay, | 
| 263 | > | ourscreen)-1-xszhints.width-2*BORWIDTH; | 
| 264 |  | if (i & YNegative) | 
| 265 | < | oursizhints.y += DisplayHeight(thedisplay, | 
| 266 | < | ourscreen)-1-oursizhints.height-2*BORWIDTH; | 
| 265 | > | xszhints.y += DisplayHeight(thedisplay, | 
| 266 | > | ourscreen)-1-xszhints.height-2*BORWIDTH; | 
| 267 |  | } | 
| 268 |  | } | 
| 269 | < | /* open window */ | 
| 270 | < | ourwinattr.border_pixel = ourblack; | 
| 271 | < | ourwinattr.background_pixel = ourwhite; | 
| 269 | > | /* open window */ | 
| 270 | > | ourwinattr.border_pixel = ourwhite; | 
| 271 | > | ourwinattr.background_pixel = ourblack; | 
| 272 |  | ourwinattr.colormap = XCreateColormap(thedisplay, ourroot, | 
| 273 |  | ourvis.visual, AllocNone); | 
| 274 | < | wind = XCreateWindow(thedisplay, ourroot, oursizhints.x, oursizhints.y, | 
| 275 | < | oursizhints.width, oursizhints.height, BORWIDTH, | 
| 276 | < | ourvis.depth, InputOutput, ourvis.visual, | 
| 277 | < | CWBackPixel|CWBorderPixel|CWColormap, &ourwinattr); | 
| 274 | > | ourwinattr.event_mask = ExposureMask|KeyPressMask|ButtonPressMask| | 
| 275 | > | ButtonReleaseMask|ButtonMotionMask|StructureNotifyMask; | 
| 276 | > | ourwinattr.cursor = XCreateFontCursor(thedisplay, XC_diamond_cross); | 
| 277 | > | wind = XCreateWindow(thedisplay, ourroot, xszhints.x, xszhints.y, | 
| 278 | > | xszhints.width, xszhints.height, BORWIDTH, | 
| 279 | > | ourvis.depth, InputOutput, ourvis.visual, CWEventMask| | 
| 280 | > | CWCursor|CWBackPixel|CWBorderPixel|CWColormap, &ourwinattr); | 
| 281 |  | if (wind == 0) | 
| 282 |  | quiterr("cannot create window"); | 
| 269 | – | XFreeColormap(thedisplay, ourwinattr.colormap); | 
| 283 |  | width = xmax; | 
| 284 |  | height = ymax; | 
| 285 | < | ourgc = XCreateGC(thedisplay, wind, 0, 0); | 
| 286 | < | XSetState(thedisplay, ourgc, ourblack, ourwhite, GXcopy, AllPlanes); | 
| 287 | < | revgc = XCreateGC(thedisplay, wind, 0, 0); | 
| 275 | < | XSetFunction(thedisplay, revgc, GXinvert); | 
| 276 | < | fontid = XLoadFont(thedisplay, FONTNAME); | 
| 277 | < | if (fontid == 0) | 
| 285 | > | xgcv.foreground = ourblack; | 
| 286 | > | xgcv.background = ourwhite; | 
| 287 | > | if ((xgcv.font = XLoadFont(thedisplay, FONTNAME)) == 0) | 
| 288 |  | quiterr("cannot get font"); | 
| 289 | < | XSetFont(thedisplay, ourgc, fontid); | 
| 290 | < | XDefineCursor(thedisplay, wind, XCreateFontCursor(thedisplay, | 
| 291 | < | XC_diamond_cross)); | 
| 292 | < | XStoreName(thedisplay, wind, fname == NULL ? progname : fname); | 
| 293 | < | if (oursizhints.flags) | 
| 294 | < | XSetNormalHints(thedisplay, wind, &oursizhints); | 
| 295 | < | ourxwmhints.flags = InputHint|IconPixmapHint; | 
| 296 | < | ourxwmhints.input = True; | 
| 297 | < | ourxwmhints.icon_pixmap = XCreateBitmapFromData(thedisplay, | 
| 289 | > | ourgc = XCreateGC(thedisplay, wind, GCForeground|GCBackground| | 
| 290 | > | GCFont, &xgcv); | 
| 291 | > | xgcv.function = GXinvert; | 
| 292 | > | revgc = XCreateGC(thedisplay, wind, GCForeground|GCBackground| | 
| 293 | > | GCFunction, &xgcv); | 
| 294 | > |  | 
| 295 | > | /* set up the window manager */ | 
| 296 | > | xwmhints.flags = InputHint|IconPixmapHint; | 
| 297 | > | xwmhints.input = True; | 
| 298 | > | xwmhints.icon_pixmap = XCreateBitmapFromData(thedisplay, | 
| 299 |  | wind, icondata, iconwidth, iconheight); | 
| 300 | < | XSetWMHints(thedisplay, wind, &ourxwmhints); | 
| 301 | < | XSelectInput(thedisplay, wind, ButtonPressMask|ButtonReleaseMask | 
| 302 | < | |ButtonMotionMask|StructureNotifyMask | 
| 303 | < | |KeyPressMask|ExposureMask); | 
| 300 | > |  | 
| 301 | > | windowName.encoding = iconName.encoding = XA_STRING; | 
| 302 | > | windowName.format = iconName.format = 8; | 
| 303 | > | windowName.value = (u_char *)name; | 
| 304 | > | windowName.nitems = strlen(windowName.value); | 
| 305 | > | iconName.value = (u_char *)name; | 
| 306 | > | iconName.nitems = strlen(windowName.value); | 
| 307 | > |  | 
| 308 | > | xclshints.res_name = NULL; | 
| 309 | > | xclshints.res_class = "Ximage"; | 
| 310 | > | XSetWMProperties(thedisplay, wind, &windowName, &iconName, | 
| 311 | > | argv, argc, &xszhints, &xwmhints, &xclshints); | 
| 312 | > | closedownAtom = XInternAtom(thedisplay, "WM_DELETE_WINDOW", False); | 
| 313 | > | wmProtocolsAtom = XInternAtom(thedisplay, "WM_PROTOCOLS", False); | 
| 314 | > | XSetWMProtocols(thedisplay, wind, &closedownAtom, 1); | 
| 315 | > |  | 
| 316 |  | XMapWindow(thedisplay, wind); | 
| 317 |  | return; | 
| 295 | – | memerr: | 
| 296 | – | quiterr("out of memory"); | 
| 318 |  | } /* end of init */ | 
| 319 |  |  | 
| 320 |  |  | 
| 497 |  |  | 
| 498 |  | getevent()                              /* process the next event */ | 
| 499 |  | { | 
| 500 | < | union { | 
| 480 | < | XEvent  u; | 
| 481 | < | XConfigureEvent  c; | 
| 482 | < | XExposeEvent  e; | 
| 483 | < | XButtonPressedEvent  b; | 
| 484 | < | XKeyPressedEvent  k; | 
| 485 | < | } e; | 
| 500 | > | XEvent xev; | 
| 501 |  |  | 
| 502 | < | XNextEvent(thedisplay, &e.u); | 
| 503 | < | switch (e.u.type) { | 
| 502 | > | XNextEvent(thedisplay, &xev); | 
| 503 | > | switch ((int)xev.type) { | 
| 504 |  | case KeyPress: | 
| 505 | < | docom(&e.k); | 
| 505 | > | docom(&xev.xkey); | 
| 506 |  | break; | 
| 507 |  | case ConfigureNotify: | 
| 508 | < | width = e.c.width; | 
| 509 | < | height = e.c.height; | 
| 508 | > | width = xev.xconfigure.width; | 
| 509 | > | height = xev.xconfigure.height; | 
| 510 |  | break; | 
| 511 |  | case MapNotify: | 
| 512 |  | map_rcolors(ourras, wind); | 
| 518 |  | unmap_rcolors(ourras); | 
| 519 |  | break; | 
| 520 |  | case Expose: | 
| 521 | < | redraw(e.e.x, e.e.y, e.e.width, e.e.height); | 
| 521 | > | redraw(xev.xexpose.x, xev.xexpose.y, | 
| 522 | > | xev.xexpose.width, xev.xexpose.height); | 
| 523 |  | break; | 
| 524 |  | case ButtonPress: | 
| 525 | < | if (e.b.state & (ShiftMask|ControlMask)) | 
| 526 | < | moveimage(&e.b); | 
| 525 | > | if (xev.xbutton.state & (ShiftMask|ControlMask)) | 
| 526 | > | moveimage(&xev.xbutton); | 
| 527 | > | else if (xev.xbutton.button == Button2) | 
| 528 | > | traceray(xev.xbutton.x, xev.xbutton.y); | 
| 529 |  | else | 
| 530 | < | getbox(&e.b); | 
| 530 | > | getbox(&xev.xbutton); | 
| 531 |  | break; | 
| 532 | + | case ClientMessage: | 
| 533 | + | if ((xev.xclient.message_type == wmProtocolsAtom) && | 
| 534 | + | (xev.xclient.data.l[0] == closedownAtom)) | 
| 535 | + | quiterr(NULL); | 
| 536 | + | break; | 
| 537 |  | } | 
| 538 |  | } | 
| 539 |  |  | 
| 540 |  |  | 
| 541 | < | docom(ekey)                                     /* execute command */ | 
| 541 | > | traceray(xpos, ypos)                    /* print ray corresponding to pixel */ | 
| 542 | > | int  xpos, ypos; | 
| 543 | > | { | 
| 544 | > | FLOAT  hv[2]; | 
| 545 | > | FVECT  rorg, rdir; | 
| 546 | > |  | 
| 547 | > | if (!gotview) {         /* no view, no can do */ | 
| 548 | > | XBell(thedisplay, 0); | 
| 549 | > | return(-1); | 
| 550 | > | } | 
| 551 | > | pix2loc(hv, &inpres, xpos-xoff, ypos-yoff); | 
| 552 | > | if (viewray(rorg, rdir, &ourview, hv[0], hv[1]) < 0) | 
| 553 | > | return(-1); | 
| 554 | > | printf("%e %e %e ", rorg[0], rorg[1], rorg[2]); | 
| 555 | > | printf("%e %e %e\n", rdir[0], rdir[1], rdir[2]); | 
| 556 | > | fflush(stdout); | 
| 557 | > | return(0); | 
| 558 | > | } | 
| 559 | > |  | 
| 560 | > |  | 
| 561 | > | docom(ekey)                             /* execute command */ | 
| 562 |  | XKeyPressedEvent  *ekey; | 
| 563 |  | { | 
| 564 |  | char  buf[80]; | 
| 567 |  | int  com, n; | 
| 568 |  | double  comp; | 
| 569 |  | FLOAT  hv[2]; | 
| 527 | – | FVECT  rorg, rdir; | 
| 570 |  |  | 
| 571 |  | n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL); | 
| 572 |  | if (n == 0) | 
| 574 |  | com = buf[0]; | 
| 575 |  | switch (com) {                  /* interpret command */ | 
| 576 |  | case 'q': | 
| 577 | + | case 'Q': | 
| 578 |  | case CTRL('D'):                         /* quit */ | 
| 579 |  | quiterr(NULL); | 
| 580 |  | case '\n': | 
| 622 |  | buf, strlen(buf)); | 
| 623 |  | return(0); | 
| 624 |  | case 't':                               /* trace */ | 
| 625 | < | if (!gotview) { | 
| 583 | < | XBell(thedisplay, 0); | 
| 584 | < | return(-1); | 
| 585 | < | } | 
| 586 | < | pix2loc(hv, &inpres, ekey->x-xoff, ekey->y-yoff); | 
| 587 | < | if (viewray(rorg, rdir, &ourview, hv[0], hv[1]) < 0) | 
| 588 | < | return(-1); | 
| 589 | < | printf("%e %e %e ", rorg[0], rorg[1], rorg[2]); | 
| 590 | < | printf("%e %e %e\n", rdir[0], rdir[1], rdir[2]); | 
| 591 | < | fflush(stdout); | 
| 592 | < | return(0); | 
| 625 | > | return(traceray(ekey->x, ekey->y)); | 
| 626 |  | case '=':                               /* adjust exposure */ | 
| 627 |  | if (avgbox(cval) == -1) | 
| 628 |  | return(-1); | 
| 668 |  | moveimage(ebut)                         /* shift the image */ | 
| 669 |  | XButtonPressedEvent  *ebut; | 
| 670 |  | { | 
| 671 | < | union { | 
| 639 | < | XEvent  u; | 
| 640 | < | XButtonReleasedEvent  b; | 
| 641 | < | XPointerMovedEvent  m; | 
| 642 | < | }  e; | 
| 671 | > | XEvent  e; | 
| 672 |  | int     mxo, myo; | 
| 673 |  |  | 
| 674 | < | XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e.u); | 
| 675 | < | while (e.u.type == MotionNotify) { | 
| 676 | < | mxo = e.m.x; | 
| 677 | < | myo = e.m.y; | 
| 674 | > | XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e); | 
| 675 | > | while (e.type == MotionNotify) { | 
| 676 | > | mxo = e.xmotion.x; | 
| 677 | > | myo = e.xmotion.y; | 
| 678 |  | revline(ebut->x, ebut->y, mxo, myo); | 
| 679 |  | revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y, | 
| 680 |  | xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax); | 
| 681 | < | XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e.u); | 
| 681 | > | XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e); | 
| 682 |  | revline(ebut->x, ebut->y, mxo, myo); | 
| 683 |  | revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y, | 
| 684 |  | xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax); | 
| 685 |  | } | 
| 686 | < | xoff += e.b.x - ebut->x; | 
| 687 | < | yoff += e.b.y - ebut->y; | 
| 686 | > | xoff += e.xbutton.x - ebut->x; | 
| 687 | > | yoff += e.xbutton.y - ebut->y; | 
| 688 |  | XClearWindow(thedisplay, wind); | 
| 689 |  | redraw(0, 0, width, height); | 
| 690 |  | } | 
| 693 |  | getbox(ebut)                            /* get new box */ | 
| 694 |  | XButtonPressedEvent  *ebut; | 
| 695 |  | { | 
| 696 | < | union { | 
| 668 | < | XEvent  u; | 
| 669 | < | XButtonReleasedEvent  b; | 
| 670 | < | XPointerMovedEvent  m; | 
| 671 | < | }  e; | 
| 696 | > | XEvent  e; | 
| 697 |  |  | 
| 698 | < | XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e.u); | 
| 699 | < | while (e.u.type == MotionNotify) { | 
| 700 | < | revbox(ebut->x, ebut->y, box.xmin = e.m.x, box.ymin = e.m.y); | 
| 701 | < | XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e.u); | 
| 698 | > | XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e); | 
| 699 | > | while (e.type == MotionNotify) { | 
| 700 | > | revbox(ebut->x, ebut->y, box.xmin = e.xmotion.x, box.ymin = e.xmotion.y); | 
| 701 | > | XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e); | 
| 702 |  | revbox(ebut->x, ebut->y, box.xmin, box.ymin); | 
| 703 |  | } | 
| 704 | < | box.xmin = e.b.x<0 ? 0 : (e.b.x>=width ? width-1 : e.b.x); | 
| 705 | < | box.ymin = e.b.y<0 ? 0 : (e.b.y>=height ? height-1 : e.b.y); | 
| 704 | > | box.xmin = e.xbutton.x<0 ? 0 : (e.xbutton.x>=width ? width-1 : e.xbutton.x); | 
| 705 | > | box.ymin = e.xbutton.y<0 ? 0 : (e.xbutton.y>=height ? height-1 : e.xbutton.y); | 
| 706 |  | if (box.xmin > ebut->x) { | 
| 707 |  | box.xsiz = box.xmin - ebut->x + 1; | 
| 708 |  | box.xmin = ebut->x; |