## Experimental Qt and QML in the browser

Update: You might also be interested in the discussion on Hacker News.

I was amazed when I read Morten Johan Sørvig’s blog post about bringing Qt to Native Client (NaCl) and Emscripten in September last year. I have been following multiple efforts to bring Qt to the web for some time. Mostly because I wanted to make my own Qt projects easily available to others, but also because I find the whole concept of running C++ code in a browser fascinating.

This is definitely not the first time someone has worked on bringing Qt to the browser. Qt4 was ported to Emscripten by Simon St James and published with a lot of examples. However, it seems the port was discontinued when Qt5 came along due to the changes that came with that transition. In the meantime, Lauri Paimen, Anton Kreuzkamp and many others have contributed to qmlweb, a QML interpreter written from scratch in JavaScript. That project does however not make it easy to use any C++ classes you may have defined. And most of my projects are QML/C++ hybrids.

These projects brought something important to the table and took us one step closer to writing QML for the browser. Personally I find QML very enjoyable because of its clean and intuitive structure in comparison to other options like XML. And the ability to easily bind GUI elements to high-performance C++ code has made Qt my favorite framework for many projects.

I tried to port Qt5 to Emscripten myself about a year ago. That turned out to be a real challenge. I based my work on the changes Simon St James made to Qt4 and tried to figure out how to make the same changes in Qt5. After a couple of weeks, I got to the point where I had QtCore running and QtDeclarative (QML) compiling, but other things caught up with me and I had to leave that project behind. The biggest disappointment was that I never got around to making any demos.

I decided to pick up the ball a couple of months ago This time I knew about Morten Johan Sørvig’s efforts and asked him to give me some info on the status of his port. At that point he had support for compiling to NaCl ready (that means Chrome only) and he had already started porting to Emscripten using pepper.js as glue between Emscripten and NaCl. There was still a bit left to do before any examples could be up and running in Firefox. I decided to give it a go and see if I could contribute with something.

A couple of weeks later, I managed to get Qt running in Firefox with a number of QML examples. The process was a lot of fun as I learned much about what happens inside Qt’s sources. It was interesting to see how often I could write many lines of code and rebuild multiple times only to arrive at a one-line change that fixed the issue at hand. I was really happy when I finally could send a patch to Qt’s NaCl branch. The main changes were to Qt’s event loop, which would hang if control wasn’t returned to the browser. I had to add a couple of hacks to keep Qt’s mutexes from locking up everything (this needs to be properly fixed later, perhaps by creating pthread stubs). And OpenGL needed to be explicitly set to OpenGL ES2 in addition to a bunch of smaller modifications.

Below are two resulting demos of QML running in the browser. I’m amazed with the performance both in Firefox and Chrome. Just be aware that the size of the examples is quite big because no optimizations have been done to reduce the size of the binary JavaScript. Further, there may be lots of bugs and some browsers where the examples don’t work. Remember that this is still very experimental and only a small taste of what may be possible with Qt in the browser in the future:

What amazes me the most is the fact that we are now running Qt’s own JavaScript engine, which is written in C++ and compiled to JavaScript with Emscripten, inside the browser’s own JavaScript engine! I really want to see if we can get QML’s WebEngineView running inside itself inside Firefox. That’s a step on the way to true inception, which reminds me of a great talk by Gary Bernhardt titled “The Birth & Death of JavaScript”.

## Today I called Python from QML

I always use QML with Qt Quick for GUI programming. It’s incredible both for prototyping and larger applications. I find it easy to express myself in QML, because it is so flexible. It’s declarative. You can bind a button’s position to the value of a slider in just one line. Not that you’d ever want to do that, but it shows how easy it is to connect objects together. I really wish the web was written in QML and not HTML.

Typically, I’m working with both QML and C++. I write high performance and visualization code in C++ and define GUI elements in QML. But today I wanted to use QML and Python together because I’m working on an experiment browser for our lab. Not an experimental browser, but an application that lists all experiments and makes it easy to export data for further analysis.

We have decided to organize the experiments as HDF5 files. To read these files I want to use the Python HDF5 package. I could use the C++ HDF5 library, but using Python should hopefully make the application more easily maintainable in the future, also for non-C++ coders in our lab. To do this, I figured there were two possibilities: PyQt and PyOtherSide.

In brief (and a bit simplified), PyQt calls Qt code from Python, while PyOtherSide calls Python code from QML. The difference isn’t really that big, so it just boils down to where the business logic resides. I figured that PyOtherSide would be the better option for us, because it allows everyone to help out with the Python code without learning anything about Qt. PyQt would on the other hand require everyone to have at least some understanding of the Qt framework to make changes in the code. More of the business logic will have to take place in QML, though.

PyOtherSide is really simple in use. You just define a Python object in QML and this loads modules and files from the Qt resource file (qrc). Once loaded, Python functions can be called from QML and their results are automatically converted from Python types to Qt types:

import io.thp.pyotherside 1.3

Python {

return
}
}

function parseData(result) {
for(var i in result) {
var element = result[i]
tableModel.append(element)
}
}

Component.onCompleted: {
})
}
}

As you can see, all Python calls are asynchronous. You can also make synchronous Python calls, but this is not recommended because it could cause the QML GUI to stall while waiting for the results.

The Python code in this case is just a simple function that returns a dictionary:

def read_experiments():
return {{"experimenter": "test",
"date": "2015-10-26"},
{"experimenter": "test2",
"date": "2015-10-25"}}


Now I just need to make this code read and parse real HDF5 files.

Edit: In QtCreator 3.1, the method used here (using resource files) will become the default way to perform deployment on all platforms. I.e., this guide is only useful if you have created your project using QtCreator < 3.1.

If your Qt application is taking too long to load on Android, it is likely because accessing asset-files is really slow on some devices. I just tested an application with about 12 QML-files and it took 40(!) seconds to load. This appears to have been an issue for quite some time, and although efforts have been made to reduce the problem, my app still loads too slow on my Asus Transformer TF300T. In Qt and Android’s defence, this device is known for its extremely slow eMMC storage.

The cure in my case was to use a Qt Resource Collection file for all my QML assets. In Qt Creator, this is as simple as clicking  File > New File or Project > Qt > Qt Resource file and then add a prefix “/” before adding all files from each QML folder. After creating and setting up the .qrc-file, I changed the URL in my main-function to “qrc:/qml/myproject/main.qml”.

This worked flawlessly, and the load time dropped from 40 seconds to less than a second!

You should of course be careful with what you add to your resource file. All listed files will be compiled into your executable, so if there are files you don’t want loaded right away, you might want to keep them outside your .qrc file.

The only downside with this approach is adding all new QML files to the resource file. This  is a bit tedious in the long run, so I suppose I will automate it with a script.

## Setting up Ubuntu SDK on Kubuntu with backports enabled

Gah… So once again my temptation to install the latest and greatest causes a conflicting system setup. This time it was my attempt at installing the Ubuntu SDK on a Kubuntu system with backports enabled that conflicted. Backports are packages that are only available to newer versions of Ubuntu rebuilt for older versions, like when you want to use KDE 4.10 for Ubuntu 12.04. Although rare, when you want to install newer versions of other software you might end up with conflicts.

The result this time was the following error message upon installing the ubuntu-sdk package:

Unpacking qtchooser (from .../qtchooser_0.0.1~git20121229.g8f08405-0ubuntu1~precise1~test6_amd64.deb) ...
dpkg: error processing /var/cache/apt/archives/qtchooser_0.0.1~git20121229.g8f08405-0ubuntu1~precise1~test6_amd64.deb (--unpack):
trying to overwrite '/usr/bin/qdbuscpp2xml', which is also in package libqt4-dev-bin 4:4.8.2+dfsg-2ubuntu1~precise1~ppa2
Processing triggers for man-db ...
Errors were encountered while processing:
/var/cache/apt/archives/qtchooser_0.0.1~git20121229.g8f08405-0ubuntu1~precise1~test6_amd64.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)

Trying to fix the error by removing libqt4-dev-bin only resulted in a long line of dependencies that will eventually conflict with the kde-workspace package, and you really don’t want to remove that (unless you want to get rid of KDE altogether).

To fix this, I tried a multitude of other options, only to realize that I could install all other packages in ubuntu-sdk to get what was needed to start developing apps for Ubuntu Phone and Tablet. These were installed by the single command:

sudo apt-get install qtdeclarative5-dev libqt5xmlpatterns5-dev qtscript5-dev qttools5-dev libqt5webkit5-dev qt3d5-dev qtmultimedia5-dev libqt5svg5-dev libqt5graphicaleffects5 qmlscene qtdeclarative5-dev-tools qttools5-dev-tools qtlocation5-dev qtsensors5-dev qtpim5-dev qtcreator ubuntu-qtcreator-qt5libs ubuntu-qtcreator-plugins qt-components-ubuntu qt-components-ubuntu-demos qt-components-ubuntu-examples

After this, you may launch ubuntu-qtcreator from terminal. It won’t find the Qt5 installation however, but you can point it to it by going to Tools > Options > Build & Run > Qt Versions and adding /usr/lib/x86_64-linux-gnu/qt5/bin/qmake:

Now you just need to add a new Kit pointing to the new Qt version. Before you do this, click OK and then open Options again to refresh your Qt versions available for Kits.

That’s it. Now you should be able to add a new Ubuntu UI project in Qt Creator and get started!