Index | Thread | Search

From:
Rafael Sadowski <rafael@sizeofvoid.org>
Subject:
Re: KDE Plasma clock not updating
To:
Mark Kane <mark@kane.mn>
Cc:
ports@openbsd.org
Date:
Fri, 10 Apr 2026 19:56:19 +0200

Download raw body.

Thread
On Thu Apr 09, 2026 at 08:51:34PM +0200, Rafael Sadowski wrote:
> On Wed Apr 08, 2026 at 04:43:38PM -0500, Mark Kane wrote:
> > Hi,
> > 
> > On recent snapshots (sorry, not sure exactly when it started) the clock in
> > various parts of KDE Plasma appears hung and does not update the date/time
> > along with the system clock.
> > 
> > Panel widgets such as "Digital Clock" and "Analog Clock" are stuck at the
> > date/time that KDE started and do not tick forward. If a change is made to
> > Digital Clock settings that would update the time display such as "Show
> > seconds", the panel widget does update once with the correct time at the
> > exact moment of the change but doesn't update again unless another setting
> > change is made.
> > 
> > When locking a KDE session, the clock on the lock screen hangs at the moment
> > it was locked and does not move forward. Unlocking and re-locking updates
> > the lock screen clock each time to the correct time at the moment it was
> > locked.
> > 
> > I enabled logging per the kde-plasma pkg-readme and there are no errors
> > output there. Same result when testing digitalclock with
> > plasmawindowed/plasmoidviewer.
> > 
> > This is reproducible on a clean 7.9-beta amd64 snap install from April 7
> > with the latest packages from April 4 as well as a machine that has been
> > upgraded from previous snaps.
> > 
> > Thanks,
> > 
> > -Mark
> > OpenBSD 7.9-beta (GENERIC.MP) #407: Wed Apr  8 10:21:00 MDT 2026
> >     deraadt@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> > 
> 
> Thanks for the report! Unfortunately, I'm aware of this, but I
> only realised it too late, as I don't want to go back to KDE 6.5.
> 
> The problem: In version 6.6, Plasma Workspace introduced libclock;
> this implementation is based entirely on sys/timerfd.h. I
> commented out that functionality back then:
> 
> x11/kde-plasma/plasma-workspace/patches/patch-libclock_alignedtimer_cpp
> 
> https://invent.kde.org/plasma/plasma-workspace/-/blob/master/libclock/alignedtimer.cpp?ref_type=heads
> 
> Anyway, I've been working on a solution for a while now, but life
> got in the way!
> 
> This error is not related to the latest pledge changes.
> 
> This is my top priority; if I haven't found a solution until 7.9,
> it will be released as a stable patch.
> 

I've been testing the following version for a hours now and am
happy with it. I "simply" tried to replace timerfd with my own
QTimer. It works great for the clocks. Since I've now received
approval from upstream, I'd like to commit it. Does anyone see any
showstoppers in the code?

I followed the cmake + create a new cpp file  pattern which is
valid for upstream.


Special: I only check for OpenBSD because Net and FreeBSD support
fimerfd(2).

See the comments and the PR for an explanation:

Index: Makefile
===================================================================
RCS file: /cvs/ports/x11/kde-plasma/plasma-workspace/Makefile,v
diff -u -p -r1.37 Makefile
--- Makefile	9 Mar 2026 06:50:16 -0000	1.37
+++ Makefile	10 Apr 2026 17:43:08 -0000
@@ -1,6 +1,6 @@
 COMMENT =	various components needed to run a Plasma-based environment
 DISTNAME =	plasma-workspace-${VERSION}
-REVISION =	0
+REVISION =	1
 
 SHARED_LIBS +=  kfontinst                 1.0 # 0.0
 SHARED_LIBS +=  kfontinstui               2.0 # 0.0
Index: patches/patch-libclock_CMakeLists_txt
===================================================================
RCS file: patches/patch-libclock_CMakeLists_txt
diff -N patches/patch-libclock_CMakeLists_txt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-libclock_CMakeLists_txt	10 Apr 2026 17:43:08 -0000
@@ -0,0 +1,18 @@
+https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/6487
+
+Index: libclock/CMakeLists.txt
+--- libclock/CMakeLists.txt.orig
++++ libclock/CMakeLists.txt
+@@ -3,7 +3,11 @@ URI "org.kde.plasma.clock"
+ GENERATE_PLUGIN_SOURCE
+ )
+ 
+-target_sources(clockplugin PRIVATE alignedtimer.cpp clock.cpp)
++if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
++    target_sources(clockplugin PRIVATE alignedtimer_posix.cpp clock.cpp)
++else()
++    target_sources(clockplugin PRIVATE alignedtimer.cpp clock.cpp)
++endif()
+ 
+ target_link_libraries(clockplugin
+     PRIVATE
Index: patches/patch-libclock_alignedtimer_h
===================================================================
RCS file: patches/patch-libclock_alignedtimer_h
diff -N patches/patch-libclock_alignedtimer_h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-libclock_alignedtimer_h	10 Apr 2026 17:43:08 -0000
@@ -0,0 +1,25 @@
+https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/6487
+
+Index: libclock/alignedtimer.h
+--- libclock/alignedtimer.h.orig
++++ libclock/alignedtimer.h
+@@ -9,6 +9,8 @@
+ #include <chrono>
+ #include <memory>
+ 
++class QTimer;
++
+ class AlignedTimer : public QObject
+ {
+     Q_OBJECT
+@@ -25,5 +27,9 @@ Q_SIGNALS:
+ private:
+     void initTimer();
+     std::chrono::seconds m_interval;
+-    int m_timerFd = -1;
++#if defined(Q_OS_OPENBSD)
++     QTimer *m_timer = nullptr;
++#else
++     int m_timerFd = -1;
++#endif
+ };
Index: patches/patch-libclock_alignedtimer_posix_cpp
===================================================================
RCS file: patches/patch-libclock_alignedtimer_posix_cpp
diff -N patches/patch-libclock_alignedtimer_posix_cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-libclock_alignedtimer_posix_cpp	10 Apr 2026 17:43:08 -0000
@@ -0,0 +1,88 @@
+https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/6487
+
+Index: libclock/alignedtimer_posix.cpp
+--- libclock/alignedtimer_posix.cpp.orig
++++ libclock/alignedtimer_posix.cpp
+@@ -0,0 +1,82 @@
++/*
++    SPDX-FileCopyrightText: 2023 David Edmundson <davidedmundson@kde.org>
++    SPDX-FileCopyrightText: 2026 Rafael Sadowski <rafael@sizeofvoid.org>
++    SPDX-License-Identifier: LGPL-2.0-or-later
++    SPDX-License-Identifier: ISC
++*/
++
++#include "alignedtimer.h"
++
++#include <QDebug>
++#include <QTimer>
++
++#include <algorithm>
++#include <climits>
++#include <time.h>
++
++std::shared_ptr<AlignedTimer> AlignedTimer::getMinuteTimer()
++{
++    static std::weak_ptr<AlignedTimer> s_minuteTimer;
++
++    std::shared_ptr<AlignedTimer> timer = s_minuteTimer.lock();
++    if (!timer) {
++        timer = std::make_shared<AlignedTimer>(std::chrono::minutes(1));
++        s_minuteTimer = timer;
++    }
++    return timer;
++}
++
++std::shared_ptr<AlignedTimer> AlignedTimer::getSecondTimer()
++{
++    static std::weak_ptr<AlignedTimer> s_secondTimer;
++
++    std::shared_ptr<AlignedTimer> timer = s_secondTimer.lock();
++    if (!timer) {
++        timer = std::make_shared<AlignedTimer>(std::chrono::seconds(1));
++        s_secondTimer = timer;
++    }
++    return timer;
++}
++
++AlignedTimer::AlignedTimer(std::chrono::seconds interval)
++    : m_interval(interval)
++{
++    m_timer = new QTimer(this);
++    m_timer->setSingleShot(true);
++    connect(m_timer, &QTimer::timeout, this, [this]() {
++        Q_EMIT timeout();
++        initTimer();
++    });
++    initTimer();
++}
++
++AlignedTimer::~AlignedTimer() = default;
++
++/**
++ * Starts the timer so it fires exactly at the next whole interval boundary.
++ * For example, with a 1-second interval the timer always fires at :00, :01...
++ * and with a 1-minute interval it fires at 12:01:00, 12:02:00 regardless of
++ * when this function is called.
++ */
++void AlignedTimer::initTimer()
++{
++    struct timespec now;
++    if (clock_gettime(CLOCK_REALTIME, &now) != 0) {
++        qCritical() << "AlignedTimer: clock_gettime failed.";
++        return;
++    }
++
++    // Current wall clock time in milliseconds since the Unix epoch.
++    const long long intervalMs = m_interval.count() * 1000LL;
++    const long long nowMs = (long long)now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
++
++    // Round down to the last boundary, then step forward to the next one.
++    const long long nextMs = ((nowMs / intervalMs) + 1) * intervalMs;
++
++    // How long to wait from now until that boundary.
++    const long long delayMs = nextMs - nowMs;
++
++    m_timer->start(static_cast<int>(std::min<long long>(delayMs, INT_MAX)));
++}
++
++#include "moc_alignedtimer.cpp"