Book Review: Cross-Platform Development with Qt 6 and Modern C++

I recently received a review copy of the Cross-Platform Development with Qt 6 and Modern C++ by Nibedit Dey available from Packt. I find it interesting to read books on Qt in the midst of a major version shift, as many of the underpinnings of Qt are revisited and updated by the development teams.

In his book, Nibedit balances between the newer technologies used, e.g. CMake, function reference based signals and slots, etc while referring back to Qt 5 (and even Qt 4) practices such as QMake, the SIGNAL and SLOT macros, and more. This gives a good context to the reader, which is good for the reader, as older practices still are used in older Qt-based codebases.

The book is divided into blocks with increasing depth and complexity. This makes it a good read for the beginner, as well as the more experienced used of Qt. Either you start from the beginning and get introduced to both widgets and QML, or you can dive straight into the more advanced topics such as the model-view concepts.

What I particularly like about the book is the focus on the cross-platform capabilities of Qt. This is how Qt was started, and something that is often lost these days. Qt is more than a UI toolkit and the real strength is the ability to use a single code base to build native applications for the major desktop (and some not so major) as well as the major mobile platforms. This is a reoccuring theme throughout the book where it starts by installing the Qt development environment on all major platforms, discusses how to setup Qt for mobile development, as well as for how to deploy Qt applications in all these scenarios.

There are other highlights too such as the chapter on testing, discussions on profiling and optimizations, and other topics not commonly found in this type of book.

What could be said to be missing is any content on embedded device development, 3D tooling and classes, the design focused tooling, and more. But Qt is such a broad topic these days that it would be impossible to cover it all in a single book.

All in all, this is a recommended read!

Time for PineTime

I just recieved my PineTime and set it up with GadgetBridge on my Android device. So far it has been a pleasant experience.

The unboxing experience was good. Inside a very anonymous brown cardboard box was a white box with the device.

The device itself was nicely presented. Under the clock is a tiny users manual and a charging dock.

My device was shipped with version 1.2 of the InfiniTime firmware, so I’m one release behind. I ordered the sealed device (because the price is amazing), but I already am itching to get coding.

Some highlights:

  • Just works!
  • Snappy UX
  • Some cute phone apps included

Left to do:

  • Get the heart rate sensor reading over to GadgetBridge
  • Is there a way to clear the notifications on the clock?
  • More watch faces and apps!

All in all, this was more then I expected and I’m really looking forward to playing with it (and hopefully not brick it…)

XmlListModels in Qt 6

I had a look at a small XmlListModel based project of mine and started migrating the code from Qt 5.12 to Qt 6.2. The code ports pretty cleanly, but there are some caveats to be aware of.

As I’m lazy, I started by changing the imports from 2.12 to 6.2 and tried running the code. The first changes I had to make was to change the import from QtQuick.XmlListModel to QtQml.XmlListModel. I also learned that the import statement no longer requires a specific version to be specified – I’m not sure if I’m a fan of that quite yet.

The second change was that XmlRole has been renamed to XmlListModelRole, and that it no longer has a query property, but an elementName and attributeName property. I guess that saves Qt from having to implement support for XPath queries, and in my use-case (and most others), this should still be enough.

The last change I had to made was to silence a warning. It is no longer encouraged to connect objects directly to signals in QML. In my case, it was animations triggered by the onAdd and onRemove signals in a model. The trick is to declare the animation (in my case, a pair of SequentialAnimation instances, separately. Provide an id for them, and then call start on that id in the signal handler.

All in all, a quite pleasant migration experience with only superficial API changes to handle. All logic could be used as is. Nice!

Upgrading NextCloudPi

So I finally got around to upgrading my NextCloudPi to version 20 with the hub and all. I really like it so far.

It also seems that I bumped into a know issue. All of a sudden I could not upload files over 8kB. It turns out that for some reasons the sys_temp_dir in /etc/php/7.3/php.ini had shifted from my USB media (a portable HDD) to the default location (/var/www/nextcloud/tmp) during the upgrade. After a quick move back to /media/USBDrive/data/tmp, everything is back to normal.

I found the solution over at the nextcloud forums.

foss-north 2021 – Speakers and Call for Papers

TL;DR; Call for Papers closes on Sunday. Join foss-north 2021 and be a part of a great speaker line-up!

When planning foss-north, we always pre-announce some speakers early on. This helps set the tone of the conference, show sponsors that we have contents, and – interestingly – also increase the number of submissions to our call for papers.

This year is a bit special due to COVID-19 and the conference will be our third virtual installment, but we are still hoping to bring together great people and contents.

This year we have four pre-announced speakers who I’m very excited about. We have everything from stories from how the Internet is kept safe, how to use open source methods in your organization, how industry verticals collaborate around open source, all the way to how to write a Linux kernel driver.

So, in no particular order, I give you…

Anne-Marie Eklund Löwinder who will talk about signing the Internet root zone.

This will be the story from when Anne-Marie worked as Crypto Officer and attended the cermonies around DNSSEC. How do we protect the secrets that are used to protect the Internet itself.

Isabel Drost-Fromm who will talk about how to use the open source way beyond open source. By applying inner source principles, the magic that makes open source work can be used inside an organization too.

These are aspects such as sense of ownership, independence, and so on. If developers are willing to work for fun on open source, how do we create the same joy at work.

Leslie Hawthorn who will talk about strategic open source engagements for vertical markets. This is about how to work openly within an industry vertical and not a single component or project.

This is interesting from a foss-north perspective, as this is a conference about everything and nothing. I guess that makes it a horizontal event. How can vertical organizations meet to identify shared cross-cutting aspects.

Marta Rybczynska will give a talk appropriately titled Into the Jungle, about writing Linux kernel drivers.

In this talk we will look at writing a Linux network driver from scratch, diving into the deep end and learning how to swim.

The Call for Paper is still open until Sunday, so if you have a topic that you want to discuss, make sure to get your contribution in!

One more week of CfP

Usually foss-north takes place ~April. This year, foss-north 2021 will be virtual. We shifted the date to the end of May to try to make it possible to at least go hybrid and have some sort of conference experience, but in light of the current COVID-19 situation and the pace of the roll-out of the vaccination programmes, we decided for a virtual event.

One of the benefits of going virtual is that it is a lot easier to attend – both as a speaker and as audience. For those of you who want to speak, you have one week left to submit a talk proposal to the Call for Papers.

To register a talk requires you to log in using oauth via either github or google. We are working on adding more login alternatives, but as with many volunteer run efforts, time is the current limiting factor. If you feel that this is a blocker, please reach out to me over email and we can sort it out.

Some Vue + Django tips

As I wrote last time, I currently develop a web app based on Django and Vue using the django-compressor-parceljs. I’d like to mention some small things that I’ve learned since last.

Vue in development mode

I found it interesting that parceljs described how to get Vue into development mode for several bundlers, but failed to mention parcel. After some digging around, I figured out that parcel respects the NODE_ENV environment variable, so starting the django server with NODE_ENV=development ./ runserver does the trick. Now I get proper error messages from Vue.

Constantly rebundling

Another annoyance with the default configuration of the compressor, was that it compiles (bundles / compresses) the Vue files once every time the server is started. This really lengthened the change-build-test cycle time, so something needed to be done. It turns out that the solution is to set the COMPRESS_REBUILD_TIME to a really low value in the django settings, and the contents is compressed every time. I set it to one second on my development machine.

Disabling compression would break the Vue files, as the browser cannot run the Vue files natively, i.e. they need a compression to be possible to run.

The consequence of this configuration is that loading a view based on Vue takes a bit longer, but it takes way shorter time than restarting the django server, recreating the backend state and so on.

Exposing Django context to Javascript

Django exposes a set of context variables when loading a view. This avoids an unnecessary round-trip over the server to asynchronously request the info that I already know the view will need. I’ve developed a small convention for this.

In the Django template, I add something along these lines:

var context_title = '{{ title }}';
var context_actors = [
{% for actor in actors %}'{{ actor }}',
{% endfor %} ];

This copies the django context into Javascript space with the variable name prefix of context_. I then consume these in the Vue app’s mounted method, e.g.:

    mounted() {
        this.title = context_title;
        this.actors = context_actors;

This copies the state into the state of the app, which means that it is now a part of what the Vue interface is reactive to.

Looking at Vue

All applications are more or less connected today. The time of files on a disk, or moving them with a USB stick (or floppy) are over. Even file based programs are often synced using Nextcloud, dropbox, google drive, etc.

At Eperoto I’m busy building a backend for a React frontend, but there I stay in my comfort zone at the backend. It is Python, databases and files, just as I know and like things to be. I also have my normal toolbox for debugging and know how to execute a rich set of unit and integration tests to ensure that things stay sane over time.

However, I have another side project. Finally I’ve reached a point where have to do take a dip in the sea of web frontend. I don’t mean messing about with the odd Javascript snippet or fighting the windmil^Wcss.

The choices I was looking at where React, Angular and Vue. I did not do a deep analysis when picking a framework to try. Instead my reasoning was a long these lines:

  • React, I can pick this up from Manos at Eperoto.
  • Angular, requires npm and a setting up an environment to get started.
  • Vue, just needs a script to be included into your web page.

So, me being lazy, I choose to view Vue, which is pronounced view. It seems that I like a bit of pronunciation ambiguity in my frameworks.

Starting Slow

The reason for choosing Vue was the ability to run right in the browser. The strength of today’s browsers is the easy of deployment, but a hidden strength takes me back to the 1980s and 90’s. Everyone has a development environment sitting right in front of them. However, instead of being used to load programs like with the C64, you now I have to look for the development tools to bring up the console.,550x550.u10.jpg

I’m building a tool that is currently in closed alpha stage, so I cannot tell you too much about it. What I can show is one of my first Vue components. It is a text element, that when clicked turns into a text edit. I made two of these, one for editing a line, and one for editing a paragraph. It also sports a placeholder text if it is empty.

Vue.component('editable-text', {
     props: ['value', 'placeholder'],
     data: function() { return { editing: false, } },
     template: '{{value}}' + 
               '{{placeholder}}' +
     methods: {
         on_start_editing: function(e) {
             this.editing = true;
         on_end_editing: function() {
             this.editing = false;
     directives: {
         focus: {
             inserted(el) {

The code above makes it possible to use an editable-text tag. In order to be able to use the new tag, a Vue app needs to be created and mounted into the DOM of the web page. That means making it take over a div somewhere in the page, and let Vue manage its contents.

This is partially done in the Javascript file:

var app = Vue({
     el: '#app',
     data: [ text: '' ]

And the other half goes into the html:

<div id="app">
<editable-text v-model="text" placeholder="enter text"></editable-text>

<script src="js/vue-test.js"></script>

Finally I sprinkled some css on top of this to make it look sane. For instance, defining a placeholder class.

.placeholder {
     color: #999999;

Now we have something that works! I can include a development version of Vue into my page, which provides helpful feedback and point me in the right direction when I make mistakes. And then I can point this to a minified production build of Vue once I’m done.

Bring on the Django

For my backend needs I choose to go with Django. It might because I know Python, it might because of the extensive docs, the great intro tutorial (no damn video – text that I can read back and forth in my own order and pace), or maybe it is just because I’m old.

I like Django. Django plays nice. It is my choice of backend framework. End of discussion.

So, how do we make Vue and Django play nice?

First up, the index.html needs to be served from Django, and the CSRF cookie needs to be served along with it:

from django.views.decorators.csrf import ensure_csrf_cookie
def my_view(request):
     context = { … }
     return render(request, 'app/index.html', context=context)

Then the index.html needs to be adapted, e.g. use {% static 'app/index.html' %} instead of direct URLs and such. Then I place the js files in the app/static directory tree and run collectstatic to get it all in the correct location for nginx to serve it on the production server.

There is, of course, more to the app. I provide a REST-ish API passing JSON around via a set of views served under /api/…. I could probably have used the Django REST Framework here, but I tend to have to adapt things as the API isn’t really proper REST. I just picked out the convenient bits from it, so I roll my own for now. To make these requests, I use Axios, which plays nicely with the Django CSRF cookie.

What is the Point?

When using Vue like this, the question is really what the point is. For smaller stuff I’ve rolled this in plain Javascript. Including the AJAX (AJAJ?) calls and updating the DOM. What Vue helps me with is that I can share a single JSON state between the server and client, and Vue reactively renders it as needed on the client side.

Still, writing Vue as shown above kind of sucks. The template part of a component is html wrapped into a Javascript string. This means loads of fun when handing various string enclosing chars – ” and ‘, I’m looking at you two! Also, just stuffing everything in to a Javascript map makes everything a bit clumsy. It is really had to misspell something and it just stops working.

So, it was time to take it to the next level. Vue can handle single file components. This sounds a lot like classes to an old C++ guy like me, so bring it on!

The Computer Says No

Vue might know what a *.vue file is, but Firefox sure does not. It does not know what an include is either. It has lots of interesting errors about it, so it knows about a similar concept, but not what I needed it to know. Instead, I need a compiler and linker, or what the webistas call a bundler.

When mucking about with npm to get React or Vue things to work, I always ended up with webpack. But apparently web pack is old, boring, and slow (a bit like me). Having asked a friend, I learned that all the new kids use Parcel – a project that has an icon next to every heading on the whole site. Amazing…

What Parcel (and webpack or any other bundler) does is that it transform assets into Javascript, HTML and CSS, that the browser understands. It also combines the assets into fewer files, e.g. one js-file instead of a pile of them, thus reducing the number of files the browser has to request, thus making things a bit quicker.

If this sounds a lot like what a compiler (or transpiler) and linker would do – it is exactly what it is.

So, with a bundler like Parcel, I can build my *.vue files into Javascript, which I then can run in my Browser.

What is the Point – part 2

So, what does a Vue file look like?

    <span v-if="(!editing) && (!!value)" @click="on_start_editing()" >{{value}}</span>

    <span v-else-if="(!editing) && (!(!!value))" @click="on_start_editing()" class="placeholder">{{placeholder}}</span>

    <span v-else-if="editing">
        <input v-focus="" :value="value" @input="$emit('input', $" @keydown.enter="on_end_editing()" @blur="on_end_editing()" type="text" class="form-control">

export default {
    name: "editable-text",
    components: {},
    props: ['value', 'placeholder'],
    data: function() { return { editing: false, } },
    methods: {
        on_start_editing: function(e) {
            this.editing = true;
        on_end_editing: function() {
            this.editing = false;
    directives: {
        focus: {
            inserted(el) {

Apparently you can stuff some css in there as well. But still, the whole script part is just the same mess as before. Why, when making a transpiler, didn’t anyone come up with a sane syntax for properties, data, methods and directives?

Django and the Modern Frontend

Ignoring my annoyances with the the single file Vue components, it is still an improvement, so let’s continue.

I would like to build my frontend and backend in one go. I’d like a single git hash and know that the frontend and backend there fits together. At the same time, I don’t want to deploy my entire development toolchain to the production server. What I want is:

  • The Django stuff running an an uwsgi application.
  • All static files served directly from nginx.
  • All the frontend stuff to be a set of static files.

Enter: django-compressor-parceljs. Using this Django extension I can have parceljs do it’s work on the fly, in the Django app – and it allows me to build for production as well. More on this later.

However, going for parceljs took me one step beyond what I could do with simply including scripts into my web pages, I needed to install npm. I have a lot to say about this tool. To some extent it feels like it is trying to solve a problem with tooling more complex than the system, but let’s get to some specifics:

  • parceljs (and lots of command line tools) wants to get installed globally. This will collide head on with the distro, so it is a no-go for me.
  • When installing locally (in your dev tree) with npm, the executables end up in node_modules/.bin. A hidden directory. Thanks. Still, fixable by updating PATH.
  • The number of dependencies pulled in for a fairly small project is quite astonishing. The number of dependencies is huge. My package-lock.json clocks in at 6243 lines… That is for Vue, Axios and Parcel.
  • Many dependencies likes to not install their dependencies, but instead to tell me to do so in the form of error messages. I’m not sure I get the point of this – just install it, or have a recommends option or something.

Having setup django-compressor-parceljs and updated my PATH to include node_modules/.bin, it actually works. However, since the vue-files are compressed, the development experience is not perfect. I’d much rather be able to debug the vue-files directly via the Django server. If anyone knows how to, please tell :-)

I also created a small script that sets the COMPRESS_OFFLINE to true and then compil^Wcompresses the frontend on my development machine, meaning that I don’t have to install npm and all the dependencies of vue, parceljs, and axios on the server.


I’m still learning. I bet there is a lot that can be improved in this workflow. I also need to work on my CI/CD to do the offline compression automatically, and such. Still, I have some reflections to make from the viewpoint of a C++, Qt, QML, Python perspective:

  • All my web frontend friends appreciate the separation of behaviour from style from state. This can be done in QML, but requires discipline.
  • To me, the vue files are only half-way there. The script part of the file would benefit from a domain specific language such as QML, instead of putting everyting into a dictionary based on conventions.
  • To a large extent it feels like the web frontend world reinvents terminology – I really hope that there are some people carrying over experiences (in both directions). For instance, a bundler is just a transpiler + linker. Why not reusing common Makefile systems instead of re-inventing the wheel?
  • Why can’t I do nice inheritance and templating within Vue components? I.e. why do I have to duplicate all code for a line edit version of a clickable text when I have the text area version already? What am I missing?

Is anyone else doing this? How does your setup look and what does your working process look like?

Also, Happy Holidays and God Jul!

foss-north pod – a look at the stats

The foss-north pod about Licenses and Copyright has been around since May 1st, so I decided to talk a look at the stats. We gather very little statistics, but what I know is that we have 635 followers on YouTube and 108 over at (a peertube instance). We also serve the pod directly from, where we keep 14 days of access logs. What can we read out from them?

First of all – we decided to provide the pod as ogg or mp3, and it seems like a majority of you prefer the ogg version.

The downloads per day is a mess. From the episodes page I can see that we released the last two episodes on Nov 20, and Dec 4. I was a bit surprised not to see a spike on the 4th or 5ph, nor any apparent weekend vs workday pattern.

So, what was downloaded? Keep in mind that this is a two weeks window, and episode 26 was available for the last 3 days only. It seems like we have an even spread of listeners across many episodes, with a focus on episode 25, which was the latest during the time window.

Does this mean that we have a steady flow of new listeners? Not sure – the YouTube subscriber count raises steadily, so it might be the case.

Finally, let’s have a look at the user agent strings. I’ve tried to classify this into client OS for browsers, Apps for obvious pod listening apps, Bot for bots and other for the unidentified ones.

To my surprise, quite a few of you are listening from Windows machines. Then we have the Linux devices followed by Android, and Apps. Unless you count the bots, of course.

Another surprise is that OpenBSD is more common than OSX among our listeners.

It is possible to dig out more from the logs, but the evening is approaching. There are some surprises here, but it is good to see that we have had 800+ downloads over the past two weeks. To be honest, I was a bit worried when we shifted from YouTube to a podcasting format in August. Our views dropped quite dramatically on YouTube, but it seems that you found your way to the pod instead.

At the end of the day, the positive feedback given over social media and email is worth more than stats, so we will keep on going. Also, clocking in at almost 200 views on our episode on the definition of copyright and 250+ on the history of free and open source is quite amazing in my book, as this is a quite a narrow meta-topic inside the free and open source movement.