diff --git a/callback.c b/callback.c index 84ea0c80..3273002a 100644 --- a/callback.c +++ b/callback.c @@ -26,6 +26,21 @@ void request_callback_notifications(toplevel_callback_notify_fn_t fn, frontend = fr; } +static void run_idempotent_callback(void *ctx) +{ + struct IdempotentCallback *ic = (struct IdempotentCallback *)ctx; + ic->queued = FALSE; + ic->fn(ic->ctx); +} + +void queue_idempotent_callback(struct IdempotentCallback *ic) +{ + if (ic->queued) + return; + ic->queued = TRUE; + queue_toplevel_callback(run_idempotent_callback, ic); +} + void delete_callbacks_for_context(void *ctx) { struct callback *newhead, *newtail; @@ -34,7 +49,9 @@ void delete_callbacks_for_context(void *ctx) while (cbhead) { struct callback *cb = cbhead; cbhead = cbhead->next; - if (cb->ctx == ctx) { + if (cb->ctx == ctx || + (cb->fn == run_idempotent_callback && + ((struct IdempotentCallback *)cb->ctx)->ctx == ctx)) { sfree(cb); } else { if (!newhead) diff --git a/putty.h b/putty.h index 590370f7..a96230f2 100644 --- a/putty.h +++ b/putty.h @@ -1603,6 +1603,22 @@ void run_toplevel_callbacks(void); int toplevel_callback_pending(void); void delete_callbacks_for_context(void *ctx); +/* + * Another facility in callback.c deals with 'idempotent' callbacks, + * defined as those which never need to be scheduled again if they are + * already scheduled and have not yet run. (An example would be one + * which, when called, empties a queue of data completely: when data + * is added to the queue, you must ensure a run of the queue-consuming + * function has been scheduled, but if one is already pending, you + * don't need to schedule a second one.) + */ +struct IdempotentCallback { + toplevel_callback_fn_t fn; + void *ctx; + int queued; +}; +void queue_idempotent_callback(struct IdempotentCallback *ic); + typedef void (*toplevel_callback_notify_fn_t)(void *frontend); void request_callback_notifications(toplevel_callback_notify_fn_t notify, void *frontend);