]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
Syntactic cleanup.
[gnu-emacs] / src / xdisp.c
index 9cb3d26a49da8666d95d05590ae113d759179ae7..d22c9a53bc3cc01f8d6e51cc0832856f9b5c0398 100644 (file)
@@ -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.  */);