refactor(renderer): Use redirection groups instead of pixmaps

This commit is contained in:
Michael Carlberg 2017-01-25 09:54:18 +01:00
parent d2eeac9b22
commit c7f33e2567
4 changed files with 105 additions and 59 deletions

View File

@ -111,6 +111,11 @@ namespace cairo {
return *this;
}
context& operator<<(const translate& d) {
cairo_translate(m_c, d.x, d.y);
return *this;
}
context& operator<<(const linear_gradient& l) {
if (l.steps.size() >= 2) {
auto pattern = cairo_pattern_create_linear(l.x1, l.y1, l.x2, l.y2);
@ -274,10 +279,30 @@ namespace cairo {
return *this;
}
context& mask(cairo_pattern_t* pattern) {
cairo_mask(m_c, pattern);
return *this;
}
context& pop(cairo_pattern_t** pattern) {
*pattern = cairo_pop_group(m_c);
return *this;
}
context& push() {
cairo_push_group(m_c);
return *this;
}
context& destroy(cairo_pattern_t** pattern) {
cairo_pattern_destroy(*pattern);
*pattern = nullptr;
return *this;
}
context& clear() {
cairo_save(m_c);
cairo_set_operator(m_c, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(m_c, 0.0, 0.0, 0.0, 0.0);
cairo_set_operator(m_c, CAIRO_OPERATOR_CLEAR);
cairo_paint(m_c);
cairo_restore(m_c);
return *this;

View File

@ -41,6 +41,10 @@ namespace cairo {
double dx;
double dy;
};
struct translate {
double x;
double y;
};
struct linear_gradient {
double x1;
double y1;

View File

@ -1,6 +1,7 @@
#pragma once
#include <bitset>
#include <cairo/cairo.h>
#include "cairo/fwd.hpp"
#include "common.hpp"
@ -21,7 +22,7 @@ class logger;
using std::map;
struct alignment_block {
xcb_pixmap_t pixmap;
cairo_pattern_t* pattern;
double x;
double y;
};
@ -58,7 +59,9 @@ class renderer
double block_x(alignment a) const;
double block_y(alignment a) const;
double block_w(alignment a) const;
double block_h(alignment a) const;
void flush(alignment a);
void highlight_clickable_areas();
bool on(const signals::ui::request_snapshot& evt);
@ -122,6 +125,8 @@ class renderer
bool m_fixedcenter;
string m_snapshot_dst;
cairo_pattern_t* m_cornermask{};
};
POLYBAR_NS_END

View File

@ -102,15 +102,9 @@ renderer::renderer(
m_log.trace("renderer: Allocate alignment blocks");
{
const auto create_block = [&](alignment a) {
auto pid = m_connection.generate_id();
m_connection.create_pixmap_checked(m_depth, pid, m_pixmap, m_bar.size.w, m_bar.size.h);
m_blocks.emplace(a, alignment_block{pid, 0.0, 0.0});
};
create_block(alignment::LEFT);
create_block(alignment::CENTER);
create_block(alignment::RIGHT);
m_blocks.emplace(alignment::LEFT, alignment_block{nullptr, 0.0, 0.0});
m_blocks.emplace(alignment::CENTER, alignment_block{nullptr, 0.0, 0.0});
m_blocks.emplace(alignment::RIGHT, alignment_block{nullptr, 0.0, 0.0});
}
m_log.trace("renderer: Allocate cairo components");
@ -155,7 +149,8 @@ renderer::renderer(
auto fonts_loaded = false;
for (const auto& f : fonts) {
vector<string> fd{string_util::split(f, ';')};
auto font = cairo::make_font(*m_context, string(fd[0]), fd.size() > 1 ? std::atoi(fd[1].c_str()) : 0, dpi_x, dpi_y);
auto font =
cairo::make_font(*m_context, string(fd[0]), fd.size() > 1 ? std::atoi(fd[1].c_str()) : 0, dpi_x, dpi_y);
m_log.info("Loaded font \"%s\" (name=%s, file=%s)", fd[0], font->name(), font->file());
*m_context << move(font);
fonts_loaded = true;
@ -214,20 +209,35 @@ void renderer::begin() {
m_ul = m_bar.underline.color;
m_ol = m_bar.overline.color;
// Clear canvas
m_context->clear();
m_context->save();
// Clear canvas
m_surface->set_drawable(m_pixmap, m_bar.size.w, m_bar.size.h);
m_context->clear();
// Create corner mask
if (m_bar.radius != 0.0) {
m_context->save();
m_context->push();
// clang-format off
*m_context << cairo::rounded_corners{
static_cast<double>(m_rect.x),
static_cast<double>(m_rect.y),
static_cast<double>(m_rect.width),
static_cast<double>(m_rect.height), m_bar.radius};
// clang-format on
*m_context << rgba{1.0, 1.0, 1.0, 1.0};
m_context->fill();
m_context->pop(&m_cornermask);
m_context->restore();
}
fill_borders();
// clang-format off
m_context->clip(cairo::rect{
static_cast<double>(m_rect.x),
static_cast<double>(m_rect.y),
static_cast<double>(m_rect.width),
static_cast<double>(m_rect.height)});
static_cast<double>(m_rect.x),
static_cast<double>(m_rect.y),
static_cast<double>(m_rect.width),
static_cast<double>(m_rect.height)});
// clang-format on
fill_background();
@ -247,8 +257,6 @@ void renderer::end() {
rgba bg1{m_bar.background}; bg1.a = 0.0;
rgba bg2{m_bar.background}; bg2.a = 1.0;
// clang-format on
m_surface->set_drawable(b.second.pixmap, m_bar.size.w, m_bar.size.h);
m_context->save();
*m_context << cairo::linear_gradient{x - 40.0, 0.0, x, 0.0, {bg1, bg2}};
m_context->paint();
@ -262,39 +270,47 @@ void renderer::end() {
a.end_x += block_x(a.align) + m_rect.x;
}
flush(m_align);
m_context->restore();
m_surface->flush();
flush();
}
/**
* Flush contents of given alignment block
*/
void renderer::flush(alignment a) {
if (a != alignment::NONE) {
double x = block_x(a);
double y = block_y(a);
double w = block_w(a);
double h = block_h(a);
m_surface->flush();
m_context->pop(&m_blocks[m_align].pattern);
m_context->save();
{
*m_context << cairo::rect{m_rect.x + x, m_rect.y + y, w, h};
*m_context << cairo::translate{x, 0.0};
*m_context << m_blocks[a].pattern;
m_context->paint();
m_surface->flush();
}
m_context->restore();
m_surface->flush();
m_context->destroy(&m_blocks[a].pattern);
}
}
/**
* Flush pixmap contents onto the target window
*/
void renderer::flush() {
m_log.trace_x("renderer: flush");
m_surface->set_drawable(m_pixmap, m_bar.size.w, m_bar.size.h);
m_surface->flush();
for (auto&& b : m_blocks) {
double x = m_rect.x + block_x(b.first);
double y = m_rect.y + block_y(b.first);
double w = m_rect.x + m_rect.width - x;
double h = m_rect.y + m_rect.height - y;
if (w > 0.0) {
m_log.trace_x("renderer: copy alignment block (x=%.0f y=%.0f w=%.0f h=%.0f)", x, y, w, h);
m_connection.copy_area(b.second.pixmap, m_pixmap, m_gcontext, m_rect.x, m_rect.y, x, y, w, h);
m_connection.flush();
} else {
m_log.trace_x("renderer: ignoring empty alignment block");
continue;
}
}
m_surface->dirty();
m_surface->flush();
highlight_clickable_areas();
#if 0
@ -363,6 +379,13 @@ double renderer::block_w(alignment a) const {
return m_blocks.at(a).x;
}
/**
* Get block height for given alignment
*/
double renderer::block_h(alignment) const {
return m_rect.height;
}
/**
* Reserve space at given edge
*/
@ -405,16 +428,6 @@ void renderer::fill_background() {
m_context->save();
*m_context << static_cast<cairo_operator_t>(m_comp_bg);
if (m_bar.radius != 0.0) {
// clang-format off
*m_context << cairo::rounded_corners{
static_cast<double>(m_rect.x),
static_cast<double>(m_rect.y),
static_cast<double>(m_rect.width),
static_cast<double>(m_rect.height), m_bar.radius};
// clang-format on
}
if (!m_bar.background_steps.empty()) {
m_log.trace_x("renderer: gradient background (steps=%lu)", m_bar.background_steps.size());
*m_context << cairo::linear_gradient{0.0, 0.0 + m_rect.y, 0.0, 0.0 + m_rect.height, m_bar.background_steps};
@ -423,8 +436,8 @@ void renderer::fill_background() {
*m_context << m_bar.background;
}
if (m_bar.radius != 0.0) {
m_context->fill();
if (m_cornermask != nullptr) {
m_context->mask(m_cornermask);
} else {
m_context->paint();
}
@ -621,12 +634,11 @@ bool renderer::on(const signals::parser::change_alignment& evt) {
auto align = static_cast<const alignment&>(evt.cast());
if (align != m_align) {
m_log.trace_x("renderer: change_alignment(%i)", static_cast<int>(align));
flush(m_align);
m_context->push();
m_align = align;
m_blocks[m_align].x = 0.0;
m_blocks[m_align].y = 0.0;
m_surface->set_drawable(m_blocks.at(m_align).pixmap, m_bar.size.w, m_bar.size.h);
m_context->clear();
fill_background();
}
return true;
}