Insert Title

Aug 01, 2018

Fix for Keepass crashing under Linux

If you want to try out the free password management solution KeePass under Linux and experience crashes every time you press the Windows key, there is an easy fix:

Edit /usr/bin/keepass2 and change the line

exec /usr/bin/cli /usr/lib/keepass2/KeePass.exe "$@"

to:

exec /usr/bin/cli --verify-all /usr/lib/keepass2/KeePass.exe "$@"

The developers of Keepass have acknowledged the problem, but sadly they can't do anything about it, since it is a bug in Mono and not in Keepass: https://sourceforge.net/p/keepass/bugs/1545

Jul 22, 2018

Running applications only when you are idle

The problem: Bad responsiveness caused by high I/O load

On a typical desktop PC, there are several long-running tasks with a high I/O load which usually need to be executed regularly — like backups, indexing files for search, checking the backups, etc. Tasks with high I/O load however can cause bad responsiveness of the system under Linux, which results in applications being frozen, the mouse cursor not moving, etc.

With the most systems this can usually be fixed by selecting the CFQ scheduler in the kernel. If you are running particular new hardware however, this might not work since e.g. the kernel does not support setting an I/O scheduler for those new fancy m.2 SSDs. Running an application like recollindex or borgbackup on one of those disks can completely fubar the desktop until they are done.

The solution

To work around this problem, I've created the following script:

#!/bin/bash
# execute-idle.sh
# Copyright (C) 2018 Philipp Ludwig, <idle (at) philippludwig.net>
# License: GPLv3
export DISPLAY=:0.0
set -e

if [ "$1" == "" ]; then
    echo "Error: No command given"
    exit 1
fi

$@ &

PID=$!

if [ "$PID" == "" ]; then
    echo "Could not determine PID of $1!"
    exit 1
fi

kill -SIGSTOP $PID
for p in $(ps --ppid $PID -ho '%p'); do kill -SIGSTOP $p; done

while kill -0 $PID &> /dev/null; do
    sleep 5
    if [ "$(xprintidle)" -gt 30000 ]; then # 30 seconds
        signal="-SIGCONT"
    else
        signal="-SIGSTOP"
    fi

    kill $signal $PID
    for p in $(ps --ppid $PID -ho '%p'); do kill $signal $p; done
done

It is called execute-idle.sh and designed to run these tasks only while you are not using the computer (e.g. when you are in the kitchen for 10 minutes, waiting on the cup of coffee).

Dependencies: xprintidle, bash

How it works

execute-idle.sh first starts the task specified as an argument, then pauses it immediately by sending a SIGSTOP. Then it calls xprintidle every 5 seconds to check if you are still using the computer — if not, it sends a SIGCONT signal to the process and all of its children, letting the job continue. As soon as you return and type on your keyboard or move your mouse, execute-idle.sh again sends SIGSTOP to the process and its children, pausing the task until you are idle again.

How to use it

Just put it in your crontab like this:

0 12 * * * ~/tools/execute-idle.sh ~/my-backup-script.sh

Remarks

You might think that this causes some jobs to never finish, but after using this script for several weeks I didn't encounter any problems like this. Due to the rather short 5 second interval, execute-idle.sh can utilize even small breaks of e.g. 30 seconds.

Try running your backup with it — your regular backup check job should tell you if something went wrong.

Jan 20, 2018

Fixing Cura under Fedora

If you try to run Cura under the latest Fedora, you might experience that the application just doesn't start - at least that was the case for me.

Running strace and digging through the log made clear that Cura was looking for several files under ~/.local/share/cura/v3.0 (or v2.7, depending on which version you have installed), while these were installed under /usr/share/cura.

The fix is to symlink/copy these files to your home directory:

cd ~/.local/share/cura/*
rm -rf themes
ln -sv /usr/share/cura/resources/{themes,qml,definitions,resources,images}
cp -rv /usr/share/uranium/resources/shaders/* shaders/
cp -rv /usr/share/cura/resources/shaders/* shaders/

Also, don't forget to add yourself to the dialout group if you want to use your printer via USB:

sudo gpasswd -a <yourname> dialout

Okt 20, 2017

KDE Plasma applications outside of KDE

If you ever use KDE/Plasma applications outside of Plasma (e.g. under i3) and experience theme problems and/or missing icons, try this:

QT_QPA_PLATFORMTHEME=kde <command>

While this is not recommended, it works for me; using this command, I can now use skrooge under i3 with icons, nice fonts and the plasma GUI theme.

Okt 19, 2017

Rust: if let .... not

Introduction

Rust's error handling can be very exhaustive, both in terms of safety and verbosity. Consider the following example:

match get() {
    Some(value) => {
        println!("Do something with value: {}", value);
    },
    None => {}
}

If you have a lot of statements like this, your code can get very verbose, which is why this has been addressed by the if let syntax:

if let Some(value) = get() {
    println!("Do something with value: {}", value);
} else { /* error handling here */ }

Now this is much shorter, but what if you have multiple chained operations? Of course you can use and_then, but this will cause you the loss of any possibility of error management:

get().and_then(parse)   // What if "parse" fails?
     .and_then(output)

If you use if let, it will look like this:

if let Some(value) = get() {
    if let Some(parsed_value) = parse(value) {
        output(value);
    } else {
        println!("parsing failed");
    }
} else {
    println!("Getting the value failed");
}

Convoluted and hard to read.

if not let

There was a RFC for including something like if !let x = get() { error management }, but it didn't caught on. What nobody online however doesn't seem to mention is that you can create something like this:

let value = if let Some(value) = get() {value} else {
    println!("Couldn't get value!");
    return;
};

let parsed_value = if let Some(pv) = parse(value) {pv} else {
    println!("Couldn't parse value!");
    return;
};

I admit, that looks very convoluted. In another RFC the following syntax was proposed, but postponed for now:

let value = get() else return println!("No value!");  // Not valid

So I guess for now we will have to live with either the convoluted syntax or a lot of lines/indentation.

posted at 14:40  ·  rust  if  let

Mai 27, 2017

Deploying apps with QtWebEngine for Ubuntu

Introduction

QtWebEngine is a very handy C++/Qt module for creating applications with embedded web content. It carries a complete Chromium browser and allows you to embed HTML/JS content in your application or to modify such content as you wish.

QtWebEngine

If you however want to deploy this application to Ubuntu, you will be faced with two problems:

  • QtWebEngine is not available in the official repository (yet). This means that you can't just create a .deb package, since the necessary dependencies won't be available. There are PPA's, but at least at the time of this writing, none of them worked.

  • You can't compile Qt statically with QtWebEngine included, since the codebase doesn't support it. Also you would have to make the source code of your application available under the terms of the LGPL, which could be unwanted if you chose a different license or if your application is proprietary.

Using a snap package

Note: As for now, this only works under 16.04. Under Ubuntu 16.10 you need to add -Wl,--as-needed to the linker flags, but I couldn't figure out how.

Luckily, we can overcome this problem by utilizing the new snap package format which has been introduced into ubuntu 16.04. A snap package will allow you to distribute your application shipped with a Qt version of your choice, allowing to include QtWebEngine and to comply with the terms of the LGPL (Note: I'm not a lawyer. Check with your legal experts if your application is proprietary and if you don't want to make your source code publicly available).

Creating the snap package

If you are new to snap packages, I'd advise you to read the official tutorial, called "Build your first snap". It takes about 5 minutes to complete and will tell you everything you will need to know to distribute your application.

The remainder of this article will assume that you have basic knowledge of snap packaging.

Adding your source code

We start first by adding your source code to the snapcraft.yml file. For the sake of this tutorial, I will use the QtWebEngine minimal example, which is included in the Qt sourcecode:

name: qtwebengine-snap-tutorial
version: "2017-18-02"
summary: A short demo on howto package Qt using snap

grade: devel
confinement: devmode

apps:
  qtwebengine-example:
    command: deploy/qtwebengine.sh

parts:
  example:
    # Replace this with the path to your sourcecode
    source: https://download.qt.io/archive/qt/5.8/5.8.0/submodules/qtwebengine-opensource-src-5.8.0.tar.xz
    source-subdir: qtwebengine-opensource-src-5.8.0/examples/webengine/minimal/

Including Qt

For adding Qt to our build, we will need to complete several steps:

  • Download the Qt sourcecode from download.qt.io.
  • Extract it
  • Install all necessary dependencies inside the snap environment
  • run the configure script will the right parameters. Important: Depending on what parts of Qt your application uses, you will maybe need to adjust this step.
  • Compile & install it.
  • Copy everything needed for the application into a special deploy folder.

The last step is needed since the QtWebEngineProcess looks for it's resource files at some hard-coded paths and in the path where the executable lies. Of course it would be nicer if we could omit this step and put everything into /usr in the snap environment, but as far as I know, this is not possible.

Anyway, here is the qt part for the snapcraft.yml file:

parts:
  qt:
    source: http://download.qt.io/archive/qt/5.8/5.8.0/single/qt-everywhere-opensource-src-5.8.0.tar.gz
    stage-packages:
        - libdbus-1-dev
        - libpci-dev
        - libxss-dev
        - gperf
        - bison
        - libegl1-mesa-dev
        - libfontconfig1-dev
        - libudev-dev
        - libudev1
        - re2c
        - libvpx-dev
        - libsnappy-dev
        - libsrtp0-dev
        - zlib1g-dev
        - libwebp-dev
        - libxslt1-dev
        - libevent-dev
        - libjsoncpp-dev
        - libopus-dev
        - libprotobuf-dev
        - libfreetype6-dev
        - libx11-dev
        - libxext-dev
        - libxfixes-dev
        - libxi-dev
        - libxrender-dev
        - libxcb1-dev
        - libx11-xcb-dev
        - libxcb-glx0-dev
        - libxcb-keysyms1-dev
        - libxcb-image0-dev
        - libxcb-shm0-dev
        - libxcb-icccm4-dev
        - libxcb-sync-dev
        - libxcb-xfixes0-dev
        - libxcb-shape0-dev
        - libxcb-randr0-dev
        - libxcb-render-util0-dev
        - libxcb-xinerama0-dev
        - libxcomposite-dev
        - libxcursor-dev
        - libxrandr-dev
        - libxtst-dev
        - libpng12-dev
        - yasm
        - bc
        - python
        - libbluetooth-dev
        - libopenal-dev
        - libgstreamer1.0-dev
        - libgles2-mesa-dev
        - libgl1-mesa-dev
        - mesa-common-dev
        - libglu1-mesa-dev
        - libgstreamer-plugins-base1.0-dev
    plugin: make
    prepare: |
        bash -c '$SNAPCRAFT_STAGE/../patch.sh'
    build: |
        ./configure -opensource -release -confirm-license -nomake tests -no-compile-examples -system-zlib -skip virtualkeyboard -skip wayland -skip charts -prefix $SNAPCRAFT_PART_INSTALL -I $SNAPCRAFT_PART_INSTALL/usr/include/freetype2 -I $SNAPCRAFT_PART_INSTALL/usr/include -L $SNAPCRAFT_PART_INSTALL/usr/lib/x86_64-linux-gnu/ -nomake examples -nomake tools -opengl desktop -qt-libpng -qt-xcb -v 2>&1 | tee qt-configure.log
        make -s -j $(echo $(nproc) +1 | bc)
        rm -v $SNAPCRAFT_PART_INSTALL/usr/include/x86_64-linux-gnu/bits/string3.h
        make -s install
        mkdir $SNAPCRAFT_PART_INSTALL/deploy
        cp -r $SNAPCRAFT_PART_INSTALL/plugins $SNAPCRAFT_PART_INSTALL/deploy/
        cp -r $SNAPCRAFT_PART_INSTALL/libexec/* $SNAPCRAFT_PART_INSTALL/deploy/
        cp -r $SNAPCRAFT_PART_INSTALL/resources/icudtl.dat $SNAPCRAFT_PART_INSTALL/deploy/
        cp -r $SNAPCRAFT_PART_INSTALL/resources/qtwebengine_resources_100p.pak $SNAPCRAFT_PART_INSTALL/deploy/
        cp -r $SNAPCRAFT_PART_INSTALL/resources/qtwebengine_resources_200p.pak $SNAPCRAFT_PART_INSTALL/deploy/
        cp -r $SNAPCRAFT_PART_INSTALL/resources/qtwebengine_resources.pak $SNAPCRAFT_PART_INSTALL/deploy/
        cp -r $SNAPCRAFT_PART_INSTALL/translations/qtwebengine_locales $SNAPCRAFT_PART_INSTALL/deploy/
        cp $SNAPCRAFT_STAGE/../example.sh $SNAPCRAFT_PART_INSTALL/deploy/
    stage:
        - bin/*
        - usr/*
        - deploy/*
        - lib/*
        - translations/*
        - resources/*

OK, this is a lot. Here is what's going on:

  1. We are installing several dependencies. These are needed for compiling Qt and QtWebEngine and my be needed to be adjusted by you, regarding which modules your application needs.

  2. The prepare step calls a custom bash script, which works around a bug in the C header files supplied by Ubuntu 16.04. The script & patch is listed below.

  3. Since we need to do several custom steps during the build process, we can't use snapcraft's autotools plugin. Instead, we utilize the more general make plugin and provide a custom build script.

  4. During the stage phase, we make sure that all files needed by QtWebEngine are carried over to the final package.

Patching the ubuntu C header files

One of the ubuntu header files uses the notation // for commenting at one point instead of /*. Since QtWebEngine uses the flags -pedantic -Werror internally, this causes the build process to fail. Therefore we need to patch this file:

--- ./usr/include/x86_64-linux-gnu/bits/string3.h   2016-11-16 21:53:50.000000000 +0100
+++ ./usr/include/x86_64-linux-gnu/bits/string3.h   2017-02-10 08:12:21.786385589 +0100
@@ -126,7 +126,7 @@
   return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
    }

    -// XXX We have no corresponding builtin yet.
    +/* XXX We have no corresponding builtin yet. */
     extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n,
                            size_t __destlen) __THROW;
 extern char *__REDIRECT_NTH (__stpncpy_alias, (char *__dest, const char *__src,

This patch file called c-comment.patch is applied during the build stage by a helper script called patch.sh:

1
2
3
4
#!/bin/bash
pushd $SNAPCRAFT_PART_INSTALL
patch -p1 < ../../../c-comment.patch
popd

That's it; our snapcraft package is complete.

Final remarks

To be honest, this is a lot of stuff to deploy an application and the resulting package is rather big; furthermore, this doesn't seem to work with Ubuntu 16.10/17.04 due to changes in some libraries (if you know a solution, write me a e-mail).

Nevertheless, it shows that all kinds of programs can be packaged and deployed using snap.

Troubleshooting

  • If Qt doesn't build for you, change the -qt-xcb parameter of call to ./configure to -system-xcb (or the other way around).
  • The message Note: No relevant classes found. No output generated. is normal during to the compilation of Qt and does not indicate an error.