Introducing Boot to Qt – A Technology Preview

For a few months now, we have been working on a new project under the codename Boot to Qt, and today we launch it as a technology preview.

Boot to Qt is a commercial offering that provides a fully integrated solution for the creation of slick user interfaces on embedded devices. The offering includes:

  • A light-weight UI stack for embedded linux, based on the Qt Framework - Boot to Qt is built on an Android kernel/baselayer and offers an elegant means of developing beautiful and performant embedded devices.
  • Ready-made images – We have images for several different devices which include the Boot to Qt software stack, making it possible to get up and running with minimal effort from day one.
  • Full Qt Creator Integration – One-click deploy and run on hardware and a fully featured development environment.
  • Simulator – A VirtualBox based simulator which allows device development without hardware and opens up for simulating hardware input, such as GPS and  connectivity.

This technology preview focuses on the stack built on an Android baselayer. We also want to provide a similar software stack and the same convenience with ready-made images and IDE integration also for traditional embedded Linux, hopefully with a preview coming some time this summer.

We are expecting to have an official release towards the end of this year.

The following video shows Boot to Qt in action on our reference hardware:

And the following video show the Boot to Qt SDK works:

Scope of Boot to Qt

The software stack includes most of the Qt Framework:

  • Qt Core, Qt Gui, Qt Network, Qt Widgets, Qt Xml
  • Qt QML and Qt Quick
  • Qt Quick Controls
  • Qt Graphical Effects
  • Boot to Qt specific additions, including virtual keyboard, brightness control and power off/reboot functionality

The hardware devices supported in the Technology Preview are:

This is not a fixed set, but a place for us to start. If you have suggestions for other devices, let us know. The stack can also run on x86 hardware.

Right now, the stack is single-process. The launcher is a QML application which launches other QML applications in-process. We have looked briefly into using Android Gralloc APIs to do multiprocess sharing of hardware buffers, and we know it can be done, but we consider this out of the 1.0 scope.

We have also had similar discussions around Multimedia and Webkit, we want to have them in place, but maybe not in the initial release. The current software stack is already quite powerful and serves a number of different use cases.

Performance

Qt 5 introduced a new OpenGL ES 2.0 based scene graph to power Qt Quick 2. This makes Qt Quick very suitable for running on embedded hardware, even those with moderate specs. The demo launcher we ship with the images for instance, runs velvet at 60 FPS on all our hardware devices.

We were looking at CPU usage while playing around in the application launcher on the Nexus 7. When idle, it uses a shader to add a glow on the currently selected item and has a small particle system on the Qt logo in the corner. We found that when the launcher was just animating the glow on the active item and running the small particle system on the Qt logo, the CPU load was running at about 50%. When we flicked it, it dropped to 30% and when the finger was down and we were moving the list via touch, it dropped to below 20%. So it seemed that the more we did, the less the CPU load became. What we were observing was CPU frequency scaling. The CPU is a Quad-core clocked at 1.2GHz (with a special 1.3Ghz single-core operating mode), but when idle, it had disabled 3 cores and had scaled the one remaining core to 102Mhz. So we were able to animate a large part of a 1280×800 screen at 60FPS on a CPU clocked at 102Mhz, and were still only using half of that. 

For reference, the same animation runs at 2% CPU on the i.MX6 and 15% on the Beagle, none of which does do frequency scaling.

We also have pretty decent startup times. Below is a diagram comparing Boot to Qt to native Android. Now of course, full Android brings in a lot of additional stuff, but that is also the point. Most embedded devices do not need that.

Startup times, in seconds, from power-on until device reaches the B2Qt launcher or the Android Homescreen.
Lower is better

This is not too shabby, but we believe we can cut this down a bit more, at least when we start exploring various embedded Linux configurations. As an example,  Qt 5 on Raspberry Pi can start rendering after as little as 3 seconds.

Getting Access

For more information, see the product page.

Boot to Qt is available for evaluation upon request. If you want to try it out or if you are just interested in the software, please use the contact form on the product page and we will be happy to get you started. Of course, feel free to leave comments and questions on this blog too.

Enjoy!

Qt in World’s Fastest Electric Car

Digia has supported Metropolia University of Applied Sciences in their electric car project called Electric Raceabout (E-RA). This cool research project has produced a street legal electric sports car, which not only has the World record on ice, but also runs Qt.

Metropolia University, located in Helsinki, Finland, does extensive research on electric vehicles, one example being E-RA – an electric sports car built primarily by automotive engineering students.

With 4-wheel drive and well designed handling E-RA is a really capable sports car with impressive specs:

  • Top speed of over 260 km/h
  • Motor power of 282 kW
  • Peak torque of 800 Nm – in each wheel

And all this provided by an electric vehicle that is fully street legal (and rest assured, the Finnish road inspection is surely one of the toughest in the world to pass).

E-RA has achieved lap time of 8 minutes 42,72 seconds at Nürburgring Nordschleife, which was electric vehicle track record for quite a while, as well as World record as the fastest electric vehicle on ice with average speed of 252,09 km/h. Nicely driven E-RA has operating range of over 200 kilometers.

The students have built both the IVI system and the instrument cluster with Qt 4.8 running on top of Linux. I think the whole E-RA project is a really great proof of the skills the soon-to-graduate engineers have, and certainly the Qt parts are no less impressive.

Have a look on the enclosed video produced by the students at Metropolia University to hear the full story:

Introducing Qt Quick Layouts

If you want to create a QML application where the UI responds well to window resizing, the toolbox that Qt Quick offers has been somewhat limited. Qt 5.1 will offer the new Qt Quick types RowLayout, ColumnLayout and GridLayout for this purpose.

Background

Up until Qt 5.1, positioners and anchors have been the only Qt Quick tools available for arranging items in the UI.

Positioners are convenient for adding many items, but not always helpful for creating a resizable UI since they (as the name implies – surprise, surprise) only positions the items – the widths and heights are kept the same.

Anchors allows a bit more flexibility, at the price of verbosity. With anchors you can make an item stretch by binding one edge to the corresponding edge of the parent, and you set up a similar binding on the items’ opposite edge. However, you cannot make several items distribute themselves evenly if the window is resized.

The last option is to do the manual layouting yourself. This offers great flexibility, but it can be verbose, cumbersome and error-prone. During the development of Qt Quick Controls, we wanted to improve this and decided to provide a better and more convenient layout system.

import QtQuick.Layouts 1.0

By including the above import you will have RowLayout, ColumnLayout and GridLayout available in your toolbox. These layouts behave very much like their sisters found in the QtWidgets module: QHBoxLayout, QVBoxLayout and QGridLayout. It also tries to match the API of the Row, Grid and Column QML elements where it makes sense. So, if you are familiar with any of these APIs, you will find Qt Quick Layouts easy to grasp.

Alignment of items inside a cell can be specified with the Layout.alignment property.

Spans across rows or columns can be specified with the Layout.rowSpan and Layout.columnSpan properties.

Grid coordinates can be specified with the Layout.row and Layout.column properties.

Resizable items can be specified with the Layout.fillWidth and Layout.fillHeight properties. This was the main goal of the Qt Quick Layouts.

Minimum, Preferred and Maximum sizes can be specified with Layout.minimumWidth, Layout.preferredWidth and Layout.maximumWidth  properties (“Width” can be replaced with “Height” for specifying similar constraints to the height).

The feature set it adds might not look like a lot, but the fact that you can have both non-stretching items and stretching items in the same layout makes things easier and more intuitive in many cases.

Example

Suppose we need to create a ToolBar with two buttons and a slider that occupies the remaining space. When resizing, the extra space will be allocated to the slider.
Without Qt Quick Layouts, the solution with least code would probably be a mix between using a Row and using anchors:
ToolBar {
    Row {
        id: row
        spacing: 2
        anchors.verticalCenter: parent.verticalCenter
        ToolButton { iconSource: "images/go-previous.png" }
        ToolButton { iconSource: "images/go-next.png" }
    }
    Slider {
        anchors.left: row.right
        anchors.leftMargin: 2
        anchors.verticalCenter: parent.verticalCenter
        anchors.right: parent.right
    }
}
With Qt Quick Layouts, all items can be added to the same layout:
ToolBar {
    RowLayout {
        anchors.fill: parent
        spacing: 2
        ToolButton { iconSource: "images/go-previous.png" }
        ToolButton { iconSource: "images/go-next.png" }
        Slider { Layout.fillWidth: true }
    }
}
Notice how much shorter the declaration for the Slider element is. Also note that when using Qt Quick Layouts, the spacing only needs to be specified once. Code is reduced from 288 to 172 characters (whitespace excluded), which is a 40% reduction.

Summary

In this example, by using Qt Quick Layouts we got 40% less code, improved readability (not only because the code got shorter, but also because the structure of the code became closer to the structure of the UI).
If you want a resizable UI, you will probably find that Qt Quick Layouts are easier to use than anchors, positioners and manual layouting.

Qtified JavaScript

When writing JavaScript code, it doesn’t take long until I’m missing some function which is available in Qt’s C++ API. One very simple example is QList::contains. Checking whether an array contains a certain element works like this in JavaScript:

var names = ["Egon", "Peter", "Raymond", "Waldo"];
if (names.indexOf("Waldo") !== -1)
    print("We've found him!");

It would be nice if we could express the condition using a contains method but Array doesn’t provide one.
Luckily, JavaScript enables us to add methods to inbuilt types by modifiying the corresponding prototype object.

Array.prototype.contains = function(e) {
    return this.indexOf(e) !== -1;
}
if (names.contains("Waldo"))
    print("We've found him!");

Yay! Now we can use the contains method for all arrays!
But wait – there’s a surprise lurking right around the corner once you’re trying to iterate over the keys of the array.

for (var i in names)
    print(i);

This will print:

0
1
2
3
contains

I know, iterating over arrays should be done with an index variable…but still…this additional key is unexpected and asking for trouble.

The solution for this problem is to mark the property contains as non-enumerable. We can use the Object.defineProperty function for that which is available since JavaScript 1.8.5.

Object.defineProperty(Array.prototype, "contains", {
    value: function(e) { return this.indexOf(e) !== -1; },
    enumerable: false    // This is the default and can be omitted.
})

We’re passing to Object.defineProperty the object we want to enhance, the name of the property we want to add and a descriptor object that contains the attributes of our new property.
The value of  contains will be the function that we formerly passed directly to the prototype. Setting the enumerable property to false in the descriptor object will hide contains when using a for (... in ...) loop.

This way we can create a nice Qtish API for the inbuilt JavaScript types Array and String. This can be put into a .js file and used it in QML/JS or in qbs project files.

What do you think? Would such an API be helpful for your QML code? Which QList or QString method are you missing most?

Qt 5.1 Beta Released

I am happy to announce that we have today released Qt 5.1 Beta. We are now a major step closer to release Qt 5.1.0, which is expected before the summer. With the Beta release, binary installers for Qt 5.1 are available making it easier for you to get started with Qt. Let’s take a quick look at what is in the package.

Key functionality

The main driver for Qt 5.1 has been to increase the maturity of the new features introduced with Qt 5.0. We have improved the functionality and performance based on the feedback received from real-world use cases of Qt 5.0 and porting applications from Qt 4.x. We are able to meet your needs with Qt 5 because of the feedback and contributions from our growing ecosystem of about 500,000 developers in over 70 industries using Qt on numerous platforms and configurations.

The key new features of Qt 5.1 Beta include:

  • Qt Quick Controls module providing a set of reusable UI components especially for desktop applications created with Qt Quick
  • Qt Quick Layouts module bringing an easier, more intuitive, way to manage scalable UIs by ensuring that items are consistently arranged, and that the UI as a whole remains usable across different screen sizes.
  • Qt Serial Port module providing a cross-platform interface for using hardware and virtual serial ports in Qt applications
  • Possibility to use Qt Quick and Widgets together in the same application window
  • Qt Creator 2.7.1 bundled into the package, providing, for example, Qt Quick Designer for rapid prototyping, as well as improved C++11 code editing
  • Support for static Qt builds making it possible to address those use cases that cannot use dynamic linking
  • Introducing Qt Sensors as an officially supported module

For a more detailed look, please take a look to the Wiki article listing the new features of Qt 5.1 Beta, refer to the Qt 5.1 Documentation Snapshot as well as the Known Issues page in the wiki.

Binary installers

For most users the big thing with Qt 5.1 Beta compared to Qt 5.1 Alpha is binary installers that provide a convenient way of installing all you need to start developing with Qt without needing to build Qt yourself. With Qt 5.1 we are introducing some new configurations such as 64bit VS2012 with OpenGL, which is already available with the Beta. Soon after the Beta we are upgrading MinGW to version 4.8 and aim to bring also 32bit VS2012 with ANGLE configuration by the time we are releasing Qt 5.1.0.

Qt 5.1 Beta comes as an offline installer, but we will also be providing online installers before the release of Qt 5.1.0 final. The offline installer contains all you need to get started with Qt – tools, documentation, examples and pre-built Qt libraries. Source packages are available for those who wish to build Qt (or need to use a configuration that is not available as a pre-built binary). In addition to the desktop binaries, Qt 5.1 Beta comes with pre-built binaries for Android that can be bundled in with your application.

New platforms

Qt 5.1 Beta provides technology-preview level implementation of the new Android and iOS ports. In addition, Qt 5.1.0 final is planned to re-introduce Windows Embedded Compact 7 support that has earlier been available with Qt 4.8. We have added all these new platforms into the CI system so that each change that goes into Qt is verified to work on these as well as the other platforms and configurations already in the CI. At the moment, the CI for Android and iOS only tests for building, but we are gradually also adding the automated tests to be run on these new platforms, to decrease the possibility of regressions.

There is quite a lot of buzz around the new mobile ports and many are interested in knowing what is possible already with the Qt 5.1 Beta. In general, it can be stated that you can create stunning applications that run smoothly on both of the new platforms, but with limitations in supported functionality and the developer experience of getting your masterpiece into these devices.

With Android the following functionality works quite well in the Qt 5.1 Beta:

  • Widgets, Graphics View, Qt Quick 1 and Qt Quick 2 applications
  • OpenGL, networking and other core functionalities of Qt
  • Some parts of Qt Multimedia, for example QML media player
  • A set of commonly used sensors with Qt Sensors
  • Deploying your application to a device from Qt Creator
  • Debugging your application from Qt Creator
  • Qt 5.1 Beta comes with pre-built binaries for Android that can be bundled in with your application

With iOS the main issue is Qt Quick 2 not being available, as it needs a new QML engine, but the following functionality works quite well in the Qt 5.1 Beta:

  • Widgets, Graphics View and Qt Quick 1 applications
  • OpenGL, networking and other core functionalities of Qt
  • A set of commonly used sensors with Qt Sensors
  • Deploying your application to a device from Xcode / iTunes

Next steps

With the release of Qt 5.1 Beta we are one step closer to the Qt 5.1.0 final release, which we aim to have out before summer. Based on the feedback we receive from the Beta, there will be a Release Candidate created in a few weeks time, or alternatively a second Beta.

Please test out Qt 5.1 Beta and send us feedback:

  • File a bug report to bugreports.qt-project.org in case you find a new bug
  • Send e-mail to Qt Project mailing lists or contact us via IRC
  • If you have a commercial license, please contact Digia Qt Support via the Customer Portal

Qt 5.1 Beta release can be downloaded from the Digia Qt Customer Portal or from download.qt-project.org for open-source users.

 

Qt Contributors Summit 2013 – Please register

Guggenheim mirror balls
Guggenheim mirror balls

Registration for the Qt Contributors Summit 2013 is now open.

Before going into details, I’ve added a photo of the The Guggenheim mirror balls right outside the famous Guggenheim Museum in Bilbao. It can symbolise how every Qt contributor is linked together, working on the same project, using the summit to reflect on how Qt can be developed even better. Ok, Knut, snap out of it. Over to the practicalities.

Qt Contributors Summit 2013 registration is easy. Just use the Qt CS registration form.

Since the Qt Contributors Summit is an invitation-only event, please make sure you fit into one or more of the following before registering:

  • You are a Qt Project maintainer
  • You are a Qt Project approver
  • You took part in the previous Summit (Attendees at Qt CS 2012)
  • You took a sponsorship package including event invitations (coming soon)
  • You are in the organization team.
  • You are invited by a maintainer or the organization team and we still have seats left.
  • KDE Akademy contributor

Please add sessions unconference style

Since the main idea for the Qt CS is to let developers meet and make solutions, now is the time to pre-schedule sessions on the Qt CS program wiki. Please press “Join group” at the top of the wiki-page. We will  give you wiki-access as soon as possible and add you to the group.

Qt Creator 2.7.1 released

We take today’s Qt 5.1 beta release as an opportunity to push out some fixes to Qt Creator 2.7.

Around 40 bugs reported on our bugtracker have been fixed, so if you wonder if your favorite issue is one of them you might want to check out the list of “Qt Creator bugs that have been closed as ‘done’ for 2.7.1″ on our bug tracker. And of course there were other bugs fixed that do not appear on that list, so you should definitely check Qt Creator 2.7.1 out.

Download Qt Creator 2.7.1

How to tile widgets in a multiple document interface application

In Qt you can create multiple document interface (MDI) applications using a QMdiArea as the central widget. The QMdiArea widget serves as a window manager for the MDI windows. There are already functions available for tiling all the child windows into a tile pattern and for cascading them into a cascade pattern.

With MDI application it would sometimes be useful to tile the child windows also horizontally and vertically. The QMdiArea does not currently have an API to achieve this functionality but it’s quite simple to arrange the child windows in your application. We will next cover the steps needed to tile the child windows horizontally and vertically. The approach presented here is implemented on top of the MDI Example (http://qt-project.org/doc/qt-5.0/qtwidgets/mainwindows-mdi.html).

Let’s start by adding the actions in place so that the functionality can be triggered. To the MainWindow we will add one action for each function as private member variable:

QAction *tileVerticalAct;
QAction *tileHorizontalAct;

We will also add a private slot for each function:

void tileSubWindowsVertically();
void tileSubWindowsHorizontally();

Then we will initialize the actions and connect them to the right slots. We are going to add the following code to the createActions() method that already initializes actions for the application:

tileVerticalAct = new QAction(tr("Tile Vertically"), this);
tileVerticalAct->setStatusTip(tr("Tile the windows vertically"));
connect(tileVerticalAct, SIGNAL(triggered()), this, SLOT(tileSubWindowsVertically()));
tileHorizontalAct = new QAction(tr("Tile Horizontally"), this);
tileHorizontalAct->setStatusTip(tr("Tile the windows horizontally"));
connect(tileHorizontalAct, SIGNAL(triggered()), this, SLOT(tileSubWindowsHorizontally()));

And naturally we need to add the actions to the menu in order to launch the tiling. We can do this in the updateWindowMenu() where other actions are added to the menu too:

windowMenu->addAction(tileVerticalAct);
windowMenu->addAction(tileHorizontalAct);

Now we are ready to start tiling the child windows. We are going to take a closer look at the tileSubWindowsVertically() slot here. To begin with, we will start by checking that there are child windows in the MDI area to prevent us from trying to do modifications to non-existing windows.

if (mdiArea->subWindowList().isEmpty())
    return;

We are going to initialize a rectangle that defines the size of one child window. The width for a child window will naturally be the width of the MDI area. The height of a child window will be based on the height of the MDI area and the amount of child windows. Basically, we will just divide the MDI area height with the amount of child windows. The rectangle can then be used to set the geometry for each child widget in the MDI area.

QPoint position(0, 0);
foreach (QMdiSubWindow *window, mdiArea->subWindowList()) {
    QRect rect(0, 0, mdiArea->width(), 
               mdiArea->height() / mdiArea->subWindowList().count());
    window->setGeometry(rect);
    window->move(position);
    position.setY(position.y() + window->height());
}

While we are setting the geometry for the child widgets we also define the new position for them to have the windows tiled vertically. The child windows are ordered here based on the order of the child windows in the MDI area. By default, this order is the order in which the windows were inserted into the workspace. We will move the first window in the MDI area to the top left corner. While processing the child windows we will adjust the position so that each child window is position below the previously processed one. This is all we need to tile the child windows vertically.

Tiling the child windows horizontally will be almost the same; you only need to adjust the width and x-position of the window. The height of a child window will be the same as the height of the MDI area. The position of a child window will be on the right of the previous child.

void MainWindow::tileSubWindowsHorizontally()
{
    if (mdiArea->subWindowList().isEmpty())
        return;
    QPoint position(0, 0);
    foreach (QMdiSubWindow *window, mdiArea->subWindowList()) {
        QRect rect(0, 0, mdiArea->width() / mdiArea->subWindowList().count(), 
                   mdiArea->height());
        window->setGeometry(rect);
        window->move(position);
        position.setX(position.x() + window->width());
    }
}

Not that hard or what do you think? If you want to give it a try you can get the source code for the example here: Source code for example application . Shall you have any questions related to this you can always contact us in the Qt Support team via the Customer Portal.

Enginio: Qt Backend as a Service Launches Tech Preview

You may have already heard of Enginio at Qt Developer Days 2012  or you may have stumbled across our site, http://engin.io. We are now ready to officially open up the doors to our Enginio Tech Preview and welcome you to test it out. We have already had some early adopters who have given us valuable feedback which we have used to develop the product.

Why Enginio?

When we had a look at the existing cloud solutions, we saw that there was room for improvement. They were sometimes difficult to get started using and required specific knowledge of certain infrastructures or platforms and in most cases did not have Qt/C++ APIs. Using the experience we have from building backend solutions for various kinds of applications, we decided to create a solution that linked applications with a backend cloud storage based on Qt’s intuitive APIs. With Enginio developers can concentrate on creating their application making it visually pleasing and performing and let Enginio manage the backend functionality, scalability, security and performance.

Our goal was to build upon Qt’s motto of making “developer’s lives easier” and so what we wanted to do was provide developers with an uncomplicated and stress-free development experience in the backend. So, we started to create a solution that was easy to use and value-adding for Qt application development and at the same time transmit that Qt effortless development trait to other platforms. We want to make sure that the value-adding benefits of having a Qt backends are available to all. Enginio will be commercially available for both open-source and enterprise Qt users. For enterprise Qt users developing with a commercial license, a few additional value-adding features and functions will be made available to them later on.

The Enginio Technology Previews supports:

  • Web dashboard (UI for configuring & managing your backend)
  • Schema-less data storage (Place to store your application data)
  • Security model (Mechanism to control which end-users can access what data)
  • File support (Save small or large files in the cloud)
  • Full text search (Search stored data by its content)
  • Qt/QML client library (Convenient way to create applications)

How to get started?

1. Sign up for an Enginio account

2. Setup your new backend

3. Develop your App

The latest release version of the Qt library is available from the Enginio dashboard.

Shared library and QML extension plugin are built and installed as usual with `qmake && make && make install`

Qt example:

I. In Qt Creator choose File > New File or Project… and create new “Qt Gui Application”.
II. In the new project’s pro file add:

QT += network
win32:CONFIG(debug, debug|release): LIBS += -lenginioclientd
else: LIBS += -lenginioclient

III. In MainWindow.cpp:

// Include Enginio headers
#include <Enginio/Enginio>

// Instantiate Enginio Client
// Copy your backend ID and secret from Enginio dashboard
const QString backendId("YOUR_OWN_BACKEND_ID");
const QString backendSecret("YOUR_OWN_BACKEND_SECRET");
EnginioClient *client = new EnginioClient(backendId, backendSecret);

// Create new object to backend
EnginioJsonObject banana("objects.fruits");
banana.insert("name", QStringLiteral("Banana"));
banana.insert("price", 1.59);
EnginioObjectOperation *createOp = new EnginioObjectOperation(client);
createOp->create(banana);
createOp->execute(); // Initiates asynchronous operation

// Fetch objects from backend to list model
EnginioObjectModel *objectModel = new EnginioObjectModel();
EnginioQueryOperation *queryOp = new EnginioQueryOperation(client);
queryOp->setObjectType("objects.fruits");
queryOp->setModel(objectModel);
queryOp->execute();

 

QML example:

I. In Qt Creator choose File > New File or Project… and create new “Qt Quick 2 Application (Built-in Elements)”
II. In main.qml:

import io.engin 1.0 as Enginio

// Instantiate Enginio Client
// Copy your backend ID and secret from Enginio dashboard
Enginio.Client {
	id: client
	backendId: "YOUR_OWN_BACKEND_ID"
	backendSecret: "YOUR_OWN_BACKEND_SECRET"
}

Enginio.ObjectModel {
	id: objectModel
}

Enginio.QueryOperation {
	id: queryOp
	client: client
	model: objectModel // Query results are added to model
	objectTypes: ["objects.fruits"] // Get all fruit objects
}

Component.onCompleted: {
	// Create new object to backend
	var banana = {
		objectType: "objects.fruits",
		name: "Banana",
		price: 1.59
	};
	var createOp = client.createObjectOperation();
	createOp.create(banana);
	createOp.execute();
	createOp.finished.connect(function() {
		// Fetch objects from backend to list model
		queryOp.execute();
	});
}

Build and your connected application is ready.

We would like to invite more people to test and provide feedback. However, please bear in mind that the service is still under development and you may experience some bugs, changes and breaks. Go and check it out at http://engin.io. Let us know what you think!

You can reach the Enginio development team at mailus@engin.io.

Retina display support for Mac OS, iOS and X11

Qt 5.0 added basic support for retina reasonable resolution displays. The upcoming Qt 5.1 will improve the support with new API and bug fixes. Qt 4.8 has good support, and backports of some of the Qt 5 patches are available.

While this implementation effort is mostly relevant to Mac and iOS developers, it is interesting to look at how other platforms handle high-dpi displays. There are two main approaches:

  • DPI-based scalingWin32 GDI and KDE. In approach the application works in the full physical device resolution and is provided with a DPI setting or scaling factor, which should be used to scale layouts. Fonts are automatically scaled by the OS (as long as you specify the font sizes in points and not pixels)
  • Pixels By Other Names. In this approach the physical resolution is (to various degrees) hidden to the application. Physical pixels are replaced with logical pixels:
    Platform/API Logical Physical
    HTML CSS pixel Device pixel
    Apple Point Pixel
    Android Density-independent pixel (dp) (Screen) Pixel
    Direct2D Device Independent Pixel (DIP) Physical Pixel
    Qt (past) Pixel Pixel
    Qt (now) Device-Independent Pixel Device Pixel

Qt has historically worked in device pixels with DPI scaling. Back in 2009 support for high DPI values on Windows was improved. The Qt layouts do however not account for increased DPI. Qt 5 now adds support of the “new pixels” type of scaling.

(Are there other high-dpi implementations out there? Use the comments section for corrections etc.)

Mac OS X High-dpi Support

The key to the OS X high-dpi mode is that most geometry that was previously specified in device pixels are now in device-independent points. This includes desktop geometry (which on the 15 inch retina MacBook Pro is 1440×900 and not the full 2880×1800), window geometry and event coordinates. The CoreGraphics paint engine is aware of the full resolution and will produce output at that resolution. For example, a 100×100 window occupies the same area on screen on a normal and high-dpi screen (everything else being equal). On the high-dpi screen the window’s backing store contains 200×200 pixels.

The main benefits of this mode is backwards compatibility and free high-dpi vector graphics. Unaware applications simply continue to work with the same geometry as before and can keep hardcoded pixel values. At the same time they get crisp vector graphics such as text for free. Raster graphics does not get an automatic improvement but is manageable. The downside is the inevitable coordinate system confusion when working with code that mixes points and pixels.

The scale factor between points and pixels is always 2x. This is also true when changing the screen resolution – points and pixels are scaled by the same amount. When scaling for “More Space” applications will render to a large backing store which is then scaled down to the physical screen resolution.

Scaling the user interface resolution on Mac OS

If you don’t have access to retina hardware there is also an emulation mode which can be useful when used on an extra monitor. Open Display Properties and select one of the HiDPI modes. (See this question on stack overflow if there are none.)

Enabling high-dpi for OS X Applications

High DPI mode is controlled by the following keys in the Info.Plist file:

<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<string>True</string>

Qmake will add these for you. (Strictly speaking it will only add NSPrincipalClass, NSHighResolutionCapable is optional and true by default).

If NSHighResolutionCapable is set to false, or the keys are missing, then the application will be rendered at the “normal” resolution and scaled up. This looks horrible and should be avoided, especially since the high-dpi mode is very backwards compatible and the application gets a lot of high-dpi support for free.

Scaled Qt Creator

High DPI Qt Creator

 

 

 

 

 

 

 

 

 
(Appart from a patch to update the “mode” icons, this an unmodified version of Qt Creator.)

Qt implementation details

Mac OS 10.8 (unofficially 10.7?) added support for high-dpi retina displays. Qt 4 gets this support for free, since it uses the CoreGraphics paint engine.

Qt 5 uses the raster paint engine and Qt implements high-dpi vector graphics by scaling the painter transform. HITheme provides high-dpi Mac style for both Qt 4 and 5. In Qt 5 the fusion style has been tweaked to run well in high-dpi mode.

OpenGL is a device pixel based API and remains so in high-dpi mode. There is a flag on NSView to enable/disable the 2x scaling – Qt sets it in all cases. Shaders run in device pixels.

Qt Quick 1 is built on QGraphicsView which is a QWidget and gets high-dpi support through QPainter.

Qt Quick 2 is built on Scene Graph (and OpenGL) which has been updated with high-dpi support. The Qt Quick Controls (née Desktop Components) has also been updated to render in high-dpi mode, including using distance field text rendering.

The take-away point here is that for app developers this doesn’t matter, you can do most of your work in the comfort of the device-independent pixel space while Qt and/or the OS does the heavy lifting. There is one exception which is raster content – high-dpi raster content needs to be provided and correctly handled by application code.

Widgets and QPainter

QPainter code can mostly be kept as is. As an example lets look at drawing a gradient:

QRect destinationRect = ...
QGradient gradient = ...
painter.fillRect(rect, QBrush(gradient));

On high-dpi displays the gradient will have the same size on screen but will be filled with more (device) pixels.

Drawing a pixmap is similar:

QRect destinationRect = ...
QPixmap pixmap = ...
painter.drawPixmap(destinationRect, pixmap);

To avoid scaling artifacts on high-dpi displays the pixmap must contain enough pixels: 2x the width and height of destinationRect. The application can either provide one directly or use QIcon to manage the different resolutions:

QRect destinationRect = ...
QIcon icon = ...
painter.drawPixmap(destinationRect, icon.pixmap(destinationRect.size()));

QIcon::pixmap() has been modified to return a larger pixmap on high-dpi systems. This is a behavior change and can break existing code, so it’s controlled by the AA_UseHighDpiPixmaps application attribute:

qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);

The attribute is off by default in Qt 5.1 but will most likely be on by default in a future release of Qt.

Edge cases and devicePixelRatio

Qt Widgets has some edge cases. Ideally it would pass QIcons around and the correct pixmap would be select at draw time, but in reality Qt API often produces and consumes pixmaps instead. This can cause errors when the pixmap size is used for calculating layout geometry – the pixmap should not use more space on screen if it’s high-resolution.

To indicate that a 200×200 pixmap should occupy 100×100 device-independent pixels use QPixmap::devicePixelRatio(). Pixmaps returned from QIcon::pixmap() will have a suitable devicePixelRatio set.

QLabel is one “pixmap consumer” example:

QPixmap pixmap2x = ...
pixmap2x.setDevicePixelRatio(2.0);
QLabel *label = ...
label->setPixmap(pixmap2x);

QLabel then divides by devicePixelRatio to get the layout size:

QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio();

Several issues like this has been fixed in Qt, and application code can have similar code that needs to be corrected before enabling AA_UseHighDpixmaps.

The devicePixelRatio() accessor is available on several Qt classes:

Class Note
QWindow::devicePixelRatio() Preferred accessor
QScreen::devicePixelRatio()
QGuiApplication::devicePixelRatio() Fallback if there is no QWindow pointer
QImage::[set]devicePixelRatio()
QPixmap::[set]devicePixelRatio()

Text

Font sizes can be kept as-is, and produce similarly-sized (but crisp) text on high-dpi displays. Font pixel sizes are device-independent pixel sizes. You never get tiny text on high-dpi displays.

QGlWidget

OpenGL operates in device pixel space. For example, the width and height passed to glViewport should be in device pixels. QGLWidget::resizeGL() gives the width and height in device pixels.

However, QGLWidget::width() is really QWidget::width() which returns a value in device-independent pixels. Resolve it by multiplying with widget->windowHandle()->devicePixelRatio() if needed.

Qt Quick 2 and controls

Qt Quick 2 and the Qt Quick Controls work well out-of-the box. As with widgets coordinates are in device-independent pixels. Qt Quick has fewer raster-related edge cases, since the QML Image element specifies the image source as a url which avoids passing around pixmaps.

Qt Quick Controls

One exception is OpenGL shaders that run in device pixel space and see the full resolution. This is usually not a problem, the main thing to be aware of is that mouse coordinates are in device-independent pixels and may need to be converted to device pixels.

shadereffects example in action

Managing high-resolution raster content

As we have seen, raster content won’t look nice when scaled and high-resolution content should be provided. As an app developer you have two options: (ignoring the “do-nothing” option)

  • Replace existing raster content with a high-resolution version
  • Provide separate high-resolution content

The first option is convenient since there is only one version of each resource. However, you may find (or your designer will tell you) that resources like icons look best when created for a specific resolution. To facilitate this, Qt as adopted the “@2x” convention for image filenames:

foo.png
foo@2x.png

High-resolution content can be provided side-by-side with the originals. The “@2x” version will be loaded automatically when needed by the QML Image element and QIcon:

Image { source = “foo.png” }
QIcon icon(“foo.png”)

(remember to set AA_UseHighDpiPixmaps for QIcon)

Experimental cross-platform high-dpi support:

QPA allows us to relatively easily make a cross-platform implementation. The Qt stack can be divided into three layers:

  1. The Application layer (App code and Qt code that uses the QPA classes)
  2. The QPA layer (QWindow, QScreen, QBackingStore)
  3. The platform plugin layer (QPlatform* subclasses)

Simplified, the application layer operates in the device-independent pixel space and does not know about device pixels. The platform plugins operates in device pixel space and does not know about device-independent pixels. The QPA layer sits in between and translates, based on a scale factor set by the QT_HIGHDPI_SCALE_FACTOR environment variable.

In reality the picture is a little bit more complicated, with some leakage between the layers and the special Mac and iOS exception that there is additional scaling on the platform.

Code is on github. Finally, screenshots of Qt Creator on XCB:

DPI scaled Qt Creator

QT_HIGDPI_SCALE_FACTOR=2 Scaled Qt Creator

 

 

The Qt Blog

Welcome to the new Qt blog! We have consolidated all the blog posts from the Qt Labs Blog with the posts from the Digia Qt Commercial blog. Our intention is to provide you with one area for all Qt development posts from our Qt experts.

As Qt enters a new era, we are working diligently to provide you with an ever-growing Qt Blog that includes projects, awesome ideas, tips and tricks and product info from our pool of very clever Qt developers.

This blog will be transforming as we move forward, so keep your eyes peeled for new developments.

Recent Comments

Archives

Categories