Move trivial formatting state into tags::context

The variables storing the current colors, attribute activations and font
were only used in a single place and can easily also be read from the
context.

This allows us to remove a lot of the state of the renderer.
This commit is contained in:
patrick96 2021-01-06 16:53:52 +01:00 committed by Patrick Ziegler
parent 5d518e171e
commit 0a474bb2f2
10 changed files with 251 additions and 222 deletions

View file

@ -32,13 +32,9 @@ struct alignment_block {
double y;
};
class renderer
: public renderer_interface,
public signal_receiver<SIGN_PRIORITY_RENDERER, signals::ui::request_snapshot, signals::parser::change_background,
signals::parser::change_foreground, signals::parser::change_underline, signals::parser::change_overline,
signals::parser::change_font, signals::parser::change_alignment, signals::parser::reverse_colors,
signals::parser::attribute_set, signals::parser::attribute_unset, signals::parser::attribute_toggle,
signals::parser::action_begin, signals::parser::action_end, signals::parser::text, signals::parser::control> {
class renderer : public renderer_interface,
public signal_receiver<SIGN_PRIORITY_RENDERER, signals::ui::request_snapshot,
signals::parser::change_alignment, signals::parser::action_begin, signals::parser::action_end> {
public:
using make_type = unique_ptr<renderer>;
static make_type make(const bar_settings& bar);
@ -58,12 +54,12 @@ class renderer
void reserve_space(edge side, unsigned int w);
#endif
void fill_background();
void fill_overline(double x, double w);
void fill_underline(double x, double w);
void fill_overline(rgba color, double x, double w);
void fill_underline(rgba color, double x, double w);
void fill_borders();
void draw_text(const string& contents);
void render_offset(const tags::context& ctxt, int pixels) override;
void render_text(const tags::context& ctxt, const string&&) override;
protected:
double block_x(alignment a) const;
@ -75,20 +71,9 @@ class renderer
void highlight_clickable_areas();
bool on(const signals::ui::request_snapshot& evt) override;
bool on(const signals::parser::change_background& evt) override;
bool on(const signals::parser::change_foreground& evt) override;
bool on(const signals::parser::change_underline& evt) override;
bool on(const signals::parser::change_overline& evt) override;
bool on(const signals::parser::change_font& evt) override;
bool on(const signals::parser::change_alignment& evt) override;
bool on(const signals::parser::reverse_colors&) override;
bool on(const signals::parser::attribute_set& evt) override;
bool on(const signals::parser::attribute_unset& evt) override;
bool on(const signals::parser::attribute_toggle& evt) override;
bool on(const signals::parser::action_begin& evt) override;
bool on(const signals::parser::action_end& evt) override;
bool on(const signals::parser::text& evt) override;
bool on(const signals::parser::control& evt) override;
protected:
struct reserve_area {
@ -129,12 +114,6 @@ class renderer
bool m_pseudo_transparency{false};
alignment m_align;
std::bitset<3> m_attr;
int m_font{0};
rgba m_bg{};
rgba m_fg{};
rgba m_ol{};
rgba m_ul{};
vector<action_block> m_actions;
bool m_fixedcenter;

View file

@ -6,6 +6,7 @@ POLYBAR_NS
class renderer_interface {
public:
virtual void render_offset(const tags::context& ctxt, int pixels) = 0;
virtual void render_text(const tags::context& ctxt, const string&& str) = 0;
};
POLYBAR_NS_END

View file

@ -132,48 +132,15 @@ namespace signals {
} // namespace ui_tray
namespace parser {
struct change_background : public detail::value_signal<change_background, rgba> {
using base_type::base_type;
};
struct change_foreground : public detail::value_signal<change_foreground, rgba> {
using base_type::base_type;
};
struct change_underline : public detail::value_signal<change_underline, rgba> {
using base_type::base_type;
};
struct change_overline : public detail::value_signal<change_overline, rgba> {
using base_type::base_type;
};
struct change_font : public detail::value_signal<change_font, int> {
using base_type::base_type;
};
struct change_alignment : public detail::value_signal<change_alignment, alignment> {
using base_type::base_type;
};
struct reverse_colors : public detail::base_signal<reverse_colors> {
using base_type::base_type;
};
struct attribute_set : public detail::value_signal<attribute_set, tags::attribute> {
using base_type::base_type;
};
struct attribute_unset : public detail::value_signal<attribute_unset, tags::attribute> {
using base_type::base_type;
};
struct attribute_toggle : public detail::value_signal<attribute_toggle, tags::attribute> {
using base_type::base_type;
};
struct action_begin : public detail::value_signal<action_begin, action> {
using base_type::base_type;
};
struct action_end : public detail::value_signal<action_end, mousebtn> {
using base_type::base_type;
};
struct text : public detail::value_signal<text, string> {
using base_type::base_type;
};
struct control : public detail::value_signal<control, tags::controltag> {
using base_type::base_type;
};
} // namespace parser
} // namespace signals

View file

@ -45,20 +45,9 @@ namespace signals {
struct mapped_clients;
}
namespace parser {
struct change_background;
struct change_foreground;
struct change_underline;
struct change_overline;
struct change_font;
struct change_alignment;
struct reverse_colors;
struct attribute_set;
struct attribute_unset;
struct attribute_toggle;
struct action_begin;
struct action_end;
struct text;
struct control;
} // namespace parser
} // namespace signals

View file

@ -1,11 +1,87 @@
#pragma once
#include "common.hpp"
#include "components/types.hpp"
#include "tags/types.hpp"
#include "utils/color.hpp"
POLYBAR_NS
namespace tags {
class context {};
/**
* Stores all the formatting data which comes from formatting tags needed to
* render a formatting string.
*/
class context {
public:
context() = delete;
context(const bar_settings& settings);
/**
* Resets to the initial state.
*
* The initial state depends on the colors set on the bar itself.
*/
void reset();
void apply_bg(color_value c);
void apply_fg(color_value c);
void apply_ol(color_value c);
void apply_ul(color_value c);
void apply_font(int font);
void apply_reverse();
void apply_alignment(alignment align);
void apply_attr(attr_activation act, attribute attr);
void apply_reset();
rgba get_bg() const;
rgba get_fg() const;
rgba get_ol() const;
rgba get_ul() const;
int get_font() const;
bool has_overline() const;
bool has_underline() const;
alignment get_alignment() const;
protected:
rgba get_color(color_value c, rgba fallback) const;
/**
* Background color
*/
rgba m_bg;
/**
* Foreground color
*/
rgba m_fg;
/**
* Overline color
*/
rgba m_ol;
/**
* Underline color
*/
rgba m_ul;
/**
* Font index (1-based)
*/
int m_font;
/**
* Is overline enabled?
*/
bool m_attr_overline;
/**
* Is underline enabled?
*/
bool m_attr_underline;
/**
* Alignment block
*/
alignment m_align;
private:
const bar_settings& m_settings;
};
} // namespace tags
POLYBAR_NS_END

View file

@ -29,8 +29,9 @@ namespace tags {
void parse(const bar_settings& bar, renderer_interface&, string data);
protected:
void text(string&& data);
void handle_text(renderer_interface& renderer, context& ctxt, string&& data);
void handle_action(mousebtn btn, bool closing, const string&& cmd);
void handle_control(context& ctxt, controltag ctrl);
private:
signal_emitter& m_sig;

View file

@ -96,6 +96,7 @@ if(BUILD_LIBPOLY)
${src_dir}/modules/xwindow.cpp
${src_dir}/modules/xworkspaces.cpp
${src_dir}/tags/context.cpp
${src_dir}/tags/dispatch.cpp
${src_dir}/tags/parser.cpp

View file

@ -209,15 +209,8 @@ void renderer::begin(xcb_rectangle_t rect) {
// Reset state
m_rect = rect;
m_actions.clear();
m_attr.reset();
m_align = alignment::NONE;
// Reset colors
m_bg = m_bar.background;
m_fg = m_bar.foreground;
m_ul = m_bar.underline.color;
m_ol = m_bar.overline.color;
// Clear canvas
m_context->save();
m_context->clear();
@ -593,12 +586,12 @@ void renderer::fill_background() {
/**
* Fill overline color
*/
void renderer::fill_overline(double x, double w) {
if (m_bar.overline.size && m_attr.test(static_cast<int>(tags::attribute::OVERLINE))) {
void renderer::fill_overline(rgba color, double x, double w) {
if (m_bar.overline.size) {
m_log.trace_x("renderer: overline(x=%f, w=%f)", x, w);
m_context->save();
*m_context << m_comp_ol;
*m_context << m_ol;
*m_context << color;
*m_context << cairo::rect{x, static_cast<double>(m_rect.y), w, static_cast<double>(m_bar.overline.size)};
m_context->fill();
m_context->restore();
@ -608,12 +601,12 @@ void renderer::fill_overline(double x, double w) {
/**
* Fill underline color
*/
void renderer::fill_underline(double x, double w) {
if (m_bar.underline.size && m_attr.test(static_cast<int>(tags::attribute::UNDERLINE))) {
void renderer::fill_underline(rgba color, double x, double w) {
if (m_bar.underline.size) {
m_log.trace_x("renderer: underline(x=%f, w=%f)", x, w);
m_context->save();
*m_context << m_comp_ul;
*m_context << m_ul;
*m_context << color;
*m_context << cairo::rect{x, static_cast<double>(m_rect.y + m_rect.height - m_bar.underline.size), w,
static_cast<double>(m_bar.underline.size)};
m_context->fill();
@ -670,7 +663,7 @@ void renderer::fill_borders() {
/**
* Draw text contents
*/
void renderer::draw_text(const string& contents) {
void renderer::render_text(const tags::context& ctxt, const string&& contents) {
m_log.trace_x("renderer: text(%s)", contents.c_str());
cairo::abspos origin{};
@ -680,17 +673,19 @@ void renderer::draw_text(const string& contents) {
cairo::textblock block{};
block.align = m_align;
block.contents = contents;
block.font = m_font;
block.font = ctxt.get_font();
block.x_advance = &m_blocks[m_align].x;
block.y_advance = &m_blocks[m_align].y;
block.bg_rect = cairo::rect{0.0, 0.0, 0.0, 0.0};
rgba bg = ctxt.get_bg();
// Only draw text background if the color differs from
// the background color of the bar itself
// Note: this means that if the user explicitly set text
// background color equal to background-0 it will be ignored
if (m_bg != m_bar.background) {
block.bg = m_bg;
if (bg != m_bar.background) {
block.bg = bg;
block.bg_operator = m_comp_bg;
block.bg_rect.x = m_rect.x;
block.bg_rect.y = m_rect.y;
@ -700,14 +695,19 @@ void renderer::draw_text(const string& contents) {
m_context->save();
*m_context << origin;
*m_context << m_comp_fg;
*m_context << m_fg;
*m_context << ctxt.get_fg();
*m_context << block;
m_context->restore();
double dx = m_rect.x + m_blocks[m_align].x - origin.x;
if (dx > 0.0) {
fill_underline(origin.x, dx);
fill_overline(origin.x, dx);
if (ctxt.has_underline()) {
fill_underline(ctxt.get_ul(), origin.x, dx);
}
if (ctxt.has_overline()) {
fill_overline(ctxt.get_ol(), origin.x, dx);
}
}
}
@ -746,51 +746,6 @@ bool renderer::on(const signals::ui::request_snapshot& evt) {
return true;
}
bool renderer::on(const signals::parser::change_background& evt) {
const rgba color{evt.cast()};
if (color != m_bg) {
m_log.trace_x("renderer: change_background(#%08x)", color);
m_bg = color;
}
return true;
}
bool renderer::on(const signals::parser::change_foreground& evt) {
const rgba color{evt.cast()};
if (color != m_fg) {
m_log.trace_x("renderer: change_foreground(#%08x)", color);
m_fg = color;
}
return true;
}
bool renderer::on(const signals::parser::change_underline& evt) {
const rgba color{evt.cast()};
if (color != m_ul) {
m_log.trace_x("renderer: change_underline(#%08x)", color);
m_ul = color;
}
return true;
}
bool renderer::on(const signals::parser::change_overline& evt) {
const rgba color{evt.cast()};
if (color != m_ol) {
m_log.trace_x("renderer: change_overline(#%08x)", color);
m_ol = color;
}
return true;
}
bool renderer::on(const signals::parser::change_font& evt) {
const int font{evt.cast()};
if (font != m_font) {
m_log.trace_x("renderer: change_font(%i)", font);
m_font = font;
}
return true;
}
bool renderer::on(const signals::parser::change_alignment& evt) {
auto align = static_cast<const alignment&>(evt.cast());
if (align != m_align) {
@ -812,30 +767,6 @@ bool renderer::on(const signals::parser::change_alignment& evt) {
return true;
}
bool renderer::on(const signals::parser::reverse_colors&) {
m_log.trace_x("renderer: reverse_colors");
std::swap(m_fg, m_bg);
return true;
}
bool renderer::on(const signals::parser::attribute_set& evt) {
m_log.trace_x("renderer: attribute_set(%i)", static_cast<int>(evt.cast()));
m_attr.set(static_cast<int>(evt.cast()), true);
return true;
}
bool renderer::on(const signals::parser::attribute_unset& evt) {
m_log.trace_x("renderer: attribute_unset(%i)", static_cast<int>(evt.cast()));
m_attr.set(static_cast<int>(evt.cast()), false);
return true;
}
bool renderer::on(const signals::parser::attribute_toggle& evt) {
m_log.trace_x("renderer: attribute_toggle(%i)", static_cast<int>(evt.cast()));
m_attr.flip(static_cast<int>(evt.cast()));
return true;
}
bool renderer::on(const signals::parser::action_begin& evt) {
auto a = evt.cast();
m_log.trace_x("renderer: action_begin(btn=%i, command=%s)", static_cast<int>(a.button), a.command);
@ -866,30 +797,4 @@ bool renderer::on(const signals::parser::action_end& evt) {
return true;
}
bool renderer::on(const signals::parser::text& evt) {
auto text = evt.cast();
draw_text(text);
return true;
}
bool renderer::on(const signals::parser::control& evt) {
auto ctrl = evt.cast();
switch (ctrl) {
case tags::controltag::R:
m_bg = m_bar.background;
m_fg = m_bar.foreground;
m_ul = m_bar.underline.color;
m_ol = m_bar.overline.color;
m_font = 0;
m_attr.reset();
break;
case tags::controltag::NONE:
break;
}
return true;
}
POLYBAR_NS_END

116
src/tags/context.cpp Normal file
View file

@ -0,0 +1,116 @@
#include "tags/context.hpp"
POLYBAR_NS
namespace tags {
context::context(const bar_settings& settings) : m_settings(settings) {
reset();
}
void context::reset() {
apply_reset();
m_align = alignment::NONE;
}
void context::apply_bg(color_value c) {
m_bg = get_color(c, m_settings.background);
}
void context::apply_fg(color_value c) {
m_fg = get_color(c, m_settings.foreground);
}
void context::apply_ol(color_value c) {
m_ol = get_color(c, m_settings.overline.color);
}
void context::apply_ul(color_value c) {
m_ul = get_color(c, m_settings.underline.color);
}
void context::apply_font(int font) {
m_font = std::max(font, 0);
}
void context::apply_reverse() {
std::swap(m_bg, m_fg);
}
void context::apply_alignment(alignment align) {
m_align = align;
}
void context::apply_attr(attr_activation act, attribute attr) {
if (attr == attribute::NONE) {
return;
}
bool& current = attr == attribute::OVERLINE ? m_attr_overline : m_attr_underline;
switch (act) {
case attr_activation::ON:
current = true;
break;
case attr_activation::OFF:
current = false;
break;
case attr_activation::TOGGLE:
current = !current;
break;
default:
break;
}
}
void context::apply_reset() {
m_bg = m_settings.background;
m_fg = m_settings.foreground;
m_ul = m_settings.underline.color;
m_ol = m_settings.overline.color;
m_font = 0;
m_attr_overline = false;
m_attr_underline = false;
}
rgba context::get_bg() const {
return m_bg;
}
rgba context::get_fg() const {
return m_fg;
}
rgba context::get_ol() const {
return m_ol;
}
rgba context::get_ul() const {
return m_ul;
}
int context::get_font() const {
return m_font;
}
bool context::has_overline() const {
return m_attr_overline;
}
bool context::has_underline() const {
return m_attr_underline;
}
alignment context::get_alignment() const {
return m_align;
}
rgba context::get_color(color_value c, rgba fallback) const {
if (c.type == color_type::RESET) {
return fallback;
} else {
return c.val;
}
}
} // namespace tags
POLYBAR_NS_END

View file

@ -14,14 +14,6 @@ POLYBAR_NS
using namespace signals::parser;
namespace tags {
static rgba get_color(tags::color_value c, rgba fallback) {
if (c.type == tags::color_type::RESET) {
return fallback;
} else {
return c.val;
}
}
/**
* Create instance
*/
@ -41,6 +33,8 @@ namespace tags {
tags::parser p;
p.set(std::move(data));
context ctxt(bar);
while (p.has_next_element()) {
tags::element el;
try {
@ -58,36 +52,39 @@ namespace tags {
handle_action(el.tag_data.action.btn, el.tag_data.action.closing, std::move(el.data));
break;
case tags::syntaxtag::B:
m_sig.emit(change_background{get_color(el.tag_data.color, bar.background)});
ctxt.apply_bg(el.tag_data.color);
break;
case tags::syntaxtag::F:
m_sig.emit(change_foreground{get_color(el.tag_data.color, bar.foreground)});
ctxt.apply_fg(el.tag_data.color);
break;
case tags::syntaxtag::T:
m_sig.emit(change_font{el.tag_data.font});
ctxt.apply_font(el.tag_data.font);
break;
case tags::syntaxtag::O:
renderer.render_offset(tags::context{}, el.tag_data.offset);
renderer.render_offset(ctxt, el.tag_data.offset);
break;
case tags::syntaxtag::R:
m_sig.emit(reverse_colors{});
ctxt.apply_reverse();
break;
case tags::syntaxtag::o:
m_sig.emit(change_overline{get_color(el.tag_data.color, bar.overline.color)});
ctxt.apply_ol(el.tag_data.color);
break;
case tags::syntaxtag::u:
m_sig.emit(change_underline{get_color(el.tag_data.color, bar.underline.color)});
ctxt.apply_ul(el.tag_data.color);
break;
case tags::syntaxtag::P:
m_sig.emit(control{el.tag_data.ctrl});
handle_control(ctxt, el.tag_data.ctrl);
break;
case tags::syntaxtag::l:
ctxt.apply_alignment(alignment::LEFT);
m_sig.emit(change_alignment{alignment::LEFT});
break;
case tags::syntaxtag::r:
ctxt.apply_alignment(alignment::RIGHT);
m_sig.emit(change_alignment{alignment::RIGHT});
break;
case tags::syntaxtag::c:
ctxt.apply_alignment(alignment::CENTER);
m_sig.emit(change_alignment{alignment::CENTER});
break;
default:
@ -96,25 +93,11 @@ namespace tags {
}
break;
case tags::tag_type::ATTR:
tags::attribute act = el.tag_data.attr;
switch (el.tag_data.subtype.activation) {
case tags::attr_activation::ON:
m_sig.emit(attribute_set{act});
break;
case tags::attr_activation::OFF:
m_sig.emit(attribute_unset{act});
break;
case tags::attr_activation::TOGGLE:
m_sig.emit(attribute_toggle{act});
break;
default:
throw runtime_error("Unrecognized attribute activation: " +
to_string(static_cast<int>(el.tag_data.subtype.activation)));
}
ctxt.apply_attr(el.tag_data.subtype.activation, el.tag_data.attr);
break;
}
} else {
text(std::move(el.data));
handle_text(renderer, ctxt, std::move(el.data));
}
}
@ -126,7 +109,7 @@ namespace tags {
/**
* Process text contents
*/
void dispatch::text(string&& data) {
void dispatch::handle_text(renderer_interface& renderer, context& ctxt, string&& data) {
#ifdef DEBUG_WHITESPACE
string::size_type p;
while ((p = data.find(' ')) != string::npos) {
@ -134,7 +117,7 @@ namespace tags {
}
#endif
m_sig.emit(signals::parser::text{std::move(data)});
renderer.render_text(ctxt, std::move(data));
}
void dispatch::handle_action(mousebtn btn, bool closing, const string&& cmd) {
@ -166,6 +149,17 @@ namespace tags {
m_sig.emit(action_begin{action{btn, std::move(cmd)}});
}
}
void dispatch::handle_control(context& ctxt, controltag ctrl) {
switch (ctrl) {
case controltag::R:
ctxt.reset();
break;
default:
throw runtime_error("Unrecognized polybar control tag: " + to_string(static_cast<int>(ctrl)));
}
}
} // namespace tags
POLYBAR_NS_END