changeset 14406:7d998103f266

(Qtimer_event): New symbol. (read_char, kbd_buffer_get_event): Don't sleep past the next timer. (readable_events, kbd_buffer_get_event): Check for timer events. (make_lispy_event): Handle timer events. (timer_check): New function. (Vtimer_list): New variable. (syms_of_keyboard): Set up Qtimer_event and Vtimer_list.
author Richard M. Stallman <rms@gnu.org>
date Mon, 29 Jan 1996 04:53:02 +0000
parents 4aa693528ee3
children 78c37f6d697b
files src/keyboard.c
diffstat 1 files changed, 124 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/keyboard.c	Mon Jan 29 04:52:15 1996 +0000
+++ b/src/keyboard.c	Mon Jan 29 04:53:02 1996 +0000
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,89,93,94,95,96 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -435,6 +435,7 @@
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
+Lisp_Object Qtimer_event;
 /* Lisp_Object Qmouse_movement; - also an event header */
 
 /* Properties of event headers.  */
@@ -467,11 +468,15 @@
 Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
 Lisp_Object Qextended_command_history;
+EMACS_TIME timer_check ();
 
 extern char *x_get_keysym_name ();
 
 Lisp_Object Qpolling_period;
 
+/* List of active timers.  Appears in order of next scheduled event.  */
+Lisp_Object Vtimer_list;
+
 extern Lisp_Object Vprint_level, Vprint_length;
 
 /* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
@@ -1883,11 +1888,25 @@
 	  && XINT (Vauto_save_timeout) > 0)
 	{
 	  Lisp_Object tem0;
-	  int delay = delay_level * XFASTINT (Vauto_save_timeout) / 4;
+	  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 (delay, 0, 1, 1);
+	  tem0 = sit_for (EMACS_SECS (delay), EMACS_USECS (delay), 1, 1);
 	  restore_getcjmp (save_jump);
 
 	  if (EQ (tem0, Qt))
@@ -2322,6 +2341,7 @@
 static int
 readable_events ()
 {
+  timer_check (0);
   if (kbd_fetch_ptr != kbd_store_ptr)
     return 1;
 #ifdef HAVE_MOUSE
@@ -2501,6 +2521,7 @@
 {
   register int c;
   Lisp_Object obj;
+  EMACS_TIME next_timer_delay;
 
   if (noninteractive)
     {
@@ -2520,6 +2541,17 @@
 	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))
@@ -2545,7 +2577,9 @@
 	Lisp_Object minus_one;
 
 	XSETINT (minus_one, -1);
-	wait_reading_process_input (0, 0, minus_one, 1);
+	wait_reading_process_input (EMACS_SECS (next_timer_delay),
+				    EMACS_USECS (next_timer_delay),
+				    minus_one, 1);
 
 	if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
 	  /* Pass 1 for EXPECT since we just waited to have input.  */
@@ -2830,6 +2864,83 @@
   get_input_pending (&input_pending);
 }
 
+/* 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.
+
+   Returns the number of seconds to wait until the next timer fires.  If a
+   timer is triggering now, return zero seconds.
+   If no timer is active, return -1 seconds.
+
+   If a timer is triggering now, either queue a timer-event
+   or run the timer's handler function if DO_IT_NOW is nonzero.  */
+
+EMACS_TIME
+timer_check (do_it_now)
+     int do_it_now;
+{
+  EMACS_TIME nexttime;
+  EMACS_TIME now;
+  Lisp_Object timers = Vtimer_list;
+
+  EMACS_GET_TIME (now);
+  EMACS_SET_SECS (nexttime, -1);
+  EMACS_SET_USECS (nexttime, -1);
+
+  while (CONSP (timers))
+    {
+      int triggertime;
+      Lisp_Object timer, *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 (EMACS_TIME_NEG_P (difference))
+	{
+	  if (NILP (vector[0]))
+	    {
+	      if (do_it_now)
+		apply1 (vector[5], vector[6]);
+	      else
+		{
+		  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);
+
+		  /* Mark the timer as triggered to prevent problems if the lisp
+		     code fails to reschedule it right.  */
+		  vector[0] = Qt;
+		  EMACS_SET_SECS (nexttime, 0);
+		  EMACS_SET_USECS (nexttime, 0);
+		}
+	    }
+	}
+      else
+	return difference;
+    }
+  return nexttime;
+}
+
 /* Caches for modify_event_symbol.  */
 static Lisp_Object accent_key_syms;
 static Lisp_Object func_key_syms;
@@ -3297,6 +3408,9 @@
 				   / sizeof (lispy_function_keys[0])));
       break;
 
+    case timer_event:
+      return Fcons (Qtimer_event, Fcdr (event->frame_or_window));
+
 #ifdef HAVE_MOUSE
       /* A mouse click.  Figure out where it is, decide whether it's
          a press, click or drag, and build the appropriate structure.  */
@@ -7299,6 +7413,8 @@
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
+  Qtimer_event = intern ("timer-event");
+  staticpro (&Qtimer_event);
 
   Qmenu_enable = intern ("menu-enable");
   staticpro (&Qmenu_enable);
@@ -7664,6 +7780,10 @@
   DEFVAR_LISP ("column-number-mode", &Vcolumn_number_mode,
     "Non-nil enables display of the current column number in the mode line.");
   Vcolumn_number_mode = Qnil;
+
+  DEFVAR_LISP ("timer-list", &Vtimer_list,
+    "List of active timers in order of increasing time");
+  Vtimer_list = Qnil;
 }
 
 keys_of_keyboard ()