diff --git a/cmake/build/options.cmake b/cmake/build/options.cmake index 264678dc..b57f1b19 100644 --- a/cmake/build/options.cmake +++ b/cmake/build/options.cmake @@ -72,6 +72,12 @@ option(WITH_XDAMAGE "XDAMAGE support" OFF) option(WITH_XSYNC "XSYNC support" OFF) option(WITH_XCOMPOSITE "XCOMPOSITE support" OFF) option(WITH_XKB "XKB support" ON) +option(WITH_XRM "xcb-xrm support" ON) + +if(NOT DEFINED WITH_XRM) + pkg_check_modules(XRM QUIET xcb-xrm) + set(WITH_XRM ${XRM_FOUND} CACHE BOOL "Enable xcb-xrm support") +endif() if(NOT DEFINED ENABLE_XRANDR_MONITORS) pkg_check_modules(XRANDR QUIET xrandr>=1.5.0) diff --git a/cmake/build/summary.cmake b/cmake/build/summary.cmake index ae2abe07..3e65478c 100644 --- a/cmake/build/summary.cmake +++ b/cmake/build/summary.cmake @@ -75,3 +75,5 @@ colored_option(STATUS " XSYNC support ${WITH_XSYNC}" WITH_XSYNC "32;1" "3 colored_option(STATUS " XCOMPOSITE support ${WITH_XCOMPOSITE}" WITH_XCOMPOSITE "32;1" "37;2") colored_option(STATUS " XKB support ${WITH_XKB}" WITH_XKB "32;1" "37;2") message(STATUS "--------------------------") +colored_option(STATUS " xcb-util-xrm ${WITH_XCB_UTIL_XRM}" WITH_XCB_UTIL_XRM "32;1" "37;2") +message(STATUS "--------------------------") diff --git a/contrib/polybar-git.aur/.SRCINFO b/contrib/polybar-git.aur/.SRCINFO index 4a264b60..fd3585c3 100644 --- a/contrib/polybar-git.aur/.SRCINFO +++ b/contrib/polybar-git.aur/.SRCINFO @@ -12,7 +12,7 @@ pkgbase = polybar-git makedepends = pkg-config depends = libxft depends = xcb-util-wm - depends = xcb-util-image + depends = xcb-util-xrm optdepends = alsa-lib: volume module support optdepends = libmpdclient: mpd module support optdepends = wireless_tools: network module support diff --git a/contrib/polybar-git.aur/PKGBUILD b/contrib/polybar-git.aur/PKGBUILD index 4223b5ae..203fe9c2 100644 --- a/contrib/polybar-git.aur/PKGBUILD +++ b/contrib/polybar-git.aur/PKGBUILD @@ -8,7 +8,7 @@ pkgdesc="A fast and easy-to-use status bar" arch=("i686" "x86_64") url="https://github.com/jaagr/polybar" license=("MIT") -depends=("libxft" "xcb-util-wm" "xcb-util-image") +depends=("libxft" "xcb-util-wm" "xcb-util-xrm") optdepends=("alsa-lib: volume module support" "libmpdclient: mpd module support" "wireless_tools: network module support" diff --git a/contrib/polybar.aur/.SRCINFO b/contrib/polybar.aur/.SRCINFO index 70f5df62..72009acb 100644 --- a/contrib/polybar.aur/.SRCINFO +++ b/contrib/polybar.aur/.SRCINFO @@ -12,7 +12,7 @@ pkgbase = polybar makedepends = pkg-config depends = libxft depends = xcb-util-wm - depends = xcb-util-image + depends = xcb-util-xrm optdepends = alsa-lib: volume module support optdepends = libmpdclient: mpd module support optdepends = wireless_tools: network module support diff --git a/contrib/polybar.aur/PKGBUILD b/contrib/polybar.aur/PKGBUILD index f11c4c70..507edf72 100644 --- a/contrib/polybar.aur/PKGBUILD +++ b/contrib/polybar.aur/PKGBUILD @@ -7,7 +7,7 @@ pkgdesc="A fast and easy-to-use status bar" arch=("i686" "x86_64") url="https://github.com/jaagr/polybar" license=("MIT") -depends=("libxft" "xcb-util-wm" "xcb-util-image") +depends=("libxft" "xcb-util-wm" "xcb-util-xrm") optdepends=("alsa-lib: volume module support" "libmpdclient: mpd module support" "wireless_tools: network module support" diff --git a/include/components/config.hpp b/include/components/config.hpp index 3169b17f..990d764f 100644 --- a/include/components/config.hpp +++ b/include/components/config.hpp @@ -5,10 +5,13 @@ #include "common.hpp" #include "components/logger.hpp" #include "errors.hpp" +#include "settings.hpp" #include "utils/env.hpp" #include "utils/file.hpp" #include "utils/string.hpp" +#ifdef WITH_XRM #include "x11/xresources.hpp" +#endif POLYBAR_NS @@ -23,7 +26,7 @@ class config { using make_type = const config&; static make_type make(string path = "", string bar = ""); - explicit config(const logger& logger, const xresource_manager& xrm, string&& path = "", string&& bar = ""); + explicit config(const logger& logger, string&& path = "", string&& bar = ""); string filepath() const; string section() const; @@ -209,11 +212,11 @@ class config { size_t pos; if (path.compare(0, 4, "env:") == 0) { - return dereference_env(path.substr(4), fallback); + return dereference_env(path.substr(4)); } else if (path.compare(0, 5, "xrdb:") == 0) { - return dereference_xrdb(path.substr(5), fallback); + return dereference_xrdb(path.substr(5)); } else if (path.compare(0, 5, "file:") == 0) { - return dereference_file(path.substr(5), fallback); + return dereference_file(path.substr(5)); } else if ((pos = path.find(".")) != string::npos) { return dereference_local(path.substr(0, pos), path.substr(pos + 1), section); } else { @@ -252,9 +255,9 @@ class config { * ${env:key:fallback value} */ template - T dereference_env(string var, const T&) const { + T dereference_env(string var) const { size_t pos; - string env_default{""}; + string env_default; if ((pos = var.find(":")) != string::npos) { env_default = var.substr(pos + 1); @@ -281,15 +284,37 @@ class config { * ${xrdb:key:fallback value} */ template - T dereference_xrdb(string var, const T& fallback) const { + T dereference_xrdb(string var) const { size_t pos; - +#ifndef WITH_XRM + m_log.warn("No built-in support for xrdb (requires xcb-util-xrm). Using default value for `%s`", var); if ((pos = var.find(":")) != string::npos) { - return convert(m_xrm.get_string(var.substr(0, pos), var.substr(pos + 1))); + return var.substr(pos + 1); + } + return fallback; +#else + if (!m_xrm) { + throw application_error("xrm is not initialized"); } - string str{m_xrm.get_string(var, "")}; - return str.empty() ? fallback : convert(move(str)); + string fallback; + if ((pos = var.find(":")) != string::npos) { + fallback = var.substr(pos + 1); + var.erase(pos); + } + + try { + auto value = m_xrm->require(var.c_str()); + m_log.info("Found matching X resource \"%s\" (value=%s)", var, value); + return convert(move(value)); + } catch (const xresource_error& err) { + if (!fallback.empty()) { + m_log.warn("%s, using defined fallback value \"%s\"", err.what(), fallback); + return convert(move(fallback)); + } + throw value_error(sstream() << err.what() << " (no fallback set)"); + } +#endif } /** @@ -297,11 +322,12 @@ class config { * ${file:/absolute/file/path} */ template - T dereference_file(string var, const T& fallback) const { - string filename{move(var)}; - - if (file_util::exists(filename)) { - return convert(string_util::trim(file_util::contents(filename), '\n')); + T dereference_file(string var) const { + size_t pos; + string fallback; + if ((pos = var.find(":")) != string::npos) { + fallback = var.substr(pos + 1); + var.erase(pos); } return fallback; @@ -310,10 +336,12 @@ class config { private: static constexpr const char* KEY_INHERIT{"inherit"}; const logger& m_log; - const xresource_manager& m_xrm; string m_file; string m_barname; sectionmap_t m_sections{}; +#ifdef WITH_XRM + unique_ptr m_xrm; +#endif }; POLYBAR_NS_END diff --git a/include/components/logger.hpp b/include/components/logger.hpp index c76c8342..1c83b32b 100644 --- a/include/components/logger.hpp +++ b/include/components/logger.hpp @@ -6,6 +6,7 @@ #include #include "common.hpp" +#include "settings.hpp" #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 diff --git a/include/settings.hpp.cmake b/include/settings.hpp.cmake index 51a836d6..113f7b5b 100644 --- a/include/settings.hpp.cmake +++ b/include/settings.hpp.cmake @@ -25,6 +25,7 @@ #cmakedefine01 WITH_XSYNC #cmakedefine01 WITH_XCOMPOSITE #cmakedefine01 WITH_XKB +#cmakedefine01 WITH_XRM #if WITH_XRANDR #cmakedefine01 ENABLE_XRANDR_MONITORS @@ -97,14 +98,15 @@ const auto print_build_info = [](bool extended = false) { (ENABLE_NETWORK ? '+' : '-')); if (extended) { printf("\n"); - printf("X extensions: %cxrandr (%cmonitors) %cxrender %cxdamage %cxsync %cxcomposite %cxkb\n", + printf("X extensions: %cxrandr (%cmonitors) %cxrender %cxdamage %cxsync %cxcomposite %cxkb %cxcb-util-xrm\n", (WITH_XRANDR ? '+' : '-'), (ENABLE_XRANDR_MONITORS ? '+' : '-'), (WITH_XRENDER ? '+' : '-'), (WITH_XDAMAGE ? '+' : '-'), (WITH_XSYNC ? '+' : '-'), (WITH_XCOMPOSITE ? '+' : '-'), - (WITH_XKB ? '+' : '-')); + (WITH_XKB ? '+' : '-'), + (WITH_XRM ? '+' : '-')); printf("\n"); printf("Build type: @CMAKE_BUILD_TYPE@\n"); printf("Compiler: @CMAKE_CXX_COMPILER@\n"); diff --git a/include/x11/xresources.hpp b/include/x11/xresources.hpp index 7f2f3431..b5f44d9e 100644 --- a/include/x11/xresources.hpp +++ b/include/x11/xresources.hpp @@ -1,33 +1,64 @@ #pragma once -#include -#include +#include "settings.hpp" + +#if not WITH_XRM +#error "Not built with support for xcb-xrm..." +#endif + +#include #include "common.hpp" +#include "errors.hpp" +#include "utils/string.hpp" +#include "x11/connection.hpp" POLYBAR_NS +DEFINE_ERROR(xresource_error); + class xresource_manager { public: - using make_type = const xresource_manager&; - static make_type make(); + explicit xresource_manager(xcb_connection_t* conn) : m_xrm(xcb_xrm_database_from_default(conn)) { + if (m_xrm == nullptr) { + throw application_error("xcb_xrm_database_from_default()"); + } + } - explicit xresource_manager(Display*); - ~xresource_manager(); + ~xresource_manager() { + xcb_xrm_database_free(m_xrm); + } - xresource_manager(const xresource_manager& o) = delete; - xresource_manager& operator=(const xresource_manager& o) = delete; + operator bool() const { + return m_xrm != nullptr; + } - string get_string(string name, string fallback = "") const; - float get_float(string name, float fallback = 0.0f) const; - int get_int(string name, int fallback = 0) const; + template + T require(const char* name) const { + char* result{nullptr}; + if (xcb_xrm_resource_get_string(m_xrm, string_util::replace(name, "*", ".").c_str(), "String", &result) == -1) { + throw xresource_error(sstream() << "X resource \"" << name << "\" not found"); + } else if (result == nullptr) { + throw xresource_error(sstream() << "X resource \"" << name << "\" not found"); + } + return convert(string(result)); + } + + template + T get(const char* name, const T& fallback) const { + try { + return convert(require(name)); + } catch (const xresource_error) { + return fallback; + } + } protected: - string load_value(const string& key, const string& res_type, size_t n) const; + template + T convert(string&& value) const; private: - XrmDatabase m_db; - char* m_manager{nullptr}; + xcb_xrm_database_t* m_xrm; }; POLYBAR_NS_END diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e650e28..455873a0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,11 @@ if(WITH_XKB) else() list(REMOVE_ITEM SOURCES x11/extensions/xkb.cpp modules/xkeyboard.cpp) endif() +if(WITH_XRM) + pkg_check_modules(XCB_UTIL_XRM REQUIRED xcb-xrm) + set(APP_LIBRARIES ${APP_LIBRARIES} ${XCB_UTIL_XRM_LIBRARIES}) + set(APP_INCLUDE_DIRS ${APP_INCLUDE_DIRS} ${XCB_UTIL_XRM_INCLUDE_DIRS}) +endif() string(REPLACE ";" ", " XPP_EXTENSION_LIST "${XPP_EXTENSION_LIST}") diff --git a/src/components/config.cpp b/src/components/config.cpp index ef9cb11d..99b58f64 100644 --- a/src/components/config.cpp +++ b/src/components/config.cpp @@ -8,6 +8,7 @@ #include "utils/math.hpp" #include "utils/string.hpp" #include "x11/color.hpp" +#include "x11/xresources.hpp" POLYBAR_NS @@ -15,18 +16,14 @@ POLYBAR_NS * Create instance */ config::make_type config::make(string path, string bar) { - return static_cast(*factory_util::singleton>( - logger::make(), xresource_manager::make(), move(path), move(bar))); + return *factory_util::singleton>(logger::make(), move(path), move(bar)); } /** * Construct config object */ -config::config(const logger& logger, const xresource_manager& xrm, string&& path, string&& bar) - : m_log(logger) - , m_xrm(forward(xrm)) - , m_file(forward(path)) - , m_barname(forward(bar)) { +config::config(const logger& logger, string&& path, string&& bar) + : m_log(logger), m_file(forward(path)), m_barname(forward(bar)) { if (!file_util::exists(m_file)) { throw application_error("Could not find config file: " + m_file); } @@ -126,6 +123,14 @@ void config::parse_file() { } } +#ifdef WITH_XRM + // Initialize the xresource manage if there are any xrdb refs + // present in the configuration + if (!m_xrm && value.find("${xrdb") != string::npos) { + m_xrm.reset(new xresource_manager{connection::make()}); + } +#endif + m_sections[section].emplace_hint(it, move(key), move(value)); } } diff --git a/src/x11/xresources.cpp b/src/x11/xresources.cpp index 45d04575..49d4aa2e 100644 --- a/src/x11/xresources.cpp +++ b/src/x11/xresources.cpp @@ -1,88 +1,15 @@ -#include -#include -#include - -#include "utils/factory.hpp" -#include "x11/connection.hpp" #include "x11/xresources.hpp" POLYBAR_NS -/** - * Create instance - */ -xresource_manager::make_type xresource_manager::make() { - return *factory_util::singleton(static_cast(connection::make())); +template <> +string xresource_manager::convert(string&& value) const { + return forward(value); } -/** - * Construct manager instance - */ -xresource_manager::xresource_manager(Display* dsp) { - XrmInitialize(); - - if ((m_manager = XResourceManagerString(dsp)) != nullptr) { - m_db = XrmGetStringDatabase(m_manager); - } -} - -/** - * Deconstruct instance - */ -xresource_manager::~xresource_manager() { - if (m_manager != nullptr) { - XrmDestroyDatabase(m_db); - } -} - -/** - * Get string value from the X resource db - */ -string xresource_manager::get_string(string name, string fallback) const { - auto result = load_value(move(name), "String", 64); - if (result.empty()) { - return fallback; - } - return result; -} - -/** - * Get float value from the X resource db - */ -float xresource_manager::get_float(string name, float fallback) const { - auto result = load_value(move(name), "String", 64); - if (result.empty()) { - return fallback; - } - return strtof(result.c_str(), nullptr); -} - -/** - * Get integer value from the X resource db - */ -int xresource_manager::get_int(string name, int fallback) const { - auto result = load_value(move(name), "String", 64); - if (result.empty()) { - return fallback; - } - return atoi(result.c_str()); -} - -/** - * Query the database for given key - */ -string xresource_manager::load_value(const string& key, const string& res_type, size_t n) const { - if (m_manager != nullptr) { - char* type = nullptr; - XrmValue ret{}; - - if (XrmGetResource(m_db, key.c_str(), res_type.c_str(), &type, &ret)) { - if (ret.addr != nullptr && !std::strncmp(res_type.c_str(), type, n)) { - return {ret.addr}; - } - } - } - return ""; +template <> +double xresource_manager::convert(string&& value) const { + return std::strtod(value.c_str(), nullptr); } POLYBAR_NS_END