## EQL in Slime -- how does it work?

- Start swank using the EQL executable, running the swank server in an ECL thread, and using the main thread for the Qt main event loop.

- Wrap every internal EQL function in a macro, which will call the function either directly (if called from GUI/main thread), or, if called from another ECL thread, will wrap the function call in a closure.

- This closure will be passed to a queued, blocking Qt function running on the UI thread, which will in turn call the closure.

The crucial part is passing a Lisp closure from an ECL thread to Qt and calling it from C++ on the UI/main thread.

This is trivial in ECL/Qt, since both ECL and Qt use/wrap native C threads, and Qt offers a nice utility with `Q_INVOKABLE`.

First let's wrap the actual Lisp function, e.g. `(foo x y)` in a closure, so we only need to pass one ECL closure pointer to C++.

No need to pass Lisp arguments to C++, they are in the closure; no return value needed from C++, Lisp return values will be assigned in the closure:

      ;; in some ECL thread
      (let (values)
        (run-on-ui-thread

          ;; in ECL main/GUI thread
          (lambda ()
            (setf values (multiple-value-list (foo x y)))))

        ;; back in some ECL thread
        (values-list values))

Here the implementation of the ECL function `run-on-ui-thread` (embedded in Qt):

      cl_object run_on_ui_thread(cl_object closure) // define ECL function
      {
          QMetaObject::invokeMethod(
              object,                       // any QObject from GUI thread
              "runOnUiThread",              // see Q_INVOKABLE
              Qt::BlockingQueuedConnection, // blocking for return values
              Q_ARG(void*, closure));       // 'closure' is just a pointer

          return Cnil;
      }

Now the Lisp closure will run on the UI/main thread, and the implementation of the Qt function `runOnUiThread` is as simple as:

      Q_INVOKABLE void runOnUiThread(void* closure) // note Q_INVOKABLE
      {
          cl_funcall(1, (cl_object)closure); // ECL function call
      }

After introducing a macro `qrun*`, and wrapping all EQL functions in it (see `"lib/thread-safe.lisp"`), we are done!

(Please note that the above code is a stripped down version, see sources for the actual implementation.)