Chapter 46. Connection threads and callbacks

Index

Callback calling conventions
Callback invocations
Flushing the display buffers

As mentioned briefly in the introduction, the LibCXX Widget Toolkit creates an internal execution thread for the connection with the display server. LibCXX Widget Toolkit takes care of starting and stopping the connection thread. The connection thread gets started when needed, and the connection thread gets stopped when the last top level window, or an explicitly constructed connection object, goes out of scope and gets destroyed.

The connection thread takes care of updating the display, and processing internal display protocol messages. The connection thread also executes application-specified lambdas or other callable objects in response to specific events.

The connection thread resumes its normal duties after the application callback returns. Application callbacks should not get bogged down with long-running tasks, as this will result in the application window appearing to be frozen. Callbacks should be minimal, and consist of little more than sending a message of some kind, or setting a flag.

Callback calling conventions

Typical example: a main window's on_delete() method sets the callback that gets executed in when the window's close button gets clicked:

main_window->on_delete([close_flag]
    (ONLY IN_THREAD,
     const x::w::busy &ignore)
     {
         close_flag->close();
     });

This is an example of the calling convention LibCXXW uses for invoking its callbacks by the internal execution thread. The callback's first parameter is a reference to an internal object that represents the connection thread itself. The callback's first parameter gets specified as ONLY IN_THREAD, this declares a parameter named IN_THREAD that carries this internal reference.

This calling convention serves a dual purpose:

  • This identifies lambdas that always get invoked by the library's' internal connection thread, as well as object methods that can only be invoked from the connection thread.

  • A lambda that receives the IN_THREAD parameter can call other functions and methods by forwarding to them this parameter:

    lm->remove_item(IN_THREAD, 0);

    The only way to receive the IN_THREAD parameter is by having a function executed by the internal connection thread. In this manner only IN_THREAD code can invoke other IN_THREAD code.

The THREAD_CALLBACK designation is just an alias. for the parameter's type:

main_window->on_delete([close_flag]
    (THREAD_CALLBACK,
     const x::w::busy &ignore)
     {
         close_flag->close();
     });

ONLY IN_THREAD and THREAD_CALLBACK mean the same thing. The only difference is that the former declares a named parameter, called IN_THREAD; and the latter is just a parameter type declaration. This on_delete() example does not need to call any other connection thread code, so it doesn't need to forward its thread parameter anywhere. Using the THREAD_CALLBACK designation is a little but more descriptive.

Some LibCXXW objects provide overloaded versions of the same method, with and without the ONLY IN_THREAD designation. Except where noted, LibCXXW makes all changes to widgets from the internal connection thread. Application code invoking the non-IN_THREAD method does not immediately update the widget. What happens is that a message gets sent to the connection thread, which processes it at the first available opportunity.

But a callback that gets executed by the connection thread and receives the IN_THREAD parameter has the ability to use the ONLY IN_THREAD overload, which makes the change immediately. An IN_THREAD code is free to invoke the non-IN_THREAD overload also, but this will not result in any changes until the callback returns, and the connection thread resumes processing its internal messages.