Files
bananarchy/src/dwm-plugins/theme.h
T

637 lines
22 KiB
C++
Raw Normal View History

#ifndef DWM_PLUGINS_THEME_H
#define DWM_PLUGINS_THEME_H
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#include <pango/pango.h>
#include <pango/pangoxft.h>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#include <unordered_map>
namespace bananarchy {
inline std::string themeTrim(const std::string& s) {
size_t b = 0;
while (b < s.size() && std::isspace(static_cast<unsigned char>(s[b]))) {
++b;
}
size_t e = s.size();
while (e > b && std::isspace(static_cast<unsigned char>(s[e - 1]))) {
--e;
}
if (e >= b + 2 &&
((s[b] == '"' && s[e - 1] == '"') || (s[b] == '\'' && s[e - 1] == '\''))) {
return s.substr(b + 1, e - b - 2);
}
return s.substr(b, e - b);
}
inline int themeHexNibble(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
return -1;
}
inline bool parseHexRgb(const std::string& raw, uint32_t* outRgb) {
std::string s = themeTrim(raw);
if (s.rfind("0x", 0) == 0 || s.rfind("0X", 0) == 0) {
s = "#" + s.substr(2);
}
if (s.size() == 7 && s[0] == '#') {
uint32_t v = 0;
for (int i = 1; i < 7; ++i) {
int n = themeHexNibble(s[i]);
if (n < 0) return false;
v = (v << 4) | static_cast<uint32_t>(n);
}
*outRgb = v;
return true;
}
if (s.size() == 4 && s[0] == '#') {
int r = themeHexNibble(s[1]);
int g = themeHexNibble(s[2]);
int b = themeHexNibble(s[3]);
if (r < 0 || g < 0 || b < 0) return false;
*outRgb = static_cast<uint32_t>(((r * 17) << 16) | ((g * 17) << 8) | (b * 17));
return true;
}
return false;
}
inline std::string formatHexRgb(uint32_t rgb) {
char buf[16];
std::snprintf(buf, sizeof(buf), "#%06x", static_cast<unsigned int>(rgb & 0xffffffu));
return buf;
}
inline uint32_t adjustRgb(uint32_t rgb, int delta) {
int r = std::clamp(static_cast<int>((rgb >> 16) & 0xff) + delta, 0, 255);
int g = std::clamp(static_cast<int>((rgb >> 8) & 0xff) + delta, 0, 255);
int b = std::clamp(static_cast<int>(rgb & 0xff) + delta, 0, 255);
return static_cast<uint32_t>((r << 16) | (g << 8) | b);
}
inline uint32_t blendRgb(uint32_t c1, uint32_t c2, int weight2Pct) {
int w2 = std::clamp(weight2Pct, 0, 100);
int w1 = 100 - w2;
int r = (((c1 >> 16) & 0xff) * w1 + ((c2 >> 16) & 0xff) * w2) / 100;
int g = (((c1 >> 8) & 0xff) * w1 + ((c2 >> 8) & 0xff) * w2) / 100;
int b = ((c1 & 0xff) * w1 + (c2 & 0xff) * w2) / 100;
return static_cast<uint32_t>((std::clamp(r, 0, 255) << 16) |
(std::clamp(g, 0, 255) << 8) |
std::clamp(b, 0, 255));
}
inline std::string getHomeDirPath() {
const char* h = std::getenv("HOME");
return (h && h[0]) ? h : "/home/user";
}
inline std::string getXresourcesPath() {
return getHomeDirPath() + "/.Xresources";
}
inline std::string getThemesDirPath() {
return getHomeDirPath() + "/.xthemes";
}
struct ThemeSpec {
std::string name = "Default";
std::string fontFace = "Fira Code";
std::string iconFontFace = "DejaVuSansM Nerd Font";
int baseFontSize = 15;
// Core colors (24-bit RGB)
uint32_t bgMain = 0x222222;
uint32_t bgBar = 0x222222;
uint32_t bgHeader = 0x1c1c1c;
uint32_t bgFooter = 0x181818;
uint32_t bgOverlay = 0x161616;
uint32_t bgAltEven = 0x282828;
uint32_t bgAltOdd = 0x2e2e2e;
uint32_t bgInput = 0x1a1a1a;
uint32_t bgInputFocus = 0x1b3b4b;
uint32_t bgButton = 0x2a2a2a;
uint32_t bgSearch = 0x383838;
uint32_t bgBubbleIn = 0x262d32;
uint32_t bgBubbleOut = 0x1f2d38;
uint32_t bgToast = 0x102535;
uint32_t fgMain = 0xdddddd;
uint32_t fgBright = 0xffffff;
uint32_t fgMuted = 0x999999;
uint32_t selBg = 0x005577;
uint32_t selFg = 0xffffff;
uint32_t accent = 0xf4d03f;
uint32_t accentAlt = 0x0088bb;
uint32_t highlight = 0xffc978;
uint32_t border = 0x444444;
uint32_t divider = 0x666666;
uint32_t success = 0x2ecc71;
uint32_t info = 0x5dade2;
uint32_t warning = 0xe67e22;
uint32_t danger = 0xe74c3c;
uint32_t dangerBg = 0x922b21;
int sizeSmall() const {
return std::max(8, static_cast<int>(std::lround(baseFontSize * 12.0 / 15.0)));
}
int sizeMain() const {
return std::clamp(baseFontSize, 10, 24);
}
int sizeIcon() const {
return std::max(10, static_cast<int>(std::lround(baseFontSize * 16.0 / 15.0)));
}
int sizeLarge() const {
return std::max(11, static_cast<int>(std::lround(baseFontSize * 18.0 / 15.0)));
}
std::string pangoMainFontStr() const {
return fontFace + ", " + iconFontFace + " " + std::to_string(sizeMain()) + "px";
}
std::string pangoSmallFontStr() const {
return fontFace + ", " + iconFontFace + " " + std::to_string(sizeSmall()) + "px";
}
std::string pangoIconFontStr() const {
return iconFontFace + ", " + fontFace + " " + std::to_string(sizeIcon()) + "px";
}
std::string pangoLargeBoldFontStr() const {
return fontFace + ", " + iconFontFace + " Bold " + std::to_string(sizeLarge()) + "px";
}
std::string xftFontStr(int pxSize) const {
return fontFace + ":pixelsize=" + std::to_string(pxSize) +
":style=Regular:antialias=true:autohint=true";
}
std::string xftIconFontStr(int pxSize) const {
return iconFontFace + ":pixelsize=" + std::to_string(pxSize) +
":style=Regular:antialias=true:autohint=true";
}
void recomputeDerivedFromCore() {
int luma = (((bgMain >> 16) & 0xff) * 299 +
((bgMain >> 8) & 0xff) * 587 +
(bgMain & 0xff) * 114) / 1000;
int dir = (luma > 140) ? -1 : 1;
bgBar = bgMain;
bgHeader = adjustRgb(bgMain, -dir * 6);
bgFooter = adjustRgb(bgMain, -dir * 10);
bgOverlay = adjustRgb(bgMain, -dir * 12);
bgAltEven = adjustRgb(bgMain, dir * 6);
bgAltOdd = adjustRgb(bgMain, dir * 12);
bgInput = adjustRgb(bgMain, -dir * 8);
bgInputFocus = blendRgb(bgMain, selBg, 40);
bgButton = adjustRgb(bgMain, dir * 8);
bgSearch = adjustRgb(bgMain, dir * 22);
bgBubbleIn = blendRgb(bgMain, success, 14);
bgBubbleOut = blendRgb(bgMain, selBg, 26);
bgToast = blendRgb(bgOverlay, selBg, 35);
int fgLuma = (((fgMain >> 16) & 0xff) * 299 +
((fgMain >> 8) & 0xff) * 587 +
(fgMain & 0xff) * 114) / 1000;
fgBright = (fgLuma > 128) ? 0xffffff : 0x000000;
fgMuted = blendRgb(fgMain, bgMain, 45);
accentAlt = adjustRgb(selBg, 48);
highlight = blendRgb(accent, 0xffffff, 30);
border = adjustRgb(bgMain, dir * 34);
divider = adjustRgb(bgMain, dir * 68);
}
void parseFromMap(const std::unordered_map<std::string, std::string>& kv) {
auto getStr = [&](const char* k1, const char* k2 = nullptr,
const char* k3 = nullptr) -> std::string {
auto it = kv.find(k1);
if (it != kv.end() && !it->second.empty()) return it->second;
if (k2) {
it = kv.find(k2);
if (it != kv.end() && !it->second.empty()) return it->second;
}
if (k3) {
it = kv.find(k3);
if (it != kv.end() && !it->second.empty()) return it->second;
}
return "";
};
std::string nm = getStr("theme.name", "*themeName");
if (!nm.empty()) name = nm;
std::string ff = getStr("theme.fontFace", "*fontFace");
if (!ff.empty()) {
fontFace = ff;
} else {
std::string dwmFont = getStr("dwm.font");
if (!dwmFont.empty()) {
size_t comma = dwmFont.find(',');
if (comma != std::string::npos) {
fontFace = themeTrim(dwmFont.substr(0, comma));
}
}
}
std::string iff = getStr("theme.iconFontFace", "*iconFontFace");
if (!iff.empty()) iconFontFace = iff;
std::string bfs = getStr("theme.baseFontSize", "*baseFontSize");
if (!bfs.empty()) {
int sz = std::atoi(bfs.c_str());
if (sz >= 10 && sz <= 24) baseFontSize = sz;
} else {
std::string dwmFont = getStr("dwm.font");
size_t pxPos = dwmFont.rfind("px");
if (pxPos != std::string::npos && pxPos > 0) {
size_t sp = pxPos;
while (sp > 0 && std::isdigit(static_cast<unsigned char>(dwmFont[sp - 1]))) {
--sp;
}
if (sp < pxPos) {
int sz = std::atoi(dwmFont.substr(sp, pxPos - sp).c_str());
if (sz >= 10 && sz <= 24) baseFontSize = sz;
}
}
}
auto getCol = [&](uint32_t* dst, const char* k1, const char* k2 = nullptr,
const char* k3 = nullptr) -> bool {
std::string s = getStr(k1, k2, k3);
if (s.empty()) return false;
uint32_t v = 0;
if (parseHexRgb(s, &v)) {
*dst = v;
return true;
}
return false;
};
bool hasCoreBg = getCol(&bgMain, "theme.bgMain", "*background", "dmenu.background");
bool hasCoreFg = getCol(&fgMain, "theme.fgMain", "*foreground", "dwm.normfgcolor");
bool hasSelBg = getCol(&selBg, "theme.selBg", "dmenu.selbackground", "dwm.selbgcolor");
bool hasSelFg = getCol(&selFg, "theme.selFg", "dmenu.selforeground", "dwm.selfgcolor");
bool hasAccent = getCol(&accent, "theme.accent", "*accentColor", "st.cursorColor");
(void)hasCoreBg;
(void)hasCoreFg;
(void)hasSelBg;
(void)hasSelFg;
(void)hasAccent;
// Derive defaults from core colors first, then override with any explicit tokens
recomputeDerivedFromCore();
getCol(&bgBar, "theme.bgBar", "dwm.background", "dwm.normbgcolor");
getCol(&bgHeader, "theme.bgHeader", "dmenu.background", "st.background");
getCol(&bgFooter, "theme.bgFooter");
getCol(&bgOverlay, "theme.bgOverlay");
getCol(&bgAltEven, "theme.bgAltEven");
getCol(&bgAltOdd, "theme.bgAltOdd");
getCol(&bgInput, "theme.bgInput");
getCol(&bgInputFocus, "theme.bgInputFocus");
getCol(&bgButton, "theme.bgButton");
getCol(&bgSearch, "theme.bgSearch", "dmenu.outbackground");
getCol(&bgBubbleIn, "theme.bgBubbleIn");
getCol(&bgBubbleOut, "theme.bgBubbleOut");
getCol(&bgToast, "theme.bgToast");
getCol(&fgBright, "theme.fgBright", "dmenu.selforeground");
getCol(&fgMuted, "theme.fgMuted");
getCol(&accentAlt, "theme.accentAlt");
getCol(&highlight, "theme.highlight", "dmenu.highlight");
getCol(&border, "theme.border", "dwm.border", "dwm.normbordercolor");
getCol(&divider, "theme.divider");
getCol(&success, "theme.success");
getCol(&info, "theme.info");
getCol(&warning, "theme.warning");
getCol(&danger, "theme.danger");
getCol(&dangerBg, "theme.dangerBg");
}
static void parseLinesIntoMap(const std::string& content,
std::unordered_map<std::string, std::string>& kv) {
std::istringstream ss(content);
std::string line;
while (std::getline(ss, line)) {
std::string t = themeTrim(line);
if (t.empty() || t[0] == '!' || t[0] == '#') continue;
size_t colon = t.find(':');
if (colon == std::string::npos) continue;
std::string key = themeTrim(t.substr(0, colon));
std::string val = themeTrim(t.substr(colon + 1));
if (!key.empty() && !val.empty()) {
kv[key] = val;
}
}
}
bool loadFromFile(const std::string& path) {
std::ifstream in(path);
if (!in.is_open()) return false;
std::ostringstream ss;
ss << in.rdbuf();
std::unordered_map<std::string, std::string> kv;
parseLinesIntoMap(ss.str(), kv);
parseFromMap(kv);
return true;
}
void loadActive(Display* dpy, int screen) {
std::unordered_map<std::string, std::string> kv;
if (dpy) {
Atom actualType = None;
int actualFormat = 0;
unsigned long nitems = 0, bytesAfter = 0;
unsigned char* prop = nullptr;
if (XGetWindowProperty(dpy, RootWindow(dpy, screen), XA_RESOURCE_MANAGER,
0L, 65536L, False, XA_STRING, &actualType,
&actualFormat, &nitems, &bytesAfter,
&prop) == Success &&
prop) {
if (actualType == XA_STRING && actualFormat == 8 && nitems > 0) {
std::string resStr(reinterpret_cast<char*>(prop), nitems);
parseLinesIntoMap(resStr, kv);
}
XFree(prop);
}
}
// Also read ~/.Xresources so direct file edits always take effect
std::ifstream in(getXresourcesPath());
if (in.is_open()) {
std::ostringstream ss;
ss << in.rdbuf();
parseLinesIntoMap(ss.str(), kv);
}
if (!kv.empty()) {
parseFromMap(kv);
}
}
std::string serializeXresources() const {
std::ostringstream out;
out << "! Space to setup configversion\n";
out << "! configversion: 7bff124b2de16292fe6e7a7e5d3322ae\n";
out << "! Bananarchy Unified Theme: " << name << "\n\n";
out << "theme.name: " << name << "\n";
out << "theme.fontFace: " << fontFace << "\n";
out << "theme.iconFontFace: " << iconFontFace << "\n";
out << "theme.baseFontSize: " << sizeMain() << "\n\n";
out << "theme.bgMain: " << formatHexRgb(bgMain) << "\n";
out << "theme.bgBar: " << formatHexRgb(bgBar) << "\n";
out << "theme.bgHeader: " << formatHexRgb(bgHeader) << "\n";
out << "theme.bgFooter: " << formatHexRgb(bgFooter) << "\n";
out << "theme.bgOverlay: " << formatHexRgb(bgOverlay) << "\n";
out << "theme.bgAltEven: " << formatHexRgb(bgAltEven) << "\n";
out << "theme.bgAltOdd: " << formatHexRgb(bgAltOdd) << "\n";
out << "theme.bgInput: " << formatHexRgb(bgInput) << "\n";
out << "theme.bgInputFocus: " << formatHexRgb(bgInputFocus) << "\n";
out << "theme.bgButton: " << formatHexRgb(bgButton) << "\n";
out << "theme.bgSearch: " << formatHexRgb(bgSearch) << "\n";
out << "theme.bgBubbleIn: " << formatHexRgb(bgBubbleIn) << "\n";
out << "theme.bgBubbleOut: " << formatHexRgb(bgBubbleOut) << "\n";
out << "theme.bgToast: " << formatHexRgb(bgToast) << "\n\n";
out << "theme.fgMain: " << formatHexRgb(fgMain) << "\n";
out << "theme.fgBright: " << formatHexRgb(fgBright) << "\n";
out << "theme.fgMuted: " << formatHexRgb(fgMuted) << "\n\n";
out << "theme.selBg: " << formatHexRgb(selBg) << "\n";
out << "theme.selFg: " << formatHexRgb(selFg) << "\n";
out << "theme.accent: " << formatHexRgb(accent) << "\n";
out << "theme.accentAlt: " << formatHexRgb(accentAlt) << "\n";
out << "theme.highlight: " << formatHexRgb(highlight) << "\n";
out << "theme.border: " << formatHexRgb(border) << "\n";
out << "theme.divider: " << formatHexRgb(divider) << "\n\n";
out << "theme.success: " << formatHexRgb(success) << "\n";
out << "theme.info: " << formatHexRgb(info) << "\n";
out << "theme.warning: " << formatHexRgb(warning) << "\n";
out << "theme.danger: " << formatHexRgb(danger) << "\n";
out << "theme.dangerBg: " << formatHexRgb(dangerBg) << "\n\n";
out << "dmenu.font: " << xftFontStr(sizeLarge()) << "\n";
out << "dmenu.background: " << formatHexRgb(bgHeader) << "\n";
out << "dmenu.foreground: " << formatHexRgb(fgBright) << "\n";
out << "dmenu.selbackground: " << formatHexRgb(selBg) << "\n";
out << "dmenu.selforeground: " << formatHexRgb(selFg) << "\n";
out << "dmenu.outbackground: " << formatHexRgb(bgSearch) << "\n";
out << "dmenu.outforeground: " << formatHexRgb(fgBright) << "\n";
out << "dmenu.highlight: " << formatHexRgb(highlight) << "\n\n";
out << "dwm.font: " << pangoMainFontStr() << "\n";
out << "dwm.background: " << formatHexRgb(bgBar) << "\n";
out << "dwm.foreground: " << formatHexRgb(fgMain) << "\n";
out << "dwm.border: " << formatHexRgb(border) << "\n";
out << "dwm.selbackground: " << formatHexRgb(selBg) << "\n";
out << "dwm.selforeground: " << formatHexRgb(selFg) << "\n";
out << "dwm.selborder: " << formatHexRgb(selBg) << "\n";
out << "dwm.normbgcolor: " << formatHexRgb(bgBar) << "\n";
out << "dwm.normbordercolor: " << formatHexRgb(border) << "\n";
out << "dwm.normfgcolor: " << formatHexRgb(fgMain) << "\n";
out << "dwm.selbgcolor: " << formatHexRgb(selBg) << "\n";
out << "dwm.selbordercolor: " << formatHexRgb(selBg) << "\n";
out << "dwm.selfgcolor: " << formatHexRgb(selFg) << "\n\n";
out << "st.font: " << xftFontStr(sizeLarge()) << "\n";
out << "st.termname: xterm-256color\n";
out << "st.background: " << formatHexRgb(bgHeader) << "\n";
out << "st.foreground: " << formatHexRgb(fgMain) << "\n";
out << "st.cursorColor: " << formatHexRgb(accent) << "\n\n";
out << "svkbd.font: " << fontFace << ":pixelsize=" << sizeSmall() << "\n";
return out.str();
}
bool saveToFile(const std::string& path) const {
std::ofstream out(path, std::ios::trunc);
if (!out.is_open()) return false;
out << serializeXresources();
return true;
}
};
inline ThemeSpec loadThemeSpec(Display* dpy = nullptr, int screen = 0) {
ThemeSpec spec;
spec.loadActive(dpy, screen);
return spec;
}
struct PluginTheme {
ThemeSpec spec;
time_t lastXresMtime = -1;
off_t lastXresSize = -1;
bool colorsAllocated = false;
Display* dpy_ = nullptr;
int screen_ = 0;
Visual* visual_ = nullptr;
Colormap cmap_ = 0;
Window win_ = None;
PangoContext* pangoCtx = nullptr;
PangoLayout* layoutMain = nullptr;
PangoLayout* layoutSmall = nullptr;
PangoLayout* layoutIcon = nullptr;
PangoLayout* layoutNum = nullptr;
XftColor colWhite{};
XftColor colLight{};
XftColor colMuted{};
XftColor colYellow{};
XftColor colGreen{};
XftColor colBlue{};
XftColor colOrange{};
XftColor colRed{};
void allocXft(Display* dpy, Visual* visual, Colormap cmap, uint32_t rgb,
XftColor* dst) {
std::string hex = formatHexRgb(rgb);
XftColorAllocName(dpy, visual, cmap, hex.c_str(), dst);
}
void init(Display* dpy, int screen, Visual* visual, Colormap cmap,
Window win = None) {
dpy_ = dpy;
screen_ = screen;
visual_ = visual;
cmap_ = cmap;
win_ = win;
if (!pangoCtx && dpy) {
PangoFontMap* fontMap = pango_xft_get_font_map(dpy, screen);
pangoCtx = pango_font_map_create_context(fontMap);
layoutMain = pango_layout_new(pangoCtx);
layoutSmall = pango_layout_new(pangoCtx);
layoutIcon = pango_layout_new(pangoCtx);
layoutNum = pango_layout_new(pangoCtx);
}
reload();
}
void reload() {
if (dpy_ && visual_) {
load(dpy_, screen_, visual_, cmap_, layoutMain, layoutSmall, layoutIcon,
layoutNum, win_);
}
}
void load(Display* dpy, int screen, Visual* visual, Colormap cmap,
PangoLayout* lMain = nullptr,
PangoLayout* lSmall = nullptr,
PangoLayout* lIcon = nullptr,
PangoLayout* lNum = nullptr,
Window win = None) {
dpy_ = dpy;
screen_ = screen;
visual_ = visual;
cmap_ = cmap;
if (win != None) win_ = win;
if (lMain) layoutMain = lMain;
if (lSmall) layoutSmall = lSmall;
if (lIcon) layoutIcon = lIcon;
if (lNum) layoutNum = lNum;
struct stat st {};
if (::stat(getXresourcesPath().c_str(), &st) == 0) {
lastXresMtime = st.st_mtim.tv_sec;
lastXresSize = st.st_size;
}
spec = ThemeSpec{};
spec.loadActive(dpy, screen);
if (colorsAllocated) {
XftColorFree(dpy, visual, cmap, &colWhite);
XftColorFree(dpy, visual, cmap, &colLight);
XftColorFree(dpy, visual, cmap, &colMuted);
XftColorFree(dpy, visual, cmap, &colYellow);
XftColorFree(dpy, visual, cmap, &colGreen);
XftColorFree(dpy, visual, cmap, &colBlue);
XftColorFree(dpy, visual, cmap, &colOrange);
XftColorFree(dpy, visual, cmap, &colRed);
}
allocXft(dpy, visual, cmap, spec.fgBright, &colWhite);
allocXft(dpy, visual, cmap, spec.fgMain, &colLight);
allocXft(dpy, visual, cmap, spec.fgMuted, &colMuted);
allocXft(dpy, visual, cmap, spec.accent, &colYellow);
allocXft(dpy, visual, cmap, spec.success, &colGreen);
allocXft(dpy, visual, cmap, spec.info, &colBlue);
allocXft(dpy, visual, cmap, spec.warning, &colOrange);
allocXft(dpy, visual, cmap, spec.danger, &colRed);
colorsAllocated = true;
if (layoutMain) {
PangoFontDescription* d =
pango_font_description_from_string(spec.pangoMainFontStr().c_str());
pango_layout_set_font_description(layoutMain, d);
pango_font_description_free(d);
}
if (layoutSmall) {
PangoFontDescription* d =
pango_font_description_from_string(spec.pangoSmallFontStr().c_str());
pango_layout_set_font_description(layoutSmall, d);
pango_font_description_free(d);
}
if (layoutIcon) {
PangoFontDescription* d =
pango_font_description_from_string(spec.pangoIconFontStr().c_str());
pango_layout_set_font_description(layoutIcon, d);
pango_font_description_free(d);
}
if (layoutNum) {
PangoFontDescription* d = pango_font_description_from_string(
spec.pangoLargeBoldFontStr().c_str());
pango_layout_set_font_description(layoutNum, d);
pango_font_description_free(d);
}
if (win_ != None) {
XSetWindowBackground(dpy, win_, spec.bgMain);
XSetWindowBorder(dpy, win_, spec.selBg);
}
}
bool checkAndReload() {
if (!dpy_ || !visual_) return false;
return checkAndReload(dpy_, screen_, visual_, cmap_, layoutMain,
layoutSmall, layoutIcon, layoutNum, win_);
}
bool checkAndReload(Display* dpy, int screen, Visual* visual, Colormap cmap,
PangoLayout* lMain = nullptr,
PangoLayout* lSmall = nullptr,
PangoLayout* lIcon = nullptr,
PangoLayout* lNum = nullptr,
Window win = None) {
struct stat st {};
if (::stat(getXresourcesPath().c_str(), &st) == 0) {
if (st.st_mtim.tv_sec != lastXresMtime || st.st_size != lastXresSize) {
load(dpy, screen, visual, cmap, lMain, lSmall, lIcon, lNum, win);
return true;
}
}
return false;
}
};
} // namespace bananarchy
#endif // DWM_PLUGINS_THEME_H