Avoid (most) uses of XCAR/XCDR as lvalues, for flexibility in experimenting
[bpt/emacs.git] / src / keyboard.c
index 18c1f3e..23b1f0d 100644 (file)
@@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA.  */
 #include "dispextern.h"
 #include "syntax.h"
 #include "intervals.h"
+#include "keymap.h"
 #include "blockinput.h"
 #include "puresize.h"
 #include "systime.h"
@@ -103,9 +104,11 @@ extern int input_fd;
 #define KBD_BUFFER_SIZE 4096
 #endif
 #else  /* No X-windows, character input */
-#define KBD_BUFFER_SIZE 256
+#define KBD_BUFFER_SIZE 4096
 #endif /* No X-windows */
 
+#define abs(x)         ((x) >= 0 ? (x) : -(x))
+
 /* Following definition copied from eval.c */
 
 struct backtrace
@@ -188,13 +191,21 @@ extern struct backtrace *backtrace_list;
 
 Lisp_Object Vshow_help_function;
 
+/* If a string, the message displayed before displaying a help-echo
+   in the echo area.  */
+
+Lisp_Object Vpre_help_message;
+
 /* Nonzero means do menu prompting.  */
+
 static int menu_prompting;
 
 /* Character to see next line of menu prompt.  */
+
 static Lisp_Object menu_prompt_more_char;
 
 /* For longjmp to where kbd input is being done.  */
+
 static jmp_buf getcjmp;
 
 /* True while doing kbd input.  */
@@ -214,7 +225,7 @@ static struct kboard *ok_to_echo_at_next_pause;
    exists, and echo_message_buffer is eq to the current message
    buffer, we know that the message comes from echo_kboard.  */
 
-static struct kboard *echo_kboard;
+struct kboard *echo_kboard;
 
 /* The buffer used for echoing.  Set in echo_now, reset in
    cancel_echoing.  */
@@ -644,6 +655,10 @@ Lisp_Object Vdisable_point_adjustment;
 
 Lisp_Object Vglobal_disable_point_adjustment;
 
+/* The time when Emacs started being idle.  */
+
+static EMACS_TIME timer_idleness_start_time;
+
 \f
 /* Global variable declarations.  */
 
@@ -676,14 +691,12 @@ static void save_getcjmp ();
 static void restore_getcjmp P_ ((jmp_buf));
 static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
 static void clear_event P_ ((struct input_event *));
+static void any_kboard_state P_ ((void));
 
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
 static int cannot_suspend;
 
-#define        min(a,b)        ((a)<(b)?(a):(b))
-#define        max(a,b)        ((a)>(b)?(a):(b))
-
 /* Install the string STR as the beginning of the string of echoing,
    so that it serves as a prompt for the next character.
    Also start echoing.  */
@@ -879,8 +892,6 @@ static void
 add_command_key (key)
      Lisp_Object key;
 {
-  int size = XVECTOR (this_command_keys)->size;
-
   /* If reset-this-command-length was called recently, obey it now.
      See the doc string of that function for an explanation of why.  */
   if (before_command_restore_flag)
@@ -892,20 +903,15 @@ add_command_key (key)
       before_command_restore_flag = 0;
     }
 
-  if (this_command_key_count >= size)
-    {
-      Lisp_Object new_keys;
-
-      new_keys = Fmake_vector (make_number (size * 2), Qnil);
-      bcopy (XVECTOR (this_command_keys)->contents,
-            XVECTOR (new_keys)->contents,
-            size * sizeof (Lisp_Object));
-
-      this_command_keys = new_keys;
-    }
+  if (this_command_key_count >= ASIZE (this_command_keys))
+    this_command_keys = larger_vector (this_command_keys,
+                                      2 * ASIZE (this_command_keys),
+                                      Qnil);
 
-  XVECTOR (this_command_keys)->contents[this_command_key_count++] = key;
+  AREF (this_command_keys, this_command_key_count) = key;
+  ++this_command_key_count;
 }
+
 \f
 Lisp_Object
 recursive_edit_1 ()
@@ -977,30 +983,45 @@ This function is called by the editor initialization to begin editing.")
   ()
 {
   int count = specpdl_ptr - specpdl;
+  Lisp_Object buffer;
 
   command_loop_level++;
   update_mode_lines = 1;
 
+  if (command_loop_level
+      && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
+    buffer = Fcurrent_buffer ();
+  else
+    buffer = Qnil;
+
+  /* If we leave recursive_edit_1 below with a `throw' for instance,
+     like it is done in the splash screen display, we have to
+     make sure that we restore single_kboard as command_loop_1
+     would have done if it were left normally.  */
   record_unwind_protect (recursive_edit_unwind,
-                        (command_loop_level
-                         && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
-                        ? Fcurrent_buffer ()
-                        : Qnil);
+                        Fcons (buffer, single_kboard ? Qt : Qnil));
+
   recursive_edit_1 ();
   return unbind_to (count, Qnil);
 }
 
 Lisp_Object
-recursive_edit_unwind (buffer)
-     Lisp_Object buffer;
+recursive_edit_unwind (info)
+     Lisp_Object info;
 {
-  if (!NILP (buffer))
-    Fset_buffer (buffer);
-
+  if (BUFFERP (XCAR (info)))
+    Fset_buffer (XCAR (info));
+  
+  if (NILP (XCDR (info)))
+    any_kboard_state ();
+  else
+    single_kboard_state ();
+      
   command_loop_level--;
   update_mode_lines = 1;
   return Qnil;
 }
+
 \f
 static void
 any_kboard_state ()
@@ -1280,7 +1301,6 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 /* This is the actual command reading loop,
    sans error-handling encapsulation.  */
 
-EXFUN (Fcommand_execute, 4);
 static int read_key_sequence P_ ((Lisp_Object *, int, Lisp_Object,
                                  int, int, int));
 void safe_run_hooks P_ ((Lisp_Object));
@@ -1321,7 +1341,7 @@ command_loop_1 ()
   /* If displaying a message, resize the echo area window to fit
      that message's size exactly.  */
   if (!NILP (echo_area_buffer[0]))
-    resize_echo_area_axactly ();
+    resize_echo_area_exactly ();
 
   if (!NILP (Vdeferred_action_list))
     call0 (Vdeferred_action_function);
@@ -1636,7 +1656,7 @@ command_loop_1 ()
       /* If displaying a message, resize the echo area window to fit
         that message's size exactly.  */
       if (!NILP (echo_area_buffer[0]))
-       resize_echo_area_axactly ();
+       resize_echo_area_exactly ();
 
       if (!NILP (Vdeferred_action_list))
        safe_run_hooks (Qdeferred_action_function);
@@ -2031,14 +2051,25 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
        {
          if (STRINGP (help))
            {
-             int count = specpdl_ptr - specpdl;
+             int count = BINDING_STACK_SIZE ();
+
+             if (!help_echo_showing_p)
+               Vpre_help_message = current_message ();
+             
              specbind (Qmessage_truncate_lines, Qt);
              message3_nolog (help, STRING_BYTES (XSTRING (help)),
                              STRING_MULTIBYTE (help));
              unbind_to (count, Qnil);
            }
+         else if (STRINGP (Vpre_help_message))
+           {
+             message3_nolog (Vpre_help_message,
+                             STRING_BYTES (XSTRING (Vpre_help_message)),
+                             STRING_MULTIBYTE (Vpre_help_message));
+             Vpre_help_message = Qnil;
+           }
          else
-             message (0);
+           message (0);
        }
       
       help_echo_showing_p = STRINGP (help);
@@ -2095,6 +2126,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   volatile Lisp_Object also_record;
   volatile int reread;
   struct gcpro gcpro1, gcpro2;
+  EMACS_TIME last_idle_start;
 
   also_record = Qnil;
 
@@ -2142,10 +2174,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Undo what read_char_x_menu_prompt did when it unread
         additional keys returned by Fx_popup_menu.  */
       if (CONSP (c)
-         && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c)))
-         && NILP (XCDR (c)))
+         && EQ (XCDR (c), Qdisabled)
+         && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c))))
        c = XCAR (c);
-
+      
       /* If the queued event is something that used the mouse,
          set used_mouse_menu accordingly.  */
       if (used_mouse_menu
@@ -2326,15 +2358,21 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
        if (kb != current_kboard)
          {
-           Lisp_Object *tailp = &kb->kbd_queue;
+           Lisp_Object link = kb->kbd_queue;
            /* We shouldn't get here if we were in single-kboard mode!  */
            if (single_kboard)
              abort ();
-           while (CONSP (*tailp))
-             tailp = &XCDR (*tailp);
-           if (!NILP (*tailp))
-             abort ();
-           *tailp = Fcons (c, Qnil);
+           if (CONSP (link))
+             {
+               while (CONSP (XCDR (link)))
+                 link = XCDR (link);
+               if (!NILP (XCDR (link)))
+                 abort ();
+             }
+           if (!CONSP (link))
+             kb->kbd_queue = Fcons (c, Qnil);
+           else
+             XSETCDR (link, Fcons (c, Qnil));
            kb->kbd_queue_has_data = 1;
            current_kboard = kb;
            /* This is going to exit from read_char
@@ -2549,12 +2587,18 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 #ifdef MULTI_KBOARD
       if (! NILP (c) && (kb != current_kboard))
        {
-         Lisp_Object *tailp = &kb->kbd_queue;
-         while (CONSP (*tailp))
-           tailp = &XCDR (*tailp);
-         if (!NILP (*tailp))
-           abort ();
-         *tailp = Fcons (c, Qnil);
+         Lisp_Object link = kb->kbd_queue;
+         if (CONSP (link))
+           {
+             while (CONSP (XCDR (link)))
+               link = XCDR (link);
+             if (!NILP (XCDR (link)))
+               abort ();
+           }
+         if (!CONSP (link))
+           kb->kbd_queue = Fcons (c, Qnil);
+         else
+           XSETCDR (link, Fcons (c, Qnil));
          kb->kbd_queue_has_data = 1;
          c = Qnil;
          if (single_kboard)
@@ -2588,6 +2632,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  non_reread:
 
+  /* Record the last idle start time so that we can reset it
+     should the next event read be a help-echo.  */
+  last_idle_start = timer_idleness_start_time;
   timer_stop_idle ();
   start_polling ();
 
@@ -2667,7 +2714,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
-         POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
+         POSN_BUFFER_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
 
          also_record = c;
          Vunread_command_events = Fcons (c, Vunread_command_events);
@@ -2696,7 +2743,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   /* Now wipe the echo area, except for help events which do their
      own stuff with the echo area.  */
-  if (!CONSP (c) || !(EQ (Qhelp_echo, XCAR (c))))
+  if (!CONSP (c)
+      || (!(EQ (Qhelp_echo, XCAR (c)))
+         && !(EQ (Qswitch_frame, XCAR (c)))))
     {
       if (!NILP (echo_area_buffer[0]))
        safe_run_hooks (Qecho_area_clear_hook);
@@ -2804,6 +2853,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       object = Fnth (make_number (4), c);
       position = Fnth (make_number (5), c);
       show_help_echo (help, window, object, position, 0);
+
+      /* We stopped being idle for this event; undo that.  */
+      timer_idleness_start_time = last_idle_start;
       goto retry;
     }
   
@@ -3824,8 +3876,6 @@ swallow_events (do_display)
     redisplay_preserve_echo_area (7);
 }
 \f
-static EMACS_TIME timer_idleness_start_time;
-
 /* Record the start of when Emacs is idle,
    for the sake of running idle-time timers.  */
 
@@ -4534,11 +4584,16 @@ static int last_mouse_x;
 static int last_mouse_y;
 static unsigned long button_down_time;
 
-/* The maximum time between clicks to make a double-click,
-   or Qnil to disable double-click detection,
-   or Qt for no time limit.  */
+/* The maximum time between clicks to make a double-click, or Qnil to
+   disable double-click detection, or Qt for no time limit.  */
+
 Lisp_Object Vdouble_click_time;
 
+/* Maximum number of pixels the mouse may be moved between clicks
+   to make a double-click.  */
+
+int double_click_fuzz;
+
 /* The number of clicks in this multiple-click. */
 
 int double_click_count;
@@ -4642,12 +4697,35 @@ make_lispy_event (event)
                                     / sizeof (iso_lispy_function_keys[0])));
       else
 #endif
-       return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
-                                   event->modifiers,
-                                   Qfunction_key, Qnil,
-                                   lispy_function_keys, &func_key_syms,
-                                   (sizeof (lispy_function_keys)
-                                    / sizeof (lispy_function_keys[0])));
+
+#ifdef HAVE_X_WINDOWS
+      if (event->code - FUNCTION_KEY_OFFSET < 0
+         || (event->code - FUNCTION_KEY_OFFSET
+             >= sizeof lispy_function_keys / sizeof *lispy_function_keys))
+       {
+         /* EVENT->code is an unknown keysym, for example someone
+            assigned `ccaron' to a key in a locale where
+            XmbLookupString doesn't return a translation for it.  */
+         char *name;
+         Lisp_Object symbol;
+         
+         BLOCK_INPUT;
+         /* This returns a pointer to a static area.  Don't free it.  */
+         name = XKeysymToString (event->code);
+         symbol = name ? intern (name) : Qnil;
+         UNBLOCK_INPUT;
+         
+         if (!NILP (symbol))
+           return apply_modifiers (event->modifiers, symbol);
+       }
+#endif /* HAVE_X_WINDOWS */
+
+      return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+                                 event->modifiers,
+                                 Qfunction_key, Qnil,
+                                 lispy_function_keys, &func_key_syms,
+                                 (sizeof (lispy_function_keys)
+                                  / sizeof (lispy_function_keys[0])));
 
 #ifdef HAVE_MOUSE
       /* A mouse click.  Figure out where it is, decide whether it's
@@ -4662,6 +4740,7 @@ make_lispy_event (event)
        Lisp_Object position;
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
+       Lisp_Object window;
 
        position = Qnil;
 
@@ -4669,8 +4748,7 @@ make_lispy_event (event)
        if (event->kind == mouse_click)
          {
            int part;
-           FRAME_PTR f = XFRAME (event->frame_or_window);
-           Lisp_Object window;
+           struct frame *f = XFRAME (event->frame_or_window);
            Lisp_Object posn;
            Lisp_Object string_info = Qnil;
            int row, column;
@@ -4808,7 +4886,6 @@ make_lispy_event (event)
        else
          {
            /* It's a scrollbar click.  */
-           Lisp_Object window;
            Lisp_Object portion_whole;
            Lisp_Object part;
 
@@ -4836,14 +4913,35 @@ make_lispy_event (event)
        start_pos = *start_pos_ptr;
        *start_pos_ptr = Qnil;
 
-       is_double = (button == last_mouse_button
-                    && XINT (event->x) == last_mouse_x
-                    && XINT (event->y) == last_mouse_y
-                    && button_down_time != 0
-                    && (EQ (Vdouble_click_time, Qt)
-                        || (INTEGERP (Vdouble_click_time)
-                            && ((int)(event->timestamp - button_down_time)
-                                < XINT (Vdouble_click_time)))));
+       {
+         /* On window-system frames, use the value of
+            double-click-fuzz as is.  On other frames, interpret it
+            as a multiple of 1/8 characters.  */
+         struct frame *f;
+         int fuzz;
+
+         if (WINDOWP (event->frame_or_window))
+           f = XFRAME (XWINDOW (event->frame_or_window)->frame);
+         else if (FRAMEP (event->frame_or_window))
+           f = XFRAME (event->frame_or_window);
+         else
+           abort ();
+
+         if (FRAME_WINDOW_P (f))
+           fuzz = double_click_fuzz;
+         else
+           fuzz = double_click_fuzz / 8;
+
+         is_double = (button == last_mouse_button
+                      && (abs (XINT (event->x) - last_mouse_x) <= fuzz)
+                      && (abs (XINT (event->y) - last_mouse_y) <= fuzz)
+                      && button_down_time != 0
+                      && (EQ (Vdouble_click_time, Qt)
+                          || (INTEGERP (Vdouble_click_time)
+                              && ((int)(event->timestamp - button_down_time)
+                                  < XINT (Vdouble_click_time)))));
+       }
+       
        last_mouse_button = button;
        last_mouse_x = XINT (event->x);
        last_mouse_y = XINT (event->y);
@@ -5529,7 +5627,7 @@ parse_modifiers (symbol)
                                         STRING_BYTES (XSYMBOL (symbol)->name) - end),
                            Qnil);
 
-      if (modifiers & ~(((EMACS_INT)1 << VALBITS) - 1))
+      if (modifiers & ~VALMASK)
        abort ();
       XSETFASTINT (mask, modifiers);
       elements = Fcons (unmodified, Fcons (mask, Qnil));
@@ -5566,7 +5664,7 @@ apply_modifiers (modifiers, base)
   Lisp_Object cache, index, entry, new_symbol;
 
   /* Mask out upper bits.  We don't know where this value's been.  */
-  modifiers &= ((EMACS_INT)1 << VALBITS) - 1;
+  modifiers &= VALMASK;
 
   /* The click modifier never figures into cache indices.  */
   cache = Fget (base, Qmodifier_cache);
@@ -6252,25 +6350,6 @@ reinvoke_input_signal ()
 
 
 \f
-/* Return the prompt-string of a sparse keymap.
-   This is the first element which is a string.
-   Return nil if there is none.  */
-
-Lisp_Object
-map_prompt (map)
-     Lisp_Object map;
-{
-  while (CONSP (map))
-    {
-      register Lisp_Object tem;
-      tem = Fcar (map);
-      if (STRINGP (tem))
-       return tem;
-      map = Fcdr (map);
-    }
-  return Qnil;
-}
-
 static void menu_bar_item P_ ((Lisp_Object, Lisp_Object));
 static void menu_bar_one_keymap P_ ((Lisp_Object));
 
@@ -6787,19 +6866,19 @@ parse_menu_item (item, notreal, inmenubar)
     {
       /* We have to create a cachelist.  */
       CHECK_IMPURE (start);
-      XCDR (start) = Fcons (Fcons (Qnil, Qnil), XCDR (start));
+      XSETCDR (start, Fcons (Fcons (Qnil, Qnil), XCDR (start)));
       cachelist = XCAR (XCDR (start));
       newcache = 1;
       tem = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
       if (!NILP (keyhint))
        {
-         XCAR (cachelist) = XCAR (keyhint);
+         XSETCAR (cachelist, XCAR (keyhint));
          newcache = 0;
        }
       else if (STRINGP (tem))
        {
-         XCDR (cachelist) = Fsubstitute_command_keys (tem);
-         XCAR (cachelist) = Qt;
+         XSETCDR (cachelist, Fsubstitute_command_keys (tem));
+         XSETCAR (cachelist, Qt);
        }
     }
   
@@ -6857,10 +6936,10 @@ parse_menu_item (item, notreal, inmenubar)
              && ! NILP (Fget (def, Qmenu_alias)))
            def = XSYMBOL (def)->function;
          tem = Fwhere_is_internal (def, Qnil, Qt, Qnil);
-         XCAR (cachelist) = tem;
+         XSETCAR (cachelist, tem);
          if (NILP (tem))
            {
-             XCDR (cachelist) = Qnil;
+             XSETCDR (cachelist, Qnil);
              chkcache = 0;
            }
        }
@@ -6881,7 +6960,7 @@ parse_menu_item (item, notreal, inmenubar)
              if (STRINGP (XCDR (prefix)))
                tem = concat2 (tem, XCDR (prefix));
            }
-         XCDR (cachelist) = tem;
+         XSETCDR (cachelist, tem);
        }
     }
 
@@ -6889,7 +6968,7 @@ parse_menu_item (item, notreal, inmenubar)
   if (newcache && !NILP (tem))
     {
       tem = concat3 (build_string ("  ("), tem, build_string (")"));
-      XCDR (cachelist) = tem;
+      XSETCDR (cachelist, tem);
     }
 
   /* If we only want to precompute equivalent key bindings, stop here. */
@@ -7360,7 +7439,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
-      name = map_prompt (maps[mapno]);
+      name = Fkeymap_prompt (maps[mapno]);
       if (!NILP (name))
        break;
     }
@@ -7402,14 +7481,12 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
             to indicate that they came from a mouse menu,
             so that when present in last_nonmenu_event
             they won't confuse things.  */
-         for (tem = XCDR (value); !NILP (tem);
-              tem = XCDR (tem))
+         for (tem = XCDR (value); !NILP (tem); tem = XCDR (tem))
            {
              record_menu_key (XCAR (tem));
              if (SYMBOLP (XCAR (tem))
                  || INTEGERP (XCAR (tem)))
-               XCAR (tem)
-                 = Fcons (XCAR (tem), Qnil);
+               XSETCAR (tem, Fcons (XCAR (tem), Qdisabled));
            }
 
          /* If we got more than one event, put all but the first
@@ -7472,7 +7549,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
-      name = map_prompt (maps[mapno]);
+      name = Fkeymap_prompt (maps[mapno]);
       if (!NILP (name))
        break;
     }
@@ -8164,7 +8241,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          /* If we have a quit that was typed in another frame, and
             quit_throw_to_read_char switched buffers,
             replay to get the right keymap.  */
-         if (XINT (key) == quit_char && current_buffer != starting_buffer)
+         if (INTEGERP (key)
+             && XINT (key) == quit_char
+             && current_buffer != starting_buffer)
            {
              GROW_RAW_KEYBUF;
              XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
@@ -8399,8 +8478,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  /* Zap the position in key, so we know that we've
                     expanded it, and don't try to do so again.  */
-                 POSN_BUFFER_POSN (EVENT_START (key))
-                   = Fcons (posn, Qnil);
+                 POSN_BUFFER_SET_POSN (EVENT_START (key),
+                                       Fcons (posn, Qnil));
 
                  mock_input = t + 2;
                  goto replay_sequence;
@@ -9136,7 +9215,7 @@ a special event, so ignore the prefix argument and don't clear it.")
            {
              tem = Fnthcdr (Vhistory_length, Vcommand_history);
              if (CONSP (tem))
-               XCDR (tem) = Qnil;
+               XSETCDR (tem, Qnil);
            }
        }
 
@@ -10153,9 +10232,12 @@ struct event_head head_table[] = {
 void
 syms_of_keyboard ()
 {
+  Vpre_help_message = Qnil;
+  staticpro (&Vpre_help_message);
+  
   Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
-  
+
   /* Tool-bars.  */
   QCimage = intern (":image");
   staticpro (&QCimage);
@@ -10505,6 +10587,14 @@ t means double-clicks have no time limit and are detected\n\
 by position only.");
   Vdouble_click_time = make_number (500);
 
+  DEFVAR_INT ("double-click-fuzz", &double_click_fuzz,
+    "*Maximum mouse movement between clicks to make a double-click.\n\
+On window-system frames, value is the number of pixels the mouse may have\n\
+moved horizontally or vertically between two clicks to make a double-click.\n\
+On non window-system frames, value is interpreted in units of 1/8 characters\n\
+instead of pixels.");
+  double_click_fuzz = 3;
+  
   DEFVAR_BOOL ("inhibit-local-menu-bar-menus", &inhibit_local_menu_bar_menus,
     "*Non-nil means inhibit local map menu bar menus.");
   inhibit_local_menu_bar_menus = 0;
@@ -10640,7 +10730,7 @@ This is measured in microseconds.");
     "Normal hook run when clearing the echo area.");
 #endif
   Qecho_area_clear_hook = intern ("echo-area-clear-hook");
-  XSYMBOL (Qecho_area_clear_hook)->value = Qnil;
+  SET_SYMBOL_VALUE (Qecho_area_clear_hook, Qnil);
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
     "t means menu bar, specified Lucid style, needs to be recomputed.");