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