X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/889a70140b110c0fc768eae4c89a38863025256a..7f59302aef3e384cfca55b03490a1542060e821c:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index 9cb3d26a49..d22c9a53bc 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1,13 +1,13 @@ /* Display generation from window structure and buffer text. Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006 Free Software Foundation, Inc. + 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) +the Free Software Foundation; either version 3, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, @@ -283,10 +283,12 @@ Lisp_Object Vtool_bar_button_margin; EMACS_INT tool_bar_button_relief; -/* Non-zero means automatically resize tool-bars so that all tool-bar - items are visible, and no blank lines remain. */ +/* Non-nil means automatically resize tool-bars so that all tool-bar + items are visible, and no blank lines remain. -int auto_resize_tool_bars_p; + If value is `grow-only', only make tool-bar bigger. */ + +Lisp_Object Vauto_resize_tool_bars; /* Non-zero means draw block and hollow cursor as wide as the glyph under it. For example, if a block cursor is over a tab, it will be @@ -6267,7 +6269,7 @@ next_element_from_buffer (it) it->c = *p, it->len = 1; /* Record what we have and where it came from. */ - it->what = IT_CHARACTER;; + it->what = IT_CHARACTER; it->object = it->w->buffer; it->position = it->current.pos; @@ -7085,18 +7087,22 @@ move_it_by_lines (it, dvpos, need_y_p) { struct position pos; - if (!FRAME_WINDOW_P (it->f)) + /* The commented-out optimization uses vmotion on terminals. This + gives bad results, because elements like it->what, on which + callers such as pos_visible_p rely, aren't updated. */ + /* if (!FRAME_WINDOW_P (it->f)) { struct text_pos textpos; - /* We can use vmotion on frames without proportional fonts. */ pos = *vmotion (IT_CHARPOS (*it), dvpos, it->w); SET_TEXT_POS (textpos, pos.bufpos, pos.bytepos); reseat (it, textpos, 1); it->vpos += pos.vpos; it->current_y += pos.vpos; } - else if (dvpos == 0) + else */ + + if (dvpos == 0) { /* DVPOS == 0 means move to the start of the screen line. */ move_it_vertically_backward (it, 0); @@ -9363,7 +9369,7 @@ update_tool_bar (f, save_match_data) struct frame *f; int save_match_data; { -#ifdef USE_GTK +#if defined (USE_GTK) || USE_MAC_TOOLBAR int do_update = FRAME_EXTERNAL_TOOL_BAR (f); #else int do_update = WINDOWP (f->tool_bar_window) @@ -9694,9 +9700,16 @@ display_tool_bar_line (it, height) out:; row->displays_text_p = row->used[TEXT_AREA] != 0; - /* Use default face for the border below the tool bar. */ - if (!row->displays_text_p) + + /* Use default face for the border below the tool bar. + + FIXME: When auto-resize-tool-bars is grow-only, there is + no additional border below the possibly empty tool-bar lines. + So to make the extra empty lines look "normal", we have to + use the tool-bar face for the border too. */ + if (!row->displays_text_p && !EQ (Vauto_resize_tool_bars, Qgrow_only)) it->face_id = DEFAULT_FACE_ID; + extend_face_to_end_of_line (it); last = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1; last->right_box_line_p = 1; @@ -9718,6 +9731,7 @@ display_tool_bar_line (it, height) if (!row->displays_text_p) { row->height = row->phys_height = it->last_visible_y - row->y; + row->visible_height = row->height; row->ascent = row->phys_ascent = 0; row->extra_line_spacing = 0; } @@ -9820,9 +9834,8 @@ redisplay_tool_bar (f) struct window *w; struct it it; struct glyph_row *row; - int change_height_p = 0; -#ifdef USE_GTK +#if defined (USE_GTK) || USE_MAC_TOOLBAR if (FRAME_EXTERNAL_TOOL_BAR (f)) update_frame_tool_bar (f); return 0; @@ -9915,10 +9928,10 @@ redisplay_tool_bar (f) w->desired_matrix->no_scrolling_p = 1; w->must_be_updated_p = 1; - if (auto_resize_tool_bars_p) + if (!NILP (Vauto_resize_tool_bars)) { - int nlines, nrows; int max_tool_bar_height = MAX_FRAME_TOOL_BAR_HEIGHT (f); + int change_height_p = 0; /* If we couldn't display everything, change the tool-bar's height if there is room for more. */ @@ -9944,29 +9957,40 @@ redisplay_tool_bar (f) /* Resize windows as needed by changing the `tool-bar-lines' frame parameter. */ - if (change_height_p - && (nlines = tool_bar_lines_needed (f, &nrows), - nlines != WINDOW_TOTAL_LINES (w))) + if (change_height_p) { extern Lisp_Object Qtool_bar_lines; Lisp_Object frame; int old_height = WINDOW_TOTAL_LINES (w); + int nrows; + int nlines = tool_bar_lines_needed (f, &nrows); - XSETFRAME (frame, f); - Fmodify_frame_parameters (frame, - Fcons (Fcons (Qtool_bar_lines, - make_number (nlines)), - Qnil)); - if (WINDOW_TOTAL_LINES (w) != old_height) + change_height_p = ((EQ (Vauto_resize_tool_bars, Qgrow_only) + && !f->minimize_tool_bar_window_p) + ? (nlines > old_height) + : (nlines != old_height)); + f->minimize_tool_bar_window_p = 0; + + if (change_height_p) { - clear_glyph_matrix (w->desired_matrix); - f->n_tool_bar_rows = nrows; - fonts_changed_p = 1; + XSETFRAME (frame, f); + Fmodify_frame_parameters (frame, + Fcons (Fcons (Qtool_bar_lines, + make_number (nlines)), + Qnil)); + if (WINDOW_TOTAL_LINES (w) != old_height) + { + clear_glyph_matrix (w->desired_matrix); + f->n_tool_bar_rows = nrows; + fonts_changed_p = 1; + return 1; + } } } } - return change_height_p; + f->minimize_tool_bar_window_p = 0; + return 0; } @@ -10816,7 +10840,7 @@ redisplay_internal (preserve_echo_area) int must_finish = 0; struct text_pos tlbufpos, tlendpos; int number_of_visible_frames; - int count; + int count, count1; struct frame *sf; int polling_stopped_here = 0; @@ -10852,7 +10876,7 @@ redisplay_internal (preserve_echo_area) return; } -#if defined (USE_X_TOOLKIT) || defined (USE_GTK) +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (MAC_OS) if (popup_activated ()) return; #endif @@ -10954,6 +10978,10 @@ redisplay_internal (preserve_echo_area) update_mode_lines++; } + /* Avoid invocation of point motion hooks by `current_column' below. */ + count1 = SPECPDL_INDEX (); + specbind (Qinhibit_point_motion_hooks, Qt); + /* If %c is in the mode line, update it if needed. */ if (!NILP (w->column_number_displayed) /* This alternative quickly identifies a common case @@ -10965,6 +10993,8 @@ redisplay_internal (preserve_echo_area) != (int) current_column ())) /* iftc */ w->update_mode_line = Qt; + unbind_to (count1, Qnil); + FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1; /* The variable buffer_shared is set in redisplay_window and @@ -12757,6 +12787,7 @@ redisplay_window (window, just_this_one_p) int rc; int centering_position = -1; int last_line_misfit = 0; + int beg_unchanged, end_unchanged; SET_TEXT_POS (lpoint, PT, PT_BYTE); opoint = lpoint; @@ -12821,6 +12852,9 @@ redisplay_window (window, just_this_one_p) set_buffer_internal_1 (XBUFFER (w->buffer)); SET_TEXT_POS (opoint, PT, PT_BYTE); + beg_unchanged = BEG_UNCHANGED; + end_unchanged = END_UNCHANGED; + current_matrix_up_to_date_p = (!NILP (w->window_end_valid) && !current_buffer->clip_changed @@ -12944,6 +12978,8 @@ redisplay_window (window, just_this_one_p) w->force_start = Qt; } + force_start: + /* Handle case where place to start displaying has been specified, unless the specified location is outside the accessible range. */ if (!NILP (w->force_start) @@ -13114,32 +13150,25 @@ redisplay_window (window, just_this_one_p) /* If first window line is a continuation line, and window start is inside the modified region, but the first change is before - current window start, we must select a new window start.*/ - if (NILP (w->start_at_line_beg) - && CHARPOS (startp) > BEGV) - { - /* Make sure beg_unchanged and end_unchanged are up to date. - Do it only if buffer has really changed. This may or may - not have been done by try_window_id (see which) already. */ - if (MODIFF > SAVE_MODIFF - /* This seems to happen sometimes after saving a buffer. */ - || BEG_UNCHANGED + END_UNCHANGED > Z_BYTE) - { - if (GPT - BEG < BEG_UNCHANGED) - BEG_UNCHANGED = GPT - BEG; - if (Z - GPT < END_UNCHANGED) - END_UNCHANGED = Z - GPT; - } + current window start, we must select a new window start. - if (CHARPOS (startp) > BEG + BEG_UNCHANGED - && CHARPOS (startp) <= Z - END_UNCHANGED) - { - /* There doesn't seems to be a simple way to find a new - window start that is near the old window start, so - we just recenter. */ - goto recenter; - } - } + However, if this is the result of a down-mouse event (e.g. by + extending the mouse-drag-overlay), we don't want to select a + new window start, since that would change the position under + the mouse, resulting in an unwanted mouse-movement rather + than a simple mouse-click. */ + if (NILP (w->start_at_line_beg) + && NILP (do_mouse_tracking) + && CHARPOS (startp) > BEGV + && CHARPOS (startp) > BEG + beg_unchanged + && CHARPOS (startp) <= Z - end_unchanged) + { + w->force_start = Qt; + if (XMARKER (w->start)->buffer == current_buffer) + compute_window_start_on_continuation_line (w); + SET_TEXT_POS_FROM_MARKER (startp, w->start); + goto force_start; + } #if GLYPH_DEBUG debug_method_add (w, "same window start"); @@ -13442,12 +13471,12 @@ redisplay_window (window, just_this_one_p) display_menu_bar (w); #ifdef HAVE_WINDOW_SYSTEM -#ifdef USE_GTK +#if defined (USE_GTK) || USE_MAC_TOOLBAR redisplay_tool_bar_p = FRAME_EXTERNAL_TOOL_BAR (f); #else redisplay_tool_bar_p = WINDOWP (f->tool_bar_window) && (FRAME_TOOL_BAR_LINES (f) > 0 - || auto_resize_tool_bars_p); + || !NILP (Vauto_resize_tool_bars)); #endif @@ -13495,7 +13524,10 @@ redisplay_window (window, just_this_one_p) /* Restore current_buffer and value of point in it. */ TEMP_SET_PT_BOTH (CHARPOS (opoint), BYTEPOS (opoint)); set_buffer_internal_1 (old); - TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint)); + /* Avoid an abort in TEMP_SET_PT_BOTH if the buffer has become + shorter. This can be caused by log truncation in *Messages*. */ + if (CHARPOS (lpoint) <= ZV) + TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint)); unbind_to (count, Qnil); } @@ -13518,6 +13550,7 @@ try_window (window, pos, check_margins) struct window *w = XWINDOW (window); struct it it; struct glyph_row *last_text_row = NULL; + struct frame *f = XFRAME (w->frame); /* Make POS the new window start. */ set_marker_both (w->start, Qnil, CHARPOS (pos), BYTEPOS (pos)); @@ -13769,7 +13802,7 @@ try_window_reusing_current_matrix (w) nrows_scrolled); /* Disable lines that must be updated. */ - for (i = 0; i < it.vpos; ++i) + for (i = 0; i < nrows_scrolled; ++i) (start_row + i)->enabled_p = 0; /* Re-compute Y positions. */ @@ -14870,7 +14903,7 @@ try_window_id (w) sync_frame_with_window_matrix_rows (w); /* Adjust buffer positions in reused rows. */ - if (delta) + if (delta || delta_bytes) increment_matrix_positions (current_matrix, first_unchanged_at_end_vpos + dvpos, bottom_vpos, delta, delta_bytes); @@ -15825,13 +15858,37 @@ cursor_row_p (w, row) if (PT == MATRIX_ROW_END_CHARPOS (row)) { - /* If the row ends with a newline from a string, we don't want - the cursor there, but we still want it at the start of the - string if the string starts in this row. - If the row is continued it doesn't end in a newline. */ + /* Suppose the row ends on a string. + Unless the row is continued, that means it ends on a newline + in the string. If it's anything other than a display string + (e.g. a before-string from an overlay), we don't want the + cursor there. (This heuristic seems to give the optimal + behavior for the various types of multi-line strings.) */ if (CHARPOS (row->end.string_pos) >= 0) - cursor_row_p = (row->continued_p - || PT >= MATRIX_ROW_START_CHARPOS (row)); + { + if (row->continued_p) + cursor_row_p = 1; + else + { + /* Check for `display' property. */ + struct glyph *beg = row->glyphs[TEXT_AREA]; + struct glyph *end = beg + row->used[TEXT_AREA] - 1; + struct glyph *glyph; + + cursor_row_p = 0; + for (glyph = end; glyph >= beg; --glyph) + if (STRINGP (glyph->object)) + { + Lisp_Object prop + = Fget_char_property (make_number (PT), + Qdisplay, Qnil); + cursor_row_p = + (!NILP (prop) + && display_prop_string_p (prop, glyph->object)); + break; + } + } + } else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)) { /* If the row ends in middle of a real character, @@ -17292,7 +17349,7 @@ are the selected window and the window's buffer). */) CHECK_BUFFER (buffer); if (NILP (format)) - return build_string (""); + return empty_unibyte_string; if (no_props) face = Qnil; @@ -17350,7 +17407,7 @@ are the selected window and the window's buffer). */) { mode_line_string_list = Fnreverse (mode_line_string_list); str = Fmapconcat (intern ("identity"), mode_line_string_list, - make_string ("", 0)); + empty_unibyte_string); } unbind_to (count, Qnil); @@ -17944,6 +18001,16 @@ decode_mode_spec (w, c, field_width, precision, multibyte) #endif break; + case '@': + { + Lisp_Object val; + val = call1 (intern ("file-remote-p"), current_buffer->directory); + if (NILP (val)) + return "-"; + else + return "@"; + } + case 't': /* indicate TEXT or BINARY */ #ifdef MODE_LINE_BINARY_TEXT return MODE_LINE_BINARY_TEXT (b); @@ -18368,6 +18435,27 @@ invisible_p (propval, list) return 0; } +DEFUN ("invisible-p", Finvisible_p, Sinvisible_p, 1, 1, 0, + doc: /* Non-nil if the property makes the text invisible. +POS-OR-PROP can be a marker or number, in which case it is taken to be +a position in the current buffer and the value of the `invisible' property +is checked; or it can be some other value, which is then presumed to be the +value of the `invisible' property of the text of interest. +The non-nil value returned can be t for truly invisible text or something +else if the text is replaced by an ellipsis. */) + (pos_or_prop) + Lisp_Object pos_or_prop; +{ + Lisp_Object prop + = (NATNUMP (pos_or_prop) || MARKERP (pos_or_prop) + ? Fget_char_property (pos_or_prop, Qinvisible, Qnil) + : pos_or_prop); + int invis = TEXT_PROP_MEANS_INVISIBLE (prop); + return (invis == 0 ? Qnil + : invis == 1 ? Qt + : make_number (invis)); +} + /* Calculate a width or height in pixels from a specification using the following elements: @@ -22409,7 +22497,7 @@ note_mode_line_or_margin_highlight (window, x, y, area) Lisp_Object mouse_face; int original_x_pixel = x; - struct glyph * glyph = NULL; + struct glyph * glyph = NULL, * row_start_glyph = NULL; struct glyph_row *row; if (area == ON_MODE_LINE || area == ON_HEADER_LINE) @@ -22427,7 +22515,7 @@ note_mode_line_or_margin_highlight (window, x, y, area) /* Find glyph */ if (row->mode_line_p && row->enabled_p) { - glyph = row->glyphs[TEXT_AREA]; + glyph = row_start_glyph = row->glyphs[TEXT_AREA]; end = glyph + row->used[TEXT_AREA]; for (x0 = original_x_pixel; @@ -22551,12 +22639,17 @@ note_mode_line_or_margin_highlight (window, x, y, area) is converted to a flatten by emacs lisp interpreter. The internal string is an element of the structures. The displayed string is the flatten string. */ - for (tmp_glyph = glyph - 1, gpos = 0; - tmp_glyph->charpos >= XINT (b); - tmp_glyph--, gpos++) + gpos = 0; + if (glyph > row_start_glyph) { - if (!EQ (tmp_glyph->object, glyph->object)) - break; + tmp_glyph = glyph - 1; + while (tmp_glyph >= row_start_glyph + && tmp_glyph->charpos >= XINT (b) + && EQ (tmp_glyph->object, glyph->object)) + { + tmp_glyph--; + gpos++; + } } /* Calculate the lenght(glyph sequence length: GSEQ_LENGTH) of @@ -22644,7 +22737,7 @@ note_mouse_highlight (f, x, y) struct buffer *b; /* When a menu is active, don't highlight because this looks odd. */ -#if defined (USE_X_TOOLKIT) || defined (USE_GTK) +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (MAC_OS) if (popup_activated ()) return; #endif @@ -23734,6 +23827,7 @@ syms_of_xdisp () defsubr (&Slookup_image_map); #endif defsubr (&Sformat_mode_line); + defsubr (&Sinvisible_p); staticpro (&Qmenu_bar_update_hook); Qmenu_bar_update_hook = intern ("menu-bar-update-hook"); @@ -24026,7 +24120,7 @@ and is used only on frames for which no explicit name has been set = Vframe_title_format = Fcons (intern ("multiple-frames"), Fcons (build_string ("%b"), - Fcons (Fcons (empty_string, + Fcons (Fcons (empty_unibyte_string, Fcons (intern ("invocation-name"), Fcons (build_string ("@"), Fcons (intern ("system-name"), @@ -24037,7 +24131,7 @@ and is used only on frames for which no explicit name has been set doc: /* Maximum number of lines to keep in the message log buffer. If nil, disable message logging. If t, log messages but don't truncate the buffer when it becomes large. */); - Vmessage_log_max = make_number (50); + Vmessage_log_max = make_number (100); DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions, doc: /* Functions called before redisplay, if window sizes have changed. @@ -24077,12 +24171,13 @@ Autoselection selects the minibuffer only if it is active, and never unselects the minibuffer if it is active. */); Vmouse_autoselect_window = Qnil; - DEFVAR_BOOL ("auto-resize-tool-bars", &auto_resize_tool_bars_p, + DEFVAR_LISP ("auto-resize-tool-bars", &Vauto_resize_tool_bars, doc: /* *Non-nil means automatically resize tool-bars. -This increases a tool-bar's height if not all tool-bar items are visible. -It decreases a tool-bar's height when it would display blank lines -otherwise. */); - auto_resize_tool_bars_p = 1; +This dynamically changes the tool-bar's height to the minimum height +that is needed to make all tool-bar items visible. +If value is `grow-only', the tool-bar's height is only increased +automatically; to decrease the tool-bar height, use \\[recenter]. */); + Vauto_resize_tool_bars = Qt; DEFVAR_BOOL ("auto-raise-tool-bar-buttons", &auto_raise_tool_bar_buttons_p, doc: /* *Non-nil means raise tool-bar buttons when the mouse moves over them. */);