quick commit

This commit is contained in:
2026-02-04 15:52:31 +01:00
parent 0463c37543
commit ce0643b6ac
26 changed files with 929 additions and 45 deletions

View File

@@ -2,8 +2,8 @@
#include <sigc++/sigc++.h>
#include <vector>
#include "services/dbus/notification.hpp"
#include "services/dbus/mpris.hpp"
#include "connection/dbus/notification.hpp"
#include "connection/dbus/mpris.hpp"
#include "services/notificationController.hpp"
#include "services/textureCache.hpp"

View File

View File

@@ -1,4 +1,4 @@
#include "services/dbus/mpris.hpp"
#include "connection/dbus/mpris.hpp"
#include <map>
#include <spdlog/spdlog.h>
@@ -19,16 +19,12 @@ std::shared_ptr<MprisController> MprisController::createForPlayer(const std::str
}
MprisController::MprisController() {
Gio::DBus::Connection::get(
Gio::DBus::BusType::SESSION,
sigc::mem_fun(*this, &MprisController::on_bus_connected));
connect_session_async(sigc::mem_fun(*this, &MprisController::on_bus_connected));
}
MprisController::MprisController(const std::string &bus_name)
: m_player_bus_name(bus_name) {
Gio::DBus::Connection::get(
Gio::DBus::BusType::SESSION,
sigc::mem_fun(*this, &MprisController::on_bus_connected));
connect_session_async(sigc::mem_fun(*this, &MprisController::on_bus_connected));
}
std::vector<std::string> MprisController::get_registered_players() const {
@@ -65,11 +61,11 @@ void MprisController::on_bus_connected(const Glib::RefPtr<Gio::AsyncResult> &res
return;
}
try {
m_connection = Gio::DBus::Connection::get_finish(result);
connection = Gio::DBus::Connection::get_finish(result);
if (!m_dbus_proxy) {
m_dbus_proxy = Gio::DBus::Proxy::create_sync(
m_connection,
connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus");
@@ -131,10 +127,10 @@ void MprisController::handle_player_registered(const std::string &bus_name) {
registeredPlayers.insert(bus_name);
if (bus_name == m_player_bus_name && !m_proxy && m_connection) {
if (bus_name == m_player_bus_name && !m_proxy && connection) {
try {
m_proxy = Gio::DBus::Proxy::create_sync(
m_connection,
connection,
m_player_bus_name,
"/org/mpris/MediaPlayer2",
"org.mpris.MediaPlayer2.Player");

View File

@@ -1,11 +1,9 @@
#include "services/dbus/notification.hpp"
#include "connection/dbus/notification.hpp"
#include <spdlog/spdlog.h>
#include <sys/types.h>
#include "helpers/string.hpp"
#include "services/notificationController.hpp"
#include "widgets/notification/copyNotification.hpp"
#include "glib.h"
#include "glibconfig.h"

View File

@@ -1,4 +1,4 @@
#include "services/tray.hpp"
#include "connection/dbus/tray.hpp"
#include <algorithm>
#include <cstring>
@@ -277,11 +277,7 @@ void TrayService::start() {
return;
}
try {
Gio::init();
} catch (const Glib::Error &) {
// Already initialised; ignore.
}
ensure_gio_init();
if (!nodeInfo) {
try {

View File

@@ -0,0 +1,119 @@
#include "connection/httpConnection.hpp"
#include <algorithm>
#include <cctype>
#include <curl/curl.h>
#include <string>
#include <utility>
namespace {
size_t write_to_string(void *contents, size_t size, size_t nmemb, void *userp) {
size_t total = size * nmemb;
auto *buffer = static_cast<std::string *>(userp);
buffer->append(static_cast<char *>(contents), total);
return total;
}
std::string trim(std::string value) {
auto not_space = [](unsigned char c) { return std::isspace(c) == 0; };
value.erase(value.begin(),
std::find_if(value.begin(), value.end(), not_space));
value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(),
value.end());
return value;
}
size_t header_to_map(char *buffer, size_t size, size_t nitems, void *userdata) {
size_t total = size * nitems;
auto *header_map = static_cast<std::map<std::string, std::string> *>(userdata);
std::string line(buffer, total);
auto colon = line.find(':');
if (colon != std::string::npos) {
auto key = trim(line.substr(0, colon));
auto value = trim(line.substr(colon + 1));
if (!key.empty()) {
header_map->insert_or_assign(std::move(key), std::move(value));
}
}
return total;
}
}
HttpResponse HttpConnection::get(const std::string &url,
const std::map<std::string, std::string> &headers,
long timeout_ms) {
return performRequest("GET", url, std::string(), headers, std::string(), timeout_ms);
}
HttpResponse HttpConnection::post(const std::string &url,
const std::string &body,
const std::map<std::string, std::string> &headers,
const std::string &content_type,
long timeout_ms) {
return performRequest("POST", url, body, headers, content_type, timeout_ms);
}
HttpResponse HttpConnection::performRequest(const std::string &method,
const std::string &url,
const std::string &body,
const std::map<std::string, std::string> &headers,
const std::string &content_type,
long timeout_ms) {
HttpResponse response;
CURL *curl = curl_easy_init();
if (!curl) {
response.error = "curl_easy_init failed";
return response;
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response.body);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_to_map);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &response.headers);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "bar/1.0");
if (timeout_ms > 0) {
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms);
}
if (method == "POST") {
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(body.size()));
} else {
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
}
struct curl_slist *header_list = nullptr;
for (const auto &pair : headers) {
std::string header = pair.first + ": " + pair.second;
header_list = curl_slist_append(header_list, header.c_str());
}
if (method == "POST" && !content_type.empty()) {
std::string content_header = "Content-Type: " + content_type;
header_list = curl_slist_append(header_list, content_header.c_str());
}
if (header_list) {
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
}
auto result = curl_easy_perform(curl);
if (result != CURLE_OK) {
response.error = curl_easy_strerror(result);
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response.status_code);
if (header_list) {
curl_slist_free_all(header_list);
}
curl_easy_cleanup(curl);
return response;
}

View File

@@ -3,7 +3,7 @@
#include <algorithm>
#include <memory>
#include "services/dbus/messages.hpp"
#include "connection/dbus/messages.hpp"
#include "widgets/notification/baseNotification.hpp"
#include "widgets/notification/copyNotification.hpp"
#include "widgets/notification/notificationWindow.hpp"

View File

@@ -34,10 +34,8 @@ ControlCenter::ControlCenter(std::string icon, std::string name)
this->controlCenterContainer.set_orientation(Gtk::Orientation::VERTICAL);
this->controlCenterContainer.set_spacing(4);
this->testLabel.set_text("Test tab");
this->contentStack.add(this->controlCenterContainer, "controls", "Controls");
this->contentStack.add(this->testLabel, "test", "Test");
this->contentStack.add(this->weatherWidget, "test", "Test");
this->contentStack.set_visible_child("controls");
this->setActiveTab("controls");

112
src/widgets/weather.cpp Normal file
View File

@@ -0,0 +1,112 @@
#include "widgets/weather.hpp"
#include <curl/curl.h>
#include <glibmm/main.h>
#include <ios>
#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include <sstream>
#include <thread>
namespace {
constexpr const char *kWeatherUrl =
"https://api.open-meteo.com/v1/forecast?latitude=49.0094&longitude=8.4044&daily=temperature_2m_max,temperature_2m_min,weather_code&hourly=temperature_2m,rain&current=temperature_2m&timezone=Europe%2FBerlin";
size_t write_to_buffer(void *contents, size_t size, size_t nmemb, void *userp) {
size_t total = size * nmemb;
auto *buffer = static_cast<std::string *>(userp);
buffer->append(static_cast<char *>(contents), total);
return total;
}
std::string formatTemp(double value) {
std::ostringstream ss;
ss.setf(std::ios::fixed);
ss.precision(1);
ss << value << "°C";
return ss.str();
}
} // namespace
WeatherWidget::WeatherWidget()
: Gtk::Box(Gtk::Orientation::VERTICAL) {
this->set_orientation(Gtk::Orientation::VERTICAL);
this->set_spacing(6);
this->set_margin_top(4);
this->set_margin_bottom(4);
this->set_margin_start(4);
this->set_margin_end(4);
this->titleLabel.set_text("Weather");
this->currentLabel.set_text("Now: --");
this->todayLabel.set_text("Today: -- / --");
this->append(this->titleLabel);
this->append(this->currentLabel);
this->append(this->todayLabel);
this->fetchWeather();
Glib::signal_timeout().connect_seconds(
sigc::mem_fun(*this, &WeatherWidget::onRefreshTick),
3600);
}
bool WeatherWidget::onRefreshTick() {
this->fetchWeather();
return true;
}
void WeatherWidget::fetchWeather() {
std::thread([this]() {
std::string buffer;
CURL *curl = curl_easy_init();
if (!curl) {
Glib::signal_idle().connect_once([this]() {
this->applyWeatherText("Now: --", "Today: -- / --");
});
return;
}
curl_easy_setopt(curl, CURLOPT_URL, kWeatherUrl);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_buffer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "bar/1.0");
auto res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK || buffer.empty()) {
Glib::signal_idle().connect_once([this]() {
this->applyWeatherText("Now: --", "Today: -- / --");
});
return;
}
try {
auto json = nlohmann::json::parse(buffer);
double current = json.at("current").at("temperature_2m").get<double>();
double minTemp = json.at("daily").at("temperature_2m_min").at(0).get<double>();
double maxTemp = json.at("daily").at("temperature_2m_max").at(0).get<double>();
std::string currentText = "Now: " + formatTemp(current);
std::string todayText = "Today: " + formatTemp(minTemp) + " / " + formatTemp(maxTemp);
Glib::signal_idle().connect_once([this, currentText, todayText]() {
this->applyWeatherText(currentText, todayText);
});
} catch (const std::exception &ex) {
spdlog::error("Weather parse error: {}", ex.what());
Glib::signal_idle().connect_once([this]() {
this->applyWeatherText("Now: --", "Today: -- / --");
});
}
}).detach();
}
void WeatherWidget::applyWeatherText(const std::string &current_text,
const std::string &today_text) {
this->currentLabel.set_text(current_text);
this->todayLabel.set_text(today_text);
}