// SPDX-License-Identifier: MIT #include "tooltip.h" #include "readingformat.h" #include #include QVector tooltipSensors(const QVector &sensors) { QVector result{{"cpu", "CPU", {}}, {"memory", "RAM", {}}, {"nvme", "NVMe", {}}, {"battery", "Battery", {}}, {"board", "Board", {}}}; const QStringList prefixes{"cros_ec/peci-temp", "spd5118/", "nvme/Composite", "cros_ec/battery_temp@b", "cros_ec/local_f75397@4c"}; for (int i = 0; i < result.size(); ++i) { for (const auto &sensor : sensors) if (sensor.id.startsWith(prefixes[i])) { result[i].id = sensor.id; break; } if (i == 0 && result[i].id.isEmpty()) for (const auto &sensor : sensors) if (sensor.id.startsWith("coretemp/Package id")) { result[i].id = sensor.id; break; } } return result; } bool tooltipEnabled(const QVariantMap &settings, const QString &key, bool fallback) { return settings.value("tray/hover/" + key, fallback).toBool(); } int tooltipAppCount(const QVariantMap &settings) { return std::clamp(settings.value("tray/hover/topApps", settings.value("tray/hover/topApp", false).toBool() ? 1 : 0).toInt(), 0, 3); } QString batteryTooltip(const QVariantMap &battery, int limit, const QVariantMap &upower) { if (battery.isEmpty()) return "Battery unavailable"; QString text = "Battery " + (battery.contains("capacity") ? QString::number(battery["capacity"].toInt()) + "%" : "—"); const auto energy = [&](const QString &key) { const double value = battery.value(key, NAN).toDouble(); if (!std::isfinite(value) || value < 0) return QString("—"); QString number = QString::number(qRound64(value)); for (int i = number.size() - 3; i > 0; i -= 3) number.insert(i, ' '); return number; }; text += " · " + energy("remainingMWh") + " mWh / " + energy("fullMWh") + " mWh"; const auto watts = batteryRate(battery); text += "\n\u2003" + (watts ? (*watts > 0 ? "+" : "") + formatReading(*watts) + " W" : "— W"); const bool charging = battery["state"] == "Charging", discharging = battery["state"] == "Discharging"; double seconds = 0; bool approximate = false; if (discharging) seconds = upower.value("TimeToEmpty").toDouble(); else if (charging && limit == 100) seconds = upower.value("TimeToFull").toDouble(); else if (charging && limit < 100) { approximate = true; if (battery["current_now"].toDouble() > 0 && battery.contains("charge_now") && battery["charge_full"].toDouble() > 0) seconds = (battery["charge_full"].toDouble() * limit / 100 - battery["charge_now"].toDouble()) / battery["current_now"].toDouble() * 3600; else if (watts && *watts > 0 && battery.contains("energy_now") && battery["energy_full"].toDouble() > 0) seconds = (battery["energy_full"].toDouble() * limit / 100 - battery["energy_now"].toDouble()) / (*watts * 1e6) * 3600; } if (std::isfinite(seconds) && seconds > 0) { const auto minutes = qint64(std::ceil(seconds / 60)); text += QString(" · %1%2 h %3 min to %4%").arg(approximate ? "≈" : "") .arg(minutes / 60).arg(minutes % 60).arg(discharging ? 0 : limit); } else if (charging && battery.contains("capacity") && battery["capacity"].toInt() >= limit) text += QString(" · %1% limit reached").arg(limit); else if (charging || discharging) text += " · Time remaining unavailable"; else text += " · " + battery["state"].toString(); return text; } QString trayTooltip(const QVariantMap &settings, const QMap &values, const QVector &temperatures, const QString &battery, const QStringList &topApps, const QVector &powerSensors) { const auto reading = [&](const QString &id, int decimals) { const auto it = values.constFind(id); return it != values.cend() && std::isfinite(*it) ? QString::number(*it, 'f', decimals) : QString("—"); }; QStringList lines; if (tooltipEnabled(settings, "cpu")) { lines << "CPU usage: " + reading("cpu-usage", 1) + " %"; const int count = tooltipAppCount(settings); if (count && topApps.isEmpty()) lines << "\u2003CPU app readings unavailable"; for (int i = 0; i < std::min(count, int(topApps.size())); ++i) lines << "\u2003" + topApps[i]; } if (tooltipEnabled(settings, "battery")) lines << battery; if (tooltipEnabled(settings, "fan")) lines << "Fan speed: " + reading("fan", 0) + " RPM (" + reading("fan-duty", 0) + " %)"; QStringList power; for (const auto &sensor : powerSensors) if (tooltipEnabled(settings, sensor.id, false)) power << sensor.name + ": " + formatReading(values.value(sensor.id, NAN)) + " W"; if (power.size() > 1) lines << "Power consumption:"; for (const auto &line : power) lines << (power.size() > 1 ? "\u2003" : "") + line; QStringList temps; for (const auto &sensor : temperatures) if (!sensor.id.isEmpty() && tooltipEnabled(settings, "temperature/" + sensor.key)) temps << sensor.name + " " + formatReading(values.value(sensor.id, NAN)) + "°C"; if (temps.size() > 1) lines << "Temperatures:"; for (const auto &temp : temps) lines << (temps.size() > 1 ? "\u2003" : "") + temp; return lines.join('\n'); }