Annotation of GNUtools/emacs/src/dispnew.c, revision 1.1.1.1

1.1       root        1: /* Newly written part of redisplay code.
                      2:    Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU Emacs.
                      5: 
                      6: GNU Emacs is free software; you can redistribute it and/or modify
                      7: it under the terms of the GNU General Public License as published by
                      8: the Free Software Foundation; either version 1, or (at your option)
                      9: any later version.
                     10: 
                     11: GNU Emacs is distributed in the hope that it will be useful,
                     12: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: GNU General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU Emacs; see the file COPYING.  If not, write to
                     18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     19: 
                     20: 
                     21: /* This must precede sys/signal.h on certain machines.  */
                     22: #include <sys/types.h>
                     23: #include <signal.h>
                     24: 
                     25: #include "config.h"
                     26: #include <stdio.h>
                     27: #include <errno.h>
                     28: 
                     29: #ifdef HAVE_TIMEVAL
                     30: #ifdef HPUX
                     31: #include <time.h>
                     32: #else
                     33: #include <sys/time.h>
                     34: #endif
                     35: #endif
                     36: 
                     37: #ifdef HAVE_TERMIO
                     38: #include <termio.h>
                     39: #ifdef TCOUTQ
                     40: #undef TIOCOUTQ
                     41: #define TIOCOUTQ TCOUTQ
                     42: #include <fcntl.h>
                     43: #endif /* TCOUTQ defined */
                     44: #else
                     45: #ifndef VMS
                     46: #include <sys/ioctl.h>
                     47: #endif /* not VMS */
                     48: #endif /* not HAVE_TERMIO */
                     49: 
                     50: /* Allow m- file to inhibit use of FIONREAD.  */
                     51: #ifdef BROKEN_FIONREAD
                     52: #undef FIONREAD
                     53: #endif
                     54: 
                     55: /* We are unable to use interrupts if FIONREAD is not available,
                     56:    so flush SIGIO so we won't try. */
                     57: #ifndef FIONREAD
                     58: #ifdef SIGIO
                     59: #undef SIGIO
                     60: #endif
                     61: #endif
                     62: 
                     63: #undef NULL
                     64: 
                     65: #include "termchar.h"
                     66: #include "termopts.h"
                     67: #include "cm.h"
                     68: #include "dispextern.h"
                     69: #include "lisp.h"
                     70: #include "buffer.h"
                     71: #include "window.h"
                     72: #include "commands.h"
                     73: 
                     74: #define max(a, b) ((a) > (b) ? (a) : (b))
                     75: #define min(a, b) ((a) < (b) ? (a) : (b))
                     76: 
                     77: #ifndef PENDING_OUTPUT_COUNT
                     78: /* Get number of chars of output now in the buffer of a stdio stream.
                     79:    This ought to be built in in stdio, but it isn't.
                     80:    Some s- files override this because their stdio internals differ.  */
                     81: #ifdef __GNU_LIBRARY__
                     82: #define        PENDING_OUTPUT_COUNT(FILE) ((FILE)->__bufp - (FILE)->__buffer)
                     83: #else
                     84: #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base)
                     85: #endif
                     86: #endif /* No PENDING_OUTPUT_COUNT */
                     87: 
                     88: /* Nonzero means do not assume anything about current
                     89:    contents of actual terminal screen */
                     90: 
                     91: int screen_garbaged;
                     92: 
                     93: /* Desired terminal cursor position (to show position of point),
                     94:    origin zero */
                     95: 
                     96: int cursor_hpos, cursor_vpos;
                     97: 
                     98: /* Nonzero means last display completed and cursor is really at
                     99:    cursor_hpos, cursor_vpos.  Zero means it was preempted. */
                    100: 
                    101: int display_completed;
                    102: 
                    103: /* Lisp variable visible-bell; enables use of screen-flash
                    104:    instead of audible bell.  */
                    105: 
                    106: int visible_bell;
                    107: 
                    108: /* Invert the color of the whole screen, at a low level.  */
                    109: 
                    110: int inverse_video;
                    111: 
                    112: /* Line speed of the terminal.  */
                    113: 
                    114: int baud_rate;
                    115: 
                    116: /* nil or a symbol naming the window system
                    117:    under which emacs is running
                    118:    ('x is the only current possibility).  */
                    119: 
                    120: Lisp_Object Vwindow_system;
                    121: 
                    122: /* Version number of window system, or nil if no window system.  */
                    123: 
                    124: Lisp_Object Vwindow_system_version;
                    125: 
                    126: /* Nonzero means reading single-character input with prompt
                    127:    so put cursor on minibuffer after the prompt.  */
                    128: 
                    129: int cursor_in_echo_area;
                    130: 
                    131: /* Nonzero means finish redisplay regardless of available input.
                    132:    This is used with X windows to avoid a weird timing-dependent bug.  */
                    133: 
                    134: int force_redisplay;
                    135: 
                    136: /* Description of actual screen contents.  */
                    137:  
                    138: struct matrix *current_screen;
                    139: 
                    140: /* Description of desired screen contents.  */
                    141: 
                    142: struct matrix *new_screen;
                    143: 
                    144: /* Buffer sometimes used to hold partial screen contents.  */
                    145: 
                    146: struct matrix *temp_screen;
                    147: 
                    148: /* Stdio stream being used for copy of all terminal output.  */
                    149: 
                    150: FILE *termscript;
                    151: 
                    152: /* Structure for info on cursor positioning */
                    153: 
                    154: struct cm Wcm;
                    155: 
                    156: int delayed_size_change;  /* 1 means SIGWINCH happened when not safe.  */
                    157: int delayed_screen_height;  /* Remembered new screen height.  */
                    158: int delayed_screen_width;   /* Remembered new screen width.  */
                    159: 
                    160: /* This buffer records the history of display preemption.  */
                    161: 
                    162: struct preempt
                    163: {
                    164:   /* Number of keyboard characters read so far at preempt.  */
                    165:   int keyboard_char_count;
                    166:   /* Vertical position at which preemption occurred.  */
                    167:   int vpos;
                    168: };
                    169: 
                    170: #define N_PREEMPTIONS 50
                    171: 
                    172: /* Circular buffer recording recent display preemptions.  */
                    173: struct preempt preemptions[N_PREEMPTIONS];
                    174: 
                    175: /* Index of next element in preemptions.  */
                    176: int preemption_index;
                    177: 
                    178: /* Set these variables in the debugger to force a display preemption.  */
                    179: int debug_preemption_vpos = -1;
                    180: int debug_preemption_char_count = -1;
                    181: 
                    182: extern int num_input_chars;
                    183: 
                    184: /* Free and reallocate current_screen and new_screen.  */
                    185: 
                    186: struct matrix *make_screen_structure ();
                    187: 
                    188: remake_screen_structures ()
                    189: {
                    190:   int i;
                    191: 
                    192:   if (current_screen)
                    193:     free_screen_structure (current_screen);
                    194:   if (new_screen)
                    195:     free_screen_structure (new_screen);
                    196:   if (temp_screen)
                    197:     free_screen_structure (temp_screen);
                    198: 
                    199:   current_screen = make_screen_structure (0);
                    200:   new_screen = make_screen_structure (0);
                    201:   temp_screen = make_screen_structure (1);
                    202: 
                    203:   if (message_buf)
                    204:     {
                    205:       /* The echo_area_contents, used by error and message, may be pointing at
                    206:         the string we are replacing.  If so, update it.  */
                    207:       int repair_echo_area_contents = echo_area_contents == message_buf;
                    208: 
                    209:       message_buf = (char *) xrealloc (message_buf, screen_width + 1);
                    210: 
                    211:       if (repair_echo_area_contents) echo_area_contents = message_buf;
                    212:     } 
                    213:   else
                    214:     message_buf = (char *) xmalloc (screen_width + 1);
                    215: 
                    216:   /* This may fix a problem of occasionally displaying garbage in the echo area
                    217:      after a resize in X Windows.  */
                    218:   for (i = 0; i < screen_width; i++)
                    219:     message_buf[i] = ' ';
                    220:   message_buf[screen_width] = 0;
                    221: }
                    222: 
                    223: struct matrix *
                    224: make_screen_structure (empty)
                    225:      int empty;
                    226: {
                    227:   int i;
                    228:   struct matrix *new = (struct matrix *) xmalloc (sizeof (struct matrix));
                    229: 
                    230:   new->height = screen_height;
                    231:   new->width = screen_width;
                    232:   new->highlight = (char *) xmalloc (screen_height);
                    233:   new->enable = (char *) xmalloc (screen_height);
                    234:   new->contents = (unsigned char **) xmalloc (screen_height * sizeof (char *));
                    235:   new->used = (int *) xmalloc (screen_height * sizeof (int));
                    236:   if (empty)
                    237:     {
                    238:       /* Make the buffer used by decode_mode_spec.  */
                    239:       new->total_contents = (unsigned char *) xmalloc (screen_width + 2);
                    240:       for (i = 0; i < screen_width; i++)
                    241:        new->total_contents[i] = ' ';
                    242:       new->total_contents[screen_width] = 0;
                    243:     }
                    244:   else
                    245:     {
                    246:       /* Add 2 to leave extra bytes at beginning and end of each line.  */ 
                    247:       new->total_contents = (unsigned char *) xmalloc (screen_height * (screen_width + 2));
                    248:       for (i = 0; i < screen_height; i++)
                    249:        {
                    250:          int j;
                    251: 
                    252:          new->contents[i] = new->total_contents + i * (screen_width + 2) + 1;
                    253:          new->contents[i][screen_width] = 0;
                    254:          new->contents[i][-1] = 0;
                    255:          for (j = 0; j < screen_width; j++)
                    256:            new->contents[i][j] = ' ';
                    257:        }
                    258:     }
                    259:   bzero (new->enable, screen_height);
                    260:   return new;
                    261: }
                    262: 
                    263: free_screen_structure (matrix)
                    264:      struct matrix *matrix;
                    265: {
                    266:   if (matrix->total_contents)
                    267:     free (matrix->total_contents);
                    268:   free (matrix->contents);
                    269:   free (matrix->highlight);
                    270:   free (matrix->enable);
                    271:   free (matrix->used);
                    272:   free (matrix);
                    273: }
                    274: 
                    275: /* Return the hash code of contents of line VPOS of screen-matrix M.  */
                    276: 
                    277: int
                    278: line_hash_code (m, vpos)
                    279:      struct matrix *m;
                    280:      int vpos;
                    281: {
                    282:   register unsigned char *body;
                    283:   register int h = 0;
                    284:   /* Give all lighlighted lines the same hash code
                    285:      so as to encourage scrolling to leave them in place.  */
                    286:   if (m->highlight[vpos])
                    287:     return -1;
                    288: 
                    289:   body = m->contents[vpos];
                    290: 
                    291:   if (must_write_spaces)
                    292:     {
                    293:       while (1)
                    294:        {
                    295:          int c = *body++;
                    296:          if (c == 0)
                    297:            break;
                    298:          h = (((h << 4) + (h >> 24)) & 0x0fffffff) + c - ' ';
                    299:        }
                    300:     }
                    301:   else
                    302:     {
                    303:       while (1)
                    304:        {
                    305:          int c = *body++;
                    306:          if (c == 0)
                    307:            break;
                    308:          h = (((h << 4) + (h >> 24)) & 0x0fffffff) + c;
                    309:        }
                    310:     }
                    311:   if (h)
                    312:     return h;
                    313:   return 1;
                    314: }
                    315: 
                    316: /* Return number of characters in line in M at vpos VPOS,
                    317:    except don't count leading and trailing spaces
                    318:    unless the terminal requires those to be explicitly output.  */
                    319: 
                    320: int
                    321: line_draw_cost (m, vpos)
                    322:      struct matrix *m;
                    323:      int vpos;
                    324: {
                    325:   register unsigned char *body;
                    326:   register int i;
                    327: 
                    328:   if (must_write_spaces)
                    329:     return m->used[vpos];
                    330: 
                    331:   body = m->contents[vpos];
                    332:   for (i = m->used[vpos]; i > 0 && body[i - 2] == ' '; i--);
                    333: 
                    334:   i -= count_blanks (body);
                    335:   return max (i, 0);
                    336: }
                    337: 
                    338: /* The functions on this page are the interface from xdisp.c to redisplay.
                    339: 
                    340:  The only other interface into redisplay is through setting
                    341:  cursor_hpos and cursor_vpos (in xdisp.c) and setting screen_garbaged. */
                    342: 
                    343: /* cancel_line eliminates any request to display a line at position `vpos' */
                    344: 
                    345: cancel_line (vpos)
                    346:      int vpos;
                    347: {
                    348:   new_screen->enable[vpos] = 0;
                    349: }
                    350: 
                    351: clear_screen_records ()
                    352: {
                    353:   int i;
                    354: 
                    355:   bzero (current_screen->enable, screen_height);
                    356: }
                    357: 
                    358: /* Get ready to display on line `vpos'
                    359:    and set it up for outputting starting at `hpos' within it.
                    360:    Return the text string where that line is stored.  */
                    361: 
                    362: unsigned char *
                    363: get_display_line (vpos, hpos)
                    364:      int vpos;
                    365:      register int hpos;
                    366: {
                    367:   if (new_screen->enable[vpos] && new_screen->used[vpos] > hpos)
                    368:     abort ();
                    369:   if (! new_screen->enable[vpos])
                    370:     {
                    371:       new_screen->used[vpos] = 0;
                    372:       new_screen->highlight[vpos] = 0;
                    373:       new_screen->enable[vpos] = 1;
                    374:     }
                    375: 
                    376:   if (hpos > new_screen->used[vpos])
                    377:     {
                    378:       unsigned char *p = new_screen->contents[vpos] + new_screen->used[vpos];
                    379:       unsigned char *end = new_screen->contents[vpos] + hpos;
                    380:       new_screen->used[vpos] = hpos;
                    381:       while (p != end)
                    382:        *p++ = ' ';
                    383:     }
                    384: 
                    385:   return new_screen->contents[vpos];
                    386: }
                    387: 
                    388: /* Scroll lines from vpos `from' up to but not including vpos `end'
                    389:  down by `amount' lines (`amount' may be negative).
                    390:  Returns nonzero if done, zero if terminal cannot scroll them. */
                    391: 
                    392: int
                    393: scroll_screen_lines (from, end, amount)
                    394:      int from, end, amount;
                    395: {
                    396:   register int i;
                    397: 
                    398:   if (!line_ins_del_ok)
                    399:     return 0;
                    400: 
                    401:   if (amount == 0)
                    402:     return 1;
                    403:   if (amount > 0)
                    404:     {
                    405:       set_terminal_window (end + amount);
                    406:       if (!scroll_region_ok)
                    407:        ins_del_lines (end, -amount);
                    408:       ins_del_lines (from, amount);
                    409:       set_terminal_window (0);
                    410: 
                    411:       rotate_vector (current_screen->contents + from,
                    412:                     sizeof (char *) * (end + amount - from),
                    413:                     amount * sizeof (char *));
                    414:       safe_bcopy (current_screen->used + from,
                    415:                  current_screen->used + from + amount,
                    416:                  (end - from) * sizeof current_screen->used[0]);
                    417:       safe_bcopy (current_screen->highlight + from,
                    418:                  current_screen->highlight + from + amount,
                    419:                  (end - from) * sizeof current_screen->highlight[0]);
                    420:       safe_bcopy (current_screen->enable + from,
                    421:                  current_screen->enable + from + amount,
                    422:                  (end - from) * sizeof current_screen->enable[0]);
                    423:       /* Mark the lines made empty by scrolling as enabled, empty and
                    424:         normal video.  */
                    425:       bzero (current_screen->used + from,
                    426:             amount * sizeof current_screen->used[0]);
                    427:       bzero (current_screen->highlight + from,
                    428:             amount * sizeof current_screen->highlight[0]);
                    429:       for (i = from; i < from + amount; i++)
                    430:        {
                    431:          current_screen->contents[i][0] = '\0';
                    432:          current_screen->enable[i] = 1;
                    433:        }
                    434:     }
                    435:   if (amount < 0)
                    436:     {
                    437:       set_terminal_window (end);
                    438:       ins_del_lines (from + amount, amount);
                    439:       if (!scroll_region_ok)
                    440:        ins_del_lines (end + amount, -amount);
                    441:       set_terminal_window (0);
                    442: 
                    443:       rotate_vector (current_screen->contents + from + amount,
                    444:                     sizeof (char *) * (end - from - amount),
                    445:                     (end - from) * sizeof (char *));
                    446:       safe_bcopy (current_screen->used + from,
                    447:                  current_screen->used + from + amount,
                    448:                  (end - from) * sizeof current_screen->used[0]);
                    449:       safe_bcopy (current_screen->highlight + from,
                    450:                  current_screen->highlight + from + amount,
                    451:                  (end - from) * sizeof current_screen->highlight[0]);
                    452:       safe_bcopy (current_screen->enable + from,
                    453:                  current_screen->enable + from + amount,
                    454:                  (end - from) * sizeof current_screen->enable[0]);
                    455:       /* Mark the lines made empty by scrolling as enabled, empty and
                    456:         normal video.  */
                    457:       bzero (current_screen->used + end + amount,
                    458:             - amount * sizeof current_screen->used[0]);
                    459:       bzero (current_screen->highlight + end + amount,
                    460:             - amount * sizeof current_screen->highlight[0]);
                    461:       for (i = end + amount; i < end; i++)
                    462:        {
                    463:          current_screen->contents[i][0] = '\0';
                    464:          current_screen->enable[i] = 1;
                    465:        }
                    466:     }
                    467:   return 1;
                    468: }
                    469: 
                    470: /* Rotate a vector of SIZE bytes, by DISTANCE bytes.
                    471:    DISTANCE may be negative.  */
                    472: 
                    473: rotate_vector (vector, size, distance)
                    474:      char *vector;
                    475:      int size;
                    476:      int distance;
                    477: {
                    478:   char *temp = (char *) alloca (size);
                    479: 
                    480:   if (distance < 0)
                    481:     distance += size;
                    482: 
                    483:   bcopy (vector, temp + distance, size - distance);
                    484:   bcopy (vector + size - distance, temp, distance);
                    485:   bcopy (temp, vector, size);
                    486: }
                    487: 
                    488: /* Like bcopy except never gets confused by overlap.  */
                    489: 
                    490: safe_bcopy (from, to, size)
                    491:      char *from, *to;
                    492:      int size;
                    493: {
                    494:   register char *endf;
                    495:   register char *endt;
                    496: 
                    497:   if (size == 0)
                    498:     return;
                    499:   if (from > to)
                    500:     {
                    501:       /* If destination is lower in memory, we can go from the beginning.  */
                    502:       endf = from + size;
                    503:       while (from != endf)
                    504:        *to++ = *from++;
                    505:       return;
                    506:     }
                    507: 
                    508:   /* If destination is higher in memory, we can go backwards from the end.  */
                    509:   endf = from + size;
                    510:   endt = to + size;
                    511: 
                    512:   do
                    513:     *--endt = *--endf;
                    514:   while (endf != from);
                    515: }
                    516: 
                    517: /* After updating a window w that isn't the full screen wide,
                    518:  copy all the columns that w does not occupy
                    519:  from current_screen to new_screen,
                    520:  so that update_screen will not change those columns.  */
                    521: 
                    522: preserve_other_columns (w)
                    523:      struct window *w;
                    524: {
                    525:   register int vpos;
                    526:   int start = XFASTINT (w->left);
                    527:   int end = XFASTINT (w->left) + XFASTINT (w->width);
                    528:   int bot = XFASTINT (w->top) + XFASTINT (w->height);
                    529: 
                    530:   for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
                    531:     {
                    532:       if (current_screen->enable[vpos] && new_screen->enable[vpos])
                    533:        {
                    534:          if (start > 0)
                    535:            {
                    536:              int len;
                    537: 
                    538:              bcopy (current_screen->contents[vpos],
                    539:                     new_screen->contents[vpos], start);
                    540:              len = min (start, current_screen->used[vpos]);
                    541:              if (new_screen->used[vpos] < len)
                    542:                new_screen->used[vpos] = len;
                    543:            }
                    544:          if (current_screen->used[vpos] > end
                    545:              && new_screen->used[vpos] < current_screen->used[vpos])
                    546:            {
                    547:              while (new_screen->used[vpos] < end)
                    548:                new_screen->contents[vpos][new_screen->used[vpos]++] = ' ';
                    549:              bcopy (current_screen->contents[vpos] + end,
                    550:                     new_screen->contents[vpos] + end,
                    551:                     current_screen->used[vpos] - end);
                    552:              new_screen->used[vpos] = current_screen->used[vpos];
                    553:            }
                    554:        }
                    555:     }
                    556: }
                    557: 
                    558: /* On discovering that the redisplay for a window was no good,
                    559:  cancel the columns of that window,
                    560:  so that when the window is displayed over again
                    561:  get_display_line will not complain. */
                    562: 
                    563: cancel_my_columns (w)
                    564:      struct window *w;
                    565: {
                    566:   register int vpos;
                    567:   register int start = XFASTINT (w->left);
                    568:   register int bot = XFASTINT (w->top) + XFASTINT (w->height);
                    569: 
                    570:   for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
                    571:     if (new_screen->enable[vpos] && new_screen->used[vpos] >= start)
                    572:       new_screen->used[vpos] = start;
                    573: }
                    574: 
                    575: /* These functions try to perform directly and immediately on the screen
                    576:    the necessary output for one change in the buffer.
                    577:    They may return 0 meaning nothing was done if anything is difficult,
                    578:    or 1 meaning the output was performed properly.
                    579:    They assume that the screen was up to date before the buffer
                    580:    change being displayed.  THey make various other assumptions too;
                    581:    see command_loop_1 where these are called.  */
                    582: 
                    583: int
                    584: direct_output_for_insert (c)
                    585:      int c;
                    586: {
                    587: #ifndef COMPILER_REGISTER_BUG
                    588:   register
                    589: #endif COMPILER_REGISTER_BUG
                    590:     struct window *w = XWINDOW (selected_window);
                    591: #ifndef COMPILER_REGISTER_BUG
                    592:   register
                    593: #endif COMPILER_REGISTER_BUG
                    594:     int hpos = cursor_hpos;
                    595: #ifndef COMPILER_REGISTER_BUG
                    596:   register
                    597: #endif COMPILER_REGISTER_BUG
                    598:     int vpos = cursor_vpos;
                    599: 
                    600:   /* Give up if about to continue line */
                    601:   if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width)
                    602: 
                    603:   /* Avoid losing if cursor is in invisible text off left margin */
                    604:       || (XINT (w->hscroll) && hpos == XFASTINT (w->left))
                    605:     
                    606:   /* Give up if cursor outside window (in minibuf, probably) */
                    607:       || cursor_vpos < XFASTINT (w->top)
                    608:       || cursor_vpos >= XFASTINT (w->top) + XFASTINT (w->height)
                    609: 
                    610:   /* Give up if cursor not really at cursor_hpos, cursor_vpos */
                    611:       || !display_completed
                    612: 
                    613:   /* Give up if w is minibuffer and a message is being displayed there */
                    614:       || (EQ (selected_window, minibuf_window) && echo_area_contents))
                    615:     return 0;
                    616: 
                    617:   current_screen->contents[vpos][hpos] = c;
                    618:   unchanged_modified = MODIFF;
                    619:   beg_unchanged = GPT - BEG;
                    620:   XFASTINT (w->last_point) = point;
                    621:   XFASTINT (w->last_point_x) = cursor_hpos;
                    622:   XFASTINT (w->last_modified) = MODIFF;
                    623: 
                    624:   reassert_line_highlight (0, cursor_vpos);
                    625:   output_chars (&current_screen->contents[vpos][hpos], 1);
                    626:   fflush (stdout);
                    627:   ++cursor_hpos;
                    628:   if (hpos == current_screen->used[vpos])
                    629:     {
                    630:       current_screen->used[vpos] = hpos + 1;
                    631:       current_screen->contents[vpos][hpos + 1] = 0;
                    632:     }
                    633:   return 1;
                    634: }
                    635: 
                    636: int
                    637: direct_output_forward_char (n)
                    638:      int n;
                    639: {
                    640:   register struct window *w = XWINDOW (selected_window);
                    641: 
                    642:   /* Avoid losing if cursor is in invisible text off left margin */
                    643:   if (XINT (w->hscroll) && cursor_hpos == XFASTINT (w->left))
                    644:     return 0;
                    645:   /* Don't lose if we are in the truncated text at the end.  */
                    646:   if (cursor_hpos >= XFASTINT (w->left) + XFASTINT (w->width) - 1)
                    647:     return 0;
                    648:   /* Don't move past the window edges.  */
                    649:   if (cursor_hpos + n >= XFASTINT (w->left) + XFASTINT (w->width) - 1)
                    650:     return 0;
                    651:   if (cursor_hpos + n <= XFASTINT (w->left))
                    652:     return 0;
                    653: 
                    654:   cursor_hpos += n;
                    655:   XFASTINT (w->last_point_x) = cursor_hpos;
                    656:   XFASTINT (w->last_point) = point;
                    657:   move_cursor (cursor_vpos, cursor_hpos);
                    658:   fflush (stdout);
                    659:   return 1;
                    660: }
                    661: 
                    662: /* Update the actual terminal screen based on the data in new_screen.
                    663:    Value is nonzero if redisplay stopped due to pending input.
                    664:    FORCE nonzero means do not stop for pending input.  */
                    665: 
                    666: update_screen (force, inhibit_hairy_id)
                    667:      int force;
                    668:      int inhibit_hairy_id;
                    669: {
                    670:   register struct display_line **p;
                    671:   register struct display_line *l, *lnew;
                    672:   register int i;
                    673:   int pause;
                    674:   int preempt_count = baud_rate / 2400 + 1;
                    675:   extern input_pending;
                    676: 
                    677:   if (screen_height == 0) abort (); /* Some bug zeros some core */
                    678: 
                    679:   if (force_redisplay)
                    680:     force = 1;
                    681: 
                    682:   if (!force)
                    683:     detect_input_pending ();
                    684:   if (!force
                    685:       && ((num_input_chars == debug_preemption_char_count
                    686:           && debug_preemption_vpos == screen_height - 1)
                    687:          || input_pending))
                    688:     {
                    689:       pause = screen_height;
                    690:       goto do_pause;
                    691:     }
                    692: 
                    693:   update_begin ();
                    694: 
                    695:   if (!line_ins_del_ok)
                    696:     inhibit_hairy_id = 1;
                    697: 
                    698:   /* Don't compute for i/d line if just want cursor motion. */
                    699:   for (i = 0; i < screen_height; i++)
                    700:     if (new_screen->enable)
                    701:       break;
                    702: 
                    703:   /* Try doing i/d line, if not yet inhibited.  */
                    704:   if (!inhibit_hairy_id && i < screen_height)
                    705:     force |= scrolling ();
                    706: 
                    707:   /* Update the individual lines as needed.  Do bottom line first.  */
                    708: 
                    709:   if (new_screen->enable[screen_height - 1])
                    710:     update_line (screen_height - 1);
                    711:   for (i = 0; i < screen_height - 1 && (force || !input_pending); i++)
                    712:     {
                    713:       if (!force && num_input_chars == debug_preemption_char_count
                    714:          && debug_preemption_vpos == i)
                    715:        break;
                    716:       if (new_screen->enable[i])
                    717:        {
                    718:          /* Flush out every so many lines.
                    719:             Also flush out if likely to have more than 1k buffered
                    720:             otherwise.   I'm told that telnet connections get really
                    721:             screwed by more than 1k output at once.  */
                    722:          int outq = PENDING_OUTPUT_COUNT (stdout);
                    723:          if (outq > 900
                    724:              || (outq > 20 && ((i - 1) % preempt_count == 0)))
                    725:            {
                    726:              fflush (stdout);
                    727:              if (preempt_count == 1)
                    728:                {
                    729: #ifdef TIOCOUTQ
                    730:                  if (ioctl (0, TIOCOUTQ, &outq) < 0)
                    731:                    /* Probably not a tty.  Ignore the error and reset
                    732:                     * the outq count. */
                    733:                    outq = PENDING_OUTPUT_COUNT (stdout);
                    734: #endif
                    735:                  outq *= 10;
                    736:                  sleep (outq / baud_rate);
                    737:                }
                    738:            }
                    739:          if ((i - 1) % preempt_count == 0 && !force)
                    740:            detect_input_pending ();
                    741:          /* Now update this line.  */
                    742:          update_line (i);
                    743:        }
                    744:     }
                    745:   pause = (i < screen_height - 1) ? i + 1 : 0;
                    746: 
                    747:   /* Now just clean up termcap drivers and set cursor, etc.  */
                    748:   if (!pause)
                    749:     {
                    750:       if (cursor_in_echo_area < 0)
                    751:        move_cursor (screen_height - 1, 0);
                    752:       else if (cursor_in_echo_area > 0
                    753:               && !current_screen->enable[screen_height - 1])
                    754:        move_cursor (screen_height - 1, 0);
                    755:       else if (cursor_in_echo_area)
                    756:        move_cursor (screen_height - 1,
                    757:                     min (screen_width - 1,
                    758:                          current_screen->used[screen_height - 1]));
                    759:       else
                    760:        move_cursor (cursor_vpos, max (min (cursor_hpos, screen_width - 1), 0));
                    761:     }
                    762: 
                    763:   update_end ();
                    764: 
                    765:   if (termscript)
                    766:     fflush (termscript);
                    767:   fflush (stdout);
                    768: 
                    769:   /* Here if output is preempted because input is detected.  */
                    770:  do_pause:
                    771: 
                    772:   if (screen_height == 0) abort (); /* Some bug zeros some core */
                    773:   display_completed = !pause;
                    774:   if (pause)
                    775:     {
                    776:       preemptions[preemption_index].vpos = pause - 1;
                    777:       preemptions[preemption_index].keyboard_char_count = num_input_chars;
                    778:       preemption_index++;
                    779:       if (preemption_index == N_PREEMPTIONS)
                    780:        preemption_index = 0;
                    781:     }
                    782: 
                    783:   bzero (new_screen->enable, screen_height);
                    784:   return pause;
                    785: }
                    786: 
                    787: /* Called when about to quit, to check for doing so
                    788:    at an improper time.  */
                    789: 
                    790: void
                    791: quit_error_check ()
                    792: {
                    793:   if (new_screen == 0)
                    794:     return;
                    795:   if (new_screen->enable[0])
                    796:     abort ();
                    797:   if (new_screen->enable[screen_height - 1])
                    798:     abort ();
                    799: }
                    800: 
                    801: /* Decide what insert/delete line to do, and do it */
                    802: 
                    803: scrolling ()
                    804: {
                    805:   int unchanged_at_top, unchanged_at_bottom;
                    806:   int window_size;
                    807:   int changed_lines;
                    808:   int *old_hash = (int *) alloca (screen_height * sizeof (int));
                    809:   int *new_hash = (int *) alloca (screen_height * sizeof (int));
                    810:   int *draw_cost = (int *) alloca (screen_height * sizeof (int));
                    811:   register int i;
                    812:   int free_at_end_vpos = screen_height;
                    813:   
                    814:   /* Compute hash codes of all the lines.
                    815:      Also calculate number of changed lines,
                    816:      number of unchanged lines at the beginning,
                    817:      and number of unchanged lines at the end.  */
                    818: 
                    819:   changed_lines = 0;
                    820:   unchanged_at_top = 0;
                    821:   unchanged_at_bottom = screen_height;
                    822:   for (i = 0; i < screen_height; i++)
                    823:     {
                    824:       /* Give up on this scrolling if some old lines are not enabled.  */
                    825:       if (!current_screen->enable[i])
                    826:        return 0;
                    827:       old_hash[i] = line_hash_code (current_screen, i);
                    828:       if (!new_screen->enable[i])
                    829:        new_hash[i] = old_hash[i];
                    830:       else
                    831:        new_hash[i] = line_hash_code (new_screen, i);
                    832:       if (old_hash[i] != new_hash[i])
                    833:        {
                    834:          changed_lines++;
                    835:          unchanged_at_bottom = screen_height - i - 1;
                    836:        }
                    837:       else if (i == unchanged_at_top)
                    838:        unchanged_at_top++;
                    839:       /* If line is not changing, its redraw cost is infinite,
                    840:         since we can't redraw it.  */
                    841:       if (!new_screen->enable[i])
                    842:        draw_cost[i] = INFINITY;
                    843:       else
                    844:        draw_cost[i] = line_draw_cost (new_screen, i);
                    845:     }
                    846: 
                    847:   /* If changed lines are few, don't allow preemption, don't scroll.  */
                    848:   if (changed_lines < baud_rate / 2400 || unchanged_at_bottom == screen_height)
                    849:     return 1;
                    850: 
                    851:   window_size = screen_height - unchanged_at_top - unchanged_at_bottom;
                    852: 
                    853:   if (scroll_region_ok)
                    854:     free_at_end_vpos -= unchanged_at_bottom;
                    855:   else if (memory_below_screen)
                    856:     free_at_end_vpos = -1;
                    857: 
                    858:   /* If large window, fast terminal and few lines in common between
                    859:      current_screen and new_screen, don't bother with i/d calc.  */
                    860:   if (window_size >= 18 && baud_rate > 2400
                    861:       && (window_size >=
                    862:          10 * scrolling_max_lines_saved (unchanged_at_top,
                    863:                                          screen_height - unchanged_at_bottom,
                    864:                                          old_hash, new_hash, draw_cost)))
                    865:     return 0;
                    866: 
                    867:   scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom,
                    868:               draw_cost + unchanged_at_top - 1,
                    869:               old_hash + unchanged_at_top - 1,
                    870:               new_hash + unchanged_at_top - 1,
                    871:               free_at_end_vpos - unchanged_at_top);
                    872: 
                    873:   return 0;
                    874: }
                    875: 
                    876: update_line (vpos)
                    877:      int vpos;
                    878: {
                    879:   register unsigned char *obody, *nbody, *op1, *op2, *np1;
                    880:   int tem;
                    881:   int osp, nsp, begmatch, endmatch, olen, nlen;
                    882:   int save;
                    883:   unsigned char *temp;
                    884: 
                    885:   /* Check for highlighting change.  */
                    886:   if (new_screen->highlight[vpos]
                    887:       != (current_screen->enable[vpos] && current_screen->highlight[vpos]))
                    888:     {
                    889:       change_line_highlight (new_screen->highlight[vpos], vpos,
                    890:                             (current_screen->enable[vpos]
                    891:                              ? current_screen->used[vpos] : 0));
                    892:       current_screen->enable[vpos] = 0;
                    893:     }
                    894:   else
                    895:     reassert_line_highlight (new_screen->highlight[vpos], vpos);
                    896: 
                    897:   /* ??? */
                    898:   if (! current_screen->enable[vpos])
                    899:     {
                    900:       olen = 0;
                    901:     }
                    902:   else
                    903:     {
                    904:       obody = current_screen->contents[vpos];
                    905:       olen = current_screen->used[vpos];
                    906: 
                    907:       /* Check for bugs that clobber obody[-1].
                    908:         Such bugs might well clobber more than that,
                    909:         so we need to find them, not try to ignore them.  */
                    910:       if (obody[-1] != 0)
                    911:        abort ();
                    912: 
                    913:       if (! current_screen->highlight[vpos])
                    914:        {
                    915:          /* Note obody[-1] is always 0.  */
                    916:          if (!must_write_spaces)
                    917:            while (obody[olen - 1] == ' ')
                    918:              olen--;
                    919:        }
                    920:       else
                    921:        {
                    922:          /* For an inverse-video line, remember we gave it
                    923:             spaces all the way to the screen edge
                    924:             so that the reverse video extends all the way across.  */
                    925:          while (olen < screen_width - 1)
                    926:            obody[olen++] = ' ';
                    927:        }
                    928:     }
                    929: 
                    930:   /* One way or another, this will enable the line being updated.  */
                    931:   current_screen->enable[vpos] = 1;
                    932:   current_screen->used[vpos] = new_screen->used[vpos];
                    933: #if !defined (ALLIANT) || defined (ALLIANT_2800)
                    934:   current_screen->highlight[vpos] = new_screen->highlight[vpos];
                    935: #else
                    936:   {
                    937:     /* Work around for compiler bug in cc on FX/80 which causes
                    938:        "dispnew.c", line 896: compiler error: no table entry for op OREG.  */
                    939:     char tmp;
                    940:     tmp = new_screen->highlight[vpos];
                    941:     current_screen->highlight[vpos] = tmp;
                    942:   }
                    943: #endif
                    944: 
                    945:   if (!new_screen->enable[vpos])
                    946:     {
                    947:       nlen = 0;
                    948:       goto just_erase;
                    949:     }
                    950: 
                    951:   nbody = new_screen->contents[vpos];
                    952:   nlen = new_screen->used[vpos];
                    953: 
                    954:   /* Pretend trailing spaces are not there at all,
                    955:      unless for one reason or another we must write all spaces.  */
                    956:   /* We know that the previous character byte contains 0.  */
                    957:   if (! new_screen->highlight[vpos])
                    958:     {
                    959:       if (!must_write_spaces)
                    960:        while (nlen > 0 && nbody[nlen - 1] == ' ')
                    961:          nlen--;
                    962:       if (nlen == 0)
                    963:        goto just_erase;
                    964:     }
                    965:   else
                    966:     {
                    967:       /* For an inverse-video line, give it extra trailing spaces
                    968:         all the way to the screen edge
                    969:         so that the reverse video extends all the way across.  */
                    970:       while (nlen < screen_width - 1)
                    971:        nbody[nlen++] = ' ';
                    972:     }
                    973: 
                    974:   /* If there's no i/d char, quickly do the best we can without it.  */
                    975:   if (!char_ins_del_ok)
                    976:     {
                    977:       int i,j;
                    978: 
                    979:       for (i = 0; i < nlen; i++)
                    980:        {
                    981:          if (i >= olen || nbody[i] != obody[i])
                    982:            {
                    983:              /* We found a non-matching char.  */
                    984:              move_cursor (vpos, i);
                    985:              for (j = 1; (i + j < nlen &&
                    986:                           (i + j >= olen || nbody[i+j] != obody[i+j]));
                    987:                   j++);
                    988:              /* Output this run of non-matching chars.  */ 
                    989:              output_chars (nbody + i, j);
                    990:              i += j - 1;
                    991:              /* Now find the next non-match.  */
                    992:            }
                    993:        }
                    994:       /* Clear the rest of the line, or the non-clear part of it.  */
                    995:       if (olen > nlen)
                    996:        {
                    997:          move_cursor (vpos, nlen);
                    998:          clear_end_of_line (olen);
                    999:        }
                   1000: 
                   1001:       /* Exchange contents between current_screen and new_screen.  */
                   1002:       temp = new_screen->contents[vpos];
                   1003:       new_screen->contents[vpos] = current_screen->contents[vpos];
                   1004:       current_screen->contents[vpos] = temp;
                   1005:       return;
                   1006:     }
                   1007: 
                   1008:   if (!olen)
                   1009:     {
                   1010:       nsp = (must_write_spaces || new_screen->highlight[vpos])
                   1011:              ? 0 : count_blanks (nbody);
                   1012:       if (nlen > nsp)
                   1013:        {
                   1014:          move_cursor (vpos, nsp);
                   1015:          output_chars (nbody + nsp, nlen - nsp);
                   1016:        }
                   1017: 
                   1018:       /* Exchange contents between current_screen and new_screen.  */
                   1019:       temp = new_screen->contents[vpos];
                   1020:       new_screen->contents[vpos] = current_screen->contents[vpos];
                   1021:       current_screen->contents[vpos] = temp;
                   1022:       return;
                   1023:     }
                   1024: 
                   1025:   obody[olen] = 1;
                   1026:   save = nbody[nlen];
                   1027:   nbody[nlen] = 0;
                   1028: 
                   1029:   /* Compute number of leading blanks in old and new contents.  */
                   1030:   osp = count_blanks (obody);
                   1031:   if (!new_screen->highlight[vpos])
                   1032:     nsp = count_blanks (nbody);
                   1033:   else
                   1034:     nsp = 0;
                   1035: 
                   1036:   /* Compute number of matching chars starting with first nonblank.  */
                   1037:   begmatch = count_match (obody + osp, nbody + nsp);
                   1038: 
                   1039:   /* Spaces in new match implicit space past the end of old.  */
                   1040:   /* A bug causing this to be a no-op was fixed in 18.29.  */
                   1041:   if (!must_write_spaces && osp + begmatch == olen)
                   1042:     {
                   1043:       np1 = nbody + nsp;
                   1044:       while (np1[begmatch] == ' ')
                   1045:        begmatch++;
                   1046:     }
                   1047: 
                   1048:   /* Avoid doing insert/delete char
                   1049:      just cause number of leading spaces differs
                   1050:      when the following text does not match. */
                   1051:   if (begmatch == 0 && osp != nsp)
                   1052:     osp = nsp = min (osp, nsp);
                   1053: 
                   1054:   /* Find matching characters at end of line */
                   1055:   op1 = obody + olen;
                   1056:   np1 = nbody + nlen;
                   1057:   op2 = op1 + begmatch - min (olen - osp, nlen - nsp);
                   1058:   while (op1 > op2 && op1[-1] == np1[-1])
                   1059:     {
                   1060:       op1--;
                   1061:       np1--;
                   1062:     }
                   1063:   endmatch = obody + olen - op1;
                   1064: 
                   1065:   /* Put correct value back in nbody[nlen].
                   1066:      This is important because direct_output_for_insert
                   1067:      can write into the line at a later point.  */
                   1068:   nbody[nlen] = save;
                   1069:   /* Likewise, make sure that the null after the usable space in obody
                   1070:      always remains a null.  */
                   1071:   obody[olen] = 0;
                   1072: 
                   1073:   /* tem gets the distance to insert or delete.
                   1074:      endmatch is how many characters we save by doing so.
                   1075:      Is it worth it?  */
                   1076: 
                   1077:   tem = (nlen - nsp) - (olen - osp);
                   1078:   if (endmatch && tem && endmatch <= DCICcost[tem])
                   1079:     endmatch = 0;
                   1080: 
                   1081:   /* nsp - osp is the distance to insert or delete.
                   1082:      begmatch + endmatch is how much we save by doing so.
                   1083:      Is it worth it?  */
                   1084: 
                   1085:   if (begmatch + endmatch > 0 && nsp != osp
                   1086:       && begmatch + endmatch <= DCICcost[nsp - osp])
                   1087:     {
                   1088:       begmatch = 0;
                   1089:       endmatch = 0;
                   1090:       osp = nsp = min (osp, nsp);
                   1091:     }
                   1092: 
                   1093:   /* Now go through the line, inserting, writing and deleting as appropriate.  */
                   1094: 
                   1095:   if (osp > nsp)
                   1096:     {
                   1097:       move_cursor (vpos, nsp);
                   1098:       delete_chars (osp - nsp);
                   1099:     }
                   1100:   else if (nsp > osp)
                   1101:     {
                   1102:       /* If going to delete chars later in line
                   1103:         and insert earlier in the line,
                   1104:         must delete first to avoid losing data in the insert */
                   1105:       if (endmatch && nlen < olen + nsp - osp)
                   1106:        {
                   1107:          move_cursor (vpos, nlen - endmatch + osp - nsp);
                   1108:          delete_chars (olen + nsp - osp - nlen);
                   1109:          olen = nlen - (nsp - osp);
                   1110:        }
                   1111:       move_cursor (vpos, osp);
                   1112:       insert_chars ((char *)0, nsp - osp);
                   1113:     }
                   1114:   olen += nsp - osp;
                   1115: 
                   1116:   tem = nsp + begmatch + endmatch;
                   1117:   if (nlen != tem || olen != tem)
                   1118:     {
                   1119:       move_cursor (vpos, nsp + begmatch);
                   1120:       if (!endmatch || nlen == olen)
                   1121:        {
                   1122:          /* If new text being written reaches right margin,
                   1123:             there is no need to do clear-to-eol at the end.
                   1124:             (and it would not be safe, since cursor is not
                   1125:             going to be "at the margin" after the text is done) */
                   1126:          if (nlen == screen_width)
                   1127:            olen = 0;
                   1128:          output_chars (nbody + nsp + begmatch, nlen - tem);
                   1129: #ifdef obsolete
                   1130: /* the following code loses disastrously if tem == nlen.
                   1131:    Rather than trying to fix that case, I am trying the simpler
                   1132:    solution found above.  */
                   1133:          /* If the text reaches to the right margin,
                   1134:             it will lose one way or another (depending on AutoWrap)
                   1135:             to clear to end of line after outputting all the text.
                   1136:             So pause with one character to go and clear the line then.  */
                   1137:          if (nlen == screen_width && fast_clear_end_of_line && olen > nlen)
                   1138:            {
                   1139:              /* endmatch must be zero, and tem must equal nsp + begmatch */
                   1140:              output_chars (nbody + tem, nlen - tem - 1);
                   1141:              clear_end_of_line (olen);
                   1142:              olen = 0;         /* Don't let it be cleared again later */
                   1143:              output_chars (nbody + nlen - 1, 1);
                   1144:            }
                   1145:          else
                   1146:            output_chars (nbody + nsp + begmatch, nlen - tem);
                   1147: #endif
                   1148:        }
                   1149:       else if (nlen > olen)
                   1150:        {
                   1151:          output_chars (nbody + nsp + begmatch, olen - tem);
                   1152:          insert_chars (nbody + nsp + begmatch + olen - tem, nlen - olen);
                   1153:          olen = nlen;
                   1154:        }
                   1155:       else if (olen > nlen)
                   1156:        {
                   1157:          output_chars (nbody + nsp + begmatch, nlen - tem);
                   1158:          delete_chars (olen - nlen);
                   1159:          olen = nlen;
                   1160:        }
                   1161:     }
                   1162: 
                   1163:  just_erase:
                   1164:   /* If any unerased characters remain after the new line, erase them.  */
                   1165:   if (olen > nlen)
                   1166:     {
                   1167:       move_cursor (vpos, nlen);
                   1168:       clear_end_of_line (olen);
                   1169:     }
                   1170:   
                   1171:   /* Exchange contents between current_screen and new_screen.  */
                   1172:   temp = new_screen->contents[vpos];
                   1173:   new_screen->contents[vpos] = current_screen->contents[vpos];
                   1174:   current_screen->contents[vpos] = temp;
                   1175: }
                   1176: 
                   1177: count_blanks (str)
                   1178:      char *str;
                   1179: {
                   1180:   register char *p = str;
                   1181:   while (*str++ == ' ');
                   1182:   return str - p - 1;
                   1183: }
                   1184: 
                   1185: count_match (str1, str2)
                   1186:      char *str1, *str2;
                   1187: {
                   1188:   register char *p1 = str1;
                   1189:   register char *p2 = str2;
                   1190:   while (*p1++ == *p2++);
                   1191:   return p1 - str1 - 1;
                   1192: }
                   1193: 
                   1194: DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
                   1195:   1, 1, "FOpen termscript file: ",
                   1196:   "Start writing all terminal output to FILE as well as the terminal.\n\
                   1197: FILE = nil means just close any termscript file currently open.")
                   1198:   (file)
                   1199:      Lisp_Object file;
                   1200: {
                   1201:   if (termscript != 0) fclose (termscript);
                   1202:   termscript = 0;
                   1203: 
                   1204:   if (! NULL (file))
                   1205:     {
                   1206:       file = Fexpand_file_name (file, Qnil);
                   1207:       termscript = fopen (XSTRING (file)->data, "w");
                   1208:       if (termscript == 0)
                   1209:        report_file_error ("Opening termscript", Fcons (file, Qnil));
                   1210:     }
                   1211:   return Qnil;
                   1212: }
                   1213: 
                   1214: DEFUN ("set-screen-height", Fset_screen_height, Sset_screen_height, 1, 2, 0,
                   1215:   "Tell redisplay that the screen has LINES lines.\n\
                   1216: Optional second arg non-nil means that redisplay should use LINES lines\n\
                   1217: but that the idea of the actual height of the screen should not be changed.")
                   1218:   (n, pretend)
                   1219:      Lisp_Object n, pretend;
                   1220: {
                   1221:   CHECK_NUMBER (n, 0);
                   1222:   change_screen_size (XINT (n), 0, !NULL (pretend), 0, 0);
                   1223:   return Qnil;
                   1224: }
                   1225: 
                   1226: DEFUN ("set-screen-width", Fset_screen_width, Sset_screen_width, 1, 2, 0,
                   1227:   "Tell redisplay that the screen has COLS columns.\n\
                   1228: Optional second arg non-nil means that redisplay should use COLS columns\n\
                   1229: but that the idea of the actual width of the screen should not be changed.")
                   1230:   (n, pretend)
                   1231:      Lisp_Object n, pretend;
                   1232: {
                   1233:   CHECK_NUMBER (n, 0);
                   1234:   change_screen_size (0, XINT (n), !NULL (pretend), 0, 0);
                   1235:   return Qnil;
                   1236: }
                   1237: 
                   1238: DEFUN ("screen-height", Fscreen_height, Sscreen_height, 0, 0, 0,
                   1239:   "Return number of lines on screen available for display.")
                   1240:   ()
                   1241: {
                   1242:   return make_number (screen_height);
                   1243: }
                   1244: 
                   1245: DEFUN ("screen-width", Fscreen_width, Sscreen_width, 0, 0, 0,
                   1246:   "Return number of columns on screen available for display.")
                   1247:   ()
                   1248: {
                   1249:   return make_number (screen_width);
                   1250: }
                   1251: 
                   1252: #ifdef SIGWINCH
                   1253: window_change_signal ()
                   1254: {
                   1255:   int width, height;
                   1256:   extern int errno;
                   1257:   int old_errno = errno;
                   1258: 
                   1259:   get_screen_size (&width, &height);
                   1260:   /* Record the new size, but don't reallocate the data structures now.
                   1261:      Let that be done later outside of the signal handler.  */
                   1262:   change_screen_size (height, width, 0, 1, 0);
                   1263:   signal (SIGWINCH, window_change_signal);
                   1264: 
                   1265:   errno = old_errno;
                   1266: }
                   1267: #endif /* SIGWINCH */
                   1268: 
                   1269: /* Do any change in screen size that was requested by a signal.  */
                   1270: 
                   1271: do_pending_window_change ()
                   1272: {
                   1273:   /* If change_screen_size should have run before, run it now.  */
                   1274:   while (delayed_size_change)
                   1275:     {
                   1276:       int newwidth = delayed_screen_width;
                   1277:       int newheight = delayed_screen_height;
                   1278:       delayed_size_change = 0;
                   1279:       change_screen_size_1 (newheight, newwidth, 0, 0);
                   1280:     }
                   1281: }
                   1282: 
                   1283: /* Change the screen height and/or width.  Values may be given as zero to
                   1284:    indicate no change is to take place.
                   1285: 
                   1286:    PRETEND is normally 0; 1 means change used-size only but don't
                   1287:    change the size used for calculations; -1 means don't redisplay.
                   1288: 
                   1289:    If DELAYED, don't change the screen size now; just record the new
                   1290:    size and do the actual change at a more convenient time.  The
                   1291:    SIGWINCH handler and the X Windows ConfigureNotify code use this,
                   1292:    because they can both be called at inconvenient times.
                   1293: 
                   1294:    FORCE means finish redisplay now regardless of pending input.
                   1295:    This is effective only is DELAYED is not set.  */
                   1296: 
                   1297: change_screen_size (newlength, newwidth, pretend, delayed, force)
                   1298:      register int newlength, newwidth, pretend, delayed, force;
                   1299: {
                   1300:   /* Don't queue a size change if we won't really do anything.  */
                   1301:   if ((newlength == 0 || newlength == screen_height)
                   1302:       && (newwidth == 0 || newwidth == screen_width))
                   1303:     return;
                   1304:   /* If we can't deal with the change now, queue it for later.  */
                   1305:   if (delayed)
                   1306:     {
                   1307:       delayed_screen_width = newwidth;
                   1308:       delayed_screen_height = newlength;
                   1309:       delayed_size_change = 1;
                   1310:     }
                   1311:   else
                   1312:     {
                   1313:       delayed_size_change = 0;
                   1314:       change_screen_size_1 (newlength, newwidth, pretend, force);
                   1315:     }
                   1316: }
                   1317: 
                   1318: change_screen_size_1 (newlength, newwidth, pretend, force)
                   1319:      register int newlength, newwidth, pretend, force;
                   1320: {
                   1321:   if ((newlength == 0 || newlength == screen_height)
                   1322:       && (newwidth == 0 || newwidth == screen_width))
                   1323:     return;
                   1324:   if (newlength && newlength != screen_height)
                   1325:     {
                   1326:       set_window_height (XWINDOW (minibuf_window)->prev, newlength - 1, 0);
                   1327:       XFASTINT (XWINDOW (minibuf_window)->top) = newlength - 1;
                   1328:       set_window_height (minibuf_window, 1, 0);
                   1329:       screen_height = newlength;
                   1330:       if (pretend <= 0)
                   1331:        ScreenRows = newlength;
                   1332:       set_terminal_window (0);
                   1333:     }
                   1334:   if (newwidth && newwidth != screen_width)
                   1335:     {
                   1336:       set_window_width (XWINDOW (minibuf_window)->prev, newwidth, 0);
                   1337:       set_window_width (minibuf_window, newwidth, 0);
                   1338:       screen_width = newwidth;
                   1339:       if (pretend <= 0)
                   1340:        ScreenCols = newwidth;
                   1341:     }
                   1342:   remake_screen_structures ();
                   1343:   screen_garbaged = 1;
                   1344:   calculate_costs ();
                   1345:   force_redisplay += force;
                   1346:   if (pretend >= 0)
                   1347:     redisplay_preserve_echo_area ();
                   1348:   force_redisplay -= force;
                   1349: }
                   1350: 
                   1351: DEFUN ("baud-rate", Fbaud_rate, Sbaud_rate, 0, 0, 0,
                   1352:   "Return the output baud rate of the terminal.")
                   1353:   ()
                   1354: {
                   1355:   Lisp_Object temp;
                   1356:   XSET (temp, Lisp_Int, baud_rate);
                   1357:   return temp;
                   1358: }
                   1359: 
                   1360: DEFUN ("send-string-to-terminal", Fsend_string_to_terminal,
                   1361:   Ssend_string_to_terminal, 1, 1, 0,
                   1362:   "Send STRING to the terminal without alteration.\n\
                   1363: Control characters in STRING will have terminal-dependent effects.")
                   1364:   (str)
                   1365:      Lisp_Object str;
                   1366: {
                   1367:   CHECK_STRING (str, 0);
                   1368:   fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, stdout);
                   1369:   fflush (stdout);
                   1370:   if (termscript)
                   1371:     {
                   1372:       fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, termscript);
                   1373:       fflush (termscript);
                   1374:     }
                   1375:   return Qnil;
                   1376: }
                   1377: 
                   1378: DEFUN ("ding", Fding, Sding, 0, 1, 0,
                   1379:   "Beep, or flash the screen.\n\
                   1380: Terminates any keyboard macro currently executing unless an argument\n\
                   1381: is given.")
                   1382:   (arg)
                   1383:   Lisp_Object arg;
                   1384: {
                   1385:   if (!NULL (arg))
                   1386:     {
                   1387:       if (noninteractive)
                   1388:        putchar (07);
                   1389:       else
                   1390:        ring_bell ();
                   1391:       fflush (stdout);
                   1392:     }
                   1393:   else
                   1394:     bell ();
                   1395:   return Qnil;
                   1396: }
                   1397: 
                   1398: bell ()
                   1399: {
                   1400:   if (noninteractive)
                   1401:     putchar (07);
                   1402:   else if (!FROM_KBD)  /* Stop executing a keyboard macro. */
                   1403:     error ("Keyboard macro terminated by a command ringing the bell");
                   1404:   else
                   1405:     ring_bell ();
                   1406:   fflush (stdout);
                   1407: }
                   1408: 
                   1409: DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 1, 0,
                   1410:   "Pause, without updating display, for ARG seconds.")
                   1411:   (n)
                   1412:      Lisp_Object n;
                   1413: {
                   1414:   register int t;
                   1415: #ifndef subprocesses
                   1416: #ifdef HAVE_TIMEVAL
                   1417:   struct timeval timeout, end_time, garbage1;
                   1418: #endif /* HAVE_TIMEVAL */
                   1419: #endif /* no subprocesses */
                   1420: 
                   1421:   CHECK_NUMBER (n, 0);
                   1422:   t = XINT (n);
                   1423:   if (t <= 0)
                   1424:     return Qnil;
                   1425: 
                   1426: #ifdef subprocesses
                   1427:   wait_reading_process_input (t, 0, 0);
                   1428: #else /* No subprocesses */
                   1429:   immediate_quit = 1;
                   1430:   QUIT;
                   1431: 
                   1432: #ifdef VMS
                   1433:   sys_sleep (t);
                   1434: #else /* not VMS */
                   1435: /* The reason this is done this way 
                   1436:     (rather than defined (H_S) && defined (H_T))
                   1437:    is because the VMS preprocessor doesn't grok `defined' */
                   1438: #ifdef HAVE_SELECT
                   1439: #ifdef HAVE_TIMEVAL
                   1440:   gettimeofday (&end_time, &garbage1);
                   1441:   end_time.tv_sec += t;
                   1442: 
                   1443:   while (1)
                   1444:     {
                   1445:       gettimeofday (&timeout, &garbage1);
                   1446: 
                   1447:       /* In effect, timeout = end_time - timeout.
                   1448:         Break if result would be negative.  */
                   1449:       if (timeval_subtract (&timeout, end_time, timeout))
                   1450:        break;
                   1451: 
                   1452:       if (!select (1, 0, 0, 0, &timeout))
                   1453:        break;
                   1454:     }
                   1455: #else /* not HAVE_TIMEVAL */
                   1456:   /* Is it safe to quit out of `sleep'?  I'm afraid to trust it.  */
                   1457:   sleep (t);
                   1458: #endif /* HAVE_TIMEVAL */
                   1459: #else /* not HAVE_SELECT */
                   1460:   sleep (t);
                   1461: #endif /* HAVE_SELECT */
                   1462: #endif /* not VMS */
                   1463:   
                   1464:   immediate_quit = 0;
                   1465: #endif /* no subprocesses */
                   1466:   return Qnil;
                   1467: }
                   1468: 
                   1469: #ifdef HAVE_TIMEVAL
                   1470: 
                   1471: /* Subtract the `struct timeval' values X and Y,
                   1472:    storing the result in RESULT.
                   1473:    Return 1 if the difference is negative, otherwise 0.  */
                   1474: 
                   1475: int
                   1476: timeval_subtract (result, x, y)
                   1477:      struct timeval *result, x, y;
                   1478: {
                   1479:   /* Perform the carry for the later subtraction by updating y.
                   1480:      This is safer because on some systems
                   1481:      the tv_sec member is unsigned.  */
                   1482:   if (x.tv_usec < y.tv_usec)
                   1483:     {
                   1484:       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
                   1485:       y.tv_usec -= 1000000 * nsec;
                   1486:       y.tv_sec += nsec;
                   1487:     }
                   1488:   if (x.tv_usec - y.tv_usec > 1000000)
                   1489:     {
                   1490:       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
                   1491:       y.tv_usec += 1000000 * nsec;
                   1492:       y.tv_sec -= nsec;
                   1493:     }
                   1494: 
                   1495:   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
                   1496:   result->tv_sec = x.tv_sec - y.tv_sec;
                   1497:   result->tv_usec = x.tv_usec - y.tv_usec;
                   1498: 
                   1499:   /* Return indication of whether the result should be considered negative.  */
                   1500:   return x.tv_sec < y.tv_sec;
                   1501: }
                   1502: #endif /* HAVE_TIMEVAL */
                   1503: 
                   1504: DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 2, 0,
                   1505:   "Perform redisplay, then wait for ARG seconds or until input is available.\n\
                   1506: Optional second arg non-nil means don't redisplay.\n\
                   1507: Redisplay is preempted as always if input arrives, and does not happen\n\
                   1508: if input is available before it starts.\n\
                   1509: Value is t if waited the full time with no input arriving.")
                   1510:   (n, nodisp)
                   1511:      Lisp_Object n, nodisp;
                   1512: {
                   1513: #ifndef subprocesses
                   1514: #ifdef HAVE_TIMEVAL
                   1515:   struct timeval timeout;
                   1516: #else
                   1517:   int timeout_sec;
                   1518: #endif
                   1519:   int waitchannels;
                   1520: #endif /* no subprocesses */
                   1521: 
                   1522:   CHECK_NUMBER (n, 0);
                   1523: 
                   1524:   if (detect_input_pending ())
                   1525:     return Qnil;
                   1526: 
                   1527:   if (EQ (nodisp, Qnil))
                   1528:     redisplay_preserve_echo_area ();
                   1529:   if (XINT (n) > 0)
                   1530:     {
                   1531: #ifdef subprocesses
                   1532: #ifdef SIGIO
                   1533:       gobble_input ();
                   1534: #endif                         /* SIGIO */
                   1535:       wait_reading_process_input (XINT (n), 1, 1);
                   1536: #else /* not subprocesses */
                   1537:       immediate_quit = 1;
                   1538:       QUIT;
                   1539: 
                   1540:       waitchannels = 1;
                   1541: #ifdef VMS
                   1542:       input_wait_timeout (XINT (n));
                   1543: #else /* not VMS */
                   1544: #ifndef HAVE_TIMEVAL
                   1545:       timeout_sec = XINT (n);
                   1546:       select (1, &waitchannels, 0, 0, &timeout_sec);
                   1547: #else /* HAVE_TIMEVAL */
                   1548:       timeout.tv_sec = XINT (n);  
                   1549:       timeout.tv_usec = 0;
                   1550:       select (1, &waitchannels, 0, 0, &timeout);
                   1551: #endif /* HAVE_TIMEVAL */
                   1552: #endif /* not VMS */
                   1553: 
                   1554:       immediate_quit = 0;
                   1555: #endif /* not subprocesses */
                   1556:     }
                   1557:   return detect_input_pending () ? Qnil : Qt;
                   1558: }
                   1559: 
                   1560: char *terminal_type;
                   1561: 
                   1562: /* Initialization done when Emacs fork is started, before doing stty. */
                   1563: /* Determine terminal type and set terminal_driver */
                   1564: /* Then invoke its decoding routine to set up variables
                   1565:   in the terminal package */
                   1566: 
                   1567: init_display ()
                   1568: {
                   1569: #ifdef HAVE_X_WINDOWS
                   1570:   extern Lisp_Object Vxterm;
                   1571:   Vxterm = Qnil;
                   1572: #endif
                   1573: 
                   1574:   Vwindow_system = Qnil;
                   1575:   meta_key = 0;
                   1576:   inverse_video = 0;
                   1577:   cursor_in_echo_area = 0;
                   1578:   terminal_type = (char *) 0;
                   1579: 
                   1580:   if (!inhibit_window_system)
                   1581:     {
                   1582: #ifdef HAVE_X_WINDOWS
                   1583:       extern char *alternate_display;
                   1584:       char *disp = (char *) egetenv ("DISPLAY");
                   1585: 
                   1586:       /* Note KSH likes to provide an empty string as an envvar value.  */
                   1587:       if (alternate_display || (disp && *disp))
                   1588:        {
                   1589:          x_term_init ();
                   1590:          Vxterm = Qt;
                   1591:          Vwindow_system = intern ("x");
                   1592: #ifdef X11
                   1593:          Vwindow_system_version = make_number (11);
                   1594: #else
                   1595:          Vwindow_system_version = make_number (10);
                   1596: #endif
                   1597:          goto term_init_done;
                   1598:        }
                   1599: #endif /* HAVE_X_WINDOWS */
                   1600:       ;
                   1601:     }
                   1602:   /* Record we aren't using a window system.  */
                   1603:   inhibit_window_system = 1;
                   1604: 
                   1605:   /* Look at the TERM variable */
                   1606:   terminal_type = (char *) getenv ("TERM");
                   1607:   if (!terminal_type)
                   1608:     {
                   1609: #ifdef VMS
                   1610:       fprintf (stderr, "Please specify your terminal type.\n\
                   1611: For types defined in VMS, use  set term /device=TYPE.\n\
                   1612: For types not defined in VMS, use  define emacs_term \"TYPE\".\n\
                   1613: \(The quotation marks are necessary since terminal types are lower case.)\n");
                   1614: #else
                   1615:       fprintf (stderr, "Please set the environment variable TERM; see tset(1).\n");
                   1616: #endif
                   1617:       exit (1);
                   1618:     }
                   1619:   term_init (terminal_type);
                   1620: 
                   1621:  term_init_done:
                   1622:   remake_screen_structures ();
                   1623:   calculate_costs ();
                   1624: 
                   1625: #ifdef SIGWINCH
                   1626: #ifndef CANNOT_DUMP
                   1627:   if (initialized)
                   1628: #endif /* CANNOT_DUMP */
                   1629:     if (inhibit_window_system)
                   1630:       signal (SIGWINCH, window_change_signal);
                   1631: #endif /* SIGWINCH */
                   1632: }
                   1633: 
                   1634: syms_of_display ()
                   1635: {
                   1636:   defsubr (&Sopen_termscript);
                   1637:   defsubr (&Sding);
                   1638:   defsubr (&Ssit_for);
                   1639:   defsubr (&Sscreen_height);
                   1640:   defsubr (&Sscreen_width);
                   1641:   defsubr (&Sset_screen_height);
                   1642:   defsubr (&Sset_screen_width);
                   1643:   defsubr (&Ssleep_for);
                   1644:   defsubr (&Sbaud_rate);
                   1645:   defsubr (&Ssend_string_to_terminal);
                   1646: 
                   1647:   DEFVAR_BOOL ("inverse-video", &inverse_video,
                   1648:     "*Non-nil means use inverse-video.");
                   1649:   DEFVAR_BOOL ("visible-bell", &visible_bell,
                   1650:     "*Non-nil means try to flash the screen to represent a bell.\n\
                   1651: Note: for X windows, you must use x-set-bell instead.");
                   1652:   DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter,
                   1653:     "*Non-nil means no need to redraw entire screen after suspending.\n\
                   1654: It is up to you to set this variable to inform Emacs.");
                   1655:   DEFVAR_LISP ("window-system", &Vwindow_system,
                   1656:     "A symbol naming the window-system under which Emacs is running,\n\
                   1657: \(such as `x'), or nil if emacs is running on an ordinary terminal.");
                   1658:   DEFVAR_LISP ("window-system-version", &Vwindow_system_version,
                   1659:     "Version number of the window system Emacs is running under.");
                   1660:   DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area,
                   1661:     "Non-nil means put cursor in minibuffer after any message displayed there.");
                   1662: 
                   1663:   /* Initialize `window-system', unless init_display already decided it.  */
                   1664: #ifdef CANNOT_DUMP
                   1665:   if (noninteractive)
                   1666: #endif
                   1667:     {
                   1668:       Vwindow_system_version = Qnil;
                   1669:       Vwindow_system = Qnil;
                   1670:     }
                   1671: }

unix.superglobalmegacorp.com

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