Skip to content

Tuesday, 10 October 2023

At the moment I am hard at work putting together the final bits for the AppStream 1.0 release (hopefully to be released this month). The new release comes with many new new features, an improved developer API and removal of most deprecated things (so it carefully breaks compatibility with very old data and the previous C API). One of the tasks for the upcoming 1.0 release was #481 asking about a formal way to distinguish Linux phone applications from desktop applications.

AppStream infamously does not support any “is-for-phone” label for software components, instead the decision whether something is compatible with a device is based the the device’s capabilities and the component’s requirements. This allows for truly adaptive applications to describe their requirements correctly, and does not lock us into “form factors” going into the future, as there are many and the feature range between a phone, a tablet and a tiny laptop is quite fluid.

Of course the “match to current device capabilities” check does not work if you are a website ranking phone compatibility. It also does not really work if you are a developer and want to know which devices your component / application will actually be considered compatible with. One goal for AppStream 1.0 is to have its library provide more complete building blocks to software centers. Instead of just a “here’s the data, interpret it according to the specification” API, libappstream now interprets the specification for the application and provides API to handle most common operations – like checking device compatibility. For developers, AppStream also now implements a few “virtual chassis configurations”, to roughly gauge which configurations a component may be compatible with.

To test the new code, I ran it against the large Debian and Flatpak repositories to check which applications are considered compatible with what chassis/device type already. The result was fairly disastrous, with many applications not specifying compatibility correctly (many do, but it’s by far not the norm!). Which brings me to the actual topic of this blog post: Very few seem to really know how to mark an application compatible with certain screen sizes and inputs! This is most certainly a matter of incomplete guides and good templates, so maybe this post can help with that a bit:

The ultimate cheat-sheet to mark your app “chassis-type” compatible

As a quick reminder, compatibility is indicated using AppStream’s relations system: A requires relation indicates that the system will not run at all or will run terribly if the requirement is not met. If the requirement is not met, it should not be installable on a system. A recommends relation means that it would be advantageous to have the recommended items, but it’s not essential to run the application (it may run with a degraded experience without the recommended things though). And a supports relation means a given interface/device/control/etc. is supported by this application, but the application may work completely fine without it.

I have a desktop-only application

A desktop-only application is characterized by needing a larger screen to fit the application, and requiring a physical keyboard and accurate mouse input. This type is assumed by default if no capabilities are set for an application, but it’s better to be explicit. This is the metadata you need:

<component type="desktop-application">
  <id>org.example.desktopapp</id>
  <name>DesktopApp</name>
  [...]
  <requires>
    <display_length>768</display_length>

    <control>keyboard</control>
    <control>pointing</control>
  </requires>
  [...]
</component>

With this requires relation, you require a small-desktop sized screen (at least 768 device-independent pixels (dp) on its smallest edge) and require a keyboard and mouse to be present / connectable. Of course, if your application needs more minimum space, adjust the requirement accordingly. Note that if the requirement is not met, your application may not be offered for installation.

Note: Device-independent / logical pixels

One logical pixel (= device independent pixel) roughly corresponds to the visual angle of one pixel on a device with a pixel density of 96 dpi (for historical X11 reasons) and a distance from the observer of about 52 cm, making the physical pixel about 0.26 mm in size. When using logical pixels as unit, they might not always map to exact physical lengths as their exact size is defined by the device providing the display. They do however accurately depict the maximum amount of pixels that can be drawn in the depicted direction on the device’s display space. AppStream always uses logical pixels when measuring lengths in pixels.

I have an application that works on mobile and on desktop / an adaptive app

Adaptive applications have fewer hard requirements, but a wide range of support for controls and screen sizes. For example, they support touch input, unlike desktop apps. An example MetaInfo snippet for these kind of apps may look like this:

<component type="desktop-application">
  <id>org.example.adaptive_app</id>
  <name>AdaptiveApp</name>
  [...]

  <requires>
    <display_length>360</display_length>
  </requires>

  <supports>
    <control>keyboard</control>
    <control>pointing</control>
    <control>touch</control>
  </supports>
  [...]
</component>

Unlike the pure desktop application, this adaptive application requires a much smaller lowest display edge length, and also supports touch input, in addition to keyboard and mouse/touchpad precision input.

I have a pure phone/table app

Making an application a pure phone application is tricky: We need to mark it as compatible with phones only, while not completely preventing its installation on non-phone devices (even though its UI is horrible, you may want to test the app, and software centers may allow its installation when requested explicitly even if they don’t show it by default). This is how to achieve that result:

<component type="desktop-application">
  <id>org.example.phoneapp</id>
  <name>PhoneApp</name>
  [...]

  <requires>
    <display_length>360</display_length>
  </requires>

  <recommends>
    <display_length compare="lt">1280</display_length>
    <control>touch</control>
  </recommends>
  [...]
</component>

We require a phone-sized display minimum edge size (adjust to a value that is fit for your app!), but then also recommend the screen to have a smaller edge size than a larger tablet/laptop, while also recommending touch input and not listing any support for keyboard and mouse.

Please note that this blog post is of course not a comprehensive guide, so if you want to dive deeper into what you can do with requires/recommends/suggests/supports, you may want to have a look at the relations tags described in the AppStream specification.

Validation

It is still easy to make mistakes with the system requirements metadata, which is why AppStream 1.0 will provide more commands to check MetaInfo files for system compatibility. Current pre-1.0 AppStream versions already have an is-satisfied command to check if the application is compatible with the currently running operating system:

:~$ appstreamcli is-satisfied ./org.example.adaptive_app.metainfo.xml
Relation check for: */*/*/org.example.adaptive_app/*

Requirements:
 • Unable to check display size: Can not read information without GUI toolkit access.
Recommendations:
 • No recommended items are set for this software.
Supported:
  Physical keyboard found.
  Pointing device (e.g. a mouse or touchpad) found.
 • This software supports touch input.

In addition to this command, AppStream 1.0 will introduce a new one as well: check-syscompat. This command will check the component against libappstream’s mock system configurations that define a “most common” (whatever that is at the time) configuration for a respective chassis type.

If you pass the --details flag, you can even get an explanation why the component was considered or not considered for a specific chassis type:

:~$ appstreamcli check-syscompat --details ./org.example.phoneapp.metainfo.xml
Chassis compatibility check for: */*/*/org.example.phoneapp/*

Desktop:
  Incompatible
 • recommends: This software recommends a display with its shortest edge
   being << 1280 px in size, but the display of this device has 1280 px.
 • recommends: This software recommends a touch input device.

Laptop:
  Incompatible
 • recommends: This software recommends a display with its shortest edge 
   being << 1280 px in size, but the display of this device has 1280 px.
 • recommends: This software recommends a touch input device.

Server:
  Incompatible
 • requires: This software needs a display for graphical content.
 • recommends: This software needs a display for graphical content.
 • recommends: This software recommends a touch input device.

Tablet:
  Compatible (100%)

Handset:
  Compatible (100%)

I hope this is helpful for people. Happy metadata writing! 😀

I’ve been quiet since Akademy. Before that, the silence was mostly due to studying multiple books about technical writing for my talk.

After that, I had certain tasks left to do: Kirigami Addons and KConfig. The former requires a proper revision on my part to be finished, and KConfig is almost ready, but I struggled quite a bit with the solution to a problem I was having.

I moved on to focus temporarily on other matters that I’m going to handle in the near future. This blog post doesn’t provide the solutions to these matters, but it mentions my plans, which might interest you or give you a clear perspective on what I’ve been doing. The post will feel incomplete because it is a checklist. If you wish, you can skip to the end summary.

Sunday, 8 October 2023

KNotifications is KDE’s framework for creating popup notifications. It supports Linux, Windows, macOS, and Android, making it, to my knowledge, the most complete cross-platform library for this available in C++. This makes it natually interesting to use for non-KDE Qt application developers.

However there is one aspect that makes it less attractive for third-party developers: It’s number of dependencies. As of KNotifications 5.110 it depends on the following other KDE Frameworks:

  • KCoreAddons
  • KConfig
  • KWindowSystem

as well as some third-party like QtWidgets, X11, libdbusmenu-qt and libcanberra.

While none of these are a hard blocker for usage in most cases the overall impression isn’t very appetizing. During the KF5 time we already weeded out some dependencies that don’t make sense on some platforms, like removing the QtWidgets dependency on Android. We were however somewhat limited in our ability to do large cleanups by our strict API/ABI stability promise. For KF6 we have the opportunity do to larger cleanups.

One larger source of dependencies is the KStatusNotifierItem class, which is part of the KNotifications framework and is used to create system tray icons. Since its functionality is rather independent from creating popup notifications we decided to split it out into a separate, new framework. This significantly reduces the number of dependencies of KNotifications. A number of other changes further reduced the number of dependencies and cleaned up the public API a bit.

As a result what will become KF6 KNotifications on Linux only depends on Qt (QtGui + QtDBus, and optionally QtQml for QML support), KConfig (that would also be feasible to remove if someone is motivated enough) and libcanberra (for playing notification sounds).

Other KDE Frameworks received similar changes, but KNotifications is likely the one where this has the largest impact.

Doing this kind of work is part of my position as KDE Software Platform Engineer. To support my work please consider donating to KDE e.V..

This is a sort-of reply to Herzenschein’s blog post from a few months ago. He goes over how to tell KConfig put it’s files into app-specific folders instead of dumping them into the garbage bin of ~/.config. He noted that he hasn’t touched KConfigXT yet, so this is how to make it work with KConfigXT applications.

However you’ll notice by default KConfigXT generates constructors for your configuration class like this:

class Config : public KConfigSkeleton
{
  Q_OBJECT
  public:

    Config( QObject *parent );
    ~Config() override;
...

That’s not useful, and it took me a minute to figure out how to allow KConfigSkeleton and the KConfig compiler to let me pass AppConfigLocation. However, the solution is very simple.

First, you need to make sure it’s not a Singleton. (There’s probably a way to make it work with a singleton though.) Make sure that setting is turned off in your .kcfgc:

File=config.kcfg
ClassName=Config
Mutators=true
DefaultValueGetters=true
GenerateProperties=true
Singleton=false

And then in your .kcfg, modify the <kcfgfile> block to add arg = "true" instead of hardcoding a filename. It will look something like this:

<kcfgfile arg="true" />

Once you run the compiler again, you’ll get a constructor that allows you to pass a KSharedConfig!

class Config : public KConfigSkeleton
{
  Q_OBJECT
  public:

    Config( KSharedConfig::Ptr config = KSharedConfig::openConfig() );
    ~Config() override;
...

And then you call the usual function:

new Config(KSharedConfig::openConfig("myappconfigrc", KConfig::SimpleConfig, QStandardPaths::AppConfigLocation));

Now enjoy your configuration file living in it’s own directory! Here’s the constructor parameter logic in KConfig which was essential in figuring this out.

Friday, 6 October 2023

Welcome to the first "Codevis Weekly Update"

What is Codevis?

Codevis is a tool to help developers manage large codebases, sponsored by Bloomberg, developed by Codethink and hosted on the KDE Infrastructure, with all that, completely opensource with a permissive license. Codevis uses a mix of technologies to do what it does, mainly LLVM and Clang to do the heavy lifting of understanding C++ Codebases, Qt for Callback management (in the form of Signal/Slots), KDE Frameworks libraries for the desktop application, and pure Qt for the CLI application. The database layer is written with Soci , the same database layer used in CERN, targeting sqlite3.

But How does it work?

Codevis analyzes all the visible source code from your project and creates a graph database (using a relational database) in a way that the analyst can load and interpret information from the codebase without loading the codebase. The graph-database is comprehensive, and has all the information we think it's important, and also a lot of information that's good to have, with a bunch of information because why not. Since something that's not important for me could be really important for a company with billions of lines of code.

It just generates visualization?

No. Codevis also allows you to draw your software architecture and generate ready-to-compile c++ code from it. Think of this as a possibility to have C++ templates for complex projects tha are also visually documented. You can create libraries, classes, structures, connect them quickly on a dirty mockup during a meeting, and the output could be 60 c++ files on disk with all the classes, folder-hierarchy and CMake ready to compile.

This will not add any method or implement anything, but just the creation of the C++ files and CMake scripts from a small architecture meeting is pretty interesting in my point of view.

Wednesday, 4 October 2023

Contributing to KDE sometimes leads to a flood of negative or even insulting feedback. To not get disheartened by this it is important to correctly assess the significance of these comments. One possible stance to take towards these reports can be taken from punk culture.

I hope this video with hand-crafted subtitles will be a valuable resource for people stumbling into this situation in the future. Enjoy the skateboarding clips!

It's been a Long long time without posting anything. Not that i'm lazy (well, a bit). But I have been working on a lot of things related to KDE this past few years, and I was finally able to release and opensource Codevis. I know this post is as small as a tweet, just checking if the integration is stil working

Tuesday, 3 October 2023

Last weekend I went to the Linux Days in Voralberg (Austria) to host a booth with Tobias and Kai. It was hosted at the Fachhochschule (a sort of university for applied science) in Dornbirn and it was my first time attending this event.

Me and Tobias in front of the LinuxDays poster at the entrance of the event
Me and Tobias in front of the LinuxDays poster at the entrance of the event

Our booth was well visited and we had a lot of interesting discussions. As always, we had various pieces of hardware on our booth: 2 laptops, a Steam Deck, a Pinephone, a graphic tablet with Krita and two Konqi amigurumis.

Our stand
Our stand

Between booth duty, I still managed to watched one talk about open source deployment in public institutions in Baden Wurtenberg (a region/state in German). After the linux days, we all went to a restaurant and mass ordered Käsespätzle. Käsespätzle is a traditional food from this region and is made of cheese, Spätzle (noodles) and onions. It was excellent.

Käsespätzle
Käsespätzle

On Sunday, Tobias and I went to Golm with a local we met the day before. We took a gondola lift to reach a high-rope park in the mountains and then took an Alpine Coaster to go back in the valley. It was a lot of fun.

The view from the gondola
The view from the gondola

Picture of the high-rope pakr
Picture of the high-rope pakr

After our little adventure, we again went to eat in a traditional restaurant.

Fish in a plate with noodles and pumpkin
Fish in a plate with noodles and pumpkin

Here a few more pictures of the trip:

Dornbirn market place
Dornbirn market place

Castel
Castel

KStars v3.6.7 is released on 2023.10.03 for MacOS & Linux. Windows build is still pending and should hopefully be released by 10th of October. It's a bi-monthly bugfix release with a couple of exciting features.

Image Overlay Component


Hy Murveit introduced a long requested feature: Custom Image Overlays!

With this new feature, a user can add their own processed/completed astro-images, and the system will display them scaled and rotated appropriately on the Sky Map.

The feature is controlled in the KStars Settings menu, in a new tab labelled Image Overlays. First the user needs to add files into a directory, parallel to the logs directory, called imageOverlays. Simply add the images there (typically jpegs). Ideally these aren't massive files for performance reasons, but probably width 1000 or 2000 are fine. I have been testing with larger files, which will also work be use more system resources on slower CPUs.


The user then uses the Image Overlays menu in KStars Settings to (one-time) plate-solve the images and check a box to enable the image display. Successful plate-solve info is stored in the user-db so that it doesn't have to be done again. The images should, from then on, appear in the SkyMap in the proper position. There is a way to easily navigate to the images without manipulating the SkyMap by selecting a row in the overlay table and clicking on the "Show" button. You can move from one image to the next with up/down arrow keyboard commands.

A user can adjust the plate-solve timeouts. As these are mostly blind solves (jpegs won't have any header info, and as currently implemented, no header info is used) the plate solving can be problematic. You can choose a default image scale (arcseconds-per-pixel) or leave that to 0.0 to not use scale. If there are files that won't solve, the user can add RA,DEC into the image's row in the table displayed, which would get the solver to use the sky position as a constraint. The user can also add the scale that way. In fact, if the user knows all the info for the image, he/she can populate all the fields on the image's row and simply set the status field to OK, and plate-solving would no longer be required.

Rotator Dialog Improvements



Toni Schriber continued simplifying the Rotator Dialog. Rotator Flip Policy was introduced. This (global) policy is an answer to this question and to this wish. It's now possible to define how the rotator reacts after a flip or if the result of a solved reference image reports a different pierside respective to the actual mount pierside. Preserve Rotator Angle will keep the rotator position and the camera is virtually rotated by 180°. Preserve Position Angle will keep the camera position angle.

The rotator always turns the camera to the original position angle and the image will show the original star arrangement. Flip Policy can be altered in the StellarSolver Options under Rotator Settings.

More File Placeholders


Due to popular demand, Wolfgang Reissenberger added support for camera temperature %C, gain %G, offset %O and pier side %P.


This is not only applicable to locally captured images, but also for images captured on a remote INDI server.

Sunday, 1 October 2023

Learning a language is, to me, about grinding. Continously exposing yourself.

Ich lerne Deutsch. Oder, ich versuche Deutsch zu lernen. 😉

I try to expose my self to the language via YouTube (thx Nils for the tip about 7 gegen Wild), but also news papers and just chatting with people. I’d say the biggest hurdle is that people find English easier than having me try to find and reorder the words, so practice at full speed is hard to find.

I guess I do the same for people trying to learn Swedish, and i really shouldn’t.

If you have tips for how to expose myself more to German – spoken or written – please drop a comment here or join the conversation at mastodon.