working timer

This commit is contained in:
2026-02-07 21:16:35 +01:00
parent ff2d0afd9b
commit 6be70a7d93
14 changed files with 456 additions and 3 deletions

View File

@@ -7,6 +7,7 @@
#include "connection/dbus/notification.hpp"
#include "services/notificationController.hpp"
#include "services/textureCache.hpp"
#include "widgets/wallpaperWindow.hpp"
App::App() {
this->app = Gtk::Application::create("org.example.mybar");

View File

@@ -39,15 +39,15 @@ ControlCenter::ControlCenter(Icon::Type icon, std::string name)
this->contentStack.set_transition_type(Gtk::StackTransitionType::CROSSFADE);
this->mediaControlWidget = std::make_unique<MediaWidget>();
this->weatherWidget = std::make_unique<WeatherWidget>();
this->timerWidget = std::make_unique<TimerWidget>();
this->contentStack.add(*this->mediaControlWidget, "controls", "Controls");
this->contentStack.add(*this->weatherWidget, "info", "Info");
this->contentStack.add(*Gtk::make_managed<Gtk::Label>("Timer"), "timer", "Timer");
this->contentStack.add(*this->timerWidget, "timer", "Timer");
this->contentStack.set_visible_child("controls");
this->setActiveTab("info");
this->setActiveTab("controls");
this->container.append(this->contentStack);

View File

@@ -0,0 +1,125 @@
#include "widgets/controlCenter/timer.hpp"
#include <cstdint>
#include <gdk/gdkkeysyms.h>
#include <memory>
#include <spdlog/spdlog.h>
#include <sys/types.h>
#include "gtkmm/entry.h"
#include "gtkmm/eventcontrollerkey.h"
#include "gtkmm/label.h"
TimerWidget::TimerWidget() {
set_orientation(Gtk::Orientation::VERTICAL);
set_spacing(6);
this->timerService->getSignalTimerSet().connect([this](const std::string &duration, uint64_t timerId) {
this->addTimer(duration, timerId);
});
this->timerService->getSignalTimerCancelled().connect([this](uint64_t timerId) {
this->removeTimer(timerId);
});
this->timerService->getSignalTimerExpired().connect([this](uint64_t timerId) {
this->activateTimer(timerId);
});
this->timerService->tickSignal.connect([this]() {
for (auto &[id, timer] : activeTimers) {
timer->tickDown();
}
});
auto label = Gtk::make_managed<Gtk::Label>("Set Timer");
label->add_css_class("control-center-timer-label");
auto entry = Gtk::make_managed<Gtk::Entry>();
entry->set_placeholder_text("0s");
entry->set_valign(Gtk::Align::CENTER);
entry->set_alignment(0.5);
entry->add_css_class("text-area");
entry->set_editable(false);
entry->set_focusable(true);
entry->set_position(-1);
set_focusable(false);
auto keyController = Gtk::EventControllerKey::create();
keyController->set_propagation_phase(Gtk::PropagationPhase::CAPTURE);
keyController->signal_key_pressed().connect([this, entry](guint keyval, guint, Gdk::ModifierType) -> bool {
if (updatingText) {
return true;
}
if (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9) {
rawDigits.push_back(static_cast<char>('0' + (keyval - GDK_KEY_0)));
} else if (keyval >= GDK_KEY_KP_0 && keyval <= GDK_KEY_KP_9) {
rawDigits.push_back(static_cast<char>('0' + (keyval - GDK_KEY_KP_0)));
} else if (keyval == GDK_KEY_BackSpace || keyval == GDK_KEY_Delete ||
keyval == GDK_KEY_KP_Delete) {
if (!rawDigits.empty()) {
rawDigits.pop_back();
}
} else if (keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter ||
keyval == GDK_KEY_Tab || keyval == GDK_KEY_ISO_Left_Tab) {
return false;
} else {
return true;
}
if (rawDigits.size() > 6) {
rawDigits.erase(0, rawDigits.size() - 6);
}
updatingText = true;
entry->set_text(format_duration(rawDigits));
entry->set_position(-1);
updatingText = false;
return true;
},
false);
entry->add_controller(keyController);
entry->signal_activate().connect([this, entry]() {
if (rawDigits.empty()) {
return;
}
spdlog::info("Timer set for {} seconds", rawDigits);
this->timerService->addTimer(std::stoul(rawDigits));
rawDigits.clear();
this->updatingText = true;
entry->set_text("");
entry->set_position(-1);
this->updatingText = false;
},
false);
append(*label);
append(*entry);
}
void TimerWidget::addTimer(const std::string &duration, uint64_t timerId) {
std::unique_ptr<Timer> timer = std::make_unique<Timer>(duration, timerId);
append(*timer);
this->activeTimers[timerId] = std::move(timer);
}
void TimerWidget::removeTimer(uint64_t timerId) {
auto it = this->activeTimers.find(timerId);
if (it != this->activeTimers.end()) {
this->remove(*it->second);
this->activeTimers.erase(it);
}
}
void TimerWidget::activateTimer(uint64_t timerId) {
auto it = this->activeTimers.find(timerId);
if (it != this->activeTimers.end()) {
it->second->activateTimer();
}
}

View File

@@ -0,0 +1,89 @@
#include "widgets/wallpaperWindow.hpp"
#include <cstdlib>
#include <filesystem>
#include <gdk/gdk.h>
#include <spdlog/spdlog.h>
#include "giomm/file.h"
WallpaperWindow::WallpaperWindow(GdkMonitor *monitor, const std::string &imagePath) {
set_name("wallpaper-window");
set_resizable(false);
set_focusable(false);
gtk_layer_init_for_window(gobj());
if (monitor) {
gtk_layer_set_monitor(gobj(), monitor);
}
gtk_layer_set_layer(gobj(), GTK_LAYER_SHELL_LAYER_BACKGROUND);
gtk_layer_set_anchor(gobj(), GTK_LAYER_SHELL_EDGE_TOP, true);
gtk_layer_set_anchor(gobj(), GTK_LAYER_SHELL_EDGE_BOTTOM, true);
gtk_layer_set_anchor(gobj(), GTK_LAYER_SHELL_EDGE_LEFT, true);
gtk_layer_set_anchor(gobj(), GTK_LAYER_SHELL_EDGE_RIGHT, true);
gtk_layer_set_exclusive_zone(gobj(), 0);
gtk_layer_set_keyboard_mode(gobj(), GTK_LAYER_SHELL_KEYBOARD_MODE_NONE);
picture.set_hexpand(true);
picture.set_vexpand(true);
picture.set_halign(Gtk::Align::FILL);
picture.set_valign(Gtk::Align::FILL);
picture.set_can_shrink(true);
picture.set_content_fit(Gtk::ContentFit::COVER);
if (monitor) {
GdkRectangle geom{};
gdk_monitor_get_geometry(monitor, &geom);
set_default_size(geom.width, geom.height);
set_size_request(geom.width, geom.height);
picture.set_size_request(geom.width, geom.height);
}
auto resolved_path = expand_user_path(imagePath);
if (auto texture = load_texture(resolved_path)) {
picture.set_paintable(texture);
} else {
spdlog::warn("Wallpaper image failed to load: {}", resolved_path);
}
set_child(picture);
}
std::string WallpaperWindow::expand_user_path(const std::string &path) {
if (path.rfind("~/", 0) != 0) {
return path;
}
const char *home = std::getenv("HOME");
if (!home || !*home) {
return path;
}
return std::filesystem::path(home) / path.substr(2);
}
Glib::RefPtr<Gdk::Texture> WallpaperWindow::load_texture(const std::string &path) {
if (path.empty()) {
spdlog::warn("Wallpaper image path is empty");
return {};
}
if (!std::filesystem::exists(path)) {
spdlog::warn("Wallpaper image not found at path: {}", path);
return {};
}
try {
auto file = Gio::File::create_for_path(path);
return Gdk::Texture::create_from_file(file);
} catch (const std::exception &ex) {
spdlog::warn("Failed to load wallpaper image {}: {}", path, ex.what());
return {};
} catch (...) {
spdlog::warn("Failed to load wallpaper image {}: unknown error", path);
return {};
}
}