home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / x11.c < prev    next >
C/C++ Source or Header  |  1998-09-29  |  153KB  |  6,174 lines

  1. /*
  2.  *    X11 support, Dave Lemke, 11/91
  3.  *    X Toolkit support, Kevin Buettner, 2/94
  4.  *
  5.  * $Header: /usr/build/vile/vile/RCS/x11.c,v 1.192 1998/09/29 23:51:35 tom Exp $
  6.  *
  7.  */
  8.  
  9. /*
  10.  * Widget set selection.
  11.  *
  12.  * You must have exactly one of the following defined
  13.  *
  14.  *    NO_WIDGETS    -- Use only Xlib and X toolkit (Xt)
  15.  *    ATHENA_WIDGETS    -- Use Xlib, Xt, and Xaw widget set
  16.  *    MOTIF_WIDGETS    -- Use Xlib, Xt, and Motif widget set
  17.  *    OL_WIDGETS    -- Use Xlib, Xt, and Openlook widget set
  18.  *
  19.  * We derive/set from the configure script some flags that allow intermediate
  20.  * configurations between NO_WIDGETS and ATHENA_WIDGETS
  21.  *
  22.  *    KEV_WIDGETS
  23.  *    OPT_KEV_DRAGGING
  24.  *    OPT_KEV_SCROLLBARS
  25.  */
  26.  
  27. #define NEED_X_INCLUDES 1
  28. #include    "estruct.h"
  29. #include    "edef.h"
  30. #include    "nefunc.h"
  31. #include    "pscreen.h"
  32.  
  33. #include    <X11/cursorfont.h>
  34.  
  35. #if defined(lint) && HAVE_X11_INTRINSICI_H
  36. #include    <X11/IntrinsicI.h>
  37. #endif
  38.  
  39. #if XtSpecificationRelease < 4
  40. #define XtPointer caddr_t
  41. #endif
  42.  
  43. #if DISP_X11 && XTOOLKIT
  44.  
  45. /* sanity-check, so we know it's safe to not nest ifdef's */
  46.  
  47. #if NO_WIDGETS
  48. # if ATHENA_WIDGETS || MOTIF_WIDGETS || OL_WIDGETS
  49.    >make an error<
  50. # endif
  51. #else
  52. # if ATHENA_WIDGETS
  53. #  if MOTIF_WIDGETS || OL_WIDGETS
  54.     >make an error<
  55. #  endif
  56. # else
  57. #  if MOTIF_WIDGETS
  58. #   if OL_WIDGETS
  59.      >make an error<
  60. #   endif
  61. #  else
  62. #   if !OL_WIDGETS
  63.      >make an error<
  64. #   endif
  65. #  endif
  66. # endif
  67. #endif
  68.  
  69. #ifndef OPT_KEV_SCROLLBARS
  70. # if NO_WIDGETS
  71. #  define OPT_KEV_SCROLLBARS 1
  72. # endif
  73. #endif
  74.  
  75. #ifndef OPT_KEV_DRAGGING
  76. # if NO_WIDGETS
  77. #  define OPT_KEV_DRAGGING 1
  78. # endif
  79. #endif
  80.  
  81. #ifndef KEV_WIDGETS
  82. # if NO_WIDGETS || OPT_KEV_SCROLLBARS
  83. #  define KEV_WIDGETS 1
  84. # endif
  85. #endif
  86.  
  87. #ifndef OPT_XAW_SCROLLBARS
  88. # if ATHENA_WIDGETS && !OPT_KEV_SCROLLBARS
  89. #  define OPT_XAW_SCROLLBARS 1
  90. # endif
  91. #endif
  92.  
  93. #define MY_CLASS    "XVile"
  94.  
  95. #if SYS_VMS
  96. #undef SYS_UNIX
  97. #define coreWidgetClass widgetClass /* patch for VMS 5.4-3 (dickey) */
  98. #endif
  99.  
  100. /* redefined in X11/Xos.h */
  101. #undef strchr
  102. #undef strrchr
  103.  
  104. #if OPT_XAW_SCROLLBARS
  105. #if HAVE_LIB_XAW
  106. #include    <X11/Xaw/Form.h>
  107. #include    <X11/Xaw/Grip.h>
  108. #include    <X11/Xaw/Scrollbar.h>
  109. #endif
  110. #if HAVE_LIB_XAW3D
  111. #include    <X11/Xaw3d/Form.h>
  112. #include    <X11/Xaw3d/Grip.h>
  113. #include    <X11/Xaw3d/Scrollbar.h>
  114. #endif
  115. #if HAVE_LIB_NEXTAW
  116. #include    <X11/neXtaw/Form.h>
  117. #include    <X11/neXtaw/Grip.h>
  118. #include    <X11/neXtaw/Scrollbar.h>
  119. #endif
  120. #endif /* OPT_XAW_SCROLLBARS */
  121.  
  122. #if OL_WIDGETS
  123. #undef BANG
  124. #include    <Xol/OpenLook.h>
  125. #include    <Xol/Form.h>
  126. #include    <Xol/BulletinBo.h>
  127. #include    <Xol/Slider.h>
  128. #include    <Xol/Scrollbar.h>
  129. #endif /* OL_WIDGETS */
  130.  
  131. #include    <X11/Shell.h>
  132. #include    <X11/keysym.h>
  133. #include    <X11/Xatom.h>
  134.  
  135. #if MOTIF_WIDGETS
  136. #include    <Xm/Form.h>
  137. #include    <Xm/PanedW.h>
  138. #include    <Xm/ScrollBar.h>
  139. #include    <Xm/SashP.h>
  140. #if defined(lint) && HAVE_XM_XMP_H
  141. #include    <Xm/XmP.h>
  142. #endif
  143. #endif /* MOTIF_WIDGETS */
  144.  
  145. #define    XCalloc(type)    typecalloc(type)
  146.  
  147. #define    MARGIN    8
  148. #define    SCRSIZ    64
  149. #define    absol(x)    ((x) > 0 ? (x) : -(x))
  150. #define    CEIL(a,b)    ((a + b - 1) / (b))
  151.  
  152. #define onMsgRow(tw)    (ttrow == (int)(tw->rows - 1))
  153.  
  154. /* XXX -- use xcutsel instead */
  155. #undef    SABER_HACK        /* hack to support Saber since it doesn't do
  156.                  * selections right */
  157.  
  158. #undef btop        /* defined in SunOS includes */
  159.  
  160. #define PANE_WIDTH_MAX 200
  161.  
  162. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  163. # define PANE_WIDTH_DEFAULT 15
  164. # define PANE_WIDTH_MIN 7
  165. #else
  166. # if MOTIF_WIDGETS || OL_WIDGETS
  167. #  define PANE_WIDTH_DEFAULT 20
  168. #  define PANE_WIDTH_MIN 10
  169. # endif
  170. #endif
  171.  
  172. #ifndef XtNmenuHeight
  173. #define XtNmenuHeight "menuHeight"
  174. #endif
  175.  
  176. #ifndef XtCMenuHeight
  177. #define XtCMenuHeight "MenuHeight"
  178. #endif
  179.  
  180. #if OPT_MENUS_COLORED
  181. #define XtNmenuBackground "menuBackground"
  182. #define XtNmenuForeground "menuForeground"
  183. #define XtCMenuBackground "MenuBackground"
  184. #define XtCMenuForeground "MenuForeground"
  185. #endif
  186.  
  187. #define MENU_HEIGHT_DEFAULT 20
  188.  
  189. #define MINCOLS    30
  190. #define MINROWS MINWLNS
  191. #define MAXSBS    ((MAXROWS) / 2)
  192.  
  193. /* Blinking cursor toggle...defined this way to leave room for future
  194.  * cursor flags.
  195.  */
  196. #define    BLINK_TOGGLE    0x1
  197.  
  198. /*
  199.  * Fonts searched flags
  200.  */
  201.  
  202. #define FSRCH_BOLD    0x1
  203. #define FSRCH_ITAL    0x2
  204. #define FSRCH_BOLDITAL    0x4
  205.  
  206. /* Keyboard queue size */
  207. #define KQSIZE 64
  208.  
  209. static Display *dpy;
  210.  
  211. #if OPT_MENUS
  212. #if ATHENA_WIDGETS
  213. #include <X11/Xaw/SimpleMenu.h>
  214. #include <X11/Xaw/Box.h>
  215. #include <X11/Xaw/Form.h>
  216. #include <X11/Xaw/Paned.h>
  217. #endif
  218. #if MOTIF_WIDGETS
  219. #include <Xm/RowColumn.h>
  220. #endif
  221.     Widget    menub;
  222. #endif
  223.  
  224. #if OPT_XAW_SCROLLBARS
  225. typedef struct _scroll_info {
  226.     int        totlen;        /* total length of scrollbar */
  227. } ScrollInfo;
  228. #else
  229. #if OPT_KEV_SCROLLBARS
  230. typedef struct _scroll_info {
  231.     int        top;        /* top of "thumb" */
  232.     int        bot;        /* bottom of "thumb" */
  233.     int        totlen;        /* total length of scrollbar */
  234.     Boolean    exposed;    /* has scrollbar received expose event? */
  235. } ScrollInfo;
  236. #endif
  237. #endif
  238.  
  239. typedef struct _text_win {
  240.     /* X stuff */
  241.     Window    win;        /* window corresponding to screen */
  242.     XtAppContext
  243.         app_context;    /* application context */
  244.     Widget    top_widget;    /* top level widget */
  245.     Widget    screen;        /* screen widget */
  246. #if ATHENA_WIDGETS
  247.     Widget    pane_widget;    /* pane widget, actually a form */
  248.     Widget    menu_widget;    /* menu-bar widget, actually a box */
  249. #endif
  250.     Widget    form_widget;    /* form enclosing text-display + scrollbars */
  251.     Widget    pane;        /* panes in which scrollbars live */
  252.     int        maxscrollbars;    /* how many scrollbars, sliders, etc. */
  253.     Widget    *scrollbars;
  254.                 /* the scrollbars */
  255.     int        nscrollbars;    /* number of currently active scroll bars */
  256. #if OL_WIDGETS
  257.     Widget    *sliders;
  258. #endif
  259. #if OPT_MENUS_COLORED
  260.     Pixel       menubar_fg;     /* color of the menubar */
  261.     Pixel       menubar_bg;
  262. #endif
  263. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  264.     Pixel    scrollbar_fg;
  265.     Pixel    scrollbar_bg;
  266.     Bool    slider_is_solid;
  267.     Bool    slider_is_3D;
  268.     GC        scrollbargc;    /* graphics context for scrollbar "thumb" */
  269.     Pixmap    trough_pixmap;
  270.     Pixmap    slider_pixmap;
  271.     ScrollInfo    *scrollinfo;
  272.     Widget    *grips;     /* grips for resizing scrollbars */
  273.     XtIntervalId scroll_repeat_id;
  274.     ULONG    scroll_repeat_timeout;
  275. #endif    /* OPT_KEV_SCROLLBARS */
  276. #if OPT_XAW_SCROLLBARS
  277.     Pixmap    thumb_bm;    /* bitmap for scrollbar thumb */
  278. #endif
  279.     ULONG    scroll_repeat_interval;
  280.     XtIntervalId blink_id;
  281.     int        blink_status;
  282.     int        blink_interval;
  283.     Bool    exposed;    /* Have we received any expose events? */
  284.     int        visibility;    /* How visible is the window? */
  285.  
  286.     int        base_width;    /* width with screen widgets' width zero */
  287.     int        base_height;
  288.     UINT    pane_width;    /* full width of scrollbar pane */
  289.     Dimension    menu_height;    /* height of menu-bar */
  290.     Dimension    top_width;    /* width of top widget as of last resize */
  291.     Dimension    top_height;    /* height of top widget as of last resize */
  292.  
  293.     int        fsrch_flags;    /* flags which indicate which fonts have
  294.                  * been searched for
  295.                  */
  296.     XFontStruct *pfont;        /* Normal font */
  297.     XFontStruct *pfont_bold;
  298.     XFontStruct *pfont_ital;
  299.     XFontStruct *pfont_boldital;
  300.     GC          textgc;
  301.     GC          reversegc;
  302.     GC        selgc;
  303.     GC        revselgc;
  304.     int        is_color_cursor;
  305.     GC        cursgc;
  306.     GC        revcursgc;
  307.     GC        modeline_focus_gc;    /* GC for modeline w/ focus */
  308.     GC        modeline_gc;        /* GC for other modelines  */
  309.     GC        colors_fgc[16];
  310.     GC        colors_bgc[16];
  311.     Pixel    fg;
  312.     Pixel    bg;
  313.     Pixel    colors_fg[16];
  314.     Pixel    colors_bg[16];
  315.     Pixel    modeline_fg;
  316.     Pixel    modeline_bg;
  317.     Pixel    modeline_focus_fg;
  318.     Pixel    modeline_focus_bg;
  319.     Pixel    selection_fg;
  320.     Pixel    selection_bg;
  321.     int         char_width,
  322.                 char_ascent,
  323.         char_descent,
  324.                 char_height;
  325.     Bool    left_ink,    /* font has "ink" past bounding box on left */
  326.         right_ink;    /* font has "ink" past bounding box on right */
  327.     char       *geometry;
  328.     char       *starting_fontname;    /* name of font at startup */
  329.     char       *fontname;        /* name of current font */
  330.     Bool    focus_follows_mouse;
  331.     Bool    fork_on_startup;
  332.     Bool    scrollbar_on_left;
  333.     Bool    update_window_name;
  334.     Bool    update_icon_name;
  335.     Bool    persistent_selections;
  336.     Bool    selection_sets_DOT;
  337.  
  338.     /* text stuff */
  339.     Bool        reverse;
  340.     unsigned    rows,
  341.                 cols;
  342.     Bool        show_cursor;
  343.  
  344.     /* cursor stuff */
  345.     Pixel    cursor_fg;
  346.     Pixel    cursor_bg;
  347.  
  348.     /* pointer stuff */
  349.     Pixel    pointer_fg;
  350.     Pixel    pointer_bg;
  351.     Cursor    normal_pointer;
  352. #if OPT_WORKING
  353.     Cursor    watch_pointer;
  354.     Bool    want_to_work;
  355. #endif
  356.  
  357.     /* selection stuff */
  358.     String    multi_click_char_class;    /* ?? */
  359.     Time        lasttime;    /* for multi-click */
  360.     Time        click_timeout;
  361.     int         numclicks;
  362.     Bool        have_selection;
  363.     Bool    wipe_permitted;
  364.     Bool    was_on_msgline;
  365.     Bool    did_select;
  366.     Bool    pasting;
  367.     MARK    prevDOT;        /* DOT prior to selection */
  368.     XtIntervalId sel_scroll_id;
  369.  
  370.     /* key press queue */
  371.     int        kqhead;
  372.     int        kqtail;
  373.     int        kq[KQSIZE];
  374.  
  375.     /* Special translations */
  376.     XtTranslations my_scrollbars_trans;
  377. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  378.     XtTranslations my_resizeGrip_trans;
  379. #endif
  380. }           TextWindowRec, *TextWindow;
  381.  
  382.  
  383. static    TextWindowRec cur_win_rec;
  384. static    TextWindow cur_win = &cur_win_rec;
  385. static    TBUFF    *PasteBuf;
  386.  
  387. static    Atom    atom_WM_PROTOCOLS;
  388. static    Atom    atom_WM_DELETE_WINDOW;
  389. static    Atom    atom_FONT;
  390. static    Atom    atom_FOUNDRY;
  391. static    Atom    atom_WEIGHT_NAME;
  392. static    Atom    atom_SLANT;
  393. static    Atom    atom_SETWIDTH_NAME;
  394. static    Atom    atom_PIXEL_SIZE;
  395. static    Atom    atom_RESOLUTION_X;
  396. static    Atom    atom_RESOLUTION_Y;
  397. static    Atom    atom_SPACING;
  398. static    Atom    atom_AVERAGE_WIDTH;
  399. static    Atom    atom_CHARSET_REGISTRY;
  400. static    Atom    atom_CHARSET_ENCODING;
  401. static    Atom    atom_TARGETS;
  402. static    Atom    atom_MULTIPLE;
  403. static    Atom    atom_TIMESTAMP;
  404. static    Atom    atom_TEXT;
  405. static    Atom    atom_CLIPBOARD;
  406.  
  407. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  408. static    Cursor    curs_sb_v_double_arrow;
  409. static    Cursor    curs_sb_up_arrow;
  410. static    Cursor    curs_sb_down_arrow;
  411. static    Cursor    curs_sb_left_arrow;
  412. static    Cursor    curs_sb_right_arrow;
  413. static    Cursor    curs_double_arrow;
  414. #endif
  415.  
  416. #if MOTIF_WIDGETS
  417. static Bool lookfor_sb_resize = FALSE;
  418. #endif
  419.  
  420. struct eventqueue {
  421.     XEvent event;
  422.     struct eventqueue *next;
  423. };
  424.  
  425. static struct eventqueue *evqhead = NULL;
  426. static struct eventqueue *evqtail = NULL;
  427.  
  428. static    int    x_getc   (void),
  429.         x_cres   ( const char *flag );
  430.  
  431. static    void    x_open   (void),
  432.         x_close  (void),
  433.         x_flush  (void),
  434.         x_kopen  (void),
  435.         x_kclose (void),
  436.         x_beep   (void),
  437.         x_rev    ( UINT state );
  438.  
  439. #if OPT_COLOR
  440. static    void    x_fcol   ( int color ),
  441.         x_bcol   ( int color );
  442. #endif
  443.  
  444. static    void    x_scroll(int from, int to, int count);
  445.  
  446. static    int    x_watchfd(int fd, WATCHTYPE type, long *idp);
  447. static    void    x_unwatchfd(int fd, long id);
  448.  
  449. static    int    set_character_class(char *s);
  450. static    void    x_touch (TextWindow tw, int sc, int sr, UINT ec, UINT er);
  451. static    void    x_paste_selection (Atom selection);
  452. static    void    x_own_selection(Atom selection);
  453. static    Boolean    x_get_selected_text(UCHAR **datp, SIZE_T *lenp);
  454. static    Boolean    x_get_clipboard_text(UCHAR **datp, SIZE_T *lenp);
  455. static    Boolean    x_convert_selection (Widget w, Atom *selection, Atom *target,
  456.             Atom *type, XtPointer *value, unsigned long *length,
  457.             int *format);
  458. static    void    extend_selection (TextWindow tw, int nr, int nc, Bool wipe);
  459. static    void    x_process_event (Widget w, XtPointer unused, XEvent *ev,
  460.             Boolean *continue_to_dispatch);
  461. static    void    x_configure_window (Widget w, XtPointer unused, XEvent *ev,
  462.             Boolean *continue_to_dispatch);
  463. static    void    x_change_focus (Widget w, XtPointer unused, XEvent *ev,
  464.             Boolean *continue_to_dispatch);
  465. static    void    x_typahead_timeout (XtPointer flagp, XtIntervalId *id);
  466. static    void    x_key_press (Widget w, XtPointer unused, XEvent *ev,
  467.             Boolean *continue_to_dispatch);
  468. static    void    x_wm_delwin (Widget w, XtPointer unused, XEvent *ev,
  469.             Boolean *continue_to_dispatch);
  470. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  471. static    Boolean    too_light_or_too_dark (Pixel pixel);
  472. #endif
  473. #if OPT_KEV_SCROLLBARS
  474. static    Boolean    alloc_shadows (Pixel pixel, Pixel *light, Pixel *dark);
  475. #endif
  476. static    XFontStruct *query_font (TextWindow tw, const char *fname);
  477. static    void    configure_bar (Widget w, XEvent *event, String *params,
  478.             Cardinal *num_params);
  479. static    int    check_scrollbar_allocs (void);
  480. static    void    kqinit(TextWindow tw);
  481. static    int    kqempty(TextWindow tw);
  482. static    int    kqfull(TextWindow tw);
  483. static    void    kqadd (TextWindow tw, int c);
  484. static    int    kqpop(TextWindow tw);
  485. static    void    display_cursor (XtPointer client_data, XtIntervalId *idp);
  486. #if 0
  487. static    void    check_visuals (void);
  488. #endif
  489. #if MOTIF_WIDGETS
  490. static    void    grip_moved (Widget w, XtPointer unused, XEvent *ev,
  491.             Boolean *continue_to_dispatch);
  492. static    void    pane_button (Widget w, XtPointer unused, XEvent *ev,
  493.             Boolean *continue_to_dispatch);
  494. #endif /* MOTIF_WIDGETS */
  495. #if OPT_KEV_SCROLLBARS
  496. static    void    x_expose_scrollbar (Widget w, XtPointer unused, XEvent *ev,
  497.             Boolean *continue_to_dispatch);
  498. #endif /* OPT_KEV_SCROLLBARS */
  499. #if OPT_KEV_DRAGGING
  500. static    void    repeat_scroll (XtPointer count, XtIntervalId  *id);
  501. #endif
  502. #if OPT_WORKING
  503. static    void    x_set_watch_cursor(int onflag);
  504. static    int    x_has_events(void);
  505. #else
  506. #define x_has_events() (XtAppPending(cur_win->app_context) & XtIMXEvent)
  507. #endif /* OPT_WORKING */
  508. static    int    evqempty (void);
  509. static    void    evqadd(const XEvent *evp);
  510.  
  511. #define    FONTNAME    "7x13"
  512.  
  513. TERM        term = {
  514.     0,                /* these four values are set dynamically at
  515.                  * open time */
  516.     0,
  517.     0,
  518.     0,
  519.     MARGIN,
  520.     SCRSIZ,
  521.     0,
  522.     x_open,
  523.     x_close,
  524.     x_kopen,
  525.     x_kclose,
  526.     x_getc,
  527.     psc_putchar,
  528.     tttypahead,
  529.     psc_flush,
  530.     psc_move,
  531.     psc_eeol,
  532.     psc_eeop,
  533.     x_beep,
  534.     x_rev,
  535.     x_cres,
  536. #if OPT_COLOR
  537.     x_fcol,
  538.     x_bcol,
  539. #else
  540.     null_t_setfor,
  541.     null_t_setback,
  542. #endif
  543.     null_t_setpal,        /* no palette */
  544.     x_scroll,
  545.     x_flush,
  546.     null_t_icursor,
  547.     null_t_title,
  548.     x_watchfd,
  549.     x_unwatchfd,
  550. };
  551.  
  552.  
  553. #define    x_width(tw)        ((tw)->cols * (tw)->char_width)
  554. #define    x_height(tw)        ((tw)->rows * (tw)->char_height)
  555. #define    x_pos(tw, c)        ((c) * (tw)->char_width)
  556. #define    y_pos(tw, r)        ((r) * (tw)->char_height)
  557. #define    text_y_pos(tw, r)    (y_pos((tw), (r)) + (tw)->char_ascent)
  558. #define min(a,b)        ((a) < (b) ? (a) : (b))
  559. #define max(a,b)        ((a) > (b) ? (a) : (b))
  560.  
  561.  
  562.  
  563. #if KEV_WIDGETS
  564. /* We define our own little bulletin board widget here...if this gets
  565.  * too unwieldly, we should move it to another file.
  566.  */
  567.  
  568. #include    <X11/IntrinsicP.h>
  569.  
  570. /* New fields for the Bb widget class record */
  571. typedef struct {int empty;} BbClassPart;
  572.  
  573. /* Class record declaration */
  574. typedef struct _BbClassRec {
  575.     CoreClassPart    core_class;
  576.     CompositeClassPart  composite_class;
  577.     BbClassPart    bb_class;
  578. } BbClassRec;
  579.  
  580. extern BbClassRec bbClassRec;
  581.  
  582. /* Instance declaration */
  583. typedef struct _BbRec {
  584.     CorePart        core;
  585.     CompositePart   composite;
  586. } BbRec;
  587.  
  588. static XtGeometryResult bbGeometryManager (Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply);
  589. static XtGeometryResult bbPreferredSize (Widget widget, XtWidgetGeometry *constraint, XtWidgetGeometry *preferred);
  590.  
  591. BbClassRec bbClassRec = {
  592.   {
  593. /* core_class fields      */
  594.     /* superclass         */    (WidgetClass) &compositeClassRec,
  595.     /* class_name         */    "Bb",
  596.     /* widget_size        */    sizeof(BbRec),
  597.     /* class_initialize   */    NULL,
  598.     /* class_part_init    */    NULL,
  599.     /* class_inited       */    FALSE,
  600.     /* initialize         */    NULL,
  601.     /* initialize_hook    */    NULL,
  602.     /* realize            */    XtInheritRealize,
  603.     /* actions            */    NULL,
  604.     /* num_actions      */    0,
  605.     /* resources          */    NULL,
  606.     /* num_resources      */    0,
  607.     /* xrm_class          */    NULLQUARK,
  608.     /* compress_motion      */    TRUE,
  609.     /* compress_exposure  */    TRUE,
  610.     /* compress_enterleave*/    TRUE,
  611.     /* visible_interest   */    FALSE,
  612.     /* destroy            */    NULL,
  613.     /* resize             */    XtInheritResize,
  614.     /* expose             */    NULL,
  615.     /* set_values         */    NULL,
  616.     /* set_values_hook    */    NULL,
  617.     /* set_values_almost  */    XtInheritSetValuesAlmost,
  618.     /* get_values_hook    */    NULL,
  619.     /* accept_focus       */    NULL,
  620.     /* version            */    XtVersion,
  621.     /* callback_private   */    NULL,
  622.     /* tm_table           */    NULL,
  623.     /* query_geometry     */    bbPreferredSize, /*XtInheritQueryGeometry,*/
  624.     /* display_accelerator*/    XtInheritDisplayAccelerator,
  625.     /* extension          */    NULL
  626.   },{
  627. /* composite_class fields */
  628.     /* geometry_manager   */    bbGeometryManager,
  629.     /* change_managed     */    XtInheritChangeManaged,
  630.     /* insert_child      */    XtInheritInsertChild,
  631.     /* delete_child      */    XtInheritDeleteChild,
  632.     /* extension          */    NULL
  633.   },{
  634. /* Bb class fields */
  635.     /* empty          */    0,
  636.   }
  637. };
  638.  
  639. WidgetClass bbWidgetClass = (WidgetClass)&bbClassRec;
  640.  
  641. /*ARGSUSED*/
  642. static XtGeometryResult
  643. bbPreferredSize(
  644.     Widget widget GCC_UNUSED,
  645.     XtWidgetGeometry *constraint GCC_UNUSED,
  646.     XtWidgetGeometry *preferred GCC_UNUSED)
  647. {
  648.     return XtGeometryYes;
  649. }
  650.  
  651. /*ARGSUSED*/
  652. static XtGeometryResult
  653. bbGeometryManager(
  654.     Widget        w,
  655.     XtWidgetGeometry    *request,
  656.     XtWidgetGeometry    *reply GCC_UNUSED)    /* RETURN */
  657.  
  658. {
  659.     /* Allow any and all changes to the geometry */
  660.     if (request->request_mode & CWWidth)
  661.     w->core.width = request->width;
  662.     if (request->request_mode & CWHeight)
  663.     w->core.height = request->height;
  664.     if (request->request_mode & CWBorderWidth)
  665.     w->core.border_width = request->border_width;
  666.     if (request->request_mode & CWX)
  667.     w->core.x = request->x;
  668.     if (request->request_mode & CWY)
  669.     w->core.y = request->y;
  670.  
  671.     return XtGeometryYes;
  672. }
  673.  
  674. #endif /* KEV_WIDGETS */
  675.  
  676. static void set_pointer(Window win, Cursor cursor)
  677. {
  678.     XColor colordefs[2];        /* 0 is foreground, 1 is background */
  679.  
  680.     XDefineCursor(dpy, win, cursor);
  681.  
  682.     colordefs[0].pixel = cur_win->pointer_fg;
  683.     colordefs[1].pixel = cur_win->pointer_bg;
  684.     XQueryColors (dpy, DefaultColormap (dpy, DefaultScreen (dpy)),
  685.           colordefs, 2);
  686.     XRecolorCursor (dpy, cursor, colordefs, colordefs+1);
  687. }
  688.  
  689. #if !OPT_KEV_DRAGGING
  690. static int dont_update_sb = FALSE;
  691.  
  692. static void
  693. set_scroll_window(long n)
  694. {
  695.     register WINDOW *wp;
  696.     for_each_visible_window(wp) {
  697.     if (n-- == 0)
  698.         break;
  699.     }
  700.     if (n < 0)
  701.     set_curwp(wp);
  702. }
  703. #endif /* !OPT_KEV_DRAGGING */
  704.  
  705. #if OL_WIDGETS
  706. static void
  707. JumpProc(
  708.     Widget scrollbar,
  709.     XtPointer closure,
  710.     XtPointer call_data)
  711. {
  712.     long value = (long)closure;
  713.     OlScrollbarVerify *cbs = (OlScrollbarVerify *)call_data;
  714.  
  715.     if (value >= cur_win->nscrollbars)
  716.     return;
  717.     set_scroll_window(value);
  718.     mvupwind(TRUE,
  719.              line_no(curwp->w_bufp, curwp->w_line.l) - cbs->new_location);
  720.     dont_update_sb = TRUE;
  721.     (void)update(TRUE);
  722.     dont_update_sb = FALSE;
  723. }
  724.  
  725. static void
  726. grip_moved(
  727.     Widget slider,
  728.     XtPointer closure,
  729.     XtPointer call_data)
  730. {
  731.     register WINDOW *wp, *saved_curwp;
  732.     int nlines;
  733.     long i = (long) closure;
  734.     OlScrollbarVerify *cbs = (OlScrollbarVerify *)call_data;
  735.  
  736.     for_each_visible_window(wp) {
  737.     if (i-- == 0)
  738.         break;
  739.     }
  740.     if (!wp)
  741.     return;
  742.     saved_curwp = curwp;
  743.     nlines = - cbs->new_location;
  744.     if (nlines < 1)
  745.     nlines = 1;
  746.     curwp = wp;
  747.     resize(TRUE, nlines);
  748.     set_curwp(saved_curwp);
  749.     (void) update(TRUE);
  750. }
  751.  
  752. static void
  753. update_scrollbar_sizes(void)
  754. {
  755.     register WINDOW *wp;
  756.     int i, newsbcnt;
  757.     Dimension new_height;
  758.  
  759.     i=0;
  760.     for_each_visible_window(wp)
  761.     i++;
  762.     newsbcnt=i;
  763.  
  764.     /* Create any needed new scrollbars and sliders */
  765.     for (i = cur_win->nscrollbars+1; i <= newsbcnt; i++)
  766.     if (cur_win->scrollbars[i] == NULL) {
  767.         cur_win->scrollbars[i] = XtVaCreateWidget(
  768.             "scrollbar",
  769.             scrollbarWidgetClass,
  770.             cur_win->pane,
  771.             XtNtranslations, cur_win->my_scrollbars_trans,
  772.             NULL);
  773.         XtAddCallback(cur_win->scrollbars[i],
  774.             XtNsliderMoved, JumpProc, (XtPointer) i);
  775.         cur_win->sliders[i] = XtVaCreateWidget(
  776.             "slider",
  777.             sliderWidgetClass,
  778.             cur_win->pane,
  779.             NULL);
  780.         XtAddCallback(cur_win->sliders[i],
  781.             XtNsliderMoved, grip_moved, (XtPointer) i);
  782.     }
  783.  
  784.     /* Unmanage current set of scrollbars */
  785.     if (cur_win->nscrollbars > 0)
  786.     XtUnmanageChildren(cur_win->scrollbars,
  787.                        (Cardinal) (cur_win->nscrollbars));
  788.     if (cur_win->nscrollbars > 1)
  789.     XtUnmanageChildren(cur_win->sliders,
  790.                        (Cardinal) (cur_win->nscrollbars - 1));
  791.  
  792.     /* Set sizes and positions on scrollbars and sliders */
  793.     cur_win->nscrollbars = newsbcnt;
  794.     i=0;
  795.     for_each_visible_window(wp) {
  796.     new_height = wp->w_ntrows * cur_win->char_height;
  797.     XtVaSetValues(cur_win->scrollbars[i],
  798.         XtNy,    wp->w_toprow * cur_win->char_height,
  799.         XtNheight,    new_height,
  800.         XtNsliderMin,    1,
  801.         XtNsliderMax,    200,
  802.         XtNproportionLength, 2,
  803.         XtNsliderValue,    3,
  804.         NULL);
  805.     if (wp->w_wndp) {
  806.         XtVaSetValues(cur_win->sliders[i],
  807.         XtNy,        wp->w_toprow * cur_win->char_height,
  808.         XtNheight,    (wp->w_ntrows + wp->w_wndp->w_ntrows + 1)
  809.                         * cur_win->char_height,
  810.         XtNsliderMax,    0,
  811.         XtNsliderMin,    -(wp->w_ntrows + wp->w_wndp->w_ntrows),
  812.         XtNsliderValue, -wp->w_ntrows,
  813.         XtNstopPosition, OL_GRANULARITY,
  814.         XtNendBoxes,    FALSE,
  815.         XtNdragCBType,    OL_RELEASE,
  816.         XtNbackground,    cur_win->fg,
  817.         NULL);
  818.     }
  819.     wp->w_flag &= ~WFSBAR;
  820.     gui_update_scrollbar(wp);
  821.     i++;
  822.     }
  823.  
  824.     /* Manage the sliders */
  825.     if (cur_win->nscrollbars > 1)
  826.     XtManageChildren(cur_win->sliders,
  827.                 (Cardinal) (cur_win->nscrollbars - 1));
  828.  
  829.     /* Manage the current set of scrollbars */
  830.     XtManageChildren(cur_win->scrollbars,
  831.                        (Cardinal) (cur_win->nscrollbars));
  832.  
  833.  
  834.     for (i=0; i<cur_win->nscrollbars; i++)
  835.     XRaiseWindow(dpy, XtWindow(cur_win->scrollbars[i]));
  836. }
  837.  
  838. #else
  839. #if MOTIF_WIDGETS
  840.  
  841. static void
  842. JumpProc(
  843.     Widget scrollbar,
  844.     XtPointer closure,
  845.     XtPointer call_data)
  846. {
  847.     long value = (long)closure;
  848.     int lcur;
  849.  
  850.     lookfor_sb_resize = FALSE;
  851.     if (value >= cur_win->nscrollbars)
  852.     return;
  853.     set_scroll_window(value);
  854.     lcur = line_no(curwp->w_bufp, curwp->w_line.l);
  855.     mvupwind(TRUE, lcur - ((XmScrollBarCallbackStruct *)call_data)->value);
  856.     dont_update_sb = TRUE;
  857.     (void)update(TRUE);
  858.     dont_update_sb = FALSE;
  859. }
  860.  
  861. static void
  862. update_scrollbar_sizes(void)
  863. {
  864.     register WINDOW *wp;
  865.     int newsbcnt;
  866.     Dimension new_height;
  867.     Widget *children;
  868.     int num_children;
  869.     long i=0;
  870.  
  871.     for_each_visible_window(wp)
  872.     i++;
  873.     newsbcnt=i;
  874.  
  875.     /* Remove event handlers on sashes */
  876.     XtVaGetValues(cur_win->pane,
  877.     XmNchildren, &children,
  878.     XmNnumChildren, &num_children,
  879.     NULL);
  880.     while (num_children-- > 0)
  881.     if (XmIsSash(children[num_children]))
  882.         XtRemoveEventHandler(
  883.         children[num_children],
  884.         ButtonReleaseMask,
  885.         FALSE,
  886.         pane_button,
  887.         NULL);
  888.  
  889.     /* Create any needed new scrollbars */
  890.     for (i = cur_win->nscrollbars+1; i <= newsbcnt; i++)
  891.     if (cur_win->scrollbars[i] == NULL) {
  892.         cur_win->scrollbars[i] = XtVaCreateWidget(
  893.             "scrollbar",
  894.             xmScrollBarWidgetClass,
  895.             cur_win->pane,
  896.             XmNsliderSize,    1,
  897.             XmNvalue,        1,
  898.             XmNminimum,        1,
  899.             XmNmaximum,        2,    /* so we don't get warning */
  900.             XmNorientation,    XmVERTICAL,
  901.             XmNtranslations,    cur_win->my_scrollbars_trans,
  902.             NULL);
  903.         XtAddCallback(cur_win->scrollbars[i],
  904.                 XmNvalueChangedCallback, JumpProc, (XtPointer) i);
  905.         XtAddCallback(cur_win->scrollbars[i],
  906.                 XmNdragCallback, JumpProc, (XtPointer) i);
  907.         XtAddEventHandler(
  908.             cur_win->scrollbars[i],
  909.             StructureNotifyMask,
  910.             FALSE,
  911.             grip_moved,
  912.             (XtPointer) i);
  913.     }
  914.  
  915.     /* Unmanage current set of scrollbars */
  916.     if (cur_win->nscrollbars >= 0)
  917.     XtUnmanageChildren(cur_win->scrollbars,
  918.                        (Cardinal) (cur_win->nscrollbars + 1));
  919.  
  920.     /* Set sizes on scrollbars */
  921.     cur_win->nscrollbars = newsbcnt;
  922.     i=0;
  923.     for_each_visible_window(wp) {
  924.     new_height = wp->w_ntrows * cur_win->char_height;
  925.     XtVaSetValues(cur_win->scrollbars[i],
  926.         XmNallowResize,        TRUE,
  927.         XmNheight,            new_height,
  928.         XmNpaneMinimum,        1,
  929.         XmNpaneMaximum,        1000,
  930.         XmNshowArrows,        wp->w_ntrows > 3 ? TRUE : FALSE,
  931.         NULL);
  932.     wp->w_flag &= ~WFSBAR;
  933.     gui_update_scrollbar(wp);
  934.     i++;
  935.     }
  936.     XtVaSetValues(cur_win->scrollbars[i],
  937.         XmNheight,            cur_win->char_height-1,
  938.         XmNallowResize,        FALSE,
  939.         XmNpaneMinimum,        cur_win->char_height-1,
  940.         XmNpaneMaximum,        cur_win->char_height-1,
  941.         XmNshowArrows,        FALSE,
  942.         NULL);
  943.  
  944.     /* Manage the current set of scrollbars */
  945.     XtManageChildren(cur_win->scrollbars,
  946.                        (Cardinal) (cur_win->nscrollbars + 1));
  947.  
  948.     /* Add event handlers for sashes */
  949.     XtVaGetValues(cur_win->pane,
  950.     XmNchildren, &children,
  951.     XmNnumChildren, &num_children,
  952.     NULL);
  953.     while (num_children-- > 0)
  954.     if (XmIsSash(children[num_children]))
  955.         XtAddEventHandler(
  956.         children[num_children],
  957.         ButtonReleaseMask,
  958.         FALSE,
  959.         pane_button,
  960.         NULL);
  961. }
  962.  
  963. #else
  964. #if OPT_XAW_SCROLLBARS
  965.  
  966. #if !OPT_KEV_DRAGGING
  967. static void
  968. JumpProc(
  969.     Widget scrollbar GCC_UNUSED,
  970.     XtPointer closure,
  971.     XtPointer call_data)
  972. {
  973.     L_NUM lcur, lmax;
  974.     long value = (long)closure;
  975.     float *percent = (float *)call_data;
  976.  
  977.     if (value < cur_win->nscrollbars) {
  978.         set_scroll_window(value);
  979.         lcur = line_no(curwp->w_bufp, curwp->w_line.l);
  980.     lmax = line_count(curwp->w_bufp);
  981.         mvupwind(TRUE, (int)(lcur - lmax * (*percent)));
  982.         (void)update(TRUE);
  983.     }
  984. }
  985.  
  986. static void
  987. ScrollProc(
  988.     Widget scrollbar GCC_UNUSED,
  989.     XtPointer closure,
  990.     XtPointer call_data)
  991. {
  992.     long value = (long)closure;
  993.     long position = (long)call_data;
  994.  
  995.     if (value < cur_win->nscrollbars) {
  996.         set_scroll_window(value);
  997.     forwline(TRUE, (position / cur_win->char_height));
  998.         (void)update(TRUE);
  999.     }
  1000. }
  1001. #endif
  1002.  
  1003. static void
  1004. update_scrollbar_sizes(void)
  1005. {
  1006.     register WINDOW *wp;
  1007.     int i, newsbcnt;
  1008.     Dimension new_height;
  1009.  
  1010.     i=0;
  1011.     for_each_visible_window(wp)
  1012.     i++;
  1013.     newsbcnt=i;
  1014.  
  1015.     /* Create any needed new scrollbars and grips */
  1016.     for (i = cur_win->nscrollbars+1; i <= newsbcnt; i++) {
  1017.     if (cur_win->scrollbars[i] == NULL) {
  1018.         cur_win->scrollbars[i] = XtVaCreateWidget(
  1019.             "scrollbar",
  1020.             scrollbarWidgetClass,
  1021.             cur_win->pane,
  1022.             XtNforeground,    cur_win->scrollbar_fg,
  1023.             XtNbackground,    cur_win->scrollbar_bg,
  1024.             XtNthumb,        cur_win->thumb_bm,
  1025.             XtNtranslations,    cur_win->my_scrollbars_trans,
  1026.             NULL);
  1027. #if !OPT_KEV_DRAGGING
  1028.         XtAddCallback(cur_win->scrollbars[i],
  1029.             XtNjumpProc, JumpProc, (XtPointer) i);
  1030.         XtAddCallback(cur_win->scrollbars[i],
  1031.             XtNscrollProc, ScrollProc, (XtPointer) i);
  1032. #endif
  1033.     }
  1034.     }
  1035.     for (i = newsbcnt-2; i >= 0 && cur_win->grips[i] == NULL; i--) {
  1036.     cur_win->grips[i] = XtVaCreateWidget(
  1037.             "resizeGrip",
  1038.             gripWidgetClass,
  1039.             cur_win->pane,
  1040.             XtNbackground,    cur_win->modeline_bg,
  1041.             XtNborderWidth,    0,
  1042.             XtNheight,        1,
  1043.             XtNwidth,        1,
  1044.             XtNtranslations,    cur_win->my_resizeGrip_trans,
  1045.             NULL);
  1046.     }
  1047.  
  1048.     /* Unmanage current set of scrollbars */
  1049.     if (cur_win->nscrollbars > 0)
  1050.     XtUnmanageChildren(cur_win->scrollbars,
  1051.                        (Cardinal) (cur_win->nscrollbars));
  1052.  
  1053.     /* Set sizes and positions on scrollbars and grips */
  1054.     cur_win->nscrollbars = newsbcnt;
  1055.     i=0;
  1056.     for_each_visible_window(wp) {
  1057.     L_NUM total = line_count(curwp->w_bufp);
  1058.     L_NUM thumb = line_no(curwp->w_bufp, curwp->w_line.l);
  1059.  
  1060.     new_height = wp->w_ntrows * cur_win->char_height;
  1061.     cur_win->scrollinfo[i].totlen = new_height;
  1062.     XtVaSetValues(cur_win->scrollbars[i],
  1063.         XtNy,        wp->w_toprow * cur_win->char_height,
  1064.         XtNheight,        new_height,
  1065.         XtNorientation,    XtorientVertical,
  1066.         XtNvertDistance,    wp->w_toprow * cur_win->char_height,
  1067.         XtNhorizDistance,    1,
  1068.         NULL);
  1069.     XawScrollbarSetThumb(cur_win->scrollbars[i],
  1070.         ((float) (thumb - 1)) / max(total, 1),
  1071.         ((float) wp->w_ntrows) / max(total, wp->w_ntrows));
  1072.     wp->w_flag &= ~WFSBAR;
  1073.     gui_update_scrollbar(wp);
  1074.     if (wp->w_wndp) {
  1075.         XtVaSetValues(cur_win->grips[i],
  1076.         XtNx,        1,
  1077.         XtNy,        (wp->w_wndp->w_toprow-1) * cur_win->char_height,
  1078.         XtNheight,    cur_win->char_height,
  1079.         XtNwidth,    cur_win->pane_width,
  1080.         XtNvertDistance,(wp->w_wndp->w_toprow-1) * cur_win->char_height,
  1081.         XtNhorizDistance,1,
  1082.         NULL);
  1083.     }
  1084.     i++;
  1085.     }
  1086.  
  1087.     /* Manage the current set of scrollbars */
  1088.     XtManageChildren(cur_win->scrollbars,
  1089.                        (Cardinal) (cur_win->nscrollbars));
  1090.  
  1091.     XtManageChildren(cur_win->grips,
  1092.                        (Cardinal) (cur_win->nscrollbars - 1));
  1093.  
  1094.     for (i=0; i<cur_win->nscrollbars; i++)
  1095.     XRaiseWindow(dpy, XtWindow(cur_win->scrollbars[i]));
  1096.  
  1097.     for (i=1; i<cur_win->nscrollbars; i++)
  1098.     XRaiseWindow(dpy, XtWindow(cur_win->grips[i-1]));
  1099. }
  1100.  
  1101. #else
  1102. #if OPT_KEV_SCROLLBARS
  1103. static void
  1104. update_scrollbar_sizes(void)
  1105. {
  1106.     register WINDOW *wp;
  1107.     int i, newsbcnt;
  1108.     Dimension new_height;
  1109.     Cardinal nchildren;
  1110.  
  1111.     i=0;
  1112.     for_each_visible_window(wp)
  1113.     i++;
  1114.     newsbcnt=i;
  1115.  
  1116.     /* Create any needed new scrollbars and grips */
  1117.     for (i = newsbcnt-1; i >= 0 && cur_win->scrollbars[i] == NULL; i--) {
  1118.     if (cur_win->slider_is_3D) {
  1119.         cur_win->scrollbars[i] = XtVaCreateWidget(
  1120.             "scrollbar",
  1121.             coreWidgetClass,
  1122.             cur_win->pane,
  1123.             XtNbackgroundPixmap,    cur_win->trough_pixmap,
  1124.             XtNborderWidth,        0,
  1125.             XtNheight,        1,
  1126.             XtNwidth,        1,
  1127.             XtNtranslations,    cur_win->my_scrollbars_trans,
  1128.             NULL);
  1129.     }
  1130.     else {
  1131.         cur_win->scrollbars[i] = XtVaCreateWidget(
  1132.             "scrollbar",
  1133.             coreWidgetClass,
  1134.             cur_win->pane,
  1135.             XtNbackground,        cur_win->scrollbar_bg,
  1136.             XtNborderWidth,        0,
  1137.             XtNheight,        1,
  1138.             XtNwidth,        1,
  1139.             XtNtranslations,    cur_win->my_scrollbars_trans,
  1140.             NULL);
  1141.     }
  1142.  
  1143.     XtAddEventHandler(
  1144.         cur_win->scrollbars[i],
  1145.         ExposureMask,
  1146.         FALSE,
  1147.         x_expose_scrollbar,
  1148.         (XtPointer)0);
  1149.     cur_win->scrollinfo[i].exposed = False;
  1150.     }
  1151.     for (i = newsbcnt-2; i >= 0 && cur_win->grips[i] == NULL; i--)
  1152.     cur_win->grips[i] = XtVaCreateWidget(
  1153.             "resizeGrip",
  1154.             coreWidgetClass,
  1155.             cur_win->pane,
  1156.             XtNbackground,    cur_win->modeline_bg,
  1157.             XtNborderWidth,    0,
  1158.             XtNheight,        1,
  1159.             XtNwidth,        1,
  1160.             XtNtranslations,    cur_win->my_resizeGrip_trans,
  1161.             NULL);
  1162.  
  1163.     /* Set sizes and positions on scrollbars and grips */
  1164.     i=0;
  1165.     for_each_visible_window(wp) {
  1166.     new_height = wp->w_ntrows * cur_win->char_height;
  1167.     XtVaSetValues(cur_win->scrollbars[i],
  1168.         XtNx,        cur_win->slider_is_3D ? 0 : 1,
  1169.         XtNy,        wp->w_toprow * cur_win->char_height,
  1170.         XtNheight,        new_height,
  1171.         XtNwidth,        cur_win->pane_width
  1172.                                + (cur_win->slider_is_3D ? 2 : 0),
  1173.         NULL);
  1174.     cur_win->scrollinfo[i].totlen = new_height;
  1175.     if (wp->w_wndp) {
  1176.         XtVaSetValues(cur_win->grips[i],
  1177.         XtNx,        1,
  1178.         XtNy,        (wp->w_wndp->w_toprow-1) * cur_win->char_height,
  1179.         XtNheight,    cur_win->char_height,
  1180.         XtNwidth,    cur_win->pane_width,
  1181.         NULL);
  1182.     }
  1183.     i++;
  1184.     }
  1185.  
  1186.     if (cur_win->nscrollbars > newsbcnt) {
  1187.     nchildren = cur_win->nscrollbars - newsbcnt;
  1188.     XtUnmanageChildren(cur_win->scrollbars+newsbcnt, nchildren);
  1189.     XtUnmanageChildren(cur_win->grips+newsbcnt-1,    nchildren);
  1190.     for (i = cur_win->nscrollbars; i > newsbcnt; )
  1191.         cur_win->scrollinfo[--i].exposed = False;
  1192.     }
  1193.     else if (cur_win->nscrollbars < newsbcnt) {
  1194.     nchildren = newsbcnt - cur_win->nscrollbars;
  1195.     XtManageChildren(cur_win->scrollbars+cur_win->nscrollbars, nchildren);
  1196.     if (cur_win->nscrollbars > 0)
  1197.         XtManageChildren(cur_win->grips+cur_win->nscrollbars-1, nchildren);
  1198.     else if (cur_win->nscrollbars == 0 && nchildren > 1)
  1199.         XtManageChildren(cur_win->grips, nchildren-1);
  1200.     }
  1201.     cur_win->nscrollbars = newsbcnt;
  1202.  
  1203.     i = 0;
  1204.     for_each_visible_window(wp) {
  1205.     wp->w_flag &= ~WFSBAR;
  1206.     gui_update_scrollbar(wp);
  1207.     i++;
  1208.     }
  1209.  
  1210.     /*
  1211.      * Set the cursors... It would be nice if we could do this in the
  1212.      * initialization above, but the widget needs to be realized for this
  1213.      * to work
  1214.      */
  1215.     for (i=0; i<cur_win->nscrollbars; i++) {
  1216.     if (XtIsRealized(cur_win->scrollbars[i]))
  1217.         set_pointer(
  1218.             XtWindow(cur_win->scrollbars[i]),
  1219.             curs_sb_v_double_arrow);
  1220.     if (i < cur_win->nscrollbars-1 && XtIsRealized(cur_win->grips[i]))
  1221.         set_pointer(
  1222.             XtWindow(cur_win->grips[i]),
  1223.             curs_double_arrow);
  1224.     }
  1225. }
  1226.  
  1227.  
  1228. /*
  1229.  * The X11R5 Athena scrollbar code was used as a reference for writing
  1230.  * draw_thumb and parts of update_thumb.
  1231.  */
  1232.  
  1233. #define FILL_TOP 0x01
  1234. #define FILL_BOT 0x02
  1235.  
  1236. #define SP_HT 16                /* slider pixmap height */
  1237.  
  1238. static void
  1239. draw_thumb(
  1240.     Widget w,
  1241.     int top,
  1242.     int bot,
  1243.     int dofill)
  1244. {
  1245.     UINT length = bot - top;
  1246.     if (bot < 0 || top < 0 || bot <= top)
  1247.     return;
  1248.  
  1249.     if (!dofill)
  1250.     XClearArea(XtDisplay(w), XtWindow(w), cur_win->slider_is_3D ? 2 : 1,
  1251.                top, cur_win->pane_width-2, length, FALSE);
  1252.     else if (!cur_win->slider_is_3D)
  1253.     XFillRectangle(XtDisplay(w), XtWindow(w), cur_win->scrollbargc,
  1254.                1, top, cur_win->pane_width-2, length);
  1255.     else {
  1256.     if (dofill & FILL_TOP) {
  1257.         int tbot;
  1258.         tbot = bot - ((dofill & FILL_BOT) ? 2 : 0);
  1259.         if (tbot <= top)
  1260.         tbot = top + 1;
  1261.         if (top + (SP_HT-2) < tbot)
  1262.         tbot = top + (SP_HT-2);
  1263.         XCopyArea(dpy, cur_win->slider_pixmap, XtWindow(w),
  1264.               cur_win->scrollbargc,
  1265.               0, 0, cur_win->pane_width-2, (unsigned int) (tbot - top),
  1266.               2, top);
  1267.  
  1268.         top = tbot;
  1269.     }
  1270.     if (dofill & FILL_BOT) {
  1271.         int btop = max(top, bot-(SP_HT-2));
  1272.         XCopyArea(dpy, cur_win->slider_pixmap, XtWindow(w),
  1273.                   cur_win->scrollbargc,
  1274.               0, SP_HT - (bot-btop),
  1275.               cur_win->pane_width-2, (unsigned int) (bot - btop),
  1276.               2, btop);
  1277.         bot = btop;
  1278.  
  1279.     }
  1280.     if (top < bot) {
  1281.         XFillRectangle(XtDisplay(w), XtWindow(w), cur_win->scrollbargc,
  1282.                    2, top,
  1283.                cur_win->pane_width-2, (unsigned int) (bot-top));
  1284.     }
  1285.     }
  1286. }
  1287.  
  1288.  
  1289. #define MIN_THUMB_SIZE 8
  1290.  
  1291. static void
  1292. update_thumb(
  1293.     int barnum,
  1294.     int newtop,
  1295.     int newlen)
  1296. {
  1297.     int oldtop, oldbot, newbot, totlen;
  1298.     int f = cur_win->slider_is_3D ? 2 : 0;
  1299.     Widget w = cur_win->scrollbars[barnum];
  1300.  
  1301.     oldtop = cur_win->scrollinfo[barnum].top;
  1302.     oldbot = cur_win->scrollinfo[barnum].bot;
  1303.     totlen = cur_win->scrollinfo[barnum].totlen;
  1304.     newtop = min(newtop, totlen-3);
  1305.     newbot = newtop + max(newlen, MIN_THUMB_SIZE);
  1306.     newbot = min(newbot, totlen);
  1307.     cur_win->scrollinfo[barnum].top = newtop;
  1308.     cur_win->scrollinfo[barnum].bot = newbot;
  1309.  
  1310.     if (!cur_win->scrollinfo[barnum].exposed)
  1311.     return;
  1312.  
  1313.     if (XtIsRealized(w)) {
  1314.     if (newtop < oldtop) {
  1315.         int tbot = min(newbot, oldtop+f);
  1316.         draw_thumb(w, newtop, tbot,
  1317.                    FILL_TOP | ((tbot == newbot) ? FILL_BOT : 0));
  1318.     }
  1319.     if (newtop > oldtop) {
  1320.         draw_thumb(w, oldtop, min(newtop, oldbot), 0);
  1321.         if (cur_win->slider_is_3D && newtop < oldbot)
  1322.         draw_thumb(w, newtop, min(newtop+f, oldbot), FILL_TOP);
  1323.     }
  1324.     if (newbot < oldbot) {
  1325.         draw_thumb(w, max(newbot, oldtop), oldbot, 0);
  1326.         if (cur_win->slider_is_3D && oldtop < newbot)
  1327.         draw_thumb(w, max(newbot-f, oldtop), newbot, FILL_BOT);
  1328.     }
  1329.     if (newbot > oldbot) {
  1330.         int btop = max(newtop, oldbot-f);
  1331.         draw_thumb(w, btop, newbot,
  1332.                    FILL_BOT | ((btop == newtop) ? FILL_TOP : 0));
  1333.     }
  1334.     }
  1335. }
  1336.  
  1337. /*ARGSUSED*/
  1338. static void
  1339. x_expose_scrollbar(
  1340.     Widget    w,
  1341.     XtPointer    unused GCC_UNUSED,
  1342.     XEvent     *ev,
  1343.     Boolean    *continue_to_dispatch GCC_UNUSED)
  1344. {
  1345.     int i;
  1346.  
  1347.     if (ev->type != Expose)
  1348.     return;
  1349.  
  1350.     for (i=0; i < cur_win->nscrollbars; i++) {
  1351.     if (cur_win->scrollbars[i] == w) {
  1352.         int top, bot;
  1353.         top = cur_win->scrollinfo[i].top;
  1354.         bot = cur_win->scrollinfo[i].bot;
  1355.         cur_win->scrollinfo[i].top = -1;
  1356.         cur_win->scrollinfo[i].bot = -1;
  1357.         cur_win->scrollinfo[i].exposed = True;
  1358.         update_thumb(i, top, bot-top);
  1359.     }
  1360.     }
  1361. }
  1362. #endif /* OPT_KEV_SCROLLBARS  */
  1363. #endif /* OPT_XAW_SCROLLBARS  */
  1364. #endif /* MOTIF_WIDGETS */
  1365. #endif /* OL_WIDGETS */
  1366.  
  1367. #if OPT_KEV_DRAGGING
  1368. static void
  1369. do_scroll(
  1370.     Widget w,
  1371.     XEvent *event,
  1372.     String *params,
  1373.     Cardinal *num_params)
  1374. {
  1375.     static enum { none, forward, backward, drag } scrollmode = none;
  1376.     int pos;
  1377.     register WINDOW *wp;
  1378.     register int i;
  1379.     XEvent nev;
  1380.     int count;
  1381.  
  1382.     /*
  1383.      * Return immediately if behind in processing motion events.  Note:
  1384.      * If this is taken out, scrolling is actually smoother, but sometimes
  1385.      * takes a while to catch up.  I should think that performance would
  1386.      * be horrible on a slow server.
  1387.      */
  1388.  
  1389.     if (scrollmode == drag
  1390.      && event->type == MotionNotify
  1391.      && x_has_events()
  1392.      && XtAppPeekEvent(cur_win->app_context, &nev)
  1393.      && (nev.type == MotionNotify || nev.type == ButtonRelease))
  1394.     return;
  1395.  
  1396.     if (*num_params != 1)
  1397.     return;
  1398.  
  1399.     /* Determine vertical position */
  1400.     switch (event->type) {
  1401.     case MotionNotify :
  1402.         pos = event->xmotion.y;
  1403.         break;
  1404.     case ButtonPress :
  1405.     case ButtonRelease :
  1406.         pos = event->xbutton.y;
  1407.         break;
  1408.     default :
  1409.         return;
  1410.     }
  1411.  
  1412.     /* Determine scrollbar number and corresponding vile window */
  1413.     i = 0;
  1414.     for_each_visible_window (wp) {
  1415.     if (cur_win->scrollbars[i] == w)
  1416.         break;
  1417.     i++;
  1418.     }
  1419.  
  1420.     if (!wp)
  1421.     return;
  1422.  
  1423.     if (pos < 0)
  1424.     pos = 0;
  1425.     if (pos > cur_win->scrollinfo[i].totlen)
  1426.     pos = cur_win->scrollinfo[i].totlen;
  1427.  
  1428.     switch (**params) {
  1429.     case 'E' :    /* End */
  1430.         if (cur_win->scroll_repeat_id != (XtIntervalId) 0) {
  1431.         XtRemoveTimeOut(cur_win->scroll_repeat_id);
  1432.         cur_win->scroll_repeat_id = (XtIntervalId) 0;
  1433.         }
  1434.         set_pointer(XtWindow(w), curs_sb_v_double_arrow);
  1435.         scrollmode = none;
  1436.         break;
  1437.     case 'F' :    /* Forward */
  1438.         if (scrollmode != none)
  1439.         break;
  1440.         count = (pos / cur_win->char_height) + 1;
  1441.         scrollmode = forward;
  1442.         set_pointer(XtWindow(w), curs_sb_up_arrow);
  1443.         goto do_scroll_common;
  1444.     case 'B' :    /* Backward */
  1445.         if (scrollmode != none)
  1446.         break;
  1447.         count = -((pos / cur_win->char_height) + 1);
  1448.         scrollmode = backward;
  1449.         set_pointer(XtWindow(w), curs_sb_down_arrow);
  1450. do_scroll_common:
  1451.         set_curwp(wp);
  1452.         mvdnwind(TRUE, count);
  1453.         cur_win->scroll_repeat_id = XtAppAddTimeOut(
  1454.             cur_win->app_context,
  1455.             cur_win->scroll_repeat_timeout,
  1456.             repeat_scroll,
  1457.             (XtPointer) count);
  1458.         (void)update(TRUE);
  1459.         break;
  1460.     case 'S' :    /* StartDrag */
  1461.         if (scrollmode == none) {
  1462.         set_curwp(wp);
  1463.         scrollmode = drag;
  1464.         set_pointer(XtWindow(w), curs_sb_right_arrow);
  1465.         }
  1466.         /* FALLTHRU */
  1467.     case 'D' :    /* Drag */
  1468.         if (scrollmode == drag) {
  1469.         int lcur = line_no(curwp->w_bufp, curwp->w_line.l);
  1470.         int ltarg = (line_count(curwp->w_bufp) * pos
  1471.                 / cur_win->scrollinfo[i].totlen) + 1;
  1472.         mvupwind(TRUE, lcur-ltarg);
  1473.         (void)update(TRUE);
  1474.         }
  1475.         break;
  1476.     }
  1477. }
  1478.  
  1479. /*ARGSUSED*/
  1480. static void
  1481. repeat_scroll(
  1482.     XtPointer count,
  1483.     XtIntervalId  *id GCC_UNUSED)
  1484. {
  1485.     cur_win->scroll_repeat_id = XtAppAddTimeOut(
  1486.         cur_win->app_context,
  1487.         cur_win->scroll_repeat_interval,
  1488.         repeat_scroll,
  1489.         (XtPointer) count);
  1490.     mvdnwind(TRUE, (int)count);
  1491.     (void)update(TRUE);
  1492.     XSync(dpy, False);
  1493. }
  1494. #endif /* OPT_KEV_DRAGGING */
  1495.  
  1496. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  1497. static void
  1498. resize_bar(
  1499.     Widget w,
  1500.     XEvent *event,
  1501.     String *params,
  1502.     Cardinal *num_params)
  1503. {
  1504.     static int motion_permitted = False;
  1505.     static int root_y;
  1506.     int pos = 0;            /* stifle -Wall */
  1507.     register WINDOW *wp;
  1508.     register int i;
  1509.     XEvent nev;
  1510.  
  1511.     /* Return immediately if behind in processing motion events */
  1512.     if (motion_permitted
  1513.      && event->type == MotionNotify
  1514.      && x_has_events()
  1515.      && XtAppPeekEvent(cur_win->app_context, &nev)
  1516.      && (nev.type == MotionNotify || nev.type == ButtonRelease))
  1517.     return;
  1518.  
  1519.     if (*num_params != 1)
  1520.     return;
  1521.  
  1522.     switch (**params) {
  1523.     case 'S' :    /* Start */
  1524.         motion_permitted = True;
  1525.         root_y = event->xbutton.y_root - event->xbutton.y;
  1526.         return;
  1527.     case 'D' :    /* Drag */
  1528.         if (!motion_permitted)
  1529.         return;
  1530.         /*
  1531.          * We use kind of convoluted mechanism to determine the vertical
  1532.          * position with respect to the widget which we are moving. The
  1533.          * reason is that the x,y position from the event structure is
  1534.          * unreliable since the widget may have moved in between the
  1535.          * time when the event was first generated (at the display
  1536.          * server) and the time at which the event is received (in
  1537.          * this code here).  So we keep track of the vertical position
  1538.          * of the widget with respect to the root window and use the
  1539.          * corresponding field in the event structure to determine
  1540.          * the vertical position of the pointer with respect to the
  1541.          * widget of interest.  In the past, XQueryPointer() was
  1542.          * used to determine the position of the pointer, but this is
  1543.          * not really what we want since the position returned by
  1544.          * XQueryPointer is the position of the pointer at a time
  1545.          * after the event was both generated and received (and thus
  1546.          * inaccurate).  This is why the resize grip would sometimes
  1547.          * "follow" the mouse pointer after the button was released.
  1548.          */
  1549.         pos = event->xmotion.y_root - root_y;
  1550.         break;
  1551.     case 'E' :    /* End */
  1552.         if (!motion_permitted)
  1553.         return;
  1554.         pos = event->xbutton.y_root - root_y;
  1555.         motion_permitted = False;
  1556.         break;
  1557.     }
  1558.  
  1559.     /* Determine grip number and corresponding vile window (above grip) */
  1560.     i = 0;
  1561.     for_each_visible_window (wp) {
  1562.     if (cur_win->grips[i] == w)
  1563.         break;
  1564.     i++;
  1565.     }
  1566.  
  1567.     if (!wp)
  1568.     return;
  1569.  
  1570.     if (pos < 0)
  1571.     pos -= cur_win->char_height;
  1572.     pos = pos / cur_win->char_height;
  1573.  
  1574.     if (pos) {
  1575.     int nlines;
  1576.     if (pos >= wp->w_wndp->w_ntrows)
  1577.         pos = wp->w_wndp->w_ntrows - 1;
  1578.  
  1579.     nlines = wp->w_ntrows + pos;
  1580.     if (nlines < 1)
  1581.         nlines = 1;
  1582.     root_y += (nlines - wp->w_ntrows) * cur_win->char_height;
  1583.     set_curwp(wp);
  1584.     resize(TRUE, nlines);
  1585.     (void)update(TRUE);
  1586.     }
  1587. }
  1588. #endif /* OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS */
  1589.  
  1590. void
  1591. gui_update_scrollbar(
  1592.     WINDOW *uwp)
  1593. {
  1594.     WINDOW *wp;
  1595.     int i;
  1596.     int lnum, lcnt;
  1597.  
  1598. #if !OPT_KEV_SCROLLBARS && !OPT_XAW_SCROLLBARS
  1599.     if (dont_update_sb)
  1600.     return;
  1601. #endif /* !OPT_KEV_SCROLLBARS */
  1602.  
  1603.     i = 0;
  1604.     for_each_visible_window(wp) {
  1605.     if (wp == uwp)
  1606.         break;
  1607.     i++;
  1608.     }
  1609.     if (i >= cur_win->nscrollbars || (wp->w_flag & WFSBAR)) {
  1610.     /*
  1611.      * update_scrollbar_sizes will recursively invoke gui_update_scrollbar,
  1612.      * but with WFSBAR disabled.
  1613.      */
  1614.     update_scrollbar_sizes();
  1615.     return;
  1616.     }
  1617.  
  1618.     lnum = line_no(wp->w_bufp, wp->w_line.l);
  1619.     lnum = (lnum > 0) ? lnum : 1;
  1620.     lcnt = line_count(wp->w_bufp);
  1621. #if MOTIF_WIDGETS
  1622.     lcnt += 1;
  1623.     XtVaSetValues(cur_win->scrollbars[i],
  1624.         XmNmaximum,        lcnt + wp->w_ntrows,
  1625.         XmNsliderSize,    wp->w_ntrows,
  1626.         XmNvalue,        lnum,
  1627.         XmNpageIncrement,    wp->w_ntrows > 1 ? wp->w_ntrows-1 : 1,
  1628.         NULL);
  1629. #else
  1630. #if OL_WIDGETS
  1631.     lcnt += 1;
  1632.     XtVaSetValues(cur_win->scrollbars[i],
  1633.         XtNsliderMin,    1,
  1634.         XtNsliderMax,    lcnt + wp->w_ntrows,
  1635.         XtNproportionLength, wp->w_ntrows,
  1636.         XtNsliderValue,    lnum,
  1637.         NULL);
  1638. #else
  1639. #if OPT_XAW_SCROLLBARS
  1640.     XawScrollbarSetThumb(cur_win->scrollbars[i],
  1641.         ((float) (lnum - 1)) / max(lcnt, wp->w_ntrows),
  1642.         ((float) wp->w_ntrows) / max(lcnt, wp->w_ntrows));
  1643. #else
  1644. #if OPT_KEV_SCROLLBARS
  1645.     {
  1646.     int top, len;
  1647.     lcnt  = max(lcnt, 1);
  1648.     len   = (min(lcnt, wp->w_ntrows) * cur_win->scrollinfo[i].totlen
  1649.                 / lcnt) + 1;
  1650.     top   = ((lnum-1) * cur_win->scrollinfo[i].totlen)
  1651.             / lcnt;
  1652.     update_thumb(i, top, len);
  1653.     }
  1654. #endif /* OPT_KEV_SCROLLBARS */
  1655. #endif /* OPT_XAW_SCROLLBARS */
  1656. #endif /* OL_WIDGETS */
  1657. #endif /* MOTIF_WIDGETS */
  1658. }
  1659.  
  1660. #define OLD_RESOURCES 1        /* New stuff not ready for prime time */
  1661.  
  1662. #define XtNnormalShape        "normalShape"
  1663. #define XtCNormalShape        "NormalShape"
  1664. #define XtNwatchShape        "watchShape"
  1665. #define XtCWatchShape        "WatchShape"
  1666.  
  1667. #define XtNforkOnStartup    "forkOnStartup"
  1668. #define XtCForkOnStartup    "ForkOnStartup"
  1669.  
  1670. #define XtNscrollbarWidth    "scrollbarWidth"
  1671. #define XtCScrollbarWidth    "ScrollbarWidth"
  1672. #define XtNfocusFollowsMouse    "focusFollowsMouse"
  1673. #define XtCFocusFollowsMouse    "FocusFollowsMouse"
  1674. #define XtNscrollbarOnLeft    "scrollbarOnLeft"
  1675. #define XtCScrollbarOnLeft    "ScrollbarOnLeft"
  1676. #define XtNmultiClickTime    "multiClickTime"
  1677. #define XtCMultiClickTime    "MultiClickTime"
  1678. #define XtNcharClass        "charClass"
  1679. #define XtCCharClass        "CharClass"
  1680. #if OPT_KEV_DRAGGING
  1681. #define    XtNscrollRepeatTimeout    "scrollRepeatTimeout"
  1682. #define    XtCScrollRepeatTimeout    "ScrollRepeatTimeout"
  1683. #endif
  1684. #define    XtNscrollRepeatInterval    "scrollRepeatInterval"
  1685. #define    XtCScrollRepeatInterval    "ScrollRepeatInterval"
  1686. #define XtNpersistentSelections    "persistentSelections"
  1687. #define XtCPersistentSelections    "PersistentSelections"
  1688. #define XtNselectionSetsDOT    "selectionSetsDOT"
  1689. #define XtCSelectionSetsDOT    "SelectionSetsDOT"
  1690. #define XtNblinkInterval    "blinkInterval"
  1691. #define XtCBlinkInterval    "BlinkInterval"
  1692. #define XtNsliderIsSolid    "sliderIsSolid"
  1693. #define XtCSliderIsSolid    "SliderIsSolid"
  1694. #define    XtNfocusForeground    "focusForeground"
  1695. #define    XtNfocusBackground    "focusBackground"
  1696.  
  1697. #define XtNfcolor0        XtNforeground
  1698. #define XtCFcolor0        XtCForeground
  1699. #define XtNbcolor0        XtNbackground
  1700. #define XtCBcolor0        XtCBackground
  1701.  
  1702. #define XtNfcolor1        "fcolor1"
  1703. #define XtCFcolor1        "Fcolor1"
  1704. #define XtNbcolor1        "bcolor1"
  1705. #define XtCBcolor1        "Bcolor1"
  1706.  
  1707. #define XtNfcolor2        "fcolor2"
  1708. #define XtCFcolor2        "Fcolor2"
  1709. #define XtNbcolor2        "bcolor2"
  1710. #define XtCBcolor2        "Bcolor2"
  1711.  
  1712. #define XtNfcolor3        "fcolor3"
  1713. #define XtCFcolor3        "Fcolor3"
  1714. #define XtNbcolor3        "bcolor3"
  1715. #define XtCBcolor3        "Bcolor3"
  1716.  
  1717. #define XtNfcolor4        "fcolor4"
  1718. #define XtCFcolor4        "Fcolor4"
  1719. #define XtNbcolor4        "bcolor4"
  1720. #define XtCBcolor4        "Bcolor4"
  1721.  
  1722. #define XtNfcolor5        "fcolor5"
  1723. #define XtCFcolor5        "Fcolor5"
  1724. #define XtNbcolor5        "bcolor5"
  1725. #define XtCBcolor5        "Bcolor5"
  1726.  
  1727. #define XtNfcolor6        "fcolor6"
  1728. #define XtCFcolor6        "Fcolor6"
  1729. #define XtNbcolor6        "bcolor6"
  1730. #define XtCBcolor6        "Bcolor6"
  1731.  
  1732. #define XtNfcolor7        "fcolor7"
  1733. #define XtCFcolor7        "Fcolor7"
  1734. #define XtNbcolor7        "bcolor7"
  1735. #define XtCBcolor7        "Bcolor7"
  1736.  
  1737. #define XtNfcolor8        "fcolor8"
  1738. #define XtCFcolor8        "Fcolor8"
  1739. #define XtNbcolor8        "bcolor8"
  1740. #define XtCBcolor8        "Bcolor8"
  1741.  
  1742. #define XtNfcolor9        "fcolor9"
  1743. #define XtCFcolor9        "Fcolor9"
  1744. #define XtNbcolor9        "bcolor9"
  1745. #define XtCBcolor9        "Bcolor9"
  1746.  
  1747. #define XtNfcolorA        "fcolor10"
  1748. #define XtCFcolorA        "Fcolor10"
  1749. #define XtNbcolorA        "bcolor10"
  1750. #define XtCBcolorA        "Bcolor10"
  1751.  
  1752. #define XtNfcolorB        "fcolor11"
  1753. #define XtCFcolorB        "Fcolor11"
  1754. #define XtNbcolorB        "bcolor11"
  1755. #define XtCBcolorB        "Bcolor11"
  1756.  
  1757. #define XtNfcolorC        "fcolor12"
  1758. #define XtCFcolorC        "Fcolor12"
  1759. #define XtNbcolorC        "bcolor12"
  1760. #define XtCBcolorC        "Bcolor12"
  1761.  
  1762. #define XtNfcolorD        "fcolor13"
  1763. #define XtCFcolorD        "Fcolor13"
  1764. #define XtNbcolorD        "bcolor13"
  1765. #define XtCBcolorD        "Bcolor13"
  1766.  
  1767. #define XtNfcolorE        "fcolor14"
  1768. #define XtCFcolorE        "Fcolor14"
  1769. #define XtNbcolorE        "bcolor14"
  1770. #define XtCBcolorE        "Bcolor14"
  1771.  
  1772. #define XtNfcolorF        "fcolor15"
  1773. #define XtCFcolorF        "Fcolor15"
  1774. #define XtNbcolorF        "bcolor15"
  1775. #define XtCBcolorF        "Bcolor15"
  1776.  
  1777. static XtResource resources[] = {
  1778. #if OPT_KEV_DRAGGING
  1779.     {
  1780.     XtNscrollRepeatTimeout,
  1781.     XtCScrollRepeatTimeout,
  1782.     XtRInt,
  1783.     sizeof(int),
  1784.     XtOffset(TextWindow, scroll_repeat_timeout),
  1785.     XtRImmediate,
  1786.     (XtPointer) 500            /* 1/2 second */
  1787.     },
  1788. #endif    /* OPT_KEV_DRAGGING */
  1789.     {
  1790.     XtNscrollRepeatInterval,
  1791.     XtCScrollRepeatInterval,
  1792.     XtRInt,
  1793.     sizeof(int),
  1794.     XtOffset(TextWindow, scroll_repeat_interval),
  1795.     XtRImmediate,
  1796.     (XtPointer) 60            /* 60 milliseconds */
  1797.     },
  1798.     {
  1799.     XtNgeometry,
  1800.     XtCGeometry,
  1801.     XtRString,
  1802.     sizeof(String *),
  1803.     XtOffset(TextWindow, geometry),
  1804.     XtRImmediate,
  1805.     "80x36"
  1806.     },
  1807.     {
  1808.     XtNfont,
  1809.     XtCFont,
  1810.     XtRString,
  1811.     sizeof(String *),
  1812.     XtOffset(TextWindow, starting_fontname),
  1813.     XtRImmediate,
  1814.     XtDefaultFont    /* used to be FONTNAME */
  1815.     },
  1816.     {
  1817.     XtNforeground,
  1818.     XtCForeground,
  1819.     XtRPixel,
  1820.     sizeof(Pixel),
  1821.     XtOffset(TextWindow, fg),
  1822.     XtRString,
  1823. #if OLD_RESOURCES
  1824.         XtDefaultForeground
  1825. #else
  1826.     "#c71bc30bc71b"
  1827. #endif /* OLD_RESOURCES */
  1828.     },
  1829.     {
  1830.     XtNbackground,
  1831.     XtCBackground,
  1832.     XtRPixel,
  1833.     sizeof(Pixel),
  1834.     XtOffset(TextWindow, bg),
  1835.     XtRString,
  1836. #if OLD_RESOURCES
  1837.     XtDefaultBackground
  1838. #else
  1839.     "#c71bc30bc71b"
  1840. #endif
  1841.     },
  1842.     {
  1843.     XtNforkOnStartup,
  1844.     XtCForkOnStartup,
  1845.     XtRBool,
  1846.     sizeof(Bool),
  1847.     XtOffset(TextWindow, fork_on_startup),
  1848.     XtRImmediate,
  1849.     (XtPointer) False
  1850.     },
  1851.     {
  1852.     XtNfocusFollowsMouse,
  1853.     XtCFocusFollowsMouse,
  1854.     XtRBool,
  1855.     sizeof(Bool),
  1856.     XtOffset(TextWindow, focus_follows_mouse),
  1857.     XtRImmediate,
  1858.     (XtPointer) False
  1859.     },
  1860.     {
  1861.     XtNmultiClickTime,
  1862.     XtCMultiClickTime,
  1863.     XtRInt,
  1864.     sizeof(Time),
  1865.     XtOffset(TextWindow, click_timeout),
  1866.     XtRImmediate,
  1867.     (XtPointer) 500
  1868.     },
  1869.     {
  1870.     XtNcharClass,
  1871.     XtCCharClass,
  1872.     XtRString,
  1873.     sizeof(String *),
  1874.     XtOffset(TextWindow, multi_click_char_class),
  1875.     XtRImmediate,
  1876.     NULL
  1877.     },
  1878.     {
  1879.     XtNscrollbarOnLeft,
  1880.     XtCScrollbarOnLeft,
  1881.     XtRBool,
  1882.     sizeof(Bool),
  1883.     XtOffset(TextWindow, scrollbar_on_left),
  1884.     XtRImmediate,
  1885.     (XtPointer) False
  1886.     },
  1887.     {
  1888.     XtNscrollbarWidth,
  1889.     XtCScrollbarWidth,
  1890.     XtRInt,
  1891.     sizeof(int),
  1892.     XtOffset(TextWindow, pane_width),
  1893.     XtRImmediate,
  1894.     (XtPointer) PANE_WIDTH_DEFAULT
  1895.     },
  1896. #if OPT_MENUS
  1897.     {
  1898.     XtNmenuHeight,
  1899.     XtCMenuHeight,
  1900.     XtRInt,
  1901.     sizeof(int),
  1902.     XtOffset(TextWindow, menu_height),
  1903.     XtRImmediate,
  1904.     (XtPointer) MENU_HEIGHT_DEFAULT
  1905.     },
  1906. #endif
  1907. #if OPT_MENUS_COLORED
  1908.     {
  1909.     XtNmenuForeground,
  1910.     XtCMenuForeground,
  1911.     XtRPixel,
  1912.     sizeof(Pixel),
  1913.     XtOffset(TextWindow, menubar_fg),
  1914.     XtRString,
  1915.     XtDefaultForeground
  1916.     },
  1917.     {
  1918.     XtNmenuBackground,
  1919.     XtCMenuBackground,
  1920.     XtRPixel,
  1921.     sizeof(Pixel),
  1922.     XtOffset(TextWindow, menubar_bg),
  1923.     XtRString,
  1924.     XtDefaultBackground
  1925.     },
  1926. #endif
  1927.     {
  1928.     XtNpersistentSelections,
  1929.     XtCPersistentSelections,
  1930.     XtRBool,
  1931.     sizeof(Bool),
  1932.     XtOffset(TextWindow, persistent_selections),
  1933.     XtRImmediate,
  1934.     (XtPointer) True
  1935.     },
  1936.     {
  1937.     XtNselectionSetsDOT,
  1938.     XtCSelectionSetsDOT,
  1939.     XtRBool,
  1940.     sizeof(Bool),
  1941.     XtOffset(TextWindow, selection_sets_DOT),
  1942.     XtRImmediate,
  1943.     (XtPointer) False
  1944.     },
  1945.     {
  1946.     XtNblinkInterval,
  1947.     XtCBlinkInterval,
  1948.     XtRInt,
  1949.     sizeof(int),
  1950.     XtOffset(TextWindow, blink_interval),
  1951.     XtRImmediate,
  1952.     (XtPointer) -666        /* 2/3 second; only when highlighted */
  1953.     },
  1954. };
  1955.  
  1956. static XtResource color_resources[] = {
  1957.     {
  1958.     XtNfcolor0,
  1959.     XtCFcolor0,
  1960.     XtRPixel,
  1961.     sizeof(Pixel),
  1962.     XtOffset(TextWindow, colors_fg[0]),
  1963.     XtRPixel,
  1964.     (XtPointer) &cur_win_rec.fg
  1965.     },
  1966.     {
  1967.     XtNbcolor0,
  1968.     XtCBcolor0,
  1969.     XtRPixel,
  1970.     sizeof(Pixel),
  1971.     XtOffset(TextWindow, colors_bg[0]),
  1972.     XtRPixel,
  1973.     (XtPointer) &cur_win_rec.bg
  1974.     },
  1975.     {
  1976.     XtNfcolor1,
  1977.     XtCFcolor1,
  1978.     XtRPixel,
  1979.     sizeof(Pixel),
  1980.     XtOffset(TextWindow, colors_fg[1]),
  1981.     XtRPixel,
  1982.     (XtPointer) &cur_win_rec.fg
  1983.     },
  1984.     {
  1985.     XtNbcolor1,
  1986.     XtCBcolor1,
  1987.     XtRPixel,
  1988.     sizeof(Pixel),
  1989.     XtOffset(TextWindow, colors_bg[1]),
  1990.     XtRPixel,
  1991.     (XtPointer) &cur_win_rec.bg
  1992.     },
  1993.     {
  1994.     XtNfcolor2,
  1995.     XtCFcolor2,
  1996.     XtRPixel,
  1997.     sizeof(Pixel),
  1998.     XtOffset(TextWindow, colors_fg[2]),
  1999.     XtRPixel,
  2000.     (XtPointer) &cur_win_rec.fg
  2001.     },
  2002.     {
  2003.     XtNbcolor2,
  2004.     XtCBcolor2,
  2005.     XtRPixel,
  2006.     sizeof(Pixel),
  2007.     XtOffset(TextWindow, colors_bg[2]),
  2008.     XtRPixel,
  2009.     (XtPointer) &cur_win_rec.bg
  2010.     },
  2011.     {
  2012.     XtNfcolor3,
  2013.     XtCFcolor3,
  2014.     XtRPixel,
  2015.     sizeof(Pixel),
  2016.     XtOffset(TextWindow, colors_fg[3]),
  2017.     XtRPixel,
  2018.     (XtPointer) &cur_win_rec.fg
  2019.     },
  2020.     {
  2021.     XtNbcolor3,
  2022.     XtCBcolor3,
  2023.     XtRPixel,
  2024.     sizeof(Pixel),
  2025.     XtOffset(TextWindow, colors_bg[3]),
  2026.     XtRPixel,
  2027.     (XtPointer) &cur_win_rec.bg
  2028.     },
  2029.     {
  2030.     XtNfcolor4,
  2031.     XtCFcolor4,
  2032.     XtRPixel,
  2033.     sizeof(Pixel),
  2034.     XtOffset(TextWindow, colors_fg[4]),
  2035.     XtRPixel,
  2036.     (XtPointer) &cur_win_rec.fg
  2037.     },
  2038.     {
  2039.     XtNbcolor4,
  2040.     XtCBcolor4,
  2041.     XtRPixel,
  2042.     sizeof(Pixel),
  2043.     XtOffset(TextWindow, colors_bg[4]),
  2044.     XtRPixel,
  2045.     (XtPointer) &cur_win_rec.bg
  2046.     },
  2047.     {
  2048.     XtNfcolor5,
  2049.     XtCFcolor5,
  2050.     XtRPixel,
  2051.     sizeof(Pixel),
  2052.     XtOffset(TextWindow, colors_fg[5]),
  2053.     XtRPixel,
  2054.     (XtPointer) &cur_win_rec.fg
  2055.     },
  2056.     {
  2057.     XtNbcolor5,
  2058.     XtCBcolor5,
  2059.     XtRPixel,
  2060.     sizeof(Pixel),
  2061.     XtOffset(TextWindow, colors_bg[5]),
  2062.     XtRPixel,
  2063.     (XtPointer) &cur_win_rec.bg
  2064.     },
  2065.     {
  2066.     XtNfcolor6,
  2067.     XtCFcolor6,
  2068.     XtRPixel,
  2069.     sizeof(Pixel),
  2070.     XtOffset(TextWindow, colors_fg[6]),
  2071.     XtRPixel,
  2072.     (XtPointer) &cur_win_rec.fg
  2073.     },
  2074.     {
  2075.     XtNbcolor6,
  2076.     XtCBcolor6,
  2077.     XtRPixel,
  2078.     sizeof(Pixel),
  2079.     XtOffset(TextWindow, colors_bg[6]),
  2080.     XtRPixel,
  2081.     (XtPointer) &cur_win_rec.bg
  2082.     },
  2083.     {
  2084.     XtNfcolor7,
  2085.     XtCFcolor7,
  2086.     XtRPixel,
  2087.     sizeof(Pixel),
  2088.     XtOffset(TextWindow, colors_fg[7]),
  2089.     XtRPixel,
  2090.     (XtPointer) &cur_win_rec.fg
  2091.     },
  2092.     {
  2093.     XtNbcolor7,
  2094.     XtCBcolor7,
  2095.     XtRPixel,
  2096.     sizeof(Pixel),
  2097.     XtOffset(TextWindow, colors_bg[7]),
  2098.     XtRPixel,
  2099.     (XtPointer) &cur_win_rec.bg
  2100.     },
  2101.     {
  2102.     XtNfcolor8,
  2103.     XtCFcolor8,
  2104.     XtRPixel,
  2105.     sizeof(Pixel),
  2106.     XtOffset(TextWindow, colors_fg[8]),
  2107.     XtRPixel,
  2108.     (XtPointer) &cur_win_rec.fg
  2109.     },
  2110.     {
  2111.     XtNbcolor8,
  2112.     XtCBcolor8,
  2113.     XtRPixel,
  2114.     sizeof(Pixel),
  2115.     XtOffset(TextWindow, colors_bg[8]),
  2116.     XtRPixel,
  2117.     (XtPointer) &cur_win_rec.bg
  2118.     },
  2119.     {
  2120.     XtNfcolor9,
  2121.     XtCFcolor9,
  2122.     XtRPixel,
  2123.     sizeof(Pixel),
  2124.     XtOffset(TextWindow, colors_fg[9]),
  2125.     XtRPixel,
  2126.     (XtPointer) &cur_win_rec.fg
  2127.     },
  2128.     {
  2129.     XtNbcolor9,
  2130.     XtCBcolor9,
  2131.     XtRPixel,
  2132.     sizeof(Pixel),
  2133.     XtOffset(TextWindow, colors_bg[9]),
  2134.     XtRPixel,
  2135.     (XtPointer) &cur_win_rec.bg
  2136.     },
  2137.     {
  2138.     XtNfcolorA,
  2139.     XtCFcolorA,
  2140.     XtRPixel,
  2141.     sizeof(Pixel),
  2142.     XtOffset(TextWindow, colors_fg[10]),
  2143.     XtRPixel,
  2144.     (XtPointer) &cur_win_rec.fg
  2145.     },
  2146.     {
  2147.     XtNbcolorA,
  2148.     XtCBcolorA,
  2149.     XtRPixel,
  2150.     sizeof(Pixel),
  2151.     XtOffset(TextWindow, colors_bg[10]),
  2152.     XtRPixel,
  2153.     (XtPointer) &cur_win_rec.bg
  2154.     },
  2155.     {
  2156.     XtNfcolorB,
  2157.     XtCFcolorB,
  2158.     XtRPixel,
  2159.     sizeof(Pixel),
  2160.     XtOffset(TextWindow, colors_fg[11]),
  2161.     XtRPixel,
  2162.     (XtPointer) &cur_win_rec.fg
  2163.     },
  2164.     {
  2165.     XtNbcolorB,
  2166.     XtCBcolorB,
  2167.     XtRPixel,
  2168.     sizeof(Pixel),
  2169.     XtOffset(TextWindow, colors_bg[11]),
  2170.     XtRPixel,
  2171.     (XtPointer) &cur_win_rec.bg
  2172.     },
  2173.     {
  2174.     XtNfcolorC,
  2175.     XtCFcolorC,
  2176.     XtRPixel,
  2177.     sizeof(Pixel),
  2178.     XtOffset(TextWindow, colors_fg[12]),
  2179.     XtRPixel,
  2180.     (XtPointer) &cur_win_rec.fg
  2181.     },
  2182.     {
  2183.     XtNbcolorC,
  2184.     XtCBcolorC,
  2185.     XtRPixel,
  2186.     sizeof(Pixel),
  2187.     XtOffset(TextWindow, colors_bg[12]),
  2188.     XtRPixel,
  2189.     (XtPointer) &cur_win_rec.bg
  2190.     },
  2191.     {
  2192.     XtNfcolorD,
  2193.     XtCFcolorD,
  2194.     XtRPixel,
  2195.     sizeof(Pixel),
  2196.     XtOffset(TextWindow, colors_fg[13]),
  2197.     XtRPixel,
  2198.     (XtPointer) &cur_win_rec.fg
  2199.     },
  2200.     {
  2201.     XtNbcolorD,
  2202.     XtCBcolorD,
  2203.     XtRPixel,
  2204.     sizeof(Pixel),
  2205.     XtOffset(TextWindow, colors_bg[13]),
  2206.     XtRPixel,
  2207.     (XtPointer) &cur_win_rec.bg
  2208.     },
  2209.     {
  2210.     XtNfcolorE,
  2211.     XtCFcolorE,
  2212.     XtRPixel,
  2213.     sizeof(Pixel),
  2214.     XtOffset(TextWindow, colors_fg[14]),
  2215.     XtRPixel,
  2216.     (XtPointer) &cur_win_rec.fg
  2217.     },
  2218.     {
  2219.     XtNbcolorE,
  2220.     XtCBcolorE,
  2221.     XtRPixel,
  2222.     sizeof(Pixel),
  2223.     XtOffset(TextWindow, colors_bg[14]),
  2224.     XtRPixel,
  2225.     (XtPointer) &cur_win_rec.bg
  2226.     },
  2227.     {
  2228.     XtNfcolorF,
  2229.     XtCFcolorF,
  2230.     XtRPixel,
  2231.     sizeof(Pixel),
  2232.     XtOffset(TextWindow, colors_fg[15]),
  2233.     XtRPixel,
  2234.     (XtPointer) &cur_win_rec.fg
  2235.     },
  2236.     {
  2237.     XtNbcolorF,
  2238.     XtCBcolorF,
  2239.     XtRPixel,
  2240.     sizeof(Pixel),
  2241.     XtOffset(TextWindow, colors_bg[15]),
  2242.     XtRPixel,
  2243.     (XtPointer) &cur_win_rec.bg
  2244.     },
  2245. };
  2246.  
  2247. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  2248. static XtResource scrollbar_resources[] = {
  2249.     {
  2250.     XtNforeground,
  2251.     XtCForeground,
  2252.     XtRPixel,
  2253.     sizeof(Pixel),
  2254.     XtOffset(TextWindow, scrollbar_fg),
  2255. #if OLD_RESOURCES
  2256.     XtRPixel,
  2257.     (XtPointer) &cur_win_rec.fg
  2258. #else
  2259.     XtRString,
  2260.     "#b6dab2cab6da"
  2261. #endif
  2262.     },
  2263.     {
  2264.     XtNbackground,
  2265.     XtCBackground,
  2266.     XtRPixel,
  2267.     sizeof(Pixel),
  2268.     XtOffset(TextWindow, scrollbar_bg),
  2269. #if OLD_RESOURCES
  2270.     XtRPixel,
  2271.     (XtPointer) &cur_win_rec.bg
  2272. #else
  2273.     XtRString,
  2274.     "#9e7996589e79"
  2275. #endif /* OLD_RESOURCES */
  2276.     },
  2277.     {
  2278.     XtNsliderIsSolid,
  2279.     XtCSliderIsSolid,
  2280.     XtRBool,
  2281.     sizeof(Bool),
  2282.     XtOffset(TextWindow, slider_is_solid),
  2283. #if OLD_RESOURCES
  2284.     XtRImmediate,
  2285.     (XtPointer) False
  2286. #else
  2287.     XtRBool,
  2288.     (XtPointer) &cur_win_rec.slider_is_solid
  2289. #endif /* OLD_RESOURCES */
  2290.     },
  2291. };
  2292. #endif
  2293.  
  2294. static XtResource modeline_resources[] = {
  2295.     {
  2296.     XtNforeground,
  2297.     XtCForeground,
  2298.     XtRPixel,
  2299.     sizeof(Pixel),
  2300.     XtOffset(TextWindow, modeline_fg),
  2301. #if OLD_RESOURCES
  2302.     XtRPixel,
  2303.     (XtPointer) &cur_win_rec.bg
  2304. #else
  2305.     XtRString,
  2306.     "#ffffffffffff"
  2307. #endif /* OLD_RESOURCES */
  2308.     },
  2309.     {
  2310.     XtNbackground,
  2311.     XtCBackground,
  2312.     XtRPixel,
  2313.     sizeof(Pixel),
  2314.     XtOffset(TextWindow, modeline_bg),
  2315. #if OLD_RESOURCES
  2316.     XtRPixel,
  2317.     (XtPointer) &cur_win_rec.fg
  2318. #else
  2319.     XtRString,
  2320.     "#70006ca37000"
  2321. #endif /* OLD_RESOURCES */
  2322.     },
  2323.     {
  2324.     XtNfocusForeground,
  2325.     XtCForeground,
  2326.     XtRPixel,
  2327.     sizeof(Pixel),
  2328.     XtOffset(TextWindow, modeline_focus_fg),
  2329. #if OLD_RESOURCES
  2330.     XtRPixel,
  2331.     (XtPointer) &cur_win_rec.bg
  2332. #else
  2333.     XtRString,
  2334.     "#ffffffffffff"
  2335. #endif /* OLD_RESOURCES */
  2336.     },
  2337.     {
  2338.     XtNfocusBackground,
  2339.     XtCBackground,
  2340.     XtRPixel,
  2341.     sizeof(Pixel),
  2342.     XtOffset(TextWindow, modeline_focus_bg),
  2343. #if OLD_RESOURCES
  2344.     XtRPixel,
  2345.     (XtPointer) &cur_win_rec.fg
  2346. #else
  2347.     XtRString,
  2348.     "#70006ca37000"
  2349. #endif /* OLD_RESOURCES */
  2350.     },
  2351. };
  2352.  
  2353. static XtResource selection_resources[] = {
  2354.     {
  2355.     XtNforeground,
  2356.     XtCBackground,                /* weird, huh? */
  2357.     XtRPixel,
  2358.     sizeof(Pixel),
  2359.     XtOffset(TextWindow, selection_fg),
  2360.     XtRPixel,
  2361.     (XtPointer) &cur_win_rec.bg
  2362.     },
  2363.     {
  2364.     XtNbackground,
  2365.     XtCForeground,
  2366.     XtRPixel,
  2367.     sizeof(Pixel),
  2368.     XtOffset(TextWindow, selection_bg),
  2369.     XtRPixel,
  2370.     (XtPointer) &cur_win_rec.fg
  2371.     },
  2372. };
  2373.  
  2374. /*
  2375.  * We resort to a bit of trickery for the cursor resources.  Note that the
  2376.  * default foreground and background for the cursor is the same as that for
  2377.  * the rest of the window.  This would render the cursor invisible!  This
  2378.  * condition actually indicates that usual technique of inverting the
  2379.  * foreground and background colors should be used, the rationale being
  2380.  * that no (sane) user would want to set the cursor foreground and
  2381.  * background to be the same as the rest of the window.
  2382.  */
  2383.  
  2384. static XtResource cursor_resources[] = {
  2385.     {
  2386.     XtNforeground,
  2387.     XtCForeground,
  2388.     XtRPixel,
  2389.     sizeof(Pixel),
  2390.     XtOffset(TextWindow, cursor_fg),
  2391.     XtRPixel,
  2392.     (XtPointer) &cur_win_rec.fg
  2393.     },
  2394.     {
  2395.     XtNbackground,
  2396.     XtCBackground,
  2397.     XtRPixel,
  2398.     sizeof(Pixel),
  2399.     XtOffset(TextWindow, cursor_bg),
  2400.     XtRPixel,
  2401.     (XtPointer) &cur_win_rec.bg
  2402.     },
  2403. };
  2404.  
  2405. static XtResource pointer_resources[] = {
  2406.     {
  2407.     XtNforeground,
  2408.     XtCForeground,
  2409.     XtRPixel,
  2410.     sizeof(Pixel),
  2411.     XtOffset(TextWindow, pointer_fg),
  2412.     XtRPixel,
  2413.     (XtPointer) &cur_win_rec.fg
  2414.     },
  2415.     {
  2416.     XtNbackground,
  2417.     XtCBackground,
  2418.     XtRPixel,
  2419.     sizeof(Pixel),
  2420.     XtOffset(TextWindow, pointer_bg),
  2421.     XtRPixel,
  2422.     (XtPointer) &cur_win_rec.bg
  2423.     },
  2424.     {
  2425.     XtNnormalShape,
  2426.     XtCNormalShape,
  2427.     XtRCursor,
  2428.     sizeof(Cursor),
  2429.     XtOffset(TextWindow, normal_pointer),
  2430.     XtRString,
  2431.     (XtPointer) "xterm"
  2432.     },
  2433. #if OPT_WORKING
  2434.     {
  2435.     XtNwatchShape,
  2436.     XtCWatchShape,
  2437.     XtRCursor,
  2438.     sizeof(Cursor),
  2439.     XtOffset(TextWindow, watch_pointer),
  2440.     XtRString,
  2441.     (XtPointer) "watch"
  2442.     },
  2443. #endif
  2444. };
  2445.  
  2446. #define CHECK_MIN_MAX(v,min,max)    \
  2447.     do {                \
  2448.         if ((v) > (max))        \
  2449.         (v)=(max);        \
  2450.         else if ((v) < (min))    \
  2451.         (v) = (min);        \
  2452.     } one_time
  2453.  
  2454. static void my_error_handler(String message)
  2455. {
  2456.     fprintf(stderr, "%s: %s\n", prog_arg, message);
  2457.     print_usage();
  2458. }
  2459.  
  2460. /* ARGSUSED */
  2461. void
  2462. x_preparse_args(
  2463.     int        *pargc,
  2464.     char     ***pargv)
  2465. {
  2466.     XFontStruct *pfont;
  2467.     XGCValues   gcvals;
  2468.     ULONG    gcmask;
  2469.     int        geo_mask, startx, starty, screen_depth;
  2470.     int        i;
  2471.     Cardinal    start_cols, start_rows;
  2472.     static XrmOptionDescRec options[] = {
  2473.     {"-t",       (char *)0,          XrmoptionSkipArg,    (caddr_t)0 },
  2474.     {"-fork",       "*forkOnStartup",   XrmoptionNoArg,    "true" },
  2475.     {"+fork",       "*forkOnStartup",   XrmoptionNoArg,    "false" },
  2476.     {"-leftbar",    "*scrollbarOnLeft", XrmoptionNoArg,    "true" },
  2477.     {"-rightbar",    "*scrollbarOnLeft", XrmoptionNoArg,    "false" },
  2478.     };
  2479. #if MOTIF_WIDGETS || OL_WIDGETS
  2480.     static XtActionsRec new_actions[] = {
  2481.     { "ConfigureBar", configure_bar }
  2482.     };
  2483.     static String scrollbars_translations =
  2484.     "#override \n\
  2485.         Ctrl<Btn1Down>:ConfigureBar(Split) \n\
  2486.         Ctrl<Btn2Down>:ConfigureBar(Kill) \n\
  2487.         Ctrl<Btn3Down>:ConfigureBar(Only)";
  2488.     static String fallback_resources[]= {
  2489.     "*scrollPane.background:grey80",
  2490.     "*scrollbar.background:grey60",
  2491.     NULL
  2492.     };
  2493. #else
  2494. #if OPT_KEV_DRAGGING
  2495.     static XtActionsRec new_actions[] = {
  2496.     { "ConfigureBar", configure_bar },
  2497.     { "DoScroll", do_scroll },
  2498.     { "ResizeBar", resize_bar }
  2499.     };
  2500.     static String scrollbars_translations =
  2501.     "#override \n\
  2502.         Ctrl<Btn1Down>:ConfigureBar(Split) \n\
  2503.         Ctrl<Btn2Down>:ConfigureBar(Kill) \n\
  2504.         Ctrl<Btn3Down>:ConfigureBar(Only) \n\
  2505.         <Btn1Down>:DoScroll(Forward) \n\
  2506.         <Btn2Down>:DoScroll(StartDrag) \n\
  2507.         <Btn3Down>:DoScroll(Backward) \n\
  2508.         <Btn2Motion>:DoScroll(Drag) \n\
  2509.         <BtnUp>:DoScroll(End)";
  2510.     static String resizeGrip_translations =
  2511.     "#override \n\
  2512.         <BtnDown>:ResizeBar(Start) \n\
  2513.         <BtnMotion>:ResizeBar(Drag) \n\
  2514.         <BtnUp>:ResizeBar(End)";
  2515.     static String fallback_resources[]= {
  2516.     NULL
  2517.     };
  2518. #else
  2519.     static XtActionsRec new_actions[] = {
  2520.     { "ConfigureBar", configure_bar },
  2521.     { "ResizeBar", resize_bar }
  2522.     };
  2523.     static String scrollbars_translations =
  2524.     "#override \n\
  2525.         Ctrl<Btn1Down>:ConfigureBar(Split) \n\
  2526.         Ctrl<Btn2Down>:ConfigureBar(Kill) \n\
  2527.         Ctrl<Btn3Down>:ConfigureBar(Only)";
  2528.     static String resizeGrip_translations =
  2529.     "#override \n\
  2530.         <BtnDown>:ResizeBar(Start) \n\
  2531.         <BtnMotion>:ResizeBar(Drag) \n\
  2532.         <BtnUp>:ResizeBar(End)";
  2533.     static String fallback_resources[]= {
  2534.     NULL
  2535.     };
  2536. #endif /* OPT_KEV_DRAGGING */
  2537.     static char solid_pixmap_bits[] = { '\003', '\003' };
  2538.     static char stippled_pixmap_bits[] = { '\002', '\001' };
  2539. #endif /* MOTIF_WIDGETS || OL_WIDGETS */
  2540.  
  2541. #if OL_WIDGETS
  2542.     /* There is a cryptic statement in the poor documentation that I have
  2543.      * on OpenLook that OlToolkitInitialize is now preferred to the older
  2544.      * OlInitialize (which is used in the examples and is documented better).
  2545.      * The documentation I have says that OlToolkitInitialize returns a
  2546.      * widget.  I don't believe it, nor do I understand what kind of widget
  2547.      * it would be.  I get the impression that it takes one argument, but
  2548.      * I don't know what that argument is supposed to be.
  2549.      */
  2550.     (void) OlToolkitInitialize( NULL );
  2551. #endif /* OL_WIDGETS */
  2552.  
  2553.     XtSetErrorHandler(my_error_handler);
  2554.     cur_win->top_widget = XtVaAppInitialize(
  2555.         &cur_win->app_context,
  2556.         MY_CLASS,
  2557.         options, XtNumber(options),
  2558.         pargc, *pargv,
  2559.         fallback_resources,
  2560.         XtNgeometry,    NULL,
  2561.         XtNinput,        TRUE,
  2562.         NULL);
  2563.     XtSetErrorHandler((XtErrorHandler)0);
  2564.     dpy = XtDisplay(cur_win->top_widget);
  2565.  
  2566. #if 0
  2567.     check_visuals();
  2568. #endif
  2569.  
  2570.     XtVaGetValues(cur_win->top_widget,
  2571.         XtNdepth, &screen_depth,
  2572.         NULL);
  2573.  
  2574. #if !OLD_RESOURCES
  2575.     cur_win->slider_is_solid = (screen_depth >= 6);
  2576. #endif
  2577.  
  2578.     XtGetApplicationResources(
  2579.         cur_win->top_widget,
  2580.         (XtPointer)cur_win,
  2581.         resources,
  2582.         XtNumber(resources),
  2583.         (ArgList)0,
  2584.         0);
  2585.  
  2586.     if (cur_win->fork_on_startup)
  2587.     (void) newprocessgroup(TRUE,1);
  2588.  
  2589.     if (cur_win->bg == cur_win->fg)
  2590.     cur_win->fg = BlackPixel(dpy,DefaultScreen(dpy));
  2591.     if (cur_win->bg == cur_win->fg)
  2592.     cur_win->bg = WhitePixel(dpy,DefaultScreen(dpy));
  2593.  
  2594.  
  2595. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  2596.     XtGetSubresources(
  2597.         cur_win->top_widget,
  2598.         (XtPointer)cur_win,
  2599.         "scrollbar",
  2600.         "Scrollbar",
  2601.         scrollbar_resources,
  2602.         XtNumber(scrollbar_resources),
  2603.         (ArgList)0,
  2604.         0);
  2605. #endif    /* OPT_KEV_SCROLLBARS */
  2606.  
  2607.     XtGetSubresources(
  2608.         cur_win->top_widget,
  2609.         (XtPointer)cur_win,
  2610.         "modeline",
  2611.         "Modeline",
  2612.         modeline_resources,
  2613.         XtNumber(modeline_resources),
  2614.         (ArgList)0,
  2615.         0);
  2616.  
  2617.     XtGetSubresources(
  2618.         cur_win->top_widget,
  2619.         (XtPointer)cur_win,
  2620.         "selection",
  2621.         "Selection",
  2622.         selection_resources,
  2623.         XtNumber(selection_resources),
  2624.         (ArgList)0,
  2625.         0);
  2626.  
  2627.     XtGetSubresources(
  2628.         cur_win->top_widget,
  2629.         (XtPointer)cur_win,
  2630.         "cursor",
  2631.         "Cursor",
  2632.         cursor_resources,
  2633.         XtNumber(cursor_resources),
  2634.         (ArgList)0,
  2635.         0);
  2636.  
  2637.     XtGetSubresources(
  2638.         cur_win->top_widget,
  2639.         (XtPointer)cur_win,
  2640.         "pointer",
  2641.         "Pointer",
  2642.         pointer_resources,
  2643.         XtNumber(pointer_resources),
  2644.         (ArgList)0,
  2645.         0);
  2646.  
  2647.     XtGetSubresources(
  2648.         cur_win->top_widget,
  2649.         (XtPointer)cur_win,
  2650.         "color",
  2651.         "Color",
  2652.         color_resources,
  2653.         XtNumber(color_resources),
  2654.         (ArgList)0,
  2655.         0);
  2656.  
  2657.     /* Initialize atoms needed for getting a fully specified font name */
  2658.     atom_FONT         = XInternAtom(dpy, "FONT", False);
  2659.     atom_FOUNDRY    = XInternAtom(dpy, "FOUNDRY", False);
  2660.     atom_WEIGHT_NAME    = XInternAtom(dpy, "WEIGHT_NAME", False);
  2661.     atom_SLANT        = XInternAtom(dpy, "SLANT", False);
  2662.     atom_SETWIDTH_NAME    = XInternAtom(dpy, "SETWIDTH_NAME", False);
  2663.     atom_PIXEL_SIZE    = XInternAtom(dpy, "PIXEL_SIZE", False);
  2664.     atom_RESOLUTION_X    = XInternAtom(dpy, "RESOLUTION_X", False);
  2665.     atom_RESOLUTION_Y    = XInternAtom(dpy, "RESOLUTION_Y", False);
  2666.     atom_SPACING    = XInternAtom(dpy, "SPACING", False);
  2667.     atom_AVERAGE_WIDTH    = XInternAtom(dpy, "AVERAGE_WIDTH", False);
  2668.     atom_CHARSET_REGISTRY = XInternAtom(dpy, "CHARSET_REGISTRY", False);
  2669.     atom_CHARSET_ENCODING = XInternAtom(dpy, "CHARSET_ENCODING", False);
  2670.  
  2671.     pfont = query_font(cur_win, cur_win->starting_fontname);
  2672.     if (!pfont) {
  2673.     pfont = query_font(cur_win, FONTNAME);
  2674.     if (!pfont) {
  2675.         (void)fprintf(stderr, "couldn't get font \"%s\" or \"%s\", exiting\n",
  2676.             cur_win->starting_fontname, FONTNAME);
  2677.         ExitProgram(BADEXIT);
  2678.     }
  2679.     }
  2680.     (void) set_character_class(cur_win->multi_click_char_class);
  2681.  
  2682.     /*
  2683.      * Look at our copy of the geometry resource to obtain the dimensions of
  2684.      * the window in characters.  We've provided a default value of 80x36
  2685.      * so there'll always be something to parse.  We still need to check
  2686.      * the return mask since the user may specify a position, but no size.
  2687.      */
  2688.     geo_mask = XParseGeometry(cur_win->geometry,
  2689.         &startx, &starty,
  2690.         &start_cols, &start_rows);
  2691.  
  2692.     cur_win->rows = (geo_mask & HeightValue) ? start_rows : 36;
  2693.     cur_win->cols = (geo_mask & WidthValue) ? start_cols : 80;
  2694.  
  2695.     /*
  2696.      * Fix up the geometry resource of top level shell providing initial
  2697.      * position if so requested by user.
  2698.      */
  2699.  
  2700.     if (geo_mask & (XValue | YValue)) {
  2701.     char *gp = cur_win->geometry;
  2702.     while (*gp && *gp != '+' && *gp != '-')
  2703.         gp++;            /* skip over width and height */
  2704.     if (*gp)
  2705.         XtVaSetValues(cur_win->top_widget,
  2706.             XtNgeometry,    gp,
  2707.             NULL);
  2708.     }
  2709.  
  2710.     /* Sanity check values obtained from XtGetApplicationResources */
  2711.     CHECK_MIN_MAX(cur_win->pane_width, PANE_WIDTH_MIN, PANE_WIDTH_MAX);
  2712.  
  2713.  
  2714. #if MOTIF_WIDGETS
  2715.     cur_win->form_widget = XtVaCreateManagedWidget(
  2716.         "form",
  2717.         xmFormWidgetClass,
  2718.         cur_win->top_widget,
  2719.         NULL);
  2720. #else
  2721. #if OL_WIDGETS
  2722.     cur_win->form_widget = XtVaCreateManagedWidget(
  2723.         "form",
  2724.         formWidgetClass,
  2725.         cur_win->top_widget,
  2726.         NULL);
  2727. #else
  2728. #if ATHENA_WIDGETS && OPT_MENUS
  2729.     cur_win->pane_widget = XtVaCreateManagedWidget(
  2730.         "pane",
  2731.         panedWidgetClass,
  2732.         cur_win->top_widget,
  2733.         NULL);
  2734.     cur_win->menu_widget = XtVaCreateManagedWidget(
  2735.         "menubar",
  2736.         boxWidgetClass,
  2737.         cur_win->pane_widget,
  2738.         XtNshowGrip,        False,
  2739.         NULL);
  2740.     cur_win->form_widget = XtVaCreateManagedWidget(
  2741.         "form",
  2742. #if KEV_WIDGETS    /* FIXME */
  2743.         bbWidgetClass,
  2744. #else
  2745.         formWidgetClass,
  2746. #endif
  2747.         cur_win->pane_widget,
  2748.         XtNwidth,            x_width(cur_win)
  2749.                         + cur_win->pane_width + 2,
  2750.         XtNheight,            x_height(cur_win),
  2751.         XtNbackground,        cur_win->bg,
  2752.         XtNbottom,            XtChainBottom,
  2753.         XtNleft,            XtChainLeft,
  2754.         XtNright,            XtChainRight,
  2755.         XtNfromVert,        cur_win->menu_widget,
  2756.         XtNvertDistance,        0,
  2757.         NULL);
  2758. #else
  2759. #if NO_WIDGETS
  2760.     cur_win->form_widget = XtVaCreateManagedWidget(
  2761.         "form",
  2762.         bbWidgetClass,
  2763.         cur_win->top_widget,
  2764.         XtNwidth,            x_width(cur_win)
  2765.                         + cur_win->pane_width + 2,
  2766.         XtNheight,            x_height(cur_win),
  2767.         XtNbackground,        cur_win->bg,
  2768.         NULL);
  2769. #endif /* NO_WIDGETS */
  2770. #endif /* ATHENA_WIDGETS */
  2771. #endif /* OL_WIDGETS */
  2772. #endif /* MOTIF_WIDGETS */
  2773.  
  2774. #if OPT_MENUS
  2775. #if ATHENA_WIDGETS
  2776.     do_menu ( cur_win->menu_widget );
  2777. #endif
  2778. #if MOTIF_WIDGETS
  2779.     menub = XmCreateMenuBar (cur_win->form_widget, "menub", NULL, 0);
  2780.  
  2781.     XtVaSetValues (menub,
  2782.             XmNtopAttachment,    XmATTACH_FORM,
  2783.             XmNleftAttachment,    XmATTACH_FORM,
  2784.             XmNbottomAttachment,    XmATTACH_NONE,
  2785.             XmNrightAttachment,    XmATTACH_FORM,
  2786.             NULL);
  2787.     XtManageChild (menub);
  2788.     do_menu ( menub );
  2789. #endif
  2790. #endif
  2791.  
  2792.     cur_win->screen = XtVaCreateManagedWidget(
  2793.         "screen",
  2794. #if MOTIF_WIDGETS
  2795.         xmPrimitiveWidgetClass,
  2796. #else
  2797.         coreWidgetClass,
  2798. #endif
  2799.         cur_win->form_widget,
  2800.         XtNwidth,            x_width(cur_win),
  2801.         XtNheight,            x_height(cur_win),
  2802.         XtNborderWidth,         0,
  2803.         XtNbackground,        cur_win->bg,
  2804. #if MOTIF_WIDGETS
  2805.         XmNresizable,        TRUE,
  2806.         XmNbottomAttachment,    XmATTACH_FORM,
  2807. #if OPT_MENUS
  2808.         XmNtopAttachment,        XmATTACH_WIDGET,
  2809.         XmNtopWidget,        menub,
  2810.         XmNtopOffset,        2,
  2811. #else
  2812.         XmNtopAttachment,        XmATTACH_FORM,
  2813. #endif
  2814.         XmNleftAttachment,        XmATTACH_FORM,
  2815.         XmNrightAttachment,        XmATTACH_NONE,
  2816. #else
  2817. #if OL_WIDGETS
  2818.         XtNyAttachBottom,        TRUE,
  2819.         XtNyVaryOffset,        FALSE,
  2820.         XtNxAddWidth,        TRUE,
  2821.         XtNyAddHeight,        TRUE,
  2822. #else
  2823. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  2824.         XtNx,            cur_win->scrollbar_on_left
  2825.                         ? cur_win->pane_width+2
  2826.                         : 0,
  2827.         XtNy,            0,
  2828. #endif    /* OPT_KEV_SCROLLBARS */
  2829. #endif    /* OL_WIDGETS */
  2830. #endif    /* MOTIF_WIDGETS */
  2831.         NULL);
  2832.  
  2833. #if defined(LESSTIF_VERSION)
  2834.     /*
  2835.      * Lesstif (0.81) seems to install translations that cause certain
  2836.      * keys (like TAB) to manipulate the focus in addition to their
  2837.      * functions within xvile.  This leads to frustration when you are
  2838.      * trying to insert text, and find the focus shifting to a scroll
  2839.      * bar or whatever.  To fix this problem, we remove those nasty
  2840.      * translations here.
  2841.      *
  2842.      * Aside from this little nit, "lesstif" seems to work admirably
  2843.      * with xvile.  Just build with screen=motif.  You can find
  2844.      * lesstif at:  ftp://ftp.lesstif.org/pub/hungry/lesstif
  2845.      */
  2846.  
  2847.     XtUninstallTranslations(cur_win->screen);
  2848. #endif  /* LESSTIF_VERSION */
  2849.  
  2850.     /* Initialize graphics context for display of normal and reverse text */
  2851.     gcmask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
  2852.     gcvals.foreground = cur_win->fg;
  2853.     gcvals.background = cur_win->bg;
  2854.     gcvals.font = cur_win->pfont->fid;
  2855.     gcvals.graphics_exposures = False;
  2856.     cur_win->textgc = XCreateGC(dpy,
  2857.             DefaultRootWindow(dpy),
  2858.         gcmask, &gcvals);
  2859.     cur_win->exposed    = FALSE;
  2860.     cur_win->visibility = VisibilityUnobscured;
  2861.  
  2862.     gcvals.foreground = cur_win->bg;
  2863.     gcvals.background = cur_win->fg;
  2864.     gcvals.font = cur_win->pfont->fid;
  2865.     cur_win->reversegc = XCreateGC(dpy,
  2866.             DefaultRootWindow(dpy),
  2867.         gcmask, &gcvals);
  2868.  
  2869.     for (i = 0; i < NCOLORS; i++) {
  2870.     if ( screen_depth == 1
  2871.       || cur_win->colors_fg[i] == cur_win->colors_bg[i]
  2872.       || ( cur_win->colors_fg[i] == cur_win->fg
  2873.         && cur_win->colors_bg[i] == cur_win->bg )) {
  2874.         /* Reuse the standard GCs if possible */
  2875.         cur_win->colors_fgc[i] = cur_win->textgc;
  2876.         cur_win->colors_bgc[i] = cur_win->reversegc;
  2877.     } else {
  2878.         gcvals.foreground = cur_win->colors_fg[i];
  2879.         gcvals.background = cur_win->colors_bg[i];
  2880.         cur_win->colors_fgc[i] = XCreateGC(dpy,
  2881.                                        DefaultRootWindow(dpy),
  2882.                                        gcmask, &gcvals);
  2883.         gcvals.foreground = cur_win->colors_bg[i];
  2884.         gcvals.background = cur_win->colors_fg[i];
  2885.         cur_win->colors_bgc[i] = XCreateGC(dpy,
  2886.                                        DefaultRootWindow(dpy),
  2887.                                        gcmask, &gcvals);
  2888.     }
  2889.     }
  2890.  
  2891.     /* Initialize graphics context for display of selections */
  2892.     if (screen_depth == 1
  2893.      || cur_win->selection_bg == cur_win->selection_fg
  2894.      ||  (cur_win->fg == cur_win->selection_fg
  2895.        && cur_win->bg == cur_win->selection_bg)
  2896.      ||  (cur_win->fg == cur_win->selection_bg
  2897.        && cur_win->bg == cur_win->selection_fg)) {
  2898.     cur_win->selgc = cur_win->reversegc;
  2899.     cur_win->revselgc = cur_win->textgc;
  2900.     }
  2901.     else {
  2902.     gcvals.foreground = cur_win->selection_fg;
  2903.     gcvals.background = cur_win->selection_bg;
  2904.     cur_win->selgc = XCreateGC(dpy,
  2905.         DefaultRootWindow(dpy),
  2906.         gcmask, &gcvals);
  2907.     gcvals.foreground = cur_win->selection_bg;
  2908.     gcvals.background = cur_win->selection_fg;
  2909.     cur_win->revselgc = XCreateGC(dpy,
  2910.         DefaultRootWindow(dpy),
  2911.         gcmask, &gcvals);
  2912.     }
  2913.  
  2914.     /*
  2915.      * Initialize graphics context for display of normal modelines.
  2916.      * Portions of the modeline are never displayed in reverse video (wrt
  2917.      * the modeline) so there is no corresponding reverse video gc.
  2918.      */
  2919.     if (screen_depth == 1
  2920.      || cur_win->modeline_bg == cur_win->modeline_fg
  2921.      ||  (cur_win->fg == cur_win->modeline_fg
  2922.        && cur_win->bg == cur_win->modeline_bg)
  2923.      ||  (cur_win->fg == cur_win->modeline_bg
  2924.        && cur_win->bg == cur_win->modeline_fg)) {
  2925.     cur_win->modeline_gc = cur_win->reversegc;
  2926.     }
  2927.     else {
  2928.     gcvals.foreground = cur_win->modeline_fg;
  2929.     gcvals.background = cur_win->modeline_bg;
  2930.     cur_win->modeline_gc = XCreateGC(dpy,
  2931.                                  DefaultRootWindow(dpy),
  2932.                                  gcmask, &gcvals);
  2933.     }
  2934.  
  2935.     /*
  2936.      * Initialize graphics context for display of modelines which indicate
  2937.      * that the corresponding window has focus.
  2938.      */
  2939.     if (screen_depth == 1
  2940.      || cur_win->modeline_focus_bg == cur_win->modeline_focus_fg
  2941.      ||  (cur_win->fg == cur_win->modeline_focus_fg
  2942.        && cur_win->bg == cur_win->modeline_focus_bg)
  2943.      ||  (cur_win->fg == cur_win->modeline_focus_bg
  2944.        && cur_win->bg == cur_win->modeline_focus_fg)) {
  2945.     cur_win->modeline_focus_gc = cur_win->reversegc;
  2946.     }
  2947.     else {
  2948.     gcvals.foreground = cur_win->modeline_focus_fg;
  2949.     gcvals.background = cur_win->modeline_focus_bg;
  2950.     cur_win->modeline_focus_gc = XCreateGC(dpy,
  2951.                                        DefaultRootWindow(dpy),
  2952.                                        gcmask, &gcvals);
  2953.     }
  2954.  
  2955.     /* Initialize cursor graphics context and flag which indicates how to
  2956.      * display cursor.
  2957.      */
  2958.     if (screen_depth == 1
  2959.      || cur_win->cursor_bg == cur_win->cursor_fg
  2960.      ||  (cur_win->fg == cur_win->cursor_fg
  2961.        && cur_win->bg == cur_win->cursor_bg)
  2962.      ||  (cur_win->fg == cur_win->cursor_bg
  2963.        && cur_win->bg == cur_win->cursor_fg)) {
  2964.     cur_win->is_color_cursor = FALSE;
  2965.     cur_win->cursor_fg = cur_win->bg;        /* undo our trickery */
  2966.     cur_win->cursor_bg = cur_win->fg;
  2967.     cur_win->cursgc = cur_win->reversegc;
  2968.     cur_win->revcursgc = cur_win->textgc;
  2969.     }
  2970.     else {
  2971.     cur_win->is_color_cursor = TRUE;
  2972.     gcvals.foreground = cur_win->cursor_fg;
  2973.     gcvals.background = cur_win->cursor_bg;
  2974.     cur_win->cursgc = XCreateGC(dpy,
  2975.         DefaultRootWindow(dpy),
  2976.         gcmask, &gcvals);
  2977.     gcvals.foreground = cur_win->cursor_bg;
  2978.     gcvals.background = cur_win->cursor_fg;
  2979.     cur_win->revcursgc = XCreateGC(dpy,
  2980.         DefaultRootWindow(dpy),
  2981.         gcmask, &gcvals);
  2982.     }
  2983.  
  2984. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  2985.     if (cur_win->scrollbar_bg == cur_win->scrollbar_fg) {
  2986.     cur_win->scrollbar_bg = cur_win->bg;
  2987.     cur_win->scrollbar_fg = cur_win->fg;
  2988.     }
  2989.     if (screen_depth == 1 || too_light_or_too_dark(cur_win->scrollbar_fg))
  2990.     cur_win->slider_is_solid = False;
  2991. #endif /* OPT_KEV_SCROLLBARS */
  2992.  
  2993. #if OPT_XAW_SCROLLBARS
  2994.     cur_win->thumb_bm =
  2995.     XCreateBitmapFromData(dpy, DefaultRootWindow(dpy),
  2996.         cur_win->slider_is_solid
  2997.         ? solid_pixmap_bits
  2998.         : stippled_pixmap_bits,
  2999.         2, 2);
  3000. #endif /* OPT_XAW_SCROLLBARS */
  3001.  
  3002. #if OPT_KEV_SCROLLBARS
  3003.     gcvals.background = cur_win->scrollbar_bg;
  3004.     if (!cur_win->slider_is_solid) {
  3005.     gcmask = GCFillStyle | GCStipple | GCForeground | GCBackground;
  3006.     gcvals.foreground = cur_win->scrollbar_fg;
  3007.     gcvals.fill_style = FillOpaqueStippled;
  3008.     gcvals.stipple = XCreatePixmapFromBitmapData(dpy,
  3009.         DefaultRootWindow(dpy),
  3010.         stippled_pixmap_bits,
  3011.         2, 2,
  3012.         1L, 0L,
  3013.         1);
  3014.     }
  3015.     else {
  3016.     gcmask = GCForeground | GCBackground;
  3017.     gcvals.foreground = cur_win->scrollbar_fg;
  3018.     }
  3019.     gcmask |= GCGraphicsExposures;
  3020.     gcvals.graphics_exposures = False;
  3021.     cur_win->scrollbargc = XCreateGC(dpy,
  3022.         DefaultRootWindow(dpy),
  3023.         gcmask, &gcvals);
  3024.  
  3025.     if (screen_depth >= 6 && cur_win->slider_is_solid) {
  3026.     Pixel fg_light, fg_dark, bg_light, bg_dark;
  3027.     if ( alloc_shadows(cur_win->scrollbar_fg, &fg_light, &fg_dark)
  3028.       && alloc_shadows(cur_win->scrollbar_bg, &bg_light, &bg_dark)) {
  3029.         GC gc;
  3030.         Pixmap slider_pixmap;
  3031.         cur_win->slider_is_3D = True;
  3032.  
  3033.         cur_win->trough_pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy),
  3034.             cur_win->pane_width+2, 16, (unsigned int)screen_depth);
  3035.  
  3036. #define TROUGH_HT 16
  3037.         gcvals.foreground = cur_win->scrollbar_bg;
  3038.         gc = XCreateGC(dpy, DefaultRootWindow(dpy), gcmask, &gcvals);
  3039.         XFillRectangle(dpy, cur_win->trough_pixmap, gc, 0,0,
  3040.             cur_win->pane_width+2, TROUGH_HT);
  3041.         XSetForeground(dpy, gc, bg_dark);
  3042.         XFillRectangle(dpy, cur_win->trough_pixmap, gc, 0,0, 2, TROUGH_HT);
  3043.         XSetForeground(dpy, gc, bg_light);
  3044.         XFillRectangle(dpy, cur_win->trough_pixmap, gc,
  3045.             (int) cur_win->pane_width, 0, 2, TROUGH_HT);
  3046.  
  3047.         slider_pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy),
  3048.             cur_win->pane_width-2, SP_HT, (unsigned int)screen_depth);
  3049.  
  3050.         XSetForeground(dpy, gc, cur_win->scrollbar_fg);
  3051.         XFillRectangle(dpy, slider_pixmap, gc, 0,0,
  3052.             cur_win->pane_width-2, SP_HT);
  3053.         XSetForeground(dpy, gc, fg_light);
  3054.         XFillRectangle(dpy, slider_pixmap, gc, 0,0, 2, SP_HT);
  3055.         XSetForeground(dpy, gc, fg_dark);
  3056.         XFillRectangle(dpy, slider_pixmap, gc,
  3057.             (int) cur_win->pane_width-4, 0, 2, SP_HT);
  3058.  
  3059.         XSetTile(dpy, cur_win->scrollbargc, slider_pixmap);
  3060.         XSetFillStyle(dpy, cur_win->scrollbargc, FillTiled);
  3061.         XSetTSOrigin(dpy, cur_win->scrollbargc, 2, 0);
  3062.  
  3063.         cur_win->slider_pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy),
  3064.             cur_win->pane_width-2, SP_HT, (unsigned int)screen_depth);
  3065.         XCopyArea(dpy, slider_pixmap, cur_win->slider_pixmap, gc,
  3066.                   0, 0, cur_win->pane_width-2, SP_HT, 0, 0);
  3067.  
  3068.         /* Draw top bevel */
  3069.         XSetForeground(dpy, gc, fg_light);
  3070.         XDrawLine(dpy, cur_win->slider_pixmap, gc,
  3071.                   0, 0, (int)cur_win->pane_width-3, 0);
  3072.         XDrawLine(dpy, cur_win->slider_pixmap, gc,
  3073.                   0, 1, (int)cur_win->pane_width-4, 1);
  3074.  
  3075.         /* Draw bottom bevel */
  3076.         XSetForeground(dpy, gc, fg_dark);
  3077.         XDrawLine(dpy, cur_win->slider_pixmap, gc,
  3078.                   2, SP_HT-2, (int)cur_win->pane_width-3, SP_HT-2);
  3079.         XDrawLine(dpy, cur_win->slider_pixmap, gc,
  3080.                   1, SP_HT-1, (int)cur_win->pane_width-3, SP_HT-1);
  3081.  
  3082.         XFreeGC(dpy, gc);
  3083.     }
  3084.     }
  3085. #endif /* OPT_KEV_SCROLLBARS */
  3086.  
  3087.     XtAppAddActions(cur_win->app_context, new_actions, XtNumber(new_actions));
  3088.     cur_win->my_scrollbars_trans = XtParseTranslationTable(scrollbars_translations);
  3089.  
  3090. #if MOTIF_WIDGETS
  3091.     cur_win->pane = XtVaCreateManagedWidget(
  3092.         "scrollPane",
  3093.         xmPanedWindowWidgetClass,
  3094.         cur_win->form_widget,
  3095.         XtNwidth,            cur_win->pane_width,
  3096.         XmNbottomAttachment,    XmATTACH_FORM,
  3097. #if OPT_MENUS
  3098.         XmNtopAttachment,        XmATTACH_WIDGET,
  3099.         XmNtopWidget,        menub,
  3100. #else
  3101.         XmNtopAttachment,        XmATTACH_FORM,
  3102. #endif
  3103.         XmNleftAttachment,        XmATTACH_WIDGET,
  3104.         XmNleftWidget,        cur_win->screen,
  3105.         XmNrightAttachment,        XmATTACH_FORM,
  3106.         XmNspacing,            cur_win->char_height,
  3107.         XmNsashIndent,        2,
  3108.         XmNsashWidth,        cur_win->pane_width - 4,
  3109.         XmNmarginHeight,        0,
  3110.         XmNmarginWidth,        0,
  3111.         XmNseparatorOn,        FALSE,
  3112.         NULL);
  3113. #else
  3114. #if OL_WIDGETS
  3115.     cur_win->pane = XtVaCreateManagedWidget(
  3116.         "scrollPane",
  3117.         bulletinBoardWidgetClass,
  3118.         cur_win->form_widget,
  3119.         XtNwidth,            cur_win->pane_width,
  3120.         XtNheight,            x_height(cur_win),
  3121.         XtNxRefWidget,        cur_win->screen,
  3122.         XtNyAttachBottom,        TRUE,
  3123.         XtNyVaryOffset,        FALSE,
  3124.         XtNxAddWidth,        TRUE,
  3125.         XtNyAddHeight,        TRUE,
  3126.         XtNlayout,            OL_IGNORE,
  3127.         NULL);
  3128. #else
  3129. #if OPT_XAW_SCROLLBARS
  3130.     cur_win->my_resizeGrip_trans = XtParseTranslationTable(resizeGrip_translations);
  3131.     cur_win->pane = XtVaCreateManagedWidget(
  3132.         "scrollPane",
  3133.         formWidgetClass,
  3134.         cur_win->form_widget,
  3135.         XtNwidth,            cur_win->pane_width + 2,
  3136.         XtNheight,            x_height(cur_win)
  3137.                         - cur_win->char_height,
  3138.         XtNx,            cur_win->scrollbar_on_left
  3139.                         ? 0
  3140.                         : x_width(cur_win),
  3141.         XtNy,            0,
  3142.         XtNborderWidth,        0,
  3143.         XtNbackground,        cur_win->modeline_bg,
  3144.         XtNfromHoriz,        cur_win->scrollbar_on_left
  3145.                         ? NULL
  3146.                         : cur_win->screen,
  3147.         XtNhorizDistance,        0,
  3148.         NULL);
  3149.     if (cur_win->scrollbar_on_left)
  3150.     XtVaSetValues(cur_win->screen,
  3151.         XtNfromHoriz,        cur_win->pane,
  3152.         NULL);
  3153. #else
  3154. #if OPT_KEV_SCROLLBARS
  3155.     cur_win->my_resizeGrip_trans = XtParseTranslationTable(resizeGrip_translations);
  3156.     cur_win->pane = XtVaCreateManagedWidget(
  3157.         "scrollPane",
  3158.         bbWidgetClass,
  3159.         cur_win->form_widget,
  3160.         XtNwidth,            cur_win->pane_width + 2,
  3161.         XtNheight,            x_height(cur_win)
  3162.                         - cur_win->char_height,
  3163.         XtNx,            cur_win->scrollbar_on_left
  3164.                         ? 0
  3165.                         : x_width(cur_win),
  3166.         XtNy,            0,
  3167.         XtNborderWidth,        0,
  3168.         XtNbackground,        cur_win->modeline_bg,
  3169.         NULL);
  3170. #endif    /* OPT_KEV_SCROLLBARS */
  3171. #endif    /* OPT_XAW_SCROLLBARS */
  3172. #endif    /* OL_WIDGETS */
  3173. #endif    /* MOTIF_WIDGETS */
  3174.  
  3175. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  3176.     curs_sb_v_double_arrow = XCreateFontCursor(dpy, XC_sb_v_double_arrow);
  3177.     curs_sb_up_arrow       = XCreateFontCursor(dpy, XC_sb_up_arrow);
  3178.     curs_sb_down_arrow     = XCreateFontCursor(dpy, XC_sb_down_arrow);
  3179.     curs_sb_left_arrow     = XCreateFontCursor(dpy, XC_sb_left_arrow);
  3180.     curs_sb_right_arrow    = XCreateFontCursor(dpy, XC_sb_right_arrow);
  3181.     curs_double_arrow      = XCreateFontCursor(dpy, XC_double_arrow);
  3182. #endif
  3183.  
  3184. #if OPT_KEV_SCROLLBARS
  3185.     cur_win->nscrollbars = 0;
  3186. #else
  3187.     cur_win->nscrollbars = -1;
  3188. #endif
  3189.  
  3190.     /*
  3191.      * Move scrollbar to the left if requested via the resources.
  3192.      * Note that this is handled elsewhere for NO_WIDGETS.
  3193.      */
  3194.     if (cur_win->scrollbar_on_left) {
  3195. #if MOTIF_WIDGETS
  3196.     XtVaSetValues(cur_win->pane,
  3197.         XmNleftAttachment,    XmATTACH_FORM,
  3198.         XmNrightAttachment, XmATTACH_WIDGET,
  3199.         XmNrightWidget,    cur_win->screen,
  3200.         NULL);
  3201.     XtVaSetValues(cur_win->screen,
  3202.         XmNleftAttachment,    XmATTACH_NONE,
  3203.         XmNrightAttachment,    XmATTACH_FORM,
  3204.         NULL);
  3205. #else    /* !MOTIF_WIDGETS */
  3206. # if OL_WIDGETS
  3207.     XtVaSetValues(cur_win->pane,
  3208.         XtNxRefWidget,    cur_win->form_widget,
  3209.         NULL);
  3210.     XtVaSetValues(cur_win->screen,
  3211.         XtNxRefWidget,    cur_win->pane,
  3212.         NULL);
  3213. # else
  3214.     /* EMPTY */;
  3215. # endif    /* OL_WIDGETS */
  3216. #endif    /* !MOTIF_WIDGETS */
  3217.     }
  3218.  
  3219.     XtAddEventHandler(
  3220.         cur_win->screen,
  3221.         KeyPressMask,
  3222.         FALSE,
  3223.         x_key_press,
  3224.         (XtPointer)0);
  3225.  
  3226.     XtAddEventHandler(
  3227.         cur_win->screen,
  3228.         (EventMask) (ButtonPressMask | ButtonReleaseMask
  3229.                | (cur_win->focus_follows_mouse ? PointerMotionMask
  3230.                                : (Button1MotionMask | Button3MotionMask))
  3231.                | ExposureMask | VisibilityChangeMask),
  3232.         TRUE,
  3233.         x_process_event,
  3234.         (XtPointer)0);
  3235.  
  3236.     XtAddEventHandler(
  3237.         cur_win->top_widget,
  3238.         StructureNotifyMask,
  3239.         FALSE,
  3240.         x_configure_window,
  3241.         (XtPointer)0);
  3242.  
  3243.     XtAddEventHandler(
  3244.         cur_win->top_widget,
  3245.         EnterWindowMask | LeaveWindowMask | FocusChangeMask,
  3246.         FALSE,
  3247.         x_change_focus,
  3248.         (XtPointer)0);
  3249.  
  3250.     cur_win->base_width = -1;    /* force base width to be set when configured */
  3251.     XtRealizeWidget(cur_win->top_widget);
  3252.  
  3253.     cur_win->win = XtWindow(cur_win->screen);
  3254.  
  3255.     /* We wish to participate in the "delete window" protocol */
  3256.     atom_WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
  3257.     atom_WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  3258.     {
  3259.     Atom atoms[2];
  3260.     i = 0;
  3261.     atoms[i++] = atom_WM_DELETE_WINDOW;
  3262.     XSetWMProtocols(dpy,
  3263.         XtWindow(cur_win->top_widget),
  3264.         atoms,
  3265.         i);
  3266.     }
  3267.     XtAddEventHandler(
  3268.         cur_win->top_widget,
  3269.         NoEventMask,
  3270.         TRUE,
  3271.         x_wm_delwin,
  3272.         (XtPointer)0);
  3273.  
  3274.     /* Atoms needed for selections */
  3275.     atom_TARGETS    = XInternAtom(dpy, "TARGETS",   False);
  3276.     atom_MULTIPLE    = XInternAtom(dpy, "MULTIPLE",  False);
  3277.     atom_TIMESTAMP    = XInternAtom(dpy, "TIMESTAMP", False);
  3278.     atom_TEXT        = XInternAtom(dpy, "TEXT",      False);
  3279.     atom_CLIPBOARD    = XInternAtom(dpy, "CLIPBOARD", False);
  3280.  
  3281.     set_pointer(XtWindow(cur_win->screen), cur_win->normal_pointer);
  3282.  
  3283. }
  3284.  
  3285. #if 0
  3286. static void
  3287. check_visuals(void)
  3288. {
  3289.     static char *classes[] = { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor" };
  3290.     XVisualInfo *visuals, visual_template;
  3291.     int nvisuals;
  3292.     visuals = XGetVisualInfo(dpy, VisualNoMask, &visual_template, &nvisuals);
  3293.     if (visuals != NULL) {
  3294.     int i;
  3295.     for (i=0; i<nvisuals; i++) {
  3296.         printf("Class: %s, Depth: %d\n",
  3297.                classes[visuals[i].class], visuals[i].depth);
  3298.     }
  3299.     XFree(visuals);
  3300.     }
  3301. }
  3302. #endif
  3303.  
  3304.  
  3305. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  3306. static Boolean
  3307. too_light_or_too_dark(
  3308.     Pixel pixel)
  3309. {
  3310.     XColor color;
  3311.     Colormap colormap;
  3312.  
  3313.     XtVaGetValues(cur_win->screen,
  3314.     XtNcolormap,    &colormap,
  3315.     NULL);
  3316.  
  3317.     color.pixel = pixel;
  3318.     XQueryColor(dpy, colormap, &color);
  3319.  
  3320.     return (color.red > 0xfff0 && color.green > 0xfff0 && color.blue > 0xfff0)
  3321.         || (color.red < 0x0020 && color.green < 0x0020 && color.blue < 0x0020);
  3322. }
  3323. #endif
  3324.  
  3325. #if OPT_KEV_SCROLLBARS
  3326. static Boolean
  3327. alloc_shadows(
  3328.     Pixel pixel,
  3329.     Pixel *light,
  3330.     Pixel *dark)
  3331. {
  3332.     XColor color;
  3333.     Colormap colormap;
  3334.     unsigned long lred, lgreen, lblue, dred, dgreen, dblue;
  3335.  
  3336.     XtVaGetValues(cur_win->screen,
  3337.     XtNcolormap,    &colormap,
  3338.     NULL);
  3339.  
  3340.     color.pixel = pixel;
  3341.     XQueryColor(dpy, colormap, &color);
  3342.  
  3343.     if ( (color.red > 0xfff0 && color.green > 0xfff0 && color.blue > 0xfff0)
  3344.       || (color.red < 0x0020 && color.green < 0x0020 && color.blue < 0x0020))
  3345.     return False;            /* It'll look awful! */
  3346.  
  3347. #define MAXINTENS ((unsigned long)65535L)
  3348. #define PlusFortyPercent(v) ((7 * (long) (v)) / 5)
  3349.     lred   = PlusFortyPercent(color.red);
  3350.     lred   = min(lred, MAXINTENS);
  3351.     lred   = max(lred, (color.red + MAXINTENS)/2);
  3352.  
  3353.     lgreen = PlusFortyPercent(color.green);
  3354.     lgreen = min(lgreen, MAXINTENS);
  3355.     lgreen = max(lgreen, (color.green + MAXINTENS)/2);
  3356.  
  3357.     lblue  = PlusFortyPercent(color.blue);
  3358.     lblue  = min(lblue, MAXINTENS);
  3359.     lblue  = max(lblue, (color.blue + MAXINTENS)/2);
  3360.  
  3361. #define MinusFortyPercent(v) ((3 * (long) (v)) / 5)
  3362.  
  3363.     dred   = MinusFortyPercent(color.red);
  3364.     dgreen = MinusFortyPercent(color.green);
  3365.     dblue  = MinusFortyPercent(color.blue);
  3366.  
  3367.     color.red = (unsigned short) lred;
  3368.     color.green = (unsigned short) lgreen;
  3369.     color.blue = (unsigned short) lblue;
  3370.  
  3371.     if (!XAllocColor(dpy, colormap, &color))
  3372.     return False;
  3373.  
  3374.     *light = color.pixel;
  3375.  
  3376.     color.red = (unsigned short) dred;
  3377.     color.green = (unsigned short) dgreen;
  3378.     color.blue = (unsigned short) dblue;
  3379.  
  3380.     if (!XAllocColor(dpy, colormap, &color))
  3381.     return False;
  3382.  
  3383.     *dark = color.pixel;
  3384.  
  3385.     return True;
  3386. }
  3387. #endif
  3388.  
  3389. char *
  3390. x_current_fontname(void)
  3391. {
  3392.     return cur_win->fontname;
  3393. }
  3394.  
  3395. static char *
  3396. x_get_font_atom_property(
  3397.     XFontStruct *pf,
  3398.     Atom atom)
  3399. {
  3400.     XFontProp *pp;
  3401.     int i;
  3402.     char *retval = NULL;
  3403.  
  3404.     for (i=0, pp = pf->properties; i < pf->n_properties; i++, pp++)
  3405.     if (pp->name == atom) {
  3406.         retval = XGetAtomName(dpy, pp->card32);
  3407.         break;
  3408.     }
  3409.     return retval;
  3410. }
  3411.  
  3412. static XFontStruct *
  3413. query_font(
  3414.     TextWindow tw,
  3415.     const char *fname)
  3416. {
  3417.     XFontStruct *pf;
  3418.  
  3419.     if ((pf = XLoadQueryFont(dpy, fname)) != 0) {
  3420.     char *fullname = NULL;
  3421.  
  3422.     if (pf->max_bounds.width != pf->min_bounds.width) {
  3423.         (void)fprintf(stderr,
  3424.               "proportional font, things will be miserable\n");
  3425.     }
  3426.  
  3427.     /*
  3428.      * Free resources assoicated with any presently loaded fonts.
  3429.      */
  3430.     if (tw->pfont)
  3431.         XFreeFont(dpy, tw->pfont);
  3432.     if (tw->pfont_bold) {
  3433.         XFreeFont(dpy, tw->pfont_bold);
  3434.         tw->pfont_bold = NULL;
  3435.     }
  3436.     if (tw->pfont_ital) {
  3437.         XFreeFont(dpy, tw->pfont_ital);
  3438.         tw->pfont_ital = NULL;
  3439.     }
  3440.     if (tw->pfont_boldital) {
  3441.         XFreeFont(dpy, tw->pfont_boldital);
  3442.         tw->pfont_boldital = NULL;
  3443.     }
  3444.     tw->fsrch_flags = 0;
  3445.  
  3446.     tw->pfont = pf;
  3447.     tw->char_width  = pf->max_bounds.width;
  3448.     tw->char_height = pf->ascent + pf->descent;
  3449.     tw->char_ascent = pf->ascent;
  3450.     tw->char_descent = pf->descent;
  3451.     tw->left_ink    = (pf->min_bounds.lbearing < 0);
  3452.     tw->right_ink    = (pf->max_bounds.rbearing > tw->char_width);
  3453.  
  3454.     FreeIfNeeded(cur_win->fontname);
  3455.     if ((fullname = x_get_font_atom_property(pf, atom_FONT)) != NULL
  3456.      && fullname[0] == '-') {
  3457.         /*
  3458.          * Good. Not much work to do; the name was available via the FONT
  3459.          * property.
  3460.          */
  3461.         tw->fontname = strmalloc(fullname);
  3462.         XFree(fullname);
  3463.     }
  3464.     else {
  3465.         /*
  3466.          * Woops, fully qualified name not available from the FONT property.
  3467.          * Attempt to get the full name piece by piece.  Ugh!
  3468.          */
  3469.         char str[1024], *s;
  3470.         if (fullname != NULL)
  3471.         XFree(fullname);
  3472.  
  3473.         s = str;
  3474.         *s++ = '-';
  3475.  
  3476. #define GET_ATOM_OR_STAR(atom)                    \
  3477.     do {                            \
  3478.     char *as;                        \
  3479.     if ((as = x_get_font_atom_property(pf, (atom))) != NULL) { \
  3480.         char *asp = as;                    \
  3481.         while ((*s++ = *asp++))                \
  3482.         ;                        \
  3483.         *(s-1) = '-';                    \
  3484.         XFree(as);                        \
  3485.     }                            \
  3486.     else {                            \
  3487.         *s++ = '*';                        \
  3488.         *s++ = '-';                        \
  3489.     }                            \
  3490.     } one_time
  3491. #define GET_ATOM_OR_GIVEUP(atom)                \
  3492.     do {                            \
  3493.     char *as;                        \
  3494.     if ((as = x_get_font_atom_property(pf, (atom))) != NULL) { \
  3495.         char *asp = as;                    \
  3496.         while ((*s++ = *asp++))                \
  3497.         ;                        \
  3498.         *(s-1) = '-';                    \
  3499.         XFree(as);                        \
  3500.     }                            \
  3501.     else                            \
  3502.         goto piecemeal_done;                \
  3503.     } one_time
  3504. #define GET_LONG_OR_GIVEUP(atom)                \
  3505.     do {                            \
  3506.     unsigned long val;                    \
  3507.     if (XGetFontProperty(pf, (atom), &val)) {        \
  3508.         sprintf(s,"%ld",val);                \
  3509.         while (*s++ != '\0')                \
  3510.         ;                        \
  3511.         *(s-1) = '-';                    \
  3512.     }                            \
  3513.     else                            \
  3514.         goto piecemeal_done;                \
  3515.     } one_time
  3516.  
  3517.         GET_ATOM_OR_STAR(atom_FOUNDRY);
  3518.         GET_ATOM_OR_GIVEUP(XA_FAMILY_NAME);
  3519.         GET_ATOM_OR_GIVEUP(atom_WEIGHT_NAME);
  3520.         GET_ATOM_OR_GIVEUP(atom_SLANT);
  3521.         GET_ATOM_OR_GIVEUP(atom_SETWIDTH_NAME);
  3522.         *s++ = '*';                /* ADD_STYLE_NAME */
  3523.         *s++ = '-';
  3524.         GET_LONG_OR_GIVEUP(atom_PIXEL_SIZE);
  3525.         GET_LONG_OR_GIVEUP(XA_POINT_SIZE);
  3526.         GET_LONG_OR_GIVEUP(atom_RESOLUTION_X);
  3527.         GET_LONG_OR_GIVEUP(atom_RESOLUTION_Y);
  3528.         GET_ATOM_OR_GIVEUP(atom_SPACING);
  3529.         GET_LONG_OR_GIVEUP(atom_AVERAGE_WIDTH);
  3530.         GET_ATOM_OR_STAR(atom_CHARSET_REGISTRY);
  3531.         GET_ATOM_OR_STAR(atom_CHARSET_ENCODING);
  3532.         *(s-1) = '\0';
  3533.  
  3534. #undef GET_ATOM_OR_STAR
  3535. #undef GET_ATOM_OR_GIVEUP
  3536. #undef GET_LONG_OR_GIVEUP
  3537.  
  3538.         fname = str;
  3539. piecemeal_done:
  3540.         /*
  3541.          * We will either use the name which was built up piecemeal or
  3542.          * the name which was originally passed to us to assign to
  3543.          * the fontname field.  We prefer the fully qualified name
  3544.          * so that we can later search for bold and italic fonts.
  3545.          */
  3546.         tw->fontname = strmalloc(fname);
  3547.     }
  3548.     }
  3549.     return pf;
  3550. }
  3551.  
  3552. static XFontStruct *
  3553. alternate_font(
  3554.     char *weight,
  3555.     char *slant)
  3556. {
  3557.     char *newname, *np, *op;
  3558.     int cnt;
  3559.     XFontStruct *fsp = NULL;
  3560.     if (cur_win->fontname == NULL
  3561.      || cur_win->fontname[0] != '-'
  3562.      || (newname = castalloc(char, (SIZE_T)strlen(cur_win->fontname)+32)) == NULL)
  3563.     return NULL;
  3564.  
  3565.     /* copy initial two fields */
  3566.     for (cnt=3, np=newname, op=cur_win->fontname; *op && cnt > 0; ) {
  3567.     if (*op == '-')
  3568.         cnt--;
  3569.     *np++ = *op++;
  3570.     }
  3571.     if (!*op)
  3572.     goto done;
  3573.  
  3574.     /* substitute new weight and slant as appropriate */
  3575. #define SUBST_FIELD(field)                \
  3576.     do {                        \
  3577.     if ((field) != NULL) {                \
  3578.         char *fp = (field);                \
  3579.         if (nocase_eq(*fp, *op))            \
  3580.         goto done;                \
  3581.         while ((*np++ = *fp++))            \
  3582.         ;                    \
  3583.         *(np-1) = '-';                \
  3584.         while (*op && *op++ != '-')            \
  3585.         ;                    \
  3586.     }                        \
  3587.     else {                        \
  3588.         while (*op && (*np++ = *op++) != '-')    \
  3589.         ;                    \
  3590.     }                        \
  3591.     if (!*op)                    \
  3592.         goto done;                    \
  3593.     } one_time
  3594.  
  3595.     SUBST_FIELD(weight);
  3596.     SUBST_FIELD(slant);
  3597. #undef SUBST_FIELD
  3598.  
  3599.     /* copy rest of name */
  3600.     while ((*np++ = *op++))
  3601.     ;
  3602.     if ((fsp = XLoadQueryFont(dpy, newname)) != NULL) {
  3603.     cur_win->left_ink = cur_win->left_ink || (fsp->min_bounds.lbearing < 0);
  3604.     cur_win->right_ink = cur_win->right_ink
  3605.             || (fsp->max_bounds.rbearing > cur_win->char_width);
  3606.     }
  3607.  
  3608. done:
  3609.     free(newname);
  3610.     return fsp;
  3611.  
  3612. }
  3613.  
  3614. #if OPT_MENUS
  3615. int
  3616. x_menu_height(void)
  3617. {
  3618.     return cur_win->menu_height;
  3619. }
  3620. #endif /* OPT_MENUS */
  3621.  
  3622. #if OPT_MENUS_COLORED
  3623. int
  3624. x_menu_foreground(void)
  3625. {
  3626.     return cur_win->menubar_fg;
  3627. }
  3628. int
  3629. x_menu_background(void)
  3630. {
  3631.     return cur_win->menubar_bg;
  3632. }
  3633. #endif /* OPT_MENUS_COLORED */
  3634.  
  3635. int
  3636. x_setfont(
  3637.     const char  *fname)
  3638. {
  3639.     XFontStruct *pfont;
  3640.     Dimension   oldw;
  3641.     Dimension   oldh;
  3642.  
  3643.     if (cur_win) {
  3644.     oldw = x_width(cur_win);
  3645.     oldh = x_height(cur_win);
  3646.     if ((pfont = query_font(cur_win, fname)) != 0) {
  3647.         int i;
  3648.  
  3649.         XSetFont(dpy, cur_win->textgc, pfont->fid);
  3650.         XSetFont(dpy, cur_win->reversegc, pfont->fid);
  3651.         XSetFont(dpy, cur_win->selgc, pfont->fid);
  3652.         XSetFont(dpy, cur_win->revselgc, pfont->fid);
  3653.         XSetFont(dpy, cur_win->cursgc, pfont->fid);
  3654.         XSetFont(dpy, cur_win->revcursgc, pfont->fid);
  3655.         XSetFont(dpy, cur_win->modeline_focus_gc, pfont->fid);
  3656.         XSetFont(dpy, cur_win->modeline_gc, pfont->fid);
  3657.         if (cur_win->textgc != cur_win->revselgc) {
  3658.         XSetFont(dpy, cur_win->selgc, pfont->fid);
  3659.         XSetFont(dpy, cur_win->revselgc, pfont->fid);
  3660.         }
  3661.         for (i = 0; i < NCOLORS; i++) {
  3662.         if (cur_win->colors_fgc[i] != cur_win->textgc) {
  3663.             XSetFont(dpy, cur_win->colors_fgc[i], pfont->fid);
  3664.             XSetFont(dpy, cur_win->colors_bgc[i], pfont->fid);
  3665.         }
  3666.         }
  3667.  
  3668.         /* if size changed, resize it, otherwise refresh */
  3669.         if (oldw != x_width(cur_win) || oldh != x_height(cur_win)) {
  3670.         XtVaSetValues(cur_win->top_widget,
  3671.             XtNminHeight,    cur_win->base_height
  3672.                         + MINROWS*cur_win->char_height,
  3673.             XtNminWidth,    cur_win->base_width
  3674.                         + MINCOLS*cur_win->char_width,
  3675.             XtNheightInc,    cur_win->char_height,
  3676.             XtNwidthInc,    cur_win->char_width,
  3677.             NULL);
  3678.         update_scrollbar_sizes();
  3679.         XClearWindow(dpy, cur_win->win);
  3680.         x_touch(cur_win, 0, 0, cur_win->cols, cur_win->rows);
  3681.         XResizeWindow(dpy, XtWindow(cur_win->top_widget),
  3682.                   x_width(cur_win) + cur_win->base_width,
  3683.                   x_height(cur_win) + cur_win->base_height);
  3684.  
  3685.         } else {
  3686.         XClearWindow(dpy, cur_win->win);
  3687.         x_touch(cur_win, 0, 0, cur_win->cols, cur_win->rows);
  3688.         x_flush();
  3689.         }
  3690.  
  3691.         return 1;
  3692.     }
  3693.     return 0;
  3694.     }
  3695.     return 1;
  3696. }
  3697.  
  3698. static void
  3699. x_open(void)
  3700. {
  3701.     kqinit(cur_win);
  3702.     cur_win->scrollbars = NULL;
  3703.     cur_win->maxscrollbars = 0;
  3704. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  3705.     cur_win->scrollinfo = NULL;
  3706.     cur_win->grips = NULL;
  3707. #endif
  3708. #if OL_WIDGETS
  3709.     cur_win->sliders = NULL;
  3710. #endif
  3711.  
  3712.     /* main code assumes that it can access a cell at nrow x ncol */
  3713.     term.t_mcol = term.t_ncol = cur_win->cols;
  3714.     term.t_mrow = term.t_nrow = cur_win->rows;
  3715.  
  3716.     if (check_scrollbar_allocs() != TRUE)
  3717.     ExitProgram(BADEXIT);
  3718. }
  3719.  
  3720. static void
  3721. x_close(void)
  3722. {
  3723.     /* FIXME: Free pixmaps and GCs !!! */
  3724.  
  3725.     XtDestroyWidget(cur_win->top_widget);
  3726. }
  3727.  
  3728. static void
  3729. x_kopen(void)
  3730. {
  3731. }
  3732.  
  3733. static void
  3734. x_kclose(void)
  3735. {
  3736. }
  3737.  
  3738. static void
  3739. x_touch(
  3740.     TextWindow tw,
  3741.     int     sc,
  3742.     int     sr,
  3743.     UINT ec,
  3744.     UINT er)
  3745. {
  3746.     register UINT r;
  3747.     register UINT c;
  3748.  
  3749.     if (er > tw->rows)
  3750.     er = tw->rows;
  3751.     if (ec > tw->cols)
  3752.     ec = tw->cols;
  3753.  
  3754.     for (r = sr; r < er; r++) {
  3755.     MARK_LINE_DIRTY(r);
  3756.     for (c = sc; c < ec; c++)
  3757.         if (CELL_TEXT(r,c) != ' ' || CELL_ATTR(r,c))
  3758.         MARK_CELL_DIRTY(r,c);
  3759.     }
  3760. }
  3761.  
  3762.  
  3763. static void
  3764. wait_for_scroll(
  3765.     TextWindow  tw)
  3766. {
  3767.     XEvent      ev;
  3768.     int         sc,
  3769.                 sr;
  3770.     unsigned    ec,
  3771.                 er;
  3772.     XGraphicsExposeEvent *gev;
  3773.  
  3774.     for_ever {        /* loop looking for a gfx expose or no expose */
  3775.     if (XCheckTypedEvent(dpy, NoExpose, &ev))
  3776.         return;
  3777.     if (XCheckTypedEvent(dpy, GraphicsExpose, &ev)) {
  3778.         gev = (XGraphicsExposeEvent *) & ev;
  3779.         sc = gev->x / tw->char_width;
  3780.         sr = gev->y / tw->char_height;
  3781.         ec = CEIL(gev->x + gev->width,  tw->char_width);
  3782.         er = CEIL(gev->y + gev->height, tw->char_height);
  3783.         x_touch(tw, sc, sr, ec, er);
  3784.         if (gev->count == 0)
  3785.         return;
  3786.     }
  3787.     XSync(dpy, False);
  3788.     }
  3789. }
  3790.  
  3791.  
  3792. static void
  3793. x_scroll(
  3794.     int from,
  3795.     int to,
  3796.     int count)
  3797. {
  3798.     if (cur_win->visibility == VisibilityFullyObscured)
  3799.     return;            /* Why bother? */
  3800.  
  3801.     if (from == to)
  3802.     return;            /* shouldn't happen */
  3803.  
  3804.     XCopyArea(dpy, cur_win->win, cur_win->win, cur_win->textgc,
  3805.           x_pos(cur_win, 0), y_pos(cur_win, from),
  3806.           x_width(cur_win), (unsigned)(count * cur_win->char_height),
  3807.           x_pos(cur_win, 0), y_pos(cur_win, to));
  3808.     if (from < to)
  3809.     XClearArea(dpy, cur_win->win,
  3810.         x_pos(cur_win, 0), y_pos(cur_win,from),
  3811.         x_width(cur_win), (unsigned)((to-from) * cur_win->char_height),
  3812.         FALSE);
  3813.     else
  3814.     XClearArea(dpy, cur_win->win,
  3815.         x_pos(cur_win, 0), y_pos(cur_win,to+count),
  3816.         x_width(cur_win), (unsigned)((from-to) * cur_win->char_height),
  3817.         FALSE);
  3818.     if (cur_win->visibility == VisibilityPartiallyObscured) {
  3819.     XFlush(dpy);
  3820.     wait_for_scroll(cur_win);
  3821.     }
  3822. }
  3823.  
  3824. /*
  3825.  * The X protocol request for clearing a rectangle (PolyFillRectangle) takes
  3826.  * 20 bytes.  It will therefore be more expensive to switch from drawing text
  3827.  * to filling a rectangle unless the area to be cleared is bigger than 20
  3828.  * spaces.  Actually it is worse than this if we are going to switch
  3829.  * immediately to drawing text again since we incur a certain overhead
  3830.  * (16 bytes) for each string to be displayed.  This is how the value of
  3831.  * CLEAR_THRESH was computed (36 = 20+16).
  3832.  *
  3833.  * Kev's opinion:  If XDrawImageString is to be called, it is hardly ever
  3834.  * worth it to call XFillRectangle.  The only time where it will be a big
  3835.  * win is when the entire area to update is all spaces (in which case
  3836.  * XDrawImageString will not be called).  The following code would be much
  3837.  * cleaner, simpler, and easier to maintain if we were to just call
  3838.  * XDrawImageString where there are non-spaces to be written and
  3839.  * XFillRectangle when the entire region is to be cleared.
  3840.  */
  3841. #define    CLEAR_THRESH    36
  3842.  
  3843. static void
  3844. flush_line(
  3845.     char  *text,
  3846.     int       len,
  3847.     unsigned int attr,
  3848.     int       sr,
  3849.     int       sc)
  3850. {
  3851.     GC    fore_gc;
  3852.     GC    back_gc;
  3853.     int    fore_yy = text_y_pos(cur_win, sr);
  3854.     int    back_yy = y_pos(cur_win, sr);
  3855.     char *p;
  3856.     int   cc, tlen, i, startcol;
  3857.     int   fontchanged = FALSE;
  3858.  
  3859.     if (attr == 0) {    /* This is the most common case, so we list it first */
  3860.     fore_gc = cur_win->textgc;
  3861.     back_gc = cur_win->reversegc;
  3862.     }
  3863.     else if ((attr & VACURS) && cur_win->is_color_cursor) {
  3864.     fore_gc = cur_win->cursgc;
  3865.     back_gc = cur_win->revcursgc;
  3866.     attr &= ~VACURS;
  3867.     }
  3868.     else if (attr & VASEL) {
  3869.     fore_gc = cur_win->selgc;
  3870.     back_gc = cur_win->revselgc;
  3871.     }
  3872.     else if (attr & VAMLFOC)
  3873.     fore_gc = back_gc = cur_win->modeline_focus_gc;
  3874.     else if (attr & VAML)
  3875.     fore_gc = back_gc = cur_win->modeline_gc;
  3876.     else if (attr & (VACOLOR)) {
  3877.     fore_gc = cur_win->colors_fgc[VCOLORNUM(attr)];
  3878.     back_gc = cur_win->colors_bgc[VCOLORNUM(attr)];
  3879.     }
  3880.     else {
  3881.     fore_gc = cur_win->textgc;
  3882.     back_gc = cur_win->reversegc;
  3883.     }
  3884.  
  3885.     if (attr & (VAREV | VACURS)) {
  3886.     GC tmp_gc = fore_gc;
  3887.     fore_gc = back_gc;
  3888.     back_gc = tmp_gc;
  3889.     }
  3890.  
  3891.     if (attr & (VABOLD | VAITAL)) {
  3892.     XFontStruct *fsp = NULL;
  3893.     if ((attr & (VABOLD | VAITAL)) == (VABOLD | VAITAL)) {
  3894.         if (!(cur_win->fsrch_flags & FSRCH_BOLDITAL)) {
  3895.         if ((fsp = alternate_font("bold","i")) != NULL
  3896.              || (fsp = alternate_font("bold","o")) != NULL)
  3897.             cur_win->pfont_boldital = fsp;
  3898.         cur_win->fsrch_flags |= FSRCH_BOLDITAL;
  3899.         }
  3900.         if (cur_win->pfont_boldital != NULL) {
  3901.         XSetFont(dpy, fore_gc, cur_win->pfont_boldital->fid);
  3902.         fontchanged = TRUE;
  3903.         attr &= ~(VABOLD | VAITAL);    /* don't use fallback */
  3904.         }
  3905.         else
  3906.         goto tryital;
  3907.     }
  3908.     else if (attr & VAITAL) {
  3909. tryital:
  3910.         if (!(cur_win->fsrch_flags & FSRCH_ITAL)) {
  3911.         if ((fsp = alternate_font((char *)0,"i")) != NULL
  3912.              || (fsp = alternate_font((char *)0,"o")) != NULL)
  3913.             cur_win->pfont_ital = fsp;
  3914.         cur_win->fsrch_flags |= FSRCH_ITAL;
  3915.         }
  3916.         if (cur_win->pfont_ital != NULL) {
  3917.         XSetFont(dpy, fore_gc, cur_win->pfont_ital->fid);
  3918.         fontchanged = TRUE;
  3919.         attr &= ~VAITAL;        /* don't use fallback */
  3920.         }
  3921.         else if (attr & VABOLD)
  3922.         goto trybold;
  3923.     }
  3924.     else if (attr & VABOLD) {
  3925. trybold:
  3926.         if (!(cur_win->fsrch_flags & FSRCH_BOLD)) {
  3927.         cur_win->pfont_bold = alternate_font("bold",NULL);
  3928.         cur_win->fsrch_flags |= FSRCH_BOLD;
  3929.         }
  3930.         if (cur_win->pfont_bold != NULL) {
  3931.         XSetFont(dpy, fore_gc, cur_win->pfont_bold->fid);
  3932.         fontchanged = TRUE;
  3933.         attr &= ~VABOLD;        /* don't use fallback */
  3934.         }
  3935.     }
  3936.     }
  3937.  
  3938.     /* break line into TextStrings and FillRects */
  3939.     p = (char *)text;
  3940.     cc = 0;
  3941.     tlen = 0;
  3942.     startcol = sc;
  3943.     for (i = 0; i < len; i++) {
  3944.     if (text[i] == ' ') {
  3945.         cc++;
  3946.         tlen++;
  3947.     } else {
  3948.         if (cc >= CLEAR_THRESH) {
  3949.         tlen -= cc;
  3950.         XDrawImageString(dpy, cur_win->win, fore_gc,
  3951.                  (int)x_pos(cur_win, sc), fore_yy,
  3952.                  p, tlen);
  3953.         if (attr & VABOLD)
  3954.             XDrawString(dpy, cur_win->win, fore_gc,
  3955.                 (int)x_pos(cur_win, sc)+1, fore_yy,
  3956.                  p, tlen);
  3957.         p += tlen + cc;
  3958.         sc += tlen;
  3959.         XFillRectangle(dpy, cur_win->win, back_gc,
  3960.                    x_pos(cur_win, sc), back_yy,
  3961.                    (unsigned)(cc * cur_win->char_width),
  3962.                    (unsigned)(cur_win->char_height));
  3963.         sc += cc;
  3964.         tlen = 1;    /* starting new run */
  3965.         } else
  3966.         tlen++;
  3967.         cc = 0;
  3968.     }
  3969.     }
  3970.     if (cc >= CLEAR_THRESH) {
  3971.     tlen -= cc;
  3972.     XDrawImageString(dpy, cur_win->win, fore_gc,
  3973.              x_pos(cur_win, sc), fore_yy,
  3974.              p, tlen);
  3975.     if (attr & VABOLD)
  3976.         XDrawString(dpy, cur_win->win, fore_gc,
  3977.             (int)x_pos(cur_win, sc)+1, fore_yy,
  3978.              p, tlen);
  3979.     sc += tlen;
  3980.     XFillRectangle(dpy, cur_win->win, back_gc,
  3981.                x_pos(cur_win, sc), back_yy,
  3982.                (unsigned)(cc * cur_win->char_width),
  3983.                (unsigned)(cur_win->char_height));
  3984.     } else if (tlen > 0) {
  3985.     XDrawImageString(dpy, cur_win->win, fore_gc,
  3986.              x_pos(cur_win, sc), fore_yy,
  3987.              p, tlen);
  3988.     if (attr & VABOLD)
  3989.         XDrawString(dpy, cur_win->win, fore_gc,
  3990.             (int)x_pos(cur_win, sc)+1, fore_yy,
  3991.              p, tlen);
  3992.     }
  3993.     if (attr & (VAUL | VAITAL)) {
  3994.     fore_yy += cur_win->char_descent - 1;
  3995.     XDrawLine(dpy, cur_win->win, fore_gc,
  3996.               x_pos(cur_win, startcol), fore_yy,
  3997.           x_pos(cur_win, startcol + len) - 1, fore_yy);
  3998.     }
  3999.  
  4000.     if (fontchanged)
  4001.     XSetFont(dpy, fore_gc, cur_win->pfont->fid);
  4002. }
  4003.  
  4004.  
  4005. /* See above comment regarding CLEAR_THRESH */
  4006. #define NONDIRTY_THRESH 16
  4007.  
  4008. /* make sure the screen looks like we want it to */
  4009. static void
  4010. x_flush(void)
  4011. {
  4012.     int r, c, sc, ec, cleanlen;
  4013.     VIDEO_ATTR attr;
  4014.  
  4015.     if (cur_win->visibility == VisibilityFullyObscured || !cur_win->exposed)
  4016.     return;        /* Why bother? */
  4017.  
  4018.     /*
  4019.      * Write out cursor _before_ rest of the screen in order to avoid
  4020.      * flickering / winking effect noticable on some display servers.  This
  4021.      * means that the old cursor position (if different from the current
  4022.      * one) will be cleared after the new cursor is displayed.
  4023.      */
  4024.  
  4025.     if (ttrow >=0 && ttrow < term.t_nrow && ttcol >= 0 && ttcol < term.t_ncol
  4026.      && !cur_win->wipe_permitted) {
  4027.     CLEAR_CELL_DIRTY(ttrow, ttcol);
  4028.     display_cursor((XtPointer) 0, (XtIntervalId *) 0);
  4029.     }
  4030.  
  4031.     /* sometimes we're the last to know about resizing...*/
  4032.     if (cur_win->rows > term.t_mrow)
  4033.     cur_win->rows = term.t_mrow;
  4034.  
  4035.     for (r = 0; r < cur_win->rows; r++) {
  4036.     if (!IS_DIRTY_LINE(r))
  4037.         continue;
  4038.     if (r !=  ttrow)
  4039.         CLEAR_LINE_DIRTY(r);
  4040.  
  4041.     /*
  4042.      * The following code will cause monospaced fonts with ink outside
  4043.      * the bounding box to be cleaned up.
  4044.      */
  4045.     if (cur_win->left_ink || cur_win->right_ink)
  4046.         for (c=0; c < term.t_ncol; ) {
  4047.         while (c < term.t_ncol && !IS_DIRTY(r,c))
  4048.             c++;
  4049.         if (c >= term.t_ncol)
  4050.             break;
  4051.         if (cur_win->left_ink && c > 0)
  4052.             MARK_CELL_DIRTY(r,c-1);
  4053.         while (c < term.t_ncol && IS_DIRTY(r,c))
  4054.             c++;
  4055.         if (cur_win->right_ink && c < term.t_ncol) {
  4056.             MARK_CELL_DIRTY(r,c);
  4057.             c++;
  4058.         }
  4059.         }
  4060.  
  4061.     c = 0;
  4062.     while (c < term.t_ncol) {
  4063.         /* Find the beginning of the next dirty sequence */
  4064.         while (c < term.t_ncol && !IS_DIRTY(r,c))
  4065.         c++;
  4066.         if (c >= term.t_ncol)
  4067.         break;
  4068.         if (r == ttrow && c == ttcol && !cur_win->wipe_permitted) {
  4069.         c++;
  4070.         continue;
  4071.         }
  4072.         CLEAR_CELL_DIRTY(r,c);
  4073.         sc = ec = c;
  4074.         attr = VATTRIB(CELL_ATTR(r,c));
  4075.         cleanlen = NONDIRTY_THRESH;
  4076.         c++;
  4077.         /*
  4078.          * Scan until we find the end of line, a cell with a different
  4079.          * attribute, a sequence of NONDIRTY_THRESH non-dirty chars, or
  4080.          * the cursor position.
  4081.          */
  4082.         while (c < term.t_ncol) {
  4083.         if (attr != VATTRIB(CELL_ATTR(r,c)))
  4084.             break;
  4085.         else if (r == ttrow && c == ttcol && !cur_win->wipe_permitted) {
  4086.             c++;
  4087.             break;
  4088.         }
  4089.         else if (IS_DIRTY(r,c)) {
  4090.             ec = c;
  4091.             cleanlen = NONDIRTY_THRESH;
  4092.             CLEAR_CELL_DIRTY(r,c);
  4093.         }
  4094.         else if (--cleanlen <= 0)
  4095.             break;
  4096.         c++;
  4097.         }
  4098.         /* write out the portion from sc thru ec */
  4099.         flush_line(&CELL_TEXT(r,sc), ec-sc+1,
  4100.                    (unsigned int) VATTRIB(CELL_ATTR(r,sc)), r, sc);
  4101.     }
  4102.     }
  4103.     XFlush(dpy);
  4104. }
  4105.  
  4106.  
  4107. /* selection processing stuff */
  4108.  
  4109. /* multi-click code stolen from xterm */
  4110. /*
  4111.  * double click table for cut and paste in 8 bits
  4112.  *
  4113.  * This table is divided in four parts :
  4114.  *
  4115.  *    - control characters    [0,0x1f] U [0x80,0x9f]
  4116.  *    - separators        [0x20,0x3f] U [0xa0,0xb9]
  4117.  *    - binding characters    [0x40,0x7f] U [0xc0,0xff]
  4118.  *    - exceptions
  4119.  */
  4120. static int  charClass[256] = {
  4121. /* NUL  SOH  STX  ETX  EOT  ENQ  ACK  BEL */
  4122.     32, 1, 1, 1, 1, 1, 1, 1,
  4123. /*  BS   HT   NL   VT   NP   CR   SO   SI */
  4124.     1, 32, 1, 1, 1, 1, 1, 1,
  4125. /* DLE  DC1  DC2  DC3  DC4  NAK  SYN  ETB */
  4126.     1, 1, 1, 1, 1, 1, 1, 1,
  4127. /* CAN   EM  SUB  ESC   FS   GS   RS   US */
  4128.     1, 1, 1, 1, 1, 1, 1, 1,
  4129. /*  SP    !    "    #    $    %    &    ' */
  4130.     32, 33, 34, 35, 36, 37, 38, 39,
  4131. /*   (    )    *    +    ,    -    .    / */
  4132.     40, 41, 42, 43, 44, 45, 46, 47,
  4133. /*   0    1    2    3    4    5    6    7 */
  4134.     48, 48, 48, 48, 48, 48, 48, 48,
  4135. /*   8    9    :    ;    <    =    >    ? */
  4136.     48, 48, 58, 59, 60, 61, 62, 63,
  4137. /*   @    A    B    C    D    E    F    G */
  4138.     64, 48, 48, 48, 48, 48, 48, 48,
  4139. /*   H    I    J    K    L    M    N    O */
  4140.     48, 48, 48, 48, 48, 48, 48, 48,
  4141. /*   P    Q    R    S    T    U    V    W */
  4142.     48, 48, 48, 48, 48, 48, 48, 48,
  4143. /*   X    Y    Z    [    \    ]    ^    _ */
  4144.     48, 48, 48, 91, 92, 93, 94, 48,
  4145. /*   `    a    b    c    d    e    f    g */
  4146.     96, 48, 48, 48, 48, 48, 48, 48,
  4147. /*   h    i    j    k    l    m    n    o */
  4148.     48, 48, 48, 48, 48, 48, 48, 48,
  4149. /*   p    q    r    s    t    u    v    w */
  4150.     48, 48, 48, 48, 48, 48, 48, 48,
  4151. /*   x    y    z    {    |    }    ~  DEL */
  4152.     48, 48, 48, 123, 124, 125, 126, 1,
  4153. /* x80  x81  x82  x83  IND  NEL  SSA  ESA */
  4154.     1, 1, 1, 1, 1, 1, 1, 1,
  4155. /* HTS  HTJ  VTS  PLD  PLU   RI  SS2  SS3 */
  4156.     1, 1, 1, 1, 1, 1, 1, 1,
  4157. /* DCS  PU1  PU2  STS  CCH   MW  SPA  EPA */
  4158.     1, 1, 1, 1, 1, 1, 1, 1,
  4159. /* x98  x99  x9A  CSI   ST  OSC   PM  APC */
  4160.     1, 1, 1, 1, 1, 1, 1, 1,
  4161. /*   -    i   c/    L   ox   Y-    |   So */
  4162.     160, 161, 162, 163, 164, 165, 166, 167,
  4163. /*  ..   c0   ip   <<    _        R0    - */
  4164.     168, 169, 170, 171, 172, 173, 174, 175,
  4165. /*   o   +-    2    3    '    u   q|    . */
  4166.     176, 177, 178, 179, 180, 181, 182, 183,
  4167. /*   ,    1    2   >>  1/4  1/2  3/4    ? */
  4168.     184, 185, 186, 187, 188, 189, 190, 191,
  4169. /*  A`   A'   A^   A~   A:   Ao   AE   C, */
  4170.     48, 48, 48, 48, 48, 48, 48, 48,
  4171. /*  E`   E'   E^   E:   I`   I'   I^   I: */
  4172.     48, 48, 48, 48, 48, 48, 48, 48,
  4173. /*  D-   N~   O`   O'   O^   O~   O:    X */
  4174.     48, 48, 48, 48, 48, 48, 48, 216,
  4175. /*  O/   U`   U'   U^   U:   Y'    P    B */
  4176.     48, 48, 48, 48, 48, 48, 48, 48,
  4177. /*  a`   a'   a^   a~   a:   ao   ae   c, */
  4178.     48, 48, 48, 48, 48, 48, 48, 48,
  4179. /*  e`   e'   e^   e:    i`  i'   i^   i: */
  4180.     48, 48, 48, 48, 48, 48, 48, 48,
  4181. /*   d   n~   o`   o'   o^   o~   o:   -: */
  4182.     48, 48, 48, 48, 48, 48, 48, 248,
  4183. /*  o/   u`   u'   u^   u:   y'    P   y: */
  4184. 48, 48, 48, 48, 48, 48, 48, 48};
  4185.  
  4186. static int
  4187. set_character_class_range(
  4188.     register int low,
  4189.     register int high,        /* in range of [0..255] */
  4190.     register int value)        /* arbitrary */
  4191. {
  4192.  
  4193.     if (low < 0 || high > 255 || high < low)
  4194.     return (-1);
  4195.  
  4196.     for (; low <= high; low++)
  4197.     charClass[low] = value;
  4198.  
  4199.     return (0);
  4200. }
  4201.  
  4202.  
  4203. /*
  4204.  * set_character_class - takes a string of the form
  4205.  *
  4206.  *                 low[-high]:val[,low[-high]:val[...]]
  4207.  *
  4208.  * and sets the indicated ranges to the indicated values.
  4209.  */
  4210.  
  4211. static int
  4212. set_character_class(register char *s)
  4213. {
  4214.     register int i;        /* iterator, index into s */
  4215.     int         len;        /* length of s */
  4216.     int         acc;        /* accumulator */
  4217.     int         low,
  4218.                 high;        /* bounds of range [0..127] */
  4219.     int         base;        /* 8, 10, 16 (octal, decimal, hex) */
  4220.     int         numbers;    /* count of numbers per range */
  4221.     int         digits;        /* count of digits in a number */
  4222.     static char *errfmt = "xvile:  %s in range string \"%s\" (position %d)\n";
  4223.  
  4224.     if (!s || !s[0])
  4225.     return -1;
  4226.  
  4227.     base = 10;            /* in case we ever add octal, hex */
  4228.     low = high = -1;        /* out of range */
  4229.  
  4230.     for (i = 0, len = strlen(s), acc = 0, numbers = digits = 0;
  4231.         i < len; i++) {
  4232.     int        c = s[i];
  4233.  
  4234.     if (isSpace(c)) {
  4235.         continue;
  4236.     } else if (isDigit(c)) {
  4237.         acc = acc * base + (c - '0');
  4238.         digits++;
  4239.         continue;
  4240.     } else if (c == '-') {
  4241.         low = acc;
  4242.         acc = 0;
  4243.         if (digits == 0) {
  4244.         (void)fprintf(stderr, errfmt, "missing number", s, i);
  4245.         return (-1);
  4246.         }
  4247.         digits = 0;
  4248.         numbers++;
  4249.         continue;
  4250.     } else if (c == ':') {
  4251.         if (numbers == 0)
  4252.         low = acc;
  4253.         else if (numbers == 1)
  4254.         high = acc;
  4255.         else {
  4256.         (void)fprintf(stderr, errfmt, "too many numbers",
  4257.             s, i);
  4258.         return (-1);
  4259.         }
  4260.         digits = 0;
  4261.         numbers++;
  4262.         acc = 0;
  4263.         continue;
  4264.     } else if (c == ',') {
  4265.         /*
  4266.          * now, process it
  4267.          */
  4268.  
  4269.         if (high < 0) {
  4270.         high = low;
  4271.         numbers++;
  4272.         }
  4273.         if (numbers != 2) {
  4274.         (void)fprintf(stderr, errfmt, "bad value number",
  4275.             s, i);
  4276.         } else if (set_character_class_range(low, high, acc) != 0) {
  4277.         (void)fprintf(stderr, errfmt, "bad range", s, i);
  4278.         }
  4279.         low = high = -1;
  4280.         acc = 0;
  4281.         digits = 0;
  4282.         numbers = 0;
  4283.         continue;
  4284.     } else {
  4285.         (void)fprintf(stderr, errfmt, "bad character", s, i);
  4286.         return (-1);
  4287.     }            /* end if else if ... else */
  4288.  
  4289.     }
  4290.  
  4291.     if (low < 0 && high < 0)
  4292.     return (0);
  4293.  
  4294.     /*
  4295.      * now, process it
  4296.      */
  4297.  
  4298.     if (high < 0)
  4299.     high = low;
  4300.     if (numbers < 1 || numbers > 2) {
  4301.     (void)fprintf(stderr, errfmt, "bad value number", s, i);
  4302.     } else if (set_character_class_range(low, high, acc) != 0) {
  4303.     (void)fprintf(stderr, errfmt, "bad range", s, i);
  4304.     }
  4305.     return (0);
  4306. }
  4307.  
  4308. /*
  4309.  * Copy a single character into the paste-buffer, quoting it if necessary
  4310.  */
  4311. static int
  4312. add2paste(
  4313. TBUFF    **p,
  4314. int    c)
  4315. {
  4316.     if (c == '\n' || isBlank(c))
  4317.         /*EMPTY*/;
  4318.     else if (isspecial(c) || (c == '\r') || !isPrint(c))
  4319.         (void)tb_append(p, quotec);
  4320.     return (tb_append(p, c) != 0);
  4321. }
  4322.  
  4323. /*
  4324.  * Copy the selection into the PasteBuf buffer.  If we are pasting into a
  4325.  * window, check to see if:
  4326.  *
  4327.  *    + the window's buffer is modifiable (if not, don't waste time copying
  4328.  *      text!)
  4329.  *    + the buffer uses 'autoindent' mode (if so, do some heuristics
  4330.  *      for placement of the pasted text -- we may put it on lines by
  4331.  *      itself, above or below the current line)
  4332.  */
  4333. #define OLD_PASTE 0
  4334.  
  4335. static int
  4336. copy_paste(
  4337. TBUFF    **p,
  4338. char    *value,
  4339. SIZE_T    length)
  4340. {
  4341.     WINDOW    *wp = row2window(ttrow);
  4342.     BUFFER    *bp = (wp != 0) ? wp->w_bufp : 0;
  4343.     int    status;
  4344.  
  4345.     if (bp != 0 && b_val(bp,MDVIEW))
  4346.         return FALSE;
  4347.  
  4348.     status = TRUE;
  4349.  
  4350.     if (bp != 0 && (is_c_mode(bp) || b_val(bp,MDAIND))) {
  4351.  
  4352. #if OLD_PASTE
  4353.         /*
  4354.          * If the cursor points before the first nonwhite on
  4355.          * the line, convert the insert into an 'O' command.
  4356.          * If it points to the end of the line, convert it into
  4357.          * an 'o' command.  Otherwise (if it is within the
  4358.          * nonwhite portion of the line), assume the user knows
  4359.          * what (s)he is doing.
  4360.          */
  4361. #endif
  4362.         if (setwmark(ttrow, ttcol)) {    /* MK gets cursor */
  4363. #if OLD_PASTE
  4364.             LINE    *lp    = MK.l;
  4365.             int    first   = firstchar(lp);
  4366.             int    last    = lastchar(lp);
  4367.             CMDFUNC    *f = 0;
  4368.  
  4369.             /* If the line contains only a single nonwhite,
  4370.              * we will insert before it.
  4371.              */
  4372.             if (first >= MK.o)
  4373.                 f = &f_openup_no_aindent;
  4374.             else if (last <= MK.o)
  4375.                 f = &f_opendown_no_aindent;
  4376.             if (insertmode) {
  4377.                 if ((*value != '\n') && MK.o == 0)
  4378.                     (void)tb_append(p, '\n');
  4379.             }
  4380.             else if (f) {
  4381.                 char *pstr;
  4382.                 /* we're _replacing_ the default
  4383.                     insertion command, so reinit */
  4384.                 tb_init(p, abortc);
  4385.                 pstr = fnc2pstr(f);
  4386.                 tb_bappend(p, pstr + 1, (ALLOC_T) *pstr);
  4387.             }
  4388. #endif
  4389.         }
  4390.     }
  4391.  
  4392.     while (length-- > 0) {
  4393.         if (!add2paste(p, *value++)) {
  4394.             status = FALSE;
  4395.             break;
  4396.         }
  4397.     }
  4398.  
  4399.     return status;
  4400. }
  4401.  
  4402. /* ARGSUSED */
  4403. static void
  4404. x_get_selection(
  4405.     Widget         w GCC_UNUSED,
  4406.     XtPointer      cldat GCC_UNUSED,
  4407.     Atom          *selection,
  4408.     Atom          *type,
  4409.     XtPointer      value,
  4410.     unsigned long *length,
  4411.     int           *format)
  4412. {
  4413.     int    do_ins;
  4414.  
  4415.     if (*format != 8 || *type != XA_STRING) {
  4416.     x_beep();            /* can't handle incoming data */
  4417.     return;
  4418.     }
  4419.  
  4420.     if (length != 0 && value != NULL) {
  4421.     char *s = NULL;            /* stifle warning */
  4422.     /* should be impossible to hit this with existing paste */
  4423.     /* XXX massive hack -- leave out 'i' if in prompt line */
  4424.     do_ins = !insertmode
  4425.         && (!onMsgRow(cur_win) || *selection == atom_CLIPBOARD)
  4426.         && ((s = fnc2pstr(&f_insert_no_aindent)) != NULL);
  4427.  
  4428.     if (tb_init(&PasteBuf, abortc)) {
  4429.         if ((do_ins && !tb_bappend(&PasteBuf, s+1, (ALLOC_T)*s))
  4430.          || !copy_paste(&PasteBuf, (char *)value, (SIZE_T) *length)
  4431.          || (do_ins && !tb_append(&PasteBuf, abortc)))
  4432.             tb_free(&PasteBuf);
  4433.     }
  4434.     XtFree((char *)value);
  4435.     }
  4436. }
  4437.  
  4438. static void
  4439. x_paste_selection(Atom selection)
  4440. {
  4441.     if (cur_win->have_selection && selection == XA_PRIMARY) {
  4442.     /* local transfer */
  4443.     UCHAR  *data;
  4444.     SIZE_T len_st;
  4445.     unsigned long len_ul;
  4446.  
  4447.     Atom    type      = XA_STRING;
  4448.     int    format    = 8;
  4449.  
  4450.     if (!x_get_selected_text(&data, &len_st)) {
  4451.         x_beep();
  4452.         return;
  4453.     }
  4454.     len_ul = (unsigned long) len_st;    /* Ugh. */
  4455.     x_get_selection(cur_win->top_widget, NULL, &selection, &type,
  4456.                     (XtPointer) data, &len_ul, &format);
  4457.     }
  4458.     else {
  4459.     XtGetSelectionValue(
  4460.         cur_win->top_widget,
  4461.         selection,
  4462.         XA_STRING,
  4463.         x_get_selection,
  4464.         (XtPointer)0,        /* client data */
  4465.         XtLastTimestampProcessed(dpy));
  4466.     }
  4467. }
  4468.  
  4469. static Boolean
  4470. x_get_selected_text(
  4471.     UCHAR **datp,
  4472.     SIZE_T *lenp)
  4473. {
  4474.     UCHAR    *data = 0;
  4475.     UCHAR    *dp = 0;
  4476.     SIZE_T    length;
  4477.     KILL    *kp;        /* pointer into kill register */
  4478.  
  4479.     /* FIXME: Can't select message line */
  4480.  
  4481.     if (!cur_win->have_selection)
  4482.     return False;
  4483.  
  4484.     sel_yank(SEL_KREG);
  4485.     for (length = 0, kp = kbs[SEL_KREG].kbufh; kp; kp = kp->d_next)
  4486.     length += KbSize(SEL_KREG, kp);
  4487.     if ( length == 0
  4488.       || (dp = data = (UCHAR *) XtMalloc(length * sizeof(UCHAR))) == 0
  4489.       || (kp = kbs[SEL_KREG].kbufh) == 0)
  4490.     return False;
  4491.  
  4492.     while (kp != NULL) {
  4493.     SIZE_T len = KbSize(SEL_KREG,kp);
  4494.     (void)memcpy((char *)dp, (char *)kp->d_chunk, len);
  4495.     kp = kp->d_next;
  4496.     dp += len;
  4497.     }
  4498.  
  4499.     *lenp = length;
  4500.     *datp = data;
  4501.     return True;
  4502. }
  4503.  
  4504. static Boolean
  4505. x_get_clipboard_text(
  4506.     UCHAR **datp,
  4507.     SIZE_T *lenp)
  4508. {
  4509.     UCHAR    *data = 0;
  4510.     UCHAR    *dp = 0;
  4511.     SIZE_T    length;
  4512.     KILL    *kp;        /* pointer into kill register */
  4513.  
  4514.     for (length = 0, kp = kbs[CLIP_KREG].kbufh; kp; kp = kp->d_next)
  4515.     length += KbSize(CLIP_KREG, kp);
  4516.     if ( length == 0
  4517.       || (dp = data = (UCHAR *) XtMalloc(length * sizeof(UCHAR))) == 0
  4518.       || (kp = kbs[CLIP_KREG].kbufh) == 0)
  4519.     return False;
  4520.  
  4521.     while (kp != NULL) {
  4522.     SIZE_T len = KbSize(CLIP_KREG,kp);
  4523.     (void)memcpy((char *)dp, (char *)kp->d_chunk, len);
  4524.     kp = kp->d_next;
  4525.     dp += len;
  4526.     }
  4527.  
  4528.     *lenp = length;
  4529.     *datp = data;
  4530.     return True;
  4531. }
  4532.  
  4533. /* ARGSUSED */
  4534. static Boolean
  4535. x_convert_selection(
  4536.     Widget       w GCC_UNUSED,
  4537.     Atom          *selection,
  4538.     Atom          *target,
  4539.     Atom          *type,
  4540.     XtPointer     *value,
  4541.     unsigned long *length,
  4542.     int           *format)
  4543. {
  4544.     if (!cur_win->have_selection && *selection == XA_PRIMARY)
  4545.     return False;
  4546.  
  4547.     /*
  4548.      * The ICCCM requires us to handle the following targets: TARGETS,
  4549.      * MULTIPLE, and TIMESTAMP.  MULTIPLE and TIMESTAMP are handled by
  4550.      * the Xt intrinsics.  Below, we handle TARGETS, STRING, and TEXT.
  4551.      * The STRING and TEXT targets are what xvile uses to transfer
  4552.      * selected text to another client.  TARGETS is simply a list of
  4553.      * the targets we support (including the ones handled by the Xt
  4554.      * intrinsics).
  4555.      */
  4556.  
  4557.     if (*target == atom_TARGETS) {
  4558.     Atom *tp;
  4559.  
  4560. #define NTARGS 5
  4561.  
  4562.     *(Atom **)value = tp = (Atom *)XtMalloc(NTARGS * sizeof(Atom));
  4563.  
  4564.     if (tp == NULL)
  4565.         return False;    /* should not happen (even if out of memory) */
  4566.  
  4567.     *tp++ = atom_TARGETS;
  4568.     *tp++ = atom_MULTIPLE;
  4569.     *tp++ = atom_TIMESTAMP;
  4570.     *tp++ = XA_STRING;
  4571.     *tp++ = atom_TEXT;
  4572.  
  4573.     *type   = XA_ATOM;
  4574.     *length = tp - *(Atom **)value;
  4575.     *format = 32;        /* width of the data being transfered */
  4576.     return True;
  4577.     }
  4578.     else if (*target == XA_STRING || *target == atom_TEXT) {
  4579.     *type   = XA_STRING;
  4580.     *format = 8;
  4581.     if (*selection == XA_PRIMARY)
  4582.         return x_get_selected_text((UCHAR **)value, (SIZE_T *)length);
  4583.     else    /* CLIPBOARD */
  4584.         return x_get_clipboard_text((UCHAR **)value, (SIZE_T *)length);
  4585.     }
  4586.  
  4587.     return False;
  4588. }
  4589.  
  4590. /* ARGSUSED */
  4591. static void
  4592. x_lose_selection(
  4593.     Widget w GCC_UNUSED,
  4594.     Atom  *selection)
  4595. {
  4596.     if (*selection == XA_PRIMARY) {
  4597.     cur_win->have_selection = False;
  4598.     cur_win->was_on_msgline = False;
  4599.     sel_release();
  4600.     (void) update(TRUE);
  4601.     }
  4602.     else {
  4603.     /* Free up the data in the kill buffer (how do we do this?) */
  4604.     }
  4605. }
  4606.  
  4607. void own_selection(void)
  4608. {
  4609.     x_own_selection(XA_PRIMARY);
  4610. }
  4611.  
  4612. static void
  4613. x_own_selection(Atom selection)
  4614. {
  4615.     /*
  4616.      * Note:  we've been told that the Hummingbird X Server (which runs on a
  4617.      * PC) updates the contents of the clipboard only if we remove the next
  4618.      * line, causing this program to assert the selection on each call.  We
  4619.      * don't do that, however, since it would violate the sense of the ICCCM,
  4620.      * which is minimizing network traffic.
  4621.      *
  4622.      * Kev's note on the above comment (which I assume was written by Tom):
  4623.      * I've added some new code for dealing with clipboards in now.  It
  4624.      * may well be that the clipboard will work properly now.  Of course,
  4625.      * you'll need to run the copy-to-clipboard command from vile.  If
  4626.      * you're on a Sun keyboard, you might want to bind this to the Copy
  4627.      * key (F16).  I may also think about doing a sort of timer mechanism
  4628.      * which asserts ownership of the clipboard if a certain amount of
  4629.      * time has gone by with no activity.
  4630.      */
  4631.     if (!cur_win->have_selection || selection != XA_PRIMARY)
  4632.     cur_win->have_selection =
  4633.         XtOwnSelection(
  4634.         cur_win->top_widget,
  4635.         selection,
  4636.         XtLastTimestampProcessed(dpy),
  4637.         x_convert_selection,
  4638.         x_lose_selection,
  4639.         (XtSelectionDoneProc)0);
  4640. }
  4641.  
  4642. static void
  4643. scroll_selection(
  4644.     XtPointer rowcol,
  4645.     XtIntervalId *idp)
  4646. {
  4647.     int row, col;
  4648.     if (*idp == cur_win->sel_scroll_id)
  4649.     XtRemoveTimeOut(cur_win->sel_scroll_id);    /* shouldn't happen */
  4650.     cur_win->sel_scroll_id = (XtIntervalId) 0;
  4651.  
  4652.     row = (((long) rowcol) >> 16) & 0xffff;
  4653.     col = ((long) rowcol) & 0xffff;
  4654.     if (row & 0x8000)
  4655.     row |= -1 << 16;
  4656.     if (col & 0x8000)
  4657.     col |= -1 << 16;
  4658.     extend_selection(cur_win, row, col, TRUE);
  4659. }
  4660.  
  4661. static int
  4662. line_count_and_interval(
  4663.     long scroll_count,
  4664.     unsigned long *ip)
  4665. {
  4666.     scroll_count = scroll_count / 4 - 2;
  4667.     if (scroll_count <= 0) {
  4668.     *ip = (1 - scroll_count) * cur_win->scroll_repeat_interval;
  4669.     return 1;
  4670.     }
  4671.     else {
  4672.     /*
  4673.      * FIXME: figure out a cleaner way to do this or something like it...
  4674.      */
  4675.     if (scroll_count > 450)
  4676.         scroll_count *= 1024;
  4677.     else if (scroll_count > 350)
  4678.         scroll_count *= 128;
  4679.     else if (scroll_count > 275)
  4680.         scroll_count *= 64;
  4681.     else if (scroll_count > 200)
  4682.         scroll_count *= 16;
  4683.     else if (scroll_count > 150)
  4684.         scroll_count *= 8;
  4685.     else if (scroll_count > 100)
  4686.         scroll_count *= 4;
  4687.     else if (scroll_count > 75)
  4688.         scroll_count *= 3;
  4689.     else if (scroll_count > 50)
  4690.         scroll_count *= 2;
  4691.     *ip = cur_win->scroll_repeat_interval;
  4692.     return scroll_count;
  4693.     }
  4694. }
  4695.  
  4696. static void
  4697. extend_selection(
  4698.     TextWindow tw GCC_UNUSED,
  4699.     int    nr,
  4700.     int    nc,
  4701.     Bool wipe)
  4702. {
  4703.     static long scroll_count = 0;
  4704.     long rowcol = 0;
  4705.     unsigned long interval = 0;
  4706.  
  4707.     if (cur_win->sel_scroll_id != (XtIntervalId) 0) {
  4708.     if (nr < curwp->w_toprow || nr >= mode_row(curwp))
  4709.         return;        /* Only let timer extend selection */
  4710.     XtRemoveTimeOut(cur_win->sel_scroll_id);
  4711.     cur_win->sel_scroll_id = (XtIntervalId) 0;
  4712.     }
  4713.  
  4714.     if (nr < curwp->w_toprow) {
  4715.     if (wipe) {
  4716.         mvupwind(TRUE, line_count_and_interval(scroll_count++, &interval));
  4717.         rowcol = (nr << 16) | (nc & 0xffff);
  4718.     }
  4719.     else {
  4720.         scroll_count = 0;
  4721.     }
  4722.     nr = curwp->w_toprow;
  4723.     }
  4724.     else if (nr >= mode_row(curwp)) {
  4725.     if (wipe) {
  4726.         mvdnwind(TRUE, line_count_and_interval(scroll_count++, &interval));
  4727.         rowcol = (nr << 16) | (nc & 0xffff);
  4728.     }
  4729.     else {
  4730.         scroll_count = 0;
  4731.     }
  4732.     nr = mode_row(curwp) - 1;
  4733.     }
  4734.     else {
  4735.     scroll_count = 0;
  4736.     }
  4737.     if (setcursor(nr,nc) && sel_extend(wipe,TRUE)) {
  4738.     cur_win->did_select = True;
  4739.     (void)update(TRUE);
  4740.     if (scroll_count > 0) {
  4741.         x_flush();
  4742.         cur_win->sel_scroll_id = XtAppAddTimeOut(cur_win->app_context,
  4743.                                                  interval,
  4744.                              scroll_selection,
  4745.                              (XtPointer) rowcol);
  4746.     }
  4747.     }
  4748.     else
  4749.     x_beep();
  4750. }
  4751.  
  4752. static void
  4753. multi_click(
  4754.     TextWindow  tw,
  4755.     int         nr,
  4756.     int         nc)
  4757. {
  4758.     UCHAR    *p;
  4759.     int    cclass;
  4760.     int    sc = nc;
  4761.     int oc = nc;
  4762.     WINDOW    *wp;
  4763.  
  4764.     tw->numclicks++;
  4765.  
  4766.     if ((wp = row2window(nr)) != 0 && nr == mode_row(wp)) {
  4767.     set_curwp(wp);
  4768.     sel_release();
  4769.     (void)update(TRUE);
  4770.     }
  4771.     else {
  4772.     switch (tw->numclicks) {
  4773.     case 0:
  4774.     case 1:            /* shouldn't happen */
  4775.         mlwrite("BUG: 0 or 1 multiclick value.");
  4776.         return;
  4777.     case 2:            /* word */
  4778. #if OPT_HYPERTEXT
  4779.         if (setcursor(nr,nc) && exechypercmd(0,0)) {
  4780.             (void) update(TRUE);
  4781.             return;
  4782.         }
  4783. #endif
  4784.         /* find word start */
  4785.         p = (UCHAR *)(&CELL_TEXT(nr,sc));
  4786.         cclass = charClass[*p];
  4787.         do {
  4788.             --sc;
  4789.             --p;
  4790.         } while (sc >= 0 && charClass[*p] == cclass);
  4791.         sc++;
  4792.         /* and end */
  4793.         p = (UCHAR *)(&CELL_TEXT(nr,nc));
  4794.         cclass = charClass[*p];
  4795.         do {
  4796.             ++nc;
  4797.             ++p;
  4798.         } while (nc < tw->cols && charClass[*p] == cclass);
  4799.         --nc;
  4800.  
  4801.         if (setcursor(nr,sc)) {
  4802.             (void)sel_begin();
  4803.             extend_selection(tw, nr, nc, FALSE);
  4804.             (void) setcursor(nr,oc);
  4805.             /* FIXME: Too many updates */
  4806.             (void) update(TRUE);
  4807.         }
  4808.         return;
  4809.     case 3:            /* line (doesn't include trailing newline) */
  4810.         if (setcursor(nr,sc)) {
  4811.             MARK saveDOT;
  4812.             saveDOT = DOT;
  4813.             (void) gotobol(0, 0);
  4814.             (void) sel_begin();
  4815.             (void) gotoeol(FALSE, 0);
  4816.             (void) sel_extend(FALSE,TRUE);
  4817.             DOT = saveDOT;
  4818.             cur_win->did_select = True;
  4819.             (void) update(TRUE);
  4820.         }
  4821.         return;
  4822.     case 4:         /* document (doesn't include trailing newline) */
  4823.         if (setcursor(nr,sc)) {
  4824.             MARK saveDOT;
  4825.             saveDOT = DOT;
  4826.             (void) gotobob(0, 0);
  4827.             (void) sel_begin();
  4828.             (void) gotoeob(FALSE, 0);
  4829.             (void) gotoeol(FALSE, 0);
  4830.             (void) sel_extend(FALSE,TRUE);
  4831.             DOT = saveDOT;
  4832.             cur_win->did_select = True;
  4833.             (void) update(TRUE);
  4834.         }
  4835.         return;
  4836.     default:
  4837.         /*
  4838.          * This provides a mechanism for getting rid of the
  4839.          * selection.
  4840.          */
  4841.         sel_release();
  4842.         (void)update(TRUE);
  4843.         return;
  4844.     }
  4845.     }
  4846. }
  4847.  
  4848. static void
  4849. start_selection(
  4850.     TextWindow  tw,
  4851.     XButtonPressedEvent *ev,
  4852.     int    nr,
  4853.     int    nc)
  4854. {
  4855.     tw->wipe_permitted = FALSE;
  4856.     if ((tw->lasttime != 0)
  4857.      && (absol(ev->time - tw->lasttime) < tw->click_timeout)) {
  4858.     /* FIXME: This code used to ignore multiple clicks which
  4859.      *      spanned rows.  Do we still want this behavior?
  4860.      *      If so, we'll have to (re)implement it.
  4861.      */
  4862.     multi_click(tw, nr, nc);
  4863.     }
  4864.     else {
  4865.     WINDOW *wp;
  4866.  
  4867.     beginDisplay();
  4868.  
  4869.     tw->lasttime = ev->time;
  4870.     tw->numclicks = 1;
  4871.     tw->was_on_msgline = onMsgRow(tw);
  4872.  
  4873.     if ((wp = row2window(nr)) != 0) {
  4874.         set_curwp(wp);
  4875.     }
  4876.     tw->prevDOT = DOT;
  4877.  
  4878.     /*
  4879.      * If we're on the message line, do nothing.
  4880.      *
  4881.      * If we're on a mode line, make the window whose mode line we're
  4882.      * on the current window.
  4883.      *
  4884.      * Otherwise update the cursor position in whatever window we're
  4885.      * in and set things up so that the current position can be the
  4886.      * possible start of a selection.
  4887.      */
  4888.     if (reading_msg_line) {
  4889.         /*EMPTY*/;    /* ignore */
  4890.     }
  4891.     else if (wp != 0 && nr == mode_row(wp)) {
  4892.         (void)update(TRUE);
  4893.     }
  4894.     else if (setcursor(nr, nc)) {
  4895.         if (!cur_win->persistent_selections) {
  4896.         sel_yank(SEL_KREG);
  4897.         sel_release();
  4898.         }
  4899.         (void) sel_begin();
  4900.         (void)update(TRUE);
  4901.         tw->wipe_permitted = TRUE;
  4902.         /* force the editor to notice the changed DOT, if it cares */
  4903.         kqadd(cur_win, KEY_Mouse);
  4904.     }
  4905.     endofDisplay();
  4906.     }
  4907. }
  4908.  
  4909. /* this doesn't need to do anything.  it's invoked when we do
  4910.     shove KEY_Mouse back on the input stream, to force the
  4911.     main editor code to notice that DOT has moved. */
  4912. /*ARGSUSED*/
  4913. int
  4914. mouse_motion(int f GCC_UNUSED, int n GCC_UNUSED)
  4915. {
  4916.     return TRUE;
  4917. }
  4918.  
  4919. /*ARGSUSED*/
  4920. int
  4921. copy_to_clipboard(int f GCC_UNUSED, int n GCC_UNUSED)
  4922. {
  4923.     if (!cur_win->have_selection) {
  4924.     x_beep();
  4925.     return FALSE;
  4926.     }
  4927.  
  4928.     sel_yank(CLIP_KREG);
  4929.     x_own_selection(atom_CLIPBOARD);
  4930.  
  4931.     return TRUE;
  4932. }
  4933.  
  4934. /*ARGSUSED*/
  4935. int
  4936. paste_from_clipboard(int f GCC_UNUSED, int n GCC_UNUSED)
  4937. {
  4938.     x_paste_selection(atom_CLIPBOARD);
  4939.     return TRUE;
  4940. }
  4941.  
  4942. static XMotionEvent *
  4943. compress_motion(
  4944.     XMotionEvent *ev)
  4945. {
  4946.     XEvent      nev;
  4947.  
  4948.     while (XPending(ev->display)) {
  4949.     XPeekEvent(ev->display, &nev);
  4950.     if (nev.type == MotionNotify &&
  4951.         nev.xmotion.window == ev->window &&
  4952.         nev.xmotion.subwindow == ev->subwindow) {
  4953.         XNextEvent(ev->display, (XEvent *) ev);
  4954.     } else
  4955.         break;
  4956.     }
  4957.     return ev;
  4958. }
  4959.  
  4960. /*
  4961.  * handle non keyboard events associated with vile screen
  4962.  */
  4963. /*ARGSUSED*/
  4964. static void
  4965. x_process_event(
  4966.     Widget    w GCC_UNUSED,
  4967.     XtPointer    unused GCC_UNUSED,
  4968.     XEvent     *ev,
  4969.     Boolean    *continue_to_dispatch GCC_UNUSED)
  4970. {
  4971.     int         sc,
  4972.                 sr;
  4973.     unsigned    ec,
  4974.                 er;
  4975.  
  4976.     int         nr,
  4977.                 nc;
  4978.     static int onr = -1, onc = -1;
  4979.  
  4980.     XMotionEvent *mev;
  4981.     XExposeEvent *gev;
  4982.     Bool    do_sel;
  4983.     WINDOW    *wp;
  4984.  
  4985.     switch (ev->type) {
  4986.     case Expose:
  4987.     gev = (XExposeEvent *)ev;
  4988.     sc = gev->x / cur_win->char_width;
  4989.     sr = gev->y / cur_win->char_height;
  4990.     ec = CEIL(gev->x + gev->width,  cur_win->char_width);
  4991.     er = CEIL(gev->y + gev->height, cur_win->char_height);
  4992.     x_touch(cur_win, sc, sr, ec, er);
  4993.     cur_win->exposed = TRUE;
  4994.     if (ev->xexpose.count == 0)
  4995.         x_flush();
  4996.     break;
  4997.  
  4998.     case VisibilityNotify:
  4999.     cur_win->visibility = ev->xvisibility.state;
  5000.     XSetGraphicsExposures(dpy, cur_win->textgc,
  5001.                   cur_win->visibility != VisibilityUnobscured);
  5002.     break;
  5003.  
  5004.     case MotionNotify:
  5005.     do_sel = cur_win->wipe_permitted;
  5006.     if (!(ev->xmotion.state & (Button1Mask | Button3Mask))) {
  5007.         if (!cur_win->focus_follows_mouse)
  5008.         return;
  5009.         else
  5010.         do_sel = FALSE;
  5011.     }
  5012.     mev = compress_motion((XMotionEvent *) ev);
  5013.     nc = mev->x / cur_win->char_width;
  5014.     nr = mev->y / cur_win->char_height;
  5015.  
  5016.     if (nr < 0)
  5017.         nr = -1;    /* want to be out of bounds to force scrolling */
  5018.     else if (nr > cur_win->rows)
  5019.         nr = cur_win->rows;
  5020.  
  5021.     if (nc < 0)
  5022.         nc = 0;
  5023.     else if (nc >= cur_win->cols)
  5024.         nc = cur_win->cols-1;
  5025.  
  5026.     /* ignore any spurious motion during a multi-cick */
  5027.     if (cur_win->numclicks > 1
  5028.      && cur_win->lasttime != 0
  5029.          && (absol(ev->xmotion.time - cur_win->lasttime) < cur_win->click_timeout))
  5030.         return;
  5031.     if (do_sel) {
  5032.         if (ev->xbutton.state & ControlMask) {
  5033.         (void)sel_setshape(RECTANGLE);
  5034.         }
  5035.         if (nr != onr || nc != onc)
  5036.         extend_selection(cur_win, nr, nc, True);
  5037.         onr = nr;
  5038.         onc = nc;
  5039.     }
  5040.     else {
  5041.         if (!reading_msg_line && (wp = row2window(nr)) && wp != curwp) {
  5042.         (void) set_curwp(wp);
  5043.         (void) update(TRUE);
  5044.         }
  5045.     }
  5046.     break;
  5047.     case ButtonPress:
  5048.     nc = ev->xbutton.x / cur_win->char_width;
  5049.     nr = ev->xbutton.y / cur_win->char_height;
  5050.     TRACE(("ButtonPress #%d (%d,%d)\n", ev->xbutton.button, nr, nc))
  5051.     switch (ev->xbutton.button) {
  5052.     case Button1:        /* move button and set selection point */
  5053.         start_selection(cur_win, (XButtonPressedEvent *) ev, nr, nc);
  5054.         onr = nr;
  5055.         onc = nc;
  5056.         break;
  5057.     case Button2:        /* paste selection */
  5058.         /*
  5059.          * If shifted, paste at mouse.  Otherwise, paste at the last
  5060.          * position marked before beginning a selection.
  5061.          */
  5062.         if (ev->xbutton.state & ShiftMask) {
  5063.         if (!setcursor(nr, nc)) {
  5064.             kbd_alarm();    /* don't know how to paste here */
  5065.             break;
  5066.         }
  5067.         }
  5068.         x_paste_selection(XA_PRIMARY);
  5069.         break;
  5070.     case Button3:        /* end/extend selection */
  5071.         if (((wp = row2window(nr)) != 0) && sel_buffer() == wp->w_bufp)
  5072.         (void) set_curwp(wp);
  5073.         if (ev->xbutton.state & ControlMask)
  5074.         (void)sel_setshape(RECTANGLE);
  5075.         cur_win->wipe_permitted = True;
  5076.         cur_win->prevDOT = DOT;
  5077.         extend_selection(cur_win, nr, nc, False);
  5078.         break;
  5079.     }
  5080.     break;
  5081.     case ButtonRelease:
  5082.     TRACE(("ButtonRelease #%d (%d,%d)%s\n",
  5083.         ev->xbutton.button,
  5084.         ev->xbutton.y / cur_win->char_height,
  5085.         ev->xbutton.x / cur_win->char_width,
  5086.         cur_win->did_select ? ": did_select" : ""))
  5087.     switch (ev->xbutton.button) {
  5088.     case Button1:
  5089.         if (cur_win->persistent_selections)
  5090.         sel_yank(SEL_KREG);
  5091.  
  5092.         /* FALLTHRU */
  5093.     case Button3:
  5094.         if (cur_win->sel_scroll_id != ((XtIntervalId) 0)) {
  5095.         XtRemoveTimeOut(cur_win->sel_scroll_id);
  5096.         cur_win->sel_scroll_id = (XtIntervalId) 0;
  5097.         }
  5098.         if (cur_win->did_select && !cur_win->selection_sets_DOT) {
  5099.         DOT = cur_win->prevDOT;
  5100.         (void)update(TRUE);
  5101.         }
  5102.         cur_win->did_select = False;
  5103.         cur_win->wipe_permitted = False;
  5104.         display_cursor((XtPointer) 0, (XtIntervalId *) 0);
  5105.         break;
  5106.     }
  5107.     break;
  5108.     }
  5109. }
  5110.  
  5111. /*ARGSUSED*/
  5112. static void
  5113. x_configure_window(
  5114.     Widget    w GCC_UNUSED,
  5115.     XtPointer    unused GCC_UNUSED,
  5116.     XEvent     *ev,
  5117.     Boolean    *continue_to_dispatch GCC_UNUSED)
  5118. {
  5119.     int nr, nc;
  5120.     Dimension new_width, new_height;
  5121.  
  5122.     if (ev->type != ConfigureNotify)
  5123.     return;
  5124.  
  5125.     if (cur_win->base_width < 0) {
  5126.     /* First time through...figure out the base width and height */
  5127.     XtVaGetValues(cur_win->top_widget,
  5128.         XtNheight,    &cur_win->top_height,
  5129.         XtNwidth,    &cur_win->top_width,
  5130.         NULL);
  5131. #if ATHENA_WIDGETS
  5132.     XtVaGetValues(cur_win->menu_widget,
  5133.         XtNheight,    &cur_win->menu_height,
  5134.         XtNwidth,    &new_width,
  5135.         NULL);
  5136. #endif
  5137.     XtVaGetValues(cur_win->screen,
  5138.         XtNheight,    &new_height,
  5139.         XtNwidth,    &new_width,
  5140.         NULL);
  5141.     cur_win->base_width = cur_win->top_width - new_width;
  5142.     cur_win->base_height = cur_win->menu_height;
  5143.  
  5144.     XtVaSetValues(cur_win->top_widget,
  5145. #if XtSpecificationRelease >= 4
  5146.         XtNbaseHeight,    cur_win->base_height,
  5147.         XtNbaseWidth,    cur_win->base_width,
  5148. #endif
  5149.         XtNminHeight,    cur_win->base_height
  5150.                     + MINROWS*cur_win->char_height,
  5151.         XtNminWidth,    cur_win->base_width
  5152.                     + MINCOLS*cur_win->char_width,
  5153.         XtNheightInc,    cur_win->char_height,
  5154.         XtNwidthInc,    cur_win->char_width,
  5155.         NULL);
  5156.     }
  5157.  
  5158.     if (ev->xconfigure.height == cur_win->top_height
  5159.      && ev->xconfigure.width == cur_win->top_width)
  5160.     return;
  5161.  
  5162.     XtVaGetValues(cur_win->top_widget,
  5163.         XtNheight,    &new_height,
  5164.         XtNwidth,    &new_width,
  5165.         NULL);
  5166.     new_height = ((new_height - cur_win->base_height) / cur_win->char_height)
  5167.                  * cur_win->char_height;
  5168.     new_width = ((new_width - cur_win->base_width) /
  5169.             cur_win->char_width) * cur_win->char_width;
  5170. #if MOTIF_WIDGETS
  5171.     XtVaSetValues(cur_win->form_widget,
  5172.         XmNresizePolicy,    XmRESIZE_NONE,
  5173.         NULL);
  5174.     {
  5175.     WidgetList children;
  5176.     Cardinal nchildren;
  5177.     XtVaGetValues(cur_win->form_widget,
  5178.         XmNchildren, &children,
  5179.         XmNnumChildren, &nchildren,
  5180.         NULL);
  5181.     XtUnmanageChildren(children, nchildren);
  5182.     }
  5183. #else
  5184. #if NO_WIDGETS || ATHENA_WIDGETS
  5185.     XtVaSetValues(cur_win->form_widget,
  5186.         XtNwidth,        new_width + cur_win->pane_width + 2,
  5187.         XtNheight,        new_height,
  5188.         NULL);
  5189. #endif /* NO_WIDGETS */
  5190. #endif /* MOTIF_WIDGETS */
  5191.     XtVaSetValues(cur_win->screen,
  5192.         XtNheight,    new_height,
  5193.         XtNwidth,    new_width,
  5194. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  5195.         XtNx,    cur_win->scrollbar_on_left ? cur_win->pane_width+2 : 0,
  5196. #endif
  5197.         NULL);
  5198.     XtVaSetValues(cur_win->pane,
  5199. #if !OPT_KEV_SCROLLBARS && !OPT_XAW_SCROLLBARS
  5200.         XtNwidth,    cur_win->pane_width,
  5201. #if OL_WIDGETS
  5202.         XtNheight,    new_height,
  5203. #endif /* OL_WIDGETS */
  5204. #else    /* OPT_KEV_SCROLLBARS */
  5205.         XtNx,    cur_win->scrollbar_on_left ? 0 : new_width,
  5206.         XtNwidth,    cur_win->pane_width+2,
  5207.         XtNheight,    new_height - cur_win->char_height,
  5208. #endif /* OPT_KEV_SCROLLBARS */
  5209.         NULL);
  5210. #if MOTIF_WIDGETS
  5211.     {
  5212.     WidgetList children;
  5213.     Cardinal nchildren;
  5214.     XtVaGetValues(cur_win->form_widget,
  5215.         XmNchildren, &children,
  5216.         XmNnumChildren, &nchildren,
  5217.         NULL);
  5218.     XtManageChildren(children, nchildren);
  5219.     }
  5220.     XtVaSetValues(cur_win->form_widget,
  5221.         XmNresizePolicy,    XmRESIZE_ANY,
  5222.         NULL);
  5223. #endif /* MOTIF_WIDGETS */
  5224.  
  5225.     XtVaGetValues(cur_win->top_widget,
  5226.         XtNheight,    &cur_win->top_height,
  5227.         XtNwidth,    &cur_win->top_width,
  5228.         NULL);
  5229.     XtVaGetValues(cur_win->screen,
  5230.         XtNheight,    &new_height,
  5231.         XtNwidth,    &new_width,
  5232.         NULL);
  5233.  
  5234.     nr = (int)(new_height / cur_win->char_height);
  5235.     nc = (int)(new_width  / cur_win->char_width);
  5236.  
  5237.     if (nr < MINROWS || nc < MINCOLS) {
  5238.     gui_resize(nc, nr);
  5239.     /* Calling XResizeWindow will cause another ConfigureNotify
  5240.      * event, so we should return early and let this event occur.
  5241.      */
  5242.     return;
  5243.     }
  5244.  
  5245.     if (nc != cur_win->cols || nr != cur_win->rows) {
  5246.     newscreensize(nr,nc);
  5247.     cur_win->rows = nr;
  5248.     cur_win->cols = nc;
  5249.     if (check_scrollbar_allocs() == TRUE) /* no allocation failure */
  5250.         update_scrollbar_sizes();
  5251.     }
  5252. #if MOTIF_WIDGETS
  5253.     lookfor_sb_resize = FALSE;
  5254. #endif
  5255. }
  5256.  
  5257. void
  5258. gui_resize(
  5259.     int cols,
  5260.     int rows)
  5261. {
  5262.     if (cols < MINCOLS)
  5263.     cols = MINCOLS;
  5264.     if (rows < MINROWS)
  5265.     rows = MINROWS;
  5266.  
  5267.     XResizeWindow(dpy, XtWindow(cur_win->top_widget),
  5268.           (unsigned)cols * cur_win->char_width + cur_win->base_width,
  5269.           (unsigned)rows * cur_win->char_height + cur_win->base_height);
  5270.     /* This should cause a ConfigureNotify event */
  5271. }
  5272.  
  5273. static
  5274. int check_scrollbar_allocs(void)
  5275. {
  5276.     int newmax = cur_win->rows/2;
  5277.     int oldmax = cur_win->maxscrollbars;
  5278.  
  5279.     if (newmax > oldmax) {
  5280.  
  5281.         GROW(cur_win->scrollbars, Widget, oldmax, newmax);
  5282. #if OL_WIDGETS
  5283.         GROW(cur_win->sliders, Widget, oldmax, newmax);
  5284. #endif
  5285. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  5286.         GROW(cur_win->scrollinfo, ScrollInfo, oldmax, newmax);
  5287.         GROW(cur_win->grips, Widget, oldmax, newmax);
  5288. #endif
  5289.  
  5290.         cur_win->maxscrollbars = newmax;
  5291.     }
  5292.     return TRUE;
  5293. }
  5294.  
  5295. #if MOTIF_WIDGETS
  5296. static void
  5297. grip_moved(
  5298.     Widget    w,
  5299.     XtPointer    unused,
  5300.     XEvent     *ev,
  5301.     Boolean    *continue_to_dispatch)
  5302. {
  5303.     int i;
  5304.     register WINDOW *wp, *saved_curwp;
  5305.     Dimension height;
  5306.     int    lines;
  5307.  
  5308.     if (!lookfor_sb_resize)
  5309.     return;
  5310.     lookfor_sb_resize = FALSE;
  5311.     saved_curwp = curwp;
  5312.  
  5313.     i = 0;
  5314.     for_each_visible_window(wp) {
  5315.     XtVaGetValues(cur_win->scrollbars[i],
  5316.         XtNheight, &height,
  5317.         NULL);
  5318.     lines = (height+(cur_win->char_height/2)) / cur_win->char_height;
  5319.     if (lines <= 0) {
  5320.         lines = 1;
  5321.     }
  5322.     curwp = wp;
  5323.     resize(TRUE, lines);
  5324.     i++;
  5325.     }
  5326.     set_curwp(saved_curwp);
  5327.     (void) update(TRUE);
  5328. }
  5329. #endif
  5330.  
  5331. static void
  5332. configure_bar(
  5333.     Widget w,
  5334.     XEvent *event,
  5335.     String *params,
  5336.     Cardinal *num_params)
  5337. {
  5338.     WINDOW *wp;
  5339.     int i;
  5340.  
  5341.     if (*num_params != 1
  5342.      || (event->type != ButtonPress && event->type != ButtonRelease))
  5343.     return;
  5344.  
  5345.     i = 0;
  5346.     for_each_visible_window(wp) {
  5347.     if (cur_win->scrollbars[i] == w) {
  5348.         if (strcmp(params[0], "Only") == 0) {
  5349.         set_curwp(wp);
  5350.         onlywind(TRUE,0);
  5351.         }
  5352.         else if (strcmp(params[0], "Kill") == 0) {
  5353.         set_curwp(wp);
  5354.         delwind(TRUE,0);
  5355.         }
  5356.         else if (strcmp(params[0], "Split") == 0) {
  5357.         if (wp->w_ntrows < 3) {
  5358.             x_beep();
  5359.             break;
  5360.         }
  5361.         else {
  5362.             int newsize;
  5363.             set_curwp(wp);
  5364.             newsize = CEIL(event->xbutton.y, cur_win->char_height)-1;
  5365.             if (newsize > wp->w_ntrows - 2)
  5366.             newsize = wp->w_ntrows - 2;
  5367.             else if (newsize < 1)
  5368.             newsize = 1;
  5369.             splitwind(TRUE, 1);
  5370.             resize(TRUE, newsize);
  5371.         }
  5372.         }
  5373.         (void) update(TRUE);
  5374.         break;
  5375.     }
  5376.     i++;
  5377.     }
  5378. }
  5379.  
  5380.  
  5381. #if MOTIF_WIDGETS
  5382. static void
  5383. pane_button(
  5384.     Widget    w,
  5385.     XtPointer    unused,
  5386.     XEvent     *ev,
  5387.     Boolean    *continue_to_dispatch)
  5388. {
  5389.     lookfor_sb_resize = TRUE;
  5390. }
  5391. #endif /* MOTIF_WIDGETS */
  5392.  
  5393. /*ARGSUSED*/
  5394. static void
  5395. x_change_focus(
  5396.     Widget    w,
  5397.     XtPointer    unused GCC_UNUSED,
  5398.     XEvent     *ev,
  5399.     Boolean    *continue_to_dispatch GCC_UNUSED)
  5400. {
  5401.     static int got_focus_event = FALSE;
  5402.  
  5403.     switch (ev->type) {
  5404.     case EnterNotify:
  5405.         if (!ev->xcrossing.focus || got_focus_event)
  5406.         return;
  5407.         goto focus_in;
  5408.     case FocusIn:
  5409.         got_focus_event = TRUE;
  5410. focus_in:
  5411.         cur_win->show_cursor = True;
  5412. #if MOTIF_WIDGETS
  5413.         XmProcessTraversal(cur_win->screen, XmTRAVERSE_CURRENT);
  5414. #else /* OL_WIDGETS || NO_WIDGETS */
  5415.         XtSetKeyboardFocus(w, cur_win->screen);
  5416. #endif
  5417.         x_flush();
  5418.         break;
  5419.     case LeaveNotify:
  5420.         if ( !ev->xcrossing.focus
  5421.           || got_focus_event
  5422.           || ev->xcrossing.detail == NotifyInferior)
  5423.         return;
  5424.         goto focus_out;
  5425.     case FocusOut:
  5426.         got_focus_event = TRUE;
  5427. focus_out:
  5428.         cur_win->show_cursor = False;
  5429.         x_flush();
  5430.         break;
  5431.     }
  5432. }
  5433.  
  5434. /*ARGSUSED*/
  5435. static void
  5436. x_wm_delwin(
  5437.     Widget    w GCC_UNUSED,
  5438.     XtPointer    unused GCC_UNUSED,
  5439.     XEvent     *ev,
  5440.     Boolean    *continue_to_dispatch GCC_UNUSED)
  5441. {
  5442.     if ( ev->type == ClientMessage
  5443.       && ev->xclient.message_type == atom_WM_PROTOCOLS
  5444.       && (Atom) ev->xclient.data.l[0] == atom_WM_DELETE_WINDOW) {
  5445.     quit(FALSE, 0);        /* quit might not return */
  5446.     (void) update(TRUE);
  5447.     }
  5448. }
  5449.  
  5450. /*
  5451.  * Return true if we want to disable reports of the cursor position because the
  5452.  * cursor really should be on the message-line.
  5453.  */
  5454. #if UNUSED
  5455. int
  5456. x_on_msgline(void)
  5457. {
  5458.     return reading_msg_line || cur_win->was_on_msgline;
  5459. }
  5460. #endif
  5461.  
  5462. /*
  5463.  * Because we poll our input-characters in 'x_getc()', it is possible to have
  5464.  * exposure-events pending while doing lengthy processes (e.g., reading from a
  5465.  * pipe).  This procedure is invoked from a timer-handler and is designed to
  5466.  * handle the exposure-events, and to get keypress-events (i.e., for stopping a
  5467.  * lengthy process).
  5468.  */
  5469. void
  5470. x_move_events(void)
  5471. {
  5472.     XEvent ev;
  5473.  
  5474.     while (x_has_events()
  5475.         && !kqfull(cur_win)) {
  5476.  
  5477.     /* Get and dispatch next event */
  5478.     XtAppNextEvent(cur_win->app_context, &ev);
  5479.  
  5480.     /*
  5481.      * Ignore or save certain events which could get us into trouble with
  5482.      * reentrancy.
  5483.      */
  5484.     switch (ev.type) {
  5485.         case ButtonPress :
  5486.         case ButtonRelease :
  5487.         case MotionNotify :
  5488.         /* Ignore the event */
  5489.         continue;
  5490.  
  5491.         case ClientMessage :
  5492.         case SelectionClear :
  5493.         case SelectionNotify :
  5494.         case SelectionRequest :
  5495.         case ConfigureNotify :
  5496.         case ConfigureRequest :
  5497.         case PropertyNotify :
  5498.         case ReparentNotify :
  5499.         case ResizeRequest :
  5500.         /* Queue for later processing.  */
  5501.         evqadd(&ev);
  5502.         continue;
  5503.  
  5504.         default :
  5505.         /* do nothing here...we'll dispatch the event below */
  5506.         break;
  5507.     }
  5508.  
  5509.     XtDispatchEvent(&ev);
  5510.  
  5511.     /*
  5512.      * If the event was a keypress, check it to see if it was an
  5513.      * interrupt character.  We check here to make sure that the
  5514.      * queue was non-empty, because not all keypresses put
  5515.      * characters into the queue.  We assume that intrc will not
  5516.      * appear in any multi-character sequence generated by a key
  5517.      * press, or that if it does, it will be the last character in
  5518.      * the sequence.  If this is a bad assumption, we will have to
  5519.      * keep track of what the state of the queue was prior to the
  5520.      * keypress and scan the characters added to the queue as a
  5521.      * result of the keypress.
  5522.      */
  5523.  
  5524.     if (!kqempty(cur_win) && ev.type == KeyPress) {
  5525.         int c = kqpop(cur_win);
  5526.         if (c == intrc) {
  5527.         kqadd(cur_win, abortc);
  5528. #if SYS_VMS
  5529.         kbd_alarm(); /* signals? */
  5530. #else
  5531.         (void)signal_pg(SIGINT);
  5532. #endif
  5533.         }
  5534.         else
  5535.         kqadd(cur_win, c);
  5536.     }
  5537.     }
  5538. }
  5539.  
  5540. #if OPT_WORKING
  5541. void
  5542. x_working(void)
  5543. {
  5544.     cur_win->want_to_work = TRUE;
  5545. }
  5546.  
  5547. static int
  5548. x_has_events(void)
  5549. {
  5550.     if (cur_win->want_to_work == TRUE) {
  5551.     x_set_watch_cursor(TRUE);
  5552.     cur_win->want_to_work = FALSE;
  5553.     }
  5554.     return (XtAppPending(cur_win->app_context) & XtIMXEvent);
  5555. }
  5556.  
  5557. static void
  5558. x_set_watch_cursor(int onflag)
  5559. {
  5560.     static int watch_is_on = FALSE;
  5561. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  5562.     int i;
  5563. #endif
  5564.  
  5565.     if (onflag == watch_is_on)
  5566.     return;
  5567.  
  5568.     watch_is_on = onflag;
  5569.  
  5570.     if (onflag) {
  5571.     set_pointer(XtWindow(cur_win->screen), cur_win->watch_pointer);
  5572. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  5573.     for (i=0; i<cur_win->nscrollbars; i++) {
  5574.         set_pointer(
  5575.             XtWindow(cur_win->scrollbars[i]), cur_win->watch_pointer);
  5576.         if (i < cur_win->nscrollbars-1)
  5577.         set_pointer(
  5578.             XtWindow(cur_win->grips[i]), cur_win->watch_pointer);
  5579.     }
  5580. #endif /* OPT_KEV_SCROLLBARS */
  5581.     }
  5582.     else {
  5583.     set_pointer(XtWindow(cur_win->screen), cur_win->normal_pointer);
  5584. #if OPT_KEV_SCROLLBARS || OPT_XAW_SCROLLBARS
  5585.     for (i=0; i<cur_win->nscrollbars; i++) {
  5586.         set_pointer(
  5587.             XtWindow(cur_win->scrollbars[i]),
  5588.             curs_sb_v_double_arrow);
  5589.         if (i < cur_win->nscrollbars-1)
  5590.         set_pointer(
  5591.             XtWindow(cur_win->grips[i]),
  5592.             curs_double_arrow);
  5593.     }
  5594. #endif /* OPT_KEV_SCROLLBARS */
  5595.     }
  5596. }
  5597. #endif /* OPT_WORKING */
  5598.  
  5599. static int
  5600. evqempty(void)
  5601. {
  5602.     return evqhead == NULL;
  5603. }
  5604.  
  5605. static void
  5606. evqadd(const XEvent *evp)
  5607. {
  5608.     struct eventqueue * newentry;
  5609.     newentry = typealloc(struct eventqueue);
  5610.     if (newentry == NULL)
  5611.     return;            /* FIXME: Need method for indicating error */
  5612.     newentry->next = NULL;
  5613.     newentry->event = *evp;
  5614.     if (evqhead == NULL)
  5615.     evqhead = evqtail = newentry;
  5616.     else {
  5617.     evqtail->next = newentry;
  5618.     evqtail = newentry;
  5619.     }
  5620. }
  5621.  
  5622. static void
  5623. evqdel(XEvent *evp)
  5624. {
  5625.     struct eventqueue *delentry = evqhead;
  5626.     if (delentry == NULL)
  5627.     return;            /* should not happen */
  5628.     *evp = delentry->event;
  5629.     evqhead = delentry->next;
  5630.     if (evqhead == NULL)
  5631.     evqtail = NULL;
  5632.     free((char *)delentry);
  5633. }
  5634.  
  5635. static void
  5636. kqinit(TextWindow tw)
  5637. {
  5638.     tw->kqhead = 0;
  5639.     tw->kqtail = 0;
  5640. }
  5641.  
  5642. static int
  5643. kqempty(TextWindow tw)
  5644. {
  5645.     return tw->kqhead == tw->kqtail;
  5646. }
  5647.  
  5648. static int
  5649. kqfull(TextWindow tw)
  5650. {
  5651.     return tw->kqhead == (tw->kqtail + 1) % KQSIZE;
  5652. }
  5653.  
  5654. static int
  5655. kqdel(TextWindow tw)
  5656. {
  5657.     int c;
  5658.     c = tw->kq[tw->kqhead];
  5659.     tw->kqhead = (tw->kqhead + 1) % KQSIZE;
  5660.     return c;
  5661. }
  5662.  
  5663. static void
  5664. kqadd(
  5665.     TextWindow tw,
  5666.     int c)
  5667. {
  5668.     tw->kq[tw->kqtail] = c;
  5669.     tw->kqtail = (tw->kqtail + 1) % KQSIZE;
  5670. }
  5671.  
  5672. static int
  5673. kqpop(TextWindow tw)
  5674. {
  5675.     if (--(tw->kqtail) < 0)
  5676.     tw->kqtail = KQSIZE-1;
  5677.     return (tw->kq[tw->kqtail]);
  5678. }
  5679.  
  5680. /*ARGSUSED*/
  5681. static void
  5682. display_cursor(
  5683.     XtPointer client_data GCC_UNUSED,
  5684.     XtIntervalId *idp)
  5685. {
  5686.     static Bool am_blinking = FALSE;
  5687.     int the_col = (ttcol >= term.t_ncol) ? term.t_ncol - 1 : ttcol;
  5688.  
  5689.     /*
  5690.      * Return immediately if we are either in the process of making a
  5691.      * selection (by wiping with the mouse) or if the cursor is already
  5692.      * displayed and display_cursor() is being called explicitly from the
  5693.      * event loop in x_getc.
  5694.      */
  5695.     if (cur_win->wipe_permitted) {
  5696.     am_blinking = FALSE;
  5697.     if (cur_win->blink_id != (XtIntervalId) 0) {
  5698.         XtRemoveTimeOut(cur_win->blink_id);
  5699.         cur_win->blink_id = (XtIntervalId) 0;
  5700.     }
  5701.     return;
  5702.     }
  5703.  
  5704.     if (IS_DIRTY(ttrow,the_col) && idp == (XtIntervalId *) 0)
  5705.     return;
  5706.  
  5707.     if (cur_win->show_cursor) {
  5708.     if ( cur_win->blink_interval > 0
  5709.       || ( cur_win->blink_interval < 0 && IS_REVERSED(ttrow, the_col) )) {
  5710.         if (idp != (XtIntervalId *) 0 || !am_blinking) {
  5711.         /* Set timer to get blinking */
  5712.         cur_win->blink_id = XtAppAddTimeOut(
  5713.             cur_win->app_context,
  5714.             (unsigned long) max(cur_win->blink_interval,
  5715.                                 -cur_win->blink_interval),
  5716.             display_cursor,
  5717.             (XtPointer) 0);
  5718.         cur_win->blink_status ^= BLINK_TOGGLE;
  5719.         am_blinking = TRUE;
  5720.         }
  5721.         else
  5722.         cur_win->blink_status &= ~BLINK_TOGGLE;
  5723.     }
  5724.     else {
  5725.         am_blinking = FALSE;
  5726.         cur_win->blink_status &= ~BLINK_TOGGLE;
  5727.         if (cur_win->blink_id != (XtIntervalId) 0) {
  5728.         XtRemoveTimeOut(cur_win->blink_id);
  5729.         cur_win->blink_id = (XtIntervalId) 0;
  5730.         }
  5731.     }
  5732.  
  5733.     MARK_CELL_DIRTY(ttrow,the_col);
  5734.     MARK_LINE_DIRTY(ttrow);
  5735.     flush_line(&CELL_TEXT(ttrow,the_col), 1,
  5736.                (unsigned int) (VATTRIB(CELL_ATTR(ttrow,the_col))
  5737.                         ^ ((cur_win->blink_status & BLINK_TOGGLE)
  5738.                   ? 0 : VACURS)),
  5739.            ttrow, the_col);
  5740.     }
  5741.     else {
  5742.     /* This code will get called when the window no longer has the focus. */
  5743.     if (cur_win->blink_id != (XtIntervalId) 0) {
  5744.         XtRemoveTimeOut(cur_win->blink_id);
  5745.         cur_win->blink_id = (XtIntervalId) 0;
  5746.     }
  5747.     am_blinking = FALSE;
  5748.     MARK_CELL_DIRTY(ttrow,the_col);
  5749.     MARK_LINE_DIRTY(ttrow);
  5750.     flush_line(&CELL_TEXT(ttrow,the_col), 1,
  5751.         (unsigned int) VATTRIB(CELL_ATTR(ttrow,the_col)), ttrow, the_col);
  5752.     XDrawRectangle(dpy, cur_win->win,
  5753.                    IS_REVERSED(ttrow,the_col) ? cur_win->cursgc
  5754.                                         : cur_win->revcursgc,
  5755.                    x_pos(cur_win, ttcol), y_pos(cur_win, ttrow),
  5756.                (unsigned)(cur_win->char_width - 1),
  5757.                (unsigned)(cur_win->char_height - 1));
  5758.     }
  5759. }
  5760.  
  5761.  
  5762. /*
  5763.  * main event loop.  this means we'll be stuck if an event that needs
  5764.  * instant processing comes in while its off doing other work, but
  5765.  * there's no (easy) way around that.
  5766.  */
  5767. static int
  5768. x_getc(void)
  5769. {
  5770.     int c;
  5771.  
  5772.     while (!evqempty()) {
  5773.     XEvent ev;
  5774.     evqdel(&ev);
  5775.     XtDispatchEvent(&ev);
  5776.     }
  5777. #if OPT_WORKING
  5778.     x_set_watch_cursor(FALSE);
  5779. #endif
  5780.     for_ever {
  5781.  
  5782.     if (tb_more(PasteBuf)) {    /* handle any queued pasted text */
  5783.         c = tb_next(PasteBuf);
  5784.         c |= NOREMAP;    /* pasted chars are not subject to mapping */
  5785.         cur_win->pasting = True;
  5786.         break;
  5787.     } else if (cur_win->pasting) {
  5788.         /*
  5789.          * Set the default position for new pasting to just past the newly
  5790.          * inserted text.
  5791.          */
  5792.         if (DOT.o < llength(DOT.l) && !insertmode)
  5793.         DOT.o++;        /* Advance DOT so that consecutive
  5794.                        pastes come out right */
  5795.         cur_win->pasting = False;
  5796.         update(TRUE);    /* make sure ttrow & ttcol are valid */
  5797.     }
  5798.  
  5799.     if (!kqempty(cur_win)) {
  5800.         c = kqdel(cur_win);
  5801.         break;
  5802.     }
  5803.  
  5804.     /*
  5805.      * Get and dispatch as many X events as possible.  This permits
  5806.      * the editor to catch up if it gets behind in processing keyboard
  5807.      * events since the keyboard queue will likely have something in it.
  5808.      * update() will check for typeahead and will defer its processing
  5809.      * until there is nothing more in the keyboard queue.
  5810.      */
  5811.  
  5812.     do {
  5813.         XEvent ev;
  5814.         XtAppNextEvent(cur_win->app_context, &ev);
  5815.         XtDispatchEvent(&ev);
  5816.     } while (x_has_events()
  5817.         && !kqfull(cur_win));
  5818.     }
  5819.  
  5820.     return c;
  5821. }
  5822.  
  5823. /*
  5824.  * Another event loop used for determining type-ahead.
  5825.  */
  5826. int
  5827. x_typahead(
  5828.     int milli)        /* milliseconds to wait for type-ahead */
  5829. {
  5830.     int status;
  5831.     XtIntervalId timeoutid = 0;
  5832.     int timedout;
  5833.     int olddkr;
  5834.  
  5835.     if (!cur_win->exposed)
  5836.     return FALSE;
  5837.  
  5838.     olddkr = im_waiting(TRUE);
  5839.  
  5840.     status = !kqempty(cur_win) || tb_more(PasteBuf);
  5841.  
  5842.     if (!status) {
  5843.  
  5844.     if (milli) {
  5845.         timedout = 0;
  5846.         timeoutid = XtAppAddTimeOut(
  5847.                 cur_win->app_context,
  5848.                 (ULONG) milli,
  5849.                 x_typahead_timeout,
  5850.                 (XtPointer) &timedout);
  5851.     }
  5852.     else
  5853.         timedout = 1;
  5854.  
  5855.     while (kqempty(cur_win) && !evqempty()) {
  5856.         XEvent ev;
  5857.         evqdel(&ev);
  5858.         XtDispatchEvent(&ev);
  5859.     }
  5860. #if OPT_WORKING
  5861.     x_set_watch_cursor(FALSE);
  5862. #endif
  5863.  
  5864.     /*
  5865.      * Process pending events until we get some keyboard input.
  5866.      * Note that we do not block here.
  5867.      */
  5868.     while (kqempty(cur_win) &&
  5869.         x_has_events()) {
  5870.         XEvent ev;
  5871.         XtAppNextEvent(cur_win->app_context, &ev);
  5872.         XtDispatchEvent(&ev);
  5873.     }
  5874.  
  5875.     /* Now wait for timer and process events as necessary. */
  5876.     while (!timedout && kqempty(cur_win)) {
  5877.         XtAppProcessEvent(cur_win->app_context, (XtInputMask)XtIMAll);
  5878.     }
  5879.  
  5880.     if (!timedout)
  5881.         XtRemoveTimeOut(timeoutid);
  5882.  
  5883.     status = !kqempty(cur_win);
  5884.     }
  5885.  
  5886.     (void) im_waiting(olddkr);
  5887.  
  5888.     return status;
  5889. }
  5890.  
  5891. /*ARGSUSED*/
  5892. static void
  5893. x_typahead_timeout(
  5894.     XtPointer flagp,
  5895.     XtIntervalId *id GCC_UNUSED)
  5896. {
  5897.     * (int *) flagp = 1;
  5898. }
  5899.  
  5900. /*ARGSUSED*/
  5901. static void
  5902. x_key_press(
  5903.     Widget    w GCC_UNUSED,
  5904.     XtPointer    unused GCC_UNUSED,
  5905.     XEvent     *ev,
  5906.     Boolean    *continue_to_dispatch GCC_UNUSED)
  5907. {
  5908.     char    buffer[128];
  5909.     KeySym    keysym;
  5910.     int        num;
  5911.  
  5912.     register int i;
  5913.     register SIZE_T n;
  5914.  
  5915.     static const struct {
  5916.     KeySym  key;
  5917.     int     code;
  5918.     } escapes[] = {
  5919.     /* Arrow keys */
  5920.     {XK_Up,      KEY_Up},
  5921.     {XK_Down,    KEY_Down},
  5922.     {XK_Right,   KEY_Right},
  5923.     {XK_Left,    KEY_Left},
  5924.     /* page scroll */
  5925.     {XK_Next,    KEY_Next},
  5926.     {XK_Prior,   KEY_Prior},
  5927.     {XK_Home,    KEY_Home},
  5928.     {XK_End,     KEY_End},
  5929.     /* editing */
  5930.     {XK_Insert,  KEY_Insert},
  5931.     {XK_Find,    KEY_Find},
  5932.     {XK_Select,  KEY_Select},
  5933.     /* command keys */
  5934.     {XK_Menu,    KEY_Menu},
  5935.     {XK_Help,    KEY_Help},
  5936.     /* function keys */
  5937.     {XK_F1,      KEY_F1},
  5938.     {XK_F2,      KEY_F2},
  5939.     {XK_F3,      KEY_F3},
  5940.     {XK_F4,      KEY_F4},
  5941.     {XK_F5,      KEY_F5},
  5942.     {XK_F6,      KEY_F6},
  5943.     {XK_F7,      KEY_F7},
  5944.     {XK_F8,      KEY_F8},
  5945.     {XK_F9,      KEY_F9},
  5946.     {XK_F10,     KEY_F10},
  5947.     {XK_F11,     KEY_F11},
  5948.     {XK_F12,     KEY_F12},
  5949.     {XK_F13,     KEY_F13},
  5950.     {XK_F14,     KEY_F14},
  5951.     {XK_F15,     KEY_F15},
  5952.     {XK_F16,     KEY_F16},
  5953.     {XK_F17,     KEY_F17},
  5954.     {XK_F18,     KEY_F18},
  5955.     {XK_F19,     KEY_F19},
  5956.     {XK_F20,     KEY_F20},
  5957. #if defined(XK_F21) && defined(KEY_F21)
  5958.     {XK_F21,     KEY_F21},
  5959.     {XK_F22,     KEY_F22},
  5960.     {XK_F23,     KEY_F23},
  5961.     {XK_F24,     KEY_F24},
  5962.     {XK_F25,     KEY_F25},
  5963.     {XK_F26,     KEY_F26},
  5964.     {XK_F27,     KEY_F27},
  5965.     {XK_F28,     KEY_F28},
  5966.     {XK_F29,     KEY_F29},
  5967.     {XK_F30,     KEY_F30},
  5968.     {XK_F31,     KEY_F31},
  5969.     {XK_F32,     KEY_F32},
  5970.     {XK_F33,     KEY_F33},
  5971.     {XK_F34,     KEY_F34},
  5972.     {XK_F35,     KEY_F35},
  5973. #endif
  5974.     /* keypad function keys */
  5975.     {XK_KP_F1,   KEY_KP_F1},
  5976.     {XK_KP_F2,   KEY_KP_F2},
  5977.     {XK_KP_F3,   KEY_KP_F3},
  5978.     {XK_KP_F4,   KEY_KP_F4}
  5979.     };
  5980.  
  5981.     if (ev->type != KeyPress)
  5982.     return;
  5983.  
  5984.     num = XLookupString((XKeyPressedEvent *) ev, buffer, sizeof(buffer),
  5985.         &keysym, (XComposeStatus *) 0);
  5986.  
  5987.     if (num <= 0) {
  5988.     for (n = 0; n < TABLESIZE(escapes); n++) {
  5989.         if (keysym == escapes[n].key) {
  5990.         kqadd(cur_win, escapes[n].code);
  5991.         return;
  5992.         }
  5993.     }
  5994.     }
  5995.     else if (num == 1 && (ev->xkey.state & Mod1Mask))
  5996.     buffer[0] |= HIGHBIT;
  5997.  
  5998.     /* FIXME: Should do something about queue full conditions */
  5999.     if (num > 0) {
  6000.     for (i=0; i<num && !kqfull(cur_win); i++)
  6001.         kqadd(cur_win, char2int(buffer[i]));
  6002.     }
  6003. }
  6004.  
  6005. /*
  6006.  * change reverse video status
  6007.  */
  6008. static void
  6009. x_rev(UINT state)
  6010. {
  6011.     cur_win->reverse = state;
  6012. }
  6013.  
  6014. /* change screen resolution */
  6015. /*ARGSUSED*/
  6016. static int
  6017. x_cres(const char *flag GCC_UNUSED)
  6018. {
  6019.     return TRUE;
  6020. }
  6021.  
  6022. #if OPT_COLOR
  6023. static void
  6024. x_fcol(int color)
  6025. {
  6026. }
  6027.  
  6028. static void
  6029. x_bcol(int color)
  6030. {
  6031. }
  6032.  
  6033. #endif
  6034.  
  6035. /* beep */
  6036. static void
  6037. x_beep(void)
  6038. {
  6039. #if OPT_FLASH
  6040.     if (global_g_val(GMDFLASH)) {
  6041.     beginDisplay();
  6042.     XGrabServer(dpy);
  6043.     XSetFunction(dpy, cur_win->textgc, GXxor);
  6044.     XSetBackground(dpy, cur_win->textgc, 0L);
  6045.     XSetForeground(dpy, cur_win->textgc, cur_win->fg ^ cur_win->bg);
  6046.     XFillRectangle(dpy, cur_win->win, cur_win->textgc,
  6047.                0, 0, x_width(cur_win), x_height(cur_win));
  6048.     XFlush(dpy);
  6049.     catnap(90, FALSE);
  6050.     XFillRectangle(dpy, cur_win->win, cur_win->textgc,
  6051.                0, 0, x_width(cur_win), x_height(cur_win));
  6052.     XFlush(dpy);
  6053.     XSetFunction(dpy, cur_win->textgc, GXcopy);
  6054.     XSetBackground(dpy, cur_win->textgc, cur_win->bg);
  6055.     XSetForeground(dpy, cur_win->textgc, cur_win->fg);
  6056.     XUngrabServer(dpy);
  6057.     endofDisplay();
  6058.     }
  6059.     else
  6060. #endif
  6061.     XBell(dpy, 0);
  6062. }
  6063.  
  6064. #if NO_LEAKS
  6065. void
  6066. x11_leaks(void)
  6067. {
  6068.     if (cur_win != 0) {
  6069.         FreeIfNeeded(cur_win->fontname);
  6070.     }
  6071. }
  6072. #endif    /* NO_LEAKS */
  6073.  
  6074. char x_window_name[NFILEN];
  6075. char x_icon_name[NFILEN];
  6076.  
  6077. void
  6078. x_set_icon_name(const char *name)
  6079. {
  6080.     XTextProperty Prop;
  6081.  
  6082.     (void)strncpy0(x_icon_name, name, NFILEN);
  6083.  
  6084.     Prop.value = (unsigned char *)x_icon_name;
  6085.     Prop.encoding = XA_STRING;
  6086.     Prop.format = 8;
  6087.     Prop.nitems = strlen(x_icon_name);
  6088.  
  6089.     XSetWMIconName(dpy,XtWindow(cur_win->top_widget),&Prop);
  6090. }
  6091.  
  6092. char *
  6093. x_get_icon_name(void)
  6094. {
  6095.     return x_icon_name;
  6096. }
  6097.  
  6098. void
  6099. x_set_window_name(const char *name)
  6100. {
  6101.     XTextProperty Prop;
  6102.  
  6103.     (void)strncpy0(x_window_name, name, NFILEN);
  6104.  
  6105.     Prop.value = (unsigned char *)x_window_name;
  6106.     Prop.encoding = XA_STRING;
  6107.     Prop.format = 8;
  6108.     Prop.nitems = strlen(x_window_name);
  6109.  
  6110.     XSetWMName(dpy,XtWindow(cur_win->top_widget),&Prop);
  6111. }
  6112.  
  6113. char *
  6114. x_get_window_name(void)
  6115. {
  6116.     return x_window_name;
  6117. }
  6118.  
  6119. static void
  6120. watched_input_callback(XtPointer fd,
  6121.                        int *src GCC_UNUSED,
  6122.                XtInputId *id GCC_UNUSED)
  6123. {
  6124.     dowatchcallback((int) fd);
  6125. }
  6126.  
  6127. static int
  6128. x_watchfd(int fd, WATCHTYPE type, long *idp)
  6129. {
  6130.     *idp = (long) XtAppAddInput(
  6131.             cur_win->app_context,
  6132.             fd,
  6133.             (XtPointer) ((type & WATCHREAD)  ? XtInputReadMask :
  6134.                          (type & WATCHWRITE) ? XtInputWriteMask
  6135.                                  : XtInputExceptMask),
  6136.             watched_input_callback,
  6137.             (XtPointer) fd);
  6138.     return TRUE;
  6139. }
  6140.  
  6141. static void
  6142. x_unwatchfd(int fd GCC_UNUSED, long id)
  6143. {
  6144.     XtRemoveInput((XtInputId) id);
  6145. }
  6146.  
  6147. /*
  6148.  * Return true if the given character would be printable.  Not all characters are.
  6149.  */
  6150. int
  6151. gui_isprint(int ch)
  6152. {
  6153.     XFontStruct *pf = cur_win->pfont;
  6154.     XCharStruct    *pc = 0;
  6155.  
  6156.     if (pf != 0
  6157.      && pf->per_char != 0
  6158.      && !pf->all_chars_exist) {
  6159.     if (pf->min_byte1 == 0
  6160.      && pf->max_byte1 == 0) {
  6161.         pc = pf->per_char + (ch - pf->min_char_or_byte2);
  6162.     } /* FIXME: this does not handle doublebyte characters */
  6163.     if (pc != 0
  6164.      && (pc->lbearing + pc->rbearing) == 0
  6165.      && (pc->ascent   + pc->descent) == 0
  6166.      && pc->width == 0) {
  6167.         return FALSE;
  6168.     }
  6169.     }
  6170.     return TRUE;
  6171. }
  6172.  
  6173. #endif    /* DISP_X11 && XTOOLKIT */
  6174.