Some of the actions that need to be run during the installation process take a long time to be finished (e.g. scanning disks for existing partitions, downloading package repository metadata, etc). And since basic principle of the GUI programming is that the user interface should be as responsive as possible and since the goal is to allow user configure other settings while some are blocked by the long lasting actions, the Anaconda installer has to run such actions in separate threads. However, the Gtk toolkit doesn't support changing its elements from multiple threads. The Gtk main event loop is running in the main thread of the Anaconda installer process and every code doing some GUI involving actions has to make sure that these actions are run in the main thread as well. The only supported way to do that is by using GLib.idle_add
method which is not much comfortable. To facilitate this issue there are some helper functions and decorators defined in the pyanaconda.ui.gui.utils module. The most useful ones are @gtk_action_wait and @gtk_action_nowait decorators that change the decorated function or method in a way that when it is called it is automatically queued to Gtk's main loop, run in the main thread and then the return value is returned to the caller or dropped, respectively.
As it has been already mentioned one of the goals of using multiple threads is to allow user configure something else while some parts of the GUI wait for some actions to finish. The example of such case is package repository metadata download which can take a while and without it being finished the Source
and Software
spokes cannot be visited as they cannot display valid data. But in the same time there is no reason why e.g. the Datetime spoke
should be blocked. Now let's take a look from the blocked spoke's perspective. It waits for some background thread to finish. But once this thread is finished how should the spoke announce it is ready and should not be blocked anymore? The hub that provides an access to the spoke has no relation with the thread the spoke has been waiting for and thus can't tell whether the spoke is yet ready or not. For such cases there is a message queue called
hubQ that is being periodically checked in the main event loop. Once the thread the spoke has been waiting for is finished the spoke sends a message
that announces the spoke should no longer be blocked. The same applies to the situation when the spoke needs to refresh its status or completion flag. In case of the Progress hub there is the
progressQ which serves as a medium to transfer installation progress updates. These mechanisms are needed also for the text mode where the situation is much more complicated, because there is no main loop in the text mode and for vast majority of time it is waiting for an input from keyboard. However there is (a bit experimental) implementation of asynchronous messages handling in TUI and the goal is to make, from spoke's perspective, everything very similar to the graphical user interface.