Notifications Architecture Proposal
Overview
In broad strokes, the notification system from C++ to Python will be similar to what exists in Chimera 1. There will be two main systems of notifications, one for communicating whether the graphics need updating, and one for communicating data changes to interested code. Neither is synchronous; the Python layer is in charge of when the notifications are acted on.
Graphics Updates
Whereas Chimera 1 has Model::setMajorChange() and Model::setMinorChange(), I'm thinking Chimera 2 will have just have Graph::set_graphics_change() with a default arg of Graph::GC_REBUILD. Other arguments would be added as needed, but I'm no graphics guru so am not going to propose a complete set, though I'm imagining that Graph::GC_REDRAW might be useful(?). At any rate, the Python layer would be in charge of querying and clearing the change flags at the appropriate time. Depending on what is most useful, turning on a "bigger" flag may also turn on "lesser" flags, e.g. GC_REBUILD also sets GC_REDRAW. Whatever behavior the "graphics guys" want here really.
There is no Model class in the C++ layer at this point. If there ever is one then this support would be moved from Graph to that class.
Data Changes
Again, this will be similar in many ways to Chimera 1. Changing the color of an Atom will put that Atom in the "modified" set of Atoms and add "color changed" to the list of Atom reasons. A significant difference from Chimera 1 is that instead of firing individual Atom/Residue/Chain/etc. triggers, one "atomic data" trigger will fire whose associated data is a dictionary that has keys of Atom/Residue/Chain/etc. and values that contain the reasons, the sets of create/modified items, and possibly the set of deleted items. This eliminates timing issues of which trigger should fire first and eliminates the possibility of changes by trigger handlers "infiltrating" later single-class triggers. Such changes will instead accumulate into the next firing of the atomic-data trigger.
The atomic-data trigger will fire when no user/tool code is executing, though like Chimera 1's checkForChanges() it will be possible to explicitly force the trigger to fire if needed.
The sets of created/modified items are collections, not lists of individual Python objects.
As usual, the deleted items is the tricky part. My proposal is this: The deleted items is a set containing all the individual Python objects that had already been created at the time they were deleted. There would also be an accompanying integer noting the total number of deleted items. My reasoning is that no code is going to care about individual deleted Python objects that had never been created at the time they were deleted. Keep in mind that collections automatically contract when their members are deleted. I propose we add a callback API to collections so that interested code can respond to such a contraction if desired.
Also keep in mind that it is possible to ask individual objects if they are "dead" since their C++ pointer will be NULL, so some code may not even look at the set of deleted items and will instead just cull their own lists/etc. based on that criteria.