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