Tonight, I found myself bitten once again by a design issue that affected Quasimodo, was solved there, and reared its ugly head again in SoftWerk. It could affect your programs too, at least if you're ambitious. Very few applications exist for Linux that use two event loops, both of which have GUI implications. Under X, you collect input events from the X server (i.e. ultimately from the keyboard, the mouse and/or any other input devices known to X), and process them. Toolkits like GTK offer ways to add new file descriptors to this event loop, apparently making the task of merging all external events into a single event stream fairly easy. Alas, it isn't so. Putting the file descriptor for a MIDI port into GTK's event input loop (with gtk_input_add()) will almost certainly result in poor MIDI response, especially if your GUI is busy. If time-sensitive MIDI data is coming in to your app, you will likely have no choice but to collect it in *another* thread. OK, so far so good. Two thread, two select(2) loops running, we're fine. Not so fast. What happens when you want incoming MIDI data to affect the GUI ? To understand the question, you need to recall that X (and GTK and Qt and Motif) are still essentially single-threaded. You can't safely make X calls from multiple threads without a mutex to prevent simultaneous collisions. But locks are bad for real-time work, so we want to avoid them wherever possible. We therefore have a problem. Consider the following scenario: an incoming MIDI note on is intended to transpose all the notes in the sequence displayed in the GUI. We want both the underlying data (the noteOn/noteOff values of the sequence) to be modified - thats easy to do from the MIDI thread. But we also want the GUI representation updated. OK, not so difficult - we just get the GUI to install a callback on the underlying data, so that whenever it changes, our callback is executed, and the GUI is updated. But wait - the change in the data is being done by the MIDI thread. Unless it takes a lock designed to protect the X server/toolkit, we'll likely run into problems with directly calling the GUI toolkit functions from the MIDI thread. And we've agreed to not take locks. Fine, we'll make the MIDI thread just queue a request with the GUI so that when it gets a chance, the GUI will update the display in the right way. If our callback for changes in the underlying data simply marks the updates needed, we should be OK. Things are looking good, until you remember that the GUI might be able to cause changes in the underlying data as well. The callback we install to pick up changes in the underlying data will be executed for those changes caused by the GUI as well as those induced by the MIDI thread. How can the GUI thread know that the changes it finds when it comes to updates its display relate to its own activity (and may thus require different handling for efficiency's sake) ? The short answer to this long question is to make sure that you always use an "EventSource" whenever you invoke a callback to notify one object that another has changed. That way, the notified object can properly distinguish what actions are needed based on the object/source that initiated the change. Failure to do this will result in many headaches. This is really just basic "Model-View-Controller" programming, in which the Model is the underlying data (the MIDI data for the sequence, for example; the View is the GUI (just one in this case) and the Controllers are both the X event loop and the MIDI input event loop. Without the ability to identify which Controller caused a change in the Model, the View will be forced to make suboptimal choices in how it responds to those changes. For example, it may update a set of widgets that are already up-to-date. There is an alternative to this, which is to provide the View with some way to check if its current "presentation" matches the current state of the Model. This works very well when the Model contains simple scalar data, and comparisons can be performed cheaply and easily. If the data is more structured or is large, however, and particularly if the presentation made by the view merges distinct aspects of the Model into single visual objects (e.g. softwerk represents a step in a sequence with both a number and a colored background to indicate if it is active), then this kind of comparison gets tricky and/or cannot be done correctly without locks. Knowing the event source can help with this, I think. OK, end of ramble. I've just checked in a version of SoftWerk which incorporates most of these kinds of changes. I discovered this afternoon that SoftWerk's "recorded MIDI" mode would reliably crash it. Oh well, we live and (re)learn. --p