Behind the Scenes of Embedded Updates

An over-the-air (OTA) update capability is an increasingly critical part of any embedded product to close cybersecurity vulnerabilities, allow just-in-time product rollouts, stomp out bugs, and deliver new features. We’ve talked about some of the key structural elements that go into an embedded OTA architecture before. But what about the back end? Let’s address some of those considerations now.

The challenges of embedded connectivity

The ideal of a constant Internet connection is more aspiration than reality for many embedded devices. Sporadic connections, costly cellular or roaming charges, and limited bandwidth are common hurdles. These conditions necessitate smart management of update payloads and robust retry strategies that can withstand interruptions, resuming where they left off without getting locked in a continually restarting update cycle.

There are other ways to manage spotty connections. Consider using less frequent update schedules or empower users to initiate updates. These strategies however have trade-offs, including the potential to miss critical security patches. One way to strike a balance is to implement updates as either optional or mandatory, or flag updates as mandatory only when critical, allowing users to pace out updates when embedded connectivity isn’t reliable.

To USB or not to USB

When network access is very unreliable, or even just plain absent, then USB updates are indispensable for updating device software. These updates can also serve as effective emergency measures or for in-field support. While the process of downloading and preparing a USB update can often be beyond a normal user’s capability, it’s a critical fallback and useful tool for technical personnel.

OTA servers: SaaS or self-hosted

Deciding between software as a service (SaaS) and self-hosted options for your OTA server is a decision that impacts not just the update experience but also compliance with industry and privacy regulations. While SaaS solutions can offer ease and reliability, certain scenarios may necessitate on-premise servers. If you do need to host an OTA server yourself, you’ll need to supply the server hardware and assign a maintenance team to manage it. But you may not have to build it all from scratch – you can still call in the experts with proven experience in setting up self-hosted OTA solutions.

Certificates: The bedrock of OTA security

SSL certificates are non-negotiable for genuine and secure OTA updates. They verify your company as the authentic source of updates. Choosing algorithms with the longest (comparatively equivalent) key lengths will extend the reliable lifespan of these certificates. However, remember that certificates do expire; having a game plan in place to deal with expired certificates will allow you to avoid the panic of an emergency scramble if it should happen unexpectedly.

Accurate timekeeping is also essential for validating SSL certificates. A functioning and accurate real-time clock that is regularly NTP/SNTP synchronized is critical. If timekeeping fails, your certificates won’t be validated properly, causing all sorts of issues. (We recommend reading our OTA best practice guide for advice on what to do proactively and reactively with invalidated or expired certificates.

Payload encryption: Non-negotiable

Encrypted update payloads are imperative as a safeguard against reverse-engineering and content tampering. This is true for OTA updates as well as any USB or offline updates. Leveraging the strongest possible encryption keys that your device can handle will enhance security significantly.

Accommodating the right to repair

The growing ‘right to repair’ movement and associated legislation imply that devices should support updates outside of your organization’s tightly controlled processes. This may mean that you need to provide a manual USB update to meet repair requirements without exposing systems to unauthorized OTA updates. To prevent your support team from struggling with amateur software updates, you’ll want to configure your device to set a flag when unauthorized software has been loaded. This status can be checked by support teams to invalidate support or warranty agreements.

Summary

By carefully navigating the critical aspects of OTA updates, such as choosing the right hosting option and managing SSL certificates and encryption protocols, your embedded systems can remain up-to-date and secure under any operating conditions. While this post introduces the issues involved in embedded-system updates, there is much more to consider for a comprehensive strategy. For a deeper exploration and best practices in managing an embedded product software update strategy, please visit our best practice guide, Updates Outside the App Store.

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Behind the Scenes of Embedded Updates appeared first on KDAB.

Qt for Android Supported Versions Guidelines

Qt for Android usually supports a wide range of Android versions, some very old. To keep the supported versions to a level that’s maintainable by Qt, especially for LTS releases which are expected to live for three years, Qt for Android is adopting new guidelines for selecting the supported versions for a given Qt release in the hope that this effort would make the selection clear and transparent, and help shape proper expectations of support for each Qt for Android release.

Qt Performance and Tools Update Part 1

Performance optimisation matters when you are trying to get your application working in a resource-constrained environment. This is typically the case in embedded but also in some desktop scenarious you may run short on resources so it’s not a matter without significance on desktop either.

What we mean by performance here is the ability to get the application running to fulfill its purpose, in practice typically meaning sufficient FPS in the UI and meeting other nonfunctional requirements, such as startup time, memory consumption and CPU/GPU load.

There have been a number of discussions on Qt performance aspects and as we have been working on a number of related items we thought now could be a good time to provide a summary of all the activities and tools we have. You can optimise the performance of your application by utilising them and also use them in testing. We have been working on improving existing performance tools as well as adding new ones and providing guidelines, so let’s look at the latest additions. This post is starting a stream of blog posts to help you with performance optimisation and provide a view to our activities in this area.

Qt for Android: a Novel Approach

This blog post is the third one in a series in which we will examine an exciting feature, a change that is first coming out as a Technology Preview in 6.7. Previously, there have been blog posts about Qt Quick in Android as a View and Qt Tools for Android Studio. It is so new that even we do not know how to call this novel approach yet 😊 Give us a name proposal in comments! In this blog post let us look at a few things: workflow, tooling, needed Qt modules, and a small glance at the technical mechanism. 

PyQt6 & PySide6 Books updated for 2024 — Extended and updated with new examples, demos including Model View Controller architecture

Hello! Today I have released new digital updates to my book Create GUI Applications with Python & Qt.

This update brings all versions up to date with the latest developments in PyQt6 & PySide6. As well as corrections and additions to existing chapters, there are new sections dealing with form layouts, built-in dialogs and developing Qt applications using a Model View Controller (MVC) architecture. The same corrections and additions have been made to the PyQt5 & PySide2 editions.

As always, if you've previously bought a copy of the book you get these updates for free! Just go to the downloads page and enter the email you used for the purchase.

You can buy the latest editions below --

If you bought the book elsewhere (in paperback or digital) you can register to get these updates too. Email your receipt to register@pythonguis.com

Enjoy!

The Smarter Way to Rust

If you’ve been following our blog, you’re likely aware of Rust’s growing presence in embedded systems. While Rust excels in safety-by-design, it’s also common to find it integrated with C++. This strategic approach leverages the strengths of both languages, including extensive C++ capabilities honed over the years in complex embedded systems. Let’s delve into some key concepts for integrating Rust and C++.

Adding Rust to C++

If you’re adding Rust to an existing C++ project, you need to start in the right place. Begin by oxidizing (that is, converting code to Rust) areas that are bug-prone, difficult to maintain, or with security vulnerabilities. These are where Rust can offer immediate improvements. Focus on modules that are self-contained, have clean interfaces, and are primarily procedural rather than object-oriented. For example, libraries that handle media or image processing can be prime candidates for rewriting in Rust as these are often vulnerable to memory safety issues. Parsers and input handling routines also stand to benefit from Rust’s guarantees of safety.

Deciding between Rusting outside-in or inside-out

As your project scales, weigh the merits of maintaining a C++ core with Rust components versus a Rust-centric application with C++ libraries. For smaller, newer projects, starting with Rust may help you avoid the complexities of dealing with C foreign function interfaces (FFIs). This decision may hinge on your safety priorities: if your project’s core tenant is safety, then a Rust-centric approach may be preferable. Conversely, if safety is needed only in certain areas of C++ project, keeping the core in C++ could be more practical.

Another consideration is how your project handles multi-threading. Mixing threading and memory ownership between Rust and C++ is very complex and prone to mistakes. Depending on how your application uses threads, this may tilt the decision in the direction of either C++ or Rust as the main “host” application.

Keeping C++ where it excels

While Rust offers many advantages, particularly in safety, C++ has its own merits that shouldn’t be hastily dismissed. The decision to rewrite should be strategic, based on actual needs rather than a pursuit of language purity since the risk of introducing new bugs through rewriting well-tested and stable C++ code outweigh the benefits of a Rust rewrite. Time-tested C++ code, particularly in areas like signal processing or cryptography, might be best left as is. Such code is often highly optimized, stable, and less prone to memory-related issues. As the saying goes, if it’s not broken, don’t “fix” it.

Navigating Rust limitations

Despite its growing ecosystem, Rust is still relatively young. Relying on packages maintained by small teams or single individuals carries inherent risks. Moreover, as Rust is still in a period of rapid language evolution, this could result in frequent updates, posing challenges for large-scale or long-lived projects. In certain scenarios, such as very large codebases, specific embedded support requirements, or projects with long development cycles, C++ may remain the more practical choice. It is wise to use C++ where stability and longevity are important, and Rust where safety is critical but some development fluidity is acceptable.

Summary

By combining the reliability of C++ with the safety of Rust, developers can engineer systems that endure while minimizing the risk of common programming pitfalls. If you’re interested in reading more about this topic, you’ll want to read our best practice guide on Rust/C++ integration, which was created in collaboration with Ferrous Systems co-founder Florian Gilcher.

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post The Smarter Way to Rust appeared first on KDAB.

Qt Design Studio 4.5.1 Released

Great news! The latest Qt Design Studio update 4.5.1 is ready for download!

This update resolves some issues from the 4.5 release and also brings in an exciting new example for Figma Effects support.

Example for Design Effects

We created an example for the Figma Design Effects, which we started supporting with the 4.5 release. You can check out the example from here or download it as part of the updated examples in Qt Design Studio.

The example demonstrate how to create modern design styles using Figma and Qt Quick. You can view the Figma project here. The Figma projects can be exported using the Qt Figma Bridge, resulting in QML that utilizes DesignEffects for a non-destructive workflow without the need to revert to images for effects.

Here's a tutorial video that provides a great overview of DesignEffects and the Design Effect Example.

 

 

Exciting Enhancements

We have significantly enhanced vital aspects of the user experience, focusing on improving the functionality and compatibility of Figma Bridge and MCU integration. Please take a look at the highlights below.

  • Fixed that fonts and assets are not part of .qmlproject config
  • Fixed that 2D View is not showing proper visual
  • Added support for Grid, Row, and Column Layouts for MCU
  • Fixed that Figma bridge exported result mismatch
  • Fixed that Qt Design Studio generates the wrong code for image files in MCU projects
  • Fixed that grouping items in an MCU project results in uncompilable code
  • Added TextInput support for MCU projects
  • Fixed that true/false triggers an error in Connection View
  • Fixed that rectangles with gradients cannot have a transparent color
  • Fixed that gradient fills do not have Alpha property

For in-depth details, including a comprehensive list of enhancements and bug fixes, head to our change log and release notes.

To understand Qt Design Studio 4.5 completely, don't hesitate to explore the original blog post. Get ready to experience a more polished and powerful Qt Design Studio!

Learn How to Automate GUI Testing with Squish: Free Courses on Qt Academy

by Emilia Valkonen-Damjanovic (Qt Blog)

Qt Academy, the free online platform for learning Qt framework and tools, is constantly updated with new content. Our new learning path made up of 9 courses, is specifically designed for Squish, and offers an ideal baseline for those interested in automated GUI testing. Created by Qt's team of Customer Success Engineers, this path features a comprehensive guide to mastering Squish and will equip you with all the necessary skills to get started with ease. 

Anchoring Qt Quick Components Instantiated with JSON

You’ve reached the third and final entry of the Instantiating arbitrary Qt Quick components with JSON series. Part 1 and Part 2 can be found at their respective links.

The first part focuses on the software design pattern used to dynamically instantiate components. The second one shows how to layout these dynamic components by incorporating QML’ s positioning and layout APIs.

Part 3: Anchors and the Dangers of Remote Code Execution

On the last entry I wrote about:

1. Coordinate positioning

2. Item positioners

3. Qt Quick Layouts

Now there’s:

4. Anchors

Unfortunately for us, this is were the QML Engine becomes a limiting factor. Items in QML, instantiate QObjects. Every QObject in Qt contains an ID. We can set that ID from QML the moment we instantiate our component, like so:

Item {
    id: myID
}

Nevertheless, id is not a normal QML property. In fact it is no property at all. As a result, we’re unable to set an id after instantiation. Since neither Repeater or Instantiator allows us to set individual IDs during object creation, we have no means for naming our instantiated components, and therefore we cannot refer to them from other components. This limits our ability to anchor components to siblings that come from the repeater. We can only anchor to the parent and to siblings defined traditionally from the QML document.

With this in mind, let’s see how far can we take the use of anchors in our components factory.

But first, a quick reminder… Qt provides us with two syntaxes for using anchors, an object syntax and a shorthand for its individual properties:

anchors.left: parent.right

anchors: {
    left: parent.right
}

To keep things simple, I make use of the longer syntax in our model:

// This model lays out buttons vertically
property var factoryModel: [
    {
        "component": "RowLayout"
        "anchors": {
            "fill": "parent"
        }
        "children": [
            {
               "component": "Button"
               "text": "Button 1"
            },
            {
               "component": "Button"
               "text": "Button 2"
            }
        ]
    }
]

Let’s start by implementing fill: parent. If we were to assign the string from our model, which says “parent”, to our instantiator, the assignment would fail because we cannot assign a string where an object id is expected.

// This would fail...
instantiator.anchors.fill = modelData.anchors.fill;

// because it evaluates to this:
instantiator.anchors.fill = "parent";

Instead, we must parse the value from our model into valid JavaScript, and for that we use Javascript’s eval function. Calling eval will return whichever value the JS expression inside the string evaluates to. Here “parent” will point to the parent property relative to the context where eval is run. For the purposes of anchoring, this is fine.

Our code now looks like:

if (typeof(modelData.anchors.fill) === "string")
    instantiator.anchors.fill = eval("instantiator."
                                     + modelData.anchors.fill);

There’s a couple of issues:

  • Qt Creator’s annotator suggests not to use eval. You may ask: Why is this? Because eval treats the string from our model as a JavaScript expression. Nothing prevents a malicious actor from injecting JS code into that string that could attach a payload to our app to our app to later perform a remote code execution attack. A malicious actor might write something like:
"parent;this.onPressed=function(){/*arbitrary_code_goes_here*/};"  // Note that I don't know if this example really works

This takes care of the parent assignment, then overrides the contents of onPressed with a function that runs arbitrary code for the user to unsuspectingly execute. This is why every respectable linter and static analyzer for JavaScript will warn you not to use eval or any of its equivalent methods; in order to prevent remote code execution.

  • If security is not a big enough concern for you, eval cannot be parsed by the new JavaScript compilers introduced with Qt 6. The compiler will error out saying:

error: The use of eval() or the use of the arguments object in signal handlers is not supported when compiling qml files ahead of time. That is because it’s ambiguous if any signal parameter is called “arguments”. Similarly the string passed to eval might use “arguments”. Unfortunately we cannot distinguish between it being a parameter or the JavaScript arguments object at this point.

Part 4: Defeat Remote Code Execution by Sanitizing Inputs

My preferred way to sanitize inputs is using Regular Expressions. We want to guarantee the strings from our models evaluate to a valid anchor name.

Valid anchor names include:

  • parent
  • idName.top
  • idName.right
  • idName.bottom
  • idName.left
  • idName.baseline
  • idName.verticalCenter
  • idName.horizontalCenter

Here’s a RegEx I wrote that covers all anchors:

const anchorsRegex =
/[a-z_][a-zA-Z_0-9]*(\.(top|right|bottom|left|baseline|(vertical|horizontal)Center))?/;

We can use it to sanitize anchor inputs from the model, like so:

anchorsRegex.test(modelData.anchors.fill))

The key is to remove all characters that could be used to execute malicious content. If one of such characters must be present, then we make sure its uses are restricted, as we’ve seen here.

Here’s what my final code for attaching anchors looks like:

Component {
  id: loaderComp
  Loader {
    id: instantiator
    // ...
    onItemChanged: {
  // Anchor properties
  if (typeof(modelData.anchors) === "object") {
    // Regex for validating id and id.validAnchorline
    const anchorsRegex = /[a-z_][a-zA-Z_0-9]*(\.(top|right|bottom|left|baseline|(vertical|horizontal)Center))?/;
    // Before attempting to assign,
    // check that properties are present in object
    // and that model attributes aren't undefined.
    if ((typeof(modelData.anchors.fill) === "string")
      && anchorsRegex.test(modelData.anchors.fill)) {
      instantiator.anchors.fill = eval("instantiator."
                                         + modelData.anchors.fill);
    }
    else if ((typeof(modelData.anchors.centerIn) === "string")
      && anchorsRegex.test(modelData.anchors.centerIn)) {
      instantiator.anchors.centerIn = eval("instantiator."
                                         + modelData.anchors.centerIn);
    }
    else {
      if ((typeof(modelData.anchors.left) === "string")
        && anchorsRegex.test(modelData.anchors.left)) {
        instantiator.anchors.left = eval("instantiator."
                                         + modelData.anchors.left);
        item.anchors.left = item.parent.anchors.left;
      }
      if ((typeof(modelData.anchors.right) === "string")
        && anchorsRegex.test(modelData.anchors.right)) {
        instantiator.anchors.right = eval("instantiator."
                                         + modelData.anchors.right);
        item.anchors.right = item.parent.anchors.right;
      }
      if ((typeof(modelData.anchors.baseline) === "string")
        && anchorsRegex.test(modelData.anchors.baseline)) {
        instantiator.anchors.baseline = eval("instantiator."
                                         + modelData.anchors.baseline);
        item.anchors.top = item.parent.anchors.top;
      }
      else {
        if ((typeof(modelData.anchors.top) === "string")
          && anchorsRegex.test(modelData.anchors.top)) {
          instantiator.anchors.top = eval("instantiator."
                                         + modelData.anchors.top);
          item.anchors.top = item.parent.anchors.top;
        }
        if ((typeof(modelData.anchors.bottom) === "string")
          && anchorsRegex.test(modelData.anchors.bottom)) {
          instantiator.anchors.bottom = eval("instantiator."
                                         + modelData.anchors.bottom);
          item.anchors.bottom = item.parent.anchors.bottom;
        }
      }
    }
    // ...

Like with Layouts, we attach our anchors to the instantiator, and not just the item. The item must attach itself to the instantiator where applicable.

Then take care of the rest of the anchor’s properties like so:

        // ...
        // Anchor number properties
if (typeof(modelData.anchors.margins) !== "undefined")
  instantiator.anchors.margins = Number(modelData.anchors.margins);
if (typeof(modelData.anchors.leftMargin) !== "undefined")
  instantiator.anchors.leftMargin = Number(modelData.anchors.leftMargin);
if (typeof(modelData.anchors.rightMargin) !== "undefined")
  instantiator.anchors.rightMargin = Number(modelData.anchors.rightMargin);
if (typeof(modelData.anchors.topMargin) !== "undefined")
  instantiator.anchors.topMargin = Number(modelData.anchors.topMargin);
if (typeof(modelData.anchors.bottomMargin) !== "undefined")
  instantiator.anchors.bottomMargin = Number(modelData.anchors.bottomMargin);
if (typeof(modelData.anchors.horizontalCenterOffset) !== "undefined")
  instantiator.anchors.horizontalCenterOffset = Number(modelData.anchors.horizontalCenterOffset);
if (typeof(modelData.anchors.verticalCenterOffset) !== "undefined")
  instantiator.anchors.verticalCenterOffset = Number(modelData.anchors.verticalCenterOffset);
if (typeof(modelData.anchors.baselineOffset) !== "undefined")
  instantiator.anchors.baselineOffset = Number(modelData.anchors.baselineOffset);
      }
    }
  }
}

As you can see, we nullify the dangers of eval by sanitizing our inputs properly. This doesn’t fix our inability to anchor to sibling components or our inability to pre-compile the QML, but we can use this tool to refer to other items in the QML tree. The tree itself may come from a document loaded from a remote location, using a Loader.

Running any remote document in our QML code would also open the doors to arbitrary code execution attacks. We may not be able to sanitize an entire QML document like we can sanitize for individual properties, therefore you should only allow QML and JS file downloads from a trusted source, and always use an encrypted connection to prevent a targeted attack. Self-signed certificates are better than no certificate. Without encryption, a malicious actor could intercept the traffic and alter our code while it’s on its way.

This has been the last entry in this series. Thanks to Jan Marker for his time reviewing my code. I hope you’ve learned something from it. I personally enjoyed looking back at Part I the most, because the technique shown there has more real world applications.

Reference

  • Learn how to write Regular Expressions by playing with the editor and cheat sheet at https://regexr.com/ The more precise you learn to make your definitions, while attempting to keep them small, the better you’ll get at writing them.
About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Anchoring Qt Quick Components Instantiated with JSON appeared first on KDAB.

QtTest Extension for VSCode

Qt Test is a framework designed for unit testing applications and libraries built with Qt. It provides all the standard features commonly found in unit testing frameworks, making it easier to write unit tests for Qt-based projects.

We’re happy to introduce the QtTest Runner – a Visual Studio Code extension for running Qt Tests via the test explorer pane.

Test Explorer

The main difference from existing test extensions is that you can now run a single test slot instead of the whole executable. Also, unlike the ctest extension, we only build the target owning the test. There is no need for big rebuilds when debugging.

Other nice-to-haves include Go To Test, which opens the corresponding .cpp file directly from the test explorer:

Go To Test

And you can now execute a slot directly from the .cpp file editor, via context menu, by selecting the slot name:

Debug Selection

Features

  • Listing and running Qt tests
  • Listing and running individual QTest test slots
  • Context-menu entry to run selected slot in the text editor
  • Build automatically before running
  • .cpp file with the test’s implementation is automatically opened when there’s a failure
  • “Go to Test” available in the test explorer

Requirements

Only CMake is supported at this time, as test discovery is done via CTest.

You’ll need the official CMake extension. See our VSCode setup for Qt blog or just grab our template to get started quickly.

You’ll also need a C++ debugger extension. This is usually either ms-vscode.cpptools or vadimcn.vscode-lldb aka CodeLLDB.

You’re expected to be using CMake’s add_test(). Confirm by running ctest in your build directory.

Settings

KDAB.QtTest.debugger

By default the extension will try to guess what the best debugger is. But you can and probably should explicitly choose which debugger to use. The best setting might be Existing Launch, which will use an existing launch config, this way you can reuse your source maps, pretty printers and launch env variables. When reusing an existing launch, its program and args are replaced by the test you’re running.

KDAB.QtTest.CheckTestLinksToQtTestLib

Only available on Linux. Turn it on in case you have non-Qt tests executables that you want to exclude from the list. It will invoke ldd and see if libQtTest.so is present. Patches are accepted for Windows and macOS support.

How it works

Test discovery is done by calling ctest --show-only=json-v1, which lists all executables in a friendly JSON format. Then, for each executable, we call -functions which lists the available slots.

If you have a weird build system to support and you know of a nice test discovery approach, file an issue request and we’ll try to guide you for a contribution.

Known Issues

  • Slots are not known at configure time, only after a build
  • Not nice if you mix non-QtTests with QtTests, as there’s no ideal way to exclude tests, however, on Linux we can call ldd and see if a test links to QtTest.

Troubleshooting

In the output pane, choose KDAB-QtTests and see if there are any errors. Before reporting a bug, clear the output pane, reproduce the bug, and copy all output, paste it in the bug report.

Try pressing the reload button if the listing seems stale.

If no tests are reported, try running ctest -N inside the build directory. If that doesn’t work either then it’s a cmake problem. Either there’s really no tests added with add_test() or the enable_testing() call is missing in the root CMakeLists.txt.

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post QtTest Extension for VSCode appeared first on KDAB.

KDDockWidgets 2.1 Released

KDDockWidgets has launched its latest version 2.1. This release comes packed with over 500 commits, offering enhanced stability over its predecessor, version 2.0, without introducing any breaking changes.

KDDockWidgets is a versatile framework for custom-tailored docking systems in Qt written by KDAB’s Sérgio Martins. For more information about its rich set of features, have a look at its GitHub repository.

What’s changed in version 2.1?

Here are the main highlights:

Bug Fixes:

For starters, KDDW 2.1 introduces a range of bug fixes aimed at enhancing stability and user experience. Less popular features like nested main-windows and auto-hide received lots of attention and window manager specific bugs such as restoring maximized windows were addressed.

KDDW is now memory-leak free, several singletons were leaking before. We’ve added a valgrind GitHub Actions workflow to prevent regressions regarding leaks.

QtQuick:

KDDW 2.1 also introduces improvements in QtQuick. New features include an API for setting affinities via QML, enabling mixing MDI with docking similar to QtWidgets, and fixing DPI issues of icons in TitleBar.qml for better scaling at 150% and 200%. Additionally, it resolves issues such as MDI widgets not raising when clicked on and various crashes related to MDI mode.

QtWidgets:

For QtWidgets, we’ve improved handling of the preferredSize argument when adding dock widgets. It was being ignored in some cases. Overriding DockWidget::closeEvent() can now be done to prevent closing. Several crashes were fixed and we’ve added a GitHub Actions workflow which runs the tests against a Qt built with AddressSanitizer.

These enhancements improve the functionality and stability of KDDW 2.1 across different Qt environments.

Miscellaneous:

KDDW 2.1 brings miscellaneous updates, including an upgrade to nlohmann json v3.11.3, the addition of a standalone layouting example using the UI toolkit Slint, and extensive testing on CI. Additionally, Config::setLayoutSpacing(int) has been added for increased customization.

Learn about all the changes here. Let us know what you think.

More information about KDDockWidgets

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post KDDockWidgets 2.1 Released appeared first on KDAB.

Qt and Trivial Relocation (Part 3)

In the last post of this series we started exploring how to erase an element from the middle of a vector.

  • We discussed that in principle there are several different possible ways to implement erase().For instance, a vector could move-assign over the elements to be erased:Alternatively, a vector could use rotations or some other algorithms to move the elements to be destroyed to the end:In both cases we’re then left with an element in the rightmost position that needs to be destroyed. We can destroy it, update the vector’s size, and that’s it!
  • Perhaps with a bit of arrogance, we have therefore claimed that the specific strategy for erasure used does not really matter. A vector implementation will just use a “good one”, and we can always change it if we find out it’s slower than an alternative.Keep this in mind, because it is going to be important really soon.
  • We have also discussed that QVector optimizes erasure of trivially relocatable types by using a memmove. If the type is trivially relocatable, QVector destroys the element to be erased, and moves bytes from the tail over:

We concluded the post wondering: is this optimization legitimate? Why can QVector replace move assignments with a byte copy?

This doubt stems from the fact that our definition of relocation did not cover move assignments; it only covered move construction. Is Qt wrong? Is our definition wrong?

The reference semantics backstab

Let’s start by analyzing erase()‘s behavior once more.

Do you remember our claim that the specific strategy used does not really matter; that is, that they are all equivalent? Well, not so fast! It is actually quite imprecise to say that they are all equivalent.

They may be, as long as we deal with types which have value semantics. If we instead use a type that has reference semantics, the choices are absolutely not equivalent, and will yield different outcomes. This is because the semantics of assignment for (certain) reference types are write-through: they assign through the reference (instead of rebinding the reference).

Since we are implementing erasure in terms of assignments (or swaps, which boil down to assignments), this means that the precise sequence of operations done by erase will be visible due to its side-effects; and it also means that changing the strategy will produce different outcomes!


An example of a Standard Library type with these write-through reference semantics is std::tuple<int &>.

When one assigns such a tuple over another one, the reference inside the tuple will assign-through. This semantic is absolutely deliberate; it is used, for instance, by std::tie to build a tuple of references that can be used to unpack a given tuple:

int a; double b;

std::tie(a, b) = getTuple();  // std::tie produces std::tuple&lt;int &amp;, double &amp;&gt;
                              // assignment will write through, over a and b

For the sake of the example, instead of dealing with std::tuple, let’s strip it down to the bare minimum into a struct IntRef, so that we can focus on the behavior that we care about:

struct IntRef {
  int &amp;m_ref;

  IntRef &amp;operator=(const IntRef &amp;other)
  { 
    // write-through semantics for assignment:
    m_ref = other.m_ref;
    return *this; 
  }
};

Here’s an example of this in action:

int a = 1;
int b = 2;
IntRef ra{a};
IntRef rb{b};

ra = rb;
std::println("{}, {}", a, b); // prints 2, 2; we've "assigned through" ra.

The assignment on line 6 wrote 2 into the variable a.

Note that I had to explicitly write an assignment operator for IntRef, and implement the wanted semantics (write-through) myself. This is necessary because of the presence of a reference as a non-static data member (m_ref): the implicitly-generated assignment operator(s) are actually deleted in this case. This default by C++ is actually good, as reference members are a bad idea, and if you have them in a class you should not support assignment.


Let’s now generalize this to a std::vector<IntRef>:

int a = 1, b = 2, c = 3, d = 4, e = 5;
IntRef ra{a}, rb{b}, rc{c}, rd{d}, re{e};

std::vector&lt;IntRef&gt; v{ra, rb, rc, rd, re};

v.erase(v.begin() + 1);

std::println("{}, {}, {}, {}, {}", a, b, c, d, e);

What does this code print? Which is another way of asking: “what happens when we erase the second element from v?”.

Now this is a very tricky question to answer; depending on the implementation strategy chosen, we may end up with a completely different outcome:

  1. If we move assign the “tail” to the left one element at a time, and erase the last element, then the output is going to be 1, 3, 4, 5, 5.
  2. If we rotate the second element to the end, and destroy the end, then the output is… well, we don’t really know, do we? It depends on the implementation of std::rotate.It could be 1, 3, 4, 5, 2; but it could be something else as well.

Please take a moment to convince yourselves of this 🙂 Pencil and paper helps, otherwise, here’s a convenient Godbolt.

Vector erasure must be specified

The conclusion is that the implementation strategy does matter for types with write-through reference semantics! This is a very different outcome than what we might have expected (or desired, even).

For this reason, the Standard Library clearly documents the behavior of std::vector::erase in [vector.modifiers]:

Complexity: The destructor of T is called the number of times equal to the number of the elements erased, but the assignment operator of T is called the number of times equal to the number of elements in the vector after the erased elements.

This pretty much imposes a specific implementation strategy (move assign the tail to the left), so you can rely on the outcome, even in the presence of types with write-through reference semantics.

I’ll also add an extra consideration: even if this behavior wasn’t fully documented, due to Hyrum’s law, we still couldn’t “just change” the implementation of erase, because existing code will be affected — it will be able to tell the difference.

What about QVector? Does it document its erasure behavior? Well… let’s talk about this later, shall we?

Is IntRef trivially relocatable?

Now, here’s a million dollar question: would you say that IntRef is trivially relocatable or that it’s not?

Maybe you’re tempted to say “it is not” based on what you’ve just seen — IntRef has a “strange” behavior, different from most types that we “normally” use. That should be enough to disqualify it, shouldn’t it?

Let’s not rush to the answer just yet! For the benefit of the discussion, I am going to repeat our current definition of relocability: to move construct an object, and destroy the source object. Relocability is trivial when these two operations can be realized by simply copying bytes.

For example:

  • int is trivially relocatable. std::unique_ptr<T> is trivially relocatable. QString is trivially relocatable.
  • std::string is usually not trivially relocatable (self-referential due to SSO). std::list may also not be (the first node and/or a sentinel node of the list may contain a pointer to the std::list object itself).
  • QObject isn’t relocatable (it is not movable at all).

So, what about our IntRef?

If we stick to this very definition the correct answer is that IntRef is absolutely, unequivocally trivially relocatable. We can replace a move construction of an IntRef object, followed by the destruction of the source, with a mere memcpy; the result is completely equivalent.

IntRef satisfies our definition of trivial relocability.

If you think about it, IntRef simply contains a reference — that is, a pointer. It’s not very different from the memory layout of a std::unique_ptr from this point of view, and we know we can relocate that.

IntRef does show its reference semantics on assignment, but remember, our current definition of (trivial) relocability does not talk about assignments at all.

As a corollary, this fact means that it would be perfectly safe to grow a vector<IntRef> using memcpy when it needs a reallocation!

What about erasure?

If IntRef is trivially relocatable, can we erase an IntRef object from a vector, using memmove to do so?

Again, based on what we have seen, the answer is no, we cannot. Erasure is fully specified to use assignments, which yield side effects for a type like IntRef. If we just moved bytes around, those side effects would not be realized, breaking our programs.

The problem

We have reached a contradiction in our design:

  1. IntRef is trivially relocatable as it satisfies our definition.
  2. Qt optimizes the erasure of trivial relocatable types by using memmove, but
  3. IntRef cannot be erased by copying bytes! It needs to be erased by using move assignments.

To solve this contradiction, something has to give in:

  • maybe vector should use a different strategy when erasing elements;
  • maybe types like IntRef should not be allowed to be stored in a vector;
  • maybe Qt should not be using memmove when erasing objects of trivially relocatable type (but it can still optimize the reallocation of a vector);
  • maybe Qt’s definition of trivial relocability does not match ours, and we need to fix our definitions.

We will explore these possibilities in the next blog post. Stay tuned!

Overview about all installments:

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Qt and Trivial Relocation (Part 3) appeared first on KDAB.

Laying Out Components with Qt Quick and JSON

I was tasked to come up with a simple architecture for remote real time instantiation of arbitrary QML components. I’ve split my findings into 3 blog entries, each one covering a slightly different topic. Part 1 focuses on the software design pattern used to dynamically instantiate components. Part 2 shows how to layout these dynamic components by incorporating QML’ s positioning and layout APIs. The last entry, consisting of Parts 3 and 4, addresses the anchors API and important safety aspects.

This is Part 2: Laying Out Components with Qt Quick and JSON

Now that we know how to instantiate trees of components, the next thing we should be able to do is lay them out on screen. If you’ve watched our Introduction to QML series, you’ll know Qt provides 4 ways to place objects in QML:

  1. Using the point coordinate system, where we pass x and y coordinates.
  2. Using Item Positioners
  3. Using Qt Quick Layouts, which are like positioners but can also resize their items using attached properties
  4. Using anchors, which allows us to link the item’s center, baseline, and edges, to anchors from other items.

For maximum flexibility, the factory design approach should support all four methods of component placement.

  • 1. The coordinate system we get almost for free. To use it, we can assign the values for x and y from onItemChanged in the instantiator Loader, as seen in Part I:
    // Root component of the factory and nodes
    Component {
        id: loaderComp
        required property var modelData
        Loader {
            id: instantiator
            // ...
            onItemChanged: {
                // ...
                if (typeof(modelData.x) === "number")
                    loaderComp.x = modelData.x;
                if (typeof(modelData.y) === "number")
                    loaderComp.y = modelData.y;
                // ...
            }
        }
    }
  • 2. &  3…Item Positioners and Qt Quick Layouts work in very similar ways. So, let’s have a look at how to approach Qt Quick Layouts, which is the most sophisticated of the two. Let’s remember how Qt Quick Layouts are commonly used in the first place: First, we import QtQuick.Layouts. Then, instantiate any of these Layout components: https://doc.qt.io/qt-6/qtquick-layouts-qmlmodule.html, and set dimensions to it, often by means of attached properties (https://doc.qt.io/qt-6/qml-qtquick-layouts-layout.html#attached-properties). For the outermost Layout in the QML stack, we might use one of the previous APIs to achieve this. Here’s a simple example for how that looks:
import QtQuick.Layouts

Item {
    ColumnLayout {
        Button {
            text: "1st button"
            Layout.fillWidth: true
        }
        Button {
            text: "2nd button"
            Layout.fillWidth: true
        }
    }
}

Now, for the Layouts API to work in our factory, the recursion described in Part I must be in place.

In addition to that, we need to take into account a property of the Loader object component: Loader inherits from Item. The items loaded by the Loader component are actually children of Loader and, as a result, must be placed relative to the loader, not its parent. This means we shouldn’t be setting Layout attached properties onto the instantiated components, but instead should set them on the Loader that is parent to our item, IDed as instantiator.

Here’s an example of what the model could define. As you can see, I’ve replaced the dot used for attached properties with an underscore.

    property var factoryModel: [
        {
            "component": "ColumnLayout",
            "children": [
                {
                    "component": "Button",
                    "text": "1st button",
                    "Layout_fillWidth": true
                },
                {
                    "component": "Button",
                    "text": "2nd button",
                    "Layout_fillWidth": true
                }
            ]
        }
    ]

Here’s what we will do, based on that model:

    // Root component of the factory and nodes
    Component {
        id: loaderComp
        Loader {
            id: instantiator
            required property var modelData
            sourceComponent: switch (modelData.component) {
                case "Button":
                return buttonComp;
                case "Column":
                return columnComp;
                case "ColumnLayout":
                return columnLayoutComp;
            }
            onItemChanged: {
                // Pass children
                if (typeof(modelData.children) === "object")
                    item.model = modelData.children;

                // Layouts
                if (typeof(modelData.Layout_fillWidth) === "bool") {
                    // Apply fillWidth to the container instead of the item
                    instantiator.Layout.fillWidth = modelData.Layout_fillWidth;
                    // Anchor the item to the container so that it produces the desired behavior
                    item.anchors.left = loaderComp.left;
                    item.anchors.right = loaderComp.right;
                }

                // Button properties
                switch (modelData.component) {
                    case "Button":
                    // If the model contains certain value, we may assign it:
                    if (typeof(modelData.text) === "string")
                        item.text = modelData.text;
                    break;
                }
                // ...
            }
        }
    }

As you can see, the attached property is set on the instantiator which acts as a container, and the component item is then anchored to that container. I do not simply anchor all children to fill the parent Loader because different components have different default sizes, and the Loader is agnostic of its children’s sizes.

Here’s the implementation for the Button, Column, and ColumnLayout components. Feel free to modify the JSON from factoryModel to use Column instead of ColumnLayouts, or any componentizations that you implement yourself.

    Component {
        id: buttonComp
        Button {
            property alias children: itemRepeater.model
            children: Repeater {
                id: itemRepeater
                delegate: loaderComp
            }
        }
    }
    Component {
        id: columnComp
        Column {
            property alias model: itemRepeater.model
            children: Repeater {
                id: itemRepeater
                delegate: loaderComp
            }
        }
    }
    Component {
        id: columnLayoutComp
        ColumnLayout {
            property alias model: itemRepeater.model
            children: Repeater {
                id: itemRepeater
                delegate: loaderComp
            }
        }
    }
  • 4. Anchors will be covered in the next entry. Some complications and security implications arise due to the fact that anchors can point to IDs, which is why I think they deserve their own separate article.

To summarize, we can dynamically attach attributes to our dynamically instantiated components to configure QML layouts. It’s important to keep in mind that the Loader will hold our dynamic component as its children, so we must assign our dimensions to the Loader and have the child mimic its behavior, possibly by anchoring to it, but this could also be done the other way around.

In the next entry I’ll be covering how to implement anchors and the security implications for which dynamically instantiating components from JSON might not be a good idea after all. Our previous entry is Recursive Instantiation with Qt Quick and JSON.

Reference

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Laying Out Components with Qt Quick and JSON appeared first on KDAB.

Qt on iOS and ITMS-91053 NSPrivacyAccessedAPITypes Error

If you develop a Felgo or Qt app for iOS and upload it to the app store via AppStore Connect, you may face a new Apple warning e-mail these days:

We noticed one or more issues with a recent submission for App Store review for the following app.

Although submission for App Store review was successful, you may want to correct the following issues in your next submission for App Store review. Once you've corrected the issues, upload a new binary to App Store Connect.

ITMS-91053: Missing API declaration - Your app’s code in the “iosproject” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategorySystemBootTime. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code.

ITMS-91053: Missing API declaration - Your app’s code in the “iosproject” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryDiskSpace. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code.

ITMS-91053: Missing API declaration - Your app’s code in the “iosproject” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryUserDefaults. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code.

ITMS-91053: Missing API declaration - Your app’s code in the “iosproject” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryFileTimestamp. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code.

Apple Developer Relations

Without a proper fix, Apple has rejected app submissions to App Store Connect since May 1st.

Why is ITMS-91053 happening?

In an attempt to prevent fingerprinting, Apple recently added a new policy that requires you to provide a specific reason if you are using one of the APIs that Apple identified as a possible backdoor for fingerprinting. Fingerprinting refers to using specific APIs or device signals to uniquely identify a device or user for the purpose of tracking, even though users might not be aware of that.

While you may not use those APIs directly, Qt or any third-party framework integrated into your app may. Read on to learn how to fix the issue.

About QML Efficiency: Compilers, Language Server, and Type Annotations

About QML Efficiency: Compilers, Language Server, and Type Annotations

In our last post we had a look at how to set up QML Modules and how we can benefit from the QML Linter. Today we’re going to set up the QML Language Server to get an IDE-like experience in an editor of our choice. We’ll also help the the QML Compiler generate more efficient code.

Continue reading About QML Efficiency: Compilers, Language Server, and Type Annotations at basysKom GmbH.

How To Use Modern QML Tooling in Practice

How To Use Modern QML Tooling in Practice

Qt 5.15 introduced “Automatic Type Registration”. With it, a C++ class can be marked as “QML_ELEMENT” to be automatically registered to the QML engine. Qt 6 takes this to the next level and builds all of its tooling around the so-called QML Modules. Let’s talk about what this new infrastructure means to your application in practice and how to benefit from it in an existing project.

Continue reading How To Use Modern QML Tooling in Practice at basysKom GmbH.

Use Compute Shader in Qt Quick

Use Compute Shader in Qt Quick

With this blog post, we introduce the QtQuickComputeItem - a Qt Quick item that allows you to easily integrate compute shader into your Qt Quick Code.
Compute
Shader are used to perform arbitrary computations on the GPU. For
example, the screenshot below shows a Qt Quick application that
generates Gray Scott Reaction Diffusion patterns.  The simulation is executed by a compute shader that is configured directly in QML.

Continue reading Use Compute Shader in Qt Quick at basysKom GmbH.