We began our exploration of the Bitcoin Core source code from the Qt graphical user interface on down.
We saw how the Qt signals and slots mechanism was used to handle signals from the underlying Bitcoin Core subsystems.
Now we’ll take a look at the noui header and source to see how the user interface signals are handled without a GUI.
The noui.h header is so short and simple we’ll just skip to the implementation instead. noui.h simply defines 6 global subroutines all starting with the noui_ prefix. We’ll take a look at what each of them does next.
Bitcoin Core relies heavily on boost:signals2 library for its signal handling. It’s not different on the noui implementation. The first few lines in the source file defines 3 signals2 connections:
/** Store connections so we can disconnect them when suppressing output */
boost::signals2::connection noui_ThreadSafeMessageBoxConn;
boost::signals2::connection noui_ThreadSafeQuestionConn;
boost::signals2::connection noui_InitMessageConn;
These three signals enable the noui subsystem to present the user with text-based messages depending on which signal has been received. MessageBox’es simply show an informational messages. On the noui console interface this means printing a notice to the screen. A Question does what it implies: asks for some feedback from the user. This is presented as a Y/N or string prompt where the user types some value. Lastly the Init Message signal is hooked up to the initialization code at init.cpp, for example to receive a notification when the RPC subsystem warms up (SetRPCWarmupStatus).
Thread safety is used so that messages from different threads don’t mangle with each other on the console. If you’ve programmed multi-threaded console sytems before you must have seen stdout text from various messages being mixed up and generating a messy output unless you have some synchronicity in place.
The bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
subroutine constructs a string and prints it out via LogPrintf. Although it looks long at 30 lines, all it does really is build a string with a different prefix for each type of message. It does not accept user input so “question” messages do not provide feedback.
bool noui_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
calls and returns from noui_ThreadSafeMessageBox.
noui_InitMessage
prints a message to stdout
.
void noui_connect()
connects the 3 declared signals to uiInterface signals:
void noui_connect()
{
noui_ThreadSafeMessageBoxConn = uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBox);
noui_ThreadSafeQuestionConn = uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestion);
noui_InitMessageConn = uiInterface.InitMessage_connect(noui_InitMessage);
}
uiInterface
is a global of type CClientUIInterface
and is defined in ui_interface.cpp
. Lots of other signals are defined in ui_interface.cpp
but noui just handles these 3 types.
The three following functions are NOOP:
bool noui_ThreadSafeMessageBoxSuppressed(const std::string& message, const std::string& caption, unsigned int style)
{
return false;
}
bool noui_ThreadSafeQuestionSuppressed(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
{
return false;
}
void noui_InitMessageSuppressed(const std::string& message)
{
}
Not much to say about those except they’ll be used on void noui_suppress()
to suppress any signal-related messages:
void noui_suppress()
{
noui_ThreadSafeMessageBoxConn.disconnect();
noui_ThreadSafeQuestionConn.disconnect();
noui_InitMessageConn.disconnect();
noui_ThreadSafeMessageBoxConn = uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBoxSuppressed);
noui_ThreadSafeQuestionConn = uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestionSuppressed);
noui_InitMessageConn = uiInterface.InitMessage_connect(noui_InitMessageSuppressed);
}
As you can see, the 3 signals are disconnected and the reconnected to NOOP version of the handlers that do nothing when signals are received. This effectively silences the console logging subsystem.
Finallly, noui_reconnect()
disconnects current signals and then reattaches them using noui_connect()
void noui_reconnect()
{
noui_ThreadSafeMessageBoxConn.disconnect();
noui_ThreadSafeQuestionConn.disconnect();
noui_InitMessageConn.disconnect();
noui_connect();
}
So this concludes our tour into noui, or how console messages are handled with there’s no graphicl user interface!
Return to Bitcoin Core commented source code