Annotation of 43BSD/contrib/emacs/src/dispnew.c, revision 1.1.1.1

1.1       root        1: /* Newly written part of redisplay code.
                      2:    Copyright (C) 1985 Richard M. Stallman.
                      3: 
                      4: This file is part of GNU Emacs.
                      5: 
                      6: GNU Emacs is distributed in the hope that it will be useful,
                      7: but WITHOUT ANY WARRANTY.  No author or distributor
                      8: accepts responsibility to anyone for the consequences of using it
                      9: or for whether it serves any particular purpose or works at all,
                     10: unless he says so in writing.  Refer to the GNU Emacs General Public
                     11: License for full details.
                     12: 
                     13: Everyone is granted permission to copy, modify and redistribute
                     14: GNU Emacs, but only under the conditions described in the
                     15: GNU Emacs General Public License.   A copy of this license is
                     16: supposed to have been given to you along with GNU Emacs so you
                     17: can know your rights and responsibilities.  It should be in a
                     18: file named COPYING.  Among other things, the copyright notice
                     19: and this notice must be preserved on all copies.  */
                     20: 
                     21: 
                     22: #include <signal.h>
                     23: 
                     24: #include "config.h"
                     25: #include <stdio.h>
                     26: 
                     27: #ifdef HAVE_TIMEVAL
                     28: #ifdef HPUX
                     29: #include <time.h>
                     30: #else
                     31: #include <sys/time.h>
                     32: #endif
                     33: #endif
                     34: 
                     35: #ifdef USG
                     36: #include <termio.h>
                     37: #else /* not USG */
                     38: #include <sys/ioctl.h>
                     39: #endif /* not USG */
                     40: 
                     41: #undef NULL
                     42: 
                     43: #include "termchar.h"
                     44: #include "termopts.h"
                     45: #include "cm.h"
                     46: #include "dispextern.h"
                     47: #include "lisp.h"
                     48: #include "buffer.h"
                     49: #include "window.h"
                     50: #include "commands.h"
                     51: 
                     52: #define max(a, b) ((a) > (b) ? (a) : (b))
                     53: #define min(a, b) ((a) < (b) ? (a) : (b))
                     54: 
                     55: /* Nonzero means do not assume anything about current
                     56:  contents of actual terminal screen */
                     57: 
                     58: int screen_garbaged;
                     59: 
                     60: /* Desired terminal cursor position (to show position of point),
                     61:  origin zero */
                     62: 
                     63: int cursX, cursY;
                     64: 
                     65: /* Nonzero means last display completed and cursor is really at cursX, cursY.
                     66:  Zero means it was preempted. */
                     67: 
                     68: int display_completed;
                     69: 
                     70: int visible_bell;      /* If true and the terminal will support it
                     71:                           then the screen will flash instead of
                     72:                           feeping when an error occurs */
                     73: int inverse_video;     /* If true and the terminal will support it
                     74:                           then we will use inverse video */
                     75: 
                     76: int baud_rate;         /* Terminal speed, so we can calculate
                     77:                           the number of characters required to
                     78:                           make the cursor sit still for n secs. */
                     79: 
                     80: /* the current (physical) screen */
                     81: struct display_line *PhysScreen[MScreenLength + 1];
                     82: 
                     83: /* temporary Copy of PhysScreen made in update_screen */
                     84: struct display_line *OPhysScreen[MScreenLength + 1];
                     85: 
                     86: /* the desired (virtual) screen */
                     87: struct display_line *DesiredScreen[MScreenLength + 1];
                     88: 
                     89: /* Record here all the display line objects, for debugging.  */
                     90: static struct display_line *all_lines[2 * MScreenLength];
                     91: 
                     92: FILE *termscript;      /* Stdio stream being used for copy of all kbdinput.  */
                     93: 
                     94: struct cm Wcm;         /* Structure for info on cursor positioning */
                     95: 
                     96: extern short ospeed;   /* Output speed (from sg_ospeed) */
                     97: 
                     98: /* Use these to chain together free lines */
                     99: 
                    100: #define LINE_NEXT(l) (*(struct display_line **) l)
                    101: #define SET_LINE_NEXT(l, next) (*((struct display_line **) l) = next)
                    102: 
                    103: /* Chain of free display_line structures, chained thru LINE_NEXT.  */
                    104: 
                    105: struct display_line *free_display_lines;
                    106: 
                    107: /* Number of lines now free.  */
                    108: 
                    109: int free_line_count;
                    110: 
                    111: /* Allocate as many display_line structures
                    112:    as we are ever supposed to need.
                    113:    Called at startup, and also if screen size is changed.  */
                    114: 
                    115: make_display_lines ()
                    116: {
                    117:   register int i;
                    118:   register struct display_line *p, *p1;
                    119: 
                    120:   /* First, free any that are already allocated */
                    121: 
                    122:   for (p = free_display_lines; p;)
                    123:     {
                    124:       p1 = p;
                    125:       p = LINE_NEXT (p);
                    126:       free (p1);
                    127:     }
                    128:   free_display_lines = 0;
                    129:   free_line_count = 0;
                    130: 
                    131:   for (i = 0; i <= MScreenLength; i++)
                    132:     if (PhysScreen[i])
                    133:       {
                    134:        free (PhysScreen[i]);
                    135:        PhysScreen[i] = 0;
                    136:       }
                    137: 
                    138:   screen_garbaged = 1;
                    139: 
                    140:   /* Now allocate as many as we can possibly validly need */
                    141: 
                    142:   for (i = - screen_height; i < screen_height; i++)
                    143:     {
                    144:       p = (struct display_line *) malloc (sizeof (struct display_line) + screen_width - MScreenWidth);
                    145:       if (!p) abort ();
                    146:       SET_LINE_NEXT (p, free_display_lines);
                    147:       free_display_lines = p;
                    148:       all_lines[i + screen_height] = p;
                    149:     }
                    150:   free_line_count = 2 * screen_height;
                    151: }
                    152: 
                    153: /* Get one of the previously malloc'd display_line structures
                    154:    from the free pool.  */
                    155: 
                    156: struct display_line *
                    157: new_display_line ()
                    158: {
                    159:   register struct display_line *p = free_display_lines;
                    160:   /* If we ever use up all the display lines that have been
                    161:      allocated, it indicates a bug, since we are supposed
                    162:      to need at most two for each line on the screen.  */
                    163:   if (!p)
                    164:     abort ();
                    165:   free_display_lines = LINE_NEXT (p);
                    166: 
                    167:   bzero (p, p->body - (char *) p);
                    168:   SET_LINE_NEXT (p, (struct display_line *)1); /* Mark as in use.  */
                    169:   free_line_count--;
                    170:   return p;
                    171: }
                    172: 
                    173: /* Put a display_line back in the free pool.  */
                    174: 
                    175: return_display_line (p)
                    176:      struct display_line *p;
                    177: {
                    178:   if (!p)
                    179:     return;
                    180:   if ((int) LINE_NEXT (p) != 1)
                    181:     abort ();                  /* Already free.  */
                    182:   SET_LINE_NEXT (p, free_display_lines);
                    183:   free_display_lines = p;
                    184:   free_line_count++;
                    185: }
                    186: 
                    187: clear_screen_records ()
                    188: {
                    189:   register int i;
                    190:   for (i = 1; i <= screen_height; i++)
                    191:     if (PhysScreen[i])
                    192:       return_display_line (PhysScreen[i]);
                    193:   bzero (PhysScreen, (screen_height + 1) * sizeof PhysScreen[0]);
                    194: }
                    195: 
                    196: /* Return the hash code of display_line p.  */
                    197: line_hash_code (p)
                    198:      register struct display_line *p;
                    199: {
                    200:   register char *body, *end;
                    201:   register int h = 0;
                    202:   if (!p)
                    203:     return 0;
                    204:   /* Give all lighlighted lines the same hash code
                    205:      so as to encourage scrolling to leave them in place.  */
                    206:   if (p->highlighted)
                    207:     return -1;
                    208: 
                    209:   body = p->body;
                    210:   end = body + p->length;
                    211:   *end = 0;
                    212:   if (!must_write_spaces)
                    213:     {
                    214:       while (*body++ == ' ');
                    215:       body--;
                    216:       if (body == end)
                    217:        return 1;
                    218:       while (end[-1] == ' ') end--;
                    219:     }
                    220:   while (body != end)
                    221:     h = (h << 5) + h + *body++;
                    222:   if (h)
                    223:     return h;
                    224:   return 1;
                    225: }
                    226: 
                    227: /* Return number of characters in display_line p,
                    228:    except don't count leading and trailing spaces
                    229:    unless the terminal requires those to be explicitly output.  */
                    230: 
                    231: line_draw_cost (p)
                    232:      struct display_line *p;
                    233: {
                    234:   register char *body;
                    235:   register int i;
                    236: 
                    237:   if (!p)
                    238:     return 0;
                    239: 
                    240:   if (must_write_spaces)
                    241:     return p->length;
                    242: 
                    243:   body = p->body - 1;
                    244:   for (i = p->length; i > 0 && body[i - 1] == ' '; i--);
                    245: 
                    246:   i -= count_blanks (p->body);
                    247:   return max (i, 0);
                    248: }
                    249: 
                    250: /* The functions on this page are the interface from xdisp.c to redisplay.
                    251:  They take cursor position arguments in origin 0.
                    252: 
                    253:  The only other interface into redisplay is through setting
                    254:  cursX and cursY (in xdisp.c) and setting screen_garbaged. */
                    255: 
                    256: /* cancel_line eliminates any request to display a line at position `vpos' */
                    257: 
                    258: cancel_line (vpos)
                    259:      int vpos;
                    260: {
                    261:   return_display_line (DesiredScreen[vpos + 1]);
                    262:   DesiredScreen[vpos + 1] = 0;
                    263: }
                    264: 
                    265: /* Get a display_line for displaying on line `vpos'
                    266:  and set it up for outputting starting at `hpos' within it.  */
                    267: 
                    268: struct display_line *
                    269: get_display_line (vpos, hpos)
                    270:      int vpos;
                    271:      register int hpos;
                    272: {
                    273:   register struct display_line *line;
                    274:   register char *p;
                    275: 
                    276:   if (vpos < 0) abort ();
                    277: 
                    278:   line = DesiredScreen[vpos + 1];
                    279:   if (line && line->length > hpos)
                    280:     abort ();
                    281:   if (!line)
                    282:     line = new_display_line ();
                    283: 
                    284:   if (hpos > line->length)
                    285:     {
                    286:       p = line->body + line->length;
                    287:       hpos -= line->length;
                    288:       line->length += hpos;
                    289:       while (--hpos >= 0)
                    290:        *p++ = ' ';
                    291:     }
                    292: 
                    293:   DesiredScreen[vpos + 1] = line;
                    294: 
                    295:   return line;
                    296: }
                    297: 
                    298: /* Scroll lines from vpos `from' up to but not including vpos `end'
                    299:  down by `amount' lines (`amount' may be negative).
                    300:  Returns nonzero if done, zero if terminal cannot scroll them. */
                    301: 
                    302: int
                    303: scroll_screen_lines (from, end, amount)
                    304:      int from, end, amount;
                    305: {
                    306:   register int i;
                    307: 
                    308:   if (!line_ins_del_ok)
                    309:     return 0;
                    310: 
                    311:   if (amount == 0)
                    312:     return 1;
                    313:   if (amount > 0)
                    314:     {
                    315:       set_terminal_window (end + amount);
                    316:       if (!scroll_region_ok)
                    317:        ins_del_lines (end, -amount);
                    318:       ins_del_lines (from, amount);
                    319:       set_terminal_window (0);
                    320: 
                    321:       for (i = end + amount; i >= end + 1; i--)
                    322:        return_display_line (PhysScreen[i]);
                    323:       for (i = end; i >= from + 1; i--)
                    324:        PhysScreen[i + amount] = PhysScreen[i];
                    325:       for (i = from + amount; i >= from + 1; i--)
                    326:        PhysScreen[i] = 0;
                    327:     }
                    328:   if (amount < 0)
                    329:     {
                    330:       set_terminal_window (end);
                    331:       ins_del_lines (from + amount, amount);
                    332:       if (!scroll_region_ok)
                    333:        ins_del_lines (end + amount, -amount);
                    334:       set_terminal_window (0);
                    335: 
                    336:       for (i = from + amount + 1; i <= from; i++)
                    337:        return_display_line (PhysScreen[i]);
                    338:       for (i = from + 1; i <= end ; i++)
                    339:        PhysScreen[i + amount] = PhysScreen[i];
                    340:       for (i = end + amount + 1; i <= end; i++)
                    341:        PhysScreen[i] = 0;
                    342:     }
                    343:   return 1;
                    344: }
                    345: 
                    346: /* After updating a window w that isn't the full screen wide,
                    347:  copy all the columns that w does not occupy
                    348:  into the DesiredScreen lines from the PhysScreen lines
                    349:  so that update_screen will not change those columns.  */
                    350: 
                    351: preserve_other_columns (w)
                    352:      struct window *w;
                    353: {
                    354:   register int vpos;
                    355:   register struct display_line *l1, *l2;
                    356:   int start = XFASTINT (w->left);
                    357:   int end = XFASTINT (w->left) + XFASTINT (w->width);
                    358:   int bot = XFASTINT (w->top) + XFASTINT (w->height);
                    359: 
                    360:   for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
                    361:     {
                    362:       if ((l1 = DesiredScreen[vpos + 1])
                    363:          && (l2 = PhysScreen[vpos + 1]))
                    364:        {
                    365:          if (start > 0)
                    366:            {
                    367:              bcopy (l2->body, l1->body, start);
                    368:              if (l1->length < start && l1->length < l2->length)
                    369:                l1->length = min (start, l2->length);
                    370:            }
                    371:          if (l2->length > end && l1->length < l2->length)
                    372:            {
                    373:              while (l1->length < end)
                    374:                l1->body[l1->length++] = ' ';
                    375:              bcopy (l2->body + end, l1->body + end, l2->length - end);
                    376:              l1->length = l2->length;
                    377:            }
                    378:        }
                    379:     }
                    380: }
                    381: 
                    382: #ifdef NOTDEF
                    383: 
                    384: /* If window w does not need to be updated and isn't the full screen wide,
                    385:  copy all the columns that w does occupy
                    386:  into the DesiredScreen lines from the PhysScreen lines
                    387:  so that update_screen will not change those columns.
                    388: 
                    389:  Have not been able to figure out how to use this correctly.  */
                    390: 
                    391: preserve_my_columns (w)
                    392:      struct window *w;
                    393: {
                    394:   register int vpos, fin;
                    395:   register struct display_line *l1, *l2;
                    396:   int start = XFASTINT (w->left);
                    397:   int end = XFASTINT (w->left) + XFASTINT (w->width);
                    398:   int bot = XFASTINT (w->top) + XFASTINT (w->height);
                    399: 
                    400:   for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
                    401:     {
                    402:       if ((l1 = DesiredScreen[vpos + 1])
                    403:          && (l2 = PhysScreen[vpos + 1]))
                    404:        {
                    405:          if (l2->length > start && l1->length < l2->length)
                    406:            {
                    407:              fin = l2->length;
                    408:              if (fin > end) fin = end;
                    409:              while (l1->length < start)
                    410:                l1->body[l1->length++] = ' ';
                    411:              bcopy (l2->body + start, l1->body + start, fin - start);
                    412:              l1->length = fin;
                    413:            }
                    414:        }
                    415:     }
                    416: }
                    417: 
                    418: #endif /* NOTDEF */
                    419: 
                    420: /* On discovering that the redisplay for a window was no good,
                    421:  cancel the columns of that window,
                    422:  so that when the window is displayed over again
                    423:  get_display_line will not complain. */
                    424: 
                    425: cancel_my_columns (w)
                    426:      struct window *w;
                    427: {
                    428:   register int vpos;
                    429:   register struct display_line *l;
                    430:   register int start = XFASTINT (w->left);
                    431:   register int bot = XFASTINT (w->top) + XFASTINT (w->height);
                    432: 
                    433:   for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
                    434:     {
                    435:       if ((l = DesiredScreen[vpos + 1])
                    436:          && l->length >= start)
                    437:        l->length = start;
                    438:     }
                    439: }
                    440: 
                    441: direct_output_for_insert (c)
                    442:      int c;
                    443: {
                    444:   register struct display_line *p = PhysScreen[cursY + 1];
                    445: #ifndef COMPILER_REGISTER_BUG
                    446:   register
                    447: #endif COMPILER_REGISTER_BUG
                    448:     struct window *w = XWINDOW (selected_window);
                    449: #ifndef COMPILER_REGISTER_BUG
                    450:   register
                    451: #endif COMPILER_REGISTER_BUG
                    452:     int hpos = cursX;
                    453: 
                    454:   /* Give up if about to continue line */
                    455:   if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width))
                    456:     return;
                    457: 
                    458:   /* Avoid losing if cursor is in invisible text off left margin */
                    459:   if (XINT (w->hscroll) && hpos == XFASTINT (w->left))
                    460:     return;
                    461:     
                    462:   /* Give up if cursor outside window (in minibuf, probably) */
                    463:   if (cursY < XFASTINT (w->top)
                    464:       || cursY >= XFASTINT (w->top) + XFASTINT (w->height))
                    465:     return;
                    466: 
                    467:   /* Give up if cursor not really at cursX, cursY */
                    468:   if (!display_completed)
                    469:     return;
                    470: 
                    471:   /* Give up if w is minibuffer and a message is being displayed there */
                    472:   if (EQ (selected_window, minibuf_window) && minibuf_message)
                    473:     return;
                    474: 
                    475:   p->body[hpos] = c;
                    476:   unchanged_modified = bf_modified;
                    477:   beg_unchanged = bf_s1;
                    478:   XFASTINT (w->last_point) = point;
                    479:   XFASTINT (w->last_point_x) = cursX;
                    480:   XFASTINT (w->last_modified) = bf_modified;
                    481: 
                    482:   reassert_line_highlight (0, cursY);
                    483:   write_chars (p->body + hpos, 1);
                    484:   fflush (stdout);
                    485:   ++cursX;
                    486:   p->length = max (p->length, cursX);
                    487:   p->body[p->length] = 0;
                    488: }
                    489: 
                    490: direct_output_forward_char (n)
                    491:      int n;
                    492: {
                    493:   register struct window *w = XWINDOW (selected_window);
                    494: 
                    495:   /* Avoid losing if cursor is in invisible text off left margin */
                    496:   if (XINT (w->hscroll) && cursX == XFASTINT (w->left))
                    497:     return;
                    498: 
                    499:   cursX += n;
                    500:   XFASTINT (w->last_point_x) = cursX;
                    501:   XFASTINT (w->last_point) = point;
                    502:   topos (cursY, cursX);
                    503:   fflush (stdout);
                    504: }
                    505: 
                    506: /* At the time this function is called,
                    507:  no line is common to PhysScreen and DesiredScreen.
                    508:  That is true again when this function returns. */
                    509: 
                    510: /* `force' nonzero means do not stop for pending input */
                    511: 
                    512: /* Value is nonzero if redisplay stopped due to pending input */
                    513: update_screen (force, inhibit_hairy_id)
                    514:      int force;
                    515:      int inhibit_hairy_id;
                    516: {
                    517:     register struct display_line **p;
                    518:     register struct display_line *l, *lnew;
                    519:     register int i;
                    520:     int pause;
                    521:     int preempt_count;
                    522:     int outq;
                    523:     extern input_pending;
                    524: 
                    525:     if (screen_height == 0) abort (); /* Some bug zeros some core */
                    526: 
                    527:     bcopy (PhysScreen, OPhysScreen, sizeof PhysScreen);
                    528: 
                    529:     detect_input_pending ();
                    530:     if (input_pending && !force)
                    531:       {
                    532:        pause = 1;
                    533:        goto do_pause;
                    534:       }
                    535: 
                    536:     update_begin ();
                    537: 
                    538:     if (!line_ins_del_ok)
                    539:       inhibit_hairy_id = 1;
                    540: 
                    541:     /* Don't compute for i/d line if just want cursor motion. */
                    542:     for (p = &DesiredScreen[screen_height]; p != DesiredScreen && *p == 0; p--);
                    543: 
                    544:     /* Try doing i/d line, if not yet inhibited.  */
                    545:     if (!inhibit_hairy_id && p != DesiredScreen)
                    546:       force |= scrolling ();
                    547: 
                    548:     /* Update the individual lines as needed.  Do bottom line first.  */
                    549: 
                    550:     l = DesiredScreen[screen_height];
                    551:     if (l && l != PhysScreen[screen_height])
                    552:       update_line (PhysScreen[screen_height], l, screen_height - 1);
                    553:     preempt_count = baud_rate / 2400;
                    554:     for (i = 1; i < screen_height && (force || !input_pending); i++)
                    555:       {
                    556:        l = PhysScreen[i];
                    557:        lnew = DesiredScreen[i];
                    558:        if (lnew && lnew != l)
                    559:          {
                    560:            /* Flush out every so many lines.
                    561:               Also flush out if likely to have more than 1k buffered otherwise.
                    562:               I'm told that telnet connections get really screwed by more
                    563:               than 1k output at once.  */
                    564:            outq = stdout->_ptr - stdout->_base;
                    565:            if (outq > ((--preempt_count < 0) ? 20 : 900))
                    566:              {
                    567:                fflush (stdout);
                    568:                if (baud_rate < 2400)
                    569:                  {
                    570: #ifdef TIOCOUTQ
                    571:                    if (ioctl (0, TIOCOUTQ, &outq) < 0)
                    572:                      /* Probably not a tty.  Ignore the error and reset
                    573:                       * the outq count. */
                    574:                      outq = stdout->_ptr - stdout->_base;
                    575: #endif
                    576:                    outq *= 10;
                    577:                    outq /= baud_rate;  /* outq is now in seconds */
                    578:                    if (outq)
                    579:                      sleep (outq);
                    580:                  }
                    581:                detect_input_pending ();
                    582: 
                    583:                preempt_count = baud_rate / 2400;
                    584:              }
                    585:            /* Now update this line.  */
                    586:            update_line (l, lnew, i - 1);
                    587:          }
                    588:       }
                    589:     pause = (i < screen_height) ? i : 0;
                    590: 
                    591:     /* Now just clean up termcap drivers and set cursor, etc.  */
                    592:     if (!pause)
                    593:       topos (cursY, max (min (cursX, screen_width - 1), 0));
                    594: 
                    595:     update_end ();
                    596: 
                    597:     if (termscript)
                    598:       fflush (termscript);
                    599:     fflush (stdout);
                    600: 
                    601:   do_pause:
                    602:     if (screen_height == 0) abort (); /* Some bug zeros some core */
                    603:     display_completed = !pause;
                    604:     /* Free any lines still in desired screen but not in phys screen */
                    605:     /* Free any lines that used to be in phys screen but are no longer */
                    606:     for (p = &PhysScreen[screen_height]; p != PhysScreen; p--)
                    607:       if (p[0]) p[0]->physical = 1;
                    608:     for (p = &DesiredScreen[screen_height]; p != DesiredScreen; p--)
                    609:       {
                    610:        if (l = *p)
                    611:          {
                    612:            if (!l->physical)
                    613:              {
                    614:                return_display_line (l);
                    615:                /* Prevent line in both DesiredScreen and OPhysScreen
                    616:                   from being freed twice.  */
                    617:                l->physical = 1;
                    618:              }
                    619:          }
                    620:       }
                    621:     for (p = &OPhysScreen[screen_height]; p != OPhysScreen; p--)
                    622:       {
                    623:        if (l = *p)
                    624:          {
                    625:            if (!l->physical)
                    626:              return_display_line (l);
                    627:          }
                    628:       }
                    629:     i = 0;
                    630:     for (p = &PhysScreen[screen_height]; p != PhysScreen; p--)
                    631:       if (p[0])
                    632:        {
                    633:          i++;
                    634:          p[0]->physical = 0;
                    635:        }
                    636: 
                    637:     {
                    638:       extern int debug_end_pos;
                    639:       if (debug_end_pos && i + free_line_count != 2 * screen_height)
                    640:        abort ();
                    641:     }
                    642: 
                    643:     bzero (OPhysScreen, (screen_height + 1) * sizeof OPhysScreen[0]);
                    644:     bzero (DesiredScreen, (screen_height + 1) * sizeof DesiredScreen[0]);
                    645:     return pause;
                    646: }
                    647: 
                    648: /* Decide what insert/delete line to do, and do it */
                    649: 
                    650: scrolling ()
                    651: {
                    652:   int unchanged_at_top, unchanged_at_bottom;
                    653:   int window_size;
                    654:   int changed_lines;
                    655:   int *old_hash = (int *) alloca (screen_height * sizeof (int));
                    656:   int *new_hash = (int *) alloca (screen_height * sizeof (int));
                    657:   int *draw_cost = (int *) alloca (screen_height * sizeof (int));
                    658:   register int i;
                    659:   int free_at_end_vpos = screen_height;
                    660:   
                    661:   /* Compute hash codes of all the lines.
                    662:      Also calculate number of changed lines,
                    663:      number of unchanged lines at the beginning,
                    664:      and number of unchanged lines at the end.  */
                    665: 
                    666:   changed_lines = 0;
                    667:   unchanged_at_top = 0;
                    668:   unchanged_at_bottom = screen_height;
                    669:   for (i = 0; i < screen_height; i++)
                    670:     {
                    671:       old_hash[i] = line_hash_code (PhysScreen[i + 1]);
                    672:       if (!DesiredScreen[i + 1])
                    673:        DesiredScreen[i + 1] = PhysScreen[i + 1];
                    674:       if (PhysScreen[i + 1] == DesiredScreen[i + 1])
                    675:        new_hash[i] = old_hash[i];
                    676:       else
                    677:        new_hash[i] = line_hash_code (DesiredScreen[i + 1]);
                    678:       if (old_hash[i] != new_hash[i])
                    679:        {
                    680:          changed_lines++;
                    681:          unchanged_at_bottom = screen_height - i - 1;
                    682:        }
                    683:       else if (i == unchanged_at_top)
                    684:        unchanged_at_top++;
                    685:       draw_cost[i] = line_draw_cost (DesiredScreen[i + 1]);
                    686:     }
                    687: 
                    688:   /* If changed lines are few, don't allow preemption, don't scroll.  */
                    689:   if (changed_lines < baud_rate / 2400 || unchanged_at_bottom == screen_height)
                    690:     return 1;
                    691: 
                    692:   window_size = screen_height - unchanged_at_top - unchanged_at_bottom;
                    693: 
                    694:   if (scroll_region_ok)
                    695:     free_at_end_vpos -= unchanged_at_bottom;
                    696:   else if (memory_below_screen)
                    697:     free_at_end_vpos = -1;
                    698: 
                    699:   /* If large window, fast terminal and few lines in common between
                    700:      PhysScreen and DesiredScreen, don't bother with i/d calc.  */
                    701:   if (window_size >= 18 && baud_rate > 2400
                    702:       && (window_size >=
                    703:          10 * scrolling_max_lines_saved (unchanged_at_top,
                    704:                                          screen_height - unchanged_at_bottom,
                    705:                                          old_hash, new_hash, draw_cost)))
                    706:     return 0;
                    707: 
                    708:   scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom,
                    709:               draw_cost + unchanged_at_top - 1,
                    710:               old_hash + unchanged_at_top - 1,
                    711:               new_hash + unchanged_at_top - 1,
                    712:               free_at_end_vpos - unchanged_at_top);
                    713: 
                    714:   return 0;
                    715: }
                    716: 
                    717: update_line (old, new, vpos)
                    718:      struct display_line *old, *new;
                    719:      int vpos;
                    720: {
                    721:   register char *obody, *nbody, *op1, *op2, *np1;
                    722:   int tem;
                    723:   int osp, nsp, m1, m2, olen, nlen;
                    724:   int save;
                    725: 
                    726:   if (old == new)
                    727:     return;
                    728: 
                    729:   /* Mark physical screen as containing the line `new' */
                    730:   PhysScreen[vpos + 1] = new;
                    731: 
                    732:   if ((new && new->highlighted) != (old && old->highlighted))
                    733:     {
                    734:       change_line_highlight (new && new->highlighted, vpos, old ? old->length : 0);
                    735:       old = 0;
                    736:     }
                    737:   else
                    738:     reassert_line_highlight (new && new->highlighted, vpos);
                    739: 
                    740:   if (!old)
                    741:     {
                    742:       olen = 0;
                    743:     }
                    744:   else
                    745:     {
                    746:       obody = old -> body;
                    747:       olen = old->length;
                    748:       if (!must_write_spaces)
                    749:        while (obody[olen - 1] == ' ')
                    750:          olen--;
                    751:     }
                    752: 
                    753:   if (!new)
                    754:     {
                    755:       nlen = 0;
                    756:       goto just_erase;
                    757:     }
                    758: 
                    759:   nbody = new -> body;
                    760:   nlen = new->length;
                    761: 
                    762:   /* We know that the previous character is the `physical' field
                    763:      and it is zero or one.  */
                    764:   if (!must_write_spaces)
                    765:     while (nbody[nlen - 1] == ' ')
                    766:       nlen--;
                    767: 
                    768:   if (!olen)
                    769:     {
                    770:       nsp = (must_write_spaces || new->highlighted)
                    771:              ? 0 : count_blanks (nbody);
                    772:       if (nlen > nsp)
                    773:        {
                    774:          topos (vpos, nsp);
                    775:          write_chars (nbody + nsp, nlen - nsp);
                    776:        }
                    777:       return;
                    778:     }
                    779: 
                    780:   obody[olen] = 1;
                    781:   save = nbody[nlen];
                    782:   nbody[nlen] = 0;
                    783: 
                    784:   /* Compute number of leading blanks in old and new contents.  */
                    785:   osp = count_blanks (obody);
                    786:   if (!new->highlighted)
                    787:     nsp = count_blanks (nbody);
                    788:   else
                    789:     nsp = 0;
                    790: 
                    791:   /* Compute number of matching chars starting with first nonblank.  */
                    792:   m1 = count_match (obody + osp, nbody + nsp);
                    793: 
                    794:   /* Spaces in new match implicit space past the end of old.  */
                    795:   /* This isn't really doing anything; osp should be osp + m1.
                    796:      I don't dare fix it now since maybe if it does anything
                    797:      it will do something bad.  */
                    798:   if (!must_write_spaces && osp == olen)
                    799:     {
                    800:       np1 = nbody + nsp;
                    801:       while (np1[m1] == ' ')
                    802:        m1++;
                    803:     }
                    804: 
                    805:   /* Avoid doing insert/delete char
                    806:      just cause number of leading spaces differs
                    807:      when the following text does not match. */
                    808:   if (m1 == 0 && osp != nsp)
                    809:     osp = nsp = min (osp, nsp);
                    810: 
                    811:   /* Find matching characters at end of line */
                    812:   op1 = obody + olen;
                    813:   np1 = nbody + nlen;
                    814:   op2 = op1 + m1 - min (olen - osp, nlen - nsp);
                    815:   while (op1 > op2 && op1[-1] == np1[-1])
                    816:     {
                    817:       op1--;
                    818:       np1--;
                    819:     }
                    820:   m2 = obody + olen - op1;
                    821: 
                    822:   /* Put correct value back in nbody[nlen].
                    823:      This is important because direct_output_for_insert
                    824:      can write into the line at a later point.  */
                    825:   nbody[nlen] = save;
                    826: 
                    827:   /* tem gets the distance to insert or delete.
                    828:      m2 is how many characters we save by doing so.
                    829:      Is it worth it?  */
                    830: 
                    831:   tem = (nlen - nsp) - (olen - osp);
                    832:   if (m2 && tem && m2 <= DCICcost[tem])
                    833:     m2 = 0;
                    834: 
                    835:   /* nsp - osp is the distance to insert or delete.
                    836:      m1 + m2 is how much we save by doing so.
                    837:      Is it worth it?  */
                    838: 
                    839:   if (m1 + m2 && nsp != osp && m1 + m2 <= DCICcost[nsp - osp])
                    840:     {
                    841:       m1 = 0;
                    842:       m2 = 0;
                    843:       osp = nsp = min (osp, nsp);
                    844:     }
                    845: 
                    846:   /* Now go through the line, inserting, writing and deleting as appropriate.  */
                    847: 
                    848:   if (osp > nsp)
                    849:     {
                    850:       topos (vpos, nsp);
                    851:       delete_chars (osp - nsp);
                    852:     }
                    853:   else if (nsp > osp)
                    854:     {
                    855:       /* If going to delete chars later in line
                    856:         and insert earlier in the line,
                    857:         must delete first to avoid losing data in the insert */
                    858:       if (m2 && nlen < olen + nsp - osp)
                    859:        {
                    860:          topos (vpos, nlen - m2 + osp - nsp);
                    861:          delete_chars (olen + nsp - osp - nlen);
                    862:          olen = nlen - (nsp - osp);
                    863:        }
                    864:       topos (vpos, osp);
                    865:       insert_chars ((char *)0, nsp - osp);
                    866:     }
                    867:   olen += nsp - osp;
                    868:   osp = nsp;
                    869: 
                    870:   tem = nsp + m1 + m2;
                    871:   if (nlen != tem || olen != tem)
                    872:     {
                    873:       topos (vpos, nsp + m1);
                    874:       if (!m2 || nlen == olen)
                    875:        {
                    876:          /* If new text being written reaches right margin,
                    877:             there is no need to do clear-to-eol at the end.
                    878:             (and it would not be safe, since cursor is not
                    879:             going to be "at the margin" after the text is done) */
                    880:          if (nlen == screen_width)
                    881:            olen = 0;
                    882:          write_chars (nbody + nsp + m1, nlen - tem);
                    883: #ifdef obsolete
                    884: /* the following code loses disastrously if tem == nlen.
                    885:    Rather than trying to fix that case, I am trying the simpler
                    886:    solution found above.  */
                    887:          /* If the text reaches to the right margin,
                    888:             it will lose one way or another (depending on AutoWrap)
                    889:             to clear to end of line after outputting all the text.
                    890:             So pause with one character to go and clear the line then.  */
                    891:          if (nlen == screen_width && fast_clear_end_of_line && olen > nlen)
                    892:            {
                    893:              /* m2 must be zero, and tem must equal nsp + m1 */
                    894:              write_chars (nbody + tem, nlen - tem - 1);
                    895:              clear_end_of_line (olen);
                    896:              olen = 0;         /* Don't let it be cleared again later */
                    897:              write_chars (nbody + nlen - 1, 1);
                    898:            }
                    899:          else
                    900:            write_chars (nbody + nsp + m1, nlen - tem);
                    901: #endif
                    902:        }
                    903:       else if (nlen > olen)
                    904:        {
                    905:          write_chars (nbody + nsp + m1, olen - tem);
                    906:          insert_chars (nbody + nsp + m1 + olen - tem, nlen - olen);
                    907:          olen = nlen;
                    908:        }
                    909:       else if (olen > nlen)
                    910:        {
                    911:          write_chars (nbody + nsp + m1, nlen - tem);
                    912:          delete_chars (olen - nlen);
                    913:          olen = nlen;
                    914:        }
                    915:     }
                    916: 
                    917:  just_erase:
                    918:   /* If any unerased characters remain after the new line, erase them.  */
                    919:   if (olen > nlen)
                    920:     {
                    921:       topos (vpos, nlen);
                    922:       clear_end_of_line (olen);
                    923:     }
                    924: }
                    925: 
                    926: count_blanks (str)
                    927:      char *str;
                    928: {
                    929:   register char *p = str;
                    930:   while (*str++ == ' ');
                    931:   return str - p - 1;
                    932: }
                    933: 
                    934: count_match (str1, str2)
                    935:      char *str1, *str2;
                    936: {
                    937:   register char *p1 = str1;
                    938:   register char *p2 = str2;
                    939:   while (*p1++ == *p2++);
                    940:   return p1 - str1 - 1;
                    941: }
                    942: 
                    943: DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
                    944:   1, 1, "FOpen termscript file: ",
                    945:   "Start writing all terminal output to FILE as well.")
                    946:   (file)
                    947:      Lisp_Object file;
                    948: {
                    949:   file = Fexpand_file_name (file, Qnil);
                    950:   termscript = fopen (XSTRING (file)->data, "w");
                    951:   return Qnil;
                    952: }
                    953: 
                    954: DEFUN ("set-screen-height", Fset_screen_height, Sset_screen_height, 1, 1, 0,
                    955:   "Set number of lines on screen available for use in windows.")
                    956:   (n)
                    957:      Lisp_Object n;
                    958: {
                    959:   CHECK_NUMBER (n, 0);
                    960:   change_screen_size (XINT (n), 0);
                    961:   return Qnil;
                    962: }
                    963: 
                    964: DEFUN ("set-screen-width", Fset_screen_width, Sset_screen_width, 1, 1, 0,
                    965:   "Set number of columns on screen available for display.")
                    966:   (n)
                    967:      Lisp_Object n;
                    968: {
                    969:   CHECK_NUMBER (n, 0);
                    970:   change_screen_size (0, XINT (n));
                    971:   return Qnil;
                    972: }
                    973: 
                    974: DEFUN ("screen-height", Fscreen_height, Sscreen_height, 0, 0, 0,
                    975:   "Return number of lines on screen available for use in windows.")
                    976:   ()
                    977: {
                    978:   return make_number (screen_height);
                    979: }
                    980: 
                    981: DEFUN ("screen-width", Fscreen_width, Sscreen_width, 0, 0, 0,
                    982:   "Return number of columns on screen available for display.")
                    983:   ()
                    984: {
                    985:   return make_number (screen_width);
                    986: }
                    987: 
                    988: /* Change the screen height and/or width.  Values may be given as zero to
                    989:    indicate no change is to take place. */
                    990: change_screen_size (newlength, newwidth)
                    991:      register int newlength, newwidth;
                    992: {
                    993:   if ((newlength == 0 || newlength == screen_height)
                    994:          && (newwidth == 0 || newwidth == screen_width))
                    995:       return;
                    996:   if (newlength && newlength != screen_height)
                    997:     {
                    998:       if (newlength > MScreenLength)
                    999:        newlength = MScreenLength;
                   1000:       set_window_height (XWINDOW (minibuf_window)->prev, newlength - 1, 0);
                   1001:       XFASTINT (XWINDOW (minibuf_window)->top) = newlength - 1;
                   1002:       set_window_height (minibuf_window, 1, 0);
                   1003:       screen_height = newlength;
                   1004:       set_terminal_window (0);
                   1005:     }
                   1006:   if (newwidth && newwidth != screen_width)
                   1007:     {
                   1008:       if (newwidth > MScreenWidth)
                   1009:        newwidth = MScreenWidth;
                   1010:       set_window_width (XWINDOW (minibuf_window)->prev, newwidth, 0);
                   1011:       set_window_width (minibuf_window, newwidth, 0);
                   1012:       screen_width = newwidth;
                   1013:     }
                   1014:   make_display_lines ();
                   1015:   calculate_costs ();
                   1016:   DoDsp (1);
                   1017: }
                   1018: 
                   1019: DEFSIMPLE ("baud-rate", Fbaud_rate, Sbaud_rate,
                   1020:           "Return the output baud rate of the terminal.",
                   1021:           Lisp_Int, XSETINT, baud_rate)
                   1022: 
                   1023: DEFUN ("send-string-to-terminal", Fsend_string_to_terminal,
                   1024:   Ssend_string_to_terminal, 1, 1, 0,
                   1025:   "Send STRING to the terminal without alteration.\n\
                   1026: Control characters in STRING will have terminal-dependent effects.")
                   1027:   (str)
                   1028:      Lisp_Object str;
                   1029: {
                   1030:   CHECK_STRING (str, 0);
                   1031:   fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, stdout);
                   1032:   fflush (stdout);
                   1033:   if (termscript)
                   1034:     {
                   1035:       fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, termscript);
                   1036:       fflush (termscript);
                   1037:     }
                   1038:   return Qnil;
                   1039: }
                   1040: 
                   1041: DEFUN ("ding", Fding, Sding, 0, 0, 0,
                   1042:   "Beep, or flash the screen.\n\
                   1043: Terminates any keyboard macro currently executing.")
                   1044:   ()
                   1045: {
                   1046:   Ding ();
                   1047:   return Qnil;
                   1048: }
                   1049: 
                   1050: Ding ()
                   1051: {
                   1052:   if (noninteractive)
                   1053:     putchar (07);
                   1054:   else if (!INTERACTIVE)  /* Stop executing a keyboard macro. */
                   1055:     error ("Keyboard macro terminated by a command ringing the bell");
                   1056:   else
                   1057:     ring_bell ();
                   1058:   fflush (stdout);
                   1059: }
                   1060: 
                   1061: DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 1, 0,
                   1062:   "Pause, without updating display, for ARG seconds.")
                   1063:   (n)
                   1064:      Lisp_Object n;
                   1065: {
                   1066:   register int t;
                   1067: #ifndef subprocesses
                   1068: #ifdef HAVE_TIMEVAL
                   1069:   struct timeval timeout, end_time, garbage1;
                   1070: #endif /* HAVE_TIMEVAL */
                   1071: #endif /* no subprocesses */
                   1072: 
                   1073:   CHECK_NUMBER (n, 0);
                   1074:   t = XINT (n);
                   1075:   if (t <= 0)
                   1076:     return Qnil;
                   1077: 
                   1078: #ifdef subprocesses
                   1079:   wait_reading_process_input (t, 0, 0);
                   1080: #else /* No subprocesses */
                   1081:   immediate_quit = 1;
                   1082:   QUIT;
                   1083: 
                   1084: #if defined(HAVE_SELECT) && defined(HAVE_TIMEVAL)
                   1085:   gettimeofday (&end_time, &garbage1);
                   1086:   end_time.tv_sec += t;
                   1087: 
                   1088:   while (1)
                   1089:     {
                   1090:       gettimeofday (&timeout, &garbage1);
                   1091:       timeout.tv_sec = end_time.tv_sec - timeout.tv_sec;
                   1092:       timeout.tv_usec = end_time.tv_usec - timeout.tv_usec;
                   1093:       if (timeout.tv_usec < 0)
                   1094:        timeout.tv_usec += 1000000,
                   1095:       timeout.tv_sec--;
                   1096:       if (timeout.tv_sec < 0)
                   1097:        break;
                   1098:       if (!select (1, 0, 0, 0, &timeout))
                   1099:        break;
                   1100:     }
                   1101: #else /* not both HAVE_SELECT and HAVE_TIMEVAL */
                   1102:   /* Is it safe to quit out of `sleep'?  I'm afraid to trust it.  */
                   1103:   sleep (t);
                   1104: #endif /* not both HAVE_SELECT and HAVE_TIMEVAL */
                   1105: 
                   1106:   immediate_quit = 0;
                   1107: #endif /* no subprocesses */
                   1108:   return Qnil;
                   1109: }
                   1110: 
                   1111: DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 1, 0,
                   1112:   "Perform redisplay, then wait for ARG seconds or until input is available")
                   1113:   (n)
                   1114:      Lisp_Object n;
                   1115: {
                   1116: #ifndef subprocesses
                   1117: #ifdef HAVE_TIMEVAL
                   1118:   struct timeval timeout;
                   1119: #else
                   1120:   int timeout_sec;
                   1121: #endif
                   1122:   int waitchannels;
                   1123: #endif /* no subprocesses */
                   1124: 
                   1125:   CHECK_NUMBER (n, 0);
                   1126: 
                   1127:   if (detect_input_pending ())
                   1128:     return Qnil;
                   1129: 
                   1130:   DoDsp (1);                   /* Make the screen correct */
                   1131:   if (XINT (n) <= 0) return Qnil;
                   1132: 
                   1133: #ifdef subprocesses
                   1134: #ifdef SIGIO
                   1135:   gobble_input ();
                   1136: #endif /* SIGIO */
                   1137:   wait_reading_process_input (XINT (n), 1, 1);
                   1138: #else /* no subprocesses */
                   1139:   immediate_quit = 1;
                   1140:   QUIT;
                   1141: 
                   1142:   waitchannels = 1;
                   1143: #ifndef HAVE_TIMEVAL
                   1144:   timeout_sec = XINT (n);
                   1145:   select (1, &waitchannels, 0, 0, &timeout_sec);
                   1146: #else /* HAVE_TIMEVAL */
                   1147:   timeout.tv_sec = XINT (n);  
                   1148:   timeout.tv_usec = 0;
                   1149:   select (1, &waitchannels, 0, 0, &timeout);
                   1150: #endif /* HAVE_TIMEVAL */
                   1151: 
                   1152:   immediate_quit = 0;
                   1153: #endif /* no subprocesses */
                   1154:   return Qnil;
                   1155: }
                   1156: 
                   1157: char *terminal_type;
                   1158: 
                   1159: /* Initialization done when Emacs fork is started, before doing stty. */
                   1160: /* Determine terminal type and set terminal_driver */
                   1161: /* Then invoke its decoding routine to set up variables
                   1162:   in the terminal package */
                   1163: 
                   1164: init_display ()
                   1165: {
                   1166:   MetaFlag = 0;
                   1167:   inverse_video = 0;
                   1168: 
                   1169:   /* Look at the TERM variable and set terminal_driver.  */
                   1170: 
                   1171:   terminal_type = (char *) getenv ("TERM");
                   1172:   if (!terminal_type)
                   1173:     {
                   1174:       fprintf (stderr, "Please set the environment variable TERM; see tset(1).\n");
                   1175:       exit (1);
                   1176:     }
                   1177: #ifdef HAVE_X_WINDOWS
                   1178:   if (!strncmp (terminal_type, "xterm", 5))
                   1179:     x_term_init ();
                   1180:   else
                   1181: #endif /* HAVE_X_WINDOWS */
                   1182:     term_init (terminal_type);
                   1183: 
                   1184:   make_display_lines ();
                   1185: 
                   1186:   cursX = 0;           /* X and Y coordinates of the cursor */
                   1187:   cursY = 0;           /* between updates. */
                   1188: }
                   1189: 
                   1190: syms_of_display ()
                   1191: {
                   1192:   defsubr (&Sopen_termscript);
                   1193:   defsubr (&Sding);
                   1194:   defsubr (&Ssit_for);
                   1195:   defsubr (&Sscreen_height);
                   1196:   defsubr (&Sscreen_width);
                   1197:   defsubr (&Sset_screen_height);
                   1198:   defsubr (&Sset_screen_width);
                   1199:   defsubr (&Ssleep_for);
                   1200:   defsubr (&Sbaud_rate);
                   1201:   defsubr (&Ssend_string_to_terminal);
                   1202: 
                   1203:   DefBoolVar ("inverse-video", &inverse_video,
                   1204:     "*Non-nil means use inverse-video.");
                   1205:   DefBoolVar ("visible-bell", &visible_bell,
                   1206:     "*Non-nil means try to flash the screen to represent a bell.");
                   1207: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.