home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume2 / window / part3 / misc.c next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  11.1 KB  |  449 lines

  1. /*
  2.  *************
  3.  * DISTRIBUTION NOTICE  July 30 1985
  4.  * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
  5.  *        Research Triangle Institute, (919) 541-7005.
  6.  * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
  7.  *        Naval Research Laboratory, (202) 767-3365.
  8.  * No claims or warranties of any sort are made for this distribution.
  9.  * General permission is granted to copy, but not for profit,
  10.  * any of this distribution, provided that this notice
  11.  * is always included in the copies.
  12.  *************
  13.  */
  14. /*
  15.  * Miscellaneous routines for the window manager.
  16.  */
  17. #include "wm.h"
  18.  
  19. /*
  20.  * Get next unused slot in window structure array.
  21.  * Returns slot number, or -1 if no slot available.
  22.  */
  23. int GetSlot()
  24. {
  25.     register int w;
  26.  
  27.     for (w = MINWINDOW; w < MAXWINDOWS; w++)
  28.     if (!(win[w].flags&INUSE))
  29.         return(w);
  30.     
  31.     return(-1);
  32. }
  33.  
  34. /*
  35.  * Prompt user for a window name.
  36.  */
  37. askwindow()
  38. {
  39.     register int w, c;
  40.  
  41.  
  42.     w = -1;
  43.     c = tty_getch();
  44.  
  45.     if (c == CANCEL1  ||  c == CANCEL2)
  46.     showmsg("Canceled.");
  47.  
  48.     else if (c == 'l')
  49.     {
  50.     if (iswindow(lastw))
  51.         w = lastw;
  52.     else
  53.         showmsg("No last window.");
  54.     }
  55.  
  56.     else
  57.     {
  58.     if ( ! isdigit(c))
  59.         showmsg("Indicate window by number, or 'l' for last window.");
  60.     else if ( ! iswindow(ctoi(c)))
  61.         showmsg("Window #%d does not exist.", ctoi(c));
  62.     else
  63.         w = ctoi(c);
  64.     }
  65.  
  66.     return(w);
  67. }
  68.  
  69. /*
  70.  * Reshape window.
  71.  * Returns 0 on normal completion, -1 otherwise.
  72.  * On abnormal completion (e.g. the user cancels)
  73.  * if this is a new window (flag) it will be deleted,
  74.  * otherwise it is restored to its original state..
  75.  * In the impossible(?) event that the window cannot
  76.  * be restored it is deleted, sorry.
  77.  */
  78. getbounds(w, flag)
  79. register int w;
  80. int flag;
  81. {
  82.     register WINDOW *wp, *twp;
  83.  
  84.     /* Unpleasant hack: we save the real window contents while
  85.      * a stunt double gets moved about.
  86.      */
  87.     wp = win[w].wptr;
  88.     if ((win[w].wptr=newwin(wlines(wp),wcols(wp),wbegy(wp),wbegx(wp)))==NULL) {
  89.     win[w].wptr = wp;
  90.     showmsg("Cannot allocate temporary window!");
  91.     return(-1);
  92.     }
  93.  
  94.     showmsg("Move cursor to lower left corner (using hjkl), then type x.");
  95.     if (getpos(w, 0) != 0) {
  96.     delwin(win[w].wptr);
  97.     win[w].wptr = wp;
  98.     if (flag||NewWindow(w, wlines(wp), wcols(wp), wbegy(wp), wbegx(wp))) {
  99.         WListDelete(w);
  100.         FreeWindow(w);
  101.     }
  102.     RedrawScreen();
  103.     return(-1);
  104.     }
  105.  
  106.     showmsg("Now move cursor to upper right corner, then type x.");
  107.     if (getpos(w, 1) != 0) {
  108.     delwin(win[w].wptr);
  109.     win[w].wptr = wp;
  110.     if (flag||NewWindow(w, wlines(wp), wcols(wp), wbegy(wp), wbegx(wp))) {
  111.         WListDelete(w);
  112.         FreeWindow(w);
  113.     }
  114.     RedrawScreen();
  115.     return(-1);
  116.     }
  117.  
  118.     twp = win[w].wptr;
  119.     win[w].wptr = wp;
  120.     if (NewWindow(w, wlines(twp), wcols(twp), wbegy(twp), wbegx(twp))) {
  121.     delwin(twp);
  122.     WListDelete(w);
  123.     FreeWindow(w);
  124.     RedrawScreen();
  125.     return(-1);
  126.     }
  127.     delwin(twp);
  128.     RedrawScreen();
  129.     return(0);
  130. }
  131.  
  132. /*
  133.  * Key definitions used only by routine getpos
  134.  * These keys are used only for entering position of new window
  135.  */
  136. # define RIGHTCHAR    'l'
  137. # define UPCHAR        'k'
  138. # define LEFTCHAR    'h'
  139. # define DOWNCHAR    'j'
  140. # define BIGRIGHTCHAR    'L'    /* jump            */
  141. # define BIGUPCHAR    'K'    /* one-fifth of the    */
  142. # define BIGLEFTCHAR    'H'    /* way across        */
  143. # define BIGDOWNCHAR    'J'    /* the screen        */
  144. # define EXECCHAR    'x'
  145.  
  146. /*
  147.  * move window on screen using UPCHAR, etc.
  148.  * If flag is 0, then window is dragged at lower left.
  149.  * If flag is non-zero, then window is re-sized at upper right.
  150.  * Does not permit bottom (y=LINES-1) line, as it is saved for messages
  151.  * Returns 0 on normal completion, -1 if user cancels.
  152.  */
  153. getpos(w, flag)
  154.  
  155. int w, flag;
  156. {
  157.     register WINDOW *wp;
  158.     register int x0, y0;
  159.     register int c;
  160.     int bigvert, bighoriz;
  161.     int lines, cols;    /* original size of window */
  162.     int aline, acol;    /* 'anchored' corner of window */
  163.     int top, bot, left, right;
  164.  
  165.     bigvert=LINES/5+1;
  166.     bighoriz=COLS/5+1;
  167.  
  168.     wp = win[w].wptr;
  169.     lines = wlines(wp);
  170.     cols = wcols(wp);
  171.     y0 = wbegy(wp)+lines-1;
  172.     x0 = wbegx(wp);
  173.     if (flag) {    /* re-size box */
  174.     aline = y0;
  175.     acol = x0;
  176.     y0 = wbegy(wp);
  177.     x0 = wbegx(wp)+cols-1;
  178.     }
  179.     RedrawScreen();
  180.     (void) movecursor(y0,x0);
  181.     (void) fflush(stdout);
  182.  
  183.     while ((c = tty_getch()) != EXECCHAR)
  184.     {
  185.     switch (c)
  186.     {
  187.     case KEY_HOME:        x0=y0=0;    break;
  188.     case KEY_RIGHT:
  189.     case RIGHTCHAR:        x0 += 1;    break;
  190.     case KEY_UP:
  191.     case UPCHAR:        y0 -= 1;    break;
  192.     case KEY_BACKSPACE:
  193.     case KEY_LEFT:
  194.     case LEFTCHAR:        x0 -= 1;    break;
  195.     case KEY_DOWN:
  196.     case DOWNCHAR:        y0 += 1;    break;
  197.     case BIGRIGHTCHAR:    x0 += bighoriz;    break;
  198.     case BIGUPCHAR:        y0 -= bigvert;    break;
  199.     case BIGLEFTCHAR:    x0 -= bighoriz;    break;
  200.     case BIGDOWNCHAR:    y0 += bigvert;    break;
  201.     default:
  202.         if (c == CANCEL1  ||  c == CANCEL2)
  203.         {
  204.         showmsg("Canceled.");
  205.         return(-1);
  206.         }
  207.         else
  208.         flash();
  209.         break;
  210.     }
  211.     x0 = MAX(x0, 0); x0 = MIN(x0, COLS-1);
  212.     y0 = MAX(y0, 0); y0 = MIN(y0, LINES-2);
  213.  
  214.     if (!flag) {    /* drag box */
  215.         bot = y0;
  216.         left = x0;
  217.         top = y0+1 - lines; top = MAX(top, 0);
  218.         right = x0+cols-1; right = MIN(right, COLS-1);
  219.     } else {    /* re-size box */
  220.         bot = MAX(y0, aline);
  221.         left = MIN(x0, acol);
  222.         top = MIN(y0, aline);
  223.         right = MAX(x0, acol);
  224.     }
  225.     if (NewWindow(w, bot+1-top, right+1-left, top, left))
  226.         return(-1);
  227.     wp = win[w].wptr;
  228.     if (!tty_inputpending()) {
  229.         RedrawScreen();
  230.         (void) movecursor(y0,x0);
  231.         (void) fflush(stdout);
  232.     }
  233.     }
  234.  
  235.     return(0);
  236. }
  237.  
  238. /*
  239.  * If c is a control character, make it printable,
  240.  * e.g. '\007' ==> '^G'.
  241.  */
  242. char *
  243. mkprint(c)
  244.  
  245. register int c;
  246. {
  247.     static char pbuf[3];
  248.  
  249.  
  250.     pbuf[0] = (c>='\040' && c<'\177'   ?   c   :   '^');
  251.     pbuf[1] = (c<'\040' ? c+0100 : c<'\177' ? '\0' : '?');
  252.     pbuf[2] = '\0';
  253.  
  254.     return(pbuf);
  255. }
  256.  
  257. /*
  258.  * Send a setenv command for wmvirt terminal to shell in window w.
  259.  * Note: this is a sad kludge.  If fails if 'vi' or anything
  260.  * other than the wm-activated shell is active in the window.
  261.  * It is rumored that 4.3 BSD supports an ioctl to change
  262.  * the window size (and corresponding signals that are understood
  263.  * by screen managers).  That will provide a better alternative.
  264.  * Note: the setenv hack will still be needed for sessions
  265.  * on remote machines via "tip".
  266.  * Rlogin should (in 4.2 BSD does not) pass along TERMCAP
  267.  * in addition to TERM.
  268.  *
  269.  * mode 0 -- disconnect termcap (unlink sneakytermcap file)
  270.  * mode 1 -- set termcap, attempting sneaky termcap method first.
  271.  * mode 2 -- set termcap, storing termcap string in environment
  272.  * mode 3 -- set termcap by writing a shell command to the window
  273.  */
  274. SetTerm(w, mode)
  275.  
  276. register int w, mode;
  277. {
  278.     register int i, fd;
  279.     register char *s, *lasts;
  280.  
  281. #ifdef SNEAKYTERMCAP
  282.     if (mode < 3) {
  283. /*
  284.  * Use of /tmp to hold the termcap files is a security hole
  285.  * on most UNIX systems.  Safer, but more trouble,
  286.  * would be to put these files in a directory in the
  287.  * users home directory.
  288.  */
  289.     char termfile[100];
  290.     int oldmask;
  291.     (void) sprintf(termfile, "/tmp/WM.%d.%d",
  292.             (mode==1? getppid(): getpid()), w);
  293.     (void) unlink(termfile);
  294.     if (mode == 0)
  295.         return;
  296.     if (mode == 1) {
  297.         (void) setenv("TERM", "wmvirt");
  298.         (void) setenv("TERMCAP", termfile);
  299.     }
  300.     s = termcap(w);
  301.     oldmask = umask(0);
  302.     fd = creat(termfile, 0644);
  303.     (void) umask(oldmask);
  304.     if (fd >= 0 && write(fd, s, strlen(s)) == strlen(s)
  305.      && write(fd, "\n", 1) == 1
  306.      && close(fd) == 0)
  307.         return;
  308.     if (fd >= 0)
  309.         (void) close(fd);
  310.     if (mode == 1) {
  311.         (void) setenv("TERMCAP", s);
  312.         return;
  313.     }
  314.     /* gotta do it the ugly way ... */
  315.     }
  316. #endif
  317.  
  318.     if (mode == 0)
  319.     return;
  320.  
  321.     /* As suggested by Dave Eckhardt (psuvax1!dae), we check for
  322.      * shellnames *ending* with csh as a clue that a csh is runnning.
  323.      * (This check is also made by the SUSPEND command.)
  324.      */
  325.     if ((i = strlen(shellname)) >= 3
  326.      && strcmp(shellname+i-3,"csh") == 0)
  327.     s = "\nsetenv TERM wmvirt; setenv TERMCAP '";
  328.     else
  329.     s = "\nexport TERM TERMCAP; TERM=wmvirt; TERMCAP='";
  330.  
  331.     fd = win[w].pty;
  332.     (void) write(fd, s, strlen(s));
  333.  
  334.  
  335.     s = termcap(w);
  336.     /* This crazy loop attempts to shield special chars from the tty driver,
  337.      * and to fold the lines to avoid bumping into TTYHOG.
  338.      * A TTYHOG of 255 is much too small, but lots of systems have that. */
  339.     lasts = s;
  340.     for (i = 0; s[i]; i++) {
  341.     if (s[i] == killchar() || s[i] == erasechar()) {
  342.         if (i)
  343.         (void) write(fd, s, i);
  344.         (void) write(fd, "\\", 1);
  345.         s += i;
  346.         i = 0;
  347.     }
  348.         else if (s[i] == ':' && i+(s-lasts) > 180 && i > 0 && s[i-1] != '\\') {
  349.         (void) write(fd, s, i+1);
  350.         (void) write(fd, "\\\r:", 3);
  351.         s += i+1;
  352.         lasts = s;
  353.         i = 0;
  354.     }
  355.     }
  356.     (void) write(fd, s, strlen(s));
  357.  
  358.     (void) write(fd, "'\n", 2);
  359. }
  360.  
  361. /*
  362.  * Find the largest unobscured rectangle on the screen,
  363.  * returning its description as (lines, cols, begline, begcol)
  364.  * via reference parameters.
  365.  * The window being fitted is 'w'.
  366.  * Returns -1 if no unobscured rectangle is found.
  367.  *
  368.  * Note: this algorithm is based on one from Jon Bentley's
  369.  * "Programming Pearls" column in the CACM.  Many readers
  370.  * independently discovered the algorithm, including some
  371.  * who wrote to Bentley and got mentioned in his column (sigh).
  372.  * An interesting question is, is there a faster algorithm?
  373.  * (Faster in the worst case, that is.)
  374.  */
  375. fitwindow(w, lp, cp, blp, bcp)
  376. int w, *lp, *cp, *blp, *bcp;
  377. {
  378.     short *wbase;            /* vaguely like a WINDOW pointer */
  379.     register short *wptop, *wpbot;    /* Ye Olde manual code optimization */
  380.     register int x, ytop, ybot;
  381.     int bestarea, bestsofar, besttohere, bestx;
  382.  
  383.     /* Allocate an appropriately sized array */
  384.     if (LINES > 32000
  385.      || (wbase = alloc(LINES*COLS, short)) == NULL)
  386.     return(-1);
  387.  
  388.     /* Compute cumulative coverage table in LINES*COLS steps */
  389.     /* This is probably the slower loop, due to the subroutine call */
  390.     for (x = 0; x < COLS; x++)
  391.     for (ytop=0,wptop=wbase+x; ytop < LINES-1; ytop++,wptop+=COLS)
  392.         wptop[0] = covers(w, ytop, x) + ((ytop > 0)? wptop[-COLS]: 0);
  393.  
  394.     /* Find largest rectangle in LINES*LINES/2*COLS steps */
  395.     bestarea = 0;
  396.     for (ytop = 0; ytop < LINES-1; ytop++) {
  397.     for (ybot  = ytop; ybot < LINES-1; ybot++) {
  398.         /* Find largest rectangle in this strip */
  399.         bestsofar = besttohere = 0;
  400.         wptop = wbase + (ytop-1)*COLS;
  401.         for (x=0,wpbot=wbase+ybot*COLS; x < COLS; x++,wpbot++,wptop++) {
  402.         if (wpbot[0] - ((ytop > 0)? wptop[0]: 0))
  403.             besttohere = 0;
  404.         else if (++besttohere > bestsofar) {
  405.             bestsofar = besttohere;
  406.             bestx = x+1 - bestsofar;
  407.         }
  408.         }
  409.         if (bestsofar*(ybot+1-ytop) > bestarea) {
  410.         bestarea = bestsofar*(ybot+1-ytop);
  411.         *lp = ybot+1-ytop;
  412.         *cp = bestsofar;
  413.         *blp = ytop;
  414.         *bcp = bestx;
  415.         }
  416.     }
  417.     }
  418.     free((char *)wbase);
  419.  
  420.     if (bestarea <= 0)
  421.     return(-1);
  422.     return(0);
  423. }
  424.  
  425. /*
  426.  * Returns "" if n == 1, otherwise "s".
  427.  * Useful for printing messages such as "1 line" or "2 lines".
  428.  */
  429. char *
  430. plural(n)
  431. int n;
  432. {
  433.     return (n == 1? "": "s");
  434. }
  435.  
  436. /*
  437.  * This routine is equivalent to 'malloc',
  438.  * but returns a 'double *' which makes lint happier.
  439.  * If only malloc were declared this way in the lint library
  440.  * this kludge would be unnecessary.
  441.  */
  442. double *
  443. Malloc(n)
  444. unsigned int n;
  445. {
  446.     extern char *malloc();    /* The tyranny of the lint library */
  447.     return((double *)malloc(n));    /* Ignore lint warning */
  448. }
  449.