Flushing the display buffers

Other toolkit libraries typically offer the means to flush their output buffer and send all buffered commands to the display server in order to update the application's window and have it reflect all buffered changes to its fields and display elements. There is no such direct equivalent with LibCXXW. Its internal connection thread automatically flushes the display buffer after the thread finishes all pending processes, and has nothing else to do.

However, sometimes its necessary to do something analogous with LibCXXW. One such case is creating a large window with many display elements, and a complicated layout, which may take a noticably long period of time, and cannot be avoided. Using get_wait_busy_mcguffin() changes the current pointer to a busy icon, but this icon doesn't appear until the display message that creates it gest flushed to the display server; and if the connection thread is busy, creating this large window, this won't happen until that's already done.

Here's one possible solution:

button->on_activate(
   [button=x::make_weak_capture(button)]
   (ONLY IN_THREAD,
    const x::w::callback_trigger_t &trigger,
    const x::w::busy &mcguffin_factory)
   {
       auto got=button.get();
       if (!got)
           return;
       auto & [button]=*got;

       x::ref<x::obj> mcguffin=mcguffin_factory.get_wait_busy_mcguffin();
       button->in_thread_idle(
          [mcguffin]
          (ONLY IN_THREAD)
          {
               // Now create the large window
          });
   });

button is some button. Its on_activate() callback weakly-captures itself, in order to prevent a circular reference. After dispensing with the formalities of dealing with the weak reference, get_wait_busy_mcguffin() acquires the busy mcguffin, to block input processing and change the pointer to the busy icon, before scheduling an in_thread_idle() callback.

Invoking a display element's in_thread_idle() method schedules the specified callback to get executed by the connection thread after the connection thread finishes all of its pending work and flushes the display buffer. The pending work here consists of changing the pointer icon, and everything else that happened previously.

Once that's done, the second callback executes, and takes its time to do whatever it needs to do. The second callback intentionally captures the reference to the busy mcguffin, so all input processing stops and the pointer icon continues to indicate busy until the callback executes and finishes.

This can be used to mimic the classical flush function:

class flagObj : virtual public x::obj {

public:

    typedef x::mpcobj<bool> value_t;

    value_t value=false;

    void signal()
    {
        value_t::lock lock{value};

        *lock=true;
        lock.notify_all();
    }

    void wait()
    {
        value_t::lock lock{value};

        lock.wait([&] { return *lock; });
    }
};

void flush(const x::w::element &e)
{
    auto flag=x::ref<flagObj>::create();

    e->in_thread_idle([flag]
              (THREAD_CALLBACK)
              {
                  flag->signal();
              });

    flag->wait();
}

This works only if flush() is not called from the connection thread itself. flush() uses in_thread_idle() to schedule execution of a callback that sets a flag and signals a condition variable, then waits for the condition variable to get signalled. If flush() itself gets called from the connection thread, this will wait forever for itself to set the flag and signal the condition variable.

There's also in_thread() in addition to in_thread_idle(). in_thread() does not wait for the connection thread to be idle, but executes the callback after all higher-priority processing is complete, but before doing any low priority work like drawing the actual display elements.