home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume9 / xterm / part03 / button.c next >
Encoding:
C/C++ Source or Header  |  1987-04-20  |  28.1 KB  |  1,177 lines

  1. /*
  2.  *    $Source: /u1/X/xterm/RCS/button.c,v $
  3.  *    $Header: button.c,v 10.103 86/12/02 09:49:20 swick Exp $
  4.  */
  5.  
  6. #include <X/mit-copyright.h>
  7.  
  8. /* Copyright    Massachusetts Institute of Technology    1984, 1985    */
  9. /*
  10. button.c    Handles button events in the terminal emulator.
  11.         does cut/paste operations, change modes via menu,
  12.         passes button events through to some applications.
  13.                 J. Gettys.
  14. */
  15. #ifndef lint
  16. static char sccs_id[] = "@(#)button.c\tX10/6.6B\t12/26/86";
  17. #endif    lint
  18. #include <stdio.h>
  19. #include <signal.h>
  20. #include <setjmp.h>
  21. #include <ctype.h>
  22. #include <X/Xlib.h>
  23. #include "scrollbar.h"
  24. #include "ptyx.h"
  25. #include "data.h"
  26. #include "error.h"
  27. #ifdef MODEMENU
  28. #include "menu.h"
  29. #endif MODEMENU
  30.  
  31. #define NBUTS 3
  32. #define DIRS 2
  33. #define UP 1
  34. #define DOWN 0
  35. #define SHIFTS 8        /* three keys, so eight combinations */
  36. #define    Coordinate(r,c)        ((r) * ncols + (c))
  37.  
  38. char *GetRestOfLine();
  39. char *SaveText();
  40. extern UnSaltText();
  41. extern StartCut();
  42. extern ReExecute();
  43. extern EditorDown();
  44.  
  45. extern ButtonUp();
  46. extern DownButtonDown();
  47. extern MiddleButtonDown();
  48. extern UpButtonDown();
  49. extern ModeMenu();
  50. extern char *xterm_name;
  51. extern Bogus(), Silence();
  52. extern GINbutton();
  53. /* due to LK201 limitations, not all of the below are actually possible */
  54. static int (*bfunc[SHIFTS][DIRS][NBUTS])() = {
  55. /*    left        middle        right    */
  56.     EditorDown,    EditorDown,    EditorDown,    /* down    |      */
  57.     Silence,    Silence,    Silence,    /* up    |no shift */
  58.  
  59.     ReExecute,    StartCut,    Silence,    /* down |      */
  60.     Silence,    Silence,    UnSaltText,    /* up    |shift      */
  61.  
  62.     Bogus,        Bogus,        Bogus,        /* down    |      */
  63.     Silence,    Silence,    Silence,    /* up    |meta      */
  64.  
  65.     Bogus,        Bogus,        Bogus,        /* down    |      */
  66.     Silence,    Silence,    Silence,    /* up    |meta shift */
  67.  
  68.     ModeMenu,    ModeMenu,    ModeMenu,    /* down    |      */
  69.     Silence,    Silence,    Silence,    /* up    |control  */
  70.  
  71.     Bogus,        Bogus,        Bogus,        /* down    |      */
  72.     Silence,    Silence,    Silence,    /* up    |ctl shift */
  73.  
  74.     Bogus,        Bogus,        Bogus,        /* down    |      */
  75.     Silence,    Silence,    Silence,    /* up    |no shift */
  76.  
  77.     Bogus,        Bogus,        Bogus,        /* down    | control  */
  78.     Silence,    Silence,    Silence        /* up    |meta shift*/
  79.  
  80. };    /* button, shift keys, and direction */
  81. static int (*tfunc[SHIFTS][DIRS][NBUTS])() = {
  82. /*    left        middle        right    */
  83.     ModeMenu,    ModeMenu,    ModeMenu,    /* down    |      */
  84.     Silence,    Silence,    Silence,    /* up    |no shift */
  85.  
  86.     ModeMenu,    ModeMenu,    ModeMenu,    /* down |      */
  87.     Silence,    Silence,    Silence,    /* up    |shift      */
  88.  
  89.     Bogus,        Bogus,        Bogus,        /* down    |      */
  90.     Silence,    Silence,    Silence,    /* up    |meta      */
  91.  
  92.     Bogus,        Bogus,        Bogus,        /* down    |      */
  93.     Silence,    Silence,    Silence,    /* up    |meta shift */
  94.  
  95.     ModeMenu,    ModeMenu,    ModeMenu,    /* down    |      */
  96.     Silence,    Silence,    Silence,    /* up    |control  */
  97.  
  98.     ModeMenu,    ModeMenu,    ModeMenu,    /* down    |      */
  99.     Silence,    Silence,    Silence,    /* up    |ctl shift */
  100.  
  101.     Bogus,        Bogus,        Bogus,        /* down    |      */
  102.     Silence,    Silence,    Silence,    /* up    |no shift */
  103.  
  104.     Bogus,        Bogus,        Bogus,        /* down    | control  */
  105.     Silence,    Silence,    Silence        /* up    |meta shift*/
  106.  
  107. };    /* button, shift keys, and direction */
  108. static int (*scrollfunc[SHIFTS][DIRS][NBUTS])() = {
  109. /*    left        middle        right    */
  110.     UpButtonDown,    ModeMenu,    DownButtonDown,    /* down    |      */
  111.     ButtonUp,    Silence,    ButtonUp,    /* up    |no shift */
  112.  
  113.     UpButtonDown,    ModeMenu,    DownButtonDown,    /* down |      */
  114.     ButtonUp,    Silence,    ButtonUp,    /* up    |shift      */
  115.  
  116.     Bogus,        Bogus,        Bogus,        /* down    |      */
  117.     Silence,    Silence,    Silence,    /* up    |meta      */
  118.  
  119.     Bogus,        Bogus,        Bogus,        /* down    |      */
  120.     Silence,    Silence,    Silence,    /* up    |meta shift */
  121.  
  122.     UpButtonDown,    ModeMenu,    DownButtonDown,    /* down    |      */
  123.     ButtonUp,    Silence,    ButtonUp,    /* up    |control  */
  124.  
  125.     Bogus,        Bogus,        Bogus,        /* down    |      */
  126.     Silence,    Silence,    Silence,    /* up    |ctl shift */
  127.  
  128.     Bogus,        Bogus,        Bogus,        /* down    |      */
  129.     Silence,    Silence,    Silence,    /* up    |no shift */
  130.  
  131.     Bogus,        Bogus,        Bogus,        /* down    | control  */
  132.     Silence,    Silence,    Silence        /* up    |meta shift*/
  133.  
  134. };    /* button, shift keys, and direction */
  135. static int (*Tbfunc[SHIFTS][DIRS][NBUTS])() = {
  136. /*    left        middle        right    */
  137.     GINbutton,    GINbutton,    GINbutton,    /* down    |      */
  138.     Silence,    Silence,    Silence,    /* up    |no shift */
  139.  
  140.     GINbutton,    GINbutton,    GINbutton,    /* down |      */
  141.     Silence,    Silence,    Silence,    /* up    |shift      */
  142.  
  143.     Bogus,        Bogus,        Bogus,        /* down    |      */
  144.     Silence,    Silence,    Silence,    /* up    |meta      */
  145.  
  146.     Bogus,        Bogus,        Bogus,        /* down    |      */
  147.     Silence,    Silence,    Silence,    /* up    |meta shift */
  148.  
  149.     ModeMenu,    ModeMenu,    ModeMenu,    /* down    |      */
  150.     Silence,    Silence,    Silence,    /* up    |control  */
  151.  
  152.     Bogus,        Bogus,        Bogus,        /* down    |      */
  153.     Silence,    Silence,    Silence,    /* up    |ctl shift */
  154.  
  155.     Bogus,        Bogus,        Bogus,        /* down    |      */
  156.     Silence,    Silence,    Silence,    /* up    |no shift */
  157.  
  158.     Bogus,        Bogus,        Bogus,        /* down    | control  */
  159.     Silence,    Silence,    Silence        /* up    |meta shift*/
  160.  
  161. };    /* button, shift keys, and direction */
  162.  
  163. extern Terminal term;
  164.  
  165. static int crow, ccol;    /* cut row and column */
  166. static int ccoord;
  167. static int ncols;
  168.  
  169. HandleButtons(term, reply, pty)
  170. register Terminal *term;
  171. register XEvent *reply;
  172. int pty;            /* file descriptor of pty */
  173. {
  174.     register Screen *screen = &term->screen;
  175.     int (*bp)();
  176.     int dir = DOWN;
  177.     /* so table above will be nice, we change left to right */
  178.     int button = 2 - ((XKeyOrButtonEvent *)reply)->detail & 0177; 
  179.     int shift = KeyState(((XKeyOrButtonEvent *)reply)->detail);
  180.  
  181.     switch (reply->type) {
  182.         case ButtonPressed:
  183.             dir = DOWN;
  184.             break;
  185.         case ButtonReleased:
  186.             dir = UP;
  187.             break;
  188.         default:
  189.             break;
  190.     }
  191.     if(L_flag && !checklogin()) {    /* if login window, check for login */
  192.         if(dir == DOWN)
  193.             Bell();
  194.         return;
  195.     }
  196.     bp = (screen->sb && (reply->window == screen->sb->bar ||
  197.      GetButtonState(screen->sb) != BUTTON_NORMAL)) ?
  198.      scrollfunc[shift][dir][button] :
  199.      ((Titlebar(screen) && (reply->window == screen->title.tbar ||
  200.      reply->window == screen->Ttitle.tbar)) ? tfunc[shift][dir][button] :
  201.      ((reply->window == TWindow(screen)) ? Tbfunc[shift][dir][button] :
  202.      bfunc[shift][dir][button]));
  203.     if (bp != NULL)
  204.         (*bp)(term, reply, pty);
  205.     else
  206.         Bell();
  207. }
  208.  
  209. UnSaltText(term, reply, pty)
  210. register Terminal *term;
  211. register XKeyOrButtonEvent *reply;
  212. int pty;            /* file descriptor of pty */
  213. {
  214.     char *line;
  215.     int nbytes;
  216.     register char *lag, *cp, *end;
  217.  
  218.     line = XFetchBytes(&nbytes);
  219.     end = &line[nbytes];
  220.     lag = line;
  221.     for (cp = line; cp != end; cp++)
  222.     {
  223.         if (*cp != '\n') continue;
  224.         *cp = '\r';
  225.         write(pty, lag, cp - lag + 1);
  226.         lag = cp + 1;
  227.     }
  228.     if (lag != end)
  229.         write(pty, lag, end - lag);
  230.     free (line);    /* free text from fetch */
  231. }
  232.  
  233. ReExecute(term, reply, pty)
  234. register XKeyOrButtonEvent *reply;
  235. Terminal *term;
  236. int pty;
  237. {
  238.     XKeyOrButtonEvent xevent;
  239.     register XKeyOrButtonEvent *ev = &xevent;
  240.     register Screen *screen = &term->screen;
  241.     register int xrow, xcol, mask, cursor, ignore;
  242.     register char *line;
  243.     int row, col;
  244.  
  245.     cursor = screen->curs;
  246.     if(!XGrabMouse(VWindow(screen), cursor,
  247.      mask = ButtonReleased | EnterWindow | LeaveWindow | MouseMoved)) {
  248.         Bell();
  249.         return;
  250.     }
  251.     ncols = screen->max_col + 1;    /* needed by Coordinate() define */
  252.     if(NearestRowCol(reply->y, reply->x, &crow, &ccol) ||
  253.      crow > screen->max_row) {
  254.         Bell();
  255.         XUngrabMouse();
  256.         return;
  257.     }
  258.     xrow = crow;
  259.     xcol = ccol;
  260.     crow++;
  261.     ccol = 0;
  262.     ccoord = Coordinate(crow, ccol);
  263.     if (screen->cursor_state)
  264.         HideCursor ();
  265.     HiliteText(xrow, xcol, crow, 0, TRUE);
  266.     ignore = FALSE;
  267.     for( ; ; ) {
  268.         XMaskEvent(mask, ev);
  269.         switch(ev->type) {
  270.          case ButtonReleased:
  271.             if(xrow == crow - 1) {
  272.                 line = GetRestOfLine(screen, xrow, xcol);
  273.                 row = strlen(line);
  274.                 write(pty, line, row);
  275.                 line[row] = '\n';
  276.                 XStoreBytes(line, row);
  277.                 free (line);    /* free text from fetch */
  278.                 HiliteText(xrow, xcol, crow, 0, FALSE);
  279.             }
  280.             XUngrabMouse();
  281.             if (screen->cursor_set && !screen->cursor_state)
  282.                 ShowCursor ();
  283.             return;
  284.          case LeaveWindow:
  285.             if(ev->window != VWindow(screen))
  286.                 break;
  287.             if(xrow == crow - 1)
  288.                 HiliteText(xrow, xcol, crow, 0, FALSE);
  289.             xrow = crow;
  290.             xcol = 0;
  291.             XGrabMouse(VWindow(screen), cursor, mask & ~MouseMoved);
  292.             ignore = TRUE;
  293.             break;
  294.          case EnterWindow:
  295.             if(ev->window != VWindow(screen))
  296.                 break;
  297.             XGrabMouse(VWindow(screen), cursor, mask);
  298.             ignore = FALSE;
  299.                 /* drop through */
  300.          case MouseMoved:
  301.             if(ignore)
  302.                 break;
  303.             NearestRowCol(ev->y, ev->x, &row, &col);
  304.             if(row != crow - 1) {
  305.                 if(xrow == crow - 1)
  306.                     HiliteText(xrow, xcol, crow, 0, FALSE);
  307.             } else if(xrow == row)
  308.                 TrackText(xrow, xcol, row, col);
  309.             else
  310.                 HiliteText(row, col, crow, 0, TRUE);
  311.             xrow = row;
  312.             xcol = col;
  313.             break;
  314.         }
  315.     }
  316. }
  317.     
  318. char *GetRestOfLine(screen, row, col)
  319. register Screen *screen;
  320. register int row, col;
  321. {
  322.     char *line;
  323.     int i;
  324.  
  325.     i = Length(screen, row, col, screen->max_col);
  326.     if((line = (char *)malloc(i + 2)) == NULL)
  327.         SysError(ERROR_BMALLOC);
  328.     SaveText(screen, row, col, screen->max_col, line);
  329.     line[i] = '\r';
  330.     line[i+1] = '\0';
  331.     return(line);
  332. }
  333.  
  334. StartCut(term, reply, pty)
  335. register XKeyOrButtonEvent *reply;
  336. Terminal *term;
  337. int pty;
  338. {
  339.     XKeyOrButtonEvent xevent;
  340.     register XKeyOrButtonEvent *ev = &xevent;
  341.     register Screen *screen = &term->screen;
  342.     register int xrow, xcol, mask, cursor, ignore;
  343.     int row, col;
  344.  
  345.     cursor = screen->curs;
  346.     if(!XGrabMouse(VWindow(screen), cursor,
  347.      mask = ButtonReleased | EnterWindow | LeaveWindow | MouseMoved)) {
  348.         Bell();
  349.         return;
  350.     }
  351.     ncols = screen->max_col + 1;    /* needed by Coordinate() define */
  352.     NearestRowCol(reply->y, reply->x, &crow, &ccol);
  353.     ccoord = Coordinate(crow, ccol);
  354.     xrow = crow;
  355.     xcol = ccol;
  356.     ignore = FALSE;
  357.     if (screen->cursor_state)
  358.         HideCursor ();
  359.     for( ; ; ) {
  360.         XMaskEvent(mask, ev);
  361.         switch(ev->type) {
  362.          case ButtonReleased:
  363.             if(!ignore) {
  364.                 row = crow;
  365.                 col = ccol; /* SaltTextAway may alter these */
  366.                 SaltTextAway(term, xrow, xcol, pty);
  367.             }
  368.             HiliteText(row, col, xrow, xcol, FALSE);
  369.             XUngrabMouse();
  370.             if (screen->cursor_set && !screen->cursor_state)
  371.                 ShowCursor ();
  372.             return;
  373.          case LeaveWindow:
  374.             if(ev->window != VWindow(screen))
  375.                 break;
  376.             HiliteText(crow, ccol, xrow, xcol, FALSE);
  377.             xrow = crow;
  378.             xcol = ccol;
  379.             XGrabMouse(VWindow(screen), cursor, mask & ~MouseMoved);
  380.             ignore = TRUE;
  381.             break;
  382.          case EnterWindow:
  383.             if(ev->window != VWindow(screen))
  384.                 break;
  385.             XGrabMouse(VWindow(screen), cursor, mask);
  386.             ignore = FALSE;
  387.                 /* drop through */
  388.          case MouseMoved:
  389.             if(ignore)
  390.                 break;
  391.             NearestRowCol(ev->y, ev->x, &row, &col);
  392.             if(row != xrow || col != xcol) {
  393.                 TrackText(xrow, xcol, row, col);
  394.                 xrow = row;
  395.                 xcol = col;
  396.             }
  397.             break;
  398.         }
  399.     }
  400. }
  401.  
  402. int NearestRowCol(y, x, r, c)
  403. register int y, x;
  404. int *r, *c;
  405. {
  406.     register Screen *screen = &term.screen;
  407.     register row, col, i;
  408.     register char *ch;
  409.     register int passed_eol = FALSE;
  410.  
  411.     if((row = (y - screen->border - Titlebar(screen)) / FontHeight(screen))
  412.      < 0)
  413.         row = 0;
  414.     else if(row > screen->max_row)
  415.         row = screen->max_row;
  416.     i = FontWidth(screen);
  417.     if((col = (x - screen->border + (i / 3)) / i) < 0)
  418.         col = 0;
  419.     else if(col > screen->max_col + 1)
  420.         col = screen->max_col + 1;
  421.     if(col > 0) {
  422.         for(i = screen->max_col,
  423.          ch = screen->buf[2 * (row + screen->topline)] + i ;
  424.          i > 0 && *ch == 0 ; ch--, i--);
  425.         if(col > i + 1) {
  426.             col = 0;
  427.             row++;
  428.             passed_eol = TRUE;
  429.         }
  430.     }
  431.     *r = row;
  432.     *c = col;
  433.     return(passed_eol);
  434. }
  435.  
  436. TrackText(frow, fcol, trow, tcol)
  437. register int frow, fcol, trow, tcol;
  438. {
  439.     register int f, t;
  440.  
  441.     f = Coordinate(frow, fcol);
  442.     t = Coordinate(trow, tcol);
  443.     if(f == t)
  444.         return;
  445.     if(f > ccoord) {
  446.         if(t < ccoord) {
  447.             HiliteText(crow, ccol, frow, fcol, FALSE);
  448.             HiliteText(trow, tcol, crow, ccol, TRUE);
  449.         } else if(t > f)
  450.             HiliteText(frow, fcol, trow, tcol, TRUE);
  451.         else
  452.             HiliteText(trow, tcol, frow, fcol, FALSE);
  453.     } else {
  454.         if(t > ccoord) {
  455.             HiliteText(frow, fcol, crow, ccol, FALSE);
  456.             HiliteText(crow, ccol, trow, tcol, TRUE);
  457.         } else if(t < f)
  458.             HiliteText(trow, tcol, frow, fcol, TRUE);
  459.         else
  460.             HiliteText(frow, fcol, trow, tcol, FALSE);
  461.     }
  462. }
  463.  
  464. HiliteText(frow, fcol, trow, tcol, hilite)
  465. register int frow, fcol, trow, tcol;
  466. int hilite;
  467. {
  468.     register Screen *screen = &term.screen;
  469.     register int i, j;
  470.  
  471.     if((i = Coordinate(frow, fcol)) == (j = Coordinate(trow, tcol)))
  472.         return;
  473.     else if(i > j) {
  474.         i = frow;
  475.         j = fcol;
  476.         frow = trow;
  477.         fcol = tcol;
  478.         trow = i;
  479.         tcol = j;
  480.     }
  481.     if(hilite) {
  482.         i = screen->foreground;
  483.         screen->foreground = screen->background;
  484.         screen->background = i;
  485.     }
  486.     if(frow != trow) {    /* do multiple rows */
  487.         if((i = screen->max_col - fcol + 1) > 0) {    /* first row */
  488.             XPixSet(VWindow(screen), fcol * FontWidth(screen) +
  489.              screen->border, frow * FontHeight(screen) +
  490.              screen->border + Titlebar(screen), i * FontWidth(screen),
  491.              FontHeight(screen), screen->background);
  492.             ScrnRefresh(screen, frow, fcol, 1, i);
  493.         }
  494.         if((i = trow - frow - 1) > 0) {            /* middle rows*/
  495.             j = screen->max_col + 1;
  496.             XPixSet(VWindow(screen), screen->border, (frow + 1) *
  497.              FontHeight(screen) + screen->border + Titlebar(screen),
  498.              j * FontWidth(screen), i * FontHeight(screen),
  499.              screen->background);
  500.             ScrnRefresh(screen, frow + 1, 0, i, j);
  501.         }
  502.         if(tcol > 0 && trow <= screen->max_row) {    /* last row */
  503.             XPixSet(VWindow(screen), screen->border, trow *
  504.              FontHeight(screen) + screen->border + Titlebar(screen),
  505.              tcol * FontWidth(screen), FontHeight(screen),
  506.              screen->background);
  507.             ScrnRefresh(screen, trow, 0, 1, tcol);
  508.         }
  509.     } else {        /* do single row */
  510.         i = tcol - fcol;
  511.         XPixSet(VWindow(screen), fcol* FontWidth(screen) + screen->border,
  512.          frow * FontHeight(screen) + screen->border + Titlebar(screen),
  513.          i * FontWidth(screen), FontHeight(screen), screen->background);
  514.         ScrnRefresh(screen, frow, fcol, 1, tcol - fcol);
  515.     }
  516.     if(hilite) {
  517.         i = screen->foreground;
  518.         screen->foreground = screen->background;
  519.         screen->background = i;
  520.     }
  521. }
  522.  
  523. SaltTextAway(term, row, col, pty)
  524. Terminal *term;
  525. register row, col;
  526. int pty;
  527. {
  528.     register Screen *screen = &term->screen;
  529.     register int i, j = 0;
  530.     register char *str;        /* string to be saved */
  531.     char *line, *lp;
  532.  
  533.     /* first order of business is to guarantee that crow,ccol is before */
  534.     /* row,col. */
  535.     if ( row == crow ) {        /* must exchange as pairs */
  536.         if ( ccol > col ) {     /* may have to exchange columns */
  537.             register int tmp;
  538.             tmp = ccol; ccol = col; col = tmp;
  539.         }
  540.     }
  541.     else {
  542.         if ( crow > row ) {    /* may have to exchange row and col */
  543.             register int tmp;
  544.             tmp = ccol; ccol = col; col = tmp;
  545.             tmp = crow; crow = row; row = tmp;
  546.         }
  547.     }
  548.         
  549.     if (ccol < 0) ccol = 0;
  550.     else if (ccol > screen->max_col) { crow++; ccol = 0; }
  551.     if (crow < 0) crow = ccol = 0;
  552.     else if (crow > screen->max_row) { crow = screen->max_row; ccol = 0; }
  553.  
  554.     if (row > screen->max_row) { row = screen->max_row + 1 ; col = 0; }
  555.     else if (--col > screen->max_col) col = screen->max_col;
  556.  
  557.     /* first we need to know how long the string is before we can save it*/
  558.  
  559.     if ( row == crow ) j = Length(screen, crow, ccol, col);
  560.     else {    /* two cases, cut is on same line, cut spans multiple lines */
  561.         j += Length(screen, crow, ccol, screen->max_col) + 1;
  562.         for(i = crow + 1; i < row; i++) 
  563.             j += Length(screen, i, 0, screen->max_col) + 1;
  564.         if (col >= 0)
  565.             j += Length(screen, row, 0, col);
  566.     }
  567.     
  568.     /* now get some memory to save it in */
  569.  
  570.     if((line = (char *)malloc(j + 1)) == NULL)
  571.         SysError(ERROR_BMALLOC2);
  572.     line[j] = '\0';        /* make sure it is null terminated */
  573.     lp = line;        /* lp points to where to save the text */
  574.     if ( row == crow ) lp = SaveText(screen, row, ccol, col, lp);
  575.     else {
  576.         lp = SaveText(screen, crow, ccol, screen->max_col, lp);
  577.         *lp ++ = '\n';    /* put in newline at end of line */
  578.         for(i = crow +1; i < row; i++) {
  579.             lp = SaveText(screen, i, 0, screen->max_col, lp);
  580.             *lp ++ = '\n';
  581.             }
  582.         if (col >= 0)
  583.             lp = SaveText(screen, row, 0, col, lp);
  584.     }
  585.     *lp = '\0';        /* make sure we have end marked */
  586.     
  587.     XStoreBytes(line, j);
  588.     free(line);
  589. }
  590.  
  591. /* returns number of chars in line from scol to ecol out */
  592. int Length(screen, row, scol, ecol)
  593. register int row, scol, ecol;
  594. register Screen *screen;
  595. {
  596.     register char *ch;
  597.     int end = 0;
  598.  
  599.     ch = screen->buf[2 * (row + screen->topline)];
  600.     while (ecol >= scol && ch[ecol] == 0)
  601.         ecol--;
  602.     return (ecol - scol + 1);
  603. }
  604.  
  605. /* copies text into line, preallocated */
  606. char *SaveText(screen, row, scol, ecol, lp)
  607. int row;
  608. int scol, ecol;
  609. Screen *screen;
  610. register char *lp;        /* pointer to where to put the text */
  611. {
  612.     register int i = 0;
  613.     register char *ch = screen->buf[2 * (row + screen->topline)];
  614.     register int c;
  615.  
  616.     if ((i = Length(screen, row, scol, ecol)) == 0) return(lp);
  617.     ecol = scol + i;
  618.     for (i = scol; i < ecol; i++) {
  619.         if ((c = ch[i]) == 0)
  620.             c = ' ';
  621.         else if(c < ' ') {
  622.             if(c == '\036')
  623.                 c = '#';
  624.             else
  625.                 c += 0x5f;
  626.         } else if(c == 0x7f)
  627.             c = 0x5f;
  628.         *lp++ = c;
  629.     }
  630.     return(lp);
  631. }
  632.  
  633. EditorDown (term, reply, pty)
  634. Terminal *term;
  635. register XKeyOrButtonEvent *reply;
  636. int pty;            /* file descriptor of pty */
  637. {
  638.     register Screen *screen = &term->screen;
  639.     char line[6];
  640.     register unsigned row, col;
  641.     int button; 
  642.  
  643.     if (!screen->send_mouse_pos) {
  644.         Bell();
  645.         return;
  646.     }
  647.     button = 2 - reply->detail & 0177; 
  648.     row = (reply->y - screen->border - Titlebar(screen)) / FontHeight(screen);
  649.     col = (reply->x - screen->border) / FontWidth(screen);
  650.     strcpy(line, "\033[M");
  651.     line[3] = ' ' + button;
  652.     line[4] = ' ' + col + 1;
  653.     line[5] = ' ' + row + 1;
  654.     write(pty, line, 6);
  655. }
  656.  
  657. #ifdef MODEMENU
  658. #define    MAXWINDOWMENU    64
  659. #define    XTERMMENU    0
  660. #define    VTMENU        1
  661. #define    TEKMENU        2
  662. #define    SCROLLBARMENU    3
  663. #ifndef NOWINDOWMENU
  664. #define    WINDOWMENU    4
  665. #define    NMENUS        5
  666. #else NOWINDOWMENU
  667. #define    NMENUS        4
  668. #endif NOWINDOWMENU
  669.  
  670. static Menu *menus[NMENUS];
  671. #ifndef NOWINDOWMENU
  672. static char *namebuf[MAXWINDOWMENU + 1];
  673. static char *wname;
  674. static Window windows[MAXWINDOWMENU];
  675. #endif NOWINDOWMENU
  676.  
  677. ModeMenu(term, reply, pty)
  678. Terminal *term;
  679. register XKeyOrButtonEvent *reply;
  680. int pty;            /* file descriptor of pty */
  681. {
  682.     register Screen *screen = &term->screen;
  683.     register Menu *menu;
  684.     register int type, item;
  685.     static int inited;
  686.     extern TekLink *TekRefresh;
  687.     extern int xeventpass();
  688.     extern Menu *setupmenu(), *Tsetupmenu(), *xsetupmenu();
  689. #ifndef NOWINDOWMENU
  690.     extern Menu *wsetupmenu();
  691. #endif NOWINDOWMENU
  692.     extern Menu *ssetupmenu();
  693.  
  694.     if((reply->window == screen->title.tbar || reply->window ==
  695.      screen->Ttitle.tbar) && InTitle(screen, reply->window,
  696.      reply->x))
  697.         return;
  698.     if(!inited) {
  699.         extern Pixmap Gray_Tile;
  700.         extern Cursor Menu_DefaultCursor;
  701.         extern char *Menu_DefaultFont;
  702.         extern FontInfo *Menu_DefaultFontInfo;
  703.  
  704.         inited++;
  705.         Gray_Tile = screen->graybordertile;
  706.         InitMenu(xterm_name);
  707.         Menu_DefaultCursor = screen->arrow;
  708.         if(strcmp(Menu_DefaultFont, f_t) == 0)
  709.             Menu_DefaultFontInfo = screen->titlefont;
  710.     }
  711.     if((reply->detail & 0177) == LeftButton)
  712.         type = XTERMMENU;
  713.     else if((reply->detail & 0177) == RightButton)
  714. #ifndef NOWINDOWMENU
  715.         type = WINDOWMENU;
  716. #else NOWINDOWMENU
  717.         {
  718.             Bell();
  719.             return;
  720.         }
  721. #endif NOWINDOWMENU
  722.     else if(reply->window == VWindow(screen) || reply->window ==
  723.      screen->title.tbar)
  724.         type = VTMENU;
  725.     else if(reply->window == TWindow(screen) || reply->window ==
  726.      screen->Ttitle.tbar)
  727.         type = TEKMENU;
  728.     else
  729.         type = SCROLLBARMENU;
  730.     switch(type) {
  731.      case XTERMMENU:
  732.         if((menu = xsetupmenu(&menus[XTERMMENU])) == NULL)
  733.             return;
  734.         break;
  735.      case VTMENU:
  736.         if((menu = setupmenu(&menus[VTMENU])) == NULL)
  737.             return;
  738.         break;
  739. #ifndef NOWINDOWMENU
  740.      case WINDOWMENU:
  741.         wname = (reply->window == screen->title.tbar || reply->window
  742.          == VWindow(screen)) ? screen->winname : screen->Twinname;
  743.         if((menu = wsetupmenu(&menus[WINDOWMENU])) == NULL)
  744.             return;
  745.         break;
  746. #endif NOWINDOWMENU
  747.      case TEKMENU:
  748.         if((menu = Tsetupmenu(&menus[TEKMENU])) == NULL)
  749.             return;
  750.         screen->waitrefresh = TRUE;
  751.         break;
  752.      case SCROLLBARMENU:
  753.         if((menu = ssetupmenu(&menus[SCROLLBARMENU])) == NULL)
  754.             return;
  755.         break;
  756.     }
  757.     /*
  758.      * Make the window entry and leaving routines holdoff on setting
  759.      * the timer and on selecting or unselecting any windows.  Then
  760.      * set the select mode manually.
  761.      */
  762.     screen->holdoff = TRUE;
  763.     SetMenuEventHandler(menu, xeventpass);
  764.     item = TrackMenu(menu, reply);
  765.     menusync();
  766.     screen->waitrefresh = FALSE;
  767.     screen->timer = 0;
  768.     screen->holdoff = FALSE;
  769.     reselectwindow(screen);
  770.  
  771.     if (item < 0) {
  772.         if(type == TEKMENU && TekRefresh)
  773.             dorefresh();
  774. #ifndef NOWINDOWMENU
  775.         else if(type == WINDOWMENU)
  776.             wfree(menu);
  777. #endif NOWINDOWMENU
  778.         return;
  779.     }
  780.     switch(type) {
  781.      case XTERMMENU:
  782.         xdomenufunc(item);
  783.         break;
  784.      case VTMENU:
  785.         domenufunc(item);
  786.         break;
  787. #ifndef NOWINDOWMENU
  788.      case WINDOWMENU:
  789.         wdomenufunc(item);
  790.         wfree(menu);
  791.         break;
  792. #endif NOWINDOWMENU
  793.      case TEKMENU:
  794.         Tdomenufunc(item);
  795.         break;
  796.      case SCROLLBARMENU:
  797.         sdomenufunc(item);
  798.         break;
  799.     }
  800. }
  801.  
  802. menusync()
  803. {
  804.     XEvent ev;
  805.  
  806.     XSync(0);
  807.     while(QLength() > 0) {
  808.         XNextEvent(&ev);
  809.         xeventpass(&ev);
  810.     }
  811. }
  812.  
  813. #define    XMENU_TITLE    0
  814. #define XMENU_ACTIVEICON (XMENU_TITLE+1)
  815. #define XMENU_ALLOWICONINPUT (XMENU_ACTIVEICON+1)
  816. #define    XMENU_AUTORAISE    (XMENU_ALLOWICONINPUT+1)
  817. #define    XMENU_VISUALBELL (XMENU_AUTORAISE+1)
  818. #define    XMENU_DEICONWARP (XMENU_VISUALBELL+1)
  819. #define    XMENU_LOG    (XMENU_DEICONWARP+1)
  820. #define    XMENU_LINE    (XMENU_LOG+1)
  821. #define    XMENU_REDRAW    (XMENU_LINE+1)
  822. #define    XMENU_RESUME    (XMENU_REDRAW+1)
  823. #define    XMENU_SUSPEND    (XMENU_RESUME+1)
  824. #define    XMENU_INTR    (XMENU_SUSPEND+1)
  825. #define    XMENU_HANGUP    (XMENU_INTR+1)
  826. #define    XMENU_TERM    (XMENU_HANGUP+1)
  827. #define    XMENU_KILL    (XMENU_TERM+1)
  828.  
  829. static char *xtext[] = {
  830.     "Title Bar(s)",
  831.     "Active Icon",
  832.     "Allow Icon Input",
  833.     "Auto Raise",
  834.     "Visual Bell",
  835.     "Deiconify Warp",
  836.     "Logging",
  837.     "-",
  838.     "Redraw",
  839.     "Continue",
  840.     "Suspend",
  841.     "Interrupt",
  842.     "Hangup",
  843.     "Terminate",
  844.     "Kill",
  845.     0,
  846. };
  847.  
  848. static int xauto;
  849. static int xbell;
  850. static int xdeiconwarp;
  851. static int xlog;
  852. static int xtbar;
  853. static int xactive_icon;
  854. static int xallow_iconinput;
  855.  
  856. Menu *xsetupmenu(menu)
  857. register Menu **menu;
  858. {
  859.     register Screen *screen = &term.screen;
  860.     register char **cp;
  861.     register int i;
  862.  
  863.     if (*menu == NULL) {
  864.         if ((*menu = NewMenu("xterm X10/6.6B", re_verse)) == NULL)
  865.             return(NULL);
  866.         for(cp = xtext ; *cp ; cp++)
  867.             AddMenuItem(*menu, *cp);
  868.         if(xtbar = (Titlebar(screen) > 0))
  869.             CheckItem(*menu, XMENU_TITLE);
  870.         if(xactive_icon = screen->active_icon)
  871.             CheckItem(*menu, XMENU_ACTIVEICON);
  872.         if(xallow_iconinput = (term.flags & ICONINPUT))
  873.             CheckItem(*menu, XMENU_ALLOWICONINPUT);
  874.         SetItemDisable(*menu, XMENU_ALLOWICONINPUT, !xactive_icon);
  875.         if(xauto = screen->autoraise)
  876.             CheckItem(*menu, XMENU_AUTORAISE);
  877.         if(xbell = screen->visualbell)
  878.             CheckItem(*menu, XMENU_VISUALBELL);
  879.         if(xdeiconwarp = screen->deiconwarp)
  880.             CheckItem(*menu, XMENU_DEICONWARP);
  881.         if(xlog = screen->logging)
  882.             CheckItem(*menu, XMENU_LOG);
  883.         DisableItem(*menu, XMENU_LINE);
  884.         if(screen->inhibit & I_LOG)
  885.             DisableItem(*menu, XMENU_LOG);
  886.         if(screen->inhibit & I_SIGNAL)
  887.             for(i = XMENU_SUSPEND ; i <= XMENU_KILL ; i++)
  888.                 DisableItem(*menu, i);
  889.         return(*menu);
  890.     }
  891.     if (xtbar != (Titlebar(screen) > 0))
  892.         SetItemCheck(*menu, XMENU_TITLE, (xtbar =
  893.          (Titlebar(screen) > 0)));
  894.     if (xactive_icon != screen->active_icon) {
  895.         SetItemCheck(*menu, XMENU_ACTIVEICON,
  896.                  (xactive_icon = screen->active_icon));
  897.         SetItemDisable(*menu, XMENU_ALLOWICONINPUT, !xactive_icon);
  898.     }
  899.     if (xallow_iconinput != (term.flags & ICONINPUT))
  900.         SetItemCheck(*menu, XMENU_ALLOWICONINPUT,
  901.                  (xallow_iconinput = (term.flags & ICONINPUT)));
  902.     if (xauto != screen->autoraise)
  903.         SetItemCheck(*menu, XMENU_AUTORAISE, (xauto =
  904.          screen->autoraise));
  905.     if (xbell != screen->visualbell)
  906.         SetItemCheck(*menu, XMENU_VISUALBELL, (xbell =
  907.          screen->visualbell));
  908.     if (xdeiconwarp != screen->deiconwarp)
  909.         SetItemCheck(*menu, XMENU_DEICONWARP, (xdeiconwarp =
  910.          screen->deiconwarp));
  911.     if (xlog != screen->logging)
  912.         SetItemCheck(*menu, XMENU_LOG, (xlog = screen->logging));
  913.     return(*menu);
  914. }
  915.  
  916. xdomenufunc(item)
  917. int item;
  918. {
  919.     register Screen *screen = &term.screen;
  920.  
  921.     switch (item) {
  922.     case XMENU_TITLE:
  923.         if(Titlebar(screen)) {
  924.                 screen->fullVwin.titlebar =
  925.                 screen->fullTwin.titlebar = 0;
  926.             if(VWindow(screen))
  927.                 VTTitleHide();
  928.             if(TWindow(screen))
  929.                 TekTitleHide();
  930.         } else {
  931.                 screen->fullVwin.titlebar =
  932.                 screen->fullTwin.titlebar = screen->titleheight;
  933.             if(VWindow(screen))
  934.                 VTTitleShow(FALSE);
  935.             if(TWindow(screen))
  936.                 TekTitleShow(FALSE);
  937.         }
  938.         break;
  939.  
  940.     case XMENU_ACTIVEICON:
  941.         screen->active_icon = !screen->active_icon;
  942.         if (screen->active_icon && !screen->fnt_icon) {
  943.             FontInfo *fInfo = XOpenFont( f_i );
  944.             screen->fnt_icon = fInfo->id;
  945.             screen->iconVwin.f_width = fInfo->width;
  946.             screen->iconVwin.f_height = fInfo->height;
  947.         }
  948.  
  949.         if (screen->iconVwin.window) {
  950.             SetIconSize( screen );
  951.             XSelectInput( screen->iconVwin.window,
  952.                       screen->active_icon
  953.                   && (term.flags & ICONINPUT)
  954.                     ? ICONWINDOWEVENTS | ICONINPUTEVENTS
  955.                     : ICONWINDOWEVENTS );
  956.         }
  957.  
  958.         if (screen->iconTwin.window) {
  959.             TSetIconSize( screen );
  960.             XSelectInput( screen->iconTwin.window,
  961.                   screen->active_icon
  962.                   && (term.flags & ICONINPUT)
  963.                     ? TICONWINDOWEVENTS | ICONINPUTEVENTS
  964.                     : TICONWINDOWEVENTS );
  965.         }
  966.  
  967.         break;
  968.  
  969.     case XMENU_ALLOWICONINPUT:
  970.         term.flags ^= ICONINPUT;
  971.         if (screen->iconVwin.window)
  972.             XSelectInput( screen->iconVwin.window,
  973.                   screen->active_icon
  974.                   && (term.flags & ICONINPUT)
  975.                     ? ICONWINDOWEVENTS | ICONINPUTEVENTS
  976.                     : ICONWINDOWEVENTS );
  977.  
  978.         if (screen->iconTwin.window)
  979.             XSelectInput( screen->iconTwin.window,
  980.                   screen->active_icon
  981.                   && (term.flags & ICONINPUT)
  982.                     ? TICONWINDOWEVENTS | ICONINPUTEVENTS
  983.                     : TICONWINDOWEVENTS );
  984.  
  985.         break;
  986.  
  987.     case XMENU_AUTORAISE:
  988.         screen->autoraise = !screen->autoraise;
  989.         break;
  990.  
  991.     case XMENU_DEICONWARP:
  992.         screen->deiconwarp = !screen->deiconwarp;
  993.         break;
  994.  
  995.     case XMENU_VISUALBELL:
  996.         screen->visualbell = !screen->visualbell;
  997.         break;
  998.  
  999.     case XMENU_LOG:
  1000.         if(screen->logging)
  1001.             CloseLog(screen);
  1002.         else
  1003.             StartLog(screen);
  1004.         break;
  1005.  
  1006.     case XMENU_REDRAW:
  1007.         Redraw();
  1008.         break;
  1009.  
  1010.     case XMENU_RESUME:
  1011.         if(screen->pid > 1)
  1012.             killpg(getpgrp(screen->pid), SIGCONT);
  1013.         break;
  1014.  
  1015.     case XMENU_SUSPEND:
  1016.         if(screen->pid > 1)
  1017.             killpg(getpgrp(screen->pid), SIGTSTP);
  1018.         break;
  1019.  
  1020.     case XMENU_INTR:
  1021.         if(screen->pid > 1)
  1022.             killpg(getpgrp(screen->pid), SIGINT);
  1023.         break;
  1024.  
  1025.     case XMENU_HANGUP:
  1026.         if(screen->pid > 1)
  1027.             killpg(getpgrp(screen->pid), SIGHUP);
  1028.         break;
  1029.  
  1030.     case XMENU_TERM:
  1031.         if(screen->pid > 1)
  1032.             killpg(getpgrp(screen->pid), SIGTERM);
  1033.         break;
  1034.  
  1035.     case XMENU_KILL:
  1036.         if(screen->pid > 1)
  1037.             killpg(getpgrp(screen->pid), SIGKILL);
  1038.         break;
  1039.     }
  1040. }
  1041.  
  1042. #ifndef NOWINDOWMENU
  1043. Menu *wsetupmenu(menu)
  1044. register Menu **menu;
  1045. {
  1046.     register Window *cp, *wp;
  1047.     register char **np;
  1048.     register int i, j;
  1049.     Window win, *children;
  1050.     int nchildren;
  1051.     char *name;
  1052.     WindowInfo winfo;
  1053.  
  1054.     if(!XQueryTree(RootWindow, &win, &nchildren, &children))
  1055.         return(NULL);
  1056.     if(nchildren > MAXWINDOWMENU)
  1057.         nchildren = MAXWINDOWMENU;
  1058.     if ((*menu = NewMenu("Windows", re_verse)) == NULL) {
  1059.         free((char *)children);
  1060.         return(NULL);
  1061.     }
  1062.     np = namebuf;
  1063.     wp = windows;
  1064.     for(i = nchildren, j = 0, cp = children ; i > 0 ; cp++, i--) {
  1065.         if(!XQueryWindow(*cp, &winfo))
  1066.             goto failed;
  1067.         if(winfo.mapped != IsMapped)
  1068.             continue;
  1069.         if(!XFetchName(*cp, &name)) {
  1070. failed:
  1071.             free((char *)children);
  1072.             *np = NULL;
  1073.             wfree(*menu);
  1074.             return(NULL);
  1075.         }
  1076.         if(name == NULL)
  1077.             continue;
  1078.         AddMenuItem(*menu, *np++ = name);
  1079.         *wp++ = *cp;
  1080.         if(strcmp(wname, name) == 0)
  1081.             CheckItem(*menu, j);
  1082.         j++;
  1083.     }
  1084.     *np = NULL;
  1085.     free((char *)children);
  1086.     if(np > namebuf)
  1087.         return(*menu);
  1088.     DisposeMenu(*menu);
  1089.     return(NULL);
  1090. }
  1091.  
  1092. wdomenufunc(item)
  1093. int item;
  1094. {
  1095.     register Window w;
  1096.  
  1097.     if((w = windows[item]) != NULL)
  1098.         XRaiseWindow(w);
  1099. }
  1100.  
  1101. wfree(menu)
  1102. Menu *menu;
  1103. {
  1104.     register char **np;
  1105.  
  1106.     for(np = namebuf ; *np ; np++)
  1107.         free(*np);
  1108.     DisposeMenu(menu);
  1109. }
  1110. #endif NOWINDOWMENU
  1111.  
  1112. MenuNewCursor(cur)
  1113. register Cursor cur;
  1114. {
  1115.     register Menu **menu;
  1116.     register int i;
  1117.     extern Cursor Menu_DefaultCursor;
  1118.  
  1119.     Menu_DefaultCursor = cur;
  1120.     for(i = XTERMMENU, menu = menus ; i <= TEKMENU ; menu++, i++) {
  1121.         if(!*menu)
  1122.             continue;
  1123.         (*menu)->menuCursor = cur;
  1124.         if((*menu)->menuWindow)
  1125.             XDefineCursor((*menu)->menuWindow, cur);
  1126.     }
  1127. }
  1128. #else MODEMENU
  1129.  
  1130. ModeMenu(term, reply, pty)
  1131. Terminal *term;
  1132. register XKeyOrButtonEvent *reply;
  1133. int pty;            /* file descriptor of pty */
  1134. {
  1135.     register Screen *screen = &term->screen;
  1136.  
  1137.     if((reply->window == screen->title.tbar || reply->window ==
  1138.      screen->Ttitle.tbar) && InTitle(screen, reply->window,
  1139.      reply->x))
  1140.         return;
  1141.     Bell();
  1142. }
  1143. #endif MODEMENU
  1144.  
  1145. GINbutton(term, reply, pty)
  1146. Terminal *term;
  1147. XKeyOrButtonEvent *reply;
  1148. int pty;            /* file descriptor of pty */
  1149. {
  1150.     register Screen *screen = &term->screen;
  1151.     register int i;
  1152.  
  1153.     if(screen->TekGIN) {
  1154.         i = "rml"[reply->detail & 0xff];
  1155.         if(reply->detail & ShiftMask)
  1156.             i = toupper(i);
  1157.         TekEnqMouse(i | 0x80);    /* set high bit */
  1158.         TekGINoff();
  1159.     } else
  1160.         Bell();
  1161. }
  1162.  
  1163. Bogus(term, reply, pty)
  1164. Terminal *term;
  1165. XKeyOrButtonEvent *reply;
  1166. int pty;            /* file descriptor of pty */
  1167. {
  1168.     Bell();
  1169. }
  1170.  
  1171. Silence(term, reply, pty)
  1172. Terminal *term;
  1173. XKeyOrButtonEvent *reply;
  1174. int pty;            /* file descriptor of pty */
  1175. {
  1176. }
  1177.