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 widgets. 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
widgets, 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 widget'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 widgets.