/* * ExecuteTimers: checks to see if any currently pending timers have * gone off, and if so, execute them, delete them, etc, setting the * current_exec_timer, so that we can't remove the timer while its * still executing. * * changed the behavior: timers will not hook while we are waiting. */ void ExecuteTimers (void) { Timeval right_now; Timer * current, *next; int old_from_server = from_server; get_time(&right_now); while (PendingTimers && time_diff(right_now, PendingTimers->time) < 0) { int old_refnum; old_refnum = current_window->refnum; current = PendingTimers; unlink_timer(current); /* Reschedule the timer if necessary */ if (current->events < 0 || (current->events != 1)) { next = clone_timer(current); if (next->events != -1) next->events--; next->time = time_add(next->time, next->interval); schedule_timer(next); } /* * Restore from_server and current_window from when the * timer was registered */ make_window_current_by_refnum(current->window); if (is_server_open(current->server)) from_server = current->server; else if (is_server_open(current_window->server)) from_server = current_window->server; else from_server = NOSERV; /* * If a callback function was registered, then * we use it. If no callback function was registered, * then we use ''parse_line''. */ get_time(&right_now); now = right_now; if (current->callback) (*current->callback)(current->callback_data); else parse_line("TIMER", current->command, current->subargs ? current->subargs : empty_string, 0,0); from_server = old_from_server; make_window_current_by_refnum(old_refnum); delete_timer(current); } }
/* * ExecuteTimers: checks to see if any currently pending timers have * gone off, and if so, execute them, delete them, etc, setting the * current_exec_timer, so that we can't remove the timer while its * still executing. * * changed the behavior: timers will not hook while we are waiting. */ void ExecuteTimers (void) { Timeval right_now; Timer * current, *next; int old_from_server = from_server; get_time(&right_now); while (PendingTimers && time_diff(right_now, PendingTimers->time) < 0) { int old_refnum; old_refnum = current_window->refnum; current = PendingTimers; unlink_timer(current); /* Reschedule the timer if necessary */ if (current->events < 0 || (current->events != 1)) { next = clone_timer(current); if (next->events != -1) next->events--; next->time = time_add(next->time, next->interval); schedule_timer(next); } if (current->domain == SERVER_TIMER) { if (!is_server_valid(current->domref)) { if (current->cancelable) goto advance; /* Otherwise, pretend you were a "GENERAL" type */ } else { from_server = current->domref; make_window_current_by_refnum( get_winref_by_servref(from_server)); } } else if (current->domain == WINDOW_TIMER) { if (!get_window_by_refnum(current->domref)) { if (current->cancelable) goto advance; /* Otherwise, pretend you were a "GENERAL" type */ } else { make_window_current_by_refnum(current->domref); from_server = current_window->server; } } else { /* General timers focus on the current window. */ if (current_window) { if (current_window->server != from_server) from_server = current_window->server; } else { if (from_server != NOSERV) make_window_current_by_refnum( get_winref_by_servref(from_server)); } } /* * If a callback function was registered, then * we use it. If no callback function was registered, * then we call the lambda function. */ get_time(&right_now); now = right_now; if (current->callback) (*current->callback)(current->callback_data); else call_lambda_command("TIMER", current->command, current->subargs); from_server = old_from_server; make_window_current_by_refnum(old_refnum); advance: delete_timer(current); } }
/* * You call this to register a timer callback. * * The arguments: * update: This should be 1 if we're updating the specified refnum * refnum_want: The refnum requested. This should only be sepcified * by the user, functions wanting callbacks should specify * the empty string, which means "dont care". * The rest of the arguments are dependant upon the value of "callback" * -- if "callback" is NULL then: * callback: NULL * what: some ircII commands to run when the timer goes off * subargs: what to use to expand $0's, etc in the 'what' variable. * * -- if "callback" is non-NULL then: * callback: function to call when timer goes off * what: argument to pass to "callback" function. Should be some * non-auto storage, perhaps a struct or a malloced char * * array. The caller is responsible for disposing of this * area when it is called, since the timer mechanism does not * know anything of the nature of the argument. * subargs: should be NULL, its ignored anyhow. */ char *add_timer (int update, const char *refnum_want, double interval, long events, int (callback) (void *), void *commands, const char *subargs, TimerDomain domain, int domref, int cancelable) { Timer *ntimer, *otimer = NULL; char * refnum_got = NULL; Timeval right_now; char * retval; /* XXX Eh, maybe it's a hack to check this here. */ if (interval < 0.01 && events == -1) { say("You can't infinitely repeat a timer that runs more " "than 100 times a second."); return NULL; } right_now = get_time(NULL); if (update) { if (!(otimer = get_timer(refnum_want))) update = 0; /* Ok so we're not updating! */ } if (update) { unlink_timer(otimer); ntimer = clone_timer(otimer); delete_timer(otimer); if (interval != -1) { ntimer->interval = double_to_timeval(interval); ntimer->time = time_add(right_now, ntimer->interval); } if (events != -2) ntimer->events = events; if (callback) { /* Delete the previous timer, if necessary */ if (ntimer->command) new_free(&ntimer->command); if (ntimer->subargs) new_free(&ntimer->subargs); ntimer->callback = callback; /* Unfortunately, command is "sometimes const". */ ntimer->callback_data = commands; ntimer->subargs = NULL; } else { if (ntimer->callback) ntimer->callback = NULL; malloc_strcpy(&ntimer->command, (const char *)commands); malloc_strcpy(&ntimer->subargs, subargs); } if (domref != -1) ntimer->domref = domref; } else { if (create_timer_ref(refnum_want, &refnum_got) == -1) { say("TIMER: Refnum '%s' already exists", refnum_want); return NULL; } ntimer = new_timer(); ntimer->ref = refnum_got; ntimer->interval = double_to_timeval(interval); ntimer->time = time_add(right_now, ntimer->interval); ntimer->events = events; ntimer->callback = callback; /* Unfortunately, command is "sometimes const". */ if (callback) ntimer->callback_data = commands; else malloc_strcpy(&ntimer->command, (const char *)commands); malloc_strcpy(&ntimer->subargs, subargs); ntimer->domain = domain; ntimer->domref = domref; ntimer->cancelable = cancelable; ntimer->fires = 0; } schedule_timer(ntimer); retval = ntimer->ref; return retval; /* Eliminates a specious warning from gcc */ }
/* * You call this to register a timer callback. * * The arguments: * update: This should be 1 if we're updating the specified refnum * refnum_want: The refnum requested. * (1) User-supplied for /TIMER timers * (2) the empty string for system timers ("dont care") * interval: How long until the timer should fire; * (1) for repeating timers (events != 1), the timer will * fire with this interval. * (2) for "snap" timers, the first fire will be the next * time time() % interval == 0. * events: The number of times this event should fire. * (1) The value -1 means "repeat forever" * (2) Timers automatically delete after they fire the * requested number of times. * * Scenario 1: You want to run ircII commands (/TIMER timers) * | callback: NULL * | commands: some ircII commands to run when the timer goes off * | subargs: what to use to expand $0's, etc in the 'what' variable. * * Scenario 2: You want to call an internal function (system timers) * | callback: function to call when timer goes off * | commands: argument to pass to "callback" function. Should be some * | non-auto storage, perhaps a struct or a malloced char * * | array. The caller is responsible for disposing of this * | area when it is called, since the timer mechanism does not * | know anything of the nature of the argument. * | subargs: should be NULL, its ignored anyhow. * * domain: What the TIMER should bind to: * (a) SERVER_TIMER - 'domref' refers to a server refnum. * Each time this timer runs, set from_server to 'domref' * and set the current window to whatever 'domref's * current window is at that time. * (b) WINDOW_TIME - 'domref' refers to a window refnum. * Each time this timer runs, set current_window to * 'domref' and set the current server to whatever * 'domref's server is at that time. * (c) GENERAL_TIMER - 'domref' is ignored. * Do not save or restore from_server or current_window: * run in whatever the context is when it goes off. * domref: Either a server refnum, window refnum, or -1 (see 'domain') * cancelable: A "Cancelable" timer will not fire if its context cannot be * restored (ie, the server it is bound to is disconnected or * deleted; or the window it is bound to is deleted). A normal * (non-cancelable) timer will turn into a GENERAL_TIMER if its * context cannot be restored. * snap: A "snap" timer runs every time (time() % interval == 0). * This is useful for things that (eg) run at the top of every * minute (60), hour (3600), or day (86400) */ char *add_timer (int update, const char *refnum_want, double interval, long events, int (callback) (void *), void *commands, const char *subargs, TimerDomain domain, int domref, int cancelable, int snap) { Timer *ntimer, *otimer = NULL; char * refnum_got = NULL; Timeval right_now; char * retval; right_now = get_time(NULL); /* * We do this first, because if 'interval' is invalid, we don't * want to do the expensive clone/create/delete operation. * It is ineligant to check for this error here. */ if (update == 1 && interval == -1) /* Not changing the interval */ (void) 0; /* XXX sigh */ else if (interval < 0.01 && events == -1) { say("You can't infinitely repeat a timer that runs more " "than 100 times a second."); return NULL; } /* * If we say we're updating; but the timer does not exist, * then we're not updating. ;-) */ if (update) { if (!(otimer = get_timer(refnum_want))) update = 0; /* Ok so we're not updating! */ } /* * Arrange for an appropriate Timer to be in 'ntimer'. */ if (update) { unlink_timer(otimer); ntimer = clone_timer(otimer); delete_timer(otimer); } else { if (create_timer_ref(refnum_want, &refnum_got) == -1) { say("TIMER: Refnum '%s' already exists", refnum_want); return NULL; } ntimer = new_timer(); ntimer->ref = refnum_got; } /* Update the interval */ if (update == 1 && interval == -1) (void) 0; /* XXX sigh - not updating interval */ else { ntimer->interval = double_to_timeval(interval); if (snap) { double x = time_to_next_interval(interval); ntimer->time = time_add(right_now, double_to_timeval(x)); } else ntimer->time = time_add(right_now, ntimer->interval); } /* Update the repeat events */ if (update == 1 && events == -2) (void) 0; /* XXX sigh - not updating events */ else ntimer->events = events; /* Update the callback */ if (callback) { /* Delete the previous timer, if necessary */ if (ntimer->command) new_free(&ntimer->command); if (ntimer->subargs) new_free(&ntimer->subargs); ntimer->callback = callback; /* Unfortunately, command is "sometimes const". */ ntimer->callback_data = commands; ntimer->subargs = NULL; } else { ntimer->callback = NULL; malloc_strcpy(&ntimer->command, (const char *)commands); malloc_strcpy(&ntimer->subargs, subargs); } /* Update the domain refnum */ ntimer->domain = domain; if (update == 1 && domref == -1) (void) 0; /* XXX sigh - not updating domref */ else ntimer->domref = domref; /* Update the cancelable */ if (update == 1 && cancelable == -1) (void) 0; /* XXX sigh - not updating cancelable */ else ntimer->cancelable = cancelable; /* Schedule up the new/updated timer! */ schedule_timer(ntimer); retval = ntimer->ref; return retval; /* Eliminates a specious warning from gcc */ }