14.5 Using updating-output

One technique of incremental redisplay is to use updating-output to inform CLIM what output has changed, and to use redisplay to recompute and redisplay that output.

The outermost call to updating-output identifies a program fragment that produces incrementally redisplayable output. A nested call to updating-output (that is, a call to updating-output that occurs during the execution of the body of the outermost updating-output and that specifies the same stream) identifies an individually redisplayable piece of output, the program fragment that produces that output, and the circumstances under which that output needs to be redrawn.

The outermost call to updating-output executes its body, producing the initial version of the output, and returns an updating-output-record that captures the body in a closure. Each nested call to updating-output caches its :unique-id and :cache-value arguments and the portion of the output produced by its body.

redisplay takes an updating-output-record and executes the captured body of updating-output over again. When a nested call to updating-output is executed during redisplay, updating-output decides whether the cached output can be reused or the output needs to be redrawn. This is controlled by the :cache-value argument to updating-output . If its value matches its previous value, the body would produce output identical to the previous output, which would thus be unnecessary. In this case, the cached output is reused and updating-output does not execute its body. If the :cache-value does not match, the output needs to be redrawn, so updating-output executes its body and the new output drawn on the stream replaces the previous output. The :cache-value argument is only meaningful for nested calls to updating-output .

If the :incremental-redisplay pane option is used, CLIM supplies the outermost call to updating-output , saves the updating-output-record , and calls redisplay . The function specified by the :display-function pane option performs only the nested calls to updating-output .

If you use incremental redisplay without using the :incremental-redisplay pane option, you must perform the outermost call to updating-output , save the updating-output-record , and call redisplay yourself.

In order to compare the cache to the output record, two pieces of information are necessary:

An association between the output being done by the program and a particular cache. This is supplied in the :unique-id option to updating-output .

  1. A means of determining whether this particular cache is valid. This is the :cache-value option to updating-output .

Normally you would supply both options. The :unique-id would be some data structure associated with the corresponding part of output. The cache value would be something in that data structure that changes whenever the output changes.

It is valid to give the :unique-id and not the :cache-value . This is done to identify a superior in the hierarchy. By this means, the inferiors essentially get a more complex :unique-id when they are matched for output. (It is rather like using a telephone area code.) The cache without a cache value is never valid. Its inferiors always have to be checked.

It is also valid to give the :cache-value and not the :unique-id . In this case, unique ids are just assigned sequentially. So, if output associated with the same thing is done in the same order each time, it isn't necessary to invent new unique ids for each piece. This is especially true in the case of inferiors of a cache with a unique id and no cache value of its own. In this case, the superior marks the particular data structure, whose components can change individually, and the inferiors are always in the same order and properly identified by their superior and the order in which they are output.

A :unique-id need not be unique across the entire redisplay, only among the inferiors of a given output cache, that is, among all possible (current and additional) uses you make of updating-output that are dynamically (not lexically) within another.

To make your incremental redisplay maximally efficient, you should attempt to give as many caches with :cache-value as possible. For instance, if you have a deeply nested tree, it is better to be able to know when whole branches have not changed than to have to recurse to every single leaf and check it. So, if you are maintaining a modification tick in the leaves, it is better to maintain one in their superiors as well and to propagate the modification up when things change. While the simpler approach works, it requires CLIM to do more work than is necessary.

CommonLisp Interface Manager 2.0 User's Guide - 27 Feb 2006