I’ve written before (PDF) about the unique event model of the Synergy/DE UI Toolkit. For historical reasons, these events are often called “menu entries,” and even though they are handled in a synchronous, delayed manner you can’t have more than one such event pending at any given time. This didn’t cause too many problems back in the old days when they were almost limited to user-initiated events. But now that they’ve also become a standard means for converting asynchronous system-level events into synchronous Toolkit events, the need to generate more than one at a time has become something much more than academic.
Consider, for instance, an input field that needs to perform non-trivial processing at three points: when it is modified, when it is displayed, and when focus leaves the field. Each of these events can be hooked to a “method” routine, but if those routines need to do anything involving user interaction, then on Windows it needs to be deferred to the outer loop by means of passing an event to M_SIGNAL. Why? Because in an asychronous callback, the UI Toolkit can’t process Windows messages, so the user will not see any changes to the UI until after that event has been handled and the routine returns. Non-Windows platforms like Unix and OpenVMS don’t have that problem, but if your code is portable to Windows then you probably want to write it that way anyway.
Now, when the user types something in the field and then advances to the next field (via Tab, etc.), all three of those events will fire: first the “change” event, then the “display” event (to display the reformatted value after validation), then the “leave” event. All three associated methods will be called in that order. If each of them signals a menu entry event, then only the last one will be seen.
I’ve added a class to my Synthesis library to extend menu-entry signaling to maintain a queue of pending events. To make use of it, you replace M_SIGNAL with multi_signal. In the outer routine that consumes events, you change M_SIGNAL(…, D_REMOVE) (or testing g_select and g_entnam, after the older form), with a loop of calls to multi_remove, until it returns ^null. Each non-null return value will be a string containing an event that was signaled, in the order in which they were signaled.
To ease the transition, I’ve made multisignal somewhat compatible with M_SIGNAL. If the consuming code isn’t changed to the new paradigm, then it will still see the most recent event — whether it was passed to M_SIGNAL or multisignal.
See the test program (test_multisignal.dbl in the tests subdirectory) for an example of how to solve the scenario I related above.
With this feature, I’m putting a lid on Synthesis version 2.2.1. Any further changes will go in the next version.