1ms slower on average 💔 sad!
This commit is contained in:
parent
39a6a5cff0
commit
ff3d9bcce8
|
@ -9,7 +9,7 @@ AllowShortLoopsOnASingleLine: true
|
|||
BasedOnStyle: Chromium
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
ColumnLimit: 100
|
||||
ColumnLimit: 120
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: false
|
||||
|
|
|
@ -2,28 +2,27 @@
|
|||
#include <filesystem>
|
||||
#include <fmt/core.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
using rfl::Result;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
inline fn GetConfigPath() -> std::string {
|
||||
inline fn GetConfigPath() -> fs::path {
|
||||
#ifdef _WIN32
|
||||
const char* localAppData = std::getenv("LOCALAPPDATA");
|
||||
|
||||
if (!localAppData)
|
||||
throw std::runtime_error("Environment variable LOCALAPPDATA is not set");
|
||||
|
||||
return localAppData;
|
||||
return fs::path(localAppData);
|
||||
#else
|
||||
const char* home = std::getenv("HOME");
|
||||
|
||||
if (!home)
|
||||
throw std::runtime_error("Environment variable HOME is not set");
|
||||
|
||||
return std::string(home) + "/.config";
|
||||
return fs::path(home) / ".config";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -34,7 +33,8 @@ fn Config::getInstance() -> Config {
|
|||
const Result<Config> result = rfl::toml::load<Config>(configPath.string());
|
||||
|
||||
if (!result) {
|
||||
fmt::println(stderr, "Failed to load config file: {}", result.error()->what());
|
||||
ERROR_LOG("Failed to load config file: {}", result.error()->what());
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/Field.hpp>
|
||||
|
@ -18,7 +18,8 @@ struct NowPlaying {
|
|||
};
|
||||
|
||||
struct Weather {
|
||||
bool enabled = false;
|
||||
bool enabled = false;
|
||||
bool show_town_name = false;
|
||||
|
||||
Location location;
|
||||
string api_key;
|
||||
|
|
129
src/main.cpp
129
src/main.cpp
|
@ -43,11 +43,11 @@ namespace {
|
|||
date.erase(date.begin());
|
||||
|
||||
// Append appropriate suffix for the date
|
||||
if (date == "1" || date == "21" || date == "31")
|
||||
if (date.ends_with("1") && date != "11")
|
||||
date += "st";
|
||||
else if (date == "2" || date == "22")
|
||||
else if (date.ends_with("2") && date != "12")
|
||||
date += "nd";
|
||||
else if (date == "3" || date == "23")
|
||||
else if (date.ends_with("3") && date != "13")
|
||||
date += "rd";
|
||||
else
|
||||
date += "th";
|
||||
|
@ -59,84 +59,125 @@ namespace {
|
|||
|
||||
fn CreateColorCircles() -> Element {
|
||||
Elements circles;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
circles.push_back(text("◯") | bold | color(Color::Palette256(i)));
|
||||
circles.push_back(text(" "));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
circles.push_back(hbox({
|
||||
text("◯") | bold | color(Color::Palette256(i)),
|
||||
text(" "),
|
||||
}));
|
||||
|
||||
return hbox(circles);
|
||||
}
|
||||
|
||||
fn SystemInfoBox(const Config& config) -> Element {
|
||||
// Fetch data
|
||||
const std::string& name = config.general.get().name.get();
|
||||
std::string date = GetDate();
|
||||
const std::string& date = GetDate();
|
||||
const std::string& host = GetHost();
|
||||
const std::string& kernelVersion = GetKernelVersion();
|
||||
const std::string& osVersion = GetOSVersion();
|
||||
u64 memInfo = GetMemInfo();
|
||||
std::string osVersion = GetOSVersion();
|
||||
Weather weather = config.weather.get();
|
||||
bool nowPlayingEnabled = config.now_playing.get().enabled;
|
||||
std::string nowPlaying = nowPlayingEnabled ? GetNowPlaying() : "";
|
||||
const std::string& nowPlaying = nowPlayingEnabled ? GetNowPlaying() : "";
|
||||
|
||||
// Icon constants (using Nerd Font v3)
|
||||
constexpr const char* calendarIcon = " ";
|
||||
constexpr const char* memoryIcon = " ";
|
||||
constexpr const char* hostIcon = " ";
|
||||
constexpr const char* kernelIcon = " ";
|
||||
constexpr const char* osIcon = " ";
|
||||
constexpr const char* memoryIcon = " ";
|
||||
constexpr const char* weatherIcon = " ";
|
||||
constexpr const char* musicIcon = " ";
|
||||
const Color::Palette16 labelColor = Color::Yellow;
|
||||
const Color::Palette16 valueColor = Color::White;
|
||||
const Color::Palette16 borderColor = Color::GrayLight;
|
||||
const Color iconColor = Color::RGB(100, 200, 255); // Bright cyan
|
||||
const Color::Palette16 iconColor = Color::Cyan;
|
||||
|
||||
Elements content;
|
||||
|
||||
content.push_back(text(" Hello " + name + "! ") | bold | color(Color::Cyan));
|
||||
content.push_back(separator() | color(borderColor));
|
||||
content.push_back(hbox({
|
||||
text(" ") | color(iconColor), // Palette icon
|
||||
CreateColorCircles(),
|
||||
}));
|
||||
content.push_back(separator() | color(borderColor));
|
||||
|
||||
// Helper function for aligned rows
|
||||
auto createRow =
|
||||
[&](const std::string& emoji, const std::string& label, const std::string& value) {
|
||||
return hbox({ text(emoji),
|
||||
text(label) | color(labelColor),
|
||||
filler(),
|
||||
text(value) | color(valueColor),
|
||||
text(" ") });
|
||||
};
|
||||
auto createRow = [&](const std::string& icon, const std::string& label, const std::string& value) {
|
||||
return hbox({
|
||||
text(icon) | color(iconColor),
|
||||
text(label) | color(labelColor),
|
||||
text(" "),
|
||||
filler(),
|
||||
text(value) | color(valueColor),
|
||||
text(" "),
|
||||
});
|
||||
};
|
||||
|
||||
// System info rows
|
||||
content.push_back(createRow(calendarIcon, "Date ", date));
|
||||
content.push_back(createRow(memoryIcon, "RAM ", fmt::format("{:.2f}", BytesToGiB { memInfo })));
|
||||
content.push_back(createRow(osIcon, "OS ", osVersion));
|
||||
content.push_back(createRow(calendarIcon, "Date", date));
|
||||
|
||||
// Weather row
|
||||
if (weather.enabled) {
|
||||
auto weatherInfo = weather.getWeatherInfo();
|
||||
content.push_back(separator() | color(borderColor));
|
||||
content.push_back(hbox(
|
||||
{ text(weatherIcon),
|
||||
text("Weather ") | color(labelColor),
|
||||
WeatherOutput weatherInfo = weather.getWeatherInfo();
|
||||
|
||||
if (weather.show_town_name)
|
||||
content.push_back(hbox({
|
||||
text(weatherIcon) | color(iconColor),
|
||||
text("Weather") | color(labelColor),
|
||||
filler(),
|
||||
hbox({ text(fmt::format("{}°F ", std::lround(weatherInfo.main.temp))) | color(Color::Red),
|
||||
text("in "),
|
||||
text(weatherInfo.name),
|
||||
text(" ") }) |
|
||||
color(valueColor) }
|
||||
));
|
||||
|
||||
hbox({
|
||||
text(fmt::format("{}°F ", std::lround(weatherInfo.main.temp))),
|
||||
text("in "),
|
||||
text(weatherInfo.name),
|
||||
text(" "),
|
||||
}) |
|
||||
color(valueColor),
|
||||
}));
|
||||
else
|
||||
content.push_back(hbox({
|
||||
text(weatherIcon) | color(iconColor),
|
||||
text("Weather") | color(labelColor),
|
||||
filler(),
|
||||
|
||||
hbox({
|
||||
text(fmt::format("{}°F, {}", std::lround(weatherInfo.main.temp), weatherInfo.weather[0].description)),
|
||||
text(" "),
|
||||
}) |
|
||||
color(valueColor),
|
||||
}));
|
||||
}
|
||||
|
||||
content.push_back(separator() | color(borderColor));
|
||||
|
||||
if (!host.empty())
|
||||
content.push_back(createRow(hostIcon, "Host", host));
|
||||
|
||||
if (!kernelVersion.empty())
|
||||
content.push_back(createRow(kernelIcon, "Kernel", kernelVersion));
|
||||
|
||||
if (!osVersion.empty())
|
||||
content.push_back(createRow(osIcon, "OS", osVersion));
|
||||
|
||||
if (memInfo > 0)
|
||||
content.push_back(createRow(memoryIcon, "RAM", fmt::format("{:.2f}", BytesToGiB { memInfo })));
|
||||
|
||||
// Now Playing row
|
||||
if (nowPlayingEnabled && !nowPlaying.empty()) {
|
||||
content.push_back(separator() | color(borderColor));
|
||||
content.push_back(hbox({ text(musicIcon),
|
||||
text("Now Playing ") | color(labelColor),
|
||||
filler(),
|
||||
text(nowPlaying),
|
||||
text(" ") | color(Color::Magenta) }));
|
||||
content.push_back(hbox({
|
||||
text(musicIcon) | color(iconColor),
|
||||
text("Music") | color(labelColor),
|
||||
text(" "),
|
||||
filler(),
|
||||
text(nowPlaying.length() > 30 ? nowPlaying.substr(0, 30) + "..." : nowPlaying) | color(Color::Magenta),
|
||||
text(" "),
|
||||
}));
|
||||
}
|
||||
|
||||
// Color circles section
|
||||
content.push_back(filler());
|
||||
content.push_back(separator() | color(borderColor));
|
||||
content.push_back(hbox({ text(" ") | color(iconColor), // Palette icon
|
||||
CreateColorCircles() }));
|
||||
return vbox(content) | borderRounded | color(Color::White);
|
||||
}
|
||||
}
|
||||
|
|
101
src/os/linux.cpp
101
src/os/linux.cpp
|
@ -1,32 +1,39 @@
|
|||
#ifdef __linux__
|
||||
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fmt/format.h>
|
||||
#include <fstream>
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <vector>
|
||||
|
||||
#include "os.h"
|
||||
#include "src/util/macros.h"
|
||||
|
||||
enum SessionType : u8 { Wayland, X11, TTY, Unknown };
|
||||
|
||||
fn ParseLineAsNumber(const std::string& input) -> u64 {
|
||||
usize start = input.find_first_of("0123456789");
|
||||
|
||||
if (start == std::string::npos)
|
||||
throw std::runtime_error("No number found in input");
|
||||
if (start == std::string::npos) {
|
||||
ERROR_LOG("No number found in input");
|
||||
return 0;
|
||||
}
|
||||
|
||||
usize end = input.find_first_not_of("0123456789", start);
|
||||
|
||||
return std::stoull(input.substr(start, end - start));
|
||||
}
|
||||
|
||||
fn MeminfoParse(const std::filesystem::path& filepath) -> u64 {
|
||||
std::ifstream input(filepath);
|
||||
fn MeminfoParse() -> u64 {
|
||||
constexpr const char* path = "/proc/meminfo";
|
||||
|
||||
if (!input.is_open())
|
||||
throw std::runtime_error("Failed to open " + filepath.string());
|
||||
std::ifstream input(path);
|
||||
|
||||
if (!input.is_open()) {
|
||||
ERROR_LOG("Failed to open {}", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
|
||||
|
@ -34,16 +41,21 @@ fn MeminfoParse(const std::filesystem::path& filepath) -> u64 {
|
|||
if (line.starts_with("MemTotal"))
|
||||
return ParseLineAsNumber(line);
|
||||
|
||||
throw std::runtime_error("MemTotal line not found in " + filepath.string());
|
||||
ERROR_LOG("MemTotal line not found in {}", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn GetMemInfo() -> u64 { return MeminfoParse("/proc/meminfo") * 1024; }
|
||||
fn GetMemInfo() -> u64 { return MeminfoParse() * 1024; }
|
||||
|
||||
fn GetOSVersion() -> std::string {
|
||||
std::ifstream file("/etc/os-release");
|
||||
constexpr const char* path = "/etc/os-release";
|
||||
|
||||
if (!file.is_open())
|
||||
throw std::runtime_error("Failed to open /etc/os-release");
|
||||
std::ifstream file(path);
|
||||
|
||||
if (!file.is_open()) {
|
||||
ERROR_LOG("Failed to open {}", path);
|
||||
return "";
|
||||
}
|
||||
|
||||
string line;
|
||||
const string prefix = "PRETTY_NAME=";
|
||||
|
@ -58,7 +70,8 @@ fn GetOSVersion() -> std::string {
|
|||
return prettyName;
|
||||
}
|
||||
|
||||
throw std::runtime_error("PRETTY_NAME line not found in /etc/os-release");
|
||||
ERROR_LOG("PRETTY_NAME line not found in {}", path);
|
||||
return "";
|
||||
}
|
||||
|
||||
fn GetMprisPlayers(sdbus::IConnection& connection) -> std::vector<string> {
|
||||
|
@ -66,8 +79,7 @@ fn GetMprisPlayers(sdbus::IConnection& connection) -> std::vector<string> {
|
|||
const sdbus::ObjectPath dbusObjectPath = sdbus::ObjectPath("/org/freedesktop/DBus");
|
||||
const char* dbusMethodListNames = "ListNames";
|
||||
|
||||
const std::unique_ptr<sdbus::IProxy> dbusProxy =
|
||||
createProxy(connection, dbusInterface, dbusObjectPath);
|
||||
const std::unique_ptr<sdbus::IProxy> dbusProxy = createProxy(connection, dbusInterface, dbusObjectPath);
|
||||
|
||||
std::vector<string> names;
|
||||
|
||||
|
@ -76,8 +88,7 @@ fn GetMprisPlayers(sdbus::IConnection& connection) -> std::vector<string> {
|
|||
std::vector<string> mprisPlayers;
|
||||
|
||||
for (const std::basic_string<char>& name : names)
|
||||
if (const char* mprisInterfaceName = "org.mpris.MediaPlayer2";
|
||||
name.find(mprisInterfaceName) != std::string::npos)
|
||||
if (const char* mprisInterfaceName = "org.mpris.MediaPlayer2"; name.find(mprisInterfaceName) != std::string::npos)
|
||||
mprisPlayers.push_back(name);
|
||||
|
||||
return mprisPlayers;
|
||||
|
@ -92,30 +103,32 @@ fn GetActivePlayer(const std::vector<string>& mprisPlayers) -> string {
|
|||
|
||||
fn GetNowPlaying() -> string {
|
||||
try {
|
||||
const char *playerObjectPath = "/org/mpris/MediaPlayer2",
|
||||
*playerInterfaceName = "org.mpris.MediaPlayer2.Player";
|
||||
const char *playerObjectPath = "/org/mpris/MediaPlayer2", *playerInterfaceName = "org.mpris.MediaPlayer2.Player";
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> connection = sdbus::createSessionBusConnection();
|
||||
|
||||
std::vector<string> mprisPlayers = GetMprisPlayers(*connection);
|
||||
|
||||
if (mprisPlayers.empty())
|
||||
if (mprisPlayers.empty()) {
|
||||
DEBUG_LOG("No MPRIS players found");
|
||||
return "";
|
||||
}
|
||||
|
||||
string activePlayer = GetActivePlayer(mprisPlayers);
|
||||
|
||||
if (activePlayer.empty())
|
||||
if (activePlayer.empty()) {
|
||||
DEBUG_LOG("No active player found");
|
||||
return "";
|
||||
}
|
||||
|
||||
auto playerProxy = sdbus::createProxy(
|
||||
*connection, sdbus::ServiceName(activePlayer), sdbus::ObjectPath(playerObjectPath)
|
||||
);
|
||||
std::unique_ptr<sdbus::IProxy> playerProxy =
|
||||
sdbus::createProxy(*connection, sdbus::ServiceName(activePlayer), sdbus::ObjectPath(playerObjectPath));
|
||||
|
||||
sdbus::Variant metadataVariant =
|
||||
playerProxy->getProperty("Metadata").onInterface(playerInterfaceName);
|
||||
sdbus::Variant metadataVariant = playerProxy->getProperty("Metadata").onInterface(playerInterfaceName);
|
||||
|
||||
if (metadataVariant.containsValueOfType<std::map<std::string, sdbus::Variant>>()) {
|
||||
const auto& metadata = metadataVariant.get<std::map<std::string, sdbus::Variant>>();
|
||||
const std::map<std::basic_string<char>, sdbus::Variant>& metadata =
|
||||
metadataVariant.get<std::map<std::string, sdbus::Variant>>();
|
||||
|
||||
auto iter = metadata.find("xesam:title");
|
||||
|
||||
|
@ -123,8 +136,10 @@ fn GetNowPlaying() -> string {
|
|||
return iter->second.get<std::string>();
|
||||
}
|
||||
} catch (const sdbus::Error& e) {
|
||||
if (e.getName() != "com.github.altdesktop.playerctld.NoActivePlayer")
|
||||
return fmt::format("Error: {}", e.what());
|
||||
if (e.getName() != "com.github.altdesktop.playerctld.NoActivePlayer") {
|
||||
ERROR_LOG("Error: {}", e.what());
|
||||
return "";
|
||||
}
|
||||
|
||||
return "No active player";
|
||||
}
|
||||
|
@ -138,17 +153,33 @@ fn GetShell() -> string {
|
|||
return shell ? shell : "";
|
||||
}
|
||||
|
||||
fn GetProductFamily() -> string {
|
||||
std::ifstream file("/sys/class/dmi/id/product_family");
|
||||
fn GetHost() -> string {
|
||||
constexpr const char* path = "/sys/class/dmi/id/product_family";
|
||||
|
||||
if (!file.is_open())
|
||||
throw std::runtime_error("Failed to open /sys/class/dmi/id/product_family");
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
ERROR_LOG("Failed to open {}", path);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string productFamily;
|
||||
|
||||
std::getline(file, productFamily);
|
||||
if (!std::getline(file, productFamily)) {
|
||||
ERROR_LOG("Failed to read from {}", path);
|
||||
return "";
|
||||
}
|
||||
|
||||
return productFamily;
|
||||
}
|
||||
|
||||
fn GetKernelVersion() -> string {
|
||||
struct utsname uts;
|
||||
|
||||
if (uname(&uts) == -1) {
|
||||
ERROR_LOG("uname() failed: {}", std::strerror(errno));
|
||||
return "";
|
||||
}
|
||||
|
||||
return static_cast<const char*>(uts.release);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,4 +36,9 @@ fn GetShell() -> string;
|
|||
/**
|
||||
* @brief Get the product family
|
||||
*/
|
||||
fn GetProductFamily() -> string;
|
||||
fn GetHost() -> string;
|
||||
|
||||
/**
|
||||
* @brief Get the kernel version.
|
||||
*/
|
||||
fn GetKernelVersion() -> string;
|
||||
|
|
Loading…
Reference in a new issue