x::w::main_windows own references on their dialogs

Note

x::w::dialogs can create their own dialogs, and this applies recursively also. x::w::dialogs own references on their own dialogs, too.

A fundamental concept of the LibCXX Widget Toolkit is that all its objects are reference-counted objects. All references to the object must go out of scope and get destroyed before the underlying objects' destructors get automatically invoked; and all main windows must be destroyed in order for the library to properly clean up and disconnect from the display server.

In main windows, container elements own references to the widgets in the container. This applies to dialogs too. Their parent main window (or their parent dialog) owns a reference on all of its dialogs.

std::unordered_set<std::string> dialogs=main_window->dialogs();

menu.C gives an example of using dialogs(), which returns all identifiers for all dialogs that the x::w::main_window (or the x::w::dialog) owns.

m->append_items
        ({
            [main_window=x::make_weak_capture(main_window)]
            (ONLY IN_THREAD,
             const x::w::list_item_status_info_t &ignore)
            {
                main_window.get
                    ([&]
                     (const auto &main_window) {
                        main_window->get_dialog("help_question")->dialog_window->show_all();
                    });
            },
            "Question",

menu.C creates several dialogs, like help_question, for a main window with a menu which open the various dialogs. get_dialog() takes a dialog identifier and returns the previously-created dialog with this identifier. The callbacks that get installed for each menu item use it to locate the appropriate dialog, and make it visible.

The dialog's buttons merely hide their dialog, they don't destroy it, since their parent main window owns a reference to its dialogs. As such, when the menu item gets selected again it simply show_all()s the same dialog, making it visible again.

The only way to permanently destroy a dialog is by using remove_dialog(); and because the parent main window owns references on its dialogs, if the main window's last reference goes out of scope and it gets destroyed (as part of normal application termination), its dialogs get destroyed too.

This also means that, as shown in the above example, callbacks must capture only weak reference to their parent main window (or parent dialog), because the main window (or the parent dialog) owns (directly or indirectly) references to all elements in the main window (or the dialog), including the menu item with the callback, so the weak capture is required to avoid a circular reference.

auto d=main_window->create_ok_dialog({"example@libcxx.com", true},
                            "alert",
                            []
                            (const x::w::factory &f)
                            {
                                 f->create_label("Bad input");
                            },

                            main_window->destroy_when_closed("example@libcxx.com"));

destroy_when_closed() returns a closure that's suitable for an Ok or Cancel button's callback (except for create_input_field()'s Ok callback that takes an additional parameter). When it gets invoked the specified dialog gets remove_dialog(). This example calls main_window's destroy_when_closed(). The returned closure invokes main_window's remove_dialog("example@libcxx.com") (using a weak reference, for the reasons previously stated) and this get installed as this new dialog's callback. Thusly, the dialog ends up removing itself, as a result of Ok getting pressed.