changeset 14612:0019d219990c

(swallow_events): New arg DO_DISPLAY. (swallow_events): Process timer_event events here. (detect_input_pending_run_timers): New function. (Vtimer_idle_list): New variable. (syms_of_keyboard): Set up Lisp var. (timer_check): Check for idle-time timers too. Expect timers to have 8 slots. Initialize triggertime. (timer_start_idle, timer_stop_idle): New functions. (get_input_pending): New arg do_timers_now. (readable_events): Likewise. (Finput_pending_p): Use get_input_pending, so we can specify 1 for do_timers_now. (timer_check): Check for difference being zero.
author Karl Heuer <kwzh@gnu.org>
date Wed, 21 Feb 1996 21:06:51 +0000
parents 69fca906f068
children 386831bc4a4e
files src/keyboard.c
diffstat 1 files changed, 211 insertions(+), 126 deletions(-) [+]
line wrap: on
line diff
--- a/src/keyboard.c	Wed Feb 21 20:54:46 1996 +0000
+++ b/src/keyboard.c	Wed Feb 21 21:06:51 1996 +0000
@@ -474,9 +474,12 @@
 
 Lisp_Object Qpolling_period;
 
-/* List of active timers.  Appears in order of next scheduled event.  */
+/* List of absolute timers.  Appears in order of next scheduled event.  */
 Lisp_Object Vtimer_list;
 
+/* List of idle time timers.  Appears in order of next scheduled event.  */
+Lisp_Object Vtimer_idle_list;
+
 extern Lisp_Object Vprint_level, Vprint_length;
 
 /* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
@@ -1809,6 +1812,8 @@
       goto non_reread;
     }
 
+  timer_start_idle ();
+
   /* If in middle of key sequence and minibuffer not active,
      start echoing if enough time elapses.  */
 
@@ -1888,25 +1893,11 @@
 	  && XINT (Vauto_save_timeout) > 0)
 	{
 	  Lisp_Object tem0;
-	  EMACS_TIME timer_delay;
-	  EMACS_TIME delay, difference;
-
-	  EMACS_SET_SECS (delay,
-			  delay_level * XFASTINT (Vauto_save_timeout) / 4);
-	  EMACS_SET_USECS (delay, 0);
-
-	  /* Don't wait longer than until the next timer will fire.  */
-	  timer_delay = timer_check (0);
-	  if (! EMACS_TIME_NEG_P (timer_delay))
-	    {
-	      EMACS_SUB_TIME (difference, timer_delay, delay);
-	      if (EMACS_TIME_NEG_P (difference))
-		delay = timer_delay;
-	    }
 
 	  save_getcjmp (save_jump);
 	  restore_getcjmp (local_getcjmp);
-	  tem0 = sit_for (EMACS_SECS (delay), EMACS_USECS (delay), 1, 1);
+	  tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
+			  0, 1, 1);
 	  restore_getcjmp (save_jump);
 
 	  if (EQ (tem0, Qt))
@@ -1938,7 +1929,7 @@
 	    = XCONS (current_kboard->kbd_queue)->cdr;
 	  if (NILP (current_kboard->kbd_queue))
 	    current_kboard->kbd_queue_has_data = 0;
-	  input_pending = readable_events ();
+	  input_pending = readable_events (0);
 #ifdef MULTI_FRAME
 	  if (EVENT_HAS_PARAMETERS (c)
 	      && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
@@ -2026,6 +2017,11 @@
 
  non_reread:
 
+  /* Now that we have read an event, Emacs is not idle--
+     unless the event was a timer event.  */
+  if (! (CONSP (c) && EQ (XCONS (c)->car, Qtimer_event)))
+    timer_stop_idle ();
+
   start_polling ();
 
   if (NILP (c))
@@ -2293,10 +2289,10 @@
 	 input has been processed.  If the only input available was
 	 the sort that we have just disabled, then we need to call
 	 redisplay.  */
-      if (!readable_events ())
+      if (!readable_events (1))
 	{
 	  redisplay_preserve_echo_area ();
-	  get_input_pending (&input_pending);
+	  get_input_pending (&input_pending, 1);
 	}
     }
 }
@@ -2346,9 +2342,10 @@
 /* Return true iff there are any events in the queue that read-char
    would return.  If this returns false, a read-char would block.  */
 static int
-readable_events ()
+readable_events (do_timers_now)
+     int do_timers_now;
 {
-  timer_check (1);
+  timer_check (do_timers_now);
   if (kbd_fetch_ptr != kbd_store_ptr)
     return 1;
 #ifdef HAVE_MOUSE
@@ -2548,17 +2545,6 @@
 	break;
 #endif
 
-      /* Check when the next timer fires.  */
-      next_timer_delay = timer_check (0);
-      if (EMACS_SECS (next_timer_delay) == 0
-	  && EMACS_USECS (next_timer_delay) == 0)
-	break;
-      if (EMACS_TIME_NEG_P (next_timer_delay))
-	{
-	  EMACS_SET_SECS (next_timer_delay, 0);
-	  EMACS_SET_USECS (next_timer_delay, 0);
-	}
-
       /* If the quit flag is set, then read_char will return
 	 quit_char, so that counts as "available input."  */
       if (!NILP (Vquit_flag))
@@ -2584,9 +2570,7 @@
 	Lisp_Object minus_one;
 
 	XSETINT (minus_one, -1);
-	wait_reading_process_input (EMACS_SECS (next_timer_delay),
-				    EMACS_USECS (next_timer_delay),
-				    minus_one, 1);
+	wait_reading_process_input (0, 0, minus_one, 1);
 
 	if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
 	  /* Pass 1 for EXPECT since we just waited to have input.  */
@@ -2631,7 +2615,7 @@
 	     and process it again.  */
 	  copy = *event;
 	  kbd_fetch_ptr = event + 1;
-	  input_pending = readable_events ();
+	  input_pending = readable_events (0);
 	  x_handle_selection_request (&copy);
 #else
 	  /* We're getting selection request events, but we don't have
@@ -2648,7 +2632,7 @@
 	  /* Remove it from the buffer before processing it.  */
 	  copy = *event;
 	  kbd_fetch_ptr = event + 1;
-	  input_pending = readable_events ();
+	  input_pending = readable_events (0);
 	  x_handle_selection_clear (&copy);
 #else
 	  /* We're getting selection request events, but we don't have
@@ -2689,7 +2673,7 @@
       else if (event->kind == menu_bar_activate_event)
 	{
 	  kbd_fetch_ptr = event + 1;
-	  input_pending = readable_events ();
+	  input_pending = readable_events (0);
 	  x_activate_menubar (XFRAME (event->frame_or_window));
 	}
 #endif
@@ -2801,7 +2785,7 @@
        something for us to read!  */
     abort ();
 
-  input_pending = readable_events ();
+  input_pending = readable_events (0);
 
 #ifdef MULTI_FRAME
   Vlast_event_frame = internal_last_event_frame;
@@ -2814,7 +2798,8 @@
    then return, without reading any user-visible events.  */
 
 void
-swallow_events ()
+swallow_events (do_display)
+     int do_display;
 {
   while (kbd_fetch_ptr != kbd_store_ptr)
     {
@@ -2838,7 +2823,7 @@
 	     and process it again.  */
 	  copy = *event;
 	  kbd_fetch_ptr = event + 1;
-	  input_pending = readable_events ();
+	  input_pending = readable_events (0);
 	  x_handle_selection_request (&copy);
 #else
 	  /* We're getting selection request events, but we don't have
@@ -2856,7 +2841,7 @@
 	  copy = *event;
 
 	  kbd_fetch_ptr = event + 1;
-	  input_pending = readable_events ();
+	  input_pending = readable_events (0);
 	  x_handle_selection_clear (&copy);
 #else
 	  /* We're getting selection request events, but we don't have
@@ -2864,13 +2849,69 @@
 	  abort ();
 #endif
 	}
+      else if (event->kind == timer_event)
+	{
+	  Lisp_Object tem, lisp_event;
+	  int was_locked = single_kboard;
+
+	  tem = get_keymap_1 (Vspecial_event_map, 0, 0);
+	  tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
+			    1);
+	  lisp_event = Fcons (Qtimer_event,
+			      Fcons (Fcdr (event->frame_or_window), Qnil));
+	  kbd_fetch_ptr = event + 1;
+	  if (kbd_fetch_ptr == kbd_store_ptr)
+	    input_pending = 0;
+	  Fcommand_execute (tem, Qnil, Fvector (1, &lisp_event));
+	  if (do_display)
+	    redisplay_preserve_echo_area ();
+
+	  /* Resume allowing input from any kboard, if that was true before.  */
+	  if (!was_locked)
+	    any_kboard_state ();
+	}
       else
 	break;
     }
 
-  get_input_pending (&input_pending);
+  get_input_pending (&input_pending, 1);
 }
 
+static EMACS_TIME timer_idleness_start_time;
+
+/* Record the start of when Emacs is idle,
+   for the sake of running idle-time timers.  */
+
+timer_start_idle ()
+{
+  Lisp_Object timers;
+
+  /* If we are already in the idle state, do nothing.  */
+  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+    return;
+
+  EMACS_GET_TIME (timer_idleness_start_time);
+
+  /* Mark all idle-time timers as once again candidates for running.  */
+  for (timers = Vtimer_idle_list; CONSP (timers); timers = XCONS (timers)->cdr)
+    {
+      Lisp_Object timer;
+
+      timer = XCONS (timers)->car;
+
+      if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+	continue;
+      XVECTOR (timer)->contents[0] = Qnil;
+    }
+}
+
+/* Record that Emacs is no longer idle, so stop running idle-time timers.  */
+
+timer_stop_idle ()
+{
+  EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
+}
+
 /* Check whether a timer has fired.  To prevent larger problems we simply
    disregard elements that are not proper timers.  Do not make a circular
    timer list for the time being.
@@ -2892,6 +2933,7 @@
   /* Nonzero if we generate some events.  */
   int events_generated = 0;
   struct gcpro gcpro1, gcpro2;
+  int listnum;
 
   EMACS_SET_SECS (nexttime, -1);
   EMACS_SET_USECS (nexttime, -1);
@@ -2900,89 +2942,112 @@
   timer = Qnil;
   GCPRO2 (timers, timer);
 
-  if (CONSP (timers))
+  if (CONSP (Vtimer_list) || CONSP (Vtimer_idle_list))
     EMACS_GET_TIME (now);
 
-  while (CONSP (timers))
+  for (listnum = 0; listnum < 2; listnum++)
     {
-      int triggertime;
-      Lisp_Object *vector;
-      EMACS_TIME timer_time;
-      EMACS_TIME difference;
-
-      timer = XCONS (timers)->car;
-      timers = XCONS (timers)->cdr;
-
-      if (!VECTORP (timer) || XVECTOR (timer)->size != 7)
-	continue;
-      vector = XVECTOR (timer)->contents;
-
-      if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
-	  || !INTEGERP (vector[3]))
-	continue;
-
-      EMACS_SET_SECS (timer_time,
-		      (XINT (vector[1]) << 16) | (XINT (vector[2])));
-      EMACS_SET_USECS (timer_time, XINT (vector[3]));
-      EMACS_SUB_TIME (difference, timer_time, now);
-      /* If event is past, run it if it hasn't been run.  */
-      if (EMACS_TIME_NEG_P (difference))
+      EMACS_TIME compare_time;
+
+      /* Always first scan the absolute timer list.  */
+      if (listnum == 0)
+	{
+	  timers = Vtimer_list;
+	  compare_time = now;
+	}
+      /* If Emacs is idle, scan the idle timer list
+	 using the length of idleness as the time value.  */
+      else if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+	{
+	  timers = Vtimer_idle_list;
+	  EMACS_SUB_TIME (compare_time, now, timer_idleness_start_time);
+	}
+      else
+	break;
+
+      while (CONSP (timers))
 	{
-	  if (NILP (vector[0]))
+	  int triggertime = EMACS_SECS (now);
+	  Lisp_Object *vector;
+	  EMACS_TIME timer_time;
+	  EMACS_TIME difference;
+
+	  timer = XCONS (timers)->car;
+	  timers = XCONS (timers)->cdr;
+
+	  if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+	    continue;
+	  vector = XVECTOR (timer)->contents;
+
+	  if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+	      || !INTEGERP (vector[3]))
+	    continue;
+
+	  EMACS_SET_SECS (timer_time,
+			  (XINT (vector[1]) << 16) | (XINT (vector[2])));
+	  EMACS_SET_USECS (timer_time, XINT (vector[3]));
+	  EMACS_SUB_TIME (difference, timer_time, compare_time);
+	  /* If event is past, run it if it hasn't been run.  */
+	  if (EMACS_TIME_NEG_P (difference)
+	      || (EMACS_SECS (difference) == 0
+		  && EMACS_USECS (difference) == 0))
 	    {
-	      /* Mark the timer as triggered to prevent problems if the lisp
-		 code fails to reschedule it right.  */
-	      vector[0] = Qt;
-
-	      /* Run the timer or queue a timer event.  */
-	      if (do_it_now)
+	      if (NILP (vector[0]))
 		{
-		  Lisp_Object tem, event;
-		  int was_locked = single_kboard;
-
-		  tem = get_keymap_1 (Vspecial_event_map, 0, 0);
-		  tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
-				    1);
-		  event = Fcons (Qtimer_event, Fcons (timer, Qnil));
-		  Fcommand_execute (tem, Qnil, Fvector (1, &event));
-
-		  /* Resume allowing input from any kboard, if that was true before.  */
-		  if (!was_locked)
-		    any_kboard_state ();
-
-		  /* Since we have handled the event,
-		     we don't need to tell the caller to wake up and do it.  */
-		}
-	      else
-		{
-		  /* Generate a timer event so the caller will handle it.  */
-		  struct input_event event;
-
-		  event.kind = timer_event;
-		  event.modifiers = 0;
-		  event.x = event.y = Qnil;
-		  event.timestamp = triggertime;
-		  /* Store the timer in the frame slot.  */
-		  event.frame_or_window = Fcons (Fselected_frame (), timer);
-		  kbd_buffer_store_event (&event);
-
-		  /* Tell caller to handle this event right away.  */
-		  events_generated = 1;
-		  EMACS_SET_SECS (nexttime, 0);
-		  EMACS_SET_USECS (nexttime, 0);
+		  /* Mark the timer as triggered to prevent problems if the lisp
+		     code fails to reschedule it right.  */
+		  vector[0] = Qt;
+
+		  /* Run the timer or queue a timer event.  */
+		  if (do_it_now)
+		    {
+		      Lisp_Object tem, event;
+		      int was_locked = single_kboard;
+
+		      tem = get_keymap_1 (Vspecial_event_map, 0, 0);
+		      tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
+					1);
+		      event = Fcons (Qtimer_event, Fcons (timer, Qnil));
+		      Fcommand_execute (tem, Qnil, Fvector (1, &event));
+
+		      /* Resume allowing input from any kboard, if that was true before.  */
+		      if (!was_locked)
+			any_kboard_state ();
+
+		      /* Since we have handled the event,
+			 we don't need to tell the caller to wake up and do it.  */
+		    }
+		  else
+		    {
+		      /* Generate a timer event so the caller will handle it.  */
+		      struct input_event event;
+
+		      event.kind = timer_event;
+		      event.modifiers = 0;
+		      event.x = event.y = Qnil;
+		      event.timestamp = triggertime;
+		      /* Store the timer in the frame slot.  */
+		      event.frame_or_window = Fcons (Fselected_frame (), timer);
+		      kbd_buffer_store_event (&event);
+
+		      /* Tell caller to handle this event right away.  */
+		      events_generated = 1;
+		      EMACS_SET_SECS (nexttime, 0);
+		      EMACS_SET_USECS (nexttime, 0);
+		    }
 		}
 	    }
-	}
-      else
-	/* When we encounter a timer that is still waiting,
-	   return the amount of time to wait before it is ripe.  */
-	{
-	  UNGCPRO;
-	  /* But if we generated an event,
-	     tell the caller to handle it now.  */
-	  if (events_generated)
-	    return nexttime;
-	  return difference;
+	  else
+	    /* When we encounter a timer that is still waiting,
+	       return the amount of time to wait before it is ripe.  */
+	    {
+	      UNGCPRO;
+	      /* But if we generated an event,
+		 tell the caller to handle it now.  */
+	      if (events_generated)
+		return nexttime;
+	      return difference;
+	    }
 	}
     }
   /* No timers are pending in the future.  */
@@ -4428,14 +4493,17 @@
 /* Store into *addr a value nonzero if terminal input chars are available.
    Serves the purpose of ioctl (0, FIONREAD, addr)
    but works even if FIONREAD does not exist.
-   (In fact, this may actually read some input.)  */
+   (In fact, this may actually read some input.)
+
+   If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.  */
 
 static void
-get_input_pending (addr)
+get_input_pending (addr, do_timers_now)
      int *addr;
+     int do_timers_now;
 {
   /* First of all, have we already counted some input?  */
-  *addr = !NILP (Vquit_flag) || readable_events ();
+  *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
 
   /* If input is being read as it arrives, and we have none, there is none.  */
   if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
@@ -4443,7 +4511,7 @@
 
   /* Try to read some input and see how much we get.  */
   gobble_input (0);
-  *addr = !NILP (Vquit_flag) || readable_events ();
+  *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
 }
 
 /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
@@ -6786,11 +6854,23 @@
   return nmaps;
 }
 
+/* Return nonzero if input events are pending.  */
 
 detect_input_pending ()
 {
   if (!input_pending)
-    get_input_pending (&input_pending);
+    get_input_pending (&input_pending, 0);
+
+  return input_pending;
+}
+
+/* Return nonzero if input events are pending.
+   Execute timers immediately; don't make events for them.  */
+
+detect_input_pending_run_timers ()
+{
+  if (!input_pending)
+    get_input_pending (&input_pending, 1);
 
   return input_pending;
 }
@@ -6811,7 +6891,8 @@
   if (!NILP (Vunread_command_events) || unread_command_char != -1)
     return (Qt);
 
-  return detect_input_pending () ? Qt : Qnil;
+  get_input_pending (&input_pending, 1);
+  return input_pending > 0 ? Qt : Qnil;
 }
 
 DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
@@ -7862,8 +7943,12 @@
   Vcolumn_number_mode = Qnil;
 
   DEFVAR_LISP ("timer-list", &Vtimer_list,
-    "List of active timers in order of increasing time");
+    "List of active absolute time timers in order of increasing time");
   Vtimer_list = Qnil;
+
+  DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
+    "List of active idle-time timers in order of increasing time");
+  Vtimer_idle_list = Qnil;
 }
 
 keys_of_keyboard ()