feat(time): add TimeService for periodic widget updates

This commit is contained in:
Lemmy
2026-04-03 12:47:54 -04:00
parent 6d744a541d
commit b8f9b9f486
9 changed files with 60 additions and 15 deletions
+23 -10
View File
@@ -26,6 +26,8 @@ constexpr float kBarPaddingX = 16.0f;
Bar::Bar() = default;
bool Bar::initialize(TimeService* timeService) {
m_time = timeService;
if (!m_wayland.connect()) {
return false;
}
@@ -34,23 +36,30 @@ bool Bar::initialize(TimeService* timeService) {
syncInstances();
});
auto refreshAll = [this]() {
m_wayland.setWorkspaceChangeCallback([this]() {
for (auto& inst : m_instances) {
if (inst->surface == nullptr || inst->surface->renderer() == nullptr) {
continue;
}
inst->surface->renderer()->makeCurrent();
updateWidgets(*inst);
if (inst->sceneRoot != nullptr && inst->sceneRoot->dirty()) {
inst->surface->requestRedraw();
}
inst->surface->renderNow();
}
};
m_wayland.setWorkspaceChangeCallback(refreshAll);
});
if (timeService != nullptr) {
timeService->setTickCallback(refreshAll);
timeService->setTickCallback([this]() {
for (auto& inst : m_instances) {
if (inst->surface == nullptr || inst->surface->renderer() == nullptr) {
continue;
}
inst->surface->renderer()->makeCurrent();
updateWidgets(*inst);
if (inst->sceneRoot != nullptr && inst->sceneRoot->dirty()) {
inst->surface->requestRedraw();
}
}
});
}
syncInstances();
@@ -164,11 +173,15 @@ void Bar::destroyInstance(std::uint32_t outputName) {
}
void Bar::populateWidgets(BarInstance& instance) {
instance.startWidgets.push_back(std::make_unique<ClockWidget>());
if (m_time != nullptr) {
instance.startWidgets.push_back(std::make_unique<ClockWidget>(*m_time));
}
instance.centerWidgets.push_back(std::make_unique<WorkspacesWidget>(m_wayland, instance.output));
instance.endWidgets.push_back(std::make_unique<ClockWidget>());
if (m_time != nullptr) {
instance.endWidgets.push_back(std::make_unique<ClockWidget>(*m_time));
}
}
void Bar::buildScene(BarInstance& instance, std::uint32_t width, std::uint32_t height) {
+1
View File
@@ -30,5 +30,6 @@ private:
void updateWidgets(BarInstance& instance);
WaylandConnection m_wayland;
TimeService* m_time = nullptr;
std::vector<std::unique_ptr<BarInstance>> m_instances;
};
+9
View File
@@ -1,5 +1,7 @@
#include "time/TimeService.hpp"
#include <format>
void TimeService::setTickCallback(TickCallback callback) {
m_callback = std::move(callback);
}
@@ -18,8 +20,15 @@ void TimeService::tick() {
if (sec != m_lastSecond) {
m_lastSecond = sec;
m_now = now;
if (m_callback) {
m_callback();
}
}
}
std::string TimeService::format(const char* fmt) const {
const auto truncated = std::chrono::floor<std::chrono::seconds>(m_now);
const auto local = std::chrono::current_zone()->to_local(truncated);
return std::vformat(fmt, std::make_format_args(local));
}
+7
View File
@@ -3,16 +3,23 @@
#include <chrono>
#include <cstdint>
#include <functional>
#include <string>
class TimeService {
public:
using Clock = std::chrono::system_clock;
using TimePoint = Clock::time_point;
using TickCallback = std::function<void()>;
void setTickCallback(TickCallback callback);
[[nodiscard]] int pollTimeoutMs() const;
void tick();
[[nodiscard]] TimePoint now() const noexcept { return m_now; }
[[nodiscard]] std::string format(const char* fmt) const;
private:
TickCallback m_callback;
TimePoint m_now{};
std::int64_t m_lastSecond = -1;
};
+4 -5
View File
@@ -2,10 +2,11 @@
#include "render/Palette.hpp"
#include "render/Renderer.hpp"
#include "time/TimeService.hpp"
#include "ui/controls/Label.hpp"
#include <chrono>
#include <format>
ClockWidget::ClockWidget(const TimeService& timeService)
: m_time(timeService) {}
void ClockWidget::create(Renderer& renderer) {
auto label = std::make_unique<Label>();
@@ -21,9 +22,7 @@ void ClockWidget::layout(Renderer& renderer, float /*barWidth*/, float /*barHeig
}
void ClockWidget::update(Renderer& renderer) {
const auto now = std::chrono::system_clock::now();
const auto local = std::chrono::current_zone()->to_local(now);
auto text = std::format("{:%H:%M}", local);
auto text = m_time.format("{:%H:%M:%S}");
if (text != m_lastText) {
m_lastText = std::move(text);
+6
View File
@@ -2,15 +2,21 @@
#include "ui/Widget.hpp"
#include <string>
class Label;
class TimeService;
class ClockWidget : public Widget {
public:
explicit ClockWidget(const TimeService& timeService);
void create(Renderer& renderer) override;
void layout(Renderer& renderer, float barWidth, float barHeight) override;
void update(Renderer& renderer) override;
private:
const TimeService& m_time;
Label* m_label = nullptr;
std::string m_lastText;
};
+6
View File
@@ -112,6 +112,12 @@ void Surface::requestRedraw() {
}
}
void Surface::renderNow() {
if (m_running && m_configured) {
render();
}
}
Renderer* Surface::renderer() const noexcept {
return m_renderer.get();
}
+1
View File
@@ -30,6 +30,7 @@ public:
void setConfigureCallback(ConfigureCallback callback);
void setUpdateCallback(UpdateCallback callback);
void requestRedraw();
void renderNow();
void setAnimationManager(AnimationManager* manager) noexcept { m_animationManager = manager; }
void setSceneRoot(Node* root) noexcept { m_sceneRoot = root; }
[[nodiscard]] Renderer* renderer() const noexcept;
+3
View File
@@ -446,6 +446,9 @@ void WaylandConnection::onWorkspaceStateChanged(ext_workspace_handle_v1* workspa
const std::string label = it->second.name.empty() ? "(unnamed)" : it->second.name;
logInfo("workspace active: {}", label);
}
if (m_workspaceChangeCallback) {
m_workspaceChangeCallback();
}
}
}