# HG changeset patch # User Richard M. Stallman # Date 822891182 0 # Node ID 7d998103f266fd95012e6467fcb24f3ed5a857a3 # Parent 4aa693528ee3bd5d4803b379cb67b15684f84fa7 (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. diff -r 4aa693528ee3 -r 7d998103f266 src/keyboard.c --- 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 ()