| 1 | #ifndef lint | 
| 2 | static const char       RCSid[] = "$Id: x11.c,v 2.37 2024/08/05 21:54:01 greg Exp $"; | 
| 3 | #endif | 
| 4 | /* | 
| 5 | *  x11.c - driver for X-windows version 11 | 
| 6 | */ | 
| 7 |  | 
| 8 | #include "copyright.h" | 
| 9 |  | 
| 10 | #include  "standard.h" | 
| 11 | #include  <sys/ioctl.h> | 
| 12 | #if  !defined(FNDELAY) && defined(O_NONBLOCK) | 
| 13 | #define  FNDELAY  O_NONBLOCK | 
| 14 | #endif | 
| 15 |  | 
| 16 | #include  <X11/Xlib.h> | 
| 17 | #include  <X11/cursorfont.h> | 
| 18 | #include  <X11/Xutil.h> | 
| 19 |  | 
| 20 | #include  "platform.h" | 
| 21 | #include  "color.h" | 
| 22 | #include  "driver.h" | 
| 23 | #include  "x11twind.h" | 
| 24 | #include  "x11icon.h" | 
| 25 |  | 
| 26 | #define GAMMA           2.2             /* default exponent correction */ | 
| 27 |  | 
| 28 | #define MINWIDTH        (32*COMCW)      /* minimum graphics window width */ | 
| 29 | #define MINHEIGHT       (MINWIDTH/2)    /* minimum graphics window height */ | 
| 30 |  | 
| 31 | #define BORWIDTH        5               /* border width */ | 
| 32 | #define COMHEIGHT       (COMLH*COMCH)   /* command line height (pixels) */ | 
| 33 |  | 
| 34 | #define COMFN           "8x13"          /* command line font name */ | 
| 35 | #define COMLH           3               /* number of command lines */ | 
| 36 | #define COMCW           8               /* approx. character width (pixels) */ | 
| 37 | #define COMCH           14              /* approx. character height (pixels) */ | 
| 38 |  | 
| 39 | #define  ourscreen      DefaultScreen(ourdisplay) | 
| 40 | #define  ourroot        RootWindow(ourdisplay,ourscreen) | 
| 41 |  | 
| 42 | #define  levptr(etype)  ((etype *)¤tevent) | 
| 43 |  | 
| 44 | static XEvent  currentevent;            /* current event */ | 
| 45 |  | 
| 46 | static int  ncolors = 0;                /* color table size */ | 
| 47 | static int  mapped = 0;                 /* window is mapped? */ | 
| 48 | static unsigned long  *pixval = NULL;   /* allocated pixels */ | 
| 49 | static unsigned long  ourblack=0, ourwhite=1; | 
| 50 |  | 
| 51 | static Display  *ourdisplay = NULL;     /* our display */ | 
| 52 |  | 
| 53 | static XVisualInfo  ourvinfo;           /* our visual information */ | 
| 54 |  | 
| 55 | static Window  gwind = 0;               /* our graphics window */ | 
| 56 |  | 
| 57 | static Cursor  pickcursor = 0;          /* cursor used for picking */ | 
| 58 |  | 
| 59 | static int  gwidth, gheight;            /* graphics window size */ | 
| 60 |  | 
| 61 | static int  comheight;                  /* desired comline height */ | 
| 62 | static TEXTWIND  *comline = NULL;       /* our command line */ | 
| 63 |  | 
| 64 | static char  c_queue[64];               /* input queue */ | 
| 65 | static int  c_first = 0;                /* first character in queue */ | 
| 66 | static int  c_last = 0;                 /* last character in queue */ | 
| 67 |  | 
| 68 | static GC  ourgc = 0;                   /* our graphics context for drawing */ | 
| 69 |  | 
| 70 | static Colormap ourmap = 0;             /* our color map */ | 
| 71 |  | 
| 72 | #define IC_X11          0 | 
| 73 | #define IC_IOCTL        1 | 
| 74 | #define IC_READ         2 | 
| 75 |  | 
| 76 | static int  inpcheck;                   /* whence to check input */ | 
| 77 |  | 
| 78 | static void x11_errout(char  *msg); | 
| 79 |  | 
| 80 | static dr_closef_t x11_close; | 
| 81 | static dr_clearf_t x11_clear; | 
| 82 | static dr_paintrf_t x11_paintr; | 
| 83 | static dr_getcurf_t x11_getcur; | 
| 84 | static dr_comoutf_t x11_comout; | 
| 85 | static dr_cominf_t x11_comin; | 
| 86 | static dr_flushf_t x11_flush; | 
| 87 |  | 
| 88 | static dr_cominf_t std_comin; | 
| 89 | static dr_comoutf_t std_comout; | 
| 90 |  | 
| 91 | static struct driver  x11_driver = { | 
| 92 | x11_close, x11_clear, x11_paintr, x11_getcur, | 
| 93 | NULL, NULL, x11_flush, 1.0 | 
| 94 | }; | 
| 95 |  | 
| 96 | static dr_getchf_t x11_getc; | 
| 97 |  | 
| 98 | static void freepixels(void); | 
| 99 | static int getpixels(void); | 
| 100 | static dr_newcolrf_t xnewcolr; | 
| 101 | static unsigned long true_pixel(COLOR  col); | 
| 102 | static void getevent(void); | 
| 103 | static void getkey(XKeyPressedEvent  *ekey); | 
| 104 | static void fixwindow(XExposeEvent  *eexp); | 
| 105 | static void resizewindow(XConfigureEvent  *ersz); | 
| 106 |  | 
| 107 | extern dr_initf_t x11_init; /* XXX this should be in a seperate header file */ | 
| 108 |  | 
| 109 |  | 
| 110 | extern struct driver * | 
| 111 | x11_init(               /* initialize driver */ | 
| 112 | char  *name, | 
| 113 | char  *id | 
| 114 | ) | 
| 115 | { | 
| 116 | char  *gv; | 
| 117 | int  nplanes; | 
| 118 | XSetWindowAttributes    ourwinattr; | 
| 119 | XWMHints  ourxwmhints; | 
| 120 | XSizeHints      oursizhints; | 
| 121 | /* open display server */ | 
| 122 | ourdisplay = XOpenDisplay(NULL); | 
| 123 | if (ourdisplay == NULL) { | 
| 124 | eputs("cannot open X-windows; DISPLAY variable set?\n"); | 
| 125 | return(NULL); | 
| 126 | } | 
| 127 | /* find a usable visual */ | 
| 128 | nplanes = DisplayPlanes(ourdisplay, ourscreen); | 
| 129 | if (XMatchVisualInfo(ourdisplay,ourscreen, | 
| 130 | nplanes>12?nplanes:24,TrueColor,&ourvinfo) || | 
| 131 | XMatchVisualInfo(ourdisplay,ourscreen, | 
| 132 | nplanes>12?nplanes:24,DirectColor,&ourvinfo)) { | 
| 133 | ourblack = 0; | 
| 134 | ourwhite = ourvinfo.red_mask | | 
| 135 | ourvinfo.green_mask | | 
| 136 | ourvinfo.blue_mask ; | 
| 137 | } else { | 
| 138 | if (nplanes < 4) { | 
| 139 | eputs("not enough colors\n"); | 
| 140 | return(NULL); | 
| 141 | } | 
| 142 | if (!XMatchVisualInfo(ourdisplay,ourscreen, | 
| 143 | nplanes,PseudoColor,&ourvinfo) && | 
| 144 | !XMatchVisualInfo(ourdisplay,ourscreen, | 
| 145 | nplanes,GrayScale,&ourvinfo)) { | 
| 146 | eputs("unsupported visual type\n"); | 
| 147 | return(NULL); | 
| 148 | } | 
| 149 | ourblack = BlackPixel(ourdisplay,ourscreen); | 
| 150 | ourwhite = WhitePixel(ourdisplay,ourscreen); | 
| 151 | } | 
| 152 | /* set gamma */ | 
| 153 | if ((gv = XGetDefault(ourdisplay, "radiance", "gamma")) != NULL | 
| 154 | || (gv = getenv("DISPLAY_GAMMA")) != NULL) | 
| 155 | make_gmap(atof(gv)); | 
| 156 | else | 
| 157 | make_gmap(GAMMA); | 
| 158 | /* X11 command line or no? */ | 
| 159 | if (!strcmp(name, "x11")) | 
| 160 | comheight = COMHEIGHT; | 
| 161 | else /* "x11d" */ { | 
| 162 | comheight = 0; | 
| 163 | #ifndef  FNDELAY | 
| 164 | eputs("warning: x11d driver not fully functional on this machine\n"); | 
| 165 | #endif | 
| 166 | } | 
| 167 | /* open window */ | 
| 168 | ourwinattr.background_pixel = ourblack; | 
| 169 | ourwinattr.border_pixel = ourblack; | 
| 170 | /* this is stupid */ | 
| 171 | ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot, | 
| 172 | ourvinfo.visual, AllocNone); | 
| 173 | gwind = XCreateWindow(ourdisplay, ourroot, 0, 0, | 
| 174 | DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH, | 
| 175 | DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH, | 
| 176 | BORWIDTH, ourvinfo.depth, InputOutput, ourvinfo.visual, | 
| 177 | CWBackPixel|CWBorderPixel|CWColormap, &ourwinattr); | 
| 178 | if (gwind == 0) { | 
| 179 | eputs("cannot create window\n"); | 
| 180 | return(NULL); | 
| 181 | } | 
| 182 | XStoreName(ourdisplay, gwind, id); | 
| 183 | /* create a cursor */ | 
| 184 | pickcursor = XCreateFontCursor(ourdisplay, XC_diamond_cross); | 
| 185 | ourgc = XCreateGC(ourdisplay, gwind, 0, NULL); | 
| 186 | ourxwmhints.flags = InputHint|IconPixmapHint; | 
| 187 | ourxwmhints.input = True; | 
| 188 | ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay, | 
| 189 | gwind, x11icon_bits, x11icon_width, x11icon_height); | 
| 190 | XSetWMHints(ourdisplay, gwind, &ourxwmhints); | 
| 191 | oursizhints.min_width = MINWIDTH; | 
| 192 | oursizhints.min_height = MINHEIGHT+comheight; | 
| 193 | oursizhints.flags = PMinSize; | 
| 194 | XSetNormalHints(ourdisplay, gwind, &oursizhints); | 
| 195 | XSelectInput(ourdisplay, gwind, ExposureMask); | 
| 196 | XMapWindow(ourdisplay, gwind); | 
| 197 | XWindowEvent(ourdisplay, gwind, ExposureMask, levptr(XEvent)); | 
| 198 | gwidth = levptr(XExposeEvent)->width; | 
| 199 | gheight = levptr(XExposeEvent)->height - comheight; | 
| 200 | x11_driver.xsiz = gwidth < MINWIDTH ? MINWIDTH : gwidth; | 
| 201 | x11_driver.ysiz = gheight < MINHEIGHT ? MINHEIGHT : gheight; | 
| 202 | x11_driver.inpready = 0; | 
| 203 | mapped = 1; | 
| 204 | /* set i/o vectors */ | 
| 205 | if (comheight) { | 
| 206 | x11_driver.comin = x11_comin; | 
| 207 | x11_driver.comout = x11_comout; | 
| 208 | erract[COMMAND].pf = x11_comout; | 
| 209 | /*                      doesn't work with raypcalls.c | 
| 210 | if (erract[WARNING].pf != NULL) | 
| 211 | erract[WARNING].pf = x11_errout; | 
| 212 | */ | 
| 213 | inpcheck = IC_X11; | 
| 214 | } else { | 
| 215 | x11_driver.comin = std_comin; | 
| 216 | x11_driver.comout = std_comout; | 
| 217 | erract[COMMAND].pf = std_comout; | 
| 218 | inpcheck = IC_IOCTL; | 
| 219 | } | 
| 220 | return(&x11_driver); | 
| 221 | } | 
| 222 |  | 
| 223 |  | 
| 224 | static void | 
| 225 | x11_close(void)                 /* close our display */ | 
| 226 | { | 
| 227 | erract[COMMAND].pf = NULL;              /* reset error vectors */ | 
| 228 | if (erract[WARNING].pf != NULL) | 
| 229 | erract[WARNING].pf = wputs; | 
| 230 | if (ourdisplay == NULL) | 
| 231 | return; | 
| 232 | if (comline != NULL) { | 
| 233 | xt_close(comline); | 
| 234 | comline = NULL; | 
| 235 | } | 
| 236 | freepixels(); | 
| 237 | XFreeGC(ourdisplay, ourgc); | 
| 238 | XDestroyWindow(ourdisplay, gwind); | 
| 239 | gwind = 0; | 
| 240 | ourgc = 0; | 
| 241 | XFreeCursor(ourdisplay, pickcursor); | 
| 242 | XCloseDisplay(ourdisplay); | 
| 243 | ourdisplay = NULL; | 
| 244 | } | 
| 245 |  | 
| 246 |  | 
| 247 | static void | 
| 248 | x11_clear(                      /* clear our display */ | 
| 249 | int  xres, | 
| 250 | int  yres | 
| 251 | ) | 
| 252 | { | 
| 253 | /* check limits */ | 
| 254 | if (xres < MINWIDTH) | 
| 255 | xres = MINWIDTH; | 
| 256 | if (yres < MINHEIGHT) | 
| 257 | yres = MINHEIGHT; | 
| 258 | /* resize window */ | 
| 259 | if ((xres != gwidth) | (yres != gheight)) { | 
| 260 | XSelectInput(ourdisplay, gwind, 0); | 
| 261 | XResizeWindow(ourdisplay, gwind, xres, yres+comheight); | 
| 262 | gwidth = xres; | 
| 263 | gheight = yres; | 
| 264 | XFlush(ourdisplay); | 
| 265 | sleep(2);                       /* wait for window manager */ | 
| 266 | XSync(ourdisplay, 1);           /* discard input */ | 
| 267 | } | 
| 268 | XClearWindow(ourdisplay, gwind); | 
| 269 | /* reinitialize color table */ | 
| 270 | if ((ourvinfo.class == PseudoColor) | (ourvinfo.class == GrayScale)) { | 
| 271 | if (getpixels() == 0) | 
| 272 | eputs("cannot allocate colors\n"); | 
| 273 | else | 
| 274 | new_ctab(ncolors); | 
| 275 | } | 
| 276 | /* get new command line */ | 
| 277 | if (comline != NULL) | 
| 278 | xt_close(comline); | 
| 279 | if (comheight) { | 
| 280 | comline = xt_open(ourdisplay, gwind, 0, gheight, gwidth, | 
| 281 | comheight, 0, ourblack, ourwhite, COMFN); | 
| 282 | if (comline == NULL) { | 
| 283 | eputs("cannot open command line window\n"); | 
| 284 | quit(1); | 
| 285 | } | 
| 286 | XSelectInput(ourdisplay, comline->w, ExposureMask); | 
| 287 | /* remove earmuffs */ | 
| 288 | XSelectInput(ourdisplay, gwind, | 
| 289 | StructureNotifyMask|ExposureMask|KeyPressMask|ButtonPressMask); | 
| 290 | } else                                  /* remove earmuffs */ | 
| 291 | XSelectInput(ourdisplay, gwind, | 
| 292 | StructureNotifyMask|ExposureMask|ButtonPressMask); | 
| 293 | } | 
| 294 |  | 
| 295 |  | 
| 296 | static void | 
| 297 | x11_paintr(             /* fill a rectangle */ | 
| 298 | COLOR  col, | 
| 299 | int  xmin, | 
| 300 | int  ymin, | 
| 301 | int  xmax, | 
| 302 | int  ymax | 
| 303 | ) | 
| 304 | { | 
| 305 | unsigned long  pixel; | 
| 306 |  | 
| 307 | if (!mapped) | 
| 308 | return; | 
| 309 | if (ncolors > 0) | 
| 310 | pixel = pixval[get_pixel(col, xnewcolr)]; | 
| 311 | else | 
| 312 | pixel = true_pixel(col); | 
| 313 | XSetForeground(ourdisplay, ourgc, pixel); | 
| 314 | XFillRectangle(ourdisplay, gwind, | 
| 315 | ourgc, xmin, gheight-ymax, xmax-xmin, ymax-ymin); | 
| 316 | } | 
| 317 |  | 
| 318 |  | 
| 319 | static void | 
| 320 | x11_flush(void)                 /* flush output */ | 
| 321 | { | 
| 322 | char    buf[256]; | 
| 323 | int     n; | 
| 324 | /* check for input */ | 
| 325 | XNoOp(ourdisplay); | 
| 326 | n = XPending(ourdisplay);                       /* from X server */ | 
| 327 | while (n-- > 0) | 
| 328 | getevent(); | 
| 329 | #ifdef FNDELAY | 
| 330 | if (inpcheck == IC_IOCTL) {                     /* from stdin */ | 
| 331 | #ifdef FIONREAD | 
| 332 | if (ioctl(fileno(stdin), FIONREAD, &n) < 0) { | 
| 333 | #else | 
| 334 | if (1) { | 
| 335 | #endif | 
| 336 | if (fcntl(fileno(stdin), F_SETFL, FNDELAY) < 0) { | 
| 337 | eputs("cannot change input mode\n"); | 
| 338 | quit(1); | 
| 339 | } | 
| 340 | inpcheck = IC_READ; | 
| 341 | } else | 
| 342 | x11_driver.inpready += n; | 
| 343 | } | 
| 344 | if (inpcheck == IC_READ) { | 
| 345 | n = read(fileno(stdin), buf, sizeof(buf)-1); | 
| 346 | if (n > 0) { | 
| 347 | buf[n] = '\0'; | 
| 348 | tocombuf(buf, &x11_driver); | 
| 349 | } | 
| 350 | } | 
| 351 | #endif | 
| 352 | } | 
| 353 |  | 
| 354 |  | 
| 355 | static void | 
| 356 | x11_comin(              /* read in a command line */ | 
| 357 | char  *inp, | 
| 358 | char  *prompt | 
| 359 | ) | 
| 360 | { | 
| 361 | if (prompt != NULL) { | 
| 362 | x11_flush();            /* make sure we get everything */ | 
| 363 | if (fromcombuf(inp, &x11_driver)) | 
| 364 | return; | 
| 365 | xt_puts(prompt, comline); | 
| 366 | } | 
| 367 | xt_cursor(comline, TBLKCURS); | 
| 368 | editline(inp, x11_getc, x11_comout); | 
| 369 | xt_cursor(comline, TNOCURS); | 
| 370 | } | 
| 371 |  | 
| 372 |  | 
| 373 | static void | 
| 374 | x11_comout(             /* output a string to command line */ | 
| 375 | const char  *outp | 
| 376 | ) | 
| 377 | { | 
| 378 | if ((comline == NULL) | (outp == NULL) || !outp[0]) | 
| 379 | return; | 
| 380 | xt_puts(outp, comline); | 
| 381 | if (outp[strlen(outp)-1] == '\n') | 
| 382 | XFlush(ourdisplay); | 
| 383 | } | 
| 384 |  | 
| 385 |  | 
| 386 | static void | 
| 387 | x11_errout(                     /* output an error message */ | 
| 388 | char  *msg | 
| 389 | ) | 
| 390 | { | 
| 391 | eputs(msg);             /* send to stderr also! */ | 
| 392 | x11_comout(msg); | 
| 393 | } | 
| 394 |  | 
| 395 |  | 
| 396 | static void | 
| 397 | std_comin(              /* read in command line from stdin */ | 
| 398 | char  *inp, | 
| 399 | char  *prompt | 
| 400 | ) | 
| 401 | { | 
| 402 | int     n, c; | 
| 403 |  | 
| 404 | if (prompt != NULL) { | 
| 405 | if (fromcombuf(inp, &x11_driver)) | 
| 406 | return; | 
| 407 | if (!x11_driver.inpready) | 
| 408 | std_comout(prompt); | 
| 409 | } | 
| 410 | #ifdef FNDELAY | 
| 411 | if (inpcheck == IC_READ) {      /* turn off FNDELAY */ | 
| 412 | if (fcntl(fileno(stdin), F_SETFL, 0) < 0) { | 
| 413 | eputs("cannot change input mode\n"); | 
| 414 | quit(1); | 
| 415 | } | 
| 416 | inpcheck = IC_IOCTL; | 
| 417 | } | 
| 418 | #endif | 
| 419 | n = 0;          /* gets() no longer exists... */ | 
| 420 | while ((c = getchar()) != EOF && c != '\n') | 
| 421 | inp[n++] = c; | 
| 422 |  | 
| 423 | if (!n & (c == EOF)) { | 
| 424 | strcpy(inp, "quit"); | 
| 425 | return; | 
| 426 | } | 
| 427 | inp[n] = '\0'; | 
| 428 | x11_driver.inpready -= n + 1; | 
| 429 | x11_driver.inpready *= (x11_driver.inpready > 0); | 
| 430 | } | 
| 431 |  | 
| 432 |  | 
| 433 | static void | 
| 434 | std_comout(             /* write out string to stdout */ | 
| 435 | const char      *outp | 
| 436 | ) | 
| 437 | { | 
| 438 | fputs(outp, stdout); | 
| 439 | fflush(stdout); | 
| 440 | } | 
| 441 |  | 
| 442 |  | 
| 443 | static int | 
| 444 | x11_getcur(             /* get cursor position */ | 
| 445 | int  *xp, | 
| 446 | int  *yp | 
| 447 | ) | 
| 448 | { | 
| 449 | while (XGrabPointer(ourdisplay, gwind, True, ButtonPressMask, | 
| 450 | GrabModeAsync, GrabModeAsync, None, pickcursor, | 
| 451 | CurrentTime) != GrabSuccess) | 
| 452 | sleep(2); | 
| 453 |  | 
| 454 | do | 
| 455 | getevent(); | 
| 456 | while (c_last <= c_first && levptr(XEvent)->type != ButtonPress); | 
| 457 | *xp = levptr(XButtonPressedEvent)->x; | 
| 458 | *yp = gheight-1 - levptr(XButtonPressedEvent)->y; | 
| 459 | XUngrabPointer(ourdisplay, CurrentTime); | 
| 460 | XFlush(ourdisplay);                             /* insure release */ | 
| 461 | if (c_last > c_first)                   /* key pressed */ | 
| 462 | return(x11_getc()); | 
| 463 | /* button pressed */ | 
| 464 | if (levptr(XButtonPressedEvent)->button == Button1) | 
| 465 | return(MB1); | 
| 466 | if (levptr(XButtonPressedEvent)->button == Button2) | 
| 467 | return(MB2); | 
| 468 | if (levptr(XButtonPressedEvent)->button == Button3) | 
| 469 | return(MB3); | 
| 470 | return(ABORT); | 
| 471 | } | 
| 472 |  | 
| 473 |  | 
| 474 | static void | 
| 475 | xnewcolr(               /* enter a color into hardware table */ | 
| 476 | int  ndx, | 
| 477 | int  r, | 
| 478 | int  g, | 
| 479 | int  b | 
| 480 | ) | 
| 481 | { | 
| 482 | XColor  xcolor; | 
| 483 |  | 
| 484 | xcolor.pixel = pixval[ndx]; | 
| 485 | xcolor.red = r << 8; | 
| 486 | xcolor.green = g << 8; | 
| 487 | xcolor.blue = b << 8; | 
| 488 | xcolor.flags = DoRed|DoGreen|DoBlue; | 
| 489 |  | 
| 490 | XStoreColor(ourdisplay, ourmap, &xcolor); | 
| 491 | } | 
| 492 |  | 
| 493 |  | 
| 494 | static int | 
| 495 | getpixels(void)                         /* get the color map */ | 
| 496 | { | 
| 497 | XColor  thiscolor; | 
| 498 | register int  i, j; | 
| 499 |  | 
| 500 | if (ncolors > 0) | 
| 501 | return(ncolors); | 
| 502 | if (ourvinfo.visual == DefaultVisual(ourdisplay,ourscreen)) { | 
| 503 | ourmap = DefaultColormap(ourdisplay,ourscreen); | 
| 504 | goto loop; | 
| 505 | } | 
| 506 | newmap: | 
| 507 | ourmap = XCreateColormap(ourdisplay,gwind,ourvinfo.visual,AllocNone); | 
| 508 | loop: | 
| 509 | for (ncolors = ourvinfo.colormap_size; | 
| 510 | ncolors > ourvinfo.colormap_size/3; | 
| 511 | ncolors = ncolors*.937) { | 
| 512 | pixval = (unsigned long *)malloc(ncolors*sizeof(unsigned long)); | 
| 513 | if (pixval == NULL) | 
| 514 | return(ncolors = 0); | 
| 515 | if (XAllocColorCells(ourdisplay,ourmap,0,NULL,0,pixval,ncolors)) | 
| 516 | break; | 
| 517 | free((void *)pixval); | 
| 518 | pixval = NULL; | 
| 519 | } | 
| 520 | if (pixval == NULL) { | 
| 521 | if (ourmap == DefaultColormap(ourdisplay,ourscreen)) | 
| 522 | goto newmap;            /* try it with our map */ | 
| 523 | else | 
| 524 | return(ncolors = 0);    /* failed */ | 
| 525 | } | 
| 526 | if (ourmap != DefaultColormap(ourdisplay,ourscreen)) | 
| 527 | for (i = 0; i < ncolors; i++) { /* reset black and white */ | 
| 528 | if (pixval[i] != ourblack && pixval[i] != ourwhite) | 
| 529 | continue; | 
| 530 | thiscolor.pixel = pixval[i]; | 
| 531 | thiscolor.flags = DoRed|DoGreen|DoBlue; | 
| 532 | XQueryColor(ourdisplay, | 
| 533 | DefaultColormap(ourdisplay,ourscreen), | 
| 534 | &thiscolor); | 
| 535 | XStoreColor(ourdisplay, ourmap, &thiscolor); | 
| 536 | for (j = i; j+1 < ncolors; j++) | 
| 537 | pixval[j] = pixval[j+1]; | 
| 538 | ncolors--; | 
| 539 | i--; | 
| 540 | } | 
| 541 | XSetWindowColormap(ourdisplay, gwind, ourmap); | 
| 542 | return(ncolors); | 
| 543 | } | 
| 544 |  | 
| 545 |  | 
| 546 | static void | 
| 547 | freepixels(void)                                /* free our pixels */ | 
| 548 | { | 
| 549 | if (ncolors == 0) | 
| 550 | return; | 
| 551 | XFreeColors(ourdisplay,ourmap,pixval,ncolors,0L); | 
| 552 | free((void *)pixval); | 
| 553 | pixval = NULL; | 
| 554 | ncolors = 0; | 
| 555 | if (ourmap != DefaultColormap(ourdisplay,ourscreen)) | 
| 556 | XFreeColormap(ourdisplay, ourmap); | 
| 557 | ourmap = 0; | 
| 558 | } | 
| 559 |  | 
| 560 |  | 
| 561 | static unsigned long | 
| 562 | true_pixel(                     /* return true pixel value for color */ | 
| 563 | COLOR  col | 
| 564 | ) | 
| 565 | { | 
| 566 | unsigned long  rval; | 
| 567 | uby8  rgb[3]; | 
| 568 |  | 
| 569 | map_color(rgb, col); | 
| 570 | rval = ourvinfo.red_mask*rgb[RED]/255 & ourvinfo.red_mask; | 
| 571 | rval |= ourvinfo.green_mask*rgb[GRN]/255 & ourvinfo.green_mask; | 
| 572 | rval |= ourvinfo.blue_mask*rgb[BLU]/255 & ourvinfo.blue_mask; | 
| 573 | return(rval); | 
| 574 | } | 
| 575 |  | 
| 576 |  | 
| 577 | static int | 
| 578 | x11_getc(void)                  /* get a command character */ | 
| 579 | { | 
| 580 | while (c_last <= c_first) { | 
| 581 | c_first = c_last = 0;           /* reset */ | 
| 582 | getevent();                     /* wait for key */ | 
| 583 | } | 
| 584 | x11_driver.inpready--; | 
| 585 | return(c_queue[c_first++]); | 
| 586 | } | 
| 587 |  | 
| 588 |  | 
| 589 | static void | 
| 590 | getevent(void)                  /* get next event */ | 
| 591 | { | 
| 592 | XNextEvent(ourdisplay, levptr(XEvent)); | 
| 593 | switch (levptr(XEvent)->type) { | 
| 594 | case ConfigureNotify: | 
| 595 | resizewindow(levptr(XConfigureEvent)); | 
| 596 | break; | 
| 597 | case UnmapNotify: | 
| 598 | mapped = 0; | 
| 599 | freepixels(); | 
| 600 | break; | 
| 601 | case MapNotify: | 
| 602 | if (ourvinfo.class == PseudoColor || | 
| 603 | ourvinfo.class == GrayScale) { | 
| 604 | if (getpixels() == 0) | 
| 605 | eputs("cannot allocate colors\n"); | 
| 606 | else | 
| 607 | new_ctab(ncolors); | 
| 608 | } | 
| 609 | mapped = 1; | 
| 610 | break; | 
| 611 | case Expose: | 
| 612 | fixwindow(levptr(XExposeEvent)); | 
| 613 | break; | 
| 614 | case KeyPress: | 
| 615 | getkey(levptr(XKeyPressedEvent)); | 
| 616 | break; | 
| 617 | case ButtonPress: | 
| 618 | break; | 
| 619 | } | 
| 620 | } | 
| 621 |  | 
| 622 |  | 
| 623 | static void | 
| 624 | getkey(                         /* get input key */ | 
| 625 | register XKeyPressedEvent  *ekey | 
| 626 | ) | 
| 627 | { | 
| 628 | register int  n; | 
| 629 |  | 
| 630 | n = XLookupString(ekey, c_queue+c_last, sizeof(c_queue)-c_last, | 
| 631 | NULL, NULL); | 
| 632 | c_last += n; | 
| 633 | x11_driver.inpready += n; | 
| 634 | } | 
| 635 |  | 
| 636 |  | 
| 637 | static void | 
| 638 | fixwindow(                              /* repair damage to window */ | 
| 639 | register XExposeEvent  *eexp | 
| 640 | ) | 
| 641 | { | 
| 642 | char  buf[80]; | 
| 643 |  | 
| 644 | if (eexp->window == gwind) { | 
| 645 | sprintf(buf, "repaint %d %d %d %d\n", | 
| 646 | eexp->x, gheight - eexp->y - eexp->height, | 
| 647 | eexp->x + eexp->width, gheight - eexp->y); | 
| 648 | tocombuf(buf, &x11_driver); | 
| 649 | } else if (eexp->window == comline->w) { | 
| 650 | if (eexp->count == 0) | 
| 651 | xt_redraw(comline); | 
| 652 | } | 
| 653 | } | 
| 654 |  | 
| 655 |  | 
| 656 | static void | 
| 657 | resizewindow(                   /* resize window */ | 
| 658 | register XConfigureEvent  *ersz | 
| 659 | ) | 
| 660 | { | 
| 661 | if (ersz->width == gwidth && ersz->height-comheight == gheight) | 
| 662 | return; | 
| 663 |  | 
| 664 | gwidth = ersz->width; | 
| 665 | gheight = ersz->height-comheight; | 
| 666 | x11_driver.xsiz = gwidth < MINWIDTH ? MINWIDTH : gwidth; | 
| 667 | x11_driver.ysiz = gheight < MINHEIGHT ? MINHEIGHT : gheight; | 
| 668 |  | 
| 669 | tocombuf("new\n", &x11_driver); | 
| 670 | } |