refactor(xresources): Use xcb-util-xrm

Drop the Xlib version and handle X resource
lookups using xcb-util-xrm

Refs #356
This commit is contained in:
Michael Carlberg 2017-01-20 02:25:54 +01:00
parent 100c64a20c
commit e1483c3f65
13 changed files with 130 additions and 123 deletions

View File

@ -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)

View File

@ -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 "--------------------------")

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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<T>(path.substr(4), fallback);
return dereference_env<T>(path.substr(4));
} else if (path.compare(0, 5, "xrdb:") == 0) {
return dereference_xrdb<T>(path.substr(5), fallback);
return dereference_xrdb<T>(path.substr(5));
} else if (path.compare(0, 5, "file:") == 0) {
return dereference_file<T>(path.substr(5), fallback);
return dereference_file<T>(path.substr(5));
} else if ((pos = path.find(".")) != string::npos) {
return dereference_local<T>(path.substr(0, pos), path.substr(pos + 1), section);
} else {
@ -252,9 +255,9 @@ class config {
* ${env:key:fallback value}
*/
template <typename T>
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 <typename T>
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<T>(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<T>(move(str));
string fallback;
if ((pos = var.find(":")) != string::npos) {
fallback = var.substr(pos + 1);
var.erase(pos);
}
try {
auto value = m_xrm->require<string>(var.c_str());
m_log.info("Found matching X resource \"%s\" (value=%s)", var, value);
return convert<T>(move(value));
} catch (const xresource_error& err) {
if (!fallback.empty()) {
m_log.warn("%s, using defined fallback value \"%s\"", err.what(), fallback);
return convert<T>(move(fallback));
}
throw value_error(sstream() << err.what() << " (no fallback set)");
}
#endif
}
/**
@ -297,11 +322,12 @@ class config {
* ${file:/absolute/file/path}
*/
template <typename T>
T dereference_file(string var, const T& fallback) const {
string filename{move(var)};
if (file_util::exists(filename)) {
return convert<T>(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<xresource_manager> m_xrm;
#endif
};
POLYBAR_NS_END

View File

@ -6,6 +6,7 @@
#include <thread>
#include "common.hpp"
#include "settings.hpp"
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1

View File

@ -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");

View File

@ -1,33 +1,64 @@
#pragma once
#include <X11/X.h>
#include <X11/Xresource.h>
#include "settings.hpp"
#if not WITH_XRM
#error "Not built with support for xcb-xrm..."
#endif
#include <xcb/xcb_xrm.h>
#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 <typename T>
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<T>(string(result));
}
template <typename T>
T get(const char* name, const T& fallback) const {
try {
return convert<T>(require<T>(name));
} catch (const xresource_error) {
return fallback;
}
}
protected:
string load_value(const string& key, const string& res_type, size_t n) const;
template <typename T>
T convert(string&& value) const;
private:
XrmDatabase m_db;
char* m_manager{nullptr};
xcb_xrm_database_t* m_xrm;
};
POLYBAR_NS_END

View File

@ -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}")

View File

@ -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<config::make_type>(*factory_util::singleton<std::remove_reference_t<config::make_type>>(
logger::make(), xresource_manager::make(), move(path), move(bar)));
return *factory_util::singleton<std::remove_reference_t<config::make_type>>(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<decltype(xrm)>(xrm))
, m_file(forward<string>(path))
, m_barname(forward<string>(bar)) {
config::config(const logger& logger, string&& path, string&& bar)
: m_log(logger), m_file(forward<string>(path)), m_barname(forward<string>(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));
}
}

View File

@ -1,88 +1,15 @@
#include <X11/Xlib.h>
#include <cstring>
#include <utility>
#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<xresource_manager>(static_cast<Display*>(connection::make()));
template <>
string xresource_manager::convert(string&& value) const {
return forward<string>(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