Signaling a menu entry from a method
In method routines, a twilight zone exists from the moment you use %M_SIGNAL to signal a menu entry to the moment control returns from the method routine. An %M_SIGNAL (D_SIGNAL) call in a method routine simultaneously sets g_select and g_entnam and instructs the Synergy runtime to signal the menu entry when control returns from the method routine. So if you clear g_select or g_entnam or set them to something different during this time, your changes will be ignored. As soon as control returns from the method routine, they will be reset to the values set by the %M_SIGNAL call because the Synergy runtime has already received its instructions. We recommend, however, that you return immediately after the %M_SIGNAL call, and we recommend that you avoid modifying g_select or g_entnam after the %M_SIGNAL call. (%M_SIGNAL can also be used to cancel a signaled menu entry.)
Note the following:
- If you signal a menu entry (using %M_SIGNAL) twice without dispatching the entry between the calls, the first call is discarded. There is no event queue.
- If you use %M_SIGNAL to signal a menu entry when not in a method routine and then call a Toolkit input routine, such as I_INPUT, the event is forgotten. Again, this is because %M_SIGNAL signals the menu entry by setting g_select and g_entnam. I_INPUT resets these upon entry, as do the other Toolkit input routines. Note, however, that if the %M_SIGNAL call causes an input field leave method to be invoked, and if the method modifies g_select or g_entnam, they remain modified. This causes the %M_SIGNAL call to behave just like a menu entry selected by the user. It also means that a leave method can effectively cancel a signaled menu entry or signal a different menu entry.
- On Windows, by the time an input field change or leave method signals a menu entry (by using %M_SIGNAL), the input context has already begun to shift to the field the user is trying to access. On Unix and OpenVMS systems, however, the context does not shift to the next input field until menu entries are processed (I_NEXT, I_PREV, etc.). So signaling a menu entry from a change or leave method will typically cancel the movement to the next field because the new menu entry overwrites the menu entry the user selected. Even if the user left the field by pressing Enter, signaling a menu entry on Unix or OpenVMS implies that focus should not change unless the program explicitly moves the focus. The same thing occurs on Windows if the user uses a menu entry (I_NEXT, I_PREV, and so forth) for movement, but does not occur if the user used Tab/Shift+Tab, Enter, or the mouse to leave the field.
- If a change method signals a menu entry and the response to that menu entry causes the field to be modified (for instance, with I_FORCE), an infinite loop may occur.
Combinations of these subtleties can create order-of-magnitude subtleties. For instance, if a method routine signals a menu entry with %M_SIGNAL and then calls a Toolkit input routine such as I_INPUT, I_INPUT clears g_select and g_entnam and may signal another menu entry. But unless %M_SIGNAL is called again before returning from the method, the lost menu entry will be resurrected when the method returns. In general, it is a good idea to avoid these situations, and it’s best to avoid nesting methods. You can do this by signaling the menu entry and then returning and letting the outer-level routine dispatch the signaled menu entry. This approach results in a somewhat flatter application design, which more closely matches Toolkit’s event paradigm, where there is no event stack or queue.
There is one subtle effect of %M_SIGNAL that makes things easier: %M_SIGNAL helps you to synchronize events. On Windows platforms, there are two different types of event processing: the UI Toolkit processing of the menu entry and Windows messaging. Because Windows messages occur quickly—you can get hundreds of them by simply moving the mouse across a window—the Synergy runtime dispatches these messages between lines of Synergy code. And because asynchronous methods are invoked immediately by their associated Windows events, a toolbar method, for example, can be called between statements of another Synergy routine. If the toolbar method and the routine it interrupts access shared data, the result can be extremely confusing. If, however, you limit the toolbar routine to calling %M_SIGNAL with an event that will be dispatched later, you have ensured that the associated code will not be executed asynchronously.