home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / x11.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  48KB  |  2,041 lines

  1. /*
  2.  *     X11 support, Dave Lemke, 11/91
  3.  *
  4.  * $Log: x11.c,v $
  5.  * Revision 1.10  1992/11/19  09:20:44  foxharp
  6.  * eric krohn's window resize fix, and his new name, foreground, and
  7.  * background support
  8.  *
  9.  * Revision 1.9  1992/08/20  23:40:48  foxharp
  10.  * typo fixes -- thanks, eric
  11.  *
  12.  * Revision 1.8  1992/08/04  20:16:14  foxharp
  13.  * prototype fixups
  14.  *
  15.  * Revision 1.7  1992/05/16  12:00:31  pgf
  16.  * prototypes/ansi/void-int stuff/microsoftC
  17.  *
  18.  * Revision 1.6  1992/05/13  09:17:23  pgf
  19.  * put in chris sherman's class_hint changes, changed strdup to strmalloc,
  20.  * which is our routine that does the same thing
  21.  *
  22.  * Revision 1.5  1992/04/10  18:47:25  pgf
  23.  * change abs to absol to get rid of name conflicts
  24.  *
  25.  * Revision 1.4  1992/03/07  10:27:03  pgf
  26.  * avoid macro expansion loop -- Xos.h defines strchr and strrchr
  27.  *
  28.  * Revision 1.3  1991/12/11  21:23:13  pgf
  29.  * added Log keyword
  30.  *
  31.  * Revision 1.2  1991/12/10
  32.  * fixes from dave -- ISC conflicts in X header files, so we undef
  33.  * it here.  also, a color bug
  34.  *
  35.  * Revision 1.1  1991/11/13
  36.  * Initial revision
  37.  */
  38.  
  39. #include    "estruct.h"
  40. #include    "edef.h"
  41.  
  42. /* undef for the benefit of some X header files -- if you really _are_
  43.     both ISC and X11, well, you know what to do. */
  44. #undef ISC
  45.  
  46. #if X11
  47.  
  48. /* redefined in X11/Xos.h */
  49. #undef strchr
  50. #undef strrchr
  51.  
  52. #include    <X11/Xlib.h>
  53. #include    <X11/Xutil.h>
  54. #include    <X11/keysym.h>
  55. #include    <X11/Xos.h>
  56. #include    <X11/Xatom.h>
  57.  
  58. #include    <signal.h>
  59. #include    <stdio.h>
  60. #include    <string.h>
  61.  
  62. char *strmalloc();
  63.  
  64. #define    MARGIN    8
  65. #define    SCRSIZ    64
  66. #define    NPAUSE    10        /* # times thru update to pause */
  67. #define min(x,y)    ((x) < (y) ? (x) : (y))
  68. #define max(x,y)    ((x) > (y) ? (x) : (y))
  69. #define    absol(x)    ((x) > 0 ? (x) : -(x))
  70.  
  71. /* XX -- use xcutsel instead */
  72. #undef    SABER_HACK        /* hack to support Saber since it doesn't do
  73.                  * selections right */
  74.  
  75.  
  76. /* local screen rep flags */
  77. #define    CELL_DIRTY    0x1
  78. #define    CELL_REVERSE    0x2
  79. #define    CELL_CURSOR    0x4
  80. #define    CELL_SELECTION    0x8
  81.  
  82. /* local screen rep line flags */
  83. #define    LINE_DIRTY    0x1
  84.  
  85. static char *displayname;
  86. static Display *dpy;
  87.  
  88. typedef struct _text_win {
  89.     /* X stuff */
  90.     Display    *dpy;
  91.     int         screen;
  92.     Window      win;
  93.     int         bw;
  94.     XFontStruct *pfont;
  95.     GC          textgc;
  96.     GC          reversegc;
  97.     unsigned long fg,
  98.                 bg;
  99.     int         char_width,
  100.                 char_ascent,
  101.                 char_height;
  102.     char       *fontname;
  103.  
  104.     /* text stuff */
  105.     Bool        reverse;
  106.     int         rows,
  107.                 cols;
  108.     int         last_col,
  109.                 last_row;
  110.     Bool        show_cursor;
  111.     int         cur_row,
  112.                 cur_col;
  113.     unsigned char **sc;        /* what the screen looks like */
  114.     unsigned char **attr;    /* per-char cell flags */
  115.     unsigned char *line_attr;    /* pre-line attributes */
  116.  
  117.     /* selection stuff */
  118.     Time        lasttime;    /* for multi-click */
  119.     Time        click_timeout;
  120.     int         numclicks;
  121.     int         sel_start_col,
  122.                 sel_start_row;
  123.     int         sel_end_col,
  124.                 sel_end_row;
  125.     int         wipe_row,
  126.                 wipe_col;
  127.     Bool        have_selection;
  128.     Bool        show_selection;
  129.     Atom        sel_prop;
  130.     unsigned char *selection_data;
  131.     int         selection_len;
  132. }           TextWindowRec, *TextWindow;
  133.  
  134. static TextWindow cur_win;
  135. static char *paste;
  136. static char *pp;
  137. static int  plen;
  138.  
  139. static int  x_getc(),
  140.             x_cres();
  141.  
  142. static void  x_open(),
  143.             x_close(),
  144.             x_putc(),
  145.             x_flush(),
  146.             x_kopen(),
  147.             x_kclose(),
  148.             x_move(),
  149.             x_eeol(),
  150.             x_eeop(),
  151.             x_beep(),
  152.             x_rev();
  153.  
  154. #if COLOR
  155. static int  x_fcol(), x_bcol();
  156.  
  157. #endif
  158.  
  159. #ifdef SCROLLCODE
  160. static void  x_scroll();
  161.  
  162. #endif
  163.  
  164. static void change_selection();
  165. static void x_stash_selection();
  166. static int set_character_class();
  167. static void x_refresh();
  168.  
  169. #define    FONTNAME    "9x15"
  170. static char *fontname;
  171.  
  172. static char *geometry = NULL;
  173.  
  174. static char *progname;
  175.  
  176. static Bool reverse_video;
  177. static char *foreground_name = 0,
  178.             *background_name = 0;
  179. static int  foreground = -1,
  180.             background = -1;
  181.  
  182. static int  multi_click_time = 500;
  183.  
  184. static int  startx = 100,
  185.             starty = 100;
  186.  
  187. static int  start_rows = 36,
  188.             start_cols = 80;
  189.  
  190.  
  191. TERM        term = {
  192.     NULL,            /* these four values are set dynamically at
  193.                  * open time */
  194.     NULL,
  195.     NULL,
  196.     NULL,
  197.     MARGIN,
  198.     SCRSIZ,
  199.     NPAUSE,
  200.     x_open,
  201.     x_close,
  202.     x_kopen,
  203.     x_kclose,
  204.     x_getc,
  205.     x_putc,
  206.     x_flush,
  207.     x_move,
  208.     x_eeol,
  209.     x_eeop,
  210.     x_beep,
  211.     x_rev,
  212.     x_cres
  213.  
  214. #if    COLOR
  215.     ,x_fcol,
  216.     x_bcol
  217. #endif
  218.  
  219. #if SCROLLCODE
  220.     ,x_scroll
  221. #endif
  222. };
  223.  
  224.  
  225. #define    x_width(tw)        ((tw)->cols * (tw)->char_width)
  226. #define    x_height(tw)        ((tw)->rows * (tw)->char_height)
  227. #define    x_pos(tw, c)        ((c) * (tw)->char_width)
  228. #define    y_pos(tw, r)        ((r) * (tw)->char_height)
  229. #define    text_y_pos(tw, r)    (y_pos((tw), (r)) + (tw)->char_ascent)
  230.  
  231. /* why isn't this one standard? */
  232. static char *
  233. strndup(str, n)
  234.     char       *str;
  235.     int         n;
  236. {
  237.     char       *t;
  238.  
  239.     t = malloc(n);
  240.     bcopy(str, t, n);
  241.     return t;
  242. }
  243.  
  244. /* ARGSUSED */
  245. void
  246. x_preparse_args(pargc, pargv)
  247.     int        *pargc;
  248.     char     ***pargv;
  249. {
  250.     progname = *pargv[0];
  251.     if (*progname == '/')
  252.     progname = rindex(progname, '/');
  253. }
  254.  
  255. /* ARGSUSED */
  256. void
  257. x_setname(name)
  258.     char     *name;
  259. {
  260.     if (name && *name != '\0')
  261.     progname = name;
  262. }
  263.  
  264. char       *
  265. x_current_fontname()
  266. {
  267.     return cur_win->fontname;
  268. }
  269.  
  270. void
  271. x_set_rv()
  272. {
  273.     reverse_video = !reverse_video;
  274. }
  275.  
  276. void
  277. x_set_geometry(g)
  278.     char       *g;
  279. {
  280.     geometry = g;
  281. }
  282.  
  283. void
  284. x_set_dpy(dn)
  285.     char       *dn;
  286. {
  287.     displayname = dn;
  288. }
  289.  
  290. void
  291. x_setforeground(colorname)
  292.     char       *colorname;
  293. {
  294.     foreground_name = colorname;
  295. }
  296.  
  297. void
  298. x_setbackground(colorname)
  299.     char       *colorname;
  300. {
  301.     background_name = colorname;
  302. }
  303.  
  304. int
  305. x_setfont(fname)
  306.     char       *fname;
  307. {
  308.     XFontStruct *pfont;
  309.     XSizeHints  xsh;
  310.     int         oldw,
  311.                 oldh;
  312.  
  313.     fontname = fname;
  314.     if (cur_win) {
  315.     pfont = XLoadQueryFont(dpy, fontname);
  316.     if (pfont) {
  317.         oldw = x_width(cur_win);
  318.         oldh = x_height(cur_win);
  319.  
  320.         if (pfont->max_bounds.width != pfont->min_bounds.width) {
  321.         fprintf(stderr, "proportional font, things will be miserable\n");
  322.         }
  323.         cur_win->pfont = pfont;
  324.         cur_win->char_width = pfont->max_bounds.width;
  325.         /*
  326.          * using maxbounds instead of font ascent/descent, so it may be
  327.          * widely spaced, but won't screw up accented chars
  328.          */
  329.  
  330. #ifdef undef
  331.         cur_win->char_height = pfont->max_bounds.ascent + pfont->max_bounds.descent;
  332. #else
  333.         cur_win->char_height = pfont->ascent + pfont->descent;
  334. #endif
  335.  
  336.         cur_win->char_ascent = pfont->max_bounds.ascent;
  337.  
  338.         XSetFont(dpy, cur_win->textgc, pfont->fid);
  339.         XSetFont(dpy, cur_win->reversegc, pfont->fid);
  340.  
  341.         /* is size changed, resize it, otherwise refresh */
  342.         if (oldw != x_width(cur_win) || oldh != x_height(cur_win)) {
  343.         XResizeWindow(dpy, cur_win->win,
  344.                   x_width(cur_win), x_height(cur_win));
  345.         } else {
  346.         x_refresh(cur_win, 0, 0, cur_win->cols, cur_win->rows);
  347.         }
  348.         xsh.flags = PResizeInc | PMaxSize;
  349.         xsh.width_inc = cur_win->char_width;
  350.         xsh.height_inc = cur_win->char_height;
  351.         xsh.max_width = term.t_mrow * cur_win->char_height;
  352.         xsh.max_height = term.t_mcol * cur_win->char_width;
  353.         XSetNormalHints(dpy, cur_win->win, &xsh);
  354.  
  355.         if (cur_win->fontname)
  356.         free(cur_win->fontname);
  357.         cur_win->fontname = strmalloc(fontname);
  358.         return 1;
  359.     }
  360.     return 0;
  361.     }
  362.     return 1;
  363. }
  364.  
  365. static int
  366. x_quit()
  367. {
  368.     x_close();
  369.     exit(0);
  370.     /* NOTREACHED */
  371.     return 0;
  372. }
  373.  
  374. static void
  375. x_resize_screen(tw, rows, cols)
  376.     TextWindow  tw;
  377.     int         rows;
  378.     int         cols;
  379. {
  380.     int         r,
  381.                 c;
  382.  
  383.     if (rows != tw->rows) {
  384.     if (tw->sc) {
  385.         for (r = 0; r < tw->rows; r++) {
  386.         free(tw->sc[r]);
  387.         free(tw->attr[r]);
  388.         }
  389.         free(tw->sc);
  390.         free(tw->attr);
  391.         free(tw->line_attr);
  392.     }
  393.     tw->rows = rows;
  394.     /* allocate screen */
  395.     tw->sc = (unsigned char **) malloc(sizeof(unsigned char *) * tw->rows);
  396.     tw->attr = (unsigned char **) malloc(sizeof(unsigned char *) * tw->rows);
  397.     tw->line_attr = (unsigned char *)
  398.         malloc(sizeof(unsigned char) * tw->rows);
  399.     }
  400.     tw->cols = cols;
  401.     if (tw->cur_col >= tw->cols)
  402.         tw->cur_col = tw->cols - 1;
  403.  
  404.     if (!tw->sc || !tw->attr || !tw->line_attr) {
  405.     fprintf(stderr, "couldn't allocate memory for screen\n");
  406.     exit(-1);
  407.     }
  408.     /* init it */
  409.     for (r = 0; r < tw->rows; r++) {
  410.     tw->sc[r] = (unsigned char *) malloc(sizeof(unsigned char) * tw->cols);
  411.     tw->attr[r] = (unsigned char *) malloc(sizeof(unsigned char) * tw->cols);
  412.     if (!tw->sc[r] || !tw->attr[r]) {
  413.         fprintf(stderr, "couldn't allocate memory for screen\n");
  414.         exit(-1);
  415.     }
  416.     tw->line_attr[r] = LINE_DIRTY;
  417.     memset((char *) tw->sc[r], ' ', tw->cols);
  418.     for (c = 0; c < tw->cols; c++) {
  419.         tw->attr[r][c] = CELL_DIRTY;
  420.     }
  421.     }
  422.     if (tw->cur_row >= tw->rows)
  423.         tw->cur_row = tw->rows - 1;
  424. }
  425.  
  426. struct {
  427.     char       *name;
  428.     int         val;
  429. }           name_val[] = {
  430.  
  431.     "yes", TRUE,
  432.     "on", TRUE,
  433.     "1", TRUE,
  434.     "true", TRUE,
  435.     "no", FALSE,
  436.     "off", FALSE,
  437.     "0", FALSE,
  438.     "false", FALSE,
  439.     (char *) 0, 0,
  440. };
  441.  
  442. static Bool
  443. bool_name(t)
  444.     char       *t;
  445. {
  446.     int         len = strlen(t);
  447.     int         i;
  448.  
  449.     for (i = 0; name_val[i].name; i++) {
  450.     if (!strncmp(t, name_val[i].name, len))
  451.         return name_val[i].val;
  452.     }
  453.     return False;
  454. }
  455.  
  456. static int
  457. color_value(disp, screen, t)
  458.     Display    *disp;
  459.     int         screen;
  460.     char       *t;
  461. {
  462.     XColor      xc;
  463.     Colormap    cmap;
  464.  
  465.     cmap = DefaultColormap(disp, screen);
  466.  
  467.     XParseColor(disp, cmap, t, &xc);
  468.     XAllocColor(disp, cmap, &xc);
  469.     return xc.pixel;
  470. }
  471.  
  472. static void
  473. x_get_defaults(disp, screen)
  474.     Display    *disp;
  475.     int         screen;
  476. {
  477.     char       *t;
  478.  
  479.     if (!fontname) {
  480.     t = XGetDefault(disp, "XVile", "font");
  481.     if (t)
  482.         fontname = t;
  483.     t = XGetDefault(disp, progname, "font");
  484.     if (t)
  485.         fontname = t;
  486.     }
  487.     if (!geometry) {
  488.     t = XGetDefault(disp, "XVile", "geometry");
  489.     if (t)
  490.         geometry = t;
  491.     t = XGetDefault(disp, progname, "geometry");
  492.     if (t)
  493.         geometry = t;
  494.     }
  495.     t = XGetDefault(disp, "XVile", "charClass");
  496.     if (t)
  497.     set_character_class(t);
  498.     t = XGetDefault(disp, progname, "charClass");
  499.     if (t)
  500.     set_character_class(t);
  501.  
  502.     t = XGetDefault(disp, "XVile", "multiClickTime");
  503.     if (t)
  504.     multi_click_time = atoi(t);
  505.     t = XGetDefault(disp, progname, "multiClickTime");
  506.     if (t)
  507.     multi_click_time = atoi(t);
  508.  
  509.     t = XGetDefault(disp, "XVile", "reverseVideo");
  510.     if (t)
  511.     reverse_video = bool_name(t);
  512.     t = XGetDefault(disp, progname, "reverseVideo");
  513.     if (t)
  514.     reverse_video = bool_name(t);
  515.  
  516.     t = XGetDefault(disp, "XVile", "foreground");
  517.     if (t)
  518.     foreground = color_value(disp, screen, t);
  519.     t = XGetDefault(disp, progname, "foreground");
  520.     if (t)
  521.     foreground = color_value(disp, screen, t);
  522.     t = foreground_name;
  523.     if (t)
  524.     foreground = color_value(disp, screen, t);
  525.  
  526.     t = XGetDefault(disp, "XVile", "background");
  527.     if (t)
  528.     background = color_value(disp, screen, t);
  529.     t = XGetDefault(disp, progname, "background");
  530.     if (t)
  531.     background = color_value(disp, screen, t);
  532.     t = background_name;
  533.     if (t)
  534.     background = color_value(disp, screen, t);
  535. }
  536.  
  537. static void
  538. x_open()
  539. {
  540.     TextWindow  tw;
  541.     int         screen;
  542.     XFontStruct *pfont;
  543.     XGCValues   gcvals;
  544.     unsigned long gcmask;
  545.     XSetWindowAttributes swat;
  546.     unsigned long winmask;
  547.     XSizeHints  xsh;
  548.     XWMHints    xwmh;
  549.     int         flags;
  550.  
  551.     tw = (TextWindow) calloc(1, sizeof(TextWindowRec));
  552.     if (!tw) {
  553.     fprintf(stderr, "insufficient memory, exiting\n");
  554.     exit(-1);
  555.     }
  556.     dpy = XOpenDisplay(displayname);
  557.  
  558. #ifdef undef
  559.     XSynchronize(dpy, 1);
  560. #endif
  561.  
  562.     if (!dpy) {
  563.     fprintf(stderr, "couldn't open X display\n");
  564.     exit(0);
  565.     }
  566.     tw->dpy = dpy;
  567.     tw->screen = screen = DefaultScreen(dpy);
  568.  
  569.     x_get_defaults(dpy, screen);
  570.  
  571.     pfont = XLoadQueryFont(dpy, fontname);
  572.     if (!pfont) {
  573.     pfont = XLoadQueryFont(dpy, FONTNAME);
  574.     if (!pfont) {
  575.         fprintf(stderr, "couldn't get font \"%s\" or \"%s\", exiting\n",
  576.             fontname, FONTNAME);
  577.         exit(-1);
  578.     }
  579.     fontname = FONTNAME;
  580.     }
  581.     tw->fontname = strmalloc(fontname);
  582.  
  583.     if (pfont->max_bounds.width != pfont->min_bounds.width) {
  584.     fprintf(stderr, "proportional font, things will be miserable\n");
  585.     }
  586.     tw->pfont = pfont;
  587.     tw->char_width = pfont->max_bounds.width;
  588.     /*
  589.      * using maxbounds instead of font ascent/descent, so it may be widely
  590.      * spaced, but won't screw up accented chars
  591.      */
  592.  
  593. #ifdef undef
  594.     tw->char_height = pfont->max_bounds.ascent + pfont->max_bounds.descent;
  595. #else
  596.     tw->char_height = pfont->ascent + pfont->descent;
  597. #endif
  598.  
  599.     tw->char_ascent = pfont->max_bounds.ascent;
  600.  
  601.     if (foreground == -1)
  602.     foreground = BlackPixel(dpy, 0);
  603.     if (background == -1)
  604.     background = WhitePixel(dpy, 0);
  605.     if (reverse_video) {
  606.     tw->bg = foreground;
  607.     tw->fg = background;
  608.     } else {
  609.     tw->fg = foreground;
  610.     tw->bg = background;
  611.     }
  612.  
  613.     gcmask = GCForeground | GCBackground | GCFont;
  614.     gcvals.foreground = tw->fg;
  615.     gcvals.background = tw->bg;
  616.     gcvals.font = pfont->fid;
  617.     tw->textgc = XCreateGC(dpy, RootWindow(dpy, screen), gcmask, &gcvals);
  618.  
  619.     gcvals.foreground = tw->bg;
  620.     gcvals.background = tw->fg;
  621.     gcvals.font = pfont->fid;
  622.     tw->reversegc = XCreateGC(dpy, RootWindow(dpy, screen), gcmask, &gcvals);
  623.  
  624.     if (geometry) {
  625.     flags = XParseGeometry(geometry, &startx, &starty,
  626.                    &start_cols, &start_rows);
  627.     } else
  628.     flags = 0;
  629.     x_resize_screen(tw, start_rows, start_cols);
  630.  
  631.     if ((flags & XValue) && (flags & XNegative))
  632.     startx = DisplayWidth(dpy, screen) - x_width(tw);
  633.     if ((flags & YValue) && (flags & YNegative))
  634.     starty = DisplayHeight(dpy, screen) - x_height(tw);
  635.  
  636.     tw->reverse = False;
  637.  
  638.     tw->bw = 1;
  639.  
  640.     tw->click_timeout = multi_click_time;
  641.  
  642.     swat.background_pixel = tw->bg;
  643.     swat.border_pixel = tw->fg;
  644.     swat.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask |
  645.     ButtonPress | ButtonRelease | ButtonMotionMask |
  646.     FocusChangeMask | EnterWindowMask | LeaveWindowMask;
  647.     winmask = CWBackPixel | CWBorderPixel | CWEventMask;
  648.     tw->win = XCreateWindow(dpy, RootWindow(dpy, screen), startx, starty,
  649.           x_width(tw), x_height(tw), tw->bw, CopyFromParent, InputOutput,
  650.                 CopyFromParent, winmask, &swat);
  651.  
  652.  
  653.     /* these can go bigger, but they suck up lots of VM if they do */
  654.     term.t_mcol = 160;        /* XXX */
  655.     term.t_mrow = 150;        /* XXX */
  656.  
  657.     xsh.flags = PPosition | PResizeInc | PSize | PMaxSize;
  658.     if (flags & (XValue | YValue))
  659.     xsh.flags |= USPosition;
  660.     if (flags & (WidthValue | HeightValue))
  661.     xsh.flags |= USSize;
  662.  
  663.     xsh.width_inc = tw->char_width;
  664.     xsh.height_inc = tw->char_height;
  665.     xsh.x = startx;
  666.     xsh.y = starty;
  667.     xsh.width = x_width(tw);
  668.     xsh.height = x_height(tw);
  669.     xsh.max_width = term.t_mrow * tw->char_height;
  670.     xsh.max_height = term.t_mcol * tw->char_width;
  671.     XSetStandardProperties(dpy, tw->win, "XVile", "XVile", (Pixmap) 0,
  672.                NULL, 0, &xsh);
  673.  
  674.     xwmh.flags = InputHint;
  675.     xwmh.input = True;
  676.     XSetWMHints(dpy, tw->win, &xwmh);
  677.  
  678.     {
  679.       XClassHint *class_hints;
  680.       class_hints = XAllocClassHint();
  681.       class_hints->res_name = strmalloc("xvile");
  682.       class_hints->res_class = strmalloc("XVile");
  683.       XSetClassHint(dpy,tw->win,class_hints);
  684.       free(class_hints->res_name);
  685.       free(class_hints->res_class);
  686.       XFree(class_hints);
  687.     }
  688.     cur_win = tw;
  689.     XMapWindow(dpy, tw->win);
  690.  
  691.     XSync(dpy, 0);
  692.  
  693.     tw->sel_prop = XInternAtom(dpy, "VILE_SELECTION", False);
  694.  
  695.     signal(SIGHUP, x_quit);
  696.     signal(SIGINT, x_quit);
  697.     signal(SIGTERM, x_quit);
  698.  
  699.     /* main code assumes that it can access a cell at nrow x ncol */
  700.     term.t_ncol = tw->cols - 1;
  701.     term.t_nrow = tw->rows - 1;
  702. }
  703.  
  704. static void
  705. x_close()
  706. {
  707.     XCloseDisplay(dpy);
  708. }
  709.  
  710. static void
  711. x_kopen()
  712. {
  713. }
  714.  
  715. static void
  716. x_kclose()
  717. {
  718. }
  719.  
  720. static void
  721. x_refresh(tw, sc, sr, ec, er)
  722.     TextWindow  tw;
  723.     int         sc,
  724.                 ec;
  725.     int         sr,
  726.                 er;
  727. {
  728.     int         r,
  729.                 c;
  730.  
  731.     for (r = sr; r < er; r++) {
  732.     tw->line_attr[r] |= LINE_DIRTY;
  733.     for (c = sc; c < ec; c++) {
  734.         tw->attr[r][c] |= CELL_DIRTY;
  735.     }
  736.     }
  737.     x_flush();
  738. }
  739.  
  740. /* XXX this mostly works, except for cursor dirt.  doesn't seem to be
  741.  * a noticeable win, however...
  742.  *
  743.  * seems to give a apparent win under Xremote, but seems to repaint the stuff
  744.  * that's scrolled...
  745.  */
  746. #define    copy_area
  747.  
  748. #ifdef copy_area
  749. static void
  750. wait_for_scroll(tw)
  751.     TextWindow  tw;
  752. {
  753.     XEvent      ev;
  754.     int         sc,
  755.                 sr,
  756.                 ec,
  757.                 er;
  758.     XGraphicsExposeEvent *gev;
  759.  
  760.     while (1) {            /* loop looking for a gfx expose or no expose */
  761.     if (XCheckTypedEvent(tw->dpy, NoExpose, &ev))
  762.         return;
  763.     if (XCheckTypedEvent(tw->dpy, GraphicsExpose, &ev)) {
  764.         gev = (XGraphicsExposeEvent *) & ev;
  765.         sc = gev->x / tw->char_width;
  766.         sr = gev->y / tw->char_height;
  767.         ec = sc + gev->width / tw->char_width;
  768.         er = sr + gev->height / tw->char_height;
  769.         x_refresh(tw, sc, sr, ec, er);
  770.         return;
  771.     }
  772.     XSync(tw->dpy, 0);
  773.     }
  774. }
  775.  
  776. #endif
  777.  
  778. /*
  779.  * XXX this may not be any faster than having the guts do the scrolling
  780.  * instead
  781.  */
  782. static void
  783. x_scroll(from, to, count)
  784.     int         from,
  785.                 to,
  786.                 count;
  787. {
  788.     int         rf,
  789.                 rt,
  790.                 fst,
  791.                 tst,
  792.                 finc,
  793.                 tinc,
  794.                 i,
  795.                 diff,
  796.                 c;
  797.  
  798.     /*
  799.      * XXX since there aren't any hooks (yet) for scrolling, stop showing the
  800.      * selection as soon as the text changes
  801.      */
  802.     if (cur_win->show_selection)
  803.     change_selection(cur_win, False, True);
  804.  
  805.     /*
  806.      * figure out what lines to move first, to prevent being hosed if the
  807.      * scroll overlaps itself
  808.      */
  809.     if (from < to) {
  810.     fst = from + count - 1;
  811.     finc = -1;
  812.     tst = to + count - 1;
  813.     tinc = -1;
  814.     } else {
  815.     fst = from;
  816.     finc = 1;
  817.     tst = to;
  818.     tinc = 1;
  819.     }
  820.  
  821. #ifndef copy_area
  822.     cur_win->line_attr[cur_win->cur_row] |= LINE_DIRTY;
  823.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] |= CELL_DIRTY;
  824.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] &= ~CELL_CURSOR;
  825. #endif
  826.  
  827.     for (rf = fst, rt = tst, i = 0; i < count; i++, rf += finc, rt += tinc) {
  828.     bcopy((char *) cur_win->sc[rf], (char *) cur_win->sc[rt], cur_win->cols);
  829.     memset((char *) cur_win->sc[rf], ' ', cur_win->cols);
  830.  
  831.         /* only mark row if it isn't going to be overwritten during 
  832.          * this scroll
  833.          */
  834.         if (!((rf > tst && rf < (tst + count)) || 
  835.             (rf < tst && rf > (tst - count))))
  836.         cur_win->line_attr[rf] |= LINE_DIRTY;
  837. #ifndef copy_area
  838.     cur_win->line_attr[rt] |= LINE_DIRTY;
  839. #else
  840.     if (rf == cur_win->cur_row) {    /* erase scrolled cursor */
  841.         cur_win->line_attr[rt] |= LINE_DIRTY;
  842.         cur_win->attr[rt][cur_win->cur_col] |= CELL_DIRTY;
  843.         cur_win->attr[rt][cur_win->cur_col] &= ~CELL_CURSOR;
  844.     }
  845. #endif
  846.  
  847.     for (c = 0; c < cur_win->cols; c++) {
  848.  
  849. #ifndef copy_area
  850.         cur_win->attr[rt][c] = cur_win->attr[rf][c] | CELL_DIRTY;
  851.         cur_win->attr[rt][c] &= ~CELL_CURSOR;
  852. #endif
  853.  
  854.         /* memor() would be useful here... */
  855.         cur_win->attr[rf][c] |= CELL_DIRTY;
  856.     }
  857.     }
  858.  
  859. #ifdef copy_area
  860.     XCopyArea(cur_win->dpy, cur_win->win, cur_win->win, cur_win->textgc,
  861.           x_pos(cur_win, 0), y_pos(cur_win, from),
  862.           x_width(cur_win), count * cur_win->char_height,
  863.           x_pos(cur_win, 0), y_pos(cur_win, to));
  864.     XFlush(dpy);
  865.     wait_for_scroll(cur_win);
  866. #endif
  867.  
  868.     /* some lines weren't scrolled, so we need to wipe them */
  869.     /*
  870.      * XXX - why is this necessary?  it only gets hit when the scrolling code
  871.      * gets 'smart' and realizes it doesn't have to copy all the lines around,
  872.      * but then it doesn't bother to clean them either.
  873.      */
  874.     if (absol(from - to) != count) {
  875.     diff = absol(from - to) - count;
  876.     for (i = 0, rf = fst; i <= diff; i++, rf -= finc) {
  877.         memset((char *) cur_win->sc[rf], ' ', cur_win->cols);
  878.         cur_win->line_attr[rf] |= LINE_DIRTY;
  879.         for (c = 0; c < cur_win->cols; c++) {
  880.         /* memor() would be useful here... */
  881.         cur_win->attr[rf][c] |= CELL_DIRTY;
  882.         }
  883.     }
  884.     }
  885. }
  886.  
  887. #define    CLEAR_THRESH    8
  888.  
  889. static void
  890. flush_line(text, len, rev, sr, sc)
  891.     unsigned char *text;
  892.     int         len;
  893.     Bool        rev;
  894.     int         sr,
  895.                 sc;
  896. {
  897.     unsigned char *p;
  898.     int         cc,
  899.                 tlen,
  900.                 i = 0;
  901.  
  902.     /* break line into TextStrings and FillRects */
  903.     p = text;
  904.     cc = 0;
  905.     tlen = 0;
  906.     for (i = 0; i < len; i++) {
  907.     if (text[i] == ' ') {
  908.         cc++;
  909.         tlen++;
  910.     } else {
  911.         if (cc >= CLEAR_THRESH) {
  912.         tlen -= cc;
  913.         XDrawImageString(dpy, cur_win->win,
  914.                  (rev ? cur_win->reversegc : cur_win->textgc),
  915.                  x_pos(cur_win, sc), text_y_pos(cur_win, sr),
  916.                  (char *) p, tlen);
  917.         p += tlen + cc;
  918.         sc += tlen;
  919.         XFillRectangle(dpy, cur_win->win,
  920.                    (!rev ? cur_win->reversegc : cur_win->textgc),
  921.                    x_pos(cur_win, sc), y_pos(cur_win, sr),
  922.                (cc * cur_win->char_width), cur_win->char_height);
  923.         sc += cc;
  924.         tlen = 1;    /* starting new run */
  925.         } else
  926.         tlen++;
  927.         cc = 0;
  928.     }
  929.     }
  930.     if (cc >= CLEAR_THRESH) {
  931.     tlen -= cc;
  932.     XDrawImageString(dpy, cur_win->win,
  933.              (rev ? cur_win->reversegc : cur_win->textgc),
  934.              x_pos(cur_win, sc), text_y_pos(cur_win, sr),
  935.              (char *) p, tlen);
  936.     sc += tlen;
  937.     XFillRectangle(dpy, cur_win->win,
  938.                (!rev ? cur_win->reversegc : cur_win->textgc),
  939.                x_pos(cur_win, sc), y_pos(cur_win, sr),
  940.                (cc * cur_win->char_width), cur_win->char_height);
  941.     } else if (tlen > 0) {
  942.     XDrawImageString(dpy, cur_win->win,
  943.              (rev ? cur_win->reversegc : cur_win->textgc),
  944.              x_pos(cur_win, sc), text_y_pos(cur_win, sr),
  945.              (char *) p, tlen);
  946.     }
  947. }
  948.  
  949. #ifdef old
  950. static void
  951. clear_line(row, start, count)
  952.     int         row,
  953.                 start,
  954.                 count;
  955. {
  956.     XClearArea(dpy, cur_win->win, x_pos(cur_win, start), y_pos(cur_win, row),
  957.            (count * cur_win->char_width), cur_win->char_height, False);
  958. }
  959.  
  960. #endif
  961.  
  962. #undef    clear_hack
  963.  
  964. /* make sure the screen looks like we want it to */
  965. static void
  966. x_flush()
  967. {
  968.     unsigned char *start;
  969.     int         len;
  970.     int         r,
  971.                 c;
  972.     int         sc;
  973.     Bool        isrev;
  974.     Bool        flush;
  975.  
  976. #ifdef clear_hack
  977.     int         clear_count;
  978.     int         clear_start;
  979.  
  980. #endif
  981.  
  982. #define    reversed(c)    ((c) & (CELL_REVERSE | CELL_CURSOR | CELL_SELECTION))
  983.  
  984.     for (r = 0; r < cur_win->rows; r++) {
  985.     if (!(cur_win->line_attr[r] & LINE_DIRTY))
  986.         continue;
  987.     start = NULL;
  988.     len = 0;
  989.     isrev = False;
  990.     flush = False;
  991.     sc = 0;
  992.  
  993. #ifdef clear_hack
  994.     clear_count = 0;
  995.     clear_start = -1;
  996. #endif
  997.  
  998.     cur_win->line_attr[r] &= ~LINE_DIRTY;
  999.     for (c = 0; c < cur_win->cols;) {
  1000.         if (cur_win->attr[r][c] & CELL_DIRTY) {
  1001.  
  1002. #ifdef clear_hack
  1003.         if (cur_win->sc[r][c] == ' ' && clear_start <= 0) {
  1004.             if (clear_start == -1)
  1005.             clear_start = c;
  1006.             clear_count++;
  1007.             c++;
  1008.             continue;
  1009.         }
  1010. #endif
  1011.  
  1012.         if (isrev != (reversed(cur_win->attr[r][c]) ? True : False)) {
  1013.             if (len) {
  1014.             flush_line(start, len, isrev, r, sc);
  1015.             start = NULL;
  1016.             len = 0;
  1017.             flush = False;
  1018.             }
  1019.             isrev = !isrev;
  1020.             continue;
  1021.         }
  1022.         if (!len) {
  1023.             start = &(cur_win->sc[r][c]);
  1024.             sc = c;
  1025.         }
  1026.         len++;
  1027.         cur_win->attr[r][c] &= ~CELL_DIRTY;
  1028.         } else if (len)
  1029.         flush = True;
  1030.         c++;
  1031.  
  1032. #ifdef clear_hack
  1033.         if (clear_count && clear_start == 0) {
  1034.         clear_line(r, clear_start, clear_count);
  1035.         clear_count = 0;
  1036.         clear_start = -1;
  1037.         }
  1038. #endif
  1039.  
  1040.         if (flush && len) {
  1041.         flush_line(start, len, isrev, r, sc);
  1042.         len = 0;
  1043.         flush = False;
  1044.         }
  1045.     }
  1046.  
  1047. #ifdef clear_hack
  1048.     if (clear_count && clear_start == 0) {
  1049.         clear_line(r, clear_start, clear_count);
  1050.         clear_count = 0;
  1051.         clear_start = -1;
  1052.     }
  1053. #endif
  1054.  
  1055.     if (len) {
  1056.         flush_line(start, len, isrev, r, sc);
  1057.     }
  1058.     }
  1059.     /* last bit for cursor -- pretty sick, but it works */
  1060.     if (!cur_win->show_cursor)
  1061.     XDrawRectangle(dpy, cur_win->win, cur_win->textgc,
  1062.       x_pos(cur_win, cur_win->cur_col), y_pos(cur_win, cur_win->cur_row),
  1063.                cur_win->char_width - 1, cur_win->char_height - 1);
  1064.     XFlush(dpy);
  1065. }
  1066.  
  1067. static void
  1068. x_move(row, col)
  1069.     int         row,
  1070.                 col;
  1071. {
  1072.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] &= ~CELL_CURSOR;
  1073.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] |= CELL_DIRTY;
  1074.     cur_win->line_attr[cur_win->cur_row] |= LINE_DIRTY;
  1075.     cur_win->cur_col = col;
  1076.     cur_win->cur_row = row;
  1077.     cur_win->attr[row][col] |= (CELL_CURSOR | CELL_DIRTY);
  1078.     cur_win->line_attr[row] |= LINE_DIRTY;
  1079. }
  1080.  
  1081. #define    in_selection(tw, r)    ((r) >= (tw)->sel_start_row && \
  1082.                  (r) <= (tw)->sel_end_row)
  1083.  
  1084. /* ARGSUSED */
  1085. void
  1086. x_putline(row, str, len)
  1087.     int         row;
  1088.     char       *str;
  1089.     int        len;
  1090. {
  1091.     int         c,
  1092.                 i;
  1093.  
  1094.     /*
  1095.      * XXX since there aren't any hooks (yet) for scrolling, stop showing the
  1096.      * selection as soon as the text changes
  1097.      */
  1098.     if (cur_win->show_selection && in_selection(cur_win, row))
  1099.     change_selection(cur_win, False, True);
  1100.  
  1101.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] &= ~CELL_CURSOR;
  1102.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] |= CELL_DIRTY;
  1103.  
  1104.     bcopy((char *) str, (char *) &(cur_win->sc[row][cur_win->cur_col]), len);
  1105.     for (i = 0, c = cur_win->cur_col; i < len; c++, i++) {
  1106.     if (cur_win->reverse)
  1107.         cur_win->attr[row][c] |= CELL_REVERSE;
  1108.     else
  1109.         cur_win->attr[row][c] &= ~CELL_REVERSE;
  1110.     cur_win->attr[row][c] |= CELL_DIRTY;
  1111.     cur_win->attr[row][c] |= CELL_DIRTY;
  1112.     }
  1113.     cur_win->cur_row = row;
  1114.     cur_win->cur_col = c - 1;
  1115.  
  1116.     cur_win->attr[row][cur_win->cur_col] |= (CELL_CURSOR | CELL_DIRTY);
  1117.     cur_win->line_attr[row] |= LINE_DIRTY;
  1118. }
  1119.  
  1120. static void
  1121. x_putc(c)
  1122.     char        c;
  1123. {
  1124.     /*
  1125.      * XXX since there aren't any hooks (yet) for scrolling, stop showing the
  1126.      * selection as soon as the text changes
  1127.      */
  1128.     if (cur_win->show_selection && in_selection(cur_win, cur_win->cur_row))
  1129.     change_selection(cur_win, False, True);
  1130.  
  1131.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] &= ~CELL_CURSOR;
  1132.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] |= CELL_DIRTY;
  1133.  
  1134.     /* minibuffer prompt spits out real backspaces for some silly reason... */
  1135.     if (isprint(c)) {
  1136.     if (cur_win->reverse)
  1137.         cur_win->attr[cur_win->cur_row][cur_win->cur_col] |= CELL_REVERSE;
  1138.     else
  1139.         cur_win->attr[cur_win->cur_row][cur_win->cur_col] &= ~CELL_REVERSE;
  1140.     cur_win->sc[cur_win->cur_row][cur_win->cur_col] = c;
  1141.     cur_win->cur_col++;
  1142.     } else if (c == '\b') {
  1143.     cur_win->cur_col--;
  1144.     }
  1145.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] |=
  1146.     (CELL_CURSOR | CELL_DIRTY);
  1147.     cur_win->line_attr[cur_win->cur_row] |= LINE_DIRTY;
  1148. }
  1149.  
  1150. /*
  1151.  * clear to end of line
  1152.  */
  1153. static void
  1154. x_eeol()
  1155. {
  1156.     int         c;
  1157.  
  1158.     c = cur_win->cur_col;
  1159.  
  1160.     memset((char *) &(cur_win->sc[cur_win->cur_row][c]), ' ',
  1161.        cur_win->cols - c);
  1162.  
  1163. #ifdef old            /* XXX this might be faster, but it looks
  1164.                  * worse */
  1165.     clear_line(cur_win->cur_row, c, cur_win->cols - c);
  1166. #else
  1167.     while (c < cur_win->cols)
  1168.     cur_win->attr[cur_win->cur_row][c++] |= CELL_DIRTY;
  1169. #endif
  1170. }
  1171.  
  1172. /*
  1173.  * clear to end of page
  1174.  */
  1175. static void
  1176. x_eeop()
  1177. {
  1178.     int         r,
  1179.                 sc,
  1180.                 c;
  1181.  
  1182.     r = cur_win->cur_row;
  1183. /* XXX the old stuff is faster, but the only place the editot uses this
  1184.  * is to erase the whole page when updating, and in that case it usually
  1185.  * looks worse
  1186.  */
  1187.  
  1188. #ifdef old
  1189.     x_eeol();
  1190.     while (r < cur_win->rows) {
  1191.     clear_line(r, 0, cur_win->cols);
  1192.     memset((char *) &(cur_win->sc[r][0]), ' ', cur_win->cols);
  1193.     r++;
  1194.     }
  1195. #else
  1196.     sc = cur_win->cur_col;
  1197.     while (r < cur_win->rows) {
  1198.     cur_win->line_attr[r] |= LINE_DIRTY;
  1199.     for (c = sc; c < cur_win->cols; c++)
  1200.         cur_win->attr[r][c] |= CELL_DIRTY;
  1201.     memset((char *) &(cur_win->sc[r][0]), ' ', cur_win->cols);
  1202.     r++;
  1203.     sc = 0;
  1204.     }
  1205. #endif
  1206. }
  1207.  
  1208.  
  1209. #ifdef notyet
  1210. x_putline(row, s, fg, bg)
  1211.     int         row;
  1212.     char       *s;
  1213.     int         fg,
  1214.                 bg;
  1215. {
  1216. }
  1217.  
  1218. x_fastpoutline(row, s)
  1219.     int         row;
  1220.     char       *s;
  1221. {
  1222. }
  1223.  
  1224. x_setrowcolors(row, fg, bg)
  1225.     int         row,
  1226.                 fg,
  1227.                 bg;
  1228. {
  1229. }
  1230.  
  1231. x_cls()
  1232. {
  1233. }
  1234.  
  1235. #endif
  1236.  
  1237. /* selection processing stuff */
  1238.  
  1239. /* multi-click code stolen from xterm */
  1240. /*
  1241.  * double click table for cut and paste in 8 bits
  1242.  *
  1243.  * This table is divided in four parts :
  1244.  *
  1245.  *    - control characters    [0,0x1f] U [0x80,0x9f]
  1246.  *    - separators        [0x20,0x3f] U [0xa0,0xb9]
  1247.  *    - binding characters    [0x40,0x7f] U [0xc0,0xff]
  1248.  *      - exceptions
  1249.  */
  1250. static int  charClass[256] = {
  1251. /* NUL  SOH  STX  ETX  EOT  ENQ  ACK  BEL */
  1252.     32, 1, 1, 1, 1, 1, 1, 1,
  1253. /*  BS   HT   NL   VT   NP   CR   SO   SI */
  1254.     1, 32, 1, 1, 1, 1, 1, 1,
  1255. /* DLE  DC1  DC2  DC3  DC4  NAK  SYN  ETB */
  1256.     1, 1, 1, 1, 1, 1, 1, 1,
  1257. /* CAN   EM  SUB  ESC   FS   GS   RS   US */
  1258.     1, 1, 1, 1, 1, 1, 1, 1,
  1259. /*  SP    !    "    #    $    %    &    ' */
  1260.     32, 33, 34, 35, 36, 37, 38, 39,
  1261. /*   (    )    *    +    ,    -    .    / */
  1262.     40, 41, 42, 43, 44, 45, 46, 47,
  1263. /*   0    1    2    3    4    5    6    7 */
  1264.     48, 48, 48, 48, 48, 48, 48, 48,
  1265. /*   8    9    :    ;    <    =    >    ? */
  1266.     48, 48, 58, 59, 60, 61, 62, 63,
  1267. /*   @    A    B    C    D    E    F    G */
  1268.     64, 48, 48, 48, 48, 48, 48, 48,
  1269. /*   H    I    J    K    L    M    N    O */
  1270.     48, 48, 48, 48, 48, 48, 48, 48,
  1271. /*   P    Q    R    S    T    U    V    W */
  1272.     48, 48, 48, 48, 48, 48, 48, 48,
  1273. /*   X    Y    Z    [    \    ]    ^    _ */
  1274.     48, 48, 48, 91, 92, 93, 94, 48,
  1275. /*   `    a    b    c    d    e    f    g */
  1276.     96, 48, 48, 48, 48, 48, 48, 48,
  1277. /*   h    i    j    k    l    m    n    o */
  1278.     48, 48, 48, 48, 48, 48, 48, 48,
  1279. /*   p    q    r    s    t    u    v    w */
  1280.     48, 48, 48, 48, 48, 48, 48, 48,
  1281. /*   x    y    z    {    |    }    ~  DEL */
  1282.     48, 48, 48, 123, 124, 125, 126, 1,
  1283. /* x80  x81  x82  x83  IND  NEL  SSA  ESA */
  1284.     1, 1, 1, 1, 1, 1, 1, 1,
  1285. /* HTS  HTJ  VTS  PLD  PLU   RI  SS2  SS3 */
  1286.     1, 1, 1, 1, 1, 1, 1, 1,
  1287. /* DCS  PU1  PU2  STS  CCH   MW  SPA  EPA */
  1288.     1, 1, 1, 1, 1, 1, 1, 1,
  1289. /* x98  x99  x9A  CSI   ST  OSC   PM  APC */
  1290.     1, 1, 1, 1, 1, 1, 1, 1,
  1291. /*   -    i   c/    L   ox   Y-    |   So */
  1292.     160, 161, 162, 163, 164, 165, 166, 167,
  1293. /*  ..   c0   ip   <<    _        R0    - */
  1294.     168, 169, 170, 171, 172, 173, 174, 175,
  1295. /*   o   +-    2    3    '    u   q|    . */
  1296.     176, 177, 178, 179, 180, 181, 182, 183,
  1297. /*   ,    1    2   >>  1/4  1/2  3/4    ? */
  1298.     184, 185, 186, 187, 188, 189, 190, 191,
  1299. /*  A`   A'   A^   A~   A:   Ao   AE   C, */
  1300.     48, 48, 48, 48, 48, 48, 48, 48,
  1301. /*  E`   E'   E^   E:   I`   I'   I^   I: */
  1302.     48, 48, 48, 48, 48, 48, 48, 48,
  1303. /*  D-   N~   O`   O'   O^   O~   O:    X */
  1304.     48, 48, 48, 48, 48, 48, 48, 216,
  1305. /*  O/   U`   U'   U^   U:   Y'    P    B */
  1306.     48, 48, 48, 48, 48, 48, 48, 48,
  1307. /*  a`   a'   a^   a~   a:   ao   ae   c, */
  1308.     48, 48, 48, 48, 48, 48, 48, 48,
  1309. /*  e`   e'   e^   e:    i`  i'   i^   i: */
  1310.     48, 48, 48, 48, 48, 48, 48, 48,
  1311. /*   d   n~   o`   o'   o^   o~   o:   -: */
  1312.     48, 48, 48, 48, 48, 48, 48, 248,
  1313. /*  o/   u`   u'   u^   u:   y'    P   y: */
  1314. 48, 48, 48, 48, 48, 48, 48, 48};
  1315.  
  1316. static int
  1317. set_character_class_range(low, high, value)
  1318.     register int low,
  1319.                 high;        /* in range of [0..255] */
  1320.     register int value;        /* arbitrary */
  1321. {
  1322.  
  1323.     if (low < 0 || high > 255 || high < low)
  1324.     return (-1);
  1325.  
  1326.     for (; low <= high; low++)
  1327.     charClass[low] = value;
  1328.  
  1329.     return (0);
  1330. }
  1331.  
  1332.  
  1333. /*
  1334.  * set_character_class - takes a string of the form
  1335.  *
  1336.  *                 low[-high]:val[,low[-high]:val[...]]
  1337.  *
  1338.  * and sets the indicated ranges to the indicated values.
  1339.  */
  1340.  
  1341. static int
  1342. set_character_class(s)
  1343.     register char *s;
  1344. {
  1345.     register int i;        /* iterator, index into s */
  1346.     int         len;        /* length of s */
  1347.     int         acc;        /* accumulator */
  1348.     int         low,
  1349.                 high;        /* bounds of range [0..127] */
  1350.     int         base;        /* 8, 10, 16 (octal, decimal, hex) */
  1351.     int         numbers;    /* count of numbers per range */
  1352.     int         digits;        /* count of digits in a number */
  1353.     static char *errfmt = "%s:  %s in range string \"%s\" (position %d)\n";
  1354.  
  1355.     if (!s || !s[0])
  1356.     return -1;
  1357.  
  1358.     base = 10;            /* in case we ever add octal, hex */
  1359.     low = high = -1;        /* out of range */
  1360.  
  1361.     for (i = 0, len = strlen(s), acc = 0, numbers = digits = 0;
  1362.         i < len; i++) {
  1363.     char        c = s[i];
  1364.  
  1365.     if (isspace(c)) {
  1366.         continue;
  1367.     } else if (isdigit(c)) {
  1368.         acc = acc * base + (c - '0');
  1369.         digits++;
  1370.         continue;
  1371.     } else if (c == '-') {
  1372.         low = acc;
  1373.         acc = 0;
  1374.         if (digits == 0) {
  1375.         fprintf(stderr, errfmt, progname, "missing number", s, i);
  1376.         return (-1);
  1377.         }
  1378.         digits = 0;
  1379.         numbers++;
  1380.         continue;
  1381.     } else if (c == ':') {
  1382.         if (numbers == 0)
  1383.         low = acc;
  1384.         else if (numbers == 1)
  1385.         high = acc;
  1386.         else {
  1387.         fprintf(stderr, errfmt, progname, "too many numbers",
  1388.             s, i);
  1389.         return (-1);
  1390.         }
  1391.         digits = 0;
  1392.         numbers++;
  1393.         acc = 0;
  1394.         continue;
  1395.     } else if (c == ',') {
  1396.         /*
  1397.          * now, process it
  1398.          */
  1399.  
  1400.         if (high < 0) {
  1401.         high = low;
  1402.         numbers++;
  1403.         }
  1404.         if (numbers != 2) {
  1405.         fprintf(stderr, errfmt, progname, "bad value number",
  1406.             s, i);
  1407.         } else if (set_character_class_range(low, high, acc) != 0) {
  1408.         fprintf(stderr, errfmt, progname, "bad range", s, i);
  1409.         }
  1410.         low = high = -1;
  1411.         acc = 0;
  1412.         digits = 0;
  1413.         numbers = 0;
  1414.         continue;
  1415.     } else {
  1416.         fprintf(stderr, errfmt, progname, "bad character", s, i);
  1417.         return (-1);
  1418.     }            /* end if else if ... else */
  1419.  
  1420.     }
  1421.  
  1422.     if (low < 0 && high < 0)
  1423.     return (0);
  1424.  
  1425.     /*
  1426.      * now, process it
  1427.      */
  1428.  
  1429.     if (high < 0)
  1430.     high = low;
  1431.     if (numbers < 1 || numbers > 2) {
  1432.     fprintf(stderr, errfmt, progname, "bad value number", s, i);
  1433.     } else if (set_character_class_range(low, high, acc) != 0) {
  1434.     fprintf(stderr, errfmt, progname, "bad range", s, i);
  1435.     }
  1436.     return (0);
  1437. }
  1438.  
  1439. static void
  1440. change_selection(tw, set, save)
  1441.     TextWindow  tw;
  1442.     Bool        set;
  1443.     Bool        save;
  1444. {
  1445.     int         r,
  1446.                 c,
  1447.                 start,
  1448.                 end;
  1449.  
  1450.     tw->show_selection = set;
  1451.     if (save) {
  1452.     x_stash_selection(tw);
  1453.     tw->have_selection = False;
  1454.     }
  1455.     start = tw->sel_start_col;
  1456.     for (r = tw->sel_start_row; r <= tw->sel_end_row; r++) {
  1457.     end = (r == tw->sel_end_row) ? tw->sel_end_col : (tw->cols - 1);
  1458.     tw->line_attr[r] |= LINE_DIRTY;
  1459.     for (c = start; c <= end; c++) {
  1460.         tw->attr[r][c] |= CELL_DIRTY;
  1461.         if (set) {
  1462.         tw->attr[r][c] |= CELL_SELECTION;
  1463.         } else {
  1464.         tw->attr[r][c] &= ~CELL_SELECTION;
  1465.         }
  1466.     }
  1467.     start = 0;
  1468.     }
  1469. }
  1470.  
  1471. static void
  1472. x_lose_selection(tw)
  1473.     TextWindow  tw;
  1474. {
  1475.     if (tw->have_selection)
  1476.     change_selection(tw, False, False);
  1477.     tw->have_selection = False;
  1478.     tw->selection_len = 0;
  1479.     x_flush();            /* show the changes */
  1480. }
  1481.  
  1482. /* ARGSUSED */
  1483. static void
  1484. x_get_selection(tw, selection, type, value, length, format)
  1485.     TextWindow  tw;
  1486.     Atom        selection;
  1487.     Atom        type;
  1488.     long        length;
  1489.     char       *value;
  1490.     int         format;
  1491. {
  1492.     if (format != 8 || type != XA_STRING)
  1493.     return;            /* can't handle incoming data */
  1494.  
  1495.     if (length) {
  1496.     /* should be impossible to hit this with existing paste */
  1497.     /* XXX massive hack -- leave out 'i' if in prompt line */
  1498.     if (!insertmode && (tw->cur_row < (tw->rows - 1))) {
  1499.         length++;
  1500.         pp = paste = (char *) malloc(length);
  1501.         if (!paste)
  1502.         goto bail;
  1503.         *pp = 'i';
  1504.         plen = length;
  1505.         length--;
  1506.         bcopy((char *) value, pp + 1, length);
  1507.     } else {
  1508.         pp = paste = (char *) malloc(length);
  1509.         if (!paste)
  1510.         goto bail;
  1511.         bcopy((char *) value, pp, length);
  1512.         plen = length;
  1513.     }
  1514.     }
  1515. bail:
  1516.     free(value);
  1517. }
  1518.  
  1519. static void
  1520. x_paste_selection(tw)
  1521.     TextWindow  tw;
  1522. {
  1523.     if (tw->have_selection) {
  1524.     /* local transfer */
  1525.     if (tw->selection_len == 0)    /* stash it if it hasn't been */
  1526.         x_stash_selection(tw);
  1527.     x_get_selection(tw, XA_PRIMARY, XA_STRING,
  1528.              strndup((char *) tw->selection_data, tw->selection_len),
  1529.             tw->selection_len, 8);
  1530.     } else {
  1531.     XConvertSelection(tw->dpy, XA_PRIMARY, XA_STRING, tw->sel_prop,
  1532.               tw->win, CurrentTime);
  1533.     }
  1534. }
  1535.  
  1536. static void
  1537. x_stash_selection(tw)
  1538.     TextWindow  tw;
  1539. {
  1540.     unsigned char *data,
  1541.                *dp;
  1542.     int         r;
  1543.     int         length = 0;
  1544.     int         start,
  1545.                 end;
  1546.  
  1547.     if (!tw->have_selection)
  1548.     return;
  1549.     if (tw->selection_len) {
  1550.     free(tw->selection_data);
  1551.     tw->selection_len = 0;
  1552.     }
  1553.     if (tw->sel_start_row == tw->sel_end_row) {
  1554.     length = tw->sel_end_col - tw->sel_start_col + 1;
  1555.     data = (unsigned char *) malloc(length);
  1556.     if (!data)
  1557.         return;
  1558.     bcopy((char *) &(tw->sc[tw->sel_start_row][tw->sel_start_col]),
  1559.           data, length);
  1560.     tw->selection_len = length;
  1561.     } else {
  1562.     start = tw->sel_start_col;
  1563.     for (r = tw->sel_start_row; r <= tw->sel_end_row; r++) {
  1564.         end = (r == tw->sel_end_row) ? tw->sel_end_col : (tw->cols - 1);
  1565.         length += end - start + 2;    /* add CR */
  1566.         start = 0;
  1567.     }
  1568.     dp = data = (unsigned char *) malloc(length);
  1569.     if (!data)
  1570.         return;
  1571.     tw->selection_len = length;
  1572.     start = tw->sel_start_col;
  1573.     for (r = tw->sel_start_row; r <= tw->sel_end_row; r++) {
  1574.         end = (r == tw->sel_end_row) ? tw->sel_end_col : (tw->cols - 1);
  1575.         length = end - start + 1;
  1576.         bcopy((char *) &(tw->sc[r][start]), dp, length);
  1577.         dp += length;
  1578.         *dp++ = '\n';    /* add CR */
  1579.         start = 0;
  1580.     }
  1581.     }
  1582.     tw->selection_data = data;
  1583.  
  1584. #ifdef SABER_HACK
  1585.     XChangeProperty(dpy, RootWindow(tw->dpy, tw->screen), XA_CUT_BUFFER0,
  1586.             XA_STRING, 8, PropModeReplace,
  1587.             tw->selection_data, tw->selection_len);
  1588. #endif
  1589. }
  1590.  
  1591. /* ARGSUSED */
  1592. static Bool
  1593. x_give_selection(tw, ev, target, prop)
  1594.     TextWindow  tw;
  1595.     XSelectionRequestEvent *ev;
  1596.     Atom        target;
  1597.     Atom        prop;
  1598. {
  1599.     if (tw->show_selection)
  1600.     x_stash_selection(tw);
  1601.     XChangeProperty(dpy, ev->requestor, prop, XA_STRING, 8,
  1602.             PropModeReplace, tw->selection_data, tw->selection_len);
  1603.     return True;
  1604. }
  1605.  
  1606. static void
  1607. x_own_selection(tw)
  1608.     TextWindow  tw;
  1609. {
  1610.     if (tw->selection_len) {    /* get rid of old one */
  1611.     tw->selection_len = 0;
  1612.     free(tw->selection_data);
  1613.     }
  1614.     if (!tw->have_selection) {
  1615.     XSetSelectionOwner(tw->dpy, XA_PRIMARY, tw->win, CurrentTime);
  1616.     }
  1617.     change_selection(tw, True, False);
  1618.     x_flush();            /* show the changes */
  1619. }
  1620.  
  1621. static void
  1622. extend_selection(tw, nr, nc, wipe)
  1623.     TextWindow  tw;
  1624.     int         nr,
  1625.                 nc;
  1626.     Bool        wipe;
  1627. {
  1628.     if (tw->have_selection)    /* erase any old one */
  1629.     change_selection(tw, False, False);
  1630.  
  1631.     if (wipe) {            /* a wipe is always relative to its starting
  1632.                  * point */
  1633.     if (nr > tw->wipe_row) {
  1634.         tw->sel_end_row = nr;
  1635.         tw->sel_end_col = nc;
  1636.         tw->sel_start_col = tw->wipe_col;
  1637.         tw->sel_start_row = tw->wipe_row;
  1638.     } else if (nr == tw->wipe_row) {
  1639.         tw->sel_end_row = tw->sel_start_row = nr;
  1640.         if (nc > tw->wipe_col) {
  1641.         tw->sel_start_col = tw->wipe_col;
  1642.         tw->sel_end_col = nc;
  1643.         } else {
  1644.         tw->sel_start_col = nc;
  1645.         tw->sel_end_col = tw->wipe_col;
  1646.         }
  1647.     } else {
  1648.         tw->sel_start_row = nr;
  1649.         tw->sel_start_col = nc;
  1650.         tw->sel_end_col = tw->wipe_col;
  1651.         tw->sel_end_row = tw->wipe_row;
  1652.     }
  1653.     } else {
  1654.     if (nr < tw->sel_start_row) {
  1655.         if (!tw->have_selection)
  1656.         tw->sel_end_row = tw->sel_start_row;
  1657.         tw->sel_start_row = nr;
  1658.     } else {
  1659.         tw->sel_end_row = nr;
  1660.     }
  1661.  
  1662.     if (nc < tw->sel_start_col) {
  1663.         if (!tw->have_selection)
  1664.         tw->sel_end_col = tw->sel_start_col;
  1665.         tw->sel_start_col = nc;
  1666.     } else {
  1667.         tw->sel_end_col = nc;
  1668.     }
  1669.     }
  1670.  
  1671.     tw->show_selection = True;
  1672.     x_own_selection(tw);
  1673.     tw->have_selection = True;
  1674.  
  1675. #ifdef SABER_HACK
  1676.     x_stash_selection(tw);
  1677. #endif
  1678. }
  1679.  
  1680. static void
  1681. multi_click(tw, nr, nc)
  1682.     TextWindow  tw;
  1683.     int         nr,
  1684.                 nc;
  1685. {
  1686.     unsigned char *p;
  1687.     int         sc;
  1688.     int         cclass;
  1689.  
  1690.     tw->numclicks++;
  1691.  
  1692.     sc = tw->sel_start_col;
  1693.     switch (tw->numclicks) {
  1694.     case 0:
  1695.     case 1:
  1696.     abort();
  1697.     case 2:            /* word */
  1698.     /* find word start */
  1699.     p = &(tw->sc[nr][sc]);
  1700.     cclass = charClass[*p];
  1701.     do {
  1702.         --sc;
  1703.         --p;
  1704.     } while (sc >= 0 && charClass[*p] == cclass);
  1705.     sc++;
  1706.     /* and end */
  1707.     p = &(tw->sc[nr][nc]);
  1708.     cclass = charClass[*p];
  1709.     do {
  1710.         ++nc;
  1711.         ++p;
  1712.     } while (nc < tw->cols && charClass[*p] == cclass);
  1713.     --nc;
  1714.     break;
  1715.     case 3:            /* line */
  1716.     sc = 0;
  1717.     nc = tw->cols - 1;
  1718.     break;
  1719.     case 4:            /* screen */
  1720.     /* XXX blow off till we can figure out where screen starts & ends */
  1721.     default:
  1722.     break;
  1723.     }
  1724.     tw->sel_start_col = sc;
  1725.     tw->sel_end_col = nc;
  1726.     tw->show_selection = True;
  1727.     x_own_selection(tw);
  1728.     tw->have_selection = True;
  1729.  
  1730. #ifdef SABER_HACK
  1731.     x_stash_selection(tw);
  1732. #endif
  1733. }
  1734.  
  1735.  
  1736. static void
  1737. start_selection(tw, ev, nr, nc)
  1738.     TextWindow  tw;
  1739.     XButtonPressedEvent *ev;
  1740.     int         nr,
  1741.                 nc;
  1742. {
  1743.     if (tw->lasttime && (absol(ev->time - tw->lasttime) < tw->click_timeout)) {
  1744.     /* ignore extra clicks on other rows */
  1745.     if (nr == tw->sel_start_row) {
  1746.         multi_click(tw, nr, nc);
  1747.         return;
  1748.     }
  1749.     }
  1750.     tw->lasttime = ev->time;
  1751.     tw->numclicks = 1;
  1752.  
  1753.     if (tw->have_selection) {
  1754.     change_selection(tw, False, True);
  1755.     tw->show_selection = False;
  1756.     }
  1757.     tw->sel_start_row = nr;
  1758.     tw->sel_start_col = nc;
  1759.     tw->sel_end_row = nr;
  1760.     tw->sel_end_col = nc;
  1761.     tw->wipe_row = nr;
  1762.     tw->wipe_col = nc;
  1763.  
  1764.     if (tw->cur_row == (tw->rows - 1)) {
  1765.     return;
  1766.     }
  1767.     setcursor(nr, nc);
  1768.     /* 'True' forces the point to be centered */
  1769.     refresh((ev->state ? True : False), 0);
  1770.     (void) update(False);
  1771. }
  1772.  
  1773. static XMotionEvent *
  1774. compress_motion(ev)
  1775.     XMotionEvent *ev;
  1776. {
  1777.     XEvent      nev;
  1778.  
  1779.     while (XPending(ev->display)) {
  1780.     XPeekEvent(ev->display, &nev);
  1781.     if (nev.type == MotionNotify &&
  1782.         nev.xmotion.window == ev->window &&
  1783.         nev.xmotion.subwindow == ev->subwindow) {
  1784.         XNextEvent(ev->display, (XEvent *) ev);
  1785.     } else
  1786.         break;
  1787.     }
  1788.     return ev;
  1789. }
  1790.  
  1791. /*
  1792.  * handle any non keyboard events
  1793.  */
  1794. static void
  1795. x_process_event(ev)
  1796.     XEvent     *ev;
  1797. {
  1798.     int         nr,
  1799.                 nc;
  1800.     Bool        changed = False;
  1801.     XSelectionEvent event;
  1802.     XMotionEvent *mev;
  1803.  
  1804.     switch (ev->type) {
  1805.     case SelectionClear:
  1806.     x_lose_selection(cur_win);
  1807.     break;
  1808.     case SelectionRequest:
  1809.     event.type = SelectionNotify;
  1810.     event.display = ev->xselectionrequest.display;
  1811.     event.requestor = ev->xselectionrequest.requestor;
  1812.     event.selection = ev->xselectionrequest.selection;
  1813.     event.time = ev->xselectionrequest.time;
  1814.     event.target = ev->xselectionrequest.target;
  1815.     event.target = ev->xselectionrequest.target;
  1816.     if (ev->xselectionrequest.property == None)    /* obsolete requestor */
  1817.         ev->xselectionrequest.property = ev->xselectionrequest.target;
  1818.     if (x_give_selection(cur_win, (XSelectionRequestEvent *) ev,
  1819.                  ev->xselectionrequest.target,
  1820.                  ev->xselectionrequest.property)) {
  1821.         event.property = ev->xselectionrequest.property;
  1822.     } else {
  1823.         event.property = None;
  1824.     }
  1825.     (void) XSendEvent(dpy, event.requestor, False, (unsigned long) 0,
  1826.               (XEvent *) & event);
  1827.     break;
  1828.     case SelectionNotify:
  1829.     if (ev->xselection.property == None) {
  1830.         x_get_selection(cur_win, ev->xselection.selection,
  1831.                 None, (char *) 0, 0, 8);
  1832.     } else {
  1833.         unsigned long bytesafter;
  1834.         unsigned long length;
  1835.         int         format;
  1836.         Atom        type;
  1837.         unsigned char *value;
  1838.  
  1839.         (void) XGetWindowProperty(dpy, cur_win->win,
  1840.                       ev->xselection.property,
  1841.               0L, 100000, False, AnyPropertyType, &type, &format,
  1842.                       &length, &bytesafter, &value);
  1843.         XDeleteProperty(dpy, cur_win->win, ev->xselection.property);
  1844.         x_get_selection(cur_win, ev->xselection.selection,
  1845.                 type, (char *) value, length, format);
  1846.     }
  1847.     break;
  1848.  
  1849.     case Expose:
  1850.     /* XXX this should be smarter about lots of resizes */
  1851.     if (ev->xexpose.count == 0) {
  1852.         x_refresh(cur_win, 0, 0, cur_win->cols, cur_win->rows);
  1853.     }
  1854.     break;
  1855.     case EnterNotify:
  1856.     case FocusIn:
  1857.     cur_win->show_cursor = True;
  1858.     cur_win->line_attr[cur_win->cur_row] |= LINE_DIRTY;
  1859.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] |=
  1860.         CELL_DIRTY | CELL_CURSOR;
  1861.     x_flush();
  1862.     break;
  1863.     case LeaveNotify:
  1864.     case FocusOut:
  1865.     cur_win->line_attr[cur_win->cur_row] |= LINE_DIRTY;
  1866.     cur_win->show_cursor = False;
  1867.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] |= CELL_DIRTY;
  1868.     cur_win->attr[cur_win->cur_row][cur_win->cur_col] &= ~CELL_CURSOR;
  1869.     x_flush();
  1870.     break;
  1871.     case ConfigureNotify:
  1872.     nr = ev->xconfigure.height / cur_win->char_height;
  1873.     nc = ev->xconfigure.width / cur_win->char_width;
  1874.  
  1875.     if (nc != cur_win->cols) {
  1876.         changed = True;
  1877.         newwidth(True, nc);
  1878.     }
  1879.     if (nr != cur_win->rows) {
  1880.         changed = True;
  1881.         newlength(True, nr);
  1882.     }
  1883.     if (changed) {
  1884.         x_resize_screen(cur_win, nr, nc);
  1885.  
  1886.         refresh(True, 0);
  1887.  
  1888.         (void) update(False);
  1889.     }
  1890.     break;
  1891.     case MotionNotify:
  1892.     if (ev->xmotion.state != Button1Mask)
  1893.         return;
  1894.     mev = compress_motion((XMotionEvent *) ev);
  1895.     nc = mev->x / cur_win->char_width;
  1896.     nr = mev->y / cur_win->char_height;
  1897.     /* bounds check */
  1898.     if (nr < 0 || nc < 0 || nr >= cur_win->rows || nc >= cur_win->cols)
  1899.         return;
  1900.     /* ignore any spurious motion during a multi-cick */
  1901.     if (cur_win->numclicks > 1)
  1902.         return;
  1903.     extend_selection(cur_win, nr, nc, True);
  1904.     break;
  1905.     case ButtonPress:
  1906.     nc = ev->xbutton.x / cur_win->char_width;
  1907.     nr = ev->xbutton.y / cur_win->char_height;
  1908.     switch (ev->xbutton.button) {
  1909.     case Button1:        /* move button and set selection point */
  1910.         start_selection(cur_win, (XButtonPressedEvent *) ev, nr, nc);
  1911.         break;
  1912.     case Button2:        /* paste selection */
  1913.         if (ev->xbutton.state)    /* if modifier, paste at mouse */
  1914.         setcursor(nr, nc);
  1915.         x_paste_selection(cur_win);
  1916.         break;
  1917.     case Button3:        /* end selection */
  1918.         extend_selection(cur_win, nr, nc, False);
  1919.         cur_win->wipe_row = 0;
  1920.         cur_win->wipe_col = 0;
  1921.         break;
  1922.     }
  1923.     break;
  1924.     }
  1925. }
  1926.  
  1927. /*
  1928.  * main event loop.  this means we'll be stuck if an event that needs
  1929.  * instant processing comes in while its off doing other work, but
  1930.  * there's no (easy) way around that.
  1931.  */
  1932. static int
  1933. x_getc()
  1934. {
  1935.     XEvent      ev;
  1936.     char        buffer[10];
  1937.     KeySym      keysym;
  1938.     int         num;
  1939.     int         c;
  1940.  
  1941.     while (1) {
  1942.     if (plen) {        /* handle any queued pasted text */
  1943.         c = *pp++;
  1944.         if (--plen == 0)
  1945.         free(paste);
  1946.         return c;
  1947.     }
  1948.     XNextEvent(dpy, &ev);
  1949.     if (ev.type == KeyPress) {
  1950.         num = XLookupString((XKeyPressedEvent *) & ev, buffer, 10, &keysym,
  1951.                 (XComposeStatus *) 0);
  1952.         /* fake arrow keys -- XXX breaks down when not in insert mode */
  1953.         switch (keysym) {
  1954.         case XK_Left:
  1955.         return 'h';
  1956.         case XK_Right:
  1957.         return 'l';
  1958.         case XK_Up:
  1959.         return 'k';
  1960.         case XK_Down:
  1961.         return 'j';
  1962.         default:
  1963.         if (num)
  1964.             return buffer[0];
  1965.         }
  1966.     } else {
  1967.         x_process_event(&ev);
  1968.     }
  1969.     }
  1970. }
  1971.  
  1972. /* ARGSUSED */
  1973. static Bool
  1974. check_kbd_ev(disp, ev, arg)
  1975.     Display    *disp;
  1976.     XEvent     *ev;
  1977.     char       *arg;
  1978. {
  1979.     return (ev->type == KeyPress);
  1980. }
  1981.  
  1982. int
  1983. x_key_events_ready()
  1984. {
  1985.     XEvent      ev;
  1986.  
  1987.     /* XXX may want to use another mode */
  1988.     if (XEventsQueued(dpy, QueuedAlready))
  1989.     return XPeekIfEvent(dpy, &ev, check_kbd_ev, NULL);
  1990.     return FALSE;
  1991. }
  1992.  
  1993. /*
  1994.  * change reverse video status
  1995.  */
  1996. static void
  1997. x_rev(state)
  1998.     int         state;
  1999. {
  2000.     cur_win->reverse = state;
  2001. }
  2002.  
  2003. /* change screen resolution */
  2004. static int
  2005. x_cres()
  2006. {
  2007.     return TRUE;
  2008. }
  2009.  
  2010. #if COLOR
  2011. static int
  2012. x_fcol()
  2013. {
  2014. }
  2015.  
  2016. static int
  2017. x_bcol()
  2018. {
  2019. }
  2020.  
  2021. #endif
  2022.  
  2023. /* change palette string */
  2024. /* ARGSUSED */
  2025. void
  2026. spal(dummy)
  2027. char *dummy;
  2028. {
  2029. }
  2030.  
  2031. /* beep */
  2032. static void
  2033. x_beep()
  2034. {
  2035.     XBell(cur_win->dpy, 0);
  2036. }
  2037.  
  2038. #else
  2039. x11hello() {}
  2040. #endif                /* X11 */
  2041.