Creating a Photo-Box with the help of KWin

For a family celebration I wanted to create a “Photo-Box” or “Selfie-Box”: a place where the guests can trigger a photo of themselves without having to use tools like a selfie-stick.

The requirements for the setup were:

  • Trigger should be remote controlled
  • The remote control should not be visible or at max hardly visible
  • The guests should see themselves before taking the photo
  • All already taken photos should be presented in a slide show to the guests

The camera in question supported some but not all of the requirements. Especially the last two were tricky. While it supported showing a slide show of all taken photos, the slide show ended as soon as a new photo was taken. But the camera also has an usb-connector so the whole power of a computer could be taken in.

A short investigation showed that gphoto2 could be the solution. It allows to completely remote control the camera and download photos. With that all requirements can be fulfilled. But by using a computer a new requirement got added: the screen should be locked.

This requirement created a challenge. As the maintainer of Plasma’s lock screen infrastructure I know what it is good at and that is blocking input and preventing other applications to be visible. Thus we cannot just use e.g. Digikam with gphoto2 integration to take the photo – the lock screen would prevent the Digikam window to be visible. Also there is no way to have a slide show in the lock screen.

Which means all requirements must be fulfilled through the lock screen infrastructure. A result of that is that I spent some time on adding wallpaper plugin support to the lock screen. This allowed to reuse Plasma’s wallpaper plugins and thus also the slide show plugin. One problem solved and all Plasma users can benefit from it.

But how to trigger gphoto2? The idea I came up with is using KWin/Wayland. KWin has full control over the input stack (even before the lock screen intercepts) and also knows which input devices it is interacting with. As a remote control I decided to use a Logitech Presenter and accept any clicked button on that device as the trigger. The code looks like the following:

class PhotoBoxFilter : public InputEventFilter {
public:
    PhotoBoxFilter()
        : InputEventFilter()
        , m_tetheredProcess(new Process)
    {
        m_tetheredProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel);
        m_tetheredProcess->setWorkingDirectory(QStringLiteral("/path/to/storage"));
        m_tetheredProcess->setArguments(QStringList{
                                                   QStringLiteral("--set-config"),
                                                   QStringLiteral("output=TFT"),
                                                   QStringLiteral("--capture-image-and-download"),
                                                   QStringLiteral("--filename"),
                                                   QStringLiteral("%Y%m%d-%H%M%S.jpg"),
                                                   QStringLiteral("-I"),
                                                   QStringLiteral("-1"),
                                                   QStringLiteral("--reset-interval")
        });
        m_tetheredProcess->setProgram(QStringLiteral("gphoto2"));
    }
    virtual ~PhotoBoxFilter() {
        m_tetheredProcess->terminate();
        m_tetheredProcess->waitForFinished();
    }
    bool keyEvent(QKeyEvent *event) override {
        if (!waylandServer()->isScreenLocked()) {
            return false;
        }
        auto key = static_cast(event);
        if (key->device() && key->device()->vendor() == 1133u && key->device()->product() == 50453u) {
            if (event->type() == QEvent::KeyRelease) {
                if (m_tetheredProcess->state() != QProcess::Running) {
                    m_tetheredProcess->start();
                    m_tetheredProcess->waitForStarted(5000);
                } else {
                    ::kill(m_tetheredProcess->pid(), SIGUSR1);
                }
            }
            return true;
        }
        return false;
    }

private:
    QScopedPointer m_tetheredProcess;
};

And in addition the method InputRedirection::setupInputFilters needed an adjustment to install this new InputFilter just before installing the LockScreenFilter.

photobox

The final setup:

  • Camera on tripod
  • Connected to an external screen showing the live capture
  • Connected to a notebook through USB
  • Notebook connected to an external TV
  • Notebook locked and lock screen configured to show slide show of photos
  • Logitech Presenter used as remote control

The last detail which needed adjustments was on the lock screen theme. The text input is destroying the experience of the slide show. Thus a small hack to the QML code was needed to hide it and reveal again after pointer motion.

What I want to show with this blog post is one of the advantage of open source software: you can adjust the software to your needs and turn it into something completely different which fits your needs.

2 Replies to “Creating a Photo-Box with the help of KWin”

  1. If I understand correctly, the live capture uses a different display than the slideshow.
    Then how you got the lock screen in one display and not in the other one?

Comments are closed.