(waiting_for_input): Remove unnecessary prototype.
[bpt/emacs.git] / src / msdos.c
index 1ca6db4..fdf8b07 100644 (file)
@@ -1,5 +1,6 @@
 /* MS-DOS specific C utilities.          -*- coding: raw-text -*-
-   Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1993, 94, 95, 96, 97, 1999, 2000, 2001
+   Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -61,6 +62,7 @@ Boston, MA 02111-1307, USA.  */
 #include "buffer.h"
 #include "commands.h"
 #include "blockinput.h"
+#include "keyboard.h"
 #include <go32.h>
 #include <pc.h>
 #include <ctype.h>
@@ -167,6 +169,45 @@ mouse_off ()
     }
 }
 
+static void
+mouse_setup_buttons (int n_buttons)
+{
+  if (n_buttons == 3)
+    {
+      mouse_button_count = 3;
+      mouse_button_translate[0] = 0; /* Left */
+      mouse_button_translate[1] = 2; /* Middle */
+      mouse_button_translate[2] = 1; /* Right */
+    }
+  else /* two, what else? */
+    {
+      mouse_button_count = 2;
+      mouse_button_translate[0] = 0;
+      mouse_button_translate[1] = 1;
+    }
+}
+
+DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
+       1, 1, "NSet number of mouse buttons to: ",
+  "Set the number of mouse buttons to use by Emacs.\n\
+This is useful with mice that report the number of buttons inconsistently,\n\
+e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of\n\
+them.  This happens with wheeled mice on Windows 9X, for example.")
+  (nbuttons)
+     Lisp_Object nbuttons;
+{
+  int n;
+
+  CHECK_NUMBER (nbuttons);
+  n = XINT (nbuttons);
+  if (n < 2 || n > 3)
+    Fsignal (Qargs_out_of_range,
+            Fcons (build_string ("only 2 or 3 mouse buttons are supported"),
+                   Fcons (nbuttons, Qnil)));
+  mouse_setup_buttons (n);
+  return Qnil;
+}
+
 static void
 mouse_get_xy (int *x, int *y)
 {
@@ -277,11 +318,26 @@ mouse_check_moved ()
   mouse_last_y = y;
 }
 
+/* Force the mouse driver to ``forget'' about any button clicks until
+   now.  */
+static void
+mouse_clear_clicks (void)
+{
+  int b;
+
+  for (b = 0; b < mouse_button_count; b++)
+    {
+      int dummy_x, dummy_y;
+
+      (void) mouse_pressed (b, &dummy_x, &dummy_y);
+      (void) mouse_released (b, &dummy_x, &dummy_y);
+    }
+}
+
 void
 mouse_init ()
 {
   union REGS regs;
-  int b;
 
   if (termscript)
     fprintf (termscript, "<M_INIT>");
@@ -293,13 +349,7 @@ mouse_init ()
      doesn't do that automatically when function 21h is called, which
      causes Emacs to ``remember'' the click that switched focus to the
      window just before Emacs was started from that window.  */
-  for (b = 0; b < mouse_button_count; b++)
-    {
-      int dummy_x, dummy_y;
-
-      (void) mouse_pressed (b, &dummy_x, &dummy_y);
-      (void) mouse_released (b, &dummy_x, &dummy_y);
-    }
+  mouse_clear_clicks ();
 
   regs.x.ax = 0x0007;
   regs.x.cx = 0;
@@ -324,7 +374,6 @@ static int internal_terminal = 0;
 #ifndef HAVE_X_WINDOWS
 extern unsigned char ScreenAttrib;
 static int screen_face;
-static int highlight;
 
 static int screen_size_X;
 static int screen_size_Y;
@@ -418,29 +467,29 @@ do_visible_bell (xorattr)
      unsigned char xorattr;
 {
   asm volatile
-    ("  movb   $1,%%dl
-visible_bell_0:
-       movl   _ScreenPrimary,%%eax
-       call   dosmemsetup
-       movl   %%eax,%%ebx
-       movl   %1,%%ecx
-       movb   %0,%%al
-       incl   %%ebx
-visible_bell_1:
-       xorb   %%al,%%gs:(%%ebx)
-       addl   $2,%%ebx
-       decl   %%ecx
-       jne    visible_bell_1
-       decb   %%dl
-       jne    visible_bell_3
-visible_bell_2:
-       movzwl %%ax,%%eax
-        movzwl %%ax,%%eax
-       movzwl %%ax,%%eax
-       movzwl %%ax,%%eax
-       decw   %%cx
-       jne    visible_bell_2
-       jmp    visible_bell_0
+    ("  movb   $1,%%dl                         \n\
+visible_bell_0:                                        \n\
+       movl   _ScreenPrimary,%%eax             \n\
+       call   dosmemsetup                      \n\
+       movl   %%eax,%%ebx                      \n\
+       movl   %1,%%ecx                         \n\
+       movb   %0,%%al                          \n\
+       incl   %%ebx                            \n\
+visible_bell_1:                                        \n\
+       xorb   %%al,%%gs:(%%ebx)                \n\
+       addl   $2,%%ebx                         \n\
+       decl   %%ecx                            \n\
+       jne    visible_bell_1                   \n\
+       decb   %%dl                             \n\
+       jne    visible_bell_3                   \n\
+visible_bell_2:                                        \n\
+       movzwl %%ax,%%eax                       \n\
+        movzwl %%ax,%%eax                      \n\
+       movzwl %%ax,%%eax                       \n\
+       movzwl %%ax,%%eax                       \n\
+       decw   %%cx                             \n\
+       jne    visible_bell_2                   \n\
+       jmp    visible_bell_0                   \n\
 visible_bell_3:"
      : /* no output */
      : "m" (xorattr), "g" (screen_size)
@@ -628,6 +677,11 @@ dos_set_window_size (rows, cols)
   *rows = ScreenRows ();
   *cols = ScreenCols ();
 
+  /* Update Emacs' notion of screen dimensions.  */
+  screen_size_X = *cols;
+  screen_size_Y = *rows;
+  screen_size = *cols * *rows;
+
 #if __DJGPP__ > 1
   /* If the dimensions changed, the mouse highlight info is invalid.  */
   if (current_rows != *rows || current_cols != *cols)
@@ -822,12 +876,13 @@ static void
 IT_set_face (int face)
 {
   struct frame *sf = SELECTED_FRAME();
-  struct face *fp = FACE_FROM_ID (sf, face);
-  unsigned long fg, bg;
+  struct face *fp  = FACE_FROM_ID (sf, face);
+  struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
+  unsigned long fg, bg, dflt_fg, dflt_bg;
 
   if (!fp)
     {
-      fp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
+      fp = dfp;
       /* The default face for the frame should always be realized and
         cached.  */
       if (!fp)
@@ -836,13 +891,13 @@ IT_set_face (int face)
   screen_face = face;
   fg = fp->foreground;
   bg = fp->background;
+  dflt_fg = dfp->foreground;
+  dflt_bg = dfp->background;
 
-  /* Don't use invalid colors.  In particular, FACE_TTY_DEFAULT_*
-     colors mean use the colors of the default face, except that if
-     highlight is on, invert the foreground and the background.  Note
-     that we assume all 16 colors to be available for the background,
-     since Emacs switches on this mode (and loses the blinking
-     attribute) at startup.  */
+  /* Don't use invalid colors.  In particular, FACE_TTY_DEFAULT_* colors
+     mean use the colors of the default face.  Note that we assume all
+     16 colors to be available for the background, since Emacs switches
+     on this mode (and loses the blinking attribute) at startup.  */
   if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
     fg = FRAME_FOREGROUND_PIXEL (sf);
   else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
@@ -853,18 +908,24 @@ IT_set_face (int face)
     bg = FRAME_FOREGROUND_PIXEL (sf);
 
   /* Make sure highlighted lines really stand out, come what may.  */
-  if ((highlight || fp->tty_reverse_p)
-      && (fg == FRAME_FOREGROUND_PIXEL (sf)
-         && bg == FRAME_BACKGROUND_PIXEL (sf)))
+  if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
     {
       unsigned long tem = fg;
 
       fg = bg;
       bg = tem;
     }
+  /* If the user requested inverse video, obey.  */
+  if (inverse_video)
+    {
+      unsigned long tem2 = fg;
+
+      fg = bg;
+      bg = tem2;
+    }
   if (termscript)
-    fprintf (termscript, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face,
-            highlight ? "H" : "", fp->foreground, fp->background, fg, bg);
+    fprintf (termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
+            fp->foreground, fp->background, fg, bg);
   if (fg >= 0 && fg < 16)
     {
       ScreenAttrib &= 0xf0;
@@ -905,6 +966,9 @@ IT_write_glyphs (struct glyph *str, int str_len)
     = (NILP (current_buffer->enable_multibyte_characters)
        && unibyte_display_via_language_environment);
 
+  unsigned char conversion_buffer[256];
+  int conversion_buffer_size = sizeof conversion_buffer;
+
   if (str_len <= 0) return;
   
   screen_buf = screen_bp = alloca (str_len * 2);
@@ -940,6 +1004,9 @@ IT_write_glyphs (struct glyph *str, int str_len)
          register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
          int glyph_not_in_table = 0;
 
+         /* If g is negative, it means we have a multibyte character
+            in *str.  That's what GLYPH_FROM_CHAR_GLYPH returns for
+            multibyte characters.  */
          if (g < 0 || g >= tlen)
            {
              /* This glyph doesn't have an entry in Vglyph_table.  */
@@ -975,7 +1042,7 @@ IT_write_glyphs (struct glyph *str, int str_len)
 
          /* If the face of this glyph is different from the current
             screen face, update the screen attribute byte.  */
-         cf = FAST_GLYPH_FACE (g);
+         cf = str->face_id;
          if (cf != screen_face)
            IT_set_face (cf);   /* handles invalid faces gracefully */
 
@@ -1011,7 +1078,7 @@ IT_write_glyphs (struct glyph *str, int str_len)
                 terminal_coding with Vdos_unsupported_char_glyph.  */
              if (*conversion_buffer == '?')
                {
-                 char *cbp = conversion_buffer;
+                 unsigned char *cbp = conversion_buffer;
 
                  while (cbp < conversion_buffer + enclen && *cbp == '?')
                    *cbp++ = unsupported_char;
@@ -1112,11 +1179,18 @@ IT_write_glyphs (struct glyph *str, int str_len)
 /* This is used for debugging, to turn off note_mouse_highlight.  */
 int disable_mouse_highlight;
 
-/* If a string, dos_rawgetc generates an event to display that string.
-   (The display is done in keyboard.c:read_char.)  */
+/* If non-nil, dos_rawgetc generates an event to display that string.
+   (The display is done in keyboard.c:read_char, by calling
+   show_help_echo.)  */
 static Lisp_Object help_echo;
 static Lisp_Object previous_help_echo; /* a helper temporary variable */
 
+/* These record the window, the object and the position where the help
+   echo string was generated.  */
+static Lisp_Object help_echo_window;
+static Lisp_Object help_echo_object;
+static int help_echo_pos;
+
 static int mouse_preempted = 0;        /* non-zero when XMenu gobbles mouse events */
 
 /* Set the mouse pointer shape according to whether it is in the
@@ -1186,6 +1260,9 @@ show_mouse_face (struct display_info *dpyinfo, int hl)
 
       if (end_hpos <= start_hpos)
        continue;
+      /* Record that some glyphs of this row are displayed in
+         mouse-face.  */
+      row->mouse_face_p = hl > 0;
       if (hl > 0)
        {
          int vpos = row->y + WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
@@ -1298,6 +1375,11 @@ fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
        }
       else if (line_start_position > 0)
        best_row = row;
+
+      /* Don't overstep the last matrix row, lest we get into the
+        never-never land... */
+      if (row->y + 1 >= yb)
+       break;
       
       ++row;
     }
@@ -1340,7 +1422,7 @@ fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
 /* Take proper action when mouse has moved to the mode or top line of
    window W, x-position X.  MODE_LINE_P non-zero means mouse is on the
    mode line.  X is relative to the start of the text display area of
-   W, so the width of bitmap areas and scroll bars must be subtracted
+   W, so the width of fringes and scroll bars must be subtracted
    to get a position relative to the start of the mode line.  */
 static void
 IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
@@ -1376,7 +1458,12 @@ IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
          help = Fget_text_property (make_number (glyph->charpos),
                                     Qhelp_echo, glyph->object);
          if (!NILP (help))
-           help_echo = help;
+           {
+             help_echo = help;
+             XSETWINDOW (help_echo_window, w);
+             help_echo_object = glyph->object;
+             help_echo_pos = glyph->charpos;
+           }
        }
     }
 }
@@ -1389,7 +1476,7 @@ static void
 IT_note_mouse_highlight (struct frame *f, int x, int y)
 {
   struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
-  int portion;
+  int portion = -1;
   Lisp_Object window;
   struct window *w;
 
@@ -1448,16 +1535,22 @@ IT_note_mouse_highlight (struct frame *f, int x, int y)
       && (XFASTINT (w->last_overlay_modified)
          == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
     {
-      int pos, i, area;
+      int pos, i;
       struct glyph_row *row;
       struct glyph *glyph;
+      int nrows = w->current_matrix->nrows;
 
       /* Find the glyph under X/Y.  */
       glyph = NULL;
-      if (y < w->current_matrix->nrows)
+      if (y >= 0 && y < nrows)
        {
          row = MATRIX_ROW (w->current_matrix, y);
-         if (row->enabled_p
+         /* Give up if some row before the one we are looking for is
+            not enabled.  */
+         for (i = 0; i <= y; i++)
+           if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
+             break;
+         if (i > y  /* all rows upto and including the one at Y are enabled */
              && row->displays_text_p
              && x <  window_box_width (w, TEXT_AREA))
            {
@@ -1514,14 +1607,16 @@ IT_note_mouse_highlight (struct frame *f, int x, int y)
           enough space for all, and try again.  */
        len = 10;
        overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-       noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
+       noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
        if (noverlays > len)
          {
            len = noverlays;
            overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-           noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
+           noverlays = overlays_at (pos,
+                                    0, &overlay_vec, &len, NULL, NULL, 0);
          }
          
+       /* Sort overlays into increasing priority order.  */
        noverlays = sort_overlays (overlay_vec, noverlays, w);
 
        /* Check mouse-face highlighting.  */
@@ -1539,7 +1634,7 @@ IT_note_mouse_highlight (struct frame *f, int x, int y)
 
            /* Find highest priority overlay that has a mouse-face prop.  */
            overlay = Qnil;
-           for (i = 0; i < noverlays; i++)
+           for (i = noverlays - 1; i >= 0; --i)
              {
                mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
                if (!NILP (mouse_face))
@@ -1623,22 +1718,38 @@ IT_note_mouse_highlight (struct frame *f, int x, int y)
 
          /* Check overlays first.  */
          help = Qnil;
-         for (i = 0; i < noverlays && NILP (help); ++i)
-           help = Foverlay_get (overlay_vec[i], Qhelp_echo); 
+         for (i = noverlays - 1; i >= 0 && NILP (help); --i)
+           {
+             overlay = overlay_vec[i];
+             help = Foverlay_get (overlay, Qhelp_echo);
+           }
            
-         /* Try text properties.  */
-         if (NILP (help)
-             && ((STRINGP (glyph->object)
-                  && glyph->charpos >= 0
-                  && glyph->charpos < XSTRING (glyph->object)->size)
-                 || (BUFFERP (glyph->object)
-                     && glyph->charpos >= BEGV
-                     && glyph->charpos < ZV)))
-           help = Fget_text_property (make_number (glyph->charpos),
-                                      Qhelp_echo, glyph->object);
-
          if (!NILP (help))
-           help_echo = help;
+           {
+             help_echo = help;
+             help_echo_window = window;
+             help_echo_object = overlay;
+             help_echo_pos = pos;
+           }
+         /* Try text properties.  */
+         else if (NILP (help)
+                  && ((STRINGP (glyph->object)
+                       && glyph->charpos >= 0
+                       && glyph->charpos < XSTRING (glyph->object)->size)
+                      || (BUFFERP (glyph->object)
+                          && glyph->charpos >= BEGV
+                          && glyph->charpos < ZV)))
+           {
+             help = Fget_text_property (make_number (glyph->charpos),
+                                        Qhelp_echo, glyph->object);
+             if (!NILP (help))
+               {
+                 help_echo = help;
+                 help_echo_window = window;
+                 help_echo_object = glyph->object;
+                 help_echo_pos = glyph->charpos;
+               }
+           }
        }
          
        BEGV = obegv;
@@ -1820,30 +1931,15 @@ IT_cmgoto (FRAME_PTR f)
     mouse_on ();
 }
 
-static void
-IT_reassert_line_highlight (int new, int vpos)
-{
-  highlight = new;
-}
-
-static void
-IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
-{
-  highlight = new_highlight;
-  IT_cursor_to (vpos, 0);
-  IT_clear_end_of_line (first_unused_hpos);
-}
-
 static void
 IT_update_begin (struct frame *f)
 {
   struct display_info *display_info = FRAME_X_DISPLAY_INFO (f);
-  
-  highlight = 0;
+  struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
 
   BLOCK_INPUT;
 
-  if (f == display_info->mouse_face_mouse_frame)
+  if (f && f == mouse_face_frame)
     {
       /* Don't do highlighting for mouse motion during the update.  */
       display_info->mouse_face_defer = 1;
@@ -1855,9 +1951,8 @@ IT_update_begin (struct frame *f)
 
       /* Can we tell that this update does not affect the window
         where the mouse highlight is?  If so, no need to turn off.
-        Likewise, don't do anything if the frame is garbaged;
-        in that case, the frame's current matrix that we would use
-        is all wrong, and we will redisplay that line anyway.  */
+        Likewise, don't do anything if none of the enabled rows
+        contains glyphs highlighted in mouse face.  */
       if (!NILP (display_info->mouse_face_window)
          && WINDOWP (display_info->mouse_face_window))
        {
@@ -1872,7 +1967,8 @@ IT_update_begin (struct frame *f)
          else
            {
              for (i = 0; i < w->desired_matrix->nrows; ++i)
-               if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
+               if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
+                   && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
                  break;
            }
 
@@ -1880,7 +1976,7 @@ IT_update_begin (struct frame *f)
            clear_mouse_face (display_info);
        }
     }
-  else if (!FRAME_LIVE_P (display_info->mouse_face_mouse_frame))
+  else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
     {
       /* If the frame with mouse highlight was deleted, invalidate the
         highlight info.  */
@@ -1897,7 +1993,6 @@ IT_update_begin (struct frame *f)
 static void
 IT_update_end (struct frame *f)
 {
-  highlight = 0;
   FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
 }
 
@@ -1911,7 +2006,7 @@ IT_frame_up_to_date (struct frame *f)
   struct window *sw;
 
   if (dpyinfo->mouse_face_deferred_gc
-      || f == dpyinfo->mouse_face_mouse_frame)
+      || (f && f == dpyinfo->mouse_face_mouse_frame))
     {
       BLOCK_INPUT;
       if (dpyinfo->mouse_face_mouse_frame)
@@ -2019,10 +2114,10 @@ x_set_menu_bar_lines (f, value, oldval)
   set_menu_bar_lines (f, value, oldval);
 }
 
-/* This was copied from xfns.c  */
+/* This was copied from xfaces.c  */
 
-Lisp_Object Qbackground_color;
-Lisp_Object Qforeground_color;
+extern Lisp_Object Qbackground_color;
+extern Lisp_Object Qforeground_color;
 Lisp_Object Qreverse;
 extern Lisp_Object Qtitle;
 
@@ -2034,7 +2129,6 @@ IT_set_terminal_modes (void)
 {
   if (termscript)
     fprintf (termscript, "\n<SET_TERM>");
-  highlight = 0;
 
   screen_size_X = ScreenCols ();
   screen_size_Y = ScreenRows ();
@@ -2112,8 +2206,6 @@ IT_reset_terminal_modes (void)
   if (termscript)
     fprintf (termscript, "\n<RESET_TERM>");
 
-  highlight = 0;
-
   if (!term_setup_done)
     return;
   
@@ -2192,17 +2284,25 @@ DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
      (frame)
      Lisp_Object frame;
 {
-  int reverse;
   struct frame *f;
 
-  CHECK_FRAME (frame, 0);
+  CHECK_FRAME (frame);
   f= XFRAME (frame);
-  reverse = EQ (Fcdr (Fassq (intern ("reverse"), f->param_alist)), Qt);
 
-  initial_screen_colors[0]
-    = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
-  initial_screen_colors[1]
-    = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
+  /* This function is called after applying default-frame-alist to the
+     initial frame.  At that time, if reverse-colors option was
+     specified in default-frame-alist, it was already applied, and
+     frame colors are reversed.  We need to account for that.  */
+  if (EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt))
+    {
+      initial_screen_colors[0] = FRAME_BACKGROUND_PIXEL (f);
+      initial_screen_colors[1] = FRAME_FOREGROUND_PIXEL (f);
+    }
+  else
+    {
+      initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
+      initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
+    }
 }
 
 void
@@ -2221,8 +2321,11 @@ IT_set_frame_parameters (f, alist)
   int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
   int was_reverse = reverse;
   int redraw = 0, fg_set = 0, bg_set = 0;
+  int need_to_reverse;
   unsigned long orig_fg;
   unsigned long orig_bg;
+  Lisp_Object frame_bg, frame_fg;
+  extern Lisp_Object Qdefault, QCforeground, QCbackground;
 
   /* If we are creating a new frame, begin with the original screen colors
      used for the initial frame.  */
@@ -2234,6 +2337,15 @@ IT_set_frame_parameters (f, alist)
     }
   orig_fg = FRAME_FOREGROUND_PIXEL (f);
   orig_bg = FRAME_BACKGROUND_PIXEL (f);
+  frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
+  frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
+  /* frame_fg and frame_bg could be nil if, for example,
+     f->param_alist is nil, e.g. if we are called from
+     Fmake_terminal_frame.  */
+  if (NILP (frame_fg))
+    frame_fg = build_string (unspecified_fg);
+  if (NILP (frame_bg))
+    frame_bg = build_string (unspecified_bg);
 
   /* Extract parm names and values into those vectors.  */
   i = 0;
@@ -2243,7 +2355,7 @@ IT_set_frame_parameters (f, alist)
 
       elt = Fcar (tail);
       parms[i] = Fcar (elt);
-      CHECK_SYMBOL (parms[i], 1);
+      CHECK_SYMBOL (parms[i]);
       values[i] = Fcdr (elt);
       i++;
     }
@@ -2252,58 +2364,86 @@ IT_set_frame_parameters (f, alist)
 
   for (i = 0; i < j; i++)
     {
-      Lisp_Object prop = parms[i];
-      Lisp_Object val  = values[i];
+      Lisp_Object prop, val;
+
+      prop = parms[i];
+      val  = values[i];
 
       if (EQ (prop, Qreverse))
        reverse = EQ (val, Qt);
     }
-       
-  if (termscript && reverse && !was_reverse)
+
+  need_to_reverse = reverse && !was_reverse;
+  if (termscript && need_to_reverse)
     fprintf (termscript, "<INVERSE-VIDEO>\n");
 
   /* Now process the alist elements in reverse of specified order.  */
   for (i--; i >= 0; i--)
     {
-      Lisp_Object prop = parms[i];
-      Lisp_Object val  = values[i];
+      Lisp_Object prop, val;
+      Lisp_Object frame;
+
+      prop = parms[i];
+      val  = values[i];
 
       if (EQ (prop, Qforeground_color))
        {
-         unsigned long new_color = load_color (f, NULL, val, reverse
+         unsigned long new_color = load_color (f, NULL, val, need_to_reverse
                                                ? LFACE_BACKGROUND_INDEX
                                                : LFACE_FOREGROUND_INDEX);
          if (new_color !=  FACE_TTY_DEFAULT_COLOR
              && new_color != FACE_TTY_DEFAULT_FG_COLOR
              && new_color != FACE_TTY_DEFAULT_BG_COLOR)
            {
-             if (reverse)
-               /* FIXME: should the fore-/background of the default
-                  face change here as well?  */
-               FRAME_BACKGROUND_PIXEL (f) = new_color;
+             FRAME_FOREGROUND_PIXEL (f) = new_color;
+             /* Make sure the foreground of the default face for this
+                frame is changed as well.  */
+             XSETFRAME (frame, f);
+             if (need_to_reverse)
+               {
+                 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
+                                                    val, frame);
+                 prop = Qbackground_color;
+                 bg_set = 1;
+               }
              else
-               FRAME_FOREGROUND_PIXEL (f) = new_color;
+               {
+                 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
+                                                    val, frame);
+                 fg_set = 1;
+               }
              redraw = 1;
-             fg_set = 1;
              if (termscript)
                fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
            }
        }
       else if (EQ (prop, Qbackground_color))
        {
-         unsigned long new_color = load_color (f, NULL, val, reverse
+         unsigned long new_color = load_color (f, NULL, val, need_to_reverse
                                                ? LFACE_FOREGROUND_INDEX
                                                : LFACE_BACKGROUND_INDEX);
          if (new_color != FACE_TTY_DEFAULT_COLOR
              && new_color != FACE_TTY_DEFAULT_FG_COLOR
              && new_color != FACE_TTY_DEFAULT_BG_COLOR)
            {
-             if (reverse)
-               FRAME_FOREGROUND_PIXEL (f) = new_color;
+             FRAME_BACKGROUND_PIXEL (f) = new_color;
+             /* Make sure the background of the default face for this
+                frame is changed as well.  */
+             XSETFRAME (frame, f);
+             if (need_to_reverse)
+               {
+                 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
+                                                    val, frame);
+                 prop = Qforeground_color;
+                 fg_set = 1;
+               }
              else
-               FRAME_BACKGROUND_PIXEL (f) = new_color;
+               {
+                 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
+                                                    val, frame);
+                 bg_set = 1;
+               }
              redraw = 1;
-             bg_set = 1;
              if (termscript)
                fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
            }
@@ -2327,16 +2467,24 @@ IT_set_frame_parameters (f, alist)
 
   /* If they specified "reverse", but not the colors, we need to swap
      the current frame colors.  */
-  if (reverse && !was_reverse)
+  if (need_to_reverse)
     {
+      Lisp_Object frame;
+
       if (!fg_set)
        {
-         FRAME_BACKGROUND_PIXEL (f) = orig_fg;
+         XSETFRAME (frame, f);
+         Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
+                                            tty_color_name (f, orig_bg),
+                                            frame);
          redraw = 1;
        }
       if (!bg_set)
        {
-         FRAME_FOREGROUND_PIXEL (f) = orig_bg;
+         XSETFRAME (frame, f);
+         Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
+                                            tty_color_name (f, orig_fg),
+                                            frame);
          redraw = 1;
        }
     }
@@ -2436,10 +2584,8 @@ internal_terminal_init ()
   clear_to_end_hook = IT_clear_to_end;
   clear_end_of_line_hook = IT_clear_end_of_line;
   clear_frame_hook = IT_clear_screen;
-  change_line_highlight_hook = IT_change_line_highlight;
   update_begin_hook = IT_update_begin;
   update_end_hook = IT_update_end;
-  reassert_line_highlight_hook = IT_reassert_line_highlight;
   frame_up_to_date_hook = IT_frame_up_to_date;
 
   /* These hooks are called by term.c without being checked.  */
@@ -2992,9 +3138,6 @@ and then the scan code.")
 }
 
 /* Get a char from keyboard.  Function keys are put into the event queue.  */
-
-extern void kbd_buffer_store_event (struct input_event *);
-
 static int
 dos_rawgetc ()
 {
@@ -3235,17 +3378,26 @@ dos_rawgetc ()
       if (mouse_last_x != mouse_prev_x || mouse_last_y != mouse_prev_y)
        {
          previous_help_echo = help_echo;
-         help_echo = Qnil;
+         help_echo = help_echo_object = help_echo_window = Qnil;
+         help_echo_pos = -1;
          IT_note_mouse_highlight (SELECTED_FRAME(),
                                   mouse_last_x, mouse_last_y);
          /* If the contents of the global variable help_echo has
             changed, generate a HELP_EVENT.  */
          if (!NILP (help_echo) || !NILP (previous_help_echo))
            {
+             /* HELP_EVENT takes 2 events in the event loop.  */
              event.kind = HELP_EVENT;
              event.frame_or_window = selected_frame;
-             event.arg = help_echo;
+             event.arg = help_echo_object;
+             event.x = make_number (help_echo_pos);
              event.timestamp = event_timestamp ();
+             event.code = 0;
+             kbd_buffer_store_event (&event);
+             if (WINDOWP (help_echo_window))
+               event.frame_or_window = help_echo_window;
+             event.arg = help_echo;
+             event.code = 1;
              kbd_buffer_store_event (&event);
            }
        }
@@ -3361,7 +3513,11 @@ glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
    grab the nearest Xlib manual (down the hall, second-to-last door on the
    left), but I don't think it's worth the effort.  */
 
+/* These hold text of the current and the previous menu help messages.  */
 static char *menu_help_message, *prev_menu_help_message;
+/* Pane number and item number of the menu item which generated the
+   last menu help message.  */
+static int menu_help_paneno, menu_help_itemno;
 
 static XMenu *
 IT_menu_create ()
@@ -3445,7 +3601,7 @@ IT_menu_calc_size (XMenu *menu, int *width, int *height)
 /* Display MENU at (X,Y) using FACES.  */
 
 static void
-IT_menu_display (XMenu *menu, int y, int x, int *faces, int disp_help)
+IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
 {
   int i, j, face, width;
   struct glyph *text, *p;
@@ -3471,8 +3627,14 @@ IT_menu_display (XMenu *menu, int y, int x, int *faces, int disp_help)
        = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
       mousehere = (y + i == my && x <= mx && mx < x + width + 2);
       face = faces[enabled + mousehere * 2];
+      /* The following if clause means that we display the menu help
+        strings even if the menu item is currently disabled.  */
       if (disp_help && enabled + mousehere * 2 >= 2)
-       menu_help_message = menu->help_text[i];
+       {
+         menu_help_message = menu->help_text[i];
+         menu_help_paneno = pn - 1;
+         menu_help_itemno = i;
+       }
       p = text;
       SET_CHAR_GLYPH (*p, ' ', face, 0);
       p++;
@@ -3617,7 +3779,7 @@ struct IT_menu_state
 int
 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
               int x0, int y0, unsigned ButtonMask, char **txt,
-              void (*help_callback)(char *))
+              void (*help_callback)(char *, int, int))
 {
   struct IT_menu_state *state;
   int statecount;
@@ -3642,7 +3804,7 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
     y0 = 1;
 
   /* We will process all the mouse events directly, so we had
-     better prevented dos_rawgetc from stealing them from us.  */
+     better prevent dos_rawgetc from stealing them from us.  */
   mouse_preempted++;
 
   state = alloca (menu->panecount * sizeof (struct IT_menu_state));
@@ -3691,7 +3853,7 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
   IT_display_cursor (0);
 
   /* Display the menu title.  */
-  IT_menu_display (menu, y0 - 1, x0 - 1, title_faces, 0);
+  IT_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
   if (buffers_num_deleted)
     menu->text[0][7] = ' ';
   if ((onepane = menu->count == 1 && menu->submenu[0]))
@@ -3750,6 +3912,7 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
                        IT_menu_display (state[i].menu,
                                         state[i].y,
                                         state[i].x,
+                                        state[i].pane,
                                         faces, 1);
                        state[statecount].menu = state[i].menu->submenu[dy];
                        state[statecount].pane = state[i].menu->panenumber[dy];
@@ -3766,6 +3929,7 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
          IT_menu_display (state[statecount - 1].menu,
                           state[statecount - 1].y,
                           state[statecount - 1].x,
+                          state[statecount - 1].pane,
                           faces, 1);
        }
       else
@@ -3773,7 +3937,8 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
          if ((menu_help_message || prev_menu_help_message)
              && menu_help_message != prev_menu_help_message)
            {
-             help_callback (menu_help_message);
+             help_callback (menu_help_message,
+                            menu_help_paneno, menu_help_itemno);
              IT_display_cursor (0);
              prev_menu_help_message = menu_help_message;
            }
@@ -3830,6 +3995,9 @@ XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
      (which invoked the menu) too quickly.  If we don't remove these events,
      Emacs will process them after we return and surprise the user.  */
   discard_mouse_events ();
+  mouse_clear_clicks ();
+  if (!kbd_buffer_events_waiting (1))
+    clear_input_pending ();
   /* Allow mouse events generation by dos_rawgetc.  */
   mouse_preempted--;
   return result;
@@ -4463,20 +4631,7 @@ dos_ttraw ()
            {
              have_mouse = 1;   /* enable mouse */
              mouse_visible = 0;
-             
-             if (outregs.x.bx == 3)
-               {
-                 mouse_button_count = 3;
-                 mouse_button_translate[0] = 0; /* Left */
-                 mouse_button_translate[1] = 2; /* Middle */
-                 mouse_button_translate[2] = 1; /* Right */
-               }
-             else
-               {
-                 mouse_button_count = 2;
-                 mouse_button_translate[0] = 0;
-                 mouse_button_translate[1] = 1;
-               }
+             mouse_setup_buttons (outregs.x.bx);
              mouse_position_hook = &mouse_get_pos;
              mouse_init ();
            }
@@ -4597,18 +4752,23 @@ run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
       saveargv1 = argv[1];
       saveargv2 = argv[2];
       argv[1] = "/c";
-      if (argv[2])
+      /* We only need to mirror slashes if a DOS shell will be invoked
+        not via `system' (which does the mirroring itself).  Yes, that
+        means DJGPP v1.x will lose here.  */
+      if (argv[2] && argv[3])
        {
          char *p = alloca (strlen (argv[2]) + 1);
 
          strcpy (argv[2] = p, saveargv2);
          while (*p && isspace (*p))
            p++;
-         while (*p && !isspace (*p))
-           if (*p == '/')
-             *p++ = '\\';
-           else
-             p++;
+         while (*p)
+           {
+             if (*p == '/')
+               *p++ = '\\';
+             else
+               p++;
+           }
        }
     }
 
@@ -4649,6 +4809,7 @@ run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
       if (*cmnd)
        {
          extern char **environ;
+         char **save_env = environ;
          int save_system_flags = __system_flags;
 
          /* Request the most powerful version of `system'.  We need
@@ -4663,6 +4824,7 @@ run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
          environ = envv;
          result = system (cmnd);
          __system_flags = save_system_flags;
+         environ = save_env;
        }
       else
        result = 0;     /* emulate Unixy shell behavior with empty cmd line */
@@ -5114,10 +5276,15 @@ syms_of_msdos ()
   recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
   staticpro (&recent_doskeys);
 #ifndef HAVE_X_WINDOWS
-  staticpro (&help_echo);
   help_echo = Qnil;
-  staticpro (&previous_help_echo);
+  staticpro (&help_echo);
+  help_echo_object = Qnil;
+  staticpro (&help_echo_object);
+  help_echo_window = Qnil;
+  staticpro (&help_echo_window);
   previous_help_echo = Qnil;
+  staticpro (&previous_help_echo);
+  help_echo_pos = -1;
 
   DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
     "List of directories to search for bitmap files for X.");
@@ -5129,11 +5296,7 @@ For example, if a block cursor is over a tab, it will be drawn as\n\
 wide as that tab on the display.  (No effect on MS-DOS.)");
   x_stretch_cursor_p = 0;
 
-  /* The following three are from xfns.c:  */
-  Qbackground_color = intern ("background-color");
-  staticpro (&Qbackground_color);
-  Qforeground_color = intern ("foreground-color");
-  staticpro (&Qforeground_color);
+  /* The following two are from xfns.c:  */
   Qbar = intern ("bar");
   staticpro (&Qbar);
   Qcursor_type = intern ("cursor-type");
@@ -5143,7 +5306,7 @@ wide as that tab on the display.  (No effect on MS-DOS.)");
 
   DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
    "*Glyph to display instead of chars not supported by current codepage.\n\
-
+\n\
 This variable is used only by MSDOS terminals.");
     Vdos_unsupported_char_glyph = '\177';
 #endif
@@ -5158,6 +5321,7 @@ nil means don't delete them until `list-processes' is run.");
   defsubr (&Smsdos_long_file_names);
   defsubr (&Smsdos_downcase_filename);
   defsubr (&Smsdos_remember_default_colors);
+  defsubr (&Smsdos_set_mouse_buttons);
 }
 
 #endif /* MSDOS */