From: Rafael Sadowski Subject: Re: KDE Plasma clock not updating To: Mark Kane Cc: ports@openbsd.org Date: Fri, 10 Apr 2026 19:56:19 +0200 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 + #include + ++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 ++ SPDX-FileCopyrightText: 2026 Rafael Sadowski ++ SPDX-License-Identifier: LGPL-2.0-or-later ++ SPDX-License-Identifier: ISC ++*/ ++ ++#include "alignedtimer.h" ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++std::shared_ptr AlignedTimer::getMinuteTimer() ++{ ++ static std::weak_ptr s_minuteTimer; ++ ++ std::shared_ptr timer = s_minuteTimer.lock(); ++ if (!timer) { ++ timer = std::make_shared(std::chrono::minutes(1)); ++ s_minuteTimer = timer; ++ } ++ return timer; ++} ++ ++std::shared_ptr AlignedTimer::getSecondTimer() ++{ ++ static std::weak_ptr s_secondTimer; ++ ++ std::shared_ptr timer = s_secondTimer.lock(); ++ if (!timer) { ++ timer = std::make_shared(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(std::min(delayMs, INT_MAX))); ++} ++ ++#include "moc_alignedtimer.cpp"