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