Formatting
This commit is contained in:
parent
d74a4fab77
commit
6e716296ff
@ -15,327 +15,332 @@
|
||||
POLYBAR_NS
|
||||
|
||||
namespace cairo {
|
||||
/**
|
||||
* @brief Global pointer to the Freetype library handler
|
||||
*/
|
||||
static FT_Library g_ftlib;
|
||||
/**
|
||||
* @brief Global pointer to the Freetype library handler
|
||||
*/
|
||||
static FT_Library g_ftlib;
|
||||
|
||||
/**
|
||||
* @brief Abstract font face
|
||||
*/
|
||||
class font {
|
||||
public:
|
||||
explicit font(cairo_t* cairo, double offset) : m_cairo(cairo), m_offset(offset) {}
|
||||
virtual ~font(){};
|
||||
|
||||
virtual string name() const = 0;
|
||||
virtual string file() const = 0;
|
||||
virtual double offset() const = 0;
|
||||
virtual double size(double dpi) const = 0;
|
||||
|
||||
virtual cairo_font_extents_t extents() = 0;
|
||||
|
||||
virtual void use() {
|
||||
cairo_set_font_face(m_cairo, cairo_font_face_reference(m_font_face));
|
||||
}
|
||||
|
||||
virtual size_t match(utils::unicode_character& character) = 0;
|
||||
virtual size_t match(utils::unicode_charlist& charlist) = 0;
|
||||
virtual size_t render(const string& text, double x = 0.0, double y = 0.0) = 0;
|
||||
virtual void textwidth(const string& text, cairo_text_extents_t* extents) = 0;
|
||||
|
||||
protected:
|
||||
cairo_t* m_cairo;
|
||||
cairo_font_face_t* m_font_face{nullptr};
|
||||
cairo_font_extents_t m_extents{};
|
||||
double m_offset{0.0};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Font based on fontconfig/freetype
|
||||
*/
|
||||
class font_fc : public font {
|
||||
public:
|
||||
explicit font_fc(cairo_t* cairo, FcPattern* pattern, double offset, double dpi_x, double dpi_y)
|
||||
: font(cairo, offset), m_pattern(pattern) {
|
||||
cairo_matrix_t fm;
|
||||
cairo_matrix_t ctm;
|
||||
cairo_matrix_init_scale(&fm, size(dpi_x), size(dpi_y));
|
||||
cairo_get_matrix(m_cairo, &ctm);
|
||||
|
||||
auto fontface = cairo_ft_font_face_create_for_pattern(m_pattern);
|
||||
auto opts = cairo_font_options_create();
|
||||
m_scaled = cairo_scaled_font_create(fontface, &fm, &ctm, opts);
|
||||
cairo_font_options_destroy(opts);
|
||||
cairo_font_face_destroy(fontface);
|
||||
|
||||
auto status = cairo_scaled_font_status(m_scaled);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
throw application_error(sstream() << "cairo_scaled_font_create(): " << cairo_status_to_string(status));
|
||||
}
|
||||
|
||||
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
|
||||
auto face = static_cast<FT_Face>(*lock);
|
||||
|
||||
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) == FT_Err_Ok) {
|
||||
return;
|
||||
} else if (FT_Select_Charmap(face, FT_ENCODING_BIG5) == FT_Err_Ok) {
|
||||
return;
|
||||
} else if (FT_Select_Charmap(face, FT_ENCODING_SJIS) == FT_Err_Ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock.reset();
|
||||
}
|
||||
|
||||
~font_fc() override {
|
||||
if (m_scaled != nullptr) {
|
||||
cairo_scaled_font_destroy(m_scaled);
|
||||
}
|
||||
if (m_pattern != nullptr) {
|
||||
FcPatternDestroy(m_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_font_extents_t extents() override {
|
||||
cairo_scaled_font_extents(m_scaled, &m_extents);
|
||||
return m_extents;
|
||||
}
|
||||
|
||||
string name() const override {
|
||||
return property("family");
|
||||
}
|
||||
|
||||
string file() const override {
|
||||
return property("file");
|
||||
}
|
||||
|
||||
double offset() const override {
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Abstract font face
|
||||
* Calculates the font size in pixels for the given dpi
|
||||
*
|
||||
* We use the two font properties size and pixelsize. size is in points and
|
||||
* needs to be scaled with the given dpi. pixelsize is not scaled.
|
||||
*
|
||||
* If both size properties are 0, we fall back to a default value of 10
|
||||
* points for scalable fonts or 10 pixel for non-scalable ones. This should
|
||||
* only happen if both properties are purposefully set to 0
|
||||
*
|
||||
* For scalable fonts we try to use the size property scaled according to
|
||||
* the dpi.
|
||||
* For non-scalable fonts we try to use the pixelsize property as-is
|
||||
*/
|
||||
class font {
|
||||
public:
|
||||
explicit font(cairo_t* cairo, double offset) : m_cairo(cairo), m_offset(offset) {}
|
||||
virtual ~font(){};
|
||||
double size(double dpi) const override {
|
||||
bool scalable;
|
||||
double fc_pixelsize = 0, fc_size = 0;
|
||||
|
||||
virtual string name() const = 0;
|
||||
virtual string file() const = 0;
|
||||
virtual double offset() const = 0;
|
||||
virtual double size(double dpi) const = 0;
|
||||
property(FC_SCALABLE, &scalable);
|
||||
|
||||
virtual cairo_font_extents_t extents() = 0;
|
||||
// Size in points
|
||||
property(FC_SIZE, &fc_size);
|
||||
|
||||
virtual void use() {
|
||||
cairo_set_font_face(m_cairo, cairo_font_face_reference(m_font_face));
|
||||
}
|
||||
// Size in pixels
|
||||
property(FC_PIXEL_SIZE, &fc_pixelsize);
|
||||
|
||||
virtual size_t match(utils::unicode_character& character) = 0;
|
||||
virtual size_t match(utils::unicode_charlist& charlist) = 0;
|
||||
virtual size_t render(const string& text, double x = 0.0, double y = 0.0) = 0;
|
||||
virtual void textwidth(const string& text, cairo_text_extents_t* extents) = 0;
|
||||
// Fall back to a default value if the size is 0
|
||||
double pixelsize = fc_pixelsize == 0 ? 10 : fc_pixelsize;
|
||||
double size = fc_size == 0 ? 10 : fc_size;
|
||||
|
||||
protected:
|
||||
cairo_t* m_cairo;
|
||||
cairo_font_face_t* m_font_face{nullptr};
|
||||
cairo_font_extents_t m_extents{};
|
||||
double m_offset{0.0};
|
||||
};
|
||||
// Font size in pixels if we use the pixelsize property
|
||||
int px_pixelsize = pixelsize + 0.5;
|
||||
|
||||
/**
|
||||
* @brief Font based on fontconfig/freetype
|
||||
*/
|
||||
class font_fc : public font {
|
||||
public:
|
||||
explicit font_fc(cairo_t* cairo, FcPattern* pattern, double offset, double dpi_x, double dpi_y)
|
||||
: font(cairo, offset), m_pattern(pattern) {
|
||||
cairo_matrix_t fm;
|
||||
cairo_matrix_t ctm;
|
||||
cairo_matrix_init_scale(&fm, size(dpi_x), size(dpi_y));
|
||||
cairo_get_matrix(m_cairo, &ctm);
|
||||
|
||||
auto fontface = cairo_ft_font_face_create_for_pattern(m_pattern);
|
||||
auto opts = cairo_font_options_create();
|
||||
m_scaled = cairo_scaled_font_create(fontface, &fm, &ctm, opts);
|
||||
cairo_font_options_destroy(opts);
|
||||
cairo_font_face_destroy(fontface);
|
||||
|
||||
auto status = cairo_scaled_font_status(m_scaled);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
throw application_error(sstream() << "cairo_scaled_font_create(): " << cairo_status_to_string(status));
|
||||
}
|
||||
|
||||
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
|
||||
auto face = static_cast<FT_Face>(*lock);
|
||||
|
||||
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) == FT_Err_Ok) {
|
||||
return;
|
||||
} else if (FT_Select_Charmap(face, FT_ENCODING_BIG5) == FT_Err_Ok) {
|
||||
return;
|
||||
} else if (FT_Select_Charmap(face, FT_ENCODING_SJIS) == FT_Err_Ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock.reset();
|
||||
}
|
||||
|
||||
~font_fc() override {
|
||||
if (m_scaled != nullptr) {
|
||||
cairo_scaled_font_destroy(m_scaled);
|
||||
}
|
||||
if (m_pattern != nullptr) {
|
||||
FcPatternDestroy(m_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_font_extents_t extents() override {
|
||||
cairo_scaled_font_extents(m_scaled, &m_extents);
|
||||
return m_extents;
|
||||
}
|
||||
|
||||
string name() const override {
|
||||
return property("family");
|
||||
}
|
||||
|
||||
string file() const override {
|
||||
return property("file");
|
||||
}
|
||||
|
||||
double offset() const override {
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the font size in pixels for the given dpi
|
||||
*
|
||||
* We use the two font properties size and pixelsize. size is in points and
|
||||
* needs to be scaled with the given dpi. pixelsize is not scaled.
|
||||
*
|
||||
* If both size properties are 0, we fall back to a default value of 10
|
||||
* points for scalable fonts or 10 pixel for non-scalable ones. This should
|
||||
* only happen if both properties are purposefully set to 0
|
||||
*
|
||||
* For scalable fonts we try to use the size property scaled according to
|
||||
* the dpi.
|
||||
* For non-scalable fonts we try to use the pixelsize property as-is
|
||||
/*
|
||||
* Font size in pixels if we use the size property. Since the size
|
||||
* specifies the font size in points, this is converted to pixels
|
||||
* according to the dpi given.
|
||||
* One point is 1/72 inches, thus this gives us the number of 'dots'
|
||||
* (or pixels) for this font
|
||||
*/
|
||||
double size(double dpi) const override {
|
||||
bool scalable;
|
||||
double fc_pixelsize = 0, fc_size = 0;
|
||||
int px_size = size / 72.0 * dpi + 0.5;
|
||||
|
||||
property(FC_SCALABLE, &scalable);
|
||||
|
||||
// Size in points
|
||||
property(FC_SIZE, &fc_size);
|
||||
|
||||
// Size in pixels
|
||||
property(FC_PIXEL_SIZE, &fc_pixelsize);
|
||||
|
||||
// Fall back to a default value if the size is 0
|
||||
double pixelsize = fc_pixelsize == 0 ? 10 : fc_pixelsize;
|
||||
double size = fc_size == 0 ? 10 : fc_size;
|
||||
|
||||
// Font size in pixels if we use the pixelsize property
|
||||
int px_pixelsize = pixelsize + 0.5;
|
||||
if (fc_size == 0 && fc_pixelsize == 0) {
|
||||
return scalable ? px_size : px_pixelsize;
|
||||
}
|
||||
|
||||
if (scalable) {
|
||||
/*
|
||||
* Font size in pixels if we use the size property. Since the size
|
||||
* specifies the font size in points, this is converted to pixels
|
||||
* according to the dpi given.
|
||||
* One point is 1/72 inches, thus this gives us the number of 'dots'
|
||||
* (or pixels) for this font
|
||||
* Use the point size if it's not 0. The pixelsize is only used if the
|
||||
* size property is 0 and pixelsize is not
|
||||
*/
|
||||
int px_size = size / 72.0 * dpi + 0.5;
|
||||
|
||||
if (fc_size == 0 && fc_pixelsize == 0) {
|
||||
return scalable ? px_size : px_pixelsize;
|
||||
}
|
||||
|
||||
if (scalable) {
|
||||
/*
|
||||
* Use the point size if it's not 0. The pixelsize is only used if the
|
||||
* size property is 0 and pixelsize is not
|
||||
*/
|
||||
if (fc_size != 0) {
|
||||
return px_size;
|
||||
} else {
|
||||
return px_pixelsize;
|
||||
}
|
||||
if (fc_size != 0) {
|
||||
return px_size;
|
||||
} else {
|
||||
/*
|
||||
* Non-scalable fonts do it the other way around, here the size
|
||||
* property is only used if pixelsize is 0 and size is not
|
||||
*/
|
||||
if (fc_pixelsize != 0) {
|
||||
return px_pixelsize;
|
||||
} else {
|
||||
return px_size;
|
||||
}
|
||||
return px_pixelsize;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Non-scalable fonts do it the other way around, here the size
|
||||
* property is only used if pixelsize is 0 and size is not
|
||||
*/
|
||||
if (fc_pixelsize != 0) {
|
||||
return px_pixelsize;
|
||||
} else {
|
||||
return px_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void use() override {
|
||||
cairo_set_scaled_font(m_cairo, m_scaled);
|
||||
}
|
||||
|
||||
size_t match(utils::unicode_character& character) override {
|
||||
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
|
||||
auto face = static_cast<FT_Face>(*lock);
|
||||
return FT_Get_Char_Index(face, character.codepoint) ? 1 : 0;
|
||||
}
|
||||
|
||||
size_t match(utils::unicode_charlist& charlist) override {
|
||||
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
|
||||
auto face = static_cast<FT_Face>(*lock);
|
||||
size_t available_chars = 0;
|
||||
for (auto&& c : charlist) {
|
||||
if (FT_Get_Char_Index(face, c.codepoint)) {
|
||||
available_chars++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void use() override {
|
||||
cairo_set_scaled_font(m_cairo, m_scaled);
|
||||
}
|
||||
return available_chars;
|
||||
}
|
||||
|
||||
size_t match(utils::unicode_character& character) override {
|
||||
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
|
||||
auto face = static_cast<FT_Face>(*lock);
|
||||
return FT_Get_Char_Index(face, character.codepoint) ? 1 : 0;
|
||||
}
|
||||
size_t render(const string& text, double x = 0.0, double y = 0.0) override {
|
||||
cairo_glyph_t* glyphs{nullptr};
|
||||
cairo_text_cluster_t* clusters{nullptr};
|
||||
cairo_text_cluster_flags_t cf{};
|
||||
int nglyphs = 0;
|
||||
int nclusters = 0;
|
||||
|
||||
size_t match(utils::unicode_charlist& charlist) override {
|
||||
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
|
||||
auto face = static_cast<FT_Face>(*lock);
|
||||
size_t available_chars = 0;
|
||||
for (auto&& c : charlist) {
|
||||
if (FT_Get_Char_Index(face, c.codepoint)) {
|
||||
available_chars++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
string utf8 = string(text);
|
||||
auto status = cairo_scaled_font_text_to_glyphs(
|
||||
m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf);
|
||||
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
logger::make().notice("ERROR %d", status);
|
||||
for (char& c : utf8) {
|
||||
logger::make().notice("0x%02x", c);
|
||||
}
|
||||
|
||||
return available_chars;
|
||||
throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs() " << cairo_status_to_string(status));
|
||||
}
|
||||
|
||||
size_t render(const string& text, double x = 0.0, double y = 0.0) override {
|
||||
cairo_glyph_t* glyphs{nullptr};
|
||||
cairo_text_cluster_t* clusters{nullptr};
|
||||
cairo_text_cluster_flags_t cf{};
|
||||
int nglyphs = 0, nclusters = 0;
|
||||
size_t bytes = 0;
|
||||
for (int g = 0; g < nglyphs; g++) {
|
||||
if (glyphs[g].index) {
|
||||
bytes += clusters[g].num_bytes;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string utf8 = string(text);
|
||||
if (bytes && bytes < text.size()) {
|
||||
cairo_glyph_free(glyphs);
|
||||
cairo_text_cluster_free(clusters);
|
||||
|
||||
utf8 = text.substr(0, bytes);
|
||||
auto status = cairo_scaled_font_text_to_glyphs(
|
||||
m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf);
|
||||
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs()" << cairo_status_to_string(status));
|
||||
}
|
||||
|
||||
size_t bytes = 0;
|
||||
for (int g = 0; g < nglyphs; g++) {
|
||||
if (glyphs[g].index) {
|
||||
bytes += clusters[g].num_bytes;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes && bytes < text.size()) {
|
||||
cairo_glyph_free(glyphs);
|
||||
cairo_text_cluster_free(clusters);
|
||||
|
||||
utf8 = text.substr(0, bytes);
|
||||
auto status = cairo_scaled_font_text_to_glyphs(
|
||||
m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf);
|
||||
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs()" << cairo_status_to_string(status));
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes) {
|
||||
// auto lock = make_unique<utils::device_lock>(cairo_surface_get_device(cairo_get_target(m_cairo)));
|
||||
// if (lock.get()) {
|
||||
// cairo_glyph_path(m_cairo, glyphs, nglyphs);
|
||||
// }
|
||||
|
||||
cairo_text_extents_t extents{};
|
||||
cairo_scaled_font_glyph_extents(m_scaled, glyphs, nglyphs, &extents);
|
||||
cairo_show_text_glyphs(m_cairo, utf8.c_str(), utf8.size(), glyphs, nglyphs, clusters, nclusters, cf);
|
||||
cairo_fill(m_cairo);
|
||||
cairo_move_to(m_cairo, x + extents.x_advance, 0.0);
|
||||
}
|
||||
|
||||
cairo_glyph_free(glyphs);
|
||||
cairo_text_cluster_free(clusters);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void textwidth(const string& text, cairo_text_extents_t* extents) override {
|
||||
cairo_scaled_font_text_extents(m_scaled, text.c_str(), extents);
|
||||
}
|
||||
|
||||
protected:
|
||||
string property(string&& property) const {
|
||||
FcChar8* file;
|
||||
if (FcPatternGetString(m_pattern, property.c_str(), 0, &file) == FcResultMatch) {
|
||||
return string(reinterpret_cast<char*>(file));
|
||||
} else {
|
||||
return "";
|
||||
throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs() " << cairo_status_to_string(status));
|
||||
}
|
||||
}
|
||||
|
||||
void property(string&& property, bool* dst) const {
|
||||
FcBool b;
|
||||
FcPatternGetBool(m_pattern, property.c_str(), 0, &b);
|
||||
*dst = b;
|
||||
if (bytes) {
|
||||
// auto lock = make_unique<utils::device_lock>(cairo_surface_get_device(cairo_get_target(m_cairo)));
|
||||
// if (lock.get()) {
|
||||
// cairo_glyph_path(m_cairo, glyphs, nglyphs);
|
||||
// }
|
||||
|
||||
cairo_text_extents_t extents{};
|
||||
cairo_scaled_font_glyph_extents(m_scaled, glyphs, nglyphs, &extents);
|
||||
cairo_show_text_glyphs(m_cairo, utf8.c_str(), utf8.size(), glyphs, nglyphs, clusters, nclusters, cf);
|
||||
cairo_fill(m_cairo);
|
||||
cairo_move_to(m_cairo, x + extents.x_advance, 0.0);
|
||||
}
|
||||
|
||||
void property(string&& property, double* dst) const {
|
||||
FcPatternGetDouble(m_pattern, property.c_str(), 0, dst);
|
||||
cairo_glyph_free(glyphs);
|
||||
cairo_text_cluster_free(clusters);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void textwidth(const string& text, cairo_text_extents_t* extents) override {
|
||||
cairo_scaled_font_text_extents(m_scaled, text.c_str(), extents);
|
||||
}
|
||||
|
||||
protected:
|
||||
string property(string&& property) const {
|
||||
FcChar8* file;
|
||||
if (FcPatternGetString(m_pattern, property.c_str(), 0, &file) == FcResultMatch) {
|
||||
return string(reinterpret_cast<char*>(file));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void property(string&& property, int* dst) const {
|
||||
FcPatternGetInteger(m_pattern, property.c_str(), 0, dst);
|
||||
}
|
||||
void property(string&& property, bool* dst) const {
|
||||
FcBool b;
|
||||
FcPatternGetBool(m_pattern, property.c_str(), 0, &b);
|
||||
*dst = b;
|
||||
}
|
||||
|
||||
private:
|
||||
cairo_scaled_font_t* m_scaled{nullptr};
|
||||
FcPattern* m_pattern{nullptr};
|
||||
};
|
||||
void property(string&& property, double* dst) const {
|
||||
FcPatternGetDouble(m_pattern, property.c_str(), 0, dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match and create font from given fontconfig pattern
|
||||
*/
|
||||
inline decltype(auto) make_font(cairo_t* cairo, string&& fontname, double offset, double dpi_x, double dpi_y) {
|
||||
static bool fc_init{false};
|
||||
if (!fc_init && !(fc_init = FcInit())) {
|
||||
throw application_error("Could not load fontconfig");
|
||||
} else if (FT_Init_FreeType(&g_ftlib) != FT_Err_Ok) {
|
||||
throw application_error("Could not load FreeType");
|
||||
}
|
||||
void property(string&& property, int* dst) const {
|
||||
FcPatternGetInteger(m_pattern, property.c_str(), 0, dst);
|
||||
}
|
||||
|
||||
static scope_util::on_exit fc_cleanup([] {
|
||||
FT_Done_FreeType(g_ftlib);
|
||||
FcFini();
|
||||
});
|
||||
private:
|
||||
cairo_scaled_font_t* m_scaled{nullptr};
|
||||
FcPattern* m_pattern{nullptr};
|
||||
};
|
||||
|
||||
auto pattern = FcNameParse((FcChar8*)fontname.c_str());
|
||||
/**
|
||||
* Match and create font from given fontconfig pattern
|
||||
*/
|
||||
inline decltype(auto) make_font(cairo_t* cairo, string&& fontname, double offset, double dpi_x, double dpi_y) {
|
||||
static bool fc_init{false};
|
||||
if (!fc_init && !(fc_init = FcInit())) {
|
||||
throw application_error("Could not load fontconfig");
|
||||
} else if (FT_Init_FreeType(&g_ftlib) != FT_Err_Ok) {
|
||||
throw application_error("Could not load FreeType");
|
||||
}
|
||||
|
||||
if (!pattern) {
|
||||
logger::make().err("Could not parse font \"%s\"", fontname);
|
||||
throw application_error("Could not parse font \"" + fontname + "\"");
|
||||
}
|
||||
static scope_util::on_exit fc_cleanup([] {
|
||||
FT_Done_FreeType(g_ftlib);
|
||||
FcFini();
|
||||
});
|
||||
|
||||
FcDefaultSubstitute(pattern);
|
||||
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
|
||||
auto pattern = FcNameParse((FcChar8*)fontname.c_str());
|
||||
|
||||
FcResult result;
|
||||
FcPattern* match = FcFontMatch(nullptr, pattern, &result);
|
||||
FcPatternDestroy(pattern);
|
||||
if (!pattern) {
|
||||
logger::make().err("Could not parse font \"%s\"", fontname);
|
||||
throw application_error("Could not parse font \"" + fontname + "\"");
|
||||
}
|
||||
|
||||
if (match == nullptr) {
|
||||
throw application_error("Could not load font \"" + fontname + "\"");
|
||||
}
|
||||
FcDefaultSubstitute(pattern);
|
||||
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
|
||||
|
||||
FcResult result;
|
||||
FcPattern* match = FcFontMatch(nullptr, pattern, &result);
|
||||
FcPatternDestroy(pattern);
|
||||
|
||||
if (match == nullptr) {
|
||||
throw application_error("Could not load font \"" + fontname + "\"");
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FONTCONFIG
|
||||
FcPatternPrint(match);
|
||||
FcPatternPrint(match);
|
||||
#endif
|
||||
|
||||
return make_shared<font_fc>(cairo, match, offset, dpi_x, dpi_y);
|
||||
}
|
||||
return make_shared<font_fc>(cairo, match, offset, dpi_x, dpi_y);
|
||||
}
|
||||
} // namespace cairo
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cairo/cairo-ft.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "common.hpp"
|
||||
@ -8,63 +9,63 @@
|
||||
POLYBAR_NS
|
||||
|
||||
namespace cairo {
|
||||
namespace utils {
|
||||
/**
|
||||
* @brief RAII wrapper used acquire cairo_device_t
|
||||
*/
|
||||
class device_lock {
|
||||
public:
|
||||
explicit device_lock(cairo_device_t* device);
|
||||
~device_lock();
|
||||
operator bool() const;
|
||||
operator cairo_device_t*() const;
|
||||
namespace utils {
|
||||
/**
|
||||
* @brief RAII wrapper used acquire cairo_device_t
|
||||
*/
|
||||
class device_lock {
|
||||
public:
|
||||
explicit device_lock(cairo_device_t* device);
|
||||
~device_lock();
|
||||
operator bool() const;
|
||||
operator cairo_device_t*() const;
|
||||
|
||||
private:
|
||||
cairo_device_t* m_device{nullptr};
|
||||
};
|
||||
private:
|
||||
cairo_device_t* m_device{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief RAII wrapper used to access the underlying
|
||||
* FT_Face of a scaled font face
|
||||
*/
|
||||
class ft_face_lock {
|
||||
public:
|
||||
explicit ft_face_lock(cairo_scaled_font_t* font);
|
||||
~ft_face_lock();
|
||||
operator FT_Face() const;
|
||||
/**
|
||||
* @brief RAII wrapper used to access the underlying
|
||||
* FT_Face of a scaled font face
|
||||
*/
|
||||
class ft_face_lock {
|
||||
public:
|
||||
explicit ft_face_lock(cairo_scaled_font_t* font);
|
||||
~ft_face_lock();
|
||||
operator FT_Face() const;
|
||||
|
||||
private:
|
||||
cairo_scaled_font_t* m_font;
|
||||
FT_Face m_face;
|
||||
};
|
||||
private:
|
||||
cairo_scaled_font_t* m_font;
|
||||
FT_Face m_face;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Unicode character containing converted codepoint
|
||||
* and details on where its position in the source string
|
||||
*/
|
||||
struct unicode_character {
|
||||
explicit unicode_character();
|
||||
unsigned long codepoint;
|
||||
int offset;
|
||||
int length;
|
||||
};
|
||||
using unicode_charlist = std::list<unicode_character>;
|
||||
/**
|
||||
* @brief Unicode character containing converted codepoint
|
||||
* and details on where its position in the source string
|
||||
*/
|
||||
struct unicode_character {
|
||||
explicit unicode_character();
|
||||
unsigned long codepoint;
|
||||
int offset;
|
||||
int length;
|
||||
};
|
||||
using unicode_charlist = std::list<unicode_character>;
|
||||
|
||||
/**
|
||||
* @see <cairo/cairo.h>
|
||||
*/
|
||||
cairo_operator_t str2operator(const string& mode, cairo_operator_t fallback);
|
||||
/**
|
||||
* @see <cairo/cairo.h>
|
||||
*/
|
||||
cairo_operator_t str2operator(const string& mode, cairo_operator_t fallback);
|
||||
|
||||
/**
|
||||
* @brief Create a UCS-4 codepoint from a utf-8 encoded string
|
||||
*/
|
||||
bool utf8_to_ucs4(const unsigned char* src, unicode_charlist& result_list);
|
||||
/**
|
||||
* @brief Create a UCS-4 codepoint from a utf-8 encoded string
|
||||
*/
|
||||
bool utf8_to_ucs4(const unsigned char* src, unicode_charlist& result_list);
|
||||
|
||||
/**
|
||||
* @brief Convert a UCS-4 codepoint to a utf-8 encoded string
|
||||
*/
|
||||
size_t ucs4_to_utf8(char* utf8, unsigned int ucs);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Convert a UCS-4 codepoint to a utf-8 encoded string
|
||||
*/
|
||||
size_t ucs4_to_utf8(char* utf8, unsigned int ucs);
|
||||
} // namespace utils
|
||||
} // namespace cairo
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -34,53 +34,53 @@ class sstream {
|
||||
};
|
||||
|
||||
namespace string_util {
|
||||
/**
|
||||
* Hash type
|
||||
*/
|
||||
using hash_type = unsigned long;
|
||||
/**
|
||||
* Hash type
|
||||
*/
|
||||
using hash_type = unsigned long;
|
||||
|
||||
bool contains(const string& haystack, const string& needle);
|
||||
bool contains_ignore_case(const string& haystack, const string& needle);
|
||||
bool ends_with(const string& haystack, const string& suffix);
|
||||
string upper(const string& s);
|
||||
string lower(const string& s);
|
||||
bool compare(const string& s1, const string& s2);
|
||||
bool contains(const string& haystack, const string& needle);
|
||||
bool contains_ignore_case(const string& haystack, const string& needle);
|
||||
bool ends_with(const string& haystack, const string& suffix);
|
||||
string upper(const string& s);
|
||||
string lower(const string& s);
|
||||
bool compare(const string& s1, const string& s2);
|
||||
|
||||
string replace(const string& haystack, const string& needle, const string& replacement, size_t start = 0,
|
||||
size_t end = string::npos);
|
||||
string replace_all(const string& haystack, const string& needle, const string& replacement, size_t start = 0,
|
||||
size_t end = string::npos);
|
||||
string replace(const string& haystack, const string& needle, const string& replacement, size_t start = 0,
|
||||
size_t end = string::npos);
|
||||
string replace_all(const string& haystack, const string& needle, const string& replacement, size_t start = 0,
|
||||
size_t end = string::npos);
|
||||
|
||||
string squeeze(const string& haystack, char needle);
|
||||
string squeeze(const string& haystack, char needle);
|
||||
|
||||
string strip(const string& haystack, char needle);
|
||||
string strip_trailing_newline(const string& haystack);
|
||||
string strip(const string& haystack, char needle);
|
||||
string strip_trailing_newline(const string& haystack);
|
||||
|
||||
string ltrim(string value, function<bool(char)> pred);
|
||||
string rtrim(string value, function<bool(char)> pred);
|
||||
string trim(string value, function<bool(char)> pred);
|
||||
string ltrim(string value, function<bool(char)> pred);
|
||||
string rtrim(string value, function<bool(char)> pred);
|
||||
string trim(string value, function<bool(char)> pred);
|
||||
|
||||
string ltrim(string&& value, const char& needle = ' ');
|
||||
string rtrim(string&& value, const char& needle = ' ');
|
||||
string trim(string&& value, const char& needle = ' ');
|
||||
string ltrim(string&& value, const char& needle = ' ');
|
||||
string rtrim(string&& value, const char& needle = ' ');
|
||||
string trim(string&& value, const char& needle = ' ');
|
||||
|
||||
size_t char_len(const string& value);
|
||||
string utf8_truncate(string&& value, size_t len);
|
||||
size_t char_len(const string& value);
|
||||
string utf8_truncate(string&& value, size_t len);
|
||||
|
||||
string join(const vector<string>& strs, const string& delim);
|
||||
vector<string> split(const string& s, char delim);
|
||||
std::vector<std::string> tokenize(const string& str, char delimiters);
|
||||
string join(const vector<string>& strs, const string& delim);
|
||||
vector<string> split(const string& s, char delim);
|
||||
std::vector<std::string> tokenize(const string& str, char delimiters);
|
||||
|
||||
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth);
|
||||
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth);
|
||||
|
||||
string floating_point(double value, size_t precision, bool fixed = false, const string& locale = "");
|
||||
string filesize_mib(unsigned long long kibibytes, size_t precision = 0, const string& locale = "");
|
||||
string filesize_gib(unsigned long long kibibytes, size_t precision = 0, const string& locale = "");
|
||||
string filesize_gib_mib(
|
||||
unsigned long long kibibytes, size_t precision_mib = 0, size_t precision_gib = 0, const string& locale = "");
|
||||
string filesize(unsigned long long kbytes, size_t precision = 0, bool fixed = false, const string& locale = "");
|
||||
string floating_point(double value, size_t precision, bool fixed = false, const string& locale = "");
|
||||
string filesize_mib(unsigned long long kibibytes, size_t precision = 0, const string& locale = "");
|
||||
string filesize_gib(unsigned long long kibibytes, size_t precision = 0, const string& locale = "");
|
||||
string filesize_gib_mib(
|
||||
unsigned long long kibibytes, size_t precision_mib = 0, size_t precision_gib = 0, const string& locale = "");
|
||||
string filesize(unsigned long long kbytes, size_t precision = 0, bool fixed = false, const string& locale = "");
|
||||
|
||||
hash_type hash(const string& src);
|
||||
hash_type hash(const string& src);
|
||||
} // namespace string_util
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -1,176 +1,176 @@
|
||||
#include <map>
|
||||
|
||||
#include "cairo/utils.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
namespace cairo {
|
||||
namespace utils {
|
||||
namespace utils {
|
||||
|
||||
// implementation : device_lock {{{
|
||||
// implementation : device_lock {{{
|
||||
|
||||
device_lock::device_lock(cairo_device_t* device) {
|
||||
auto status = cairo_device_acquire(device);
|
||||
if (status == CAIRO_STATUS_SUCCESS) {
|
||||
m_device = device;
|
||||
}
|
||||
}
|
||||
device_lock::~device_lock() {
|
||||
cairo_device_release(m_device);
|
||||
}
|
||||
device_lock::operator bool() const {
|
||||
return m_device != nullptr;
|
||||
}
|
||||
device_lock::operator cairo_device_t*() const {
|
||||
return m_device;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// implementation : ft_face_lock {{{
|
||||
|
||||
ft_face_lock::ft_face_lock(cairo_scaled_font_t* font) : m_font(font) {
|
||||
m_face = cairo_ft_scaled_font_lock_face(m_font);
|
||||
}
|
||||
ft_face_lock::~ft_face_lock() {
|
||||
cairo_ft_scaled_font_unlock_face(m_font);
|
||||
}
|
||||
ft_face_lock::operator FT_Face() const {
|
||||
return m_face;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// implementation : unicode_character {{{
|
||||
|
||||
unicode_character::unicode_character() : codepoint(0), offset(0), length(0) {}
|
||||
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* @see <cairo/cairo.h>
|
||||
*/
|
||||
cairo_operator_t str2operator(const string& mode, cairo_operator_t fallback) {
|
||||
if (mode.empty()) {
|
||||
return fallback;
|
||||
}
|
||||
static std::map<string, cairo_operator_t> modes;
|
||||
if (modes.empty()) {
|
||||
modes["clear"s] = CAIRO_OPERATOR_CLEAR;
|
||||
modes["source"s] = CAIRO_OPERATOR_SOURCE;
|
||||
modes["over"s] = CAIRO_OPERATOR_OVER;
|
||||
modes["in"s] = CAIRO_OPERATOR_IN;
|
||||
modes["out"s] = CAIRO_OPERATOR_OUT;
|
||||
modes["atop"s] = CAIRO_OPERATOR_ATOP;
|
||||
modes["dest"s] = CAIRO_OPERATOR_DEST;
|
||||
modes["dest-over"s] = CAIRO_OPERATOR_DEST_OVER;
|
||||
modes["dest-in"s] = CAIRO_OPERATOR_DEST_IN;
|
||||
modes["dest-out"s] = CAIRO_OPERATOR_DEST_OUT;
|
||||
modes["dest-atop"s] = CAIRO_OPERATOR_DEST_ATOP;
|
||||
modes["xor"s] = CAIRO_OPERATOR_XOR;
|
||||
modes["add"s] = CAIRO_OPERATOR_ADD;
|
||||
modes["saturate"s] = CAIRO_OPERATOR_SATURATE;
|
||||
modes["multiply"s] = CAIRO_OPERATOR_MULTIPLY;
|
||||
modes["screen"s] = CAIRO_OPERATOR_SCREEN;
|
||||
modes["overlay"s] = CAIRO_OPERATOR_OVERLAY;
|
||||
modes["darken"s] = CAIRO_OPERATOR_DARKEN;
|
||||
modes["lighten"s] = CAIRO_OPERATOR_LIGHTEN;
|
||||
modes["color-dodge"s] = CAIRO_OPERATOR_COLOR_DODGE;
|
||||
modes["color-burn"s] = CAIRO_OPERATOR_COLOR_BURN;
|
||||
modes["hard-light"s] = CAIRO_OPERATOR_HARD_LIGHT;
|
||||
modes["soft-light"s] = CAIRO_OPERATOR_SOFT_LIGHT;
|
||||
modes["difference"s] = CAIRO_OPERATOR_DIFFERENCE;
|
||||
modes["exclusion"s] = CAIRO_OPERATOR_EXCLUSION;
|
||||
modes["hsl-hue"s] = CAIRO_OPERATOR_HSL_HUE;
|
||||
modes["hsl-saturation"s] = CAIRO_OPERATOR_HSL_SATURATION;
|
||||
modes["hsl-color"s] = CAIRO_OPERATOR_HSL_COLOR;
|
||||
modes["hsl-luminosity"s] = CAIRO_OPERATOR_HSL_LUMINOSITY;
|
||||
}
|
||||
auto it = modes.find(mode);
|
||||
return it != modes.end() ? it->second : fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a UCS-4 codepoint from a utf-8 encoded string
|
||||
*/
|
||||
bool utf8_to_ucs4(const unsigned char* src, unicode_charlist& result_list) {
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
const unsigned char* first = src;
|
||||
while (*first) {
|
||||
int len = 0;
|
||||
unsigned long result = 0;
|
||||
if ((*first >> 7) == 0) {
|
||||
len = 1;
|
||||
result = *first;
|
||||
} else if ((*first >> 5) == 6) {
|
||||
len = 2;
|
||||
result = *first & 31;
|
||||
} else if ((*first >> 4) == 14) {
|
||||
len = 3;
|
||||
result = *first & 15;
|
||||
} else if ((*first >> 3) == 30) {
|
||||
len = 4;
|
||||
result = *first & 7;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const unsigned char* next;
|
||||
for (next = first + 1; *next && ((*next >> 6) == 2) && (next - first < len); next++) {
|
||||
result = result << 6;
|
||||
result |= *next & 63;
|
||||
}
|
||||
unicode_character uc_char;
|
||||
uc_char.codepoint = result;
|
||||
uc_char.offset = first - src;
|
||||
uc_char.length = next - first;
|
||||
result_list.push_back(uc_char);
|
||||
first = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a UCS-4 codepoint to a utf-8 encoded string
|
||||
*/
|
||||
size_t ucs4_to_utf8(char* utf8, unsigned int ucs) {
|
||||
if (ucs <= 0x7f) {
|
||||
*utf8 = ucs;
|
||||
return 1;
|
||||
} else if (ucs <= 0x07ff) {
|
||||
*(utf8++) = ((ucs >> 6) & 0xff) | 0xc0;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 2;
|
||||
} else if (ucs <= 0xffff) {
|
||||
*(utf8++) = ((ucs >> 12) & 0x0f) | 0xe0;
|
||||
*(utf8++) = ((ucs >> 6) & 0x3f) | 0x80;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 3;
|
||||
} else if (ucs <= 0x1fffff) {
|
||||
*(utf8++) = ((ucs >> 18) & 0x07) | 0xf0;
|
||||
*(utf8++) = ((ucs >> 12) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 6) & 0x3f) | 0x80;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 4;
|
||||
} else if (ucs <= 0x03ffffff) {
|
||||
*(utf8++) = ((ucs >> 24) & 0x03) | 0xf8;
|
||||
*(utf8++) = ((ucs >> 18) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 12) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 6) & 0x3f) | 0x80;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 5;
|
||||
} else if (ucs <= 0x7fffffff) {
|
||||
*(utf8++) = ((ucs >> 30) & 0x01) | 0xfc;
|
||||
*(utf8++) = ((ucs >> 24) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 18) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 12) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 6) & 0x3f) | 0x80;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 6;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
device_lock::device_lock(cairo_device_t* device) {
|
||||
auto status = cairo_device_acquire(device);
|
||||
if (status == CAIRO_STATUS_SUCCESS) {
|
||||
m_device = device;
|
||||
}
|
||||
}
|
||||
}
|
||||
device_lock::~device_lock() {
|
||||
cairo_device_release(m_device);
|
||||
}
|
||||
device_lock::operator bool() const {
|
||||
return m_device != nullptr;
|
||||
}
|
||||
device_lock::operator cairo_device_t*() const {
|
||||
return m_device;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// implementation : ft_face_lock {{{
|
||||
|
||||
ft_face_lock::ft_face_lock(cairo_scaled_font_t* font) : m_font(font) {
|
||||
m_face = cairo_ft_scaled_font_lock_face(m_font);
|
||||
}
|
||||
ft_face_lock::~ft_face_lock() {
|
||||
cairo_ft_scaled_font_unlock_face(m_font);
|
||||
}
|
||||
ft_face_lock::operator FT_Face() const {
|
||||
return m_face;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// implementation : unicode_character {{{
|
||||
|
||||
unicode_character::unicode_character() : codepoint(0), offset(0), length(0) {}
|
||||
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* @see <cairo/cairo.h>
|
||||
*/
|
||||
cairo_operator_t str2operator(const string& mode, cairo_operator_t fallback) {
|
||||
if (mode.empty()) {
|
||||
return fallback;
|
||||
}
|
||||
static std::map<string, cairo_operator_t> modes;
|
||||
if (modes.empty()) {
|
||||
modes["clear"s] = CAIRO_OPERATOR_CLEAR;
|
||||
modes["source"s] = CAIRO_OPERATOR_SOURCE;
|
||||
modes["over"s] = CAIRO_OPERATOR_OVER;
|
||||
modes["in"s] = CAIRO_OPERATOR_IN;
|
||||
modes["out"s] = CAIRO_OPERATOR_OUT;
|
||||
modes["atop"s] = CAIRO_OPERATOR_ATOP;
|
||||
modes["dest"s] = CAIRO_OPERATOR_DEST;
|
||||
modes["dest-over"s] = CAIRO_OPERATOR_DEST_OVER;
|
||||
modes["dest-in"s] = CAIRO_OPERATOR_DEST_IN;
|
||||
modes["dest-out"s] = CAIRO_OPERATOR_DEST_OUT;
|
||||
modes["dest-atop"s] = CAIRO_OPERATOR_DEST_ATOP;
|
||||
modes["xor"s] = CAIRO_OPERATOR_XOR;
|
||||
modes["add"s] = CAIRO_OPERATOR_ADD;
|
||||
modes["saturate"s] = CAIRO_OPERATOR_SATURATE;
|
||||
modes["multiply"s] = CAIRO_OPERATOR_MULTIPLY;
|
||||
modes["screen"s] = CAIRO_OPERATOR_SCREEN;
|
||||
modes["overlay"s] = CAIRO_OPERATOR_OVERLAY;
|
||||
modes["darken"s] = CAIRO_OPERATOR_DARKEN;
|
||||
modes["lighten"s] = CAIRO_OPERATOR_LIGHTEN;
|
||||
modes["color-dodge"s] = CAIRO_OPERATOR_COLOR_DODGE;
|
||||
modes["color-burn"s] = CAIRO_OPERATOR_COLOR_BURN;
|
||||
modes["hard-light"s] = CAIRO_OPERATOR_HARD_LIGHT;
|
||||
modes["soft-light"s] = CAIRO_OPERATOR_SOFT_LIGHT;
|
||||
modes["difference"s] = CAIRO_OPERATOR_DIFFERENCE;
|
||||
modes["exclusion"s] = CAIRO_OPERATOR_EXCLUSION;
|
||||
modes["hsl-hue"s] = CAIRO_OPERATOR_HSL_HUE;
|
||||
modes["hsl-saturation"s] = CAIRO_OPERATOR_HSL_SATURATION;
|
||||
modes["hsl-color"s] = CAIRO_OPERATOR_HSL_COLOR;
|
||||
modes["hsl-luminosity"s] = CAIRO_OPERATOR_HSL_LUMINOSITY;
|
||||
}
|
||||
auto it = modes.find(mode);
|
||||
return it != modes.end() ? it->second : fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a UCS-4 codepoint from a utf-8 encoded string
|
||||
*/
|
||||
bool utf8_to_ucs4(const unsigned char* src, unicode_charlist& result_list) {
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
const unsigned char* first = src;
|
||||
while (*first) {
|
||||
int len = 0;
|
||||
unsigned long result = 0;
|
||||
if ((*first >> 7) == 0) {
|
||||
len = 1;
|
||||
result = *first;
|
||||
} else if ((*first >> 5) == 6) {
|
||||
len = 2;
|
||||
result = *first & 31;
|
||||
} else if ((*first >> 4) == 14) {
|
||||
len = 3;
|
||||
result = *first & 15;
|
||||
} else if ((*first >> 3) == 30) {
|
||||
len = 4;
|
||||
result = *first & 7;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const unsigned char* next;
|
||||
for (next = first + 1; *next && ((*next >> 6) == 2) && (next - first < len); next++) {
|
||||
result = result << 6;
|
||||
result |= *next & 63;
|
||||
}
|
||||
unicode_character uc_char;
|
||||
uc_char.codepoint = result;
|
||||
uc_char.offset = first - src;
|
||||
uc_char.length = next - first;
|
||||
result_list.push_back(uc_char);
|
||||
first = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a UCS-4 codepoint to a utf-8 encoded string
|
||||
*/
|
||||
size_t ucs4_to_utf8(char* utf8, unsigned int ucs) {
|
||||
if (ucs <= 0x7f) {
|
||||
*utf8 = ucs;
|
||||
return 1;
|
||||
} else if (ucs <= 0x07ff) {
|
||||
*(utf8++) = ((ucs >> 6) & 0xff) | 0xc0;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 2;
|
||||
} else if (ucs <= 0xffff) {
|
||||
*(utf8++) = ((ucs >> 12) & 0x0f) | 0xe0;
|
||||
*(utf8++) = ((ucs >> 6) & 0x3f) | 0x80;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 3;
|
||||
} else if (ucs <= 0x1fffff) {
|
||||
*(utf8++) = ((ucs >> 18) & 0x07) | 0xf0;
|
||||
*(utf8++) = ((ucs >> 12) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 6) & 0x3f) | 0x80;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 4;
|
||||
} else if (ucs <= 0x03ffffff) {
|
||||
*(utf8++) = ((ucs >> 24) & 0x03) | 0xf8;
|
||||
*(utf8++) = ((ucs >> 18) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 12) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 6) & 0x3f) | 0x80;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 5;
|
||||
} else if (ucs <= 0x7fffffff) {
|
||||
*(utf8++) = ((ucs >> 30) & 0x01) | 0xfc;
|
||||
*(utf8++) = ((ucs >> 24) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 18) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 12) & 0x3f) | 0x80;
|
||||
*(utf8++) = ((ucs >> 6) & 0x3f) | 0x80;
|
||||
*utf8 = (ucs & 0x3f) | 0x80;
|
||||
return 6;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace utils
|
||||
} // namespace cairo
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -8,337 +8,336 @@
|
||||
POLYBAR_NS
|
||||
|
||||
namespace string_util {
|
||||
/**
|
||||
* Check if haystack contains needle
|
||||
*/
|
||||
bool contains(const string& haystack, const string& needle) {
|
||||
return haystack.find(needle) != string::npos;
|
||||
/**
|
||||
* Check if haystack contains needle
|
||||
*/
|
||||
bool contains(const string& haystack, const string& needle) {
|
||||
return haystack.find(needle) != string::npos;
|
||||
}
|
||||
|
||||
bool ends_with(const string& haystack, const string& suffix) {
|
||||
if (haystack.length() < suffix.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ends_with(const string& haystack, const string& suffix) {
|
||||
if (haystack.length() < suffix.length()) {
|
||||
return false;
|
||||
return haystack.compare(haystack.length() - suffix.length(), suffix.length(), suffix) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if haystack contains needle ignoring case
|
||||
*/
|
||||
bool contains_ignore_case(const string& haystack, const string& needle) {
|
||||
return lower(haystack).find(lower(needle)) != string::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string to uppercase
|
||||
*/
|
||||
string upper(const string& s) {
|
||||
string str(s);
|
||||
for (auto& c : str) {
|
||||
c = toupper(c);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string to lowercase
|
||||
*/
|
||||
string lower(const string& s) {
|
||||
string str(s);
|
||||
for (auto& c : str) {
|
||||
c = tolower(c);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test lower case equality
|
||||
*/
|
||||
bool compare(const string& s1, const string& s2) {
|
||||
return lower(s1) == lower(s2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace first occurrence of needle in haystack
|
||||
*/
|
||||
string replace(const string& haystack, const string& needle, const string& replacement, size_t start, size_t end) {
|
||||
string str(haystack);
|
||||
string::size_type pos;
|
||||
|
||||
if (needle != replacement && (pos = str.find(needle, start)) != string::npos) {
|
||||
if (end == string::npos || pos < end) {
|
||||
str = str.replace(pos, needle.length(), replacement);
|
||||
}
|
||||
|
||||
return haystack.compare(haystack.length() - suffix.length(), suffix.length(), suffix) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if haystack contains needle ignoring case
|
||||
*/
|
||||
bool contains_ignore_case(const string& haystack, const string& needle) {
|
||||
return lower(haystack).find(lower(needle)) != string::npos;
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all occurrences of needle in haystack
|
||||
*/
|
||||
string replace_all(const string& haystack, const string& needle, const string& replacement, size_t start, size_t end) {
|
||||
string result{haystack};
|
||||
string::size_type pos;
|
||||
while ((pos = result.find(needle, start)) != string::npos && pos < result.length() &&
|
||||
(end == string::npos || pos + needle.length() <= end)) {
|
||||
result.replace(pos, needle.length(), replacement);
|
||||
start = pos + replacement.length();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all consecutive occurrences of needle in haystack
|
||||
*/
|
||||
string squeeze(const string& haystack, char needle) {
|
||||
string result = haystack;
|
||||
while (result.find({needle, needle}) != string::npos) {
|
||||
result = replace_all(result, {needle, needle}, {needle});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all occurrences of needle in haystack
|
||||
*/
|
||||
string strip(const string& haystack, char needle) {
|
||||
string str(haystack);
|
||||
string::size_type pos;
|
||||
while ((pos = str.find(needle)) != string::npos) {
|
||||
str.erase(pos, 1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove trailing newline
|
||||
*/
|
||||
string strip_trailing_newline(const string& haystack) {
|
||||
string str(haystack);
|
||||
if (str[str.length() - 1] == '\n') {
|
||||
str.erase(str.length() - 1, 1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims all characters that match pred from the left
|
||||
*/
|
||||
string ltrim(string value, function<bool(char)> pred) {
|
||||
value.erase(value.begin(), find_if(value.begin(), value.end(), std::not_fn(pred)));
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims all characters that match pred from the right
|
||||
*/
|
||||
string rtrim(string value, function<bool(char)> pred) {
|
||||
value.erase(find_if(value.rbegin(), value.rend(), std::not_fn(pred)).base(), value.end());
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims all characters that match pred from both sides
|
||||
*/
|
||||
string trim(string value, function<bool(char)> pred) {
|
||||
return ltrim(rtrim(move(value), pred), pred);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove needle from the start of the string
|
||||
*/
|
||||
string ltrim(string&& value, const char& needle) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
while (*value.begin() == needle) {
|
||||
value.erase(0, 1);
|
||||
}
|
||||
return forward<string>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove needle from the end of the string
|
||||
*/
|
||||
string rtrim(string&& value, const char& needle) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
while (*(value.end() - 1) == needle) {
|
||||
value.erase(value.length() - 1, 1);
|
||||
}
|
||||
return forward<string>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove needle from the start and end of the string
|
||||
*/
|
||||
string trim(string&& value, const char& needle) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
return rtrim(ltrim(forward<string>(value), needle), needle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of codepoints in a utf8 encoded string.
|
||||
*/
|
||||
size_t char_len(const string& value) {
|
||||
// utf-8 bytes of the form 10xxxxxx are continuation bytes, so we
|
||||
// simply count the number of bytes not of this form.
|
||||
//
|
||||
// 0xc0 = 11000000
|
||||
// 0x80 = 10000000
|
||||
return std::count_if(value.begin(), value.end(), [](char c) { return (c & 0xc0) != 0x80; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a utf8 string at len number of codepoints. This isn't 100%
|
||||
* matching the user-perceived character count, but it should be close
|
||||
* enough and avoids having to pull in something like ICU to count actual
|
||||
* grapheme clusters.
|
||||
*/
|
||||
string utf8_truncate(string&& value, size_t len) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string to uppercase
|
||||
*/
|
||||
string upper(const string& s) {
|
||||
string str(s);
|
||||
for (auto& c : str) {
|
||||
c = toupper(c);
|
||||
}
|
||||
return str;
|
||||
// utf-8 bytes of the form 10xxxxxx are continuation bytes, so we
|
||||
// simply jump forward to bytes not of that form and truncate starting
|
||||
// at that byte if we've counted too many codepoints
|
||||
//
|
||||
// 0xc0 = 11000000
|
||||
// 0x80 = 10000000
|
||||
auto it = value.begin();
|
||||
auto end = value.end();
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (it == end)
|
||||
break;
|
||||
++it;
|
||||
it = std::find_if(it, end, [](char c) { return (c & 0xc0) != 0x80; });
|
||||
}
|
||||
value.erase(it, end);
|
||||
|
||||
return forward<string>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join all strings in vector into a single string separated by delim
|
||||
*/
|
||||
string join(const vector<string>& strs, const string& delim) {
|
||||
string str;
|
||||
for (auto& s : strs) {
|
||||
str += (str.empty() ? "" : delim) + s;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode string by delim, ignore empty tokens
|
||||
*/
|
||||
vector<string> split(const string& s, char delim) {
|
||||
std::string::size_type pos = 0;
|
||||
std::vector<std::string> result;
|
||||
|
||||
while ((pos = s.find_first_not_of(delim, pos)) != std::string::npos) {
|
||||
auto nextpos = s.find_first_of(delim, pos);
|
||||
result.emplace_back(s.substr(pos, nextpos - pos));
|
||||
pos = nextpos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string to lowercase
|
||||
*/
|
||||
string lower(const string& s) {
|
||||
string str(s);
|
||||
for (auto& c : str) {
|
||||
c = tolower(c);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test lower case equality
|
||||
*/
|
||||
bool compare(const string& s1, const string& s2) {
|
||||
return lower(s1) == lower(s2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace first occurrence of needle in haystack
|
||||
*/
|
||||
string replace(const string& haystack, const string& needle, const string& replacement, size_t start, size_t end) {
|
||||
string str(haystack);
|
||||
string::size_type pos;
|
||||
|
||||
if (needle != replacement && (pos = str.find(needle, start)) != string::npos) {
|
||||
if (end == string::npos || pos < end) {
|
||||
str = str.replace(pos, needle.length(), replacement);
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all occurrences of needle in haystack
|
||||
*/
|
||||
string replace_all(
|
||||
const string& haystack, const string& needle, const string& replacement, size_t start, size_t end) {
|
||||
string result{haystack};
|
||||
string::size_type pos;
|
||||
while ((pos = result.find(needle, start)) != string::npos && pos < result.length() &&
|
||||
(end == string::npos || pos + needle.length() <= end)) {
|
||||
result.replace(pos, needle.length(), replacement);
|
||||
start = pos + replacement.length();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all consecutive occurrences of needle in haystack
|
||||
*/
|
||||
string squeeze(const string& haystack, char needle) {
|
||||
string result = haystack;
|
||||
while (result.find({needle, needle}) != string::npos) {
|
||||
result = replace_all(result, {needle, needle}, {needle});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all occurrences of needle in haystack
|
||||
*/
|
||||
string strip(const string& haystack, char needle) {
|
||||
string str(haystack);
|
||||
string::size_type pos;
|
||||
while ((pos = str.find(needle)) != string::npos) {
|
||||
str.erase(pos, 1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove trailing newline
|
||||
*/
|
||||
string strip_trailing_newline(const string& haystack) {
|
||||
string str(haystack);
|
||||
if (str[str.length() - 1] == '\n') {
|
||||
str.erase(str.length() - 1, 1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims all characters that match pred from the left
|
||||
*/
|
||||
string ltrim(string value, function<bool(char)> pred) {
|
||||
value.erase(value.begin(), find_if(value.begin(), value.end(), std::not_fn(pred)));
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims all characters that match pred from the right
|
||||
*/
|
||||
string rtrim(string value, function<bool(char)> pred) {
|
||||
value.erase(find_if(value.rbegin(), value.rend(), std::not_fn(pred)).base(), value.end());
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims all characters that match pred from both sides
|
||||
*/
|
||||
string trim(string value, function<bool(char)> pred) {
|
||||
return ltrim(rtrim(move(value), pred), pred);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove needle from the start of the string
|
||||
*/
|
||||
string ltrim(string&& value, const char& needle) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
while (*value.begin() == needle) {
|
||||
value.erase(0, 1);
|
||||
}
|
||||
return forward<string>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove needle from the end of the string
|
||||
*/
|
||||
string rtrim(string&& value, const char& needle) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
while (*(value.end() - 1) == needle) {
|
||||
value.erase(value.length() - 1, 1);
|
||||
}
|
||||
return forward<string>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove needle from the start and end of the string
|
||||
*/
|
||||
string trim(string&& value, const char& needle) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
return rtrim(ltrim(forward<string>(value), needle), needle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of codepoints in a utf8 encoded string.
|
||||
*/
|
||||
size_t char_len(const string& value) {
|
||||
// utf-8 bytes of the form 10xxxxxx are continuation bytes, so we
|
||||
// simply count the number of bytes not of this form.
|
||||
//
|
||||
// 0xc0 = 11000000
|
||||
// 0x80 = 10000000
|
||||
return std::count_if(value.begin(), value.end(), [](char c) { return (c & 0xc0) != 0x80; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a utf8 string at len number of codepoints. This isn't 100%
|
||||
* matching the user-perceived character count, but it should be close
|
||||
* enough and avoids having to pull in something like ICU to count actual
|
||||
* grapheme clusters.
|
||||
*/
|
||||
string utf8_truncate(string&& value, size_t len) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// utf-8 bytes of the form 10xxxxxx are continuation bytes, so we
|
||||
// simply jump forward to bytes not of that form and truncate starting
|
||||
// at that byte if we've counted too many codepoints
|
||||
//
|
||||
// 0xc0 = 11000000
|
||||
// 0x80 = 10000000
|
||||
auto it = value.begin();
|
||||
auto end = value.end();
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (it == end)
|
||||
break;
|
||||
++it;
|
||||
it = std::find_if(it, end, [](char c) { return (c & 0xc0) != 0x80; });
|
||||
}
|
||||
value.erase(it, end);
|
||||
|
||||
return forward<string>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join all strings in vector into a single string separated by delim
|
||||
*/
|
||||
string join(const vector<string>& strs, const string& delim) {
|
||||
string str;
|
||||
for (auto& s : strs) {
|
||||
str += (str.empty() ? "" : delim) + s;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode string by delim, ignore empty tokens
|
||||
*/
|
||||
vector<string> split(const string& s, char delim) {
|
||||
std::string::size_type pos = 0;
|
||||
std::vector<std::string> result;
|
||||
|
||||
while ((pos = s.find_first_not_of(delim, pos)) != std::string::npos) {
|
||||
auto nextpos = s.find_first_of(delim, pos);
|
||||
result.emplace_back(s.substr(pos, nextpos - pos));
|
||||
pos = nextpos;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode string by delim, include empty tokens
|
||||
*/
|
||||
std::vector<std::string> tokenize(const string& str, char delimiters) {
|
||||
std::vector<std::string> tokens;
|
||||
std::string::size_type lastPos = 0;
|
||||
auto pos = str.find_first_of(delimiters, lastPos);
|
||||
|
||||
while (pos != std::string::npos && lastPos != std::string::npos) {
|
||||
tokens.emplace_back(str.substr(lastPos, pos - lastPos));
|
||||
|
||||
lastPos = pos + 1;
|
||||
pos = str.find_first_of(delimiters, lastPos);
|
||||
}
|
||||
/**
|
||||
* Explode string by delim, include empty tokens
|
||||
*/
|
||||
std::vector<std::string> tokenize(const string& str, char delimiters) {
|
||||
std::vector<std::string> tokens;
|
||||
std::string::size_type lastPos = 0;
|
||||
auto pos = str.find_first_of(delimiters, lastPos);
|
||||
|
||||
while (pos != std::string::npos && lastPos != std::string::npos) {
|
||||
tokens.emplace_back(str.substr(lastPos, pos - lastPos));
|
||||
return tokens;
|
||||
|
||||
lastPos = pos + 1;
|
||||
pos = str.find_first_of(delimiters, lastPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the nth occurrence of needle in haystack starting from pos
|
||||
*/
|
||||
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth) {
|
||||
size_t found_pos = haystack.find(needle, pos);
|
||||
if (1 == nth || string::npos == found_pos) {
|
||||
return found_pos;
|
||||
}
|
||||
return find_nth(haystack, found_pos + 1, needle, nth - 1);
|
||||
}
|
||||
tokens.emplace_back(str.substr(lastPos, pos - lastPos));
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a floating point string
|
||||
*/
|
||||
string floating_point(double value, size_t precision, bool fixed, const string& locale) {
|
||||
std::stringstream ss;
|
||||
ss.imbue(!locale.empty() ? std::locale(locale.c_str()) : std::locale::classic());
|
||||
ss << std::fixed << std::setprecision(precision) << value;
|
||||
return fixed ? ss.str() : replace(ss.str(), ".00", "");
|
||||
/**
|
||||
* Find the nth occurrence of needle in haystack starting from pos
|
||||
*/
|
||||
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth) {
|
||||
size_t found_pos = haystack.find(needle, pos);
|
||||
if (1 == nth || string::npos == found_pos) {
|
||||
return found_pos;
|
||||
}
|
||||
return find_nth(haystack, found_pos + 1, needle, nth - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MiB filesize string
|
||||
*/
|
||||
string filesize_mib(unsigned long long kibibytes, size_t precision, const string& locale) {
|
||||
return floating_point(kibibytes / 1024.0, precision, true, locale) + " MiB";
|
||||
}
|
||||
/**
|
||||
* Create a floating point string
|
||||
*/
|
||||
string floating_point(double value, size_t precision, bool fixed, const string& locale) {
|
||||
std::stringstream ss;
|
||||
ss.imbue(!locale.empty() ? std::locale(locale.c_str()) : std::locale::classic());
|
||||
ss << std::fixed << std::setprecision(precision) << value;
|
||||
return fixed ? ss.str() : replace(ss.str(), ".00", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a GiB filesize string
|
||||
*/
|
||||
string filesize_gib(unsigned long long kibibytes, size_t precision, const string& locale) {
|
||||
return floating_point(kibibytes / 1024.0 / 1024.0, precision, true, locale) + " GiB";
|
||||
}
|
||||
/**
|
||||
* Create a MiB filesize string
|
||||
*/
|
||||
string filesize_mib(unsigned long long kibibytes, size_t precision, const string& locale) {
|
||||
return floating_point(kibibytes / 1024.0, precision, true, locale) + " MiB";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a GiB string, if the value in GiB is >= 1.0. Otherwise, create a MiB string.
|
||||
*/
|
||||
string filesize_gib_mib(
|
||||
unsigned long long kibibytes, size_t precision_mib, size_t precision_gib, const string& locale) {
|
||||
if (kibibytes < 1024 * 1024) {
|
||||
return filesize_mib(kibibytes, precision_mib, locale);
|
||||
} else {
|
||||
return filesize_gib(kibibytes, precision_gib, locale);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a GiB filesize string
|
||||
*/
|
||||
string filesize_gib(unsigned long long kibibytes, size_t precision, const string& locale) {
|
||||
return floating_point(kibibytes / 1024.0 / 1024.0, precision, true, locale) + " GiB";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a filesize string by converting given bytes to highest unit possible
|
||||
*/
|
||||
string filesize(unsigned long long bytes, size_t precision, bool fixed, const string& locale) {
|
||||
vector<string> suffixes{"TB", "GB", "MB", "KB"};
|
||||
string suffix{"B"};
|
||||
double value = bytes;
|
||||
while (!suffixes.empty() && value >= 1024.0) {
|
||||
suffix = suffixes.back();
|
||||
suffixes.pop_back();
|
||||
value /= 1024.0;
|
||||
}
|
||||
return floating_point(value, precision, fixed, locale) + " " + suffix;
|
||||
/**
|
||||
* Create a GiB string, if the value in GiB is >= 1.0. Otherwise, create a MiB string.
|
||||
*/
|
||||
string filesize_gib_mib(
|
||||
unsigned long long kibibytes, size_t precision_mib, size_t precision_gib, const string& locale) {
|
||||
if (kibibytes < 1024 * 1024) {
|
||||
return filesize_mib(kibibytes, precision_mib, locale);
|
||||
} else {
|
||||
return filesize_gib(kibibytes, precision_gib, locale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute string hash
|
||||
*/
|
||||
hash_type hash(const string& src) {
|
||||
return std::hash<string>()(src);
|
||||
/**
|
||||
* Create a filesize string by converting given bytes to highest unit possible
|
||||
*/
|
||||
string filesize(unsigned long long bytes, size_t precision, bool fixed, const string& locale) {
|
||||
vector<string> suffixes{"TB", "GB", "MB", "KB"};
|
||||
string suffix{"B"};
|
||||
double value = bytes;
|
||||
while (!suffixes.empty() && value >= 1024.0) {
|
||||
suffix = suffixes.back();
|
||||
suffixes.pop_back();
|
||||
value /= 1024.0;
|
||||
}
|
||||
} // namespace string_util
|
||||
return floating_point(value, precision, fixed, locale) + " " + suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute string hash
|
||||
*/
|
||||
hash_type hash(const string& src) {
|
||||
return std::hash<string>()(src);
|
||||
}
|
||||
} // namespace string_util
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
Loading…
Reference in New Issue
Block a user