X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/18160b98ce2ce9f534a4aee6be181788322b6c01..919fa9cbf0b0aabb55af71e54a2050304f4347bf:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index 7f73516266..cbcad61400 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1,5 +1,5 @@ /* Display generation from window structure and buffer text. - Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc. + Copyright (C) 1985, 86, 87, 88, 93, 94 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -35,9 +35,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "termhooks.h" #include "intervals.h" +#ifdef USE_X_TOOLKIT +extern void set_frame_menubar (); +#endif + extern int interrupt_input; extern int command_loop_level; +extern Lisp_Object Qface; + /* Nonzero means print newline before next minibuffer message. */ int noninteractive_need_newline; @@ -79,6 +85,10 @@ char *previous_echo_glyphs; /* Nonzero means truncate lines in all windows less wide than the frame */ int truncate_partial_width_windows; +/* Nonzero means we have more than one non-minibuffer-only frame. + Not guaranteed to be accurate except while parsing frame-title-format. */ +int multiple_frames; + Lisp_Object Vglobal_mode_string; /* Marker for where to display an arrow on top of the buffer text. */ @@ -87,9 +97,17 @@ Lisp_Object Voverlay_arrow_position; /* String to display for the arrow. */ Lisp_Object Voverlay_arrow_string; +/* Like mode-line-format, but for the titlebar on a visible frame. */ +Lisp_Object Vframe_title_format; + +/* Like mode-line-format, but for the titlebar on an iconified frame. */ +Lisp_Object Vicon_title_format; + /* Values of those variables at last redisplay. */ static Lisp_Object last_arrow_position, last_arrow_string; +Lisp_Object Qmenu_bar_update_hook; + /* Nonzero if overlay arrow has been displayed once in this window. */ static int overlay_arrow_seen; @@ -124,6 +142,8 @@ static void echo_area_display (); void mark_window_display_accurate (); static void redisplay_windows (); static void redisplay_window (); +static void update_menu_bars (); +static void update_menu_bar (); static void try_window (); static int try_window_id (); static struct position *display_text_line (); @@ -136,7 +156,7 @@ static void display_menu_bar (); static int display_count_lines (); /* Prompt to display in front of the minibuffer contents */ -char *minibuf_prompt; +Lisp_Object minibuf_prompt; /* Width in columns of current minibuffer prompt. */ int minibuf_prompt_width; @@ -147,6 +167,9 @@ int minibuf_prompt_width; It overrides the minibuf_prompt as well as the buffer. */ char *echo_area_glyphs; +/* This is the length of the message in echo_area_glyphs. */ +int echo_area_glyphs_length; + /* true iff we should redraw the mode lines on the next redisplay */ int update_mode_lines; @@ -180,21 +203,24 @@ int line_number_displayed; /* Maximum buffer size for which to display line numbers. */ int line_number_display_limit; -/* Specify m, a string, as a message in the minibuf. If m is 0, clear out - any existing message, and let the minibuffer text show through. */ +/* Display an echo area message M with a specified length of LEN chars. + The string may include null characters. If m is 0, clear out any + existing message, and let the minibuffer text show through. + Do not pass text that is stored in a Lisp string. */ + void -message1 (m) +message2 (m, len) char *m; + int len; { if (noninteractive) { if (noninteractive_need_newline) putc ('\n', stderr); noninteractive_need_newline = 0; - if (cursor_in_echo_area != 0) - fprintf (stderr, "%s", m); - else - fprintf (stderr, "%s\n", m); + fwrite (m, len, 1, stderr); + if (cursor_in_echo_area == 0) + fprintf (stderr, "\n"); fflush (stderr); } /* A null message buffer means that the frame hasn't really been @@ -214,7 +240,10 @@ message1 (m) #endif if (m) - echo_area_glyphs = m; + { + echo_area_glyphs = m; + echo_area_glyphs_length = len; + } else echo_area_glyphs = previous_echo_glyphs = 0; @@ -222,9 +251,32 @@ message1 (m) echo_area_display (); update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1); do_pending_window_change (); + if (frame_up_to_date_hook != 0 && ! gc_in_progress) + (*frame_up_to_date_hook) (XFRAME (XWINDOW (minibuf_window)->frame)); } } +void +message1 (m) + char *m; +{ + message2 (m, (m ? strlen (m) : 0)); +} + +/* Truncate what will be displayed in the echo area + the next time we display it--but don't redisplay it now. */ + +void +truncate_echo_area (len) + int len; +{ + /* A null message buffer means that the frame hasn't really been + initialized yet. Error messages get reported properly by + cmd_error, so this must be just an informative message; toss it. */ + if (!noninteractive && INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame)) + echo_area_glyphs_length = len; +} + /* Nonzero if FRAME_MESSAGE_BUF (selected_frame) is being used by print; zero if being used by message. */ int message_buf_print; @@ -235,6 +287,7 @@ int message_buf_print; void message (m, a1, a2, a3) char *m; + EMACS_INT a1, a2, a3; { if (noninteractive) { @@ -269,22 +322,21 @@ message (m, a1, a2, a3) { if (m) { - { + int len; #ifdef NO_ARG_ARRAY - int a[3]; - a[0] = a1; - a[1] = a2; - a[2] = a3; + EMACS_INT a[3]; + a[0] = a1; + a[1] = a2; + a[2] = a3; - doprnt (FRAME_MESSAGE_BUF (echo_frame), - FRAME_WIDTH (echo_frame), m, 0, 3, a); + len = doprnt (FRAME_MESSAGE_BUF (echo_frame), + FRAME_WIDTH (echo_frame), m, 0, 3, a); #else - doprnt (FRAME_MESSAGE_BUF (echo_frame), - FRAME_WIDTH (echo_frame), m, 0, 3, &a1); + len = doprnt (FRAME_MESSAGE_BUF (echo_frame), + FRAME_WIDTH (echo_frame), m, 0, 3, &a1); #endif /* NO_ARG_ARRAY */ - } - message1 (FRAME_MESSAGE_BUF (echo_frame)); + message2 (FRAME_MESSAGE_BUF (echo_frame), len); } else message1 (0); @@ -296,6 +348,12 @@ message (m, a1, a2, a3) } } +void +update_echo_area () +{ + message2 (echo_area_glyphs, echo_area_glyphs_length); +} + static void echo_area_display () { @@ -323,7 +381,8 @@ echo_area_display () get_display_line (f, vpos, 0); display_string (XWINDOW (minibuf_window), vpos, echo_area_glyphs ? echo_area_glyphs : "", - 0, 0, 0, FRAME_WIDTH (f)); + echo_area_glyphs ? echo_area_glyphs_length : -1, + 0, 0, 0, 0, FRAME_WIDTH (f)); /* If desired cursor location is on this line, put it at end of text */ if (FRAME_CURSOR_Y (f) == vpos) @@ -338,7 +397,7 @@ echo_area_display () { get_display_line (f, i, 0); display_string (XWINDOW (minibuf_window), vpos, - "", 0, 0, 0, FRAME_WIDTH (f)); + "", 0, 0, 0, 0, 0, FRAME_WIDTH (f)); } } } @@ -350,6 +409,121 @@ echo_area_display () previous_echo_glyphs = echo_area_glyphs; } + +#ifdef HAVE_X_WINDOWS +static char frame_title_buf[512]; +static char *frame_title_ptr; + +static int +store_frame_title (str, mincol, maxcol) + char *str; + int mincol, maxcol; +{ + char *limit; + if (maxcol < 0 || maxcol >= sizeof(frame_title_buf)) + maxcol = sizeof (frame_title_buf); + limit = &frame_title_buf[maxcol]; + while (*str != '\0' && frame_title_ptr < limit) + *frame_title_ptr++ = *str++; + while (frame_title_ptr < &frame_title_buf[mincol]) + *frame_title_ptr++ = ' '; + return frame_title_ptr - frame_title_buf; +} + +static void +x_consider_frame_title (frame) + Lisp_Object frame; +{ + Lisp_Object fmt; + struct buffer *obuf; + int len; + FRAME_PTR f = XFRAME (frame); + + if (!FRAME_X_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name) + return; + multiple_frames = !EQ (Fnext_frame (frame, Qnil), frame); + obuf = current_buffer; + Fset_buffer (XWINDOW (f->selected_window)->buffer); + fmt = (FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format); + frame_title_ptr = frame_title_buf; + len = display_mode_element (XWINDOW (f->selected_window), 0, 0, 0, + 0, sizeof (frame_title_buf), fmt); + frame_title_ptr = 0; + set_buffer_internal (obuf); + /* Set the name only if it's changed. This avoids consing + in the common case where it hasn't. (If it turns out that we've + already wasted too much time by walking through the list with + display_mode_element, then we might need to optimize at a higher + level than this.) */ + if (! STRINGP (f->name) || XSTRING (f->name)->size != len + || bcmp (frame_title_buf, XSTRING (f->name)->data, len) != 0) + x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil); +} +#else +#define frame_title_ptr ((char *)0) +#define store_frame_title(str, mincol, maxcol) 0 +#endif + +/* Prepare for redisplay by updating menu-bar item lists when appropriate. + This can't be done in `redisplay' itself because it can call eval. */ + +void +prepare_menu_bars () +{ + register struct window *w = XWINDOW (selected_window); + int all_windows; + + if (noninteractive) + return; + + /* Set the visible flags for all frames. + Do this before checking for resized or garbaged frames; they want + to know if their frames are visible. + See the comment in frame.h for FRAME_SAMPLE_VISIBILITY. */ + { + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) + FRAME_SAMPLE_VISIBILITY (XFRAME (frame)); + } + + /* Notice any pending interrupt request to change frame size. */ + do_pending_window_change (); + + if (frame_garbaged) + { + redraw_garbaged_frames (); + frame_garbaged = 0; + } + + all_windows = (update_mode_lines || buffer_shared > 1 + || clip_changed || windows_or_buffers_changed); + +#ifdef HAVE_X_WINDOWS + if (windows_or_buffers_changed) + { + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) + if (FRAME_VISIBLE_P (XFRAME (frame)) + || FRAME_ICONIFIED_P (XFRAME (frame))) + x_consider_frame_title (frame); + } +#endif + + /* Update the menu bar item lists, if appropriate. + This has to be done before any actual redisplay + or generation of display lines. */ + if (all_windows) + { + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) + update_menu_bar (XFRAME (frame)); + } + else + update_menu_bar (selected_frame); +} /* Do a frame update, taking possible shortcuts into account. This is the main external entry point for redisplay. @@ -358,14 +532,23 @@ echo_area_display () message is no longer requested, we clear the echo area or bring back the minibuffer if that is in use. - Everyone would like to have a hook here to call eval, - but that cannot be done safely without a lot of changes elsewhere. - This can be called from signal handlers; with alarms set up; + Do not call eval from within this function. + Calls to eval after the call to echo_area_display would confuse + the display_line mechanism and would cause a crash. + Calls to eval before that point will work most of the time, + but can still lose, because this function + can be called from signal handlers; with alarms set up; or with synchronous processes running. - See the function `echo' in keyboard.c. + See Fcall_process; if you called it from here, it could be entered recursively. */ +static int do_verify_charstarts; + +/* Counter is used to clear the face cache + no more than once ever 1000 redisplays. */ +static int clear_face_cache_count; + void redisplay () { @@ -400,16 +583,6 @@ redisplay () frame_garbaged = 0; } - /* Normally the message* functions will have already displayed and - updated the echo area, but the frame may have been trashed, or - the update may have been preempted, so display the echo area - again here. */ - if (echo_area_glyphs || previous_echo_glyphs) - { - echo_area_display (); - must_finish = 1; - } - if (clip_changed || windows_or_buffers_changed) update_mode_lines++; @@ -432,6 +605,16 @@ redisplay () || ! EQ (Voverlay_arrow_string, last_arrow_string)) all_windows = 1, clip_changed = 1; + /* Normally the message* functions will have already displayed and + updated the echo area, but the frame may have been trashed, or + the update may have been preempted, so display the echo area + again here. */ + if (echo_area_glyphs || previous_echo_glyphs) + { + echo_area_display (); + must_finish = 1; + } + /* If showing region, and mark has changed, must redisplay whole window. */ if (((!NILP (Vtransient_mark_mode) && !NILP (XBUFFER (w->buffer)->mark_active)) @@ -450,8 +633,8 @@ redisplay () && current_buffer == XBUFFER (w->buffer) && NILP (w->force_start) /* Point must be on the line that we have info recorded about */ - && point >= tlbufpos - && point <= Z - tlendpos + && PT >= tlbufpos + && PT <= Z - tlendpos /* All text outside that line, including its final newline, must be unchanged */ && (XFASTINT (w->last_modified) >= MODIFF @@ -459,7 +642,7 @@ redisplay () && GPT >= tlbufpos /* If selective display, can't optimize if the changes start at the beginning of the line. */ - && ((XTYPE (current_buffer->selective_display) == Lisp_Int + && ((INTEGERP (current_buffer->selective_display) && XINT (current_buffer->selective_display) > 0 ? (beg_unchanged >= tlbufpos && GPT > tlbufpos) @@ -484,6 +667,30 @@ redisplay () if (cursor_vpos >= 0 && this_line_bufpos && this_line_endpos == tlendpos) { + /* If this is not the window's last line, + we must adjust the charstarts of the lines below. */ + if (this_line_vpos + 1 + < XFASTINT (w->top) + window_internal_height (w)) + { + int left = XFASTINT (w->left); + int *charstart_next_line + = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1]; + int i; + int adjust; + + if (Z - tlendpos == ZV) + /* This line ends at end of (accessible part of) buffer. + There is no newline to count. */ + adjust = Z - tlendpos - charstart_next_line[left]; + else + /* This line ends in a newline. + Must take account of the newline and the rest of the + text that follows. */ + adjust = Z - tlendpos + 1 - charstart_next_line[left]; + + adjust_window_charstarts (w, this_line_vpos, adjust); + } + if (XFASTINT (w->width) != FRAME_WIDTH (XFRAME (WINDOW_FRAME (w)))) preserve_other_columns (w); goto update; @@ -491,7 +698,7 @@ redisplay () else goto cancel; } - else if (point == XFASTINT (w->last_point)) + else if (PT == XFASTINT (w->last_point)) { if (!must_finish) { @@ -507,10 +714,10 @@ redisplay () { pos = *compute_motion (tlbufpos, 0, XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0, - point, 2, - (1 << (SHORTBITS - 1)), + PT, 2, - (1 << (SHORTBITS - 1)), window_internal_width (w) - 1, XINT (w->hscroll), - pos_tab_offset (w, tlbufpos)); + pos_tab_offset (w, tlbufpos), w); if (pos.vpos < 1) { FRAME_CURSOR_X (selected_frame) @@ -529,14 +736,20 @@ redisplay () this_line_bufpos = 0; all_windows |= buffer_shared > 1; + clear_face_cache_count++; + if (all_windows) { Lisp_Object tail, frame; #ifdef HAVE_X_WINDOWS - /* Since we're doing a thorough redisplay, we might as well - recompute all our display faces. */ - clear_face_vector (); + /* Clear the face cache, only when we do a full redisplay + and not too often either. */ + if (clear_face_cache_count > 1000) + { + clear_face_cache (); + clear_face_cache_count = 0; + } #endif /* Recompute # windows showing selected buffer. @@ -587,7 +800,7 @@ update: { FRAME_PTR f; - if (XTYPE (XCONS (tail)->car) != Lisp_Frame) + if (!FRAMEP (XCONS (tail)->car)) continue; f = XFRAME (XCONS (tail)->car); @@ -595,7 +808,11 @@ update: { pause |= update_frame (f, 0, 0); if (!pause) - mark_window_display_accurate (f->root_window, 1); + { + mark_window_display_accurate (f->root_window, 1); + if (frame_up_to_date_hook != 0) + (*frame_up_to_date_hook) (f); + } } } } @@ -611,8 +828,8 @@ update: above call to update_frame would not have caught it. Catch it here. */ { - FRAME_PTR mini_frame = - XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window))); + FRAME_PTR mini_frame + = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window))); if (mini_frame != selected_frame) pause |= update_frame (mini_frame, 0, 0); @@ -650,19 +867,23 @@ update: beg_unchanged = BUF_GPT (b) - BUF_BEG (b); end_unchanged = BUF_Z (b) - BUF_GPT (b); - XFASTINT (w->last_point) = BUF_PT (b); - XFASTINT (w->last_point_x) = FRAME_CURSOR_X (selected_frame); - XFASTINT (w->last_point_y) = FRAME_CURSOR_Y (selected_frame); + XSETFASTINT (w->last_point, BUF_PT (b)); + XSETFASTINT (w->last_point_x, FRAME_CURSOR_X (selected_frame)); + XSETFASTINT (w->last_point_y, FRAME_CURSOR_Y (selected_frame)); if (all_windows) mark_window_display_accurate (FRAME_ROOT_WINDOW (selected_frame), 1); else { w->update_mode_line = Qnil; - XFASTINT (w->last_modified) = BUF_MODIFF (b); - w->window_end_valid = Qt; + XSETFASTINT (w->last_modified, BUF_MODIFF (b)); + w->window_end_valid = w->buffer; last_arrow_position = Voverlay_arrow_position; last_arrow_string = Voverlay_arrow_string; + if (do_verify_charstarts) + verify_charstarts (w); + if (frame_up_to_date_hook != 0) + (*frame_up_to_date_hook) (selected_frame); } update_mode_lines = 0; windows_or_buffers_changed = 0; @@ -681,6 +902,11 @@ update: /* Change frame size now if a change is pending. */ do_pending_window_change (); + + /* If we just did a pending size change, redisplay again + for the new size. */ + if (windows_or_buffers_changed && !pause) + redisplay (); } /* Redisplay, but leave alone any recent echo area message @@ -712,15 +938,13 @@ mark_window_display_accurate (window, flag) for (;!NILP (window); window = w->next) { - if (XTYPE (window) != Lisp_Window) abort (); + if (!WINDOWP (window)) abort (); w = XWINDOW (window); if (!NILP (w->buffer)) { - XFASTINT (w->last_modified) - = !flag ? 0 - : XBUFFER (w->buffer) == current_buffer - ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer)); + XSETFASTINT (w->last_modified, + !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer))); /* Record if we are showing a region, so can make sure to update it fully at next redisplay. */ @@ -730,7 +954,7 @@ mark_window_display_accurate (window, flag) : Qnil); } - w->window_end_valid = Qt; + w->window_end_valid = w->buffer; w->update_mode_line = Qnil; if (!NILP (w->vchild)) @@ -752,8 +976,60 @@ mark_window_display_accurate (window, flag) } } +/* Update the menu bar item list for frame F. + This has to be done before we start to fill in any display lines, + because it can call eval. */ + +static void +update_menu_bar (f) + FRAME_PTR f; +{ + struct buffer *old = current_buffer; + Lisp_Object window; + register struct window *w; + window = FRAME_SELECTED_WINDOW (f); + w = XWINDOW (window); + + if (update_mode_lines) + w->update_mode_line = Qt; + + if ( +#ifdef USE_X_TOOLKIT + FRAME_EXTERNAL_MENU_BAR (f) +#else + FRAME_MENU_BAR_LINES (f) > 0 +#endif + ) + { + /* If the user has switched buffers or windows, we need to + recompute to reflect the new bindings. But we'll + recompute when update_mode_lines is set too; that means + that people can use force-mode-line-update to request + that the menu bar be recomputed. The adverse effect on + the rest of the redisplay algorithm is about the same as + windows_or_buffers_changed anyway. */ + if (windows_or_buffers_changed + || !NILP (w->update_mode_line) + || (XFASTINT (w->last_modified) < MODIFF + && (XFASTINT (w->last_modified) + <= XBUFFER (w->buffer)->save_modified))) + { + struct buffer *prev = current_buffer; + call1 (Vrun_hooks, Qmenu_bar_update_hook); + current_buffer = XBUFFER (w->buffer); + FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); + current_buffer = prev; +#ifdef USE_X_TOOLKIT + set_frame_menubar (f, 0); +#endif /* USE_X_TOOLKIT */ + } + } +} + int do_id = 1; +/* Redisplay WINDOW and its subwindows and siblings. */ + static void redisplay_windows (window) Lisp_Object window; @@ -762,6 +1038,8 @@ redisplay_windows (window) redisplay_window (window, 0); } +/* Redisplay window WINDOW and its subwindows. */ + static void redisplay_window (window, just_this_one) Lisp_Object window; @@ -770,13 +1048,13 @@ redisplay_window (window, just_this_one) register struct window *w = XWINDOW (window); FRAME_PTR f = XFRAME (WINDOW_FRAME (w)); int height; - register int lpoint = point; + register int lpoint = PT; struct buffer *old = current_buffer; register int width = window_internal_width (w) - 1; register int startp; register int hscroll = XINT (w->hscroll); struct position pos; - int opoint = point; + int opoint = PT; int tem; int window_needs_modeline; @@ -817,7 +1095,7 @@ redisplay_window (window, just_this_one) for (i = 0; i < height; i++) { get_display_line (f, vpos + i, 0); - display_string (w, vpos + i, "", 0, 0, 0, width); + display_string (w, vpos + i, "", 0, 0, 0, 1, 0, width); } goto finish_scroll_bars; @@ -830,7 +1108,7 @@ redisplay_window (window, just_this_one) /* Otherwise set up data on this window; select its buffer and point value */ current_buffer = XBUFFER (w->buffer); - opoint = point; + opoint = PT; /* Count number of windows showing the selected buffer. */ @@ -843,17 +1121,38 @@ redisplay_window (window, just_this_one) if (!EQ (window, selected_window)) { - SET_PT (marker_position (w->pointm)); - if (point < BEGV) + int new_pt = marker_position (w->pointm); + if (new_pt < BEGV) { - SET_PT (BEGV); - Fset_marker (w->pointm, make_number (point), Qnil); + new_pt = BEGV; + Fset_marker (w->pointm, make_number (new_pt), Qnil); } - else if (point > (ZV - 1)) + else if (new_pt > (ZV - 1)) { - SET_PT (ZV); - Fset_marker (w->pointm, make_number (point), Qnil); + new_pt = ZV; + Fset_marker (w->pointm, make_number (new_pt), Qnil); } + /* We don't use SET_PT so that the point-motion hooks don't run. */ + BUF_PT (current_buffer) = new_pt; + } + + /* If any of the character widths specified in the display table + have changed, invalidate the width run cache. It's true that this + may be a bit late to catch such changes, but the rest of + redisplay goes (non-fatally) haywire when the display table is + changed, so why should we worry about doing any better? */ + if (current_buffer->width_run_cache) + { + struct Lisp_Vector *disptab = buffer_display_table (); + + if (! disptab_matches_widthtab (disptab, + XVECTOR (current_buffer->width_table))) + { + invalidate_region_cache (current_buffer, + current_buffer->width_run_cache, + BEG, Z); + recompute_width_table (current_buffer, disptab); + } } /* If window-start is screwed up, choose a new one. */ @@ -870,13 +1169,12 @@ redisplay_window (window, just_this_one) w->base_line_number = Qnil; w->update_mode_line = Qt; w->force_start = Qnil; - XFASTINT (w->last_modified) = 0; + XSETFASTINT (w->last_modified, 0); if (startp < BEGV) startp = BEGV; if (startp > ZV) startp = ZV; try_window (window, startp); if (cursor_vpos < 0) { - /* ??? What should happen here if highlighting a region? */ /* If point does not appear, move point so it does appear */ pos = *compute_motion (startp, 0, ((EQ (window, minibuf_window) && startp == 1) @@ -885,16 +1183,25 @@ redisplay_window (window, just_this_one) (hscroll ? 1 - hscroll : 0), ZV, height / 2, - (1 << (SHORTBITS - 1)), - width, hscroll, pos_tab_offset (w, startp)); - SET_PT (pos.bufpos); - if (w != XWINDOW (FRAME_SELECTED_WINDOW (f))) - Fset_marker (w->pointm, make_number (point), Qnil); + width, hscroll, pos_tab_offset (w, startp), w); + BUF_PT (current_buffer) = pos.bufpos; + if (w != XWINDOW (selected_window)) + Fset_marker (w->pointm, make_number (PT), Qnil); else { - lpoint = point; + if (current_buffer == old) + lpoint = PT; FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left); FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top); } + /* If we are highlighting the region, + then we just changed the region, so redisplay to show it. */ + if (!NILP (Vtransient_mark_mode) + && !NILP (current_buffer->mark_active)) + { + cancel_my_columns (XWINDOW (window)); + try_window (window, startp); + } } goto done; } @@ -910,16 +1217,19 @@ redisplay_window (window, just_this_one) in redisplay handles the same cases. */ if (XFASTINT (w->last_modified) >= MODIFF - && point >= startp && !clip_changed + && PT >= startp && !clip_changed && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f)) /* Can't use this case if highlighting a region. */ && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active)) && NILP (w->region_showing) + /* If end pos is out of date, scroll bar and percentage will be wrong */ + && INTEGERP (w->window_end_vpos) + && XFASTINT (w->window_end_vpos) < XFASTINT (w->height) && !EQ (window, minibuf_window)) { pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), - point, height + 1, 10000, width, hscroll, - pos_tab_offset (w, startp)); + PT, height + 1, 10000, width, hscroll, + pos_tab_offset (w, startp), w); if (pos.vpos < height) { @@ -945,13 +1255,13 @@ redisplay_window (window, just_this_one) /* If current starting point was originally the beginning of a line but no longer is, find a new starting point. */ else if (!NILP (w->start_at_line_beg) - && !(startp == BEGV + && !(startp <= BEGV || FETCH_CHAR (startp - 1) == '\n')) { goto recenter; } else if (just_this_one && !MINI_WINDOW_P (w) - && point >= startp + && PT >= startp && XFASTINT (w->last_modified) /* or else vmotion on first line won't work. */ && ! NILP (w->start_at_line_beg) @@ -994,14 +1304,14 @@ redisplay_window (window, just_this_one) cancel_my_columns (w); } - XFASTINT (w->last_modified) = 0; + XSETFASTINT (w->last_modified, 0); w->update_mode_line = Qt; /* Try to scroll by specified few lines */ if (scroll_step && !clip_changed) { - if (point > startp) + if (PT > startp) { pos = *vmotion (Z - XFASTINT (w->window_end_pos), scroll_step, width, hscroll, window); @@ -1009,10 +1319,10 @@ redisplay_window (window, just_this_one) goto scroll_fail; } - pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step, + pos = *vmotion (startp, PT < startp ? - scroll_step : scroll_step, width, hscroll, window); - if (point >= pos.bufpos) + if (PT >= pos.bufpos) { try_window (window, pos.bufpos); if (cursor_vpos >= 0) @@ -1034,12 +1344,12 @@ recenter: /* Forget any previously recorded base line for line number display. */ w->base_line_number = Qnil; - pos = *vmotion (point, - height / 2, width, hscroll, window); + pos = *vmotion (PT, - (height / 2), width, hscroll, window); try_window (window, pos.bufpos); startp = marker_position (w->start); - w->start_at_line_beg = - (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil; + w->start_at_line_beg + = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil; done: if ((!NILP (w->update_mode_line) @@ -1058,7 +1368,11 @@ done: /* When we reach a frame's selected window, redo the frame's menu bar. */ if (!NILP (w->update_mode_line) +#ifdef USE_X_TOOLKIT + && FRAME_EXTERNAL_MENU_BAR (f) +#else && FRAME_MENU_BAR_LINES (f) > 0 +#endif && EQ (FRAME_SELECTED_WINDOW (f), window)) display_menu_bar (w); @@ -1097,9 +1411,9 @@ done: (*redeem_scroll_bar_hook) (w); } - SET_PT (opoint); + BUF_PT (current_buffer) = opoint; current_buffer = old; - SET_PT (lpoint); + BUF_PT (current_buffer) = lpoint; } /* Do full redisplay on one window, starting at position `pos'. */ @@ -1133,9 +1447,12 @@ try_window (window, pos) last_text_vpos /* Next line, unless prev line ended in end of buffer with no cr */ = vpos - (val.vpos && (FETCH_CHAR (val.bufpos - 1) != '\n' - || ! NILP (Fget_text_property (val.bufpos-1, +#ifdef USE_TEXT_PROPERTIES + || ! NILP (Fget_char_property (val.bufpos-1, Qinvisible, - Fcurrent_buffer ())))); + window)) +#endif + )); pos = val.bufpos; } @@ -1150,8 +1467,8 @@ try_window (window, pos) w->update_mode_line = Qt; /* Say where last char on frame will be, once redisplay is finished. */ - XFASTINT (w->window_end_pos) = Z - pos; - XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top); + XSETFASTINT (w->window_end_pos, Z - pos); + XSETFASTINT (w->window_end_vpos, last_text_vpos - XFASTINT (w->top)); /* But that is not valid info until redisplay finishes. */ w->window_end_valid = Qnil; } @@ -1180,6 +1497,9 @@ try_window_id (window) register int i, tem; int last_text_vpos = 0; int stop_vpos; + int selective = (INTEGERP (current_buffer->selective_display) + ? XINT (current_buffer->selective_display) + : !NILP (current_buffer->selective_display) ? -1 : 0); struct position val, bp, ep, xp, pp; int scroll_amount = 0; @@ -1191,16 +1511,16 @@ try_window_id (window) if (Z - GPT < end_unchanged) end_unchanged = Z - GPT; - if (beg_unchanged + 1 < start) + if (beg_unchanged + BEG < start) return 0; /* Give up if changes go above top of window */ /* Find position before which nothing is changed. */ bp = *compute_motion (start, 0, lmargin, - beg_unchanged + 1, height + 1, 0, width, hscroll, - pos_tab_offset (w, start)); + min (ZV, beg_unchanged + BEG), height + 1, 0, + width, hscroll, pos_tab_offset (w, start), w); if (bp.vpos >= height) { - if (point < bp.bufpos && !bp.contin) + if (PT < bp.bufpos && !bp.contin) { /* All changes are below the frame, and point is on the frame. We don't need to change the frame at all. @@ -1208,9 +1528,9 @@ try_window_id (window) any change in buffer size. */ bp = *compute_motion (start, 0, lmargin, Z, height, 0, - width, hscroll, pos_tab_offset (w, start)); - XFASTINT (w->window_end_vpos) = height; - XFASTINT (w->window_end_pos) = Z - bp.bufpos; + width, hscroll, pos_tab_offset (w, start), w); + XSETFASTINT (w->window_end_vpos, height); + XSETFASTINT (w->window_end_pos, Z - bp.bufpos); return 1; } return 0; @@ -1232,9 +1552,7 @@ try_window_id (window) if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0) || /* Likewise if we have to worry about selective display. */ - (XTYPE (current_buffer->selective_display) == Lisp_Int - && XINT (current_buffer->selective_display) > 0 - && bp.bufpos - 1 == beg_unchanged && vpos > 0)) + (selective > 0 && bp.bufpos - 1 == beg_unchanged && vpos > 0)) { bp = *vmotion (bp.bufpos, -1, width, hscroll, window); --vpos; @@ -1251,17 +1569,14 @@ try_window_id (window) /* Find first visible newline after which no more is changed. */ tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1); - if (XTYPE (current_buffer->selective_display) == Lisp_Int - && XINT (current_buffer->selective_display) > 0) - while (tem < ZV - 1 - && (position_indentation (tem) - >= XINT (current_buffer->selective_display))) + if (selective > 0) + while (tem < ZV - 1 && (indented_beyond_p (tem, selective))) tem = find_next_newline (tem, 1); /* Compute the cursor position after that newline. */ ep = *compute_motion (pos, vpos, val.hpos, tem, height, - (1 << (SHORTBITS - 1)), - width, hscroll, pos_tab_offset (w, bp.bufpos)); + width, hscroll, pos_tab_offset (w, bp.bufpos), w); /* If changes reach past the text available on the frame, just display rest of frame. */ @@ -1292,7 +1607,7 @@ try_window_id (window) epto = pos_tab_offset (w, ep.bufpos); xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, Z - XFASTINT (w->window_end_pos), - 10000, 0, width, hscroll, epto); + 10000, 0, width, hscroll, epto, w); scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos); /* Is everything on frame below the changes whitespace? @@ -1306,24 +1621,26 @@ try_window_id (window) if (i == xp.bufpos) return -2; - XFASTINT (w->window_end_vpos) += scroll_amount; + XSETFASTINT (w->window_end_vpos, + XFASTINT (w->window_end_vpos) + scroll_amount); /* Before doing any scrolling, verify that point will be on frame. */ - if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height)) + if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height)) { - if (point <= xp.bufpos) + if (PT <= xp.bufpos) { pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, - point, height, - (1 << (SHORTBITS - 1)), - width, hscroll, epto); + PT, height, - (1 << (SHORTBITS - 1)), + width, hscroll, epto, w); } else { pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, - point, height, - (1 << (SHORTBITS - 1)), - width, hscroll, pos_tab_offset (w, xp.bufpos)); + PT, height, - (1 << (SHORTBITS - 1)), + width, hscroll, + pos_tab_offset (w, xp.bufpos), w); } - if (pp.bufpos < point || pp.vpos == height) + if (pp.bufpos < PT || pp.vpos == height) return 0; cursor_vpos = pp.vpos + top; cursor_hpos = pp.hpos + XFASTINT (w->left); @@ -1344,7 +1661,14 @@ try_window_id (window) blank_end_of_window = 1; } else if (!scroll_amount) - {} + { + /* Even if we don't need to scroll, we must adjust the + charstarts of subsequent lines (that we won't redisplay) + according to the amount of text inserted or deleted. */ + int oldpos = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0]; + int adjust = ep.bufpos - oldpos; + adjust_window_charstarts (w, ep.vpos + top - 1, adjust); + } else if (bp.bufpos == Z - end_unchanged) { /* If reprinting everything is nearly as fast as scrolling, @@ -1361,9 +1685,26 @@ try_window_id (window) following line from being overwritten by scrolling and therefore having to be redrawn. */ tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount, - top + height - max (0, scroll_amount), - scroll_amount); - if (!tem) stop_vpos = height; + top + height - max (0, scroll_amount), + scroll_amount, bp.bufpos); + if (!tem) + stop_vpos = height; + else + { + /* scroll_frame_lines did not properly adjust subsequent + lines' charstarts in the case where the text of the + screen line at bp.vpos has changed. + (This can happen in a deletion that ends in mid-line.) + To adjust properly, we need to make things constent at + the position ep. + So do a second adjust to make that happen. + Note that stop_vpos >= ep.vpos, so it is sufficient + to update the charstarts for lines at ep.vpos and below. */ + int oldstart + = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0]; + adjust_window_charstarts (w, ep.vpos + top - 1, + ep.bufpos - oldstart); + } } else if (scroll_amount) { @@ -1381,7 +1722,7 @@ try_window_id (window) return -2; tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount, top + height - max (0, scroll_amount), - scroll_amount); + scroll_amount, ep.bufpos); if (!tem) stop_vpos = height; } } @@ -1427,8 +1768,8 @@ try_window_id (window) include the split character in the text considered on the frame */ if (val.hpos < lmargin) val.bufpos++; - XFASTINT (w->window_end_vpos) = last_text_vpos; - XFASTINT (w->window_end_pos) = Z - val.bufpos; + XSETFASTINT (w->window_end_vpos, last_text_vpos); + XSETFASTINT (w->window_end_pos, Z - val.bufpos); } /* If scrolling made blank lines at window bottom, @@ -1467,7 +1808,7 @@ try_window_id (window) /* Here is a case where display_text_line sets cursor_vpos wrong. Make it be fixed up, below. */ if (xp.bufpos == ZV - && xp.bufpos == point) + && xp.bufpos == PT) cursor_vpos = -1; } @@ -1486,8 +1827,9 @@ try_window_id (window) { val = *vmotion (Z - XFASTINT (w->window_end_pos), delta, width, hscroll, window); - XFASTINT (w->window_end_pos) = Z - val.bufpos; - XFASTINT (w->window_end_vpos) += val.vpos; + XSETFASTINT (w->window_end_pos, Z - val.bufpos); + XSETFASTINT (w->window_end_vpos, + XFASTINT (w->window_end_vpos) + val.vpos); } } @@ -1496,8 +1838,8 @@ try_window_id (window) /* If point was not in a line that was displayed, find it */ if (cursor_vpos < 0) { - val = *compute_motion (start, 0, lmargin, point, 10000, 10000, - width, hscroll, pos_tab_offset (w, start)); + val = *compute_motion (start, 0, lmargin, PT, 10000, 10000, + width, hscroll, pos_tab_offset (w, start), w); /* Admit failure if point is off frame now */ if (val.vpos >= height) { @@ -1516,7 +1858,7 @@ try_window_id (window) { val = *compute_motion (start, 0, lmargin, ZV, height, - (1 << (SHORTBITS - 1)), - width, hscroll, pos_tab_offset (w, start)); + width, hscroll, pos_tab_offset (w, start), w); if (val.vpos != XFASTINT (w->window_end_vpos)) abort (); if (XFASTINT (w->window_end_pos) @@ -1560,7 +1902,15 @@ redisplay_region (buf, start, end) start = end; end = temp; } - if (buf != current_buffer) + /* If this is a buffer not in the selected window, + we must do other windows. */ + if (buf != XBUFFER (XWINDOW (selected_window)->buffer)) + windows_or_buffers_changed = 1; + /* If it's not current, we can't use beg_unchanged, end_unchanged for it. */ + else if (buf != current_buffer) + windows_or_buffers_changed = 1; + /* If multiple windows show this buffer, we must do other windows. */ + else if (buffer_shared > 1) windows_or_buffers_changed = 1; else { @@ -1589,71 +1939,96 @@ redisplay_region (buf, start, end) } -/* Copy glyphs from the vector FROM to the rope T. +/* Copy LEN glyphs starting address FROM to the rope TO. But don't actually copy the parts that would come in before S. - Value is T, advanced past the copied data. */ + Value is TO, advanced past the copied data. + F is the frame we are displaying in. */ -GLYPH * -copy_rope (t, s, from, face) - register GLYPH *t; /* Copy to here. */ +static GLYPH * +copy_part_of_rope (f, to, s, from, len, face) + FRAME_PTR f; + register GLYPH *to; /* Copy to here. */ register GLYPH *s; /* Starting point. */ - Lisp_Object from; /* Data to copy; known to be a vector. */ + Lisp_Object *from; /* Data to copy. */ + int len; int face; /* Face to apply to glyphs which don't specify one. */ { - register int n = XVECTOR (from)->size; - register Lisp_Object *f = XVECTOR (from)->contents; + int n = len; + register Lisp_Object *fp = from; + /* These cache the results of the last call to compute_glyph_face. */ + int last_code = -1; + int last_merged = 0; - while (n--) - { - int glyph = XFASTINT (*f); +#ifdef HAVE_X_WINDOWS + if (! FRAME_TERMCAP_P (f)) + while (n--) + { + int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0); + int facecode; + + if (FAST_GLYPH_FACE (glyph) == 0) + /* If GLYPH has no face code, use FACE. */ + facecode = face; + else if (FAST_GLYPH_FACE (glyph) == last_code) + /* If it's same as previous glyph, use same result. */ + facecode = last_merged; + else + { + /* Merge this glyph's face and remember the result. */ + last_code = FAST_GLYPH_FACE (glyph); + last_merged = facecode = compute_glyph_face (f, last_code, face); + } - if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (glyph), - (GLYPH_FACE (glyph) - ? GLYPH_FACE (glyph) - : face)); - ++t; - ++f; - } - return t; + if (to >= s) + *to = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), facecode); + ++to; + ++fp; + } + else +#endif + while (n--) + { + if (to >= s) *to = (INTEGERP (*fp) ? XFASTINT (*fp) : 0); + ++to; + ++fp; + } + return to; } -/* Copy exactly LEN glyphs from FROM into data at T. - But don't alter words before S. */ +/* Correct a glyph by replacing its specified user-level face code + with a displayable computed face code. */ -GLYPH * -copy_part_of_rope (t, s, from, len, face) - register GLYPH *t; /* Copy to here. */ - register GLYPH *s; /* Starting point. */ - Lisp_Object *from; /* Data to copy. */ - int len; - int face; /* Face to apply to glyphs which don't specify one. */ +static GLYPH +fix_glyph (f, glyph, cface) + FRAME_PTR f; + GLYPH glyph; + int cface; { - int n = len; - register Lisp_Object *f = from; - - while (n--) +#ifdef HAVE_X_WINDOWS + if (! FRAME_TERMCAP_P (f)) { - int glyph = XFASTINT (*f); - - if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (glyph), - (GLYPH_FACE (glyph) - ? GLYPH_FACE (glyph) - : face)); - ++t; - ++f; + if (FAST_GLYPH_FACE (glyph) != 0) + cface = compute_glyph_face (f, FAST_GLYPH_FACE (glyph), cface); + glyph = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), cface); } - return t; +#endif + return glyph; } -/* Display one line of window w, starting at position START in W's buffer. - Display starting at horizontal position HPOS, which is normally zero - or negative. A negative value causes output up to hpos = 0 to be discarded. - This is done for negative hscroll, or when this is a continuation line - and the continuation occurred in the middle of a multi-column character. +/* Display one line of window W, starting at position START in W's buffer. + + Display starting at horizontal position HPOS, expressed relative to + W's left edge. In situations where the text at START shouldn't + start at the left margin (i.e. when the window is hscrolled, or + we're continuing a line which left off in the midst of a + multi-column character), HPOS should be negative; we throw away + characters up 'til hpos = 0. So, HPOS must take hscrolling into + account. TABOFFSET is an offset for ostensible hpos, used in tab stop calculations. - Display on position VPOS on the frame. (origin 0). + Display on position VPOS on the frame. It is origin 0, relative to + the top of the frame, not W. Returns a STRUCT POSITION giving character to start next line with and where to display it, including a zero or negative hpos. @@ -1676,8 +2051,10 @@ display_text_line (w, start, vpos, hpos, taboffset) register int pause; register unsigned char *p; GLYPH *endp; - register GLYPH *startp; + register GLYPH *leftmargin; register GLYPH *p1prev = 0; + register GLYPH *p1start; + int *charstart; FRAME_PTR f = XFRAME (w->frame); int tab_width = XINT (current_buffer->tab_width); int ctl_arrow = !NILP (current_buffer->ctl_arrow); @@ -1686,20 +2063,19 @@ display_text_line (w, start, vpos, hpos, taboffset) int lastpos; int invis; int hscroll = XINT (w->hscroll); - int truncate = hscroll - || (truncate_partial_width_windows - && XFASTINT (w->width) < FRAME_WIDTH (f)) - || !NILP (current_buffer->truncate_lines); + int truncate = (hscroll + || (truncate_partial_width_windows + && XFASTINT (w->width) < FRAME_WIDTH (f)) + || !NILP (current_buffer->truncate_lines)); /* 1 if we should highlight the region. */ int highlight_region = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active); int region_beg, region_end; - int selective - = XTYPE (current_buffer->selective_display) == Lisp_Int - ? XINT (current_buffer->selective_display) - : !NILP (current_buffer->selective_display) ? -1 : 0; + int selective = (INTEGERP (current_buffer->selective_display) + ? XINT (current_buffer->selective_display) + : !NILP (current_buffer->selective_display) ? -1 : 0); register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f); register struct Lisp_Vector *dp = window_display_table (w); @@ -1707,21 +2083,21 @@ display_text_line (w, start, vpos, hpos, taboffset) /* Nonzero means display something where there are invisible lines. The precise value is the number of glyphs to display. */ int selective_rlen - = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector + = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp)) ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : selective && !NILP (current_buffer->selective_display_ellipses) ? 3 : 0); /* This is the sequence of Lisp objects to display when there are invisible lines. */ Lisp_Object *invis_vector_contents - = (dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector + = (dp && VECTORP (DISP_INVIS_VECTOR (dp)) ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents : default_invis_vector); - GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int - ? '$' : XINT (DISP_TRUNC_GLYPH (dp))); - GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int - ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp))); + GLYPH truncator = (dp == 0 || !INTEGERP (DISP_TRUNC_GLYPH (dp)) + ? '$' : XINT (DISP_TRUNC_GLYPH (dp))); + GLYPH continuer = (dp == 0 || !INTEGERP (DISP_CONTINUE_GLYPH (dp)) + ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp))); /* The next buffer location at which the face should change, due to overlays or text property changes. */ @@ -1730,13 +2106,13 @@ display_text_line (w, start, vpos, hpos, taboffset) #ifdef USE_TEXT_PROPERTIES /* The next location where the `invisible' property changes */ int next_invisible; - Lisp_Object prop, position, endpos; #endif /* The face we're currently using. */ int current_face = 0; + int i; - XFASTINT (default_invis_vector[2]) = '.'; + XSETFASTINT (default_invis_vector[2], '.'); default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2]; hpos += XFASTINT (w->left); @@ -1762,21 +2138,65 @@ display_text_line (w, start, vpos, hpos, taboffset) else region_beg = region_end = -1; - if (MINI_WINDOW_P (w) && start == 1 + if (MINI_WINDOW_P (w) + && start == 1 && vpos == XFASTINT (w->top)) { - if (minibuf_prompt) - hpos = display_string (w, vpos, minibuf_prompt, hpos, + if (! NILP (minibuf_prompt)) + { + minibuf_prompt_width + = (display_string (w, vpos, XSTRING (minibuf_prompt)->data, + XSTRING (minibuf_prompt)->size, hpos, (!truncate ? continuer : truncator), - -1, -1); - minibuf_prompt_width = hpos; + 1, -1, -1) + - hpos); + hpos += minibuf_prompt_width; + } + else + minibuf_prompt_width = 0; } - desired_glyphs->bufp[vpos] = pos; - p1 = desired_glyphs->glyphs[vpos] + hpos; end = ZV; - startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left); - endp = startp + width; + + /* If we're hscrolled at all, use compute_motion to skip over any + text off the left edge of the window. compute_motion may know + tricks to do this faster than we can. */ + if (hpos < 0) + { + struct position *left_edge + = compute_motion (pos, vpos, hpos, + end, vpos, 0, + width, hscroll, taboffset, w); + + /* Retrieve the buffer position and column provided by + compute_motion. We can't assume that the column will be + zero, because you may have multi-column characters crossing + the left margin. + + compute_motion may have moved us past the screen position we + requested, if we hit a multi-column character, or the end of + the line. If so, back up. */ + if (left_edge->vpos > vpos + || left_edge->hpos > 0) + { + pos = left_edge->bufpos - 1; + hpos = left_edge->prevhpos; + } + else + { + pos = left_edge->bufpos; + hpos = left_edge->hpos; + } + } + + desired_glyphs->bufp[vpos] = start; + p1 = desired_glyphs->glyphs[vpos] + hpos; + p1start = p1; + charstart = desired_glyphs->charstarts[vpos] + hpos; + /* In case we don't ever write anything into it... */ + desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1; + leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left); + endp = leftmargin + width; /* Arrange the overlays nicely for our purposes. Usually, we call display_text_line on only one line at a time, in which case this @@ -1794,8 +2214,16 @@ display_text_line (w, start, vpos, hpos, taboffset) #ifdef USE_TEXT_PROPERTIES next_invisible = pos; #endif - while (p1 < endp) + while (1) { + /* Record which glyph starts a character, + and the character position of that character. */ + if (p1 >= leftmargin) + charstart[p1 - p1start] = pos; + + if (p1 >= endp) + break; + p1prev = p1; if (pos >= pause) { @@ -1805,38 +2233,42 @@ display_text_line (w, start, vpos, hpos, taboffset) break; /* Did we reach point? Record the cursor location. */ - if (pos == point && cursor_vpos < 0) + if (pos == PT && cursor_vpos < 0) { cursor_vpos = vpos; - cursor_hpos = p1 - startp; + cursor_hpos = p1 - leftmargin; } #ifdef USE_TEXT_PROPERTIES /* if the `invisible' property is set to t, we can skip to the next property change */ while (pos == next_invisible && pos < end) - { - XFASTINT (position) = pos; - prop = Fget_text_property (position, - Qinvisible, - Fcurrent_buffer ()); - endpos = Fnext_single_property_change (position, - Qinvisible, - Fcurrent_buffer ()); - if (INTEGERP (endpos)) - next_invisible = XINT (endpos); - else - next_invisible = end; - if (! NILP (prop)) { - if (pos < point && next_invisible >= point) - { - cursor_vpos = vpos; - cursor_hpos = p1 - startp; - } - pos = next_invisible; + Lisp_Object position, limit, endpos, prop, ww; + XSETFASTINT (position, pos); + XSETWINDOW (ww, w); + prop = Fget_char_property (position, Qinvisible, ww); + /* This is just an estimate to give reasonable + performance; nothing should go wrong if it is too small. */ + limit = Fnext_overlay_change (position); + if (XFASTINT (limit) > pos + 50) + XSETFASTINT (limit, pos + 50); + endpos = Fnext_single_property_change (position, Qinvisible, + Fcurrent_buffer (), limit); + if (INTEGERP (endpos)) + next_invisible = XINT (endpos); + else + next_invisible = end; + if (! NILP (prop)) + { + if (pos < PT && next_invisible >= PT) + { + cursor_vpos = vpos; + cursor_hpos = p1 - leftmargin; + } + pos = next_invisible; + } } - } if (pos >= end) break; #endif @@ -1848,7 +2280,7 @@ display_text_line (w, start, vpos, hpos, taboffset) if (pos >= next_face_change && FRAME_X_P (f)) current_face = compute_char_face (f, w, pos, region_beg, region_end, - &next_face_change); + &next_face_change, pos + 50, 0); #endif pause = end; @@ -1862,8 +2294,8 @@ display_text_line (w, start, vpos, hpos, taboffset) /* Wouldn't you hate to read the next line to someone over the phone? */ - if (pos < point && point < pause) - pause = point; + if (pos < PT && PT < pause) + pause = PT; if (pos < GPT && GPT < pause) pause = GPT; @@ -1871,38 +2303,42 @@ display_text_line (w, start, vpos, hpos, taboffset) } c = *p++; if (c >= 040 && c < 0177 - && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector)) + && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c)))) { - if (p1 >= startp) - *p1 = MAKE_GLYPH (c, current_face); + if (p1 >= leftmargin) + *p1 = MAKE_GLYPH (f, c, current_face); p1++; } else if (c == '\n') { invis = 0; - while (pos < end + while (pos + 1 < end && selective > 0 - && position_indentation (pos + 1) >= selective) + && indented_beyond_p (pos + 1, selective)) { invis = 1; pos = find_next_newline (pos + 1, 1); if (FETCH_CHAR (pos - 1) == '\n') pos--; } - if (invis && selective_rlen > 0 && p1 >= startp) + if (invis && selective_rlen > 0 && p1 >= leftmargin) { p1 += selective_rlen; - if (p1 - startp > width) + if (p1 - leftmargin > width) p1 = endp; - copy_part_of_rope (p1prev, p1prev, invis_vector_contents, + copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents, (p1 - p1prev), current_face); } -#if 1 +#ifdef HAVE_X_WINDOWS /* Draw the face of the newline character as extending all the way to the end of the frame line. */ if (current_face) - while (p1 < endp) - *p1++ = MAKE_GLYPH (' ', current_face); + { + if (p1 < leftmargin) + p1 = leftmargin; + while (p1 < endp) + *p1++ = FAST_MAKE_GLYPH (' ', current_face); + } #endif break; } @@ -1910,11 +2346,11 @@ display_text_line (w, start, vpos, hpos, taboffset) { do { - if (p1 >= startp && p1 < endp) - *p1 = MAKE_GLYPH (' ', current_face); + if (p1 >= leftmargin && p1 < endp) + *p1 = MAKE_GLYPH (f, ' ', current_face); p1++; } - while ((p1 - startp + taboffset + hscroll - (hscroll > 0)) + while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0)) % tab_width); } else if (c == Ctl ('M') && selective == -1) @@ -1925,53 +2361,85 @@ display_text_line (w, start, vpos, hpos, taboffset) if (selective_rlen > 0) { p1 += selective_rlen; - if (p1 - startp > width) + if (p1 - leftmargin > width) p1 = endp; - copy_part_of_rope (p1prev, p1prev, invis_vector_contents, + copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents, (p1 - p1prev), current_face); } -#if 1 +#ifdef HAVE_X_WINDOWS /* Draw the face of the newline character as extending all the way to the end of the frame line. */ if (current_face) - while (p1 < endp) - *p1++ = MAKE_GLYPH (' ', current_face); + { + if (p1 < leftmargin) + p1 = leftmargin; + while (p1 < endp) + *p1++ = FAST_MAKE_GLYPH (' ', current_face); + } #endif break; } - else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector) + else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) { - p1 = copy_rope (p1, startp, DISP_CHAR_VECTOR (dp, c), current_face); + p1 = copy_part_of_rope (f, p1, leftmargin, + XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents, + XVECTOR (DISP_CHAR_VECTOR (dp, c))->size, + current_face); } else if (c < 0200 && ctl_arrow) { - if (p1 >= startp) - *p1 = MAKE_GLYPH ((dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int - ? XINT (DISP_CTRL_GLYPH (dp)) : '^'), - current_face); + if (p1 >= leftmargin) + *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp)) + ? XINT (DISP_CTRL_GLYPH (dp)) : '^'), + current_face); p1++; - if (p1 >= startp && p1 < endp) - *p1 = MAKE_GLYPH (c ^ 0100, current_face); + if (p1 >= leftmargin && p1 < endp) + *p1 = MAKE_GLYPH (f, c ^ 0100, current_face); p1++; } else { - if (p1 >= startp) - *p1 = MAKE_GLYPH ((dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int - ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'), - current_face); + if (p1 >= leftmargin) + *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp)) + ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'), + current_face); p1++; - if (p1 >= startp && p1 < endp) - *p1 = MAKE_GLYPH ((c >> 6) + '0', current_face); + if (p1 >= leftmargin && p1 < endp) + *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face); p1++; - if (p1 >= startp && p1 < endp) - *p1 = MAKE_GLYPH ((7 & (c >> 3)) + '0', current_face); + if (p1 >= leftmargin && p1 < endp) + *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face); p1++; - if (p1 >= startp && p1 < endp) - *p1 = MAKE_GLYPH ((7 & c) + '0', current_face); + if (p1 >= leftmargin && p1 < endp) + *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face); p1++; } + /* Do nothing here for a char that's entirely off the left edge. */ + if (p1 >= leftmargin) + { + /* For all the glyphs occupied by this character, except for the + first, store -1 in charstarts. */ + if (p1 != p1prev) + { + int *p2x = &charstart[p1prev - p1start]; + int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start]; + + /* The window's left column should always + contain a character position. + And don't clobber anything to the left of that. */ + if (p1prev < leftmargin) + { + p2x = charstart + (leftmargin - p1start); + *p2x = pos; + } + + /* This loop skips over the char p2x initially points to. */ + while (++p2x < p2) + *p2x = -1; + } + } + pos++; } @@ -1983,6 +2451,18 @@ display_text_line (w, start, vpos, hpos, taboffset) lastpos = pos; + /* Store 0 in this charstart line for the positions where + there is no character. But do leave what was recorded + for the character that ended the line. */ + /* Add 1 in the endtest to compensate for the fact that ENDP was + made from WIDTH, which is 1 less than the window's actual + internal width. */ + i = p1 - p1start + 1; + if (p1 < leftmargin) + i += leftmargin - p1; + for (; i < endp - p1start + 1; i++) + charstart[i] = 0; + /* Handle continuation in middle of a character */ /* by backing up over it */ if (p1 > endp) @@ -2009,25 +2489,35 @@ display_text_line (w, start, vpos, hpos, taboffset) if (pos < ZV) { if (FETCH_CHAR (pos) == '\n') - /* If stopped due to a newline, start next line after it */ - pos++; + { + /* If stopped due to a newline, start next line after it */ + pos++; + /* Check again for hidden lines, in case the newline occurred exactly + at the right margin. */ + while (pos < ZV && selective > 0 + && indented_beyond_p (pos, selective)) + pos = find_next_newline (pos, 1); + } else /* Stopped due to right margin of window */ { if (truncate) { - *p1++ = truncator; + *p1++ = fix_glyph (f, truncator, 0); /* Truncating => start next line after next newline, and point is on this line if it is before the newline, and skip none of first char of next line */ - pos = find_next_newline (pos, 1); + do + pos = find_next_newline (pos, 1); + while (pos < ZV && selective > 0 + && indented_beyond_p (pos, selective)); val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0; lastpos = pos - (FETCH_CHAR (pos - 1) == '\n'); } else { - *p1++ = continuer; + *p1++ = fix_glyph (f, continuer, 0); val.vpos = 0; lastpos--; } @@ -2037,10 +2527,10 @@ display_text_line (w, start, vpos, hpos, taboffset) /* If point is at eol or in invisible text at eol, record its frame location now. */ - if (start <= point && point <= lastpos && cursor_vpos < 0) + if (start <= PT && PT <= lastpos && cursor_vpos < 0) { cursor_vpos = vpos; - cursor_hpos = p1 - startp; + cursor_hpos = p1 - leftmargin; } if (cursor_vpos == vpos) @@ -2076,15 +2566,15 @@ display_text_line (w, start, vpos, hpos, taboffset) /* If hscroll and line not empty, insert truncation-at-left marker */ if (hscroll && lastpos != start) { - *startp = truncator; - if (p1 <= startp) - p1 = startp + 1; + *leftmargin = fix_glyph (f, truncator, 0); + if (p1 <= leftmargin) + p1 = leftmargin + 1; } if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f)) { endp++; - if (p1 < startp) p1 = startp; + if (p1 < leftmargin) p1 = leftmargin; while (p1 < endp) *p1++ = SPACEGLYPH; /* Don't draw vertical bars if we're using scroll bars. They're @@ -2092,7 +2582,10 @@ display_text_line (w, start, vpos, hpos, taboffset) them when the scroll bar windows are flickering around to be reconfigured. */ *p1++ = (FRAME_HAS_VERTICAL_SCROLL_BARS (f) - ? ' ' : '|'); + ? ' ' + : (dp && INTEGERP (DISP_BORDER_GLYPH (dp)) + ? DISP_BORDER_GLYPH (dp) + : '|')); } desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos], p1 - desired_glyphs->glyphs[vpos]); @@ -2101,10 +2594,10 @@ display_text_line (w, start, vpos, hpos, taboffset) /* If the start of this line is the overlay arrow-position, then put the arrow string into the display-line. */ - if (XTYPE (Voverlay_arrow_position) == Lisp_Marker + if (MARKERP (Voverlay_arrow_position) && current_buffer == XMARKER (Voverlay_arrow_position)->buffer && start == marker_position (Voverlay_arrow_position) - && XTYPE (Voverlay_arrow_string) == Lisp_String + && STRINGP (Voverlay_arrow_string) && ! overlay_arrow_seen) { unsigned char *p = XSTRING (Voverlay_arrow_string)->data; @@ -2114,11 +2607,31 @@ display_text_line (w, start, vpos, hpos, taboffset) if (len > width) len = width; - for (i = 0; i < len; i++) - startp[i] = p[i]; +#ifdef HAVE_X_WINDOWS + if (!NULL_INTERVAL_P (XSTRING (Voverlay_arrow_string)->intervals)) + { + /* If the arrow string has text props, obey them when displaying. */ + for (i = 0; i < len; i++) + { + int c = p[i]; + Lisp_Object face, ilisp; + int newface; + + XSETFASTINT (ilisp, i); + face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string); + newface = compute_glyph_face_1 (f, face, 0); + leftmargin[i] = FAST_MAKE_GLYPH (c, newface); + } + } + else +#endif /* HAVE_X_WINDOWS */ + { + for (i = 0; i < len; i++) + leftmargin[i] = p[i]; + } /* Bug in SunOS 4.1.1 compiler requires this intermediate variable. */ - arrow_end = (startp - desired_glyphs->glyphs[vpos]) + len; + arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len; if (desired_glyphs->used[vpos] < arrow_end) desired_glyphs->used[vpos] = arrow_end; @@ -2141,49 +2654,34 @@ display_menu_bar (w) register FRAME_PTR f = XFRAME (WINDOW_FRAME (w)); int maxendcol = FRAME_WIDTH (f); int hpos = 0; + int i; +#ifndef USE_X_TOOLKIT if (FRAME_MENU_BAR_LINES (f) <= 0) return; get_display_line (f, vpos, 0); - /* If the user has switched buffers or windows, we need to - recompute to reflect the new bindings. But we'll - recompute when update_mode_lines is set too; that means - that people can use force-mode-line-update to request - that the menu bar be recomputed. The adverse effect on - the rest of the redisplay algorithm is about the same as - windows_or_buffers_changed anyway. */ - if (windows_or_buffers_changed - || update_mode_lines - || (XFASTINT (w->last_modified) < MODIFF - && (XFASTINT (w->last_modified) - <= XBUFFER (w->buffer)->save_modified))) - { - struct buffer *prev = current_buffer; - current_buffer = XBUFFER (w->buffer); - FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (); - current_buffer = prev; - } - - for (tail = FRAME_MENU_BAR_ITEMS (f); CONSP (tail); tail = XCONS (tail)->cdr) + items = FRAME_MENU_BAR_ITEMS (f); + for (i = 0; i < XVECTOR (items)->size; i += 3) { - Lisp_Object string; - - string = XCONS (XCONS (XCONS (tail)->car)->cdr)->car; + Lisp_Object pos, string; + string = XVECTOR (items)->contents[i + 1]; + if (NILP (string)) + break; - /* Record in each item its hpos. */ - XFASTINT (XCONS (XCONS (XCONS (tail)->car)->cdr)->cdr) = hpos; + XSETFASTINT (XVECTOR (items)->contents[i + 2], hpos); if (hpos < maxendcol) hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos, XSTRING (string)->data, - hpos, 0, hpos, maxendcol); + XSTRING (string)->size, + hpos, 0, 0, hpos, maxendcol); /* Put a gap of 3 spaces between items. */ if (hpos < maxendcol) { int hpos1 = hpos + 3; - hpos = display_string (w, vpos, "", hpos, 0, + hpos = display_string (w, vpos, "", 0, hpos, 0, 0, min (hpos1, maxendcol), maxendcol); } } @@ -2193,12 +2691,13 @@ display_menu_bar (w) /* Fill out the line with spaces. */ if (maxendcol > hpos) - hpos = display_string (w, vpos, "", hpos, 0, maxendcol, -1); + hpos = display_string (w, vpos, "", 0, hpos, 0, 0, maxendcol, maxendcol); /* Clear the rest of the lines allocated to the menu bar. */ vpos++; while (vpos < FRAME_MENU_BAR_LINES (f)) get_display_line (f, vpos++, 0); +#endif /* not USE_X_TOOLKIT */ } /* Display the mode line for window w */ @@ -2228,25 +2727,15 @@ display_mode_line (w) if (XFASTINT (w->width) == FRAME_WIDTH (f) || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f)) FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video; - #ifdef HAVE_X_WINDOWS - /* I'm trying this out because I saw Unimpress use it, but it's - possible that this may mess adversely with some window managers. -jla - - Wouldn't it be nice to use something like mode-line-format to - describe frame titles? -JimB */ - - /* Change the title of the frame to the name of the buffer displayed - in the currently selected window. Don't do this for minibuffer frames, - and don't do it when there's only one non-minibuffer frame. */ - if (FRAME_X_P (f) - && ! FRAME_MINIBUF_ONLY_P (f) - && w == XWINDOW (f->selected_window)) - x_implicitly_set_name (f, (EQ (Fnext_frame (WINDOW_FRAME (w), Qnil), - WINDOW_FRAME (w)) - ? Qnil - : XBUFFER (w->buffer)->name), - Qnil); + else if (! FRAME_TERMCAP_P (f)) + { + /* For a partial width window, explicitly set face of each glyph. */ + int i; + GLYPH *ptr = FRAME_DESIRED_GLYPHS (f)->glyphs[vpos]; + for (i = left; i < right; ++i) + ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1); + } #endif } @@ -2309,8 +2798,11 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt) if (this - 1 != last) { register int lim = --this - last + hpos; - hpos = display_string (w, vpos, last, hpos, 0, hpos, - min (lim, maxendcol)); + if (frame_title_ptr) + hpos = store_frame_title (last, hpos, min (lim, maxendcol)); + else + hpos = display_string (w, vpos, last, -1, hpos, 0, 1, + hpos, min (lim, maxendcol)); } else /* c == '%' */ { @@ -2335,10 +2827,15 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt) spec_width, maxendcol, Vglobal_mode_string); else if (c != 0) - hpos = display_string (w, vpos, - decode_mode_spec (w, c, - maxendcol - hpos), - hpos, 0, spec_width, maxendcol); + { + char *spec = decode_mode_spec (w, c, maxendcol - hpos); + if (frame_title_ptr) + hpos = store_frame_title (spec, spec_width, maxendcol); + else + hpos = display_string (w, vpos, spec, -1, + hpos, 0, 1, + spec_width, maxendcol); + } } } } @@ -2357,9 +2854,16 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt) tem = Fsymbol_value (elt); /* If value is a string, output that string literally: don't check for % within it. */ - if (XTYPE (tem) == Lisp_String) - hpos = display_string (w, vpos, XSTRING (tem)->data, - hpos, 0, minendcol, maxendcol); + if (STRINGP (tem)) + { + if (frame_title_ptr) + hpos = store_frame_title (XSTRING (tem)->data, + minendcol, maxendcol); + else + hpos = display_string (w, vpos, XSTRING (tem)->data, + XSTRING (tem)->size, + hpos, 0, 1, minendcol, maxendcol); + } /* Give up right away for nil or t. */ else if (!EQ (tem, elt)) { elt = tem; goto tail_recurse; } @@ -2380,11 +2884,11 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt) If first element is a symbol, process the cadr or caddr recursively according to whether the symbol's value is non-nil or nil. */ car = XCONS (elt)->car; - if (XTYPE (car) == Lisp_Symbol) + if (SYMBOLP (car)) { tem = Fboundp (car); elt = XCONS (elt)->cdr; - if (XTYPE (elt) != Lisp_Cons) + if (!CONSP (elt)) goto invalid; /* elt is now the cdr, and we know it is a cons cell. Use its car if CAR has a non-nil value. */ @@ -2400,12 +2904,12 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt) elt = XCONS (elt)->cdr; if (NILP (elt)) break; - else if (XTYPE (elt) != Lisp_Cons) + else if (!CONSP (elt)) goto invalid; elt = XCONS (elt)->car; goto tail_recurse; } - else if (XTYPE (car) == Lisp_Int) + else if (INTEGERP (car)) { register int lim = XINT (car); elt = XCONS (elt)->cdr; @@ -2430,11 +2934,11 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt) } goto tail_recurse; } - else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons) + else if (STRINGP (car) || CONSP (car)) { register int limit = 50; /* LIMIT is to protect against circular lists. */ - while (XTYPE (elt) == Lisp_Cons && --limit > 0 + while (CONSP (elt) && --limit > 0 && hpos < maxendcol) { hpos = display_mode_element (w, vpos, hpos, depth, @@ -2448,13 +2952,19 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt) default: invalid: - return (display_string (w, vpos, "*invalid*", hpos, 0, - minendcol, maxendcol)); + if (frame_title_ptr) + hpos = store_frame_title ("*invalid*", minendcol, maxendcol); + else + hpos = display_string (w, vpos, "*invalid*", -1, hpos, 0, 1, + minendcol, maxendcol); + return hpos; } - end: if (minendcol > hpos) - hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1); + if (frame_title_ptr) + hpos = store_frame_title ("", minendcol, maxendcol); + else + hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol); return hpos; } @@ -2469,17 +2979,19 @@ decode_mode_spec (w, c, maxwidth) register char c; register int maxwidth; { - Lisp_Object obj = Qnil; + Lisp_Object obj; FRAME_PTR f = XFRAME (WINDOW_FRAME (w)); char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents; + struct buffer *b = XBUFFER (w->buffer); + obj = Qnil; if (maxwidth > FRAME_WIDTH (f)) maxwidth = FRAME_WIDTH (f); switch (c) { case 'b': - obj = current_buffer->name; + obj = b->name; #if 0 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth) { @@ -2492,11 +3004,11 @@ decode_mode_spec (w, c, maxwidth) break; case 'f': - obj = current_buffer->filename; + obj = b->filename; #if 0 if (NILP (obj)) return "[none]"; - else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth) + else if (STRINGP (obj) && XSTRING (obj)->size > maxwidth) { bcopy ("...", decode_mode_spec_buf, 3); bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3, @@ -2520,7 +3032,7 @@ decode_mode_spec (w, c, maxwidth) return "??"; /* If the buffer is very big, don't waste time. */ - if (ZV - BEGV > line_number_display_limit) + if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit) { w->base_line_pos = Qnil; w->base_line_number = Qnil; @@ -2537,7 +3049,7 @@ decode_mode_spec (w, c, maxwidth) else { line = 1; - linepos = BEGV; + linepos = BUF_BEGV (b); } /* Count lines from base line to window start position. */ @@ -2549,15 +3061,15 @@ decode_mode_spec (w, c, maxwidth) or too far away, or if we did not have one. "Too close" means it's plausible a scroll-down would go back past it. */ - if (startpos == BEGV) + if (startpos == BUF_BEGV (b)) { - XFASTINT (w->base_line_number) = topline; - XFASTINT (w->base_line_pos) = BEGV; + XSETFASTINT (w->base_line_number, topline); + XSETFASTINT (w->base_line_pos, BUF_BEGV (b)); } else if (nlines < height + 25 || nlines > height * 3 + 50 - || linepos == BEGV) + || linepos == BUF_BEGV (b)) { - int limit = BEGV; + int limit = BUF_BEGV (b); int position; int distance = (height * 2 + 30) * 200; @@ -2577,8 +3089,8 @@ decode_mode_spec (w, c, maxwidth) return "??"; } - XFASTINT (w->base_line_number) = topline - nlines; - XFASTINT (w->base_line_pos) = position; + XSETFASTINT (w->base_line_number, topline - nlines); + XSETFASTINT (w->base_line_pos, position); } /* Now count lines from the start pos to point. */ @@ -2594,46 +3106,69 @@ decode_mode_spec (w, c, maxwidth) break; case 'm': - obj = current_buffer->mode_name; + obj = b->mode_name; break; case 'n': - if (BEGV > BEG || ZV < Z) + if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b)) return " Narrow"; break; case '*': - if (!NILP (current_buffer->read_only)) + if (!NILP (b->read_only)) return "%"; - if (MODIFF > current_buffer->save_modified) + if (BUF_MODIFF (b) > b->save_modified) + return "*"; + return "-"; + + case '+': + /* This differs from %* only for a modified read-only buffer. */ + if (BUF_MODIFF (b) > b->save_modified) + return "*"; + if (!NILP (b->read_only)) + return "%"; + return "-"; + + case '&': + /* This differs from %* in ignoring read-only-ness. */ + if (BUF_MODIFF (b) > b->save_modified) return "*"; return "-"; case 's': /* status of process */ - obj = Fget_buffer_process (Fcurrent_buffer ()); + obj = Fget_buffer_process (w->buffer); if (NILP (obj)) return "no process"; +#ifdef subprocesses obj = Fsymbol_name (Fprocess_status (obj)); +#endif break; + case 't': /* indicate TEXT or BINARY */ +#ifdef MODE_LINE_BINARY_TEXT + return MODE_LINE_BINARY_TEXT (b); +#else + return "T"; +#endif + case 'p': { int pos = marker_position (w->start); - int total = ZV - BEGV; + int total = BUF_ZV (b) - BUF_BEGV (b); - if (XFASTINT (w->window_end_pos) <= Z - ZV) + if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b)) { - if (pos <= BEGV) + if (pos <= BUF_BEGV (b)) return "All"; else return "Bottom"; } - else if (pos <= BEGV) + else if (pos <= BUF_BEGV (b)) return "Top"; else { - total = ((pos - BEGV) * 100 + total - 1) / total; + total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total; /* We can't normally display a 3-digit number, so get us a 2-digit number that is close. */ if (total == 100) @@ -2643,6 +3178,35 @@ decode_mode_spec (w, c, maxwidth) } } + /* Display percentage of size above the bottom of the screen. */ + case 'P': + { + int toppos = marker_position (w->start); + int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos); + int total = BUF_ZV (b) - BUF_BEGV (b); + + if (botpos >= BUF_ZV (b)) + { + if (toppos <= BUF_BEGV (b)) + return "All"; + else + return "Bottom"; + } + else + { + total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total; + /* We can't normally display a 3-digit number, + so get us a 2-digit number that is close. */ + if (total == 100) + total = 99; + if (toppos <= BUF_BEGV (b)) + sprintf (decode_mode_spec_buf, "Top%2d%%", total); + else + sprintf (decode_mode_spec_buf, "%2d%%", total); + return decode_mode_spec_buf; + } + } + case '%': return "%"; @@ -2673,7 +3237,7 @@ decode_mode_spec (w, c, maxwidth) *p = 0; return decode_mode_spec_buf; } - + case '-': { register char *p; @@ -2690,12 +3254,113 @@ decode_mode_spec (w, c, maxwidth) return decode_mode_spec_buf; } } - - if (XTYPE (obj) == Lisp_String) + + if (STRINGP (obj)) return (char *) XSTRING (obj)->data; else return ""; } + +/* Search for COUNT instances of a line boundary, which means either a + newline or (if selective display enabled) a carriage return. + Start at START. If COUNT is negative, search backwards. + + If we find COUNT instances, set *SHORTAGE to zero, and return the + position after the COUNTth match. Note that for reverse motion + this is not the same as the usual convention for Emacs motion commands. + + If we don't find COUNT instances before reaching the end of the + buffer (or the beginning, if scanning backwards), set *SHORTAGE to + the number of line boundaries left unfound, and return the end of the + buffer we bumped up against. */ + +static int +display_scan_buffer (start, count, shortage) + int *shortage, start; + register int count; +{ + int limit = ((count > 0) ? ZV - 1 : BEGV); + int direction = ((count > 0) ? 1 : -1); + + register unsigned char *cursor; + unsigned char *base; + + register int ceiling; + register unsigned char *ceiling_addr; + + /* If we are not in selective display mode, + check only for newlines. */ + if (! (!NILP (current_buffer->selective_display) + && !INTEGERP (current_buffer->selective_display))) + return scan_buffer ('\n', start, 0, count, shortage, 0); + + /* The code that follows is like scan_buffer + but checks for either newline or carriage return. */ + + if (shortage != 0) + *shortage = 0; + + if (count > 0) + while (start != limit + 1) + { + ceiling = BUFFER_CEILING_OF (start); + ceiling = min (limit, ceiling); + ceiling_addr = &FETCH_CHAR (ceiling) + 1; + base = (cursor = &FETCH_CHAR (start)); + while (1) + { + while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr) + ; + if (cursor != ceiling_addr) + { + if (--count == 0) + { + immediate_quit = 0; + return (start + cursor - base + 1); + } + else + if (++cursor == ceiling_addr) + break; + } + else + break; + } + start += cursor - base; + } + else + { + start--; /* first character we scan */ + while (start > limit - 1) + { /* we WILL scan under start */ + ceiling = BUFFER_FLOOR_OF (start); + ceiling = max (limit, ceiling); + ceiling_addr = &FETCH_CHAR (ceiling) - 1; + base = (cursor = &FETCH_CHAR (start)); + cursor++; + while (1) + { + while (--cursor != ceiling_addr + && *cursor != '\n' && *cursor != 015) + ; + if (cursor != ceiling_addr) + { + if (++count == 0) + { + immediate_quit = 0; + return (start + cursor - base + 1); + } + } + else + break; + } + start += cursor - base; + } + } + + if (shortage != 0) + *shortage = count * direction; + return (start + ((direction == 1 ? 0 : 1))); +} /* Count up to N lines starting from FROM. But don't go beyond LIMIT. @@ -2716,7 +3381,7 @@ display_count_lines (from, limit, n, pos_ptr) else ZV = limit; - *pos_ptr = scan_buffer ('\n', from, n, &shortage); + *pos_ptr = display_scan_buffer (from, n, &shortage); ZV = oldzv; BEGV = oldbegv; @@ -2731,6 +3396,7 @@ display_count_lines (from, limit, n, pos_ptr) /* Display STRING on one line of window W, starting at HPOS. Display at position VPOS. Caller should have done get_display_line. If VPOS == -1, display it as the current frame's title. + LENGTH is the length of STRING, or -1 meaning STRING is null-terminated. TRUNCATE is GLYPH to display at end if truncated. Zero for none. @@ -2741,14 +3407,22 @@ display_count_lines (from, limit, n, pos_ptr) The right edge of W is an implicit maximum. If TRUNCATE is nonzero, the implicit maximum is one column before the edge. - Returns ending hpos */ + OBEY_WINDOW_WIDTH says to put spaces or vertical bars + at the place where the current window ends in this line + and not display anything beyond there. Otherwise, only MAXCOL + controls where to stop output. + + Returns ending hpos. */ static int -display_string (w, vpos, string, hpos, truncate, mincol, maxcol) +display_string (w, vpos, string, length, hpos, truncate, + obey_window_width, mincol, maxcol) struct window *w; unsigned char *string; + int length; int vpos, hpos; GLYPH truncate; + int obey_window_width; int mincol, maxcol; { register int c; @@ -2765,8 +3439,9 @@ display_string (w, vpos, string, hpos, truncate, mincol, maxcol) /* Use the standard display table, not the window's display table. We don't want the mode line in rot13. */ register struct Lisp_Vector *dp = 0; + int i; - if (XTYPE (Vstandard_display_table) == Lisp_Vector + if (VECTORP (Vstandard_display_table) && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE) dp = XVECTOR (Vstandard_display_table); @@ -2774,32 +3449,50 @@ display_string (w, vpos, string, hpos, truncate, mincol, maxcol) p1 = p1start; start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left); - end = start + window_width - (truncate != 0); - if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f)) + if (obey_window_width) { - if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + end = start + window_width - (truncate != 0); + + if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f)) { - int i; + if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + { + int i; - for (i = 0; i < VERTICAL_SCROLL_BAR_WIDTH; i++) - *end-- = ' '; + for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++) + *end-- = ' '; + } + else + *end-- = '|'; } - else - *end-- = '|'; } - if (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol) + if (! obey_window_width + || (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol)) end = desired_glyphs->glyphs[vpos] + maxcol; + + /* Store 0 in charstart for these columns. */ + for (i = (hpos >= 0 ? hpos : 0); i < end - p1start + hpos; i++) + desired_glyphs->charstarts[vpos][i] = 0; + if (maxcol >= 0 && mincol > maxcol) mincol = maxcol; while (p1 < end) { + if (length == 0) + break; c = *string++; - if (!c) break; + /* Specified length. */ + if (length >= 0) + length--; + /* Unspecified length (null-terminated string). */ + else if (c == 0) + break; + if (c >= 040 && c < 0177 - && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector)) + && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c)))) { if (p1 >= start) *p1 = c; @@ -2815,13 +3508,19 @@ display_string (w, vpos, string, hpos, truncate, mincol, maxcol) } while ((p1 - start + hscroll - (hscroll > 0)) % tab_width); } - else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector) - p1 = copy_rope (p1, start, DISP_CHAR_VECTOR (dp, c), 0); + else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) + { + p1 = copy_part_of_rope (f, p1, start, + XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents, + XVECTOR (DISP_CHAR_VECTOR (dp, c))->size, + 0); + } else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow)) { if (p1 >= start) - *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int - ? XINT (DISP_CTRL_GLYPH (dp)) : '^'); + *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp)) + ? XINT (DISP_CTRL_GLYPH (dp)) : '^'), + 0); p1++; if (p1 >= start && p1 < end) *p1 = c ^ 0100; @@ -2830,8 +3529,9 @@ display_string (w, vpos, string, hpos, truncate, mincol, maxcol) else { if (p1 >= start) - *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int - ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'); + *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp)) + ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'), + 0); p1++; if (p1 >= start && p1 < end) *p1 = (c >> 6) + '0'; @@ -2845,10 +3545,10 @@ display_string (w, vpos, string, hpos, truncate, mincol, maxcol) } } - if (c) + if (c && length > 0) { p1 = end; - if (truncate) *p1++ = truncate; + if (truncate) *p1++ = fix_glyph (f, truncate, 0); } else if (mincol >= 0) { @@ -2871,6 +3571,9 @@ display_string (w, vpos, string, hpos, truncate, mincol, maxcol) void syms_of_xdisp () { + staticpro (&Qmenu_bar_update_hook); + Qmenu_bar_update_hook = intern ("menu-bar-update-hook"); + staticpro (&last_arrow_position); staticpro (&last_arrow_string); last_arrow_position = Qnil; @@ -2913,6 +3616,33 @@ If this is zero, point is always centered after it moves off frame."); DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows, "*Non-nil means highlight region even in nonselected windows."); highlight_nonselected_windows = 1; + + DEFVAR_BOOL ("multiple-frames", &multiple_frames, + "Non-nil means more than one frame is in use, not counting minibuffer frames.\n\ +Not guaranteed to be accurate except while parsing frame-title-format."); + + DEFVAR_LISP ("frame-title-format", &Vframe_title_format, + "Template for displaying the titlebar of visible frames.\n\ +\(Assuming the window manager supports this feature.)\n\ +This variable has the same structure as `mode-line-format' (which see),\n\ +and is used only on frames for which no explicit name has been set\n\ +\(see `modify-frame-parameters')."); + DEFVAR_LISP ("icon-title-format", &Vicon_title_format, + "Template for displaying the titlebar of an iconified frame.\n\ +\(Assuming the window manager supports this feature.)\n\ +This variable has the same structure as `mode-line-format' (which see),\n\ +and is used only on frames for which no explicit name has been set\n\ +\(see `modify-frame-parameters')."); + Vicon_title_format + = Vframe_title_format + = Fcons (intern ("multiple-frames"), + Fcons (build_string ("%b"), + Fcons (Fcons (build_string (""), + Fcons (intern ("invocation-name"), + Fcons (build_string ("@"), + Fcons (intern ("system-name"), + Qnil)))), + Qnil))); } /* initialize the window system */ @@ -2935,12 +3665,12 @@ init_xdisp () if (!noninteractive) { FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window))); - XFASTINT (XWINDOW (root_window)->top) = 0; + XSETFASTINT (XWINDOW (root_window)->top, 0); set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0); - XFASTINT (mini_w->top) = FRAME_HEIGHT (f) - 1; + XSETFASTINT (mini_w->top, FRAME_HEIGHT (f) - 1); set_window_height (minibuf_window, 1, 0); - XFASTINT (XWINDOW (root_window)->width) = FRAME_WIDTH (f); - XFASTINT (mini_w->width) = FRAME_WIDTH (f); + XSETFASTINT (XWINDOW (root_window)->width, FRAME_WIDTH (f)); + XSETFASTINT (mini_w->width, FRAME_WIDTH (f)); } }