woboq / qmetaobject-rs

Integrate Qml and Rust by building the QMetaObject at compile time.
MIT License
620 stars 89 forks source link

Add a few more QmlEngine methods #302

Closed IriaSomobu closed 9 months ago

IriaSomobu commented 9 months ago

I was implementing a basic hot-reload feature for a project of mine and had a difficulties I solved by adding a few additional methods to QmlEngine wrapper.

First, I should briefly explain how hot reloading works in my case:

  1. Rust code watches for changes in ./ui/ directroy where all my .qml's are stored;
  2. When file change occurs, rust code does the following (source):
    • Invokes method hot_reload_pre on my root ApplicationWindow -- this method clears PageLoader's source and sets it to inactive;
    • Trims and clears QmlEngine's component cache;
    • Invokes method hot_reload_post -- this method makes PageLoader become active and triggers loading of page where user was before hot reload.

In this scenario I faced two problems:

The first one was caused by cryptic QMetaMethod::invoke: Unable to invoke methods with return values in queued connections QmlEngine message happens when I try to call invoke_method on engine from my watcher thread. I've looked here and there and found this answer on SO. So I copied invoke_method, removed Q_RETURN_ARG from a template and renamed method to a invoke_method_noreturn (meaning this version of invoke_method has no return arg).

The second problem was -- QmlEngine and PageLoader was written by clever guys who cares about performance and do caching if possible. And in my case I need exactly opposite -- I need to reset Engine's/PageLoader's cache on hot reload. I found no possibilities to do it from qml itself (moving my PageLoader to inactive and then back to active state wont help), but I found a way to do it from C side by calling methods engine->trimComponentCache() and engine->clearComponentCache(). Unfortunately, named methods were absent in wrapper, so I've added them.

And with these two changes I was able to do my simple hot-reload.

I believe someone else may find these addition useful, so here's PR.

IriaSomobu commented 9 months ago

It is more than I intended indeed -- I just wanted invoke to work one way or another, and with this PR it works.

I guess it is possible for me tinker with invoke_method and connections a bit later, when there will be more free time.

As for tests -- do you have any ideas on what exactly should we test on these functions?