Day 7: Fixing things

Handling callbacks

I did a small experiment today, trying to make it easier to use QtWebEngine functions which expect a callback, like QWebEnginePage::runJavaScript.

Normally, you'd call such a function like this:

def calc(view):
    def cb(data):
        print("data: {}".format(data))
    view.page().runJavaScript('1 + 1', cb)

What I wanted is to (ab)use Python's yield statement instead (as a coroutine), so I can yield a callback to call, and the rest of the function would run after it:

@wrap_cb
def calc(view):
    data = yield view.page().runJavaScript, '1 + 1'
    print("data: {}".format(data))

This worked fine, and the wrap_cb decorator looks like this:

def wrap_cb(func):

    @functools.wraps(func)
    def inner(*args):
        gen = func(*args)
        arg = next(gen)

        def _send(*args):
            try:
                gen.send(*args)
            except StopIteration:
                pass

        if callable(arg):
            cb_func = arg
            args = []
        else:
            cb_func, *args = arg
        cb_func(*args, _send)

    return inner

In the end I ended up not using it though, because it felt like too much magic.

Definitely was an interesting experiment, and I'm a step closer wrapping my head around how coroutines work.

QtWebEngine branch

Yesterday, I branched off a qtwebengine branch, and started refactoring everything so there would be a clearly defined interface which hides the implementation details of a single tab in qutebrowser (QWebView or QWebEngineView).

This means even the current QtWebKit backend broke, which is why the work is still in a branch. I got both QtWebKit and QtWebEngine to run enough to show you a nice screenshot, but as soon as you do anything except opening an URL (like scrolling, or going back/forward) qutebrowser crashed.

Today I worked on getting everything running with QtWebKit first again, and expanding the API of a tab. Here's what's working so far:

  • Scrolling
  • Going back/forward
  • :debug-dump-page (needed for tests)
  • :jseval (needed for tests)
  • Caret browsing

Everything apart from that is either broken or untested - but it's a start!

Seeing the first tests pass definitely was a satisfying feeling :)