Avoid (most) uses of XCAR/XCDR as lvalues, for flexibility in experimenting
[bpt/emacs.git] / src / keyboard.c
index 5445761..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"
@@ -224,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.  */
@@ -690,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.  */
@@ -984,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 ()
@@ -1287,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));
@@ -2345,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
@@ -2568,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)
@@ -2689,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);
@@ -2718,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);
@@ -4670,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
@@ -4690,6 +4740,7 @@ make_lispy_event (event)
        Lisp_Object position;
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
+       Lisp_Object window;
 
        position = Qnil;
 
@@ -4697,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;
@@ -4836,7 +4886,6 @@ make_lispy_event (event)
        else
          {
            /* It's a scrollbar click.  */
-           Lisp_Object window;
            Lisp_Object portion_whole;
            Lisp_Object part;
 
@@ -4864,16 +4913,34 @@ make_lispy_event (event)
        start_pos = *start_pos_ptr;
        *start_pos_ptr = Qnil;
 
-       is_double = (button == last_mouse_button
-                    && (abs (XINT (event->x) - last_mouse_x)
-                        <= double_click_fuzz)
-                    && (abs (XINT (event->y) - last_mouse_y)
-                        <= double_click_fuzz)
-                    && 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);
@@ -5560,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));
@@ -5597,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);
@@ -6283,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));
 
@@ -6818,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);
        }
     }
   
@@ -6888,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;
            }
        }
@@ -6912,7 +6960,7 @@ parse_menu_item (item, notreal, inmenubar)
              if (STRINGP (XCDR (prefix)))
                tem = concat2 (tem, XCDR (prefix));
            }
-         XCDR (cachelist) = tem;
+         XSETCDR (cachelist, tem);
        }
     }
 
@@ -6920,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. */
@@ -7391,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;
     }
@@ -7438,7 +7486,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
              record_menu_key (XCAR (tem));
              if (SYMBOLP (XCAR (tem))
                  || INTEGERP (XCAR (tem)))
-               XCAR (tem) = Fcons (XCAR (tem), Qdisabled);
+               XSETCAR (tem, Fcons (XCAR (tem), Qdisabled));
            }
 
          /* If we got more than one event, put all but the first
@@ -7501,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;
     }
@@ -8430,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;
@@ -9167,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);
            }
        }
 
@@ -10541,8 +10589,10 @@ by position only.");
 
   DEFVAR_INT ("double-click-fuzz", &double_click_fuzz,
     "*Maximum mouse movement between clicks to make a double-click.\n\
-Value is the number of pixels the mouse may have moved horizontally or\n\
-vertically between two clicks to make a double-click.");
+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,
@@ -10680,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.");