A discussion of a control's lifecycle - 0.1 Michael Meeks * Overview With a control we have a relatively complicated situation, with several Bonobo and Gtk objects all associated loosely. It is important to codify carefuly what is involved in the various interactions: ControlFrame <-> Socket ^ ^ | | CORBA X | | v v Control <------> Plug * Creation interaction (A) ** Out of proc. 1. Control creation 2. Passes it's reference 3. _control_frame_new 4. creates ControlFrame 5. creates Socket 6. _control_frame_bind_to_control 7. takes a C. Control ref. 8. Control->setFrame 9. takes a C. control_frame ref 10. -- socket realize -- Control->setWindowId ** In proc 1. Control creation 2. Passes it's reference 3. _control_frame_new 4. creates ControlFrame 5. creates Socket 6. _control_frame_bind_to_control 7. takes a C. Control ref. 8. Control->setFrame 9. takes a C. control_frame ref 10. Sets up in-proc references to each other. 11. -- socket realize -- Control->setWindowId * Steady state referencing ControlFrame: GObject ref -> Socket Socket: Bonobo ref -> ControlFrame ControlFrame: Bonobo ref -> Control ---------------------------------- Control: CORBA ref -> ControlFrame Control: GObject ref -> Plug Plug: Bonobo ref -> Control NB. The plug only holds it's bonobo ref on the control when it's realized. * Destruction interaction (B1) ** Out of proc Toplevel gtk_widget_destroy. 1. Socket dispose 2. unset control (B. unref) 3. Bonobo unref Control 4. got unref <--. and: | interchangeable 5. X connection broken <--' 6. Instantiate glib mainloop idle handler: Note 1. ... 7. unref plug -> dispose 8. plug unset control frame 9. plug C. unref ControlFrame ** Note 1. As Darin points out, the connection broken signal can occur 'inside' or during a CORBA method leading to some confusion. Thus it is best to delay the actual destruction invocations until the glib mainloop is hit. ** In proc Toplevel gtk_widget_destroy. 1. Socket dispose 2. unset control (B. unref) 3. Bonobo. unref Control if we have a plug: 4. gtk_widget_destroy plug 5. plug unset control frame 6. plug B. unref ControlFrame else: 4. B. unref Control Leaves: unref Control, [ finalized plug ] finalized socket, unref ControlFrame * Destruction interaction (B2) Fatal error: ControlFrame dies. 1. Fatal ControlFrame error; B1 - 4,5,6,7,8,9 Leaves: finalized plug, unref Control finalized socket, unref ControlFrame * Destruction interaction (B3) Fatal error: Control dies. [ don't destroy socket, it holds our place in the widget hierarchy for any re-started control ]. 1. Fatal Control error; 2. connection broken <--. and: interchangeable Note 3. | 3. X connection broken <--' ** Note 3. X connection broken yields no signal. CORBA connection broken invokes 'broken' on control->connection When we have both - track in the ControlFrame; unref socket. * Destruction interaction (B4) Client remove of Control (?) Minority usefuleness; FIXME - work out. * Size request interaction (CX) * Size request interaction (CB) * Sensitivity interaction () * CORBA connection 'broken' signal This signal is totaly unaffected by CORBA reference counting, and will happily leave an object with a broken connection - but we'll get a nice signal. We only get this signal quickly using Unix Domain Sockets, this manifests itself as a HUP under Linux and a POLL_IN + 0 length or erroneous read under Solaris / others. * FIXME: Consider the effect of extraneous Bonobo or CORBA refs on both the Control and ControlFrame references - and their affect on the destruction sequence. Consider the local case - are there any obvious optimizations possible / neccessary here; we don't get a 'broken' signal, but we get Gtk+ signals instead. We can reliably detect this by a lack of connection on the Bonobo_Unknown references though. [ unless we have invoked an async method on them ]. But also possibly from plug->socket_window and socket->plug_window [ these may race ]. Consider the 'activation' side of it all; what does activation entail, and what happens in failure modes. Consider how a BonoboWidget might correctly hold onto a child widget, and possibly it's control frame ? * Work out what to do if we die without having had our X11 ID set, we need to kill ourselves if the connection dies; _but_ what if we're local anyway ? how can we tell ? - we need to have local hacks - and have a reference to the BonoboControlFrame inside our BonoboControl etc.