]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
*** empty log message ***
[gnu-emacs] / src / keyboard.c
index 53e918d30bae4e01242a674b173ec3f088db3cc8..927e986b2684438e6c9a0df90639a28604bb6aba 100644 (file)
@@ -202,7 +202,7 @@ int waiting_for_input;
 
 /* True while displaying for echoing.   Delays C-g throwing.  */
 
-static int echoing;
+int echoing;
 
 /* Non-null means we can start echoing at the next input pause even
    though there is something in the echo area.  */
@@ -219,7 +219,7 @@ static struct kboard *echo_kboard;
 /* The buffer used for echoing.  Set in echo_now, reset in
    cancel_echoing.  */
 
-static Lisp_Object echo_message_buffer;
+Lisp_Object echo_message_buffer;
 
 /* Nonzero means disregard local maps for the menu bar.  */
 static int inhibit_local_menu_bar_menus;
@@ -644,6 +644,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.  */
 
@@ -1280,10 +1284,11 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 /* This is the actual command reading loop,
    sans error-handling encapsulation.  */
 
-Lisp_Object Fcommand_execute ();
-static int read_key_sequence ();
-void safe_run_hooks ();
-static void adjust_point_for_property ();
+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));
+static void adjust_point_for_property P_ ((int));
 
 Lisp_Object
 command_loop_1 ()
@@ -1478,6 +1483,10 @@ command_loop_1 ()
          this variable differently.  */
       Vdisable_point_adjustment = Qnil;
 
+      /* Process filters and timers may have messed with deactivate-mark.
+        reset it before we execute the command. */
+      Vdeactivate_mark = Qnil;
+
       /* Execute the command.  */
 
       Vthis_command = cmd;
@@ -2090,6 +2099,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;
 
@@ -2583,6 +2593,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 ();
 
@@ -2799,6 +2812,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;
     }
   
@@ -3819,8 +3835,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.  */
 
@@ -4016,17 +4030,18 @@ timer_check (do_it_now)
          if (NILP (vector[0]))
            {
              int was_locked = single_kboard;
-             int count = specpdl_ptr - specpdl;
+             int count = BINDING_STACK_SIZE ();
+             Lisp_Object old_deactivate_mark = Vdeactivate_mark;
 
              /* Mark the timer as triggered to prevent problems if the lisp
                 code fails to reschedule it right.  */
              vector[0] = Qt;
 
              specbind (Qinhibit_quit, Qt);
-
+             
              call1 (Qtimer_event_handler, chosen_timer);
+             Vdeactivate_mark = old_deactivate_mark;
              timers_run++;
-
              unbind_to (count, Qnil);
 
              /* Resume allowing input from any kboard, if that was true before.  */
@@ -4711,14 +4726,14 @@ make_lispy_event (event)
                for (i = 0; i < XVECTOR (items)->size; i += 4)
                  {
                    Lisp_Object pos, string;
-                   string = XVECTOR (items)->contents[i + 1];
-                   pos = XVECTOR (items)->contents[i + 3];
+                   string = AREF (items, i + 1);
+                   pos = AREF (items, i + 3);
                    if (NILP (string))
                      break;
                    if (column >= XINT (pos)
                        && column < XINT (pos) + XSTRING (string)->size)
                      {
-                       item = XVECTOR (items)->contents[i];
+                       item = AREF (items, i);
                        break;
                      }
                  }
@@ -4777,7 +4792,16 @@ make_lispy_event (event)
                else if (part == 2)
                  posn = Qvertical_line;
                else
-                 XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+                 {
+                   Lisp_Object object;
+                   struct display_pos p;
+                   buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+                   posn = make_number (CHARPOS (p.pos));
+                   if (STRINGP (object))
+                     string_info
+                       = Fcons (object,
+                                make_number (CHARPOS (p.string_pos)));
+                 }
              }
 
            position
@@ -4810,15 +4834,14 @@ make_lispy_event (event)
          }
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 
-       if (button >= XVECTOR (button_down_location)->size)
+       if (button >= ASIZE (button_down_location))
          {
            button_down_location = larger_vector (button_down_location,
                                                  button + 1, Qnil);
            mouse_syms = larger_vector (mouse_syms, button + 1, Qnil);
          }
        
-       start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
-
+       start_pos_ptr = &AREF (button_down_location, button);
        start_pos = *start_pos_ptr;
        *start_pos_ptr = Qnil;
 
@@ -4855,12 +4878,11 @@ make_lispy_event (event)
            see if this was a click or a drag.  */
        else if (event->modifiers & up_modifier)
          {
-           /* If we did not see a down before this up,
-              ignore the up.  Probably this happened because
-              the down event chose a menu item.
-              It would be an annoyance to treat the release
-              of the button that chose the menu item
-              as a separate event.  */
+           /* If we did not see a down before this up, ignore the up.
+              Probably this happened because the down event chose a
+              menu item.  It would be an annoyance to treat the
+              release of the button that chose the menu item as a
+              separate event.  */
 
            if (!CONSP (start_pos))
              return Qnil;
@@ -4877,16 +4899,29 @@ make_lispy_event (event)
                Lisp_Object down;
 
                down = Fnth (make_number (2), start_pos);
-               if (EQ (event->x, XCAR (down))
-                   && EQ (event->y, XCDR (down)))
-                 {
-                   event->modifiers |= click_modifier;
-                 }
+               if (EQ (event->x, XCAR (down)) && EQ (event->y, XCDR (down)))
+                 /* Mouse hasn't moved.  */
+                 event->modifiers |= click_modifier;
                else
                  {
-                   button_down_time = 0;
-                   event->modifiers |= drag_modifier;
+                   Lisp_Object window1, window2, posn1, posn2;
+
+                   /* Avoid generating a drag event if the mouse
+                      hasn't actually moved off the buffer position.  */
+                   window1 = Fnth (make_number (0), position);
+                   posn1 = Fnth (make_number (1), position);
+                   window2 = Fnth (make_number (0), start_pos);
+                   posn2 = Fnth (make_number (1), start_pos);
+
+                   if (EQ (window1, window2) && EQ (posn1, posn2))
+                     event->modifiers |= click_modifier;
+                   else
+                     {
+                       button_down_time = 0;
+                       event->modifiers |= drag_modifier;
+                     }
                  }
+               
                /* Don't check is_double; treat this as multiple
                   if the down-event was multiple.  */
                if (double_click_count > 1)
@@ -5060,9 +5095,13 @@ make_lispy_event (event)
            else if (part == 3)
              posn = Qheader_line;
            else
-             XSETINT (posn,
-                      buffer_posn_from_coords (XWINDOW (window),
-                                               &column, &row));
+             {
+               Lisp_Object object;
+               struct display_pos p;
+               buffer_posn_from_coords (XWINDOW (window), &column, &row,
+                                        &object, &p);
+               posn = make_number (CHARPOS (p.pos));
+             }
          }
 
        {
@@ -5139,7 +5178,12 @@ make_lispy_event (event)
            else if (part == 3)
              posn = Qheader_line;
            else
-             XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+             {
+               Lisp_Object object;
+               struct display_pos p;
+               buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+               posn = make_number (CHARPOS (p.pos));
+             }
          }
 
        {
@@ -5251,7 +5295,12 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
          else if (area == 3)
            posn = Qheader_line;
          else
-           XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+           {
+             Lisp_Object object;
+             struct display_pos p;
+             buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+             posn = make_number (CHARPOS (p.pos));
+           }
        }
       else if (frame != 0)
        {
@@ -7739,6 +7788,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      int can_return_switch_frame;
      int fix_current_buffer;
 {
+  volatile Lisp_Object from_string;
   volatile int count = specpdl_ptr - specpdl;
 
   /* How many keys there are in the current key sequence.  */
@@ -7830,6 +7880,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   volatile int function_key_possible = 0;
   volatile int key_translation_possible = 0;
 
+  /* List of events for which a fake prefix key has been generated.  */
+  volatile Lisp_Object fake_prefixed_keys = Qnil;
+
   /* Save the status of key translation before each step,
      so that we can restore this after downcasing.  */
   Lisp_Object prev_fkey_map;
@@ -7844,6 +7897,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   int junk;
 #endif
 
+  struct gcpro gcpro1;
+
+  GCPRO1 (fake_prefixed_keys);
   raw_keybuf_count = 0;
 
   last_nonmenu_event = Qnil;
@@ -7892,6 +7948,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
   orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
   orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
+  from_string = Qnil;
 
   /* We jump here when the key sequence has been thoroughly changed, and
      we need to rescan it starting from the beginning.  When we jump here,
@@ -8075,6 +8132,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          if (EQ (key, Qt))
            {
              unbind_to (count, Qnil);
+             UNGCPRO;
              return -1;
            }
 
@@ -8172,10 +8230,12 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              window = POSN_WINDOW      (EVENT_START (key));
              posn   = POSN_BUFFER_POSN (EVENT_START (key));
 
-             if (CONSP (posn))
+             if (CONSP (posn)
+                 || (!NILP (fake_prefixed_keys)
+                     && !NILP (Fmemq (key, fake_prefixed_keys))))
                {
-                 /* We're looking at the second event of a
-                    sequence which we expanded before.  Set
+                 /* We're looking a second time at an event for which
+                    we generated a fake prefix key.  Set
                     last_real_key_start appropriately.  */
                  if (t > 0)
                    last_real_key_start = t - 1;
@@ -8258,18 +8318,22 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
              /* Expand mode-line and scroll-bar events into two events:
                 use posn as a fake prefix key.  */
-             if (SYMBOLP (posn))
+             if (SYMBOLP (posn)
+                 && (NILP (fake_prefixed_keys)
+                     || NILP (Fmemq (key, fake_prefixed_keys))))
                {
                  if (t + 1 >= bufsize)
                    error ("Key sequence too long");
-                 keybuf[t] = posn;
-                 keybuf[t+1] = key;
-                 mock_input = t + 2;
                  
-                 /* 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);
+                 keybuf[t]     = posn;
+                 keybuf[t + 1] = key;
+                 mock_input    = t + 2;
+
+                 /* Record that a fake prefix key has been generated
+                    for KEY.  Don't modify the event; this would
+                    prevent proper action when the event is pushed
+                    back tino unread-command-events.  */
+                 fake_prefixed_keys = Fcons (key, fake_prefixed_keys);
 
                  /* If on a mode line string with a local keymap,
                     reconsider the key sequence with that keymap.  */
@@ -8296,6 +8360,35 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  goto replay_key;
                }
+             else if (CONSP (POSN_STRING (EVENT_START (key)))
+                      && NILP (from_string))
+               {
+                 /* For a click on a string, i.e. overlay string or a
+                    string displayed via the `display' property,
+                    consider `local-map' and `keymap' properties of
+                    that string.  */
+                 Lisp_Object string, pos, map, map2;
+
+                 string = POSN_STRING (EVENT_START (key));
+                 pos = XCDR (string);
+                 string = XCAR (string);
+                 if (XINT (pos) >= 0
+                     && XINT (pos) < XSTRING (string)->size)
+                   {
+                     map = Fget_text_property (pos, Qlocal_map, string);
+                     if (!NILP (map))
+                       orig_local_map = map;
+                     map2 = Fget_text_property (pos, Qkeymap, string);
+                     if (!NILP (map2))
+                       orig_keymap = map2;
+
+                     if (!NILP (map) || !NILP (map2))
+                       {
+                         from_string = string;
+                         goto replay_sequence;
+                       }
+                   }
+               }
            }
          else if (CONSP (XCDR (key))
                   && CONSP (EVENT_START (key))
@@ -8809,6 +8902,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
   
 
+  UNGCPRO;
   return t;
 }
 
@@ -9801,7 +9895,7 @@ quit_throw_to_read_char ()
   if (FRAMEP (internal_last_event_frame)
       && !EQ (internal_last_event_frame, selected_frame))
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
-                    Qnil, 0);
+                    0, 0);
 
   _longjmp (getcjmp, 1);
 }
@@ -9946,19 +10040,35 @@ wipe_kboard (kb)
 }
 
 #ifdef MULTI_KBOARD
+
+/* Free KB and memory referenced from it.  */
+
 void
 delete_kboard (kb)
-  KBOARD *kb;
+     KBOARD *kb;
 {
   KBOARD **kbp;
+  
   for (kbp = &all_kboards; *kbp != kb; kbp = &(*kbp)->next_kboard)
     if (*kbp == NULL)
       abort ();
   *kbp = kb->next_kboard;
+
+  /* Prevent a dangling reference to KB.  */
+  if (kb == current_kboard
+      && FRAMEP (selected_frame)
+      && FRAME_LIVE_P (XFRAME (selected_frame)))
+    {
+      current_kboard = XFRAME (selected_frame)->kboard;
+      if (current_kboard == kb)
+       abort ();
+    }
+  
   wipe_kboard (kb);
   xfree (kb);
 }
-#endif
+
+#endif /* MULTI_KBOARD */
 
 void
 init_keyboard ()
@@ -10555,7 +10665,7 @@ The elements of the list are event types that may have menu bar bindings.");
     "Per-terminal keymap that overrides all other local keymaps.\n\
 If this variable is non-nil, it is used as a keymap instead of the\n\
 buffer's local map, and the minor mode keymaps and text property keymaps.\n\
-This variable is intended to let commands such as `universal-argumemnt'\n\
+This variable is intended to let commands such as `universal-argument'\n\
 set up a different keymap for reading the next command.");
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,