X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/d460af17a8a1a8ff264b22c91a9652d8c45df435..87485d6fc91710d31c0ed046744f5f7a95f11115:/src/dispnew.c diff --git a/src/dispnew.c b/src/dispnew.c index 25eccf9596..eb20a71a28 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1,6 +1,5 @@ /* Updating of data structures for redisplay. - Copyright (C) 1985, 1986, 1987, 1988, 1990, - 1992, 1993 Free Software Foundation, Inc. + Copyright (C) 1985, 86, 87, 88, 93, 94 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -21,15 +20,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include -#include "config.h" +#include + #include #include +#include "lisp.h" #include "termchar.h" #include "termopts.h" #include "termhooks.h" #include "cm.h" -#include "lisp.h" #include "dispextern.h" #include "buffer.h" #include "frame.h" @@ -37,23 +37,40 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "commands.h" #include "disptab.h" #include "indent.h" +#include "intervals.h" #include "systty.h" -#include "systime.h" #ifdef HAVE_X_WINDOWS #include "xterm.h" #endif /* HAVE_X_WINDOWS */ +/* Include systime.h after xterm.h to avoid double inclusion of time.h. */ +#include "systime.h" + +#include + #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) -#ifndef PENDING_OUTPUT_COUNT /* Get number of chars of output now in the buffer of a stdio stream. This ought to be built in in stdio, but it isn't. Some s- files override this because their stdio internals differ. */ +#ifdef __GNU_LIBRARY__ +/* The s- file might have overridden the definition with one that works for + the system's C library. But we are using the GNU C library, so this is + the right definition for every system. */ +#ifdef GNU_LIBRARY_PENDING_OUTPUT_COUNT +#define PENDING_OUTPUT_COUNT GNU_LIBRARY_PENDING_OUTPUT_COUNT +#else +#undef PENDING_OUTPUT_COUNT +#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->__bufp - (FILE)->__buffer) +#endif +#else /* not __GNU_LIBRARY__ */ +#ifndef PENDING_OUTPUT_COUNT #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base) #endif +#endif /* Nonzero upon entry to redisplay means do not assume anything about current contents of actual terminal frame; clear and redraw it. */ @@ -104,20 +121,22 @@ Lisp_Object Vstandard_display_table; int cursor_in_echo_area; /* The currently selected frame. - In a single-frame version, this variable always remains 0. */ + In a single-frame version, this variable always holds the address of + the_only_frame. */ FRAME_PTR selected_frame; /* A frame which is not just a minibuffer, or 0 if there are no such frames. This is usually the most recent such frame that was - selected. In a single-frame version, this variable always remains 0. */ + selected. In a single-frame version, this variable always holds + the address of the_only_frame. */ FRAME_PTR last_nonminibuf_frame; /* In a single-frame version, the information that would otherwise exist inside frame objects lives in the following structure instead. NOTE: the_only_frame is not checked for garbage collection; don't - store collectable objects in any of its fields! + store collectible objects in any of its fields! You're not/The only frame in town/... */ @@ -169,13 +188,13 @@ redraw_frame (f) FRAME_PTR f; { Lisp_Object frame; - XSET (frame, Lisp_Frame, f); + XSETFRAME (frame, f); Fredraw_frame (frame); } #else -DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, "", +DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0, "Clear frame FRAME and output again what is supposed to appear on it.") (frame) Lisp_Object frame; @@ -202,26 +221,26 @@ DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "", Lisp_Object tail, frame; FOR_EACH_FRAME (tail, frame) - /* If we simply redrew all visible frames, whether or not they - were garbaged, then this would make all frames clear and - nredraw whenever a new frame is created or an existing frame - is de-iconified; those events set the global frame_garbaged - flag, to which redisplay responds by calling this function. - - This used to redraw all visible frames; the only advantage of - that approach is that if a frame changes from invisible to - visible without setting its garbaged flag, it still gets - redisplayed. But that should never happen; since invisible - frames are not updated, they should always be marked as - garbaged when they become visible again. If that doesn't - happen, it's a bug in the visibility code, not a bug here. */ - if (FRAME_VISIBLE_P (XFRAME (frame)) - && FRAME_GARBAGED_P (XFRAME (frame))) + if (FRAME_VISIBLE_P (XFRAME (frame))) Fredraw_frame (frame); return Qnil; } +/* This is used when frame_garbaged is set. + Redraw the individual frames marked as garbaged. */ + +void +redraw_garbaged_frames () +{ + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) + if (FRAME_VISIBLE_P (XFRAME (frame)) + && FRAME_GARBAGED_P (XFRAME (frame))) + Fredraw_frame (frame); +} + static struct frame_glyphs * make_frame_glyphs (frame, empty) @@ -231,14 +250,15 @@ make_frame_glyphs (frame, empty) register int i; register width = FRAME_WIDTH (frame); register height = FRAME_HEIGHT (frame); - register struct frame_glyphs *new = - (struct frame_glyphs *) xmalloc (sizeof (struct frame_glyphs)); + register struct frame_glyphs *new + = (struct frame_glyphs *) xmalloc (sizeof (struct frame_glyphs)); SET_GLYPHS_FRAME (new, frame); new->height = height; new->width = width; new->used = (int *) xmalloc (height * sizeof (int)); new->glyphs = (GLYPH **) xmalloc (height * sizeof (GLYPH *)); + new->charstarts = (int **) xmalloc (height * sizeof (int *)); new->highlight = (char *) xmalloc (height * sizeof (char)); new->enable = (char *) xmalloc (height * sizeof (char)); bzero (new->enable, height * sizeof (char)); @@ -260,9 +280,13 @@ make_frame_glyphs (frame, empty) /* Make the buffer used by decode_mode_spec. This buffer is also used as temporary storage when updating the frame. See scroll.c. */ unsigned int total_glyphs = (width + 2) * sizeof (GLYPH); + unsigned int total_charstarts = (width + 2) * sizeof (int); new->total_contents = (GLYPH *) xmalloc (total_glyphs); bzero (new->total_contents, total_glyphs); + + new->total_charstarts = (int *) xmalloc (total_charstarts); + bzero (new->total_charstarts, total_glyphs); } else { @@ -272,37 +296,60 @@ make_frame_glyphs (frame, empty) bzero (new->total_contents, total_glyphs); for (i = 0; i < height; i++) new->glyphs[i] = new->total_contents + i * (width + 2) + 1; + + if (!FRAME_TERMCAP_P (frame)) + { + unsigned int total_charstarts = height * (width + 2) * sizeof (int); + + new->total_charstarts = (int *) xmalloc (total_charstarts); + bzero (new->total_charstarts, total_charstarts); + for (i = 0; i < height; i++) + new->charstarts[i] = new->total_charstarts + i * (width + 2) + 1; + } + else + { + /* Without a window system, we don't really need charstarts. + So use a small amount of space to make enough data structure + to prevent crashes in display_text_line. */ + new->total_charstarts = (int *) xmalloc ((width + 2) * sizeof (int)); + for (i = 0; i < height; i++) + new->charstarts[i] = new->total_charstarts; + } } return new; } -static void +void free_frame_glyphs (frame, glyphs) FRAME_PTR frame; struct frame_glyphs *glyphs; { if (glyphs->total_contents) - free (glyphs->total_contents); - - free (glyphs->used); - free (glyphs->glyphs); - free (glyphs->highlight); - free (glyphs->enable); - free (glyphs->bufp); + xfree (glyphs->total_contents); + if (glyphs->total_charstarts) + xfree (glyphs->total_charstarts); + + xfree (glyphs->used); + xfree (glyphs->glyphs); + xfree (glyphs->highlight); + xfree (glyphs->enable); + xfree (glyphs->bufp); + if (glyphs->charstarts) + xfree (glyphs->charstarts); #ifdef HAVE_X_WINDOWS if (FRAME_X_P (frame)) { - free (glyphs->top_left_x); - free (glyphs->top_left_y); - free (glyphs->pix_width); - free (glyphs->pix_height); - free (glyphs->max_ascent); + xfree (glyphs->top_left_x); + xfree (glyphs->top_left_y); + xfree (glyphs->pix_width); + xfree (glyphs->pix_height); + xfree (glyphs->max_ascent); } #endif - free (glyphs); + xfree (glyphs); } static void @@ -567,13 +614,15 @@ rotate_vector (vector, size, distance) Returns nonzero if done, zero if terminal cannot scroll them. */ int -scroll_frame_lines (frame, from, end, amount) +scroll_frame_lines (frame, from, end, amount, newpos) register FRAME_PTR frame; - int from, end, amount; + int from, end, amount, newpos; { register int i; register struct frame_glyphs *current_frame = FRAME_CURRENT_GLYPHS (frame); + int pos_adjust; + int width = FRAME_WIDTH (frame); if (!line_ins_del_ok) return 0; @@ -594,6 +643,10 @@ scroll_frame_lines (frame, from, end, amount) sizeof (GLYPH *) * (end + amount - from), amount * sizeof (GLYPH *)); + rotate_vector (current_frame->charstarts + from, + sizeof (int *) * (end + amount - from), + amount * sizeof (int *)); + safe_bcopy (current_frame->used + from, current_frame->used + from + amount, (end - from) * sizeof current_frame->used[0]); @@ -606,6 +659,29 @@ scroll_frame_lines (frame, from, end, amount) current_frame->enable + from + amount, (end - from) * sizeof current_frame->enable[0]); + /* Adjust the lines by an amount + that puts the first of them at NEWPOS. */ + pos_adjust = newpos - current_frame->charstarts[from + amount][0]; + + /* Offset each char position in the charstarts lines we moved + by pos_adjust. */ + for (i = from + amount; i < end + amount; i++) + { + int *line = current_frame->charstarts[i]; + int col; + for (col = 0; col < width; col++) + if (line[col] > 0) + line[col] += pos_adjust; + } + for (i = from; i < from + amount; i++) + { + int *line = current_frame->charstarts[i]; + int col; + line[0] = -1; + for (col = 0; col < width; col++) + line[col] = 0; + } + /* Mark the lines made empty by scrolling as enabled, empty and normal video. */ bzero (current_frame->used + from, @@ -615,6 +691,7 @@ scroll_frame_lines (frame, from, end, amount) for (i = from; i < from + amount; i++) { current_frame->glyphs[i][0] = '\0'; + current_frame->charstarts[i][0] = -1; current_frame->enable[i] = 1; } @@ -662,6 +739,10 @@ scroll_frame_lines (frame, from, end, amount) sizeof (GLYPH *) * (end - from - amount), amount * sizeof (GLYPH *)); + rotate_vector (current_frame->charstarts + from + amount, + sizeof (int *) * (end - from - amount), + amount * sizeof (int *)); + safe_bcopy (current_frame->used + from, current_frame->used + from + amount, (end - from) * sizeof current_frame->used[0]); @@ -674,6 +755,29 @@ scroll_frame_lines (frame, from, end, amount) current_frame->enable + from + amount, (end - from) * sizeof current_frame->enable[0]); + /* Adjust the lines by an amount + that puts the first of them at NEWPOS. */ + pos_adjust = newpos - current_frame->charstarts[from + amount][0]; + + /* Offset each char position in the charstarts lines we moved + by pos_adjust. */ + for (i = from + amount; i < end + amount; i++) + { + int *line = current_frame->charstarts[i]; + int col; + for (col = 0; col < width; col++) + if (line[col] > 0) + line[col] += pos_adjust; + } + for (i = end + amount; i < end; i++) + { + int *line = current_frame->charstarts[i]; + int col; + line[0] = -1; + for (col = 0; col < width; col++) + line[col] = 0; + } + /* Mark the lines made empty by scrolling as enabled, empty and normal video. */ bzero (current_frame->used + end + amount, @@ -683,6 +787,7 @@ scroll_frame_lines (frame, from, end, amount) for (i = end + amount; i < end; i++) { current_frame->glyphs[i][0] = '\0'; + current_frame->charstarts[i][0] = 0; current_frame->enable[i] = 1; } @@ -747,7 +852,11 @@ preserve_other_columns (w) int len; bcopy (current_frame->glyphs[vpos], - desired_frame->glyphs[vpos], start); + desired_frame->glyphs[vpos], + start * sizeof (current_frame->glyphs[vpos][0])); + bcopy (current_frame->charstarts[vpos], + desired_frame->charstarts[vpos], + start * sizeof (current_frame->charstarts[vpos][0])); len = min (start, current_frame->used[vpos]); if (desired_frame->used[vpos] < len) desired_frame->used[vpos] = len; @@ -756,11 +865,19 @@ preserve_other_columns (w) && desired_frame->used[vpos] < current_frame->used[vpos]) { while (desired_frame->used[vpos] < end) - desired_frame->glyphs[vpos][desired_frame->used[vpos]++] - = SPACEGLYPH; + { + int used = desired_frame->used[vpos]++; + desired_frame->glyphs[vpos][used] = SPACEGLYPH; + desired_frame->glyphs[vpos][used] = 0; + } bcopy (current_frame->glyphs[vpos] + end, desired_frame->glyphs[vpos] + end, - current_frame->used[vpos] - end); + ((current_frame->used[vpos] - end) + * sizeof (current_frame->glyphs[vpos][0]))); + bcopy (current_frame->charstarts[vpos] + end, + desired_frame->charstarts[vpos] + end, + ((current_frame->used[vpos] - end) + * sizeof (current_frame->charstarts[vpos][0]))); desired_frame->used[vpos] = current_frame->used[vpos]; } } @@ -806,6 +923,89 @@ preserve_my_columns (w) #endif +/* Adjust by ADJUST the charstart values in window W + after vpos VPOS, which counts relative to the frame + (not relative to W itself). */ + +void +adjust_window_charstarts (w, vpos, adjust) + struct window *w; + int vpos; + int adjust; +{ + int left = XFASTINT (w->left); + int top = XFASTINT (w->top); + int right = left + window_internal_width (w); + int bottom = top + window_internal_height (w); + int i; + + for (i = vpos + 1; i < bottom; i++) + { + int *charstart + = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[i]; + int j; + for (j = left; j < right; j++) + if (charstart[j] > 0) + charstart[j] += adjust; + } +} + +/* Check the charstarts values in the area of window W + for internal consistency. We cannot check that they are "right"; + we can only look for something nonsensical. */ + +verify_charstarts (w) + struct window *w; +{ + FRAME_PTR f = XFRAME (WINDOW_FRAME (w)); + int i; + int top = XFASTINT (w->top); + int bottom = top + window_internal_height (w); + int left = XFASTINT (w->left); + int right = left + window_internal_width (w); + int next_line; + int truncate = (XINT (w->hscroll) + || (truncate_partial_width_windows + && (XFASTINT (w->width) < FRAME_WIDTH (f))) + || !NILP (XBUFFER (w->buffer)->truncate_lines)); + + for (i = top; i < bottom; i++) + { + int j; + int last; + int *charstart = FRAME_CURRENT_GLYPHS (f)->charstarts[i]; + + if (i != top) + { + if (truncate) + { + /* If we are truncating lines, allow a jump + in charstarts from one line to the next. */ + if (charstart[left] < next_line) + abort (); + } + else + { + if (charstart[left] != next_line) + abort (); + } + } + + for (j = left; j < right; j++) + if (charstart[j] > 0) + last = charstart[j]; + /* Record where the next line should start. */ + next_line = last; + if (BUF_ZV (XBUFFER (w->buffer)) != last) + { + /* If there's a newline between the two lines, count that. */ + int endchar = *BUF_CHAR_ADDRESS (XBUFFER (w->buffer), last); + if (endchar == '\n') + next_line++; + } + } +} + /* On discovering that the redisplay for a window was no good, cancel the columns of that window, so that when the window is displayed over again get_display_line will not complain. */ @@ -814,8 +1014,8 @@ cancel_my_columns (w) struct window *w; { register int vpos; - register struct frame_glyphs *desired_glyphs = - FRAME_DESIRED_GLYPHS (XFRAME (w->frame)); + register struct frame_glyphs *desired_glyphs + = FRAME_DESIRED_GLYPHS (XFRAME (w->frame)); register int start = XFASTINT (w->left); register int bot = XFASTINT (w->top) + XFASTINT (w->height); @@ -871,16 +1071,40 @@ direct_output_for_insert (g) /* Give up if buffer appears in two places. */ || buffer_shared > 1 +#ifdef USE_TEXT_PROPERTIES + /* Intervals have already been adjusted, point is after the + character that was just inserted. */ + /* Give up if character is invisible. */ + /* Give up if character has a face property. + At the moment we only lose at end of line or end of buffer + and only with faces that have some background */ + /* Instead of wasting time, give up if character has any text properties */ + || ! NILP (Ftext_properties_at (make_number (point - 1), Qnil)) +#endif + /* Give up if w is minibuffer and a message is being displayed there */ || (MINI_WINDOW_P (w) && echo_area_glyphs)) return 0; - current_frame->glyphs[vpos][hpos] = g; + { + int face = 0; +#ifdef HAVE_FACES + int dummy; + + if (FRAME_X_P (frame)) + face = compute_char_face (frame, w, point - 1, -1, -1, &dummy, point, 0); +#endif + current_frame->glyphs[vpos][hpos] = MAKE_GLYPH (frame, g, face); + current_frame->charstarts[vpos][hpos] = point - 1; + /* Record the entry for after the newly inserted character. */ + current_frame->charstarts[vpos][hpos + 1] = point; + adjust_window_charstarts (w, vpos, 1); + } unchanged_modified = MODIFF; beg_unchanged = GPT - BEG; - XFASTINT (w->last_point) = point; - XFASTINT (w->last_point_x) = hpos; - XFASTINT (w->last_modified) = MODIFF; + XSETFASTINT (w->last_point, point); + XSETFASTINT (w->last_point_x, hpos); + XSETFASTINT (w->last_modified, MODIFF); reassert_line_highlight (0, vpos); write_glyphs (¤t_frame->glyphs[vpos][hpos], 1); @@ -901,6 +1125,12 @@ direct_output_forward_char (n) { register FRAME_PTR frame = selected_frame; register struct window *w = XWINDOW (selected_window); + Lisp_Object position; + int hpos = FRAME_CURSOR_X (frame); + + /* Give up if in truncated text at end of line. */ + if (hpos >= XFASTINT (w->left) + window_internal_width (w) - 1) + return 0; /* Avoid losing if cursor is in invisible text off left margin or about to go off either side of window. */ @@ -910,12 +1140,36 @@ direct_output_forward_char (n) && (FRAME_CURSOR_X (frame) + 1 >= window_internal_width (w) - 1)) || cursor_in_echo_area) return 0; + + /* Can't use direct output if highlighting a region. */ + if (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active)) + return 0; + +#ifdef USE_TEXT_PROPERTIES + /* Don't use direct output next to an invisible character + since we might need to do something special. */ + + XSETFASTINT (position, point); + if (XFASTINT (position) < ZV + && ! NILP (Fget_char_property (position, + Qinvisible, + selected_window))) + return 0; + + XSETFASTINT (position, point - 1); + if (XFASTINT (position) >= BEGV + && ! NILP (Fget_char_property (position, + Qinvisible, + selected_window))) + return 0; +#endif FRAME_CURSOR_X (frame) += n; - XFASTINT (w->last_point_x) = FRAME_CURSOR_X (frame); - XFASTINT (w->last_point) = point; + XSETFASTINT (w->last_point_x, FRAME_CURSOR_X (frame)); + XSETFASTINT (w->last_point, point); cursor_to (FRAME_CURSOR_Y (frame), FRAME_CURSOR_X (frame)); fflush (stdout); + return 1; } @@ -931,8 +1185,8 @@ update_frame (f, force, inhibit_hairy_id) int force; int inhibit_hairy_id; { - register struct frame_glyphs *current_frame = FRAME_CURRENT_GLYPHS (f); - register struct frame_glyphs *desired_frame = FRAME_DESIRED_GLYPHS (f); + register struct frame_glyphs *current_frame; + register struct frame_glyphs *desired_frame = 0; register int i; int pause; int preempt_count = baud_rate / 2400 + 1; @@ -941,6 +1195,9 @@ update_frame (f, force, inhibit_hairy_id) register int downto, leftmost; #endif + if (preempt_count <= 0) + preempt_count = 1; + if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */ detect_input_pending (); @@ -955,6 +1212,10 @@ update_frame (f, force, inhibit_hairy_id) if (!line_ins_del_ok) inhibit_hairy_id = 1; + /* These are separate to avoid a possible bug in the AIX C compiler. */ + current_frame = FRAME_CURRENT_GLYPHS (f); + desired_frame = FRAME_DESIRED_GLYPHS (f); + /* See if any of the desired lines are enabled; don't compute for i/d line if just want cursor motion. */ for (i = 0; i < FRAME_HEIGHT (f); i++) @@ -1011,7 +1272,8 @@ update_frame (f, force, inhibit_hairy_id) outq = PENDING_OUTPUT_COUNT (stdout); #endif outq *= 10; - sleep (outq / baud_rate); + if (baud_rate <= outq && baud_rate > 0) + sleep (outq / baud_rate); } } if ((i - 1) % preempt_count == 0) @@ -1091,7 +1353,7 @@ update_frame (f, force, inhibit_hairy_id) if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */ display_completed = !pause; - bzero (desired_frame->enable, FRAME_HEIGHT (f)); + bzero (FRAME_DESIRED_GLYPHS (f)->enable, FRAME_HEIGHT (f)); return pause; } @@ -1194,6 +1456,7 @@ buffer_posn_from_coords (window, col, line) struct window *window; int col, line; { + int hscroll = XINT (window->hscroll); int window_left = XFASTINT (window->left); /* The actual width of the window is window->width less one for the @@ -1216,9 +1479,10 @@ buffer_posn_from_coords (window, col, line) sure I will keep it. */ posn = compute_motion (startp, 0, (window == XWINDOW (minibuf_window) && startp == 1 - ? minibuf_prompt_width : 0), - ZV, line, col - window_left, - window_width, XINT (window->hscroll), 0); + ? minibuf_prompt_width : 0) + + (hscroll ? 1 - hscroll : 0), + ZV, line, col, + window_width, hscroll, 0, window); current_buffer = old_current_buffer; @@ -1262,6 +1526,7 @@ update_line (frame, vpos) int vpos; { register GLYPH *obody, *nbody, *op1, *op2, *np1, *temp; + int *temp1; int tem; int osp, nsp, begmatch, endmatch, olen, nlen; int save; @@ -1319,7 +1584,7 @@ update_line (frame, vpos) = current_frame->used[vpos] * FONT_WIDTH (frame->display.x->font); current_frame->pix_height[vpos] - = FONT_HEIGHT (frame->display.x->font); + = frame->display.x->line_height; } #endif /* HAVE_X_WINDOWS */ @@ -1356,6 +1621,25 @@ update_line (frame, vpos) { int i,j; +#if 0 + if (FRAME_X_P (frame)) + { + /* Under X, erase everything we are going to rewrite, + and rewrite everything from the first char that's changed. + This is part of supporting fonts like Courier + whose chars can overlap outside the char width. */ + for (i = 0; i < nlen; i++) + if (i >= olen || nbody[i] != obody[i]) + break; + + cursor_to (vpos, i); + if (i != olen) + clear_end_of_line (olen); + write_glyphs (nbody + i, nlen - i); + } + else + {} +#endif /* 0 */ for (i = 0; i < nlen; i++) { if (i >= olen || nbody[i] != obody[i]) /* A non-matching char. */ @@ -1385,6 +1669,11 @@ update_line (frame, vpos) desired_frame->glyphs[vpos] = current_frame->glyphs[vpos]; current_frame->glyphs[vpos] = temp; + /* Exchange charstarts between current_frame and new_frame. */ + temp1 = desired_frame->charstarts[vpos]; + desired_frame->charstarts[vpos] = current_frame->charstarts[vpos]; + current_frame->charstarts[vpos] = temp1; + return; } @@ -1403,6 +1692,11 @@ update_line (frame, vpos) desired_frame->glyphs[vpos] = current_frame->glyphs[vpos]; current_frame->glyphs[vpos] = temp; + /* Exchange charstarts between current_frame and new_frame. */ + temp1 = desired_frame->charstarts[vpos]; + desired_frame->charstarts[vpos] = current_frame->charstarts[vpos]; + current_frame->charstarts[vpos] = temp1; + return; } @@ -1563,6 +1857,70 @@ update_line (frame, vpos) temp = desired_frame->glyphs[vpos]; desired_frame->glyphs[vpos] = current_frame->glyphs[vpos]; current_frame->glyphs[vpos] = temp; + + /* Exchange charstarts between current_frame and new_frame. */ + temp1 = desired_frame->charstarts[vpos]; + desired_frame->charstarts[vpos] = current_frame->charstarts[vpos]; + current_frame->charstarts[vpos] = temp1; +} + +/* A vector of size >= NFRAMES + 3 * NBUFFERS + 1, containing the session's + frames, buffers, buffer-read-only flags, and buffer-modified-flags, + and a trailing sentinel (so we don't need to add length checks). */ +static Lisp_Object frame_and_buffer_state; + +DEFUN ("frame-or-buffer-changed-p", Fframe_or_buffer_changed_p, + Sframe_or_buffer_changed_p, 0, 0, 0, + "Return non-nil if the frame and buffer state appears to have changed.\n\ +The state variable is an internal vector containing all frames and buffers,\n\ +along with the buffers' read-only and modified flags, which allows a fast\n\ +check to see whether the menu bars might need to be recomputed.\n\ +If this function returns non-nil, it updates the internal vector to reflect\n\ +the current state.\n") + () +{ + Lisp_Object tail, frame, buf; + Lisp_Object *vecp; + int n; + vecp = XVECTOR (frame_and_buffer_state)->contents; + FOR_EACH_FRAME (tail, frame) + if (!EQ (*vecp++, frame)) + goto changed; + for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr) + { + buf = XCONS (XCONS (tail)->car)->cdr; + if (!EQ (*vecp++, buf)) + goto changed; + if (!EQ (*vecp++, XBUFFER (buf)->read_only)) + goto changed; + if (!EQ (*vecp++, Fbuffer_modified_p (buf))) + goto changed; + } + return Qnil; + changed: + n = 1; + FOR_EACH_FRAME (tail, frame) + n++; + for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr) + n += 3; + /* Reallocate the vector if it's grown, or if it's shrunk a lot. */ + if (n > XVECTOR (frame_and_buffer_state)->size + || n < XVECTOR (frame_and_buffer_state)->size / 2) + frame_and_buffer_state = Fmake_vector (make_number (n), Qlambda); + vecp = XVECTOR (frame_and_buffer_state)->contents; + FOR_EACH_FRAME (tail, frame) + *vecp++ = frame; + for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr) + { + buf = XCONS (XCONS (tail)->car)->cdr; + *vecp++ = buf; + *vecp++ = XBUFFER (buf)->read_only; + *vecp++ = Fbuffer_modified_p (buf); + } + /* If we left any slack in the vector, fill it up now. */ + for (; n < XVECTOR (frame_and_buffer_state)->size; ++n) + *vecp++ = Qlambda; + return Qt; } DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript, @@ -1639,11 +1997,8 @@ do_pending_window_change () int height = FRAME_NEW_HEIGHT (f); int width = FRAME_NEW_WIDTH (f); - - FRAME_NEW_HEIGHT (f) = 0; - FRAME_NEW_WIDTH (f) = 0; - if (height != 0) + if (height != 0 || width != 0) change_frame_size (f, height, width, 0, 0); } } @@ -1675,7 +2030,7 @@ change_frame_size (frame, newheight, newwidth, pretend, delay) FRAME_NEW_HEIGHT (frame) = 0; FRAME_NEW_WIDTH (frame) = 0; - /* If an arguments is zero, set it to the current value. */ + /* If an argument is zero, set it to the current value. */ newheight || (newheight = FRAME_HEIGHT (frame)); newwidth || (newwidth = FRAME_WIDTH (frame)); @@ -1695,8 +2050,8 @@ change_frame_size (frame, newheight, newwidth, pretend, delay) /* Frame has both root and minibuffer. */ set_window_height (FRAME_ROOT_WINDOW (frame), newheight - 1 - FRAME_MENU_BAR_LINES (frame), 0); - XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (frame))->top) - = newheight - 1; + XSETFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (frame))->top, + newheight - 1); set_window_height (FRAME_MINIBUF_WINDOW (frame), 1, 0); } else @@ -1737,7 +2092,12 @@ change_frame_size (frame, newheight, newwidth, pretend, delay) FRAME_HEIGHT (frame) = newheight; FRAME_WIDTH (frame) = newwidth; - + + if (FRAME_CURSOR_X (frame) >= FRAME_WIDTH (frame)) + FRAME_CURSOR_X (frame) = FRAME_WIDTH (frame) - 1; + if (FRAME_CURSOR_Y (frame) >= FRAME_HEIGHT (frame)) + FRAME_CURSOR_Y (frame) = FRAME_HEIGHT (frame) - 1; + remake_frame_glyphs (frame); calculate_costs (frame); } @@ -1794,22 +2154,32 @@ bitch_at_user () DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 2, 0, "Pause, without updating display, for SECONDS seconds.\n\ -Optional second arg MILLISECONDS specifies an additional wait period,\n\ -in milliseconds.\n\ -\(Not all operating systems support milliseconds.)") +SECONDS may be a floating-point value, meaning that you can wait for a\n\ +fraction of a second. Optional second arg MILLISECONDS specifies an\n\ +additional wait period, in milliseconds; this may be useful if your\n\ +Emacs was built without floating point support.\n\ +\(Not all operating systems support waiting for a fraction of a second.)") (seconds, milliseconds) Lisp_Object seconds, milliseconds; { int sec, usec; - CHECK_NUMBER (seconds, 0); - sec = XINT (seconds); - if (NILP (milliseconds)) - XSET (milliseconds, Lisp_Int, 0); + XSETINT (milliseconds, 0); else CHECK_NUMBER (milliseconds, 1); - usec = XINT (milliseconds); + usec = XINT (milliseconds) * 1000; + +#ifdef LISP_FLOAT_TYPE + { + double duration = extract_float (seconds); + sec = (int) duration; + usec += (duration - sec) * 1000000; + } +#else + CHECK_NUMBER (seconds, 0); + sec = XINT (seconds); +#endif #ifndef EMACS_HAS_USECS if (sec == 0 && usec != 0) @@ -1834,7 +2204,7 @@ in milliseconds.\n\ { Lisp_Object zero; - XFASTINT (zero) = 0; + XSETFASTINT (zero, 0); wait_reading_process_input (sec, usec, zero, 0); } @@ -1878,8 +2248,9 @@ in milliseconds.\n\ /* This is just like wait_reading_process_input, except that it does the redisplay. - It's also just like Fsit_for, except that it can be used for - waiting for input as well. */ + It's also much like Fsit_for, except that it can be used for + waiting for input as well. One differnce is that sit_for + does not call prepare_menu_bars; Fsit_for does call that. */ Lisp_Object sit_for (sec, usec, reading, display) @@ -1900,7 +2271,7 @@ sit_for (sec, usec, reading, display) gobble_input (0); #endif - XSET (read_kbd, Lisp_Int, reading ? -1 : 1); + XSETINT (read_kbd, reading ? -1 : 1); wait_reading_process_input (sec, usec, read_kbd, display); @@ -1934,9 +2305,11 @@ sit_for (sec, usec, reading, display) DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 3, 0, "Perform redisplay, then wait for SECONDS seconds or until input is available.\n\ -Optional second arg MILLISECONDS specifies an additional wait period, in\n\ -milliseconds.\n\ -\(Not all operating systems support milliseconds.)\n\ +SECONDS may be a floating-point value, meaning that you can wait for a\n\ +fraction of a second. Optional second arg MILLISECONDS specifies an\n\ +additional wait period, in milliseconds; this may be useful if your\n\ +Emacs was built without floating point support.\n\ +\(Not all operating systems support waiting for a fraction of a second.)\n\ Optional third arg non-nil means don't redisplay, just wait for input.\n\ Redisplay is preempted as always if input arrives, and does not happen\n\ if input is available before it starts.\n\ @@ -1946,20 +2319,30 @@ Value is t if waited the full time with no input arriving.") { int sec, usec; - CHECK_NUMBER (seconds, 0); - sec = XINT (seconds); - if (NILP (milliseconds)) - XSET (milliseconds, Lisp_Int, 0); + XSETINT (milliseconds, 0); else CHECK_NUMBER (milliseconds, 1); - usec = XINT (milliseconds); + usec = XINT (milliseconds) * 1000; + +#ifdef LISP_FLOAT_TYPE + { + double duration = extract_float (seconds); + sec = (int) duration; + usec += (duration - sec) * 1000000; + } +#else + CHECK_NUMBER (seconds, 0); + sec = XINT (seconds); +#endif #ifndef EMACS_HAS_USECS if (usec != 0 && sec == 0) error ("millisecond `sit-for' not supported on %s", SYSTEM_TYPE); #endif + if (NILP (nodisp)) + prepare_menu_bars (); return sit_for (sec, usec, 0, NILP (nodisp)); } @@ -1997,10 +2380,11 @@ init_display () if (! display_arg) { #ifdef VMS - display_arg = getenv ("DECW$DISPLAY"); + display_arg = (getenv ("DECW$DISPLAY") != 0); #else - display_arg = getenv ("DISPLAY"); + display_arg = (getenv ("DISPLAY") != 0); #endif + } if (!inhibit_window_system && display_arg) { @@ -2076,14 +2460,18 @@ syms_of_display () defsubr (&Sredraw_frame); #endif defsubr (&Sredraw_display); + defsubr (&Sframe_or_buffer_changed_p); defsubr (&Sopen_termscript); defsubr (&Sding); defsubr (&Ssit_for); defsubr (&Ssleep_for); defsubr (&Ssend_string_to_terminal); + frame_and_buffer_state = Fmake_vector (make_number (1), Qlambda); + staticpro (&frame_and_buffer_state); + DEFVAR_INT ("baud-rate", &baud_rate, - "The output baud rate of the terminal.\n\ + "*The output baud rate of the terminal.\n\ On most systems, changing this value will affect the amount of padding\n\ and the other strategic decisions made during redisplay."); DEFVAR_BOOL ("inverse-video", &inverse_video, @@ -2111,7 +2499,7 @@ Each element can be:\n\ integer: a glyph code which this glyph is an alias for.\n\ string: output this glyph using that string (not impl. in X windows).\n\ nil: this glyph mod 256 is char code to output,\n\ - and this glyph / 256 is face code for X windows (see `x-set-face')."); + and this glyph / 256 is face code for X windows (see `face-id')."); Vglyph_table = Qnil; DEFVAR_LISP ("standard-display-table", &Vstandard_display_table, @@ -2128,4 +2516,3 @@ See `buffer-display-table' for more information."); Vwindow_system_version = Qnil; } } -