(tab-stop-list): Doc fix.
[bpt/emacs.git] / src / dispnew.c
... / ...
CommitLineData
1/* Updating of data structures for redisplay.
2 Copyright (C) 1985, 86, 87, 88, 93, 94 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21#include <signal.h>
22#include <stdio.h>
23
24#include <config.h>
25#include <ctype.h>
26
27#include "lisp.h"
28#include "termchar.h"
29#include "termopts.h"
30#include "termhooks.h"
31#include "cm.h"
32#include "dispextern.h"
33#include "buffer.h"
34#include "frame.h"
35#include "window.h"
36#include "commands.h"
37#include "disptab.h"
38#include "indent.h"
39#include "intervals.h"
40
41#include "systty.h"
42
43#ifdef HAVE_X_WINDOWS
44#include "xterm.h"
45#endif /* HAVE_X_WINDOWS */
46
47/* Include systime.h after xterm.h to avoid double inclusion of time.h. */
48#include "systime.h"
49
50#include <errno.h>
51
52#define max(a, b) ((a) > (b) ? (a) : (b))
53#define min(a, b) ((a) < (b) ? (a) : (b))
54
55/* Get number of chars of output now in the buffer of a stdio stream.
56 This ought to be built in in stdio, but it isn't.
57 Some s- files override this because their stdio internals differ. */
58#ifdef __GNU_LIBRARY__
59/* The s- file might have overridden the definition with one that works for
60 the system's C library. But we are using the GNU C library, so this is
61 the right definition for every system. */
62#ifdef GNU_LIBRARY_PENDING_OUTPUT_COUNT
63#define PENDING_OUTPUT_COUNT GNU_LIBRARY_PENDING_OUTPUT_COUNT
64#else
65#undef PENDING_OUTPUT_COUNT
66#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->__bufp - (FILE)->__buffer)
67#endif
68#else /* not __GNU_LIBRARY__ */
69#ifndef PENDING_OUTPUT_COUNT
70#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base)
71#endif
72#endif
73
74/* Nonzero upon entry to redisplay means do not assume anything about
75 current contents of actual terminal frame; clear and redraw it. */
76
77int frame_garbaged;
78
79/* Nonzero means last display completed. Zero means it was preempted. */
80
81int display_completed;
82
83/* Lisp variable visible-bell; enables use of screen-flash
84 instead of audible bell. */
85
86int visible_bell;
87
88/* Invert the color of the whole frame, at a low level. */
89
90int inverse_video;
91
92/* Line speed of the terminal. */
93
94int baud_rate;
95
96/* nil or a symbol naming the window system under which emacs is
97 running ('x is the only current possibility). */
98
99Lisp_Object Vwindow_system;
100
101/* Version number of X windows: 10, 11 or nil. */
102Lisp_Object Vwindow_system_version;
103
104/* Vector of glyph definitions. Indexed by glyph number,
105 the contents are a string which is how to output the glyph.
106
107 If Vglyph_table is nil, a glyph is output by using its low 8 bits
108 as a character code. */
109
110Lisp_Object Vglyph_table;
111
112/* Display table to use for vectors that don't specify their own. */
113
114Lisp_Object Vstandard_display_table;
115
116/* Nonzero means reading single-character input with prompt
117 so put cursor on minibuffer after the prompt.
118 positive means at end of text in echo area;
119 negative means at beginning of line. */
120int cursor_in_echo_area;
121\f
122/* The currently selected frame.
123 In a single-frame version, this variable always remains 0. */
124
125FRAME_PTR selected_frame;
126
127/* A frame which is not just a minibuffer, or 0 if there are no such
128 frames. This is usually the most recent such frame that was
129 selected. In a single-frame version, this variable always remains 0. */
130FRAME_PTR last_nonminibuf_frame;
131
132/* In a single-frame version, the information that would otherwise
133 exist inside frame objects lives in the following structure instead.
134
135 NOTE: the_only_frame is not checked for garbage collection; don't
136 store collectible objects in any of its fields!
137
138 You're not/The only frame in town/... */
139
140#ifndef MULTI_FRAME
141struct frame the_only_frame;
142#endif
143
144/* This is a vector, made larger whenever it isn't large enough,
145 which is used inside `update_frame' to hold the old contents
146 of the FRAME_PHYS_LINES of the frame being updated. */
147struct frame_glyphs **ophys_lines;
148/* Length of vector currently allocated. */
149int ophys_lines_length;
150
151FILE *termscript; /* Stdio stream being used for copy of all output. */
152
153struct cm Wcm; /* Structure for info on cursor positioning */
154
155extern short ospeed; /* Output speed (from sg_ospeed) */
156
157int delayed_size_change; /* 1 means SIGWINCH happened when not safe. */
158\f
159#ifdef MULTI_FRAME
160
161DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
162 "Clear frame FRAME and output again what is supposed to appear on it.")
163 (frame)
164 Lisp_Object frame;
165{
166 FRAME_PTR f;
167
168 CHECK_LIVE_FRAME (frame, 0);
169 f = XFRAME (frame);
170 update_begin (f);
171 /* set_terminal_modes (); */
172 clear_frame ();
173 clear_frame_records (f);
174 update_end (f);
175 fflush (stdout);
176 windows_or_buffers_changed++;
177 /* Mark all windows as INaccurate,
178 so that every window will have its redisplay done. */
179 mark_window_display_accurate (FRAME_ROOT_WINDOW (f), 0);
180 f->garbaged = 0;
181 return Qnil;
182}
183
184redraw_frame (f)
185 FRAME_PTR f;
186{
187 Lisp_Object frame;
188 XSET (frame, Lisp_Frame, f);
189 Fredraw_frame (frame);
190}
191
192#else
193
194DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
195 "Clear frame FRAME and output again what is supposed to appear on it.")
196 (frame)
197 Lisp_Object frame;
198{
199 update_begin (0);
200 set_terminal_modes ();
201 clear_frame ();
202 update_end (0);
203 fflush (stdout);
204 clear_frame_records (0);
205 windows_or_buffers_changed++;
206 /* Mark all windows as INaccurate,
207 so that every window will have its redisplay done. */
208 mark_window_display_accurate (FRAME_ROOT_WINDOW (0), 0);
209 return Qnil;
210}
211
212#endif
213
214DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
215 "Clear and redisplay all visible frames.")
216 ()
217{
218 Lisp_Object tail, frame;
219
220 FOR_EACH_FRAME (tail, frame)
221 if (FRAME_VISIBLE_P (XFRAME (frame)))
222 Fredraw_frame (frame);
223
224 return Qnil;
225}
226
227/* This is used when frame_garbaged is set.
228 Redraw the individual frames marked as garbaged. */
229
230void
231redraw_garbaged_frames ()
232{
233 Lisp_Object tail, frame;
234
235 FOR_EACH_FRAME (tail, frame)
236 if (FRAME_VISIBLE_P (XFRAME (frame))
237 && FRAME_GARBAGED_P (XFRAME (frame)))
238 Fredraw_frame (frame);
239}
240
241\f
242static struct frame_glyphs *
243make_frame_glyphs (frame, empty)
244 register FRAME_PTR frame;
245 int empty;
246{
247 register int i;
248 register width = FRAME_WIDTH (frame);
249 register height = FRAME_HEIGHT (frame);
250 register struct frame_glyphs *new
251 = (struct frame_glyphs *) xmalloc (sizeof (struct frame_glyphs));
252
253 SET_GLYPHS_FRAME (new, frame);
254 new->height = height;
255 new->width = width;
256 new->used = (int *) xmalloc (height * sizeof (int));
257 new->glyphs = (GLYPH **) xmalloc (height * sizeof (GLYPH *));
258 new->charstarts = (int **) xmalloc (height * sizeof (int *));
259 new->highlight = (char *) xmalloc (height * sizeof (char));
260 new->enable = (char *) xmalloc (height * sizeof (char));
261 bzero (new->enable, height * sizeof (char));
262 new->bufp = (int *) xmalloc (height * sizeof (int));
263
264#ifdef HAVE_X_WINDOWS
265 if (FRAME_X_P (frame))
266 {
267 new->top_left_x = (short *) xmalloc (height * sizeof (short));
268 new->top_left_y = (short *) xmalloc (height * sizeof (short));
269 new->pix_width = (short *) xmalloc (height * sizeof (short));
270 new->pix_height = (short *) xmalloc (height * sizeof (short));
271 new->max_ascent = (short *) xmalloc (height * sizeof (short));
272 }
273#endif
274
275 if (empty)
276 {
277 /* Make the buffer used by decode_mode_spec. This buffer is also
278 used as temporary storage when updating the frame. See scroll.c. */
279 unsigned int total_glyphs = (width + 2) * sizeof (GLYPH);
280 unsigned int total_charstarts = (width + 2) * sizeof (int);
281
282 new->total_contents = (GLYPH *) xmalloc (total_glyphs);
283 bzero (new->total_contents, total_glyphs);
284
285 new->total_charstarts = (int *) xmalloc (total_charstarts);
286 bzero (new->total_charstarts, total_glyphs);
287 }
288 else
289 {
290 unsigned int total_glyphs = height * (width + 2) * sizeof (GLYPH);
291
292 new->total_contents = (GLYPH *) xmalloc (total_glyphs);
293 bzero (new->total_contents, total_glyphs);
294 for (i = 0; i < height; i++)
295 new->glyphs[i] = new->total_contents + i * (width + 2) + 1;
296
297 if (!FRAME_TERMCAP_P (frame))
298 {
299 unsigned int total_charstarts = height * (width + 2) * sizeof (int);
300
301 new->total_charstarts = (int *) xmalloc (total_charstarts);
302 bzero (new->total_charstarts, total_charstarts);
303 for (i = 0; i < height; i++)
304 new->charstarts[i] = new->total_charstarts + i * (width + 2) + 1;
305 }
306 else
307 {
308 /* Without a window system, we don't really need charstarts.
309 So use a small amount of space to make enough data structure
310 to prevent crashes in display_text_line. */
311 new->total_charstarts = (int *) xmalloc ((width + 2) * sizeof (int));
312 for (i = 0; i < height; i++)
313 new->charstarts[i] = new->total_charstarts;
314 }
315 }
316
317 return new;
318}
319
320static void
321free_frame_glyphs (frame, glyphs)
322 FRAME_PTR frame;
323 struct frame_glyphs *glyphs;
324{
325 if (glyphs->total_contents)
326 xfree (glyphs->total_contents);
327 if (glyphs->total_charstarts)
328 xfree (glyphs->total_charstarts);
329
330 xfree (glyphs->used);
331 xfree (glyphs->glyphs);
332 xfree (glyphs->highlight);
333 xfree (glyphs->enable);
334 xfree (glyphs->bufp);
335 if (glyphs->charstarts)
336 xfree (glyphs->charstarts);
337
338#ifdef HAVE_X_WINDOWS
339 if (FRAME_X_P (frame))
340 {
341 xfree (glyphs->top_left_x);
342 xfree (glyphs->top_left_y);
343 xfree (glyphs->pix_width);
344 xfree (glyphs->pix_height);
345 xfree (glyphs->max_ascent);
346 }
347#endif
348
349 xfree (glyphs);
350}
351
352static void
353remake_frame_glyphs (frame)
354 FRAME_PTR frame;
355{
356 if (FRAME_CURRENT_GLYPHS (frame))
357 free_frame_glyphs (frame, FRAME_CURRENT_GLYPHS (frame));
358 if (FRAME_DESIRED_GLYPHS (frame))
359 free_frame_glyphs (frame, FRAME_DESIRED_GLYPHS (frame));
360 if (FRAME_TEMP_GLYPHS (frame))
361 free_frame_glyphs (frame, FRAME_TEMP_GLYPHS (frame));
362
363 if (FRAME_MESSAGE_BUF (frame))
364 {
365 /* Reallocate the frame's message buffer; remember that
366 echo_area_glyphs may be pointing here. */
367 char *old_message_buf = FRAME_MESSAGE_BUF (frame);
368
369 FRAME_MESSAGE_BUF (frame)
370 = (char *) xrealloc (FRAME_MESSAGE_BUF (frame),
371 FRAME_WIDTH (frame) + 1);
372
373 if (echo_area_glyphs == old_message_buf)
374 echo_area_glyphs = FRAME_MESSAGE_BUF (frame);
375 if (previous_echo_glyphs == old_message_buf)
376 previous_echo_glyphs = FRAME_MESSAGE_BUF (frame);
377 }
378 else
379 FRAME_MESSAGE_BUF (frame)
380 = (char *) xmalloc (FRAME_WIDTH (frame) + 1);
381
382 FRAME_CURRENT_GLYPHS (frame) = make_frame_glyphs (frame, 0);
383 FRAME_DESIRED_GLYPHS (frame) = make_frame_glyphs (frame, 0);
384 FRAME_TEMP_GLYPHS (frame) = make_frame_glyphs (frame, 1);
385 SET_FRAME_GARBAGED (frame);
386}
387\f
388/* Return the hash code of contents of line VPOS in frame-matrix M. */
389
390static int
391line_hash_code (m, vpos)
392 register struct frame_glyphs *m;
393 int vpos;
394{
395 register GLYPH *body, *end;
396 register int h = 0;
397
398 if (!m->enable[vpos])
399 return 0;
400
401 /* Give all highlighted lines the same hash code
402 so as to encourage scrolling to leave them in place. */
403 if (m->highlight[vpos])
404 return -1;
405
406 body = m->glyphs[vpos];
407
408 if (must_write_spaces)
409 while (1)
410 {
411 GLYPH g = *body++;
412
413 if (g == 0)
414 break;
415 h = (((h << 4) + (h >> 24)) & 0x0fffffff) + g - SPACEGLYPH;
416 }
417 else
418 while (1)
419 {
420 GLYPH g = *body++;
421
422 if (g == 0)
423 break;
424 h = (((h << 4) + (h >> 24)) & 0x0fffffff) + g;
425 }
426
427 if (h)
428 return h;
429 return 1;
430}
431
432/* Return number of characters in line in M at vpos VPOS,
433 except don't count leading and trailing spaces
434 unless the terminal requires those to be explicitly output. */
435
436static unsigned int
437line_draw_cost (m, vpos)
438 struct frame_glyphs *m;
439 int vpos;
440{
441 register GLYPH *beg = m->glyphs[vpos];
442 register GLYPH *end = m->glyphs[vpos] + m->used[vpos];
443 register int i;
444 register int tlen = GLYPH_TABLE_LENGTH;
445 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
446
447 /* Ignore trailing and leading spaces if we can. */
448 if (!must_write_spaces)
449 {
450 while ((end != beg) && (*end == SPACEGLYPH))
451 --end;
452 if (end == beg)
453 return (0); /* All blank line. */
454
455 while (*beg == SPACEGLYPH)
456 ++beg;
457 }
458
459 /* If we don't have a glyph-table, each glyph is one character,
460 so return the number of glyphs. */
461 if (tbase == 0)
462 return end - beg;
463
464 /* Otherwise, scan the glyphs and accumulate their total size in I. */
465 i = 0;
466 while ((beg <= end) && *beg)
467 {
468 register GLYPH g = *beg++;
469
470 if (GLYPH_SIMPLE_P (tbase, tlen, g))
471 i += 1;
472 else
473 i += GLYPH_LENGTH (tbase, g);
474 }
475 return i;
476}
477\f
478/* The functions on this page are the interface from xdisp.c to redisplay.
479
480 The only other interface into redisplay is through setting
481 FRAME_CURSOR_X (frame) and FRAME_CURSOR_Y (frame)
482 and SET_FRAME_GARBAGED (frame). */
483
484/* cancel_line eliminates any request to display a line at position `vpos' */
485
486cancel_line (vpos, frame)
487 int vpos;
488 register FRAME_PTR frame;
489{
490 FRAME_DESIRED_GLYPHS (frame)->enable[vpos] = 0;
491}
492
493clear_frame_records (frame)
494 register FRAME_PTR frame;
495{
496 bzero (FRAME_CURRENT_GLYPHS (frame)->enable, FRAME_HEIGHT (frame));
497}
498
499/* Prepare to display on line VPOS starting at HPOS within it. */
500
501void
502get_display_line (frame, vpos, hpos)
503 register FRAME_PTR frame;
504 int vpos;
505 register int hpos;
506{
507 register struct frame_glyphs *glyphs;
508 register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (frame);
509 register GLYPH *p;
510
511 if (vpos < 0)
512 abort ();
513
514 if ((desired_glyphs->enable[vpos]) && desired_glyphs->used[vpos] > hpos)
515 abort ();
516
517 if (! desired_glyphs->enable[vpos])
518 {
519 desired_glyphs->used[vpos] = 0;
520 desired_glyphs->highlight[vpos] = 0;
521 desired_glyphs->enable[vpos] = 1;
522 }
523
524 if (hpos > desired_glyphs->used[vpos])
525 {
526 GLYPH *g = desired_glyphs->glyphs[vpos] + desired_glyphs->used[vpos];
527 GLYPH *end = desired_glyphs->glyphs[vpos] + hpos;
528
529 desired_glyphs->used[vpos] = hpos;
530 while (g != end)
531 *g++ = SPACEGLYPH;
532 }
533}
534
535/* Like bcopy except never gets confused by overlap. */
536
537void
538safe_bcopy (from, to, size)
539 char *from, *to;
540 int size;
541{
542 if (size <= 0 || from == to)
543 return;
544
545 /* If the source and destination don't overlap, then bcopy can
546 handle it. If they do overlap, but the destination is lower in
547 memory than the source, we'll assume bcopy can handle that. */
548 if (to < from || from + size <= to)
549 bcopy (from, to, size);
550
551 /* Otherwise, we'll copy from the end. */
552 else
553 {
554 register char *endf = from + size;
555 register char *endt = to + size;
556
557 /* If TO - FROM is large, then we should break the copy into
558 nonoverlapping chunks of TO - FROM bytes each. However, if
559 TO - FROM is small, then the bcopy function call overhead
560 makes this not worth it. The crossover point could be about
561 anywhere. Since I don't think the obvious copy loop is too
562 bad, I'm trying to err in its favor. */
563 if (to - from < 64)
564 {
565 do
566 *--endt = *--endf;
567 while (endf != from);
568 }
569 else
570 {
571 for (;;)
572 {
573 endt -= (to - from);
574 endf -= (to - from);
575
576 if (endt < to)
577 break;
578
579 bcopy (endf, endt, to - from);
580 }
581
582 /* If SIZE wasn't a multiple of TO - FROM, there will be a
583 little left over. The amount left over is
584 (endt + (to - from)) - to, which is endt - from. */
585 bcopy (from, to, endt - from);
586 }
587 }
588}
589
590/* Rotate a vector of SIZE bytes right, by DISTANCE bytes.
591 DISTANCE may be negative. */
592
593static void
594rotate_vector (vector, size, distance)
595 char *vector;
596 int size;
597 int distance;
598{
599 char *temp = (char *) alloca (size);
600
601 if (distance < 0)
602 distance += size;
603
604 bcopy (vector, temp + distance, size - distance);
605 bcopy (vector + size - distance, temp, distance);
606 bcopy (temp, vector, size);
607}
608
609/* Scroll lines from vpos FROM up to but not including vpos END
610 down by AMOUNT lines (AMOUNT may be negative).
611 Returns nonzero if done, zero if terminal cannot scroll them. */
612
613int
614scroll_frame_lines (frame, from, end, amount, newpos)
615 register FRAME_PTR frame;
616 int from, end, amount, newpos;
617{
618 register int i;
619 register struct frame_glyphs *current_frame
620 = FRAME_CURRENT_GLYPHS (frame);
621 int pos_adjust;
622 int width = FRAME_WIDTH (frame);
623
624 if (!line_ins_del_ok)
625 return 0;
626
627 if (amount == 0)
628 return 1;
629
630 if (amount > 0)
631 {
632 update_begin (frame);
633 set_terminal_window (end + amount);
634 if (!scroll_region_ok)
635 ins_del_lines (end, -amount);
636 ins_del_lines (from, amount);
637 set_terminal_window (0);
638
639 rotate_vector (current_frame->glyphs + from,
640 sizeof (GLYPH *) * (end + amount - from),
641 amount * sizeof (GLYPH *));
642
643 rotate_vector (current_frame->charstarts + from,
644 sizeof (int *) * (end + amount - from),
645 amount * sizeof (int *));
646
647 safe_bcopy (current_frame->used + from,
648 current_frame->used + from + amount,
649 (end - from) * sizeof current_frame->used[0]);
650
651 safe_bcopy (current_frame->highlight + from,
652 current_frame->highlight + from + amount,
653 (end - from) * sizeof current_frame->highlight[0]);
654
655 safe_bcopy (current_frame->enable + from,
656 current_frame->enable + from + amount,
657 (end - from) * sizeof current_frame->enable[0]);
658
659 /* Adjust the lines by an amount
660 that puts the first of them at NEWPOS. */
661 pos_adjust = newpos - current_frame->charstarts[from + amount][0];
662
663 /* Offset each char position in the charstarts lines we moved
664 by pos_adjust. */
665 for (i = from + amount; i < end + amount; i++)
666 {
667 int *line = current_frame->charstarts[i];
668 int col;
669 for (col = 0; col < width; col++)
670 if (line[col] > 0)
671 line[col] += pos_adjust;
672 }
673 for (i = from; i < from + amount; i++)
674 {
675 int *line = current_frame->charstarts[i];
676 int col;
677 line[0] = -1;
678 for (col = 0; col < width; col++)
679 line[col] = 0;
680 }
681
682 /* Mark the lines made empty by scrolling as enabled, empty and
683 normal video. */
684 bzero (current_frame->used + from,
685 amount * sizeof current_frame->used[0]);
686 bzero (current_frame->highlight + from,
687 amount * sizeof current_frame->highlight[0]);
688 for (i = from; i < from + amount; i++)
689 {
690 current_frame->glyphs[i][0] = '\0';
691 current_frame->charstarts[i][0] = -1;
692 current_frame->enable[i] = 1;
693 }
694
695 safe_bcopy (current_frame->bufp + from,
696 current_frame->bufp + from + amount,
697 (end - from) * sizeof current_frame->bufp[0]);
698
699#ifdef HAVE_X_WINDOWS
700 if (FRAME_X_P (frame))
701 {
702 safe_bcopy (current_frame->top_left_x + from,
703 current_frame->top_left_x + from + amount,
704 (end - from) * sizeof current_frame->top_left_x[0]);
705
706 safe_bcopy (current_frame->top_left_y + from,
707 current_frame->top_left_y + from + amount,
708 (end - from) * sizeof current_frame->top_left_y[0]);
709
710 safe_bcopy (current_frame->pix_width + from,
711 current_frame->pix_width + from + amount,
712 (end - from) * sizeof current_frame->pix_width[0]);
713
714 safe_bcopy (current_frame->pix_height + from,
715 current_frame->pix_height + from + amount,
716 (end - from) * sizeof current_frame->pix_height[0]);
717
718 safe_bcopy (current_frame->max_ascent + from,
719 current_frame->max_ascent + from + amount,
720 (end - from) * sizeof current_frame->max_ascent[0]);
721 }
722#endif /* HAVE_X_WINDOWS */
723
724 update_end (frame);
725 }
726 if (amount < 0)
727 {
728 update_begin (frame);
729 set_terminal_window (end);
730 ins_del_lines (from + amount, amount);
731 if (!scroll_region_ok)
732 ins_del_lines (end + amount, -amount);
733 set_terminal_window (0);
734
735 rotate_vector (current_frame->glyphs + from + amount,
736 sizeof (GLYPH *) * (end - from - amount),
737 amount * sizeof (GLYPH *));
738
739 rotate_vector (current_frame->charstarts + from + amount,
740 sizeof (int *) * (end - from - amount),
741 amount * sizeof (int *));
742
743 safe_bcopy (current_frame->used + from,
744 current_frame->used + from + amount,
745 (end - from) * sizeof current_frame->used[0]);
746
747 safe_bcopy (current_frame->highlight + from,
748 current_frame->highlight + from + amount,
749 (end - from) * sizeof current_frame->highlight[0]);
750
751 safe_bcopy (current_frame->enable + from,
752 current_frame->enable + from + amount,
753 (end - from) * sizeof current_frame->enable[0]);
754
755 /* Adjust the lines by an amount
756 that puts the first of them at NEWPOS. */
757 pos_adjust = newpos - current_frame->charstarts[from + amount][0];
758
759 /* Offset each char position in the charstarts lines we moved
760 by pos_adjust. */
761 for (i = from + amount; i < end + amount; i++)
762 {
763 int *line = current_frame->charstarts[i];
764 int col;
765 for (col = 0; col < width; col++)
766 if (line[col] > 0)
767 line[col] += pos_adjust;
768 }
769 for (i = end + amount; i < end; i++)
770 {
771 int *line = current_frame->charstarts[i];
772 int col;
773 line[0] = -1;
774 for (col = 0; col < width; col++)
775 line[col] = 0;
776 }
777
778 /* Mark the lines made empty by scrolling as enabled, empty and
779 normal video. */
780 bzero (current_frame->used + end + amount,
781 - amount * sizeof current_frame->used[0]);
782 bzero (current_frame->highlight + end + amount,
783 - amount * sizeof current_frame->highlight[0]);
784 for (i = end + amount; i < end; i++)
785 {
786 current_frame->glyphs[i][0] = '\0';
787 current_frame->charstarts[i][0] = 0;
788 current_frame->enable[i] = 1;
789 }
790
791 safe_bcopy (current_frame->bufp + from,
792 current_frame->bufp + from + amount,
793 (end - from) * sizeof current_frame->bufp[0]);
794
795#ifdef HAVE_X_WINDOWS
796 if (FRAME_X_P (frame))
797 {
798 safe_bcopy (current_frame->top_left_x + from,
799 current_frame->top_left_x + from + amount,
800 (end - from) * sizeof current_frame->top_left_x[0]);
801
802 safe_bcopy (current_frame->top_left_y + from,
803 current_frame->top_left_y + from + amount,
804 (end - from) * sizeof current_frame->top_left_y[0]);
805
806 safe_bcopy (current_frame->pix_width + from,
807 current_frame->pix_width + from + amount,
808 (end - from) * sizeof current_frame->pix_width[0]);
809
810 safe_bcopy (current_frame->pix_height + from,
811 current_frame->pix_height + from + amount,
812 (end - from) * sizeof current_frame->pix_height[0]);
813
814 safe_bcopy (current_frame->max_ascent + from,
815 current_frame->max_ascent + from + amount,
816 (end - from) * sizeof current_frame->max_ascent[0]);
817 }
818#endif /* HAVE_X_WINDOWS */
819
820 update_end (frame);
821 }
822 return 1;
823}
824\f
825/* After updating a window W that isn't the full frame wide,
826 copy all the columns that W does not occupy
827 into the FRAME_DESIRED_GLYPHS (frame) from the FRAME_PHYS_GLYPHS (frame)
828 so that update_frame will not change those columns. */
829
830preserve_other_columns (w)
831 struct window *w;
832{
833 register int vpos;
834 register struct frame_glyphs *current_frame, *desired_frame;
835 register FRAME_PTR frame = XFRAME (w->frame);
836 int start = XFASTINT (w->left);
837 int end = XFASTINT (w->left) + XFASTINT (w->width);
838 int bot = XFASTINT (w->top) + XFASTINT (w->height);
839
840 current_frame = FRAME_CURRENT_GLYPHS (frame);
841 desired_frame = FRAME_DESIRED_GLYPHS (frame);
842
843 for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
844 {
845 if (current_frame->enable[vpos] && desired_frame->enable[vpos])
846 {
847 if (start > 0)
848 {
849 int len;
850
851 bcopy (current_frame->glyphs[vpos],
852 desired_frame->glyphs[vpos],
853 start * sizeof (current_frame->glyphs[vpos]));
854 bcopy (current_frame->charstarts[vpos],
855 desired_frame->charstarts[vpos],
856 start * sizeof (current_frame->charstarts[vpos]));
857 len = min (start, current_frame->used[vpos]);
858 if (desired_frame->used[vpos] < len)
859 desired_frame->used[vpos] = len;
860 }
861 if (current_frame->used[vpos] > end
862 && desired_frame->used[vpos] < current_frame->used[vpos])
863 {
864 while (desired_frame->used[vpos] < end)
865 {
866 int used = desired_frame->used[vpos]++;
867 desired_frame->glyphs[vpos][used] = SPACEGLYPH;
868 desired_frame->glyphs[vpos][used] = 0;
869 }
870 bcopy (current_frame->glyphs[vpos] + end,
871 desired_frame->glyphs[vpos] + end,
872 ((current_frame->used[vpos] - end)
873 * sizeof (current_frame->glyphs[vpos])));
874 bcopy (current_frame->charstarts[vpos] + end,
875 desired_frame->charstarts[vpos] + end,
876 ((current_frame->used[vpos] - end)
877 * sizeof (current_frame->charstarts[vpos])));
878 desired_frame->used[vpos] = current_frame->used[vpos];
879 }
880 }
881 }
882}
883\f
884#if 0
885
886/* If window w does not need to be updated and isn't the full frame wide,
887 copy all the columns that w does occupy
888 into the FRAME_DESIRED_LINES (frame) from the FRAME_PHYS_LINES (frame)
889 so that update_frame will not change those columns.
890
891 Have not been able to figure out how to use this correctly. */
892
893preserve_my_columns (w)
894 struct window *w;
895{
896 register int vpos, fin;
897 register struct frame_glyphs *l1, *l2;
898 register FRAME_PTR frame = XFRAME (w->frame);
899 int start = XFASTINT (w->left);
900 int end = XFASTINT (w->left) + XFASTINT (w->width);
901 int bot = XFASTINT (w->top) + XFASTINT (w->height);
902
903 for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
904 {
905 if ((l1 = FRAME_DESIRED_GLYPHS (frame)->glyphs[vpos + 1])
906 && (l2 = FRAME_PHYS_GLYPHS (frame)->glyphs[vpos + 1]))
907 {
908 if (l2->length > start && l1->length < l2->length)
909 {
910 fin = l2->length;
911 if (fin > end) fin = end;
912 while (l1->length < start)
913 l1->body[l1->length++] = ' ';
914 bcopy (l2->body + start, l1->body + start, fin - start);
915 l1->length = fin;
916 }
917 }
918 }
919}
920
921#endif
922\f
923/* Adjust by ADJUST the charstart values in window W
924 after vpos VPOS, which counts relative to the frame
925 (not relative to W itself). */
926
927void
928adjust_window_charstarts (w, vpos, adjust)
929 struct window *w;
930 int vpos;
931 int adjust;
932{
933 int left = XFASTINT (w->left);
934 int top = XFASTINT (w->top);
935 int right = left + window_internal_width (w);
936 int bottom = top + window_internal_height (w);
937 int i;
938
939 for (i = vpos + 1; i < bottom; i++)
940 {
941 int *charstart
942 = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[i];
943 int j;
944 for (j = left; j < right; j++)
945 if (charstart[j] > 0)
946 charstart[j] += adjust;
947 }
948}
949
950/* Check the charstarts values in the area of window W
951 for internal consistency. We cannot check that they are "right";
952 we can only look for something nonsensical. */
953
954verify_charstarts (w)
955 struct window *w;
956{
957 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
958 int i;
959 int top = XFASTINT (w->top);
960 int bottom = top + window_internal_height (w);
961 int left = XFASTINT (w->left);
962 int right = left + window_internal_width (w);
963 int next_line;
964 int truncate = (XINT (w->hscroll)
965 || (truncate_partial_width_windows
966 && (XFASTINT (w->width) < FRAME_WIDTH (f)))
967 || !NILP (XBUFFER (w->buffer)->truncate_lines));
968
969 for (i = top; i < bottom; i++)
970 {
971 int j;
972 int last;
973 int *charstart = FRAME_CURRENT_GLYPHS (f)->charstarts[i];
974
975 if (i != top)
976 {
977 if (truncate)
978 {
979 /* If we are truncating lines, allow a jump
980 in charstarts from one line to the next. */
981 if (charstart[left] < next_line)
982 abort ();
983 }
984 else
985 {
986 if (charstart[left] != next_line)
987 abort ();
988 }
989 }
990
991 for (j = left; j < right; j++)
992 if (charstart[j] > 0)
993 last = charstart[j];
994 /* Record where the next line should start. */
995 next_line = last;
996 if (BUF_ZV (XBUFFER (w->buffer)) != last)
997 {
998 /* If there's a newline between the two lines, count that. */
999 int endchar = *BUF_CHAR_ADDRESS (XBUFFER (w->buffer), last);
1000 if (endchar == '\n')
1001 next_line++;
1002 }
1003 }
1004}
1005\f
1006/* On discovering that the redisplay for a window was no good,
1007 cancel the columns of that window, so that when the window is
1008 displayed over again get_display_line will not complain. */
1009
1010cancel_my_columns (w)
1011 struct window *w;
1012{
1013 register int vpos;
1014 register struct frame_glyphs *desired_glyphs
1015 = FRAME_DESIRED_GLYPHS (XFRAME (w->frame));
1016 register int start = XFASTINT (w->left);
1017 register int bot = XFASTINT (w->top) + XFASTINT (w->height);
1018
1019 for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
1020 if (desired_glyphs->enable[vpos]
1021 && desired_glyphs->used[vpos] >= start)
1022 desired_glyphs->used[vpos] = start;
1023}
1024\f
1025/* These functions try to perform directly and immediately on the frame
1026 the necessary output for one change in the buffer.
1027 They may return 0 meaning nothing was done if anything is difficult,
1028 or 1 meaning the output was performed properly.
1029 They assume that the frame was up to date before the buffer
1030 change being displayed. They make various other assumptions too;
1031 see command_loop_1 where these are called. */
1032
1033int
1034direct_output_for_insert (g)
1035 int g;
1036{
1037 register FRAME_PTR frame = selected_frame;
1038 register struct frame_glyphs *current_frame
1039 = FRAME_CURRENT_GLYPHS (frame);
1040
1041#ifndef COMPILER_REGISTER_BUG
1042 register
1043#endif /* COMPILER_REGISTER_BUG */
1044 struct window *w = XWINDOW (selected_window);
1045#ifndef COMPILER_REGISTER_BUG
1046 register
1047#endif /* COMPILER_REGISTER_BUG */
1048 int hpos = FRAME_CURSOR_X (frame);
1049#ifndef COMPILER_REGISTER_BUG
1050 register
1051#endif /* COMPILER_REGISTER_BUG */
1052 int vpos = FRAME_CURSOR_Y (frame);
1053
1054 /* Give up if about to continue line. */
1055 if (hpos >= XFASTINT (w->left) + window_internal_width (w) - 1
1056
1057 /* Avoid losing if cursor is in invisible text off left margin */
1058 || (XINT (w->hscroll) && hpos == XFASTINT (w->left))
1059
1060 /* Give up if cursor outside window (in minibuf, probably) */
1061 || cursor_in_echo_area
1062 || FRAME_CURSOR_Y (frame) < XFASTINT (w->top)
1063 || FRAME_CURSOR_Y (frame) >= XFASTINT (w->top) + XFASTINT (w->height)
1064
1065 /* Give up if cursor not really at FRAME_CURSOR_X, FRAME_CURSOR_Y */
1066 || !display_completed
1067
1068 /* Give up if buffer appears in two places. */
1069 || buffer_shared > 1
1070
1071#ifdef USE_TEXT_PROPERTIES
1072 /* Intervals have already been adjusted, point is after the
1073 character that was just inserted. */
1074 /* Give up if character is invisible. */
1075 /* Give up if character has a face property.
1076 At the moment we only lose at end of line or end of buffer
1077 and only with faces that have some background */
1078 /* Instead of wasting time, give up if character has any text properties */
1079 || ! NILP (Ftext_properties_at (XFASTINT (point - 1), Qnil))
1080#endif
1081
1082 /* Give up if w is minibuffer and a message is being displayed there */
1083 || (MINI_WINDOW_P (w) && echo_area_glyphs))
1084 return 0;
1085
1086 {
1087#ifdef HAVE_X_WINDOWS
1088 int dummy;
1089 int face = compute_char_face (frame, w, point - 1, -1, -1, &dummy, point);
1090#endif
1091 current_frame->glyphs[vpos][hpos] = MAKE_GLYPH (frame, g, face);
1092 current_frame->charstarts[vpos][hpos] = point - 1;
1093 /* Record the entry for after the newly inserted character. */
1094 current_frame->charstarts[vpos][hpos + 1] = point;
1095 adjust_window_charstarts (w, vpos, 1);
1096 }
1097 unchanged_modified = MODIFF;
1098 beg_unchanged = GPT - BEG;
1099 XFASTINT (w->last_point) = point;
1100 XFASTINT (w->last_point_x) = hpos;
1101 XFASTINT (w->last_modified) = MODIFF;
1102
1103 reassert_line_highlight (0, vpos);
1104 write_glyphs (&current_frame->glyphs[vpos][hpos], 1);
1105 fflush (stdout);
1106 ++FRAME_CURSOR_X (frame);
1107 if (hpos == current_frame->used[vpos])
1108 {
1109 current_frame->used[vpos] = hpos + 1;
1110 current_frame->glyphs[vpos][hpos + 1] = 0;
1111 }
1112
1113 return 1;
1114}
1115
1116int
1117direct_output_forward_char (n)
1118 int n;
1119{
1120 register FRAME_PTR frame = selected_frame;
1121 register struct window *w = XWINDOW (selected_window);
1122 int position;
1123 int hpos = FRAME_CURSOR_X (frame);
1124
1125 /* Give up if in truncated text at end of line. */
1126 if (hpos >= XFASTINT (w->left) + window_internal_width (w) - 1)
1127 return 0;
1128
1129 /* Avoid losing if cursor is in invisible text off left margin
1130 or about to go off either side of window. */
1131 if ((FRAME_CURSOR_X (frame) == XFASTINT (w->left)
1132 && (XINT (w->hscroll) || n < 0))
1133 || (n > 0
1134 && (FRAME_CURSOR_X (frame) + 1 >= window_internal_width (w) - 1))
1135 || cursor_in_echo_area)
1136 return 0;
1137
1138 /* Can't use direct output if highlighting a region. */
1139 if (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
1140 return 0;
1141
1142#ifdef USE_TEXT_PROPERTIES
1143 /* Don't use direct output next to an invisible character
1144 since we might need to do something special. */
1145
1146 XFASTINT (position) = point;
1147 if (XFASTINT (position) < ZV
1148 && ! NILP (Fget_char_property (position,
1149 Qinvisible,
1150 selected_window)))
1151 return 0;
1152
1153 XFASTINT (position) = point - 1;
1154 if (XFASTINT (position) >= BEGV
1155 && ! NILP (Fget_char_property (position,
1156 Qinvisible,
1157 selected_window)))
1158 return 0;
1159#endif
1160
1161 FRAME_CURSOR_X (frame) += n;
1162 XFASTINT (w->last_point_x) = FRAME_CURSOR_X (frame);
1163 XFASTINT (w->last_point) = point;
1164 cursor_to (FRAME_CURSOR_Y (frame), FRAME_CURSOR_X (frame));
1165 fflush (stdout);
1166
1167 return 1;
1168}
1169\f
1170static void update_line ();
1171
1172/* Update frame F based on the data in FRAME_DESIRED_GLYPHS.
1173 Value is nonzero if redisplay stopped due to pending input.
1174 FORCE nonzero means do not stop for pending input. */
1175
1176int
1177update_frame (f, force, inhibit_hairy_id)
1178 FRAME_PTR f;
1179 int force;
1180 int inhibit_hairy_id;
1181{
1182 register struct frame_glyphs *current_frame;
1183 register struct frame_glyphs *desired_frame = 0;
1184 register int i;
1185 int pause;
1186 int preempt_count = baud_rate / 2400 + 1;
1187 extern input_pending;
1188#ifdef HAVE_X_WINDOWS
1189 register int downto, leftmost;
1190#endif
1191
1192 if (preempt_count <= 0)
1193 preempt_count = 1;
1194
1195 if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
1196
1197 detect_input_pending ();
1198 if (input_pending && !force)
1199 {
1200 pause = 1;
1201 goto do_pause;
1202 }
1203
1204 update_begin (f);
1205
1206 if (!line_ins_del_ok)
1207 inhibit_hairy_id = 1;
1208
1209 /* These are separate to avoid a possible bug in the AIX C compiler. */
1210 current_frame = FRAME_CURRENT_GLYPHS (f);
1211 desired_frame = FRAME_DESIRED_GLYPHS (f);
1212
1213 /* See if any of the desired lines are enabled; don't compute for
1214 i/d line if just want cursor motion. */
1215 for (i = 0; i < FRAME_HEIGHT (f); i++)
1216 if (desired_frame->enable[i])
1217 break;
1218
1219 /* Try doing i/d line, if not yet inhibited. */
1220 if (!inhibit_hairy_id && i < FRAME_HEIGHT (f))
1221 force |= scrolling (f);
1222
1223 /* Update the individual lines as needed. Do bottom line first. */
1224
1225 if (desired_frame->enable[FRAME_HEIGHT (f) - 1])
1226 update_line (f, FRAME_HEIGHT (f) - 1);
1227
1228#ifdef HAVE_X_WINDOWS
1229 if (FRAME_X_P (f))
1230 {
1231 leftmost = downto = f->display.x->internal_border_width;
1232 if (desired_frame->enable[0])
1233 {
1234 current_frame->top_left_x[FRAME_HEIGHT (f) - 1] = leftmost;
1235 current_frame->top_left_y[FRAME_HEIGHT (f) - 1]
1236 = PIXEL_HEIGHT (f) - f->display.x->internal_border_width
1237 - current_frame->pix_height[FRAME_HEIGHT (f) - 1];
1238 current_frame->top_left_x[0] = leftmost;
1239 current_frame->top_left_y[0] = downto;
1240 }
1241 }
1242#endif /* HAVE_X_WINDOWS */
1243
1244 /* Now update the rest of the lines. */
1245 for (i = 0; i < FRAME_HEIGHT (f) - 1 && (force || !input_pending); i++)
1246 {
1247 if (desired_frame->enable[i])
1248 {
1249 if (FRAME_TERMCAP_P (f))
1250 {
1251 /* Flush out every so many lines.
1252 Also flush out if likely to have more than 1k buffered
1253 otherwise. I'm told that some telnet connections get
1254 really screwed by more than 1k output at once. */
1255 int outq = PENDING_OUTPUT_COUNT (stdout);
1256 if (outq > 900
1257 || (outq > 20 && ((i - 1) % preempt_count == 0)))
1258 {
1259 fflush (stdout);
1260 if (preempt_count == 1)
1261 {
1262#ifdef EMACS_OUTQSIZE
1263 if (EMACS_OUTQSIZE (0, &outq) < 0)
1264 /* Probably not a tty. Ignore the error and reset
1265 * the outq count. */
1266 outq = PENDING_OUTPUT_COUNT (stdout);
1267#endif
1268 outq *= 10;
1269 if (baud_rate <= outq && baud_rate > 0)
1270 sleep (outq / baud_rate);
1271 }
1272 }
1273 if ((i - 1) % preempt_count == 0)
1274 detect_input_pending ();
1275 }
1276
1277 update_line (f, i);
1278#ifdef HAVE_X_WINDOWS
1279 if (FRAME_X_P (f))
1280 {
1281 current_frame->top_left_y[i] = downto;
1282 current_frame->top_left_x[i] = leftmost;
1283 }
1284#endif /* HAVE_X_WINDOWS */
1285 }
1286
1287#ifdef HAVE_X_WINDOWS
1288 if (FRAME_X_P (f))
1289 downto += current_frame->pix_height[i];
1290#endif
1291 }
1292 pause = (i < FRAME_HEIGHT (f) - 1) ? i : 0;
1293
1294 /* Now just clean up termcap drivers and set cursor, etc. */
1295 if (!pause)
1296 {
1297 if (cursor_in_echo_area
1298 && FRAME_HAS_MINIBUF_P (f))
1299 {
1300 int top = XINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top);
1301 int row, col;
1302
1303 if (cursor_in_echo_area < 0)
1304 {
1305 row = top;
1306 col = 0;
1307 }
1308 else
1309 {
1310 /* If the minibuffer is several lines high, find the last
1311 line that has any text on it. */
1312 row = FRAME_HEIGHT (f);
1313 do
1314 {
1315 row--;
1316 if (current_frame->enable[row])
1317 col = current_frame->used[row];
1318 else
1319 col = 0;
1320 }
1321 while (row > top && col == 0);
1322
1323 if (col >= FRAME_WIDTH (f))
1324 {
1325 col = 0;
1326 if (row < FRAME_HEIGHT (f) - 1)
1327 row++;
1328 }
1329 }
1330
1331 cursor_to (row, col);
1332 }
1333 else
1334 cursor_to (FRAME_CURSOR_Y (f), max (min (FRAME_CURSOR_X (f),
1335 FRAME_WIDTH (f) - 1), 0));
1336 }
1337
1338 update_end (f);
1339
1340 if (termscript)
1341 fflush (termscript);
1342 fflush (stdout);
1343
1344 /* Here if output is preempted because input is detected. */
1345 do_pause:
1346
1347 if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
1348 display_completed = !pause;
1349
1350 bzero (FRAME_DESIRED_GLYPHS (f)->enable, FRAME_HEIGHT (f));
1351 return pause;
1352}
1353
1354/* Called when about to quit, to check for doing so
1355 at an improper time. */
1356
1357void
1358quit_error_check ()
1359{
1360 if (FRAME_DESIRED_GLYPHS (selected_frame) == 0)
1361 return;
1362 if (FRAME_DESIRED_GLYPHS (selected_frame)->enable[0])
1363 abort ();
1364 if (FRAME_DESIRED_GLYPHS (selected_frame)->enable[FRAME_HEIGHT (selected_frame) - 1])
1365 abort ();
1366}
1367\f
1368/* Decide what insert/delete line to do, and do it */
1369
1370extern void scrolling_1 ();
1371
1372scrolling (frame)
1373 FRAME_PTR frame;
1374{
1375 int unchanged_at_top, unchanged_at_bottom;
1376 int window_size;
1377 int changed_lines;
1378 int *old_hash = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
1379 int *new_hash = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
1380 int *draw_cost = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
1381 register int i;
1382 int free_at_end_vpos = FRAME_HEIGHT (frame);
1383 register struct frame_glyphs *current_frame = FRAME_CURRENT_GLYPHS (frame);
1384 register struct frame_glyphs *desired_frame = FRAME_DESIRED_GLYPHS (frame);
1385
1386 /* Compute hash codes of all the lines.
1387 Also calculate number of changed lines,
1388 number of unchanged lines at the beginning,
1389 and number of unchanged lines at the end. */
1390
1391 changed_lines = 0;
1392 unchanged_at_top = 0;
1393 unchanged_at_bottom = FRAME_HEIGHT (frame);
1394 for (i = 0; i < FRAME_HEIGHT (frame); i++)
1395 {
1396 /* Give up on this scrolling if some old lines are not enabled. */
1397 if (!current_frame->enable[i])
1398 return 0;
1399 old_hash[i] = line_hash_code (current_frame, i);
1400 if (! desired_frame->enable[i])
1401 new_hash[i] = old_hash[i];
1402 else
1403 new_hash[i] = line_hash_code (desired_frame, i);
1404
1405 if (old_hash[i] != new_hash[i])
1406 {
1407 changed_lines++;
1408 unchanged_at_bottom = FRAME_HEIGHT (frame) - i - 1;
1409 }
1410 else if (i == unchanged_at_top)
1411 unchanged_at_top++;
1412 draw_cost[i] = line_draw_cost (desired_frame, i);
1413 }
1414
1415 /* If changed lines are few, don't allow preemption, don't scroll. */
1416 if (changed_lines < baud_rate / 2400
1417 || unchanged_at_bottom == FRAME_HEIGHT (frame))
1418 return 1;
1419
1420 window_size = (FRAME_HEIGHT (frame) - unchanged_at_top
1421 - unchanged_at_bottom);
1422
1423 if (scroll_region_ok)
1424 free_at_end_vpos -= unchanged_at_bottom;
1425 else if (memory_below_frame)
1426 free_at_end_vpos = -1;
1427
1428 /* If large window, fast terminal and few lines in common between
1429 current frame and desired frame, don't bother with i/d calc. */
1430 if (window_size >= 18 && baud_rate > 2400
1431 && (window_size >=
1432 10 * scrolling_max_lines_saved (unchanged_at_top,
1433 FRAME_HEIGHT (frame) - unchanged_at_bottom,
1434 old_hash, new_hash, draw_cost)))
1435 return 0;
1436
1437 scrolling_1 (frame, window_size, unchanged_at_top, unchanged_at_bottom,
1438 draw_cost + unchanged_at_top - 1,
1439 old_hash + unchanged_at_top - 1,
1440 new_hash + unchanged_at_top - 1,
1441 free_at_end_vpos - unchanged_at_top);
1442
1443 return 0;
1444}
1445\f
1446/* Return the offset in its buffer of the character at location col, line
1447 in the given window. */
1448int
1449buffer_posn_from_coords (window, col, line)
1450 struct window *window;
1451 int col, line;
1452{
1453 int hscroll = XINT (window->hscroll);
1454 int window_left = XFASTINT (window->left);
1455
1456 /* The actual width of the window is window->width less one for the
1457 DISP_CONTINUE_GLYPH, and less one if it's not the rightmost
1458 window. */
1459 int window_width = window_internal_width (window) - 1;
1460
1461 int startp = marker_position (window->start);
1462
1463 /* Since compute_motion will only operate on the current buffer,
1464 we need to save the old one and restore it when we're done. */
1465 struct buffer *old_current_buffer = current_buffer;
1466 struct position *posn;
1467
1468 current_buffer = XBUFFER (window->buffer);
1469
1470 /* It would be nice if we could use FRAME_CURRENT_GLYPHS (XFRAME
1471 (window->frame))->bufp to avoid scanning from the very top of
1472 the window, but it isn't maintained correctly, and I'm not even
1473 sure I will keep it. */
1474 posn = compute_motion (startp, 0,
1475 (window == XWINDOW (minibuf_window) && startp == 1
1476 ? minibuf_prompt_width : 0)
1477 + (hscroll ? 1 - hscroll : 0),
1478 ZV, line, col,
1479 window_width, hscroll, 0, window);
1480
1481 current_buffer = old_current_buffer;
1482
1483 /* compute_motion considers frame points past the end of a line
1484 to be *after* the newline, i.e. at the start of the next line.
1485 This is reasonable, but not really what we want. So if the
1486 result is on a line below LINE, back it up one character. */
1487 if (posn->vpos > line)
1488 return posn->bufpos - 1;
1489 else
1490 return posn->bufpos;
1491}
1492\f
1493static int
1494count_blanks (r)
1495 register GLYPH *r;
1496{
1497 register GLYPH *p = r;
1498 while (*p++ == SPACEGLYPH);
1499 return p - r - 1;
1500}
1501
1502static int
1503count_match (str1, str2)
1504 GLYPH *str1, *str2;
1505{
1506 register GLYPH *p1 = str1;
1507 register GLYPH *p2 = str2;
1508 while (*p1++ == *p2++);
1509 return p1 - str1 - 1;
1510}
1511
1512/* Char insertion/deletion cost vector, from term.c */
1513extern int *char_ins_del_vector;
1514
1515#define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_WIDTH((f))])
1516
1517static void
1518update_line (frame, vpos)
1519 register FRAME_PTR frame;
1520 int vpos;
1521{
1522 register GLYPH *obody, *nbody, *op1, *op2, *np1, *temp;
1523 int *temp1;
1524 int tem;
1525 int osp, nsp, begmatch, endmatch, olen, nlen;
1526 int save;
1527 register struct frame_glyphs *current_frame
1528 = FRAME_CURRENT_GLYPHS (frame);
1529 register struct frame_glyphs *desired_frame
1530 = FRAME_DESIRED_GLYPHS (frame);
1531
1532 if (desired_frame->highlight[vpos]
1533 != (current_frame->enable[vpos] && current_frame->highlight[vpos]))
1534 {
1535 change_line_highlight (desired_frame->highlight[vpos], vpos,
1536 (current_frame->enable[vpos] ?
1537 current_frame->used[vpos] : 0));
1538 current_frame->enable[vpos] = 0;
1539 }
1540 else
1541 reassert_line_highlight (desired_frame->highlight[vpos], vpos);
1542
1543 if (! current_frame->enable[vpos])
1544 {
1545 olen = 0;
1546 }
1547 else
1548 {
1549 obody = current_frame->glyphs[vpos];
1550 olen = current_frame->used[vpos];
1551 if (! current_frame->highlight[vpos])
1552 {
1553 if (!must_write_spaces)
1554 while (obody[olen - 1] == SPACEGLYPH && olen > 0)
1555 olen--;
1556 }
1557 else
1558 {
1559 /* For an inverse-video line, remember we gave it
1560 spaces all the way to the frame edge
1561 so that the reverse video extends all the way across. */
1562
1563 while (olen < FRAME_WIDTH (frame) - 1)
1564 obody[olen++] = SPACEGLYPH;
1565 }
1566 }
1567
1568 /* One way or another, this will enable the line being updated. */
1569 current_frame->enable[vpos] = 1;
1570 current_frame->used[vpos] = desired_frame->used[vpos];
1571 current_frame->highlight[vpos] = desired_frame->highlight[vpos];
1572 current_frame->bufp[vpos] = desired_frame->bufp[vpos];
1573
1574#ifdef HAVE_X_WINDOWS
1575 if (FRAME_X_P (frame))
1576 {
1577 current_frame->pix_width[vpos]
1578 = current_frame->used[vpos]
1579 * FONT_WIDTH (frame->display.x->font);
1580 current_frame->pix_height[vpos]
1581 = frame->display.x->line_height;
1582 }
1583#endif /* HAVE_X_WINDOWS */
1584
1585 if (!desired_frame->enable[vpos])
1586 {
1587 nlen = 0;
1588 goto just_erase;
1589 }
1590
1591 nbody = desired_frame->glyphs[vpos];
1592 nlen = desired_frame->used[vpos];
1593
1594 /* Pretend trailing spaces are not there at all,
1595 unless for one reason or another we must write all spaces. */
1596 if (! desired_frame->highlight[vpos])
1597 {
1598 if (!must_write_spaces)
1599 /* We know that the previous character byte contains 0. */
1600 while (nbody[nlen - 1] == SPACEGLYPH)
1601 nlen--;
1602 }
1603 else
1604 {
1605 /* For an inverse-video line, give it extra trailing spaces
1606 all the way to the frame edge
1607 so that the reverse video extends all the way across. */
1608
1609 while (nlen < FRAME_WIDTH (frame) - 1)
1610 nbody[nlen++] = SPACEGLYPH;
1611 }
1612
1613 /* If there's no i/d char, quickly do the best we can without it. */
1614 if (!char_ins_del_ok)
1615 {
1616 int i,j;
1617
1618#if 0
1619 if (FRAME_X_P (frame))
1620 {
1621 /* Under X, erase everything we are going to rewrite,
1622 and rewrite everything from the first char that's changed.
1623 This is part of supporting fonts like Courier
1624 whose chars can overlap outside the char width. */
1625 for (i = 0; i < nlen; i++)
1626 if (i >= olen || nbody[i] != obody[i])
1627 break;
1628
1629 cursor_to (vpos, i);
1630 if (i != olen)
1631 clear_end_of_line (olen);
1632 write_glyphs (nbody + i, nlen - i);
1633 }
1634 else
1635 {}
1636#endif /* 0 */
1637 for (i = 0; i < nlen; i++)
1638 {
1639 if (i >= olen || nbody[i] != obody[i]) /* A non-matching char. */
1640 {
1641 cursor_to (vpos, i);
1642 for (j = 1; (i + j < nlen &&
1643 (i + j >= olen || nbody[i+j] != obody[i+j]));
1644 j++);
1645
1646 /* Output this run of non-matching chars. */
1647 write_glyphs (nbody + i, j);
1648 i += j - 1;
1649
1650 /* Now find the next non-match. */
1651 }
1652 }
1653
1654 /* Clear the rest of the line, or the non-clear part of it. */
1655 if (olen > nlen)
1656 {
1657 cursor_to (vpos, nlen);
1658 clear_end_of_line (olen);
1659 }
1660
1661 /* Exchange contents between current_frame and new_frame. */
1662 temp = desired_frame->glyphs[vpos];
1663 desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
1664 current_frame->glyphs[vpos] = temp;
1665
1666 /* Exchange charstarts between current_frame and new_frame. */
1667 temp1 = desired_frame->charstarts[vpos];
1668 desired_frame->charstarts[vpos] = current_frame->charstarts[vpos];
1669 current_frame->charstarts[vpos] = temp1;
1670
1671 return;
1672 }
1673
1674 if (!olen)
1675 {
1676 nsp = (must_write_spaces || desired_frame->highlight[vpos])
1677 ? 0 : count_blanks (nbody);
1678 if (nlen > nsp)
1679 {
1680 cursor_to (vpos, nsp);
1681 write_glyphs (nbody + nsp, nlen - nsp);
1682 }
1683
1684 /* Exchange contents between current_frame and new_frame. */
1685 temp = desired_frame->glyphs[vpos];
1686 desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
1687 current_frame->glyphs[vpos] = temp;
1688
1689 /* Exchange charstarts between current_frame and new_frame. */
1690 temp1 = desired_frame->charstarts[vpos];
1691 desired_frame->charstarts[vpos] = current_frame->charstarts[vpos];
1692 current_frame->charstarts[vpos] = temp1;
1693
1694 return;
1695 }
1696
1697 obody[olen] = 1;
1698 save = nbody[nlen];
1699 nbody[nlen] = 0;
1700
1701 /* Compute number of leading blanks in old and new contents. */
1702 osp = count_blanks (obody);
1703 if (!desired_frame->highlight[vpos])
1704 nsp = count_blanks (nbody);
1705 else
1706 nsp = 0;
1707
1708 /* Compute number of matching chars starting with first nonblank. */
1709 begmatch = count_match (obody + osp, nbody + nsp);
1710
1711 /* Spaces in new match implicit space past the end of old. */
1712 /* A bug causing this to be a no-op was fixed in 18.29. */
1713 if (!must_write_spaces && osp + begmatch == olen)
1714 {
1715 np1 = nbody + nsp;
1716 while (np1[begmatch] == SPACEGLYPH)
1717 begmatch++;
1718 }
1719
1720 /* Avoid doing insert/delete char
1721 just cause number of leading spaces differs
1722 when the following text does not match. */
1723 if (begmatch == 0 && osp != nsp)
1724 osp = nsp = min (osp, nsp);
1725
1726 /* Find matching characters at end of line */
1727 op1 = obody + olen;
1728 np1 = nbody + nlen;
1729 op2 = op1 + begmatch - min (olen - osp, nlen - nsp);
1730 while (op1 > op2 && op1[-1] == np1[-1])
1731 {
1732 op1--;
1733 np1--;
1734 }
1735 endmatch = obody + olen - op1;
1736
1737 /* Put correct value back in nbody[nlen].
1738 This is important because direct_output_for_insert
1739 can write into the line at a later point.
1740 If this screws up the zero at the end of the line, re-establish it. */
1741 nbody[nlen] = save;
1742 obody[olen] = 0;
1743
1744 /* tem gets the distance to insert or delete.
1745 endmatch is how many characters we save by doing so.
1746 Is it worth it? */
1747
1748 tem = (nlen - nsp) - (olen - osp);
1749 if (endmatch && tem
1750 && (!char_ins_del_ok || endmatch <= char_ins_del_cost (frame)[tem]))
1751 endmatch = 0;
1752
1753 /* nsp - osp is the distance to insert or delete.
1754 If that is nonzero, begmatch is known to be nonzero also.
1755 begmatch + endmatch is how much we save by doing the ins/del.
1756 Is it worth it? */
1757
1758 if (nsp != osp
1759 && (!char_ins_del_ok
1760 || begmatch + endmatch <= char_ins_del_cost (frame)[nsp - osp]))
1761 {
1762 begmatch = 0;
1763 endmatch = 0;
1764 osp = nsp = min (osp, nsp);
1765 }
1766
1767 /* Now go through the line, inserting, writing and
1768 deleting as appropriate. */
1769
1770 if (osp > nsp)
1771 {
1772 cursor_to (vpos, nsp);
1773 delete_glyphs (osp - nsp);
1774 }
1775 else if (nsp > osp)
1776 {
1777 /* If going to delete chars later in line
1778 and insert earlier in the line,
1779 must delete first to avoid losing data in the insert */
1780 if (endmatch && nlen < olen + nsp - osp)
1781 {
1782 cursor_to (vpos, nlen - endmatch + osp - nsp);
1783 delete_glyphs (olen + nsp - osp - nlen);
1784 olen = nlen - (nsp - osp);
1785 }
1786 cursor_to (vpos, osp);
1787 insert_glyphs ((char *)0, nsp - osp);
1788 }
1789 olen += nsp - osp;
1790
1791 tem = nsp + begmatch + endmatch;
1792 if (nlen != tem || olen != tem)
1793 {
1794 cursor_to (vpos, nsp + begmatch);
1795 if (!endmatch || nlen == olen)
1796 {
1797 /* If new text being written reaches right margin,
1798 there is no need to do clear-to-eol at the end.
1799 (and it would not be safe, since cursor is not
1800 going to be "at the margin" after the text is done) */
1801 if (nlen == FRAME_WIDTH (frame))
1802 olen = 0;
1803 write_glyphs (nbody + nsp + begmatch, nlen - tem);
1804
1805#ifdef obsolete
1806
1807/* the following code loses disastrously if tem == nlen.
1808 Rather than trying to fix that case, I am trying the simpler
1809 solution found above. */
1810
1811 /* If the text reaches to the right margin,
1812 it will lose one way or another (depending on AutoWrap)
1813 to clear to end of line after outputting all the text.
1814 So pause with one character to go and clear the line then. */
1815 if (nlen == FRAME_WIDTH (frame) && fast_clear_end_of_line && olen > nlen)
1816 {
1817 /* endmatch must be zero, and tem must equal nsp + begmatch */
1818 write_glyphs (nbody + tem, nlen - tem - 1);
1819 clear_end_of_line (olen);
1820 olen = 0; /* Don't let it be cleared again later */
1821 write_glyphs (nbody + nlen - 1, 1);
1822 }
1823 else
1824 write_glyphs (nbody + nsp + begmatch, nlen - tem);
1825#endif /* OBSOLETE */
1826
1827 }
1828 else if (nlen > olen)
1829 {
1830 write_glyphs (nbody + nsp + begmatch, olen - tem);
1831 insert_glyphs (nbody + nsp + begmatch + olen - tem, nlen - olen);
1832 olen = nlen;
1833 }
1834 else if (olen > nlen)
1835 {
1836 write_glyphs (nbody + nsp + begmatch, nlen - tem);
1837 delete_glyphs (olen - nlen);
1838 olen = nlen;
1839 }
1840 }
1841
1842 just_erase:
1843 /* If any unerased characters remain after the new line, erase them. */
1844 if (olen > nlen)
1845 {
1846 cursor_to (vpos, nlen);
1847 clear_end_of_line (olen);
1848 }
1849
1850 /* Exchange contents between current_frame and new_frame. */
1851 temp = desired_frame->glyphs[vpos];
1852 desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
1853 current_frame->glyphs[vpos] = temp;
1854
1855 /* Exchange charstarts between current_frame and new_frame. */
1856 temp1 = desired_frame->charstarts[vpos];
1857 desired_frame->charstarts[vpos] = current_frame->charstarts[vpos];
1858 current_frame->charstarts[vpos] = temp1;
1859}
1860\f
1861/* A vector of size NFRAMES + 3 * NBUFFERS + 1, containing the session's
1862 frames, buffers, buffer-read-only flags, and buffer-modified-flags,
1863 and a trailing sentinel (so we don't need to add length checks). */
1864static Lisp_Object frame_and_buffer_state;
1865
1866DEFUN ("frame-or-buffer-changed-p", Fframe_or_buffer_changed_p,
1867 Sframe_or_buffer_changed_p, 0, 0, 0,
1868 "Return non-nil if the frame and buffer state appears to have changed.\n\
1869The state variable is an internal vector containing all frames and buffers,\n\
1870along with the buffers' read-only and modified flags, which allows a fast\n\
1871check to see whether the menu bars might need to be recomputed.\n\
1872If this function returns non-nil, it updates the internal vector to reflect\n\
1873the current state.\n")
1874 ()
1875{
1876 Lisp_Object tail, frame, buf;
1877 Lisp_Object *vecp;
1878 int n;
1879 vecp = XVECTOR (frame_and_buffer_state)->contents;
1880 FOR_EACH_FRAME (tail, frame)
1881 if (!EQ (*vecp++, frame))
1882 goto changed;
1883 for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr)
1884 {
1885 buf = XCONS (XCONS (tail)->car)->cdr;
1886 if (!EQ (*vecp++, buf))
1887 goto changed;
1888 if (!EQ (*vecp++, XBUFFER (buf)->read_only))
1889 goto changed;
1890 if (!EQ (*vecp++, Fbuffer_modified_p (buf)))
1891 goto changed;
1892 }
1893 return Qnil;
1894 changed:
1895 n = 1;
1896 FOR_EACH_FRAME (tail, frame)
1897 n++;
1898 for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr)
1899 n += 3;
1900 frame_and_buffer_state = Fmake_vector (make_number (n), Qlambda);
1901 vecp = XVECTOR (frame_and_buffer_state)->contents;
1902 FOR_EACH_FRAME (tail, frame)
1903 *vecp++ = frame;
1904 for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr)
1905 {
1906 buf = XCONS (XCONS (tail)->car)->cdr;
1907 *vecp++ = buf;
1908 *vecp++ = XBUFFER (buf)->read_only;
1909 *vecp++ = Fbuffer_modified_p (buf);
1910 }
1911 return Qt;
1912}
1913\f
1914DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
1915 1, 1, "FOpen termscript file: ",
1916 "Start writing all terminal output to FILE as well as the terminal.\n\
1917FILE = nil means just close any termscript file currently open.")
1918 (file)
1919 Lisp_Object file;
1920{
1921 if (termscript != 0) fclose (termscript);
1922 termscript = 0;
1923
1924 if (! NILP (file))
1925 {
1926 file = Fexpand_file_name (file, Qnil);
1927 termscript = fopen (XSTRING (file)->data, "w");
1928 if (termscript == 0)
1929 report_file_error ("Opening termscript", Fcons (file, Qnil));
1930 }
1931 return Qnil;
1932}
1933\f
1934
1935#ifdef SIGWINCH
1936SIGTYPE
1937window_change_signal ()
1938{
1939 int width, height;
1940 extern int errno;
1941 int old_errno = errno;
1942
1943 get_frame_size (&width, &height);
1944
1945 /* The frame size change obviously applies to a termcap-controlled
1946 frame. Find such a frame in the list, and assume it's the only
1947 one (since the redisplay code always writes to stdout, not a
1948 FILE * specified in the frame structure). Record the new size,
1949 but don't reallocate the data structures now. Let that be done
1950 later outside of the signal handler. */
1951
1952 {
1953 Lisp_Object tail, frame;
1954
1955 FOR_EACH_FRAME (tail, frame)
1956 {
1957 if (FRAME_TERMCAP_P (XFRAME (frame)))
1958 {
1959 change_frame_size (XFRAME (frame), height, width, 0, 1);
1960 break;
1961 }
1962 }
1963 }
1964
1965 signal (SIGWINCH, window_change_signal);
1966 errno = old_errno;
1967}
1968#endif /* SIGWINCH */
1969
1970
1971/* Do any change in frame size that was requested by a signal. */
1972
1973do_pending_window_change ()
1974{
1975 /* If window_change_signal should have run before, run it now. */
1976 while (delayed_size_change)
1977 {
1978 Lisp_Object tail, frame;
1979
1980 delayed_size_change = 0;
1981
1982 FOR_EACH_FRAME (tail, frame)
1983 {
1984 FRAME_PTR f = XFRAME (frame);
1985
1986 int height = FRAME_NEW_HEIGHT (f);
1987 int width = FRAME_NEW_WIDTH (f);
1988
1989 if (height != 0 || width != 0)
1990 change_frame_size (f, height, width, 0, 0);
1991 }
1992 }
1993}
1994
1995
1996/* Change the frame height and/or width. Values may be given as zero to
1997 indicate no change is to take place.
1998
1999 If DELAY is non-zero, then assume we're being called from a signal
2000 handler, and queue the change for later - perhaps the next
2001 redisplay. Since this tries to resize windows, we can't call it
2002 from a signal handler. */
2003
2004change_frame_size (frame, newheight, newwidth, pretend, delay)
2005 register FRAME_PTR frame;
2006 int newheight, newwidth, pretend;
2007{
2008 /* If we can't deal with the change now, queue it for later. */
2009 if (delay)
2010 {
2011 FRAME_NEW_HEIGHT (frame) = newheight;
2012 FRAME_NEW_WIDTH (frame) = newwidth;
2013 delayed_size_change = 1;
2014 return;
2015 }
2016
2017 /* This size-change overrides any pending one for this frame. */
2018 FRAME_NEW_HEIGHT (frame) = 0;
2019 FRAME_NEW_WIDTH (frame) = 0;
2020
2021 /* If an argument is zero, set it to the current value. */
2022 newheight || (newheight = FRAME_HEIGHT (frame));
2023 newwidth || (newwidth = FRAME_WIDTH (frame));
2024
2025 /* Round up to the smallest acceptable size. */
2026 check_frame_size (frame, &newheight, &newwidth);
2027
2028 /* If we're not changing the frame size, quit now. */
2029 if (newheight == FRAME_HEIGHT (frame)
2030 && newwidth == FRAME_WIDTH (frame))
2031 return;
2032
2033 if (newheight != FRAME_HEIGHT (frame))
2034 {
2035 if (FRAME_HAS_MINIBUF_P (frame)
2036 && ! FRAME_MINIBUF_ONLY_P (frame))
2037 {
2038 /* Frame has both root and minibuffer. */
2039 set_window_height (FRAME_ROOT_WINDOW (frame),
2040 newheight - 1 - FRAME_MENU_BAR_LINES (frame), 0);
2041 XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (frame))->top)
2042 = newheight - 1;
2043 set_window_height (FRAME_MINIBUF_WINDOW (frame), 1, 0);
2044 }
2045 else
2046 /* Frame has just one top-level window. */
2047 set_window_height (FRAME_ROOT_WINDOW (frame),
2048 newheight - FRAME_MENU_BAR_LINES (frame), 0);
2049
2050 if (FRAME_TERMCAP_P (frame) && !pretend)
2051 FrameRows = newheight;
2052
2053#if 0
2054 if (frame->output_method == output_termcap)
2055 {
2056 frame_height = newheight;
2057 if (!pretend)
2058 FrameRows = newheight;
2059 }
2060#endif
2061 }
2062
2063 if (newwidth != FRAME_WIDTH (frame))
2064 {
2065 set_window_width (FRAME_ROOT_WINDOW (frame), newwidth, 0);
2066 if (FRAME_HAS_MINIBUF_P (frame))
2067 set_window_width (FRAME_MINIBUF_WINDOW (frame), newwidth, 0);
2068
2069 if (FRAME_TERMCAP_P (frame) && !pretend)
2070 FrameCols = newwidth;
2071#if 0
2072 if (frame->output_method == output_termcap)
2073 {
2074 frame_width = newwidth;
2075 if (!pretend)
2076 FrameCols = newwidth;
2077 }
2078#endif
2079 }
2080
2081 FRAME_HEIGHT (frame) = newheight;
2082 FRAME_WIDTH (frame) = newwidth;
2083
2084 if (FRAME_CURSOR_X (frame) >= FRAME_WIDTH (frame))
2085 FRAME_CURSOR_X (frame) = FRAME_WIDTH (frame) - 1;
2086 if (FRAME_CURSOR_Y (frame) >= FRAME_HEIGHT (frame))
2087 FRAME_CURSOR_Y (frame) = FRAME_HEIGHT (frame) - 1;
2088
2089 remake_frame_glyphs (frame);
2090 calculate_costs (frame);
2091}
2092\f
2093DEFUN ("send-string-to-terminal", Fsend_string_to_terminal,
2094 Ssend_string_to_terminal, 1, 1, 0,
2095 "Send STRING to the terminal without alteration.\n\
2096Control characters in STRING will have terminal-dependent effects.")
2097 (str)
2098 Lisp_Object str;
2099{
2100 CHECK_STRING (str, 0);
2101 fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, stdout);
2102 fflush (stdout);
2103 if (termscript)
2104 {
2105 fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, termscript);
2106 fflush (termscript);
2107 }
2108 return Qnil;
2109}
2110
2111DEFUN ("ding", Fding, Sding, 0, 1, 0,
2112 "Beep, or flash the screen.\n\
2113Also, unless an argument is given,\n\
2114terminate any keyboard macro currently executing.")
2115 (arg)
2116 Lisp_Object arg;
2117{
2118 if (!NILP (arg))
2119 {
2120 if (noninteractive)
2121 putchar (07);
2122 else
2123 ring_bell ();
2124 fflush (stdout);
2125 }
2126 else
2127 bitch_at_user ();
2128
2129 return Qnil;
2130}
2131
2132bitch_at_user ()
2133{
2134 if (noninteractive)
2135 putchar (07);
2136 else if (!INTERACTIVE) /* Stop executing a keyboard macro. */
2137 error ("Keyboard macro terminated by a command ringing the bell");
2138 else
2139 ring_bell ();
2140 fflush (stdout);
2141}
2142
2143DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 2, 0,
2144 "Pause, without updating display, for SECONDS seconds.\n\
2145SECONDS may be a floating-point value, meaning that you can wait for a\n\
2146fraction of a second. Optional second arg MILLISECONDS specifies an\n\
2147additional wait period, in milliseconds; this may be useful if your\n\
2148Emacs was built without floating point support.\n\
2149\(Not all operating systems support waiting for a fraction of a second.)")
2150 (seconds, milliseconds)
2151 Lisp_Object seconds, milliseconds;
2152{
2153 int sec, usec;
2154
2155 if (NILP (milliseconds))
2156 XSET (milliseconds, Lisp_Int, 0);
2157 else
2158 CHECK_NUMBER (milliseconds, 1);
2159 usec = XINT (milliseconds) * 1000;
2160
2161#ifdef LISP_FLOAT_TYPE
2162 {
2163 double duration = extract_float (seconds);
2164 sec = (int) duration;
2165 usec += (duration - sec) * 1000000;
2166 }
2167#else
2168 CHECK_NUMBER (seconds, 0);
2169 sec = XINT (seconds);
2170#endif
2171
2172#ifndef EMACS_HAS_USECS
2173 if (sec == 0 && usec != 0)
2174 error ("millisecond `sleep-for' not supported on %s", SYSTEM_TYPE);
2175#endif
2176
2177 /* Assure that 0 <= usec < 1000000. */
2178 if (usec < 0)
2179 {
2180 /* We can't rely on the rounding being correct if user is negative. */
2181 if (-1000000 < usec)
2182 sec--, usec += 1000000;
2183 else
2184 sec -= -usec / 1000000, usec = 1000000 - (-usec % 1000000);
2185 }
2186 else
2187 sec += usec / 1000000, usec %= 1000000;
2188
2189 if (sec <= 0)
2190 return Qnil;
2191
2192 {
2193 Lisp_Object zero;
2194
2195 XFASTINT (zero) = 0;
2196 wait_reading_process_input (sec, usec, zero, 0);
2197 }
2198
2199 /* We should always have wait_reading_process_input; we have a dummy
2200 implementation for systems which don't support subprocesses. */
2201#if 0
2202 /* No wait_reading_process_input */
2203 immediate_quit = 1;
2204 QUIT;
2205
2206#ifdef VMS
2207 sys_sleep (sec);
2208#else /* not VMS */
2209/* The reason this is done this way
2210 (rather than defined (H_S) && defined (H_T))
2211 is because the VMS preprocessor doesn't grok `defined' */
2212#ifdef HAVE_SELECT
2213 EMACS_GET_TIME (end_time);
2214 EMACS_SET_SECS_USECS (timeout, sec, usec);
2215 EMACS_ADD_TIME (end_time, end_time, timeout);
2216
2217 while (1)
2218 {
2219 EMACS_GET_TIME (timeout);
2220 EMACS_SUB_TIME (timeout, end_time, timeout);
2221 if (EMACS_TIME_NEG_P (timeout)
2222 || !select (1, 0, 0, 0, &timeout))
2223 break;
2224 }
2225#else /* not HAVE_SELECT */
2226 sleep (sec);
2227#endif /* HAVE_SELECT */
2228#endif /* not VMS */
2229
2230 immediate_quit = 0;
2231#endif /* no subprocesses */
2232
2233 return Qnil;
2234}
2235
2236/* This is just like wait_reading_process_input, except that
2237 it does the redisplay.
2238
2239 It's also much like Fsit_for, except that it can be used for
2240 waiting for input as well. One differnce is that sit_for
2241 does not call prepare_menu_bars; Fsit_for does call that. */
2242
2243Lisp_Object
2244sit_for (sec, usec, reading, display)
2245 int sec, usec, reading, display;
2246{
2247 Lisp_Object read_kbd;
2248
2249 if (detect_input_pending ())
2250 return Qnil;
2251
2252 if (display)
2253 redisplay_preserve_echo_area ();
2254
2255 if (sec == 0 && usec == 0)
2256 return Qt;
2257
2258#ifdef SIGIO
2259 gobble_input (0);
2260#endif
2261
2262 XSET (read_kbd, Lisp_Int, reading ? -1 : 1);
2263 wait_reading_process_input (sec, usec, read_kbd, display);
2264
2265
2266 /* wait_reading_process_input should always be available now; it is
2267 simulated in a simple way on systems that don't support
2268 subprocesses. */
2269#if 0
2270 /* No wait_reading_process_input available. */
2271 immediate_quit = 1;
2272 QUIT;
2273
2274 waitchannels = 1;
2275#ifdef VMS
2276 input_wait_timeout (XINT (arg));
2277#else /* not VMS */
2278#ifndef HAVE_TIMEVAL
2279 timeout_sec = sec;
2280 select (1, &waitchannels, 0, 0, &timeout_sec);
2281#else /* HAVE_TIMEVAL */
2282 timeout.tv_sec = sec;
2283 timeout.tv_usec = usec;
2284 select (1, &waitchannels, 0, 0, &timeout);
2285#endif /* HAVE_TIMEVAL */
2286#endif /* not VMS */
2287
2288 immediate_quit = 0;
2289#endif
2290
2291 return detect_input_pending () ? Qnil : Qt;
2292}
2293
2294DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 3, 0,
2295 "Perform redisplay, then wait for SECONDS seconds or until input is available.\n\
2296SECONDS may be a floating-point value, meaning that you can wait for a\n\
2297fraction of a second. Optional second arg MILLISECONDS specifies an\n\
2298additional wait period, in milliseconds; this may be useful if your\n\
2299Emacs was built without floating point support.\n\
2300\(Not all operating systems support waiting for a fraction of a second.)\n\
2301Optional third arg non-nil means don't redisplay, just wait for input.\n\
2302Redisplay is preempted as always if input arrives, and does not happen\n\
2303if input is available before it starts.\n\
2304Value is t if waited the full time with no input arriving.")
2305 (seconds, milliseconds, nodisp)
2306 Lisp_Object seconds, milliseconds, nodisp;
2307{
2308 int sec, usec;
2309
2310 if (NILP (milliseconds))
2311 XSET (milliseconds, Lisp_Int, 0);
2312 else
2313 CHECK_NUMBER (milliseconds, 1);
2314 usec = XINT (milliseconds) * 1000;
2315
2316#ifdef LISP_FLOAT_TYPE
2317 {
2318 double duration = extract_float (seconds);
2319 sec = (int) duration;
2320 usec += (duration - sec) * 1000000;
2321 }
2322#else
2323 CHECK_NUMBER (seconds, 0);
2324 sec = XINT (seconds);
2325#endif
2326
2327#ifndef EMACS_HAS_USECS
2328 if (usec != 0 && sec == 0)
2329 error ("millisecond `sit-for' not supported on %s", SYSTEM_TYPE);
2330#endif
2331
2332 if (NILP (nodisp))
2333 prepare_menu_bars ();
2334 return sit_for (sec, usec, 0, NILP (nodisp));
2335}
2336\f
2337char *terminal_type;
2338
2339/* Initialization done when Emacs fork is started, before doing stty. */
2340/* Determine terminal type and set terminal_driver */
2341/* Then invoke its decoding routine to set up variables
2342 in the terminal package */
2343
2344init_display ()
2345{
2346#ifdef HAVE_X_WINDOWS
2347 extern int display_arg;
2348#endif
2349
2350 meta_key = 0;
2351 inverse_video = 0;
2352 cursor_in_echo_area = 0;
2353 terminal_type = (char *) 0;
2354
2355 /* Now is the time to initialize this; it's used by init_sys_modes
2356 during startup. */
2357 Vwindow_system = Qnil;
2358
2359 /* If the user wants to use a window system, we shouldn't bother
2360 initializing the terminal. This is especially important when the
2361 terminal is so dumb that emacs gives up before and doesn't bother
2362 using the window system.
2363
2364 If the DISPLAY environment variable is set, try to use X, and die
2365 with an error message if that doesn't work. */
2366
2367#ifdef HAVE_X_WINDOWS
2368 if (! display_arg)
2369 {
2370#ifdef VMS
2371 display_arg = (getenv ("DECW$DISPLAY") != 0);
2372#else
2373 display_arg = (getenv ("DISPLAY") != 0);
2374#endif
2375 }
2376
2377 if (!inhibit_window_system && display_arg)
2378 {
2379 Vwindow_system = intern ("x");
2380#ifdef HAVE_X11
2381 Vwindow_system_version = make_number (11);
2382#else
2383 Vwindow_system_version = make_number (10);
2384#endif
2385 return;
2386 }
2387#endif /* HAVE_X_WINDOWS */
2388
2389 /* If no window system has been specified, try to use the terminal. */
2390 if (! isatty (0))
2391 {
2392 fprintf (stderr, "emacs: standard input is not a tty\n");
2393 exit (1);
2394 }
2395
2396 /* Look at the TERM variable */
2397 terminal_type = (char *) getenv ("TERM");
2398 if (!terminal_type)
2399 {
2400#ifdef VMS
2401 fprintf (stderr, "Please specify your terminal type.\n\
2402For types defined in VMS, use set term /device=TYPE.\n\
2403For types not defined in VMS, use define emacs_term \"TYPE\".\n\
2404\(The quotation marks are necessary since terminal types are lower case.)\n");
2405#else
2406 fprintf (stderr, "Please set the environment variable TERM; see tset(1).\n");
2407#endif
2408 exit (1);
2409 }
2410
2411#ifdef VMS
2412 /* VMS DCL tends to upcase things, so downcase term type.
2413 Hardly any uppercase letters in terminal types; should be none. */
2414 {
2415 char *new = (char *) xmalloc (strlen (terminal_type) + 1);
2416 char *p;
2417
2418 strcpy (new, terminal_type);
2419
2420 for (p = new; *p; p++)
2421 if (isupper (*p))
2422 *p = tolower (*p);
2423
2424 terminal_type = new;
2425 }
2426#endif
2427
2428 term_init (terminal_type);
2429
2430 remake_frame_glyphs (selected_frame);
2431 calculate_costs (selected_frame);
2432
2433 /* X and Y coordinates of the cursor between updates. */
2434 FRAME_CURSOR_X (selected_frame) = 0;
2435 FRAME_CURSOR_Y (selected_frame) = 0;
2436
2437#ifdef SIGWINCH
2438#ifndef CANNOT_DUMP
2439 if (initialized)
2440#endif /* CANNOT_DUMP */
2441 signal (SIGWINCH, window_change_signal);
2442#endif /* SIGWINCH */
2443}
2444\f
2445syms_of_display ()
2446{
2447#ifdef MULTI_FRAME
2448 defsubr (&Sredraw_frame);
2449#endif
2450 defsubr (&Sredraw_display);
2451 defsubr (&Sframe_or_buffer_changed_p);
2452 defsubr (&Sopen_termscript);
2453 defsubr (&Sding);
2454 defsubr (&Ssit_for);
2455 defsubr (&Ssleep_for);
2456 defsubr (&Ssend_string_to_terminal);
2457
2458 frame_and_buffer_state = Fmake_vector (make_number (1), Qlambda);
2459 staticpro (&frame_and_buffer_state);
2460
2461 DEFVAR_INT ("baud-rate", &baud_rate,
2462 "The output baud rate of the terminal.\n\
2463On most systems, changing this value will affect the amount of padding\n\
2464and the other strategic decisions made during redisplay.");
2465 DEFVAR_BOOL ("inverse-video", &inverse_video,
2466 "*Non-nil means invert the entire frame display.\n\
2467This means everything is in inverse video which otherwise would not be.");
2468 DEFVAR_BOOL ("visible-bell", &visible_bell,
2469 "*Non-nil means try to flash the frame to represent a bell.");
2470 DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter,
2471 "*Non-nil means no need to redraw entire frame after suspending.\n\
2472A non-nil value is useful if the terminal can automatically preserve\n\
2473Emacs's frame display when you reenter Emacs.\n\
2474It is up to you to set this variable if your terminal can do that.");
2475 DEFVAR_LISP ("window-system", &Vwindow_system,
2476 "A symbol naming the window-system under which Emacs is running\n\
2477\(such as `x'), or nil if emacs is running on an ordinary terminal.");
2478 DEFVAR_LISP ("window-system-version", &Vwindow_system_version,
2479 "The version number of the window system in use.\n\
2480For X windows, this is 10 or 11.");
2481 DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area,
2482 "Non-nil means put cursor in minibuffer, at end of any message there.");
2483 DEFVAR_LISP ("glyph-table", &Vglyph_table,
2484 "Table defining how to output a glyph code to the frame.\n\
2485If not nil, this is a vector indexed by glyph code to define the glyph.\n\
2486Each element can be:\n\
2487 integer: a glyph code which this glyph is an alias for.\n\
2488 string: output this glyph using that string (not impl. in X windows).\n\
2489 nil: this glyph mod 256 is char code to output,\n\
2490 and this glyph / 256 is face code for X windows (see `face-id').");
2491 Vglyph_table = Qnil;
2492
2493 DEFVAR_LISP ("standard-display-table", &Vstandard_display_table,
2494 "Display table to use for buffers that specify none.\n\
2495See `buffer-display-table' for more information.");
2496 Vstandard_display_table = Qnil;
2497
2498 /* Initialize `window-system', unless init_display already decided it. */
2499#ifdef CANNOT_DUMP
2500 if (noninteractive)
2501#endif
2502 {
2503 Vwindow_system = Qnil;
2504 Vwindow_system_version = Qnil;
2505 }
2506}