diff --git a/include/cairo/context.hpp b/include/cairo/context.hpp index b1a7f748..a10bf3fa 100644 --- a/include/cairo/context.hpp +++ b/include/cairo/context.hpp @@ -315,6 +315,12 @@ namespace cairo { return *this; } + context& clip() { + cairo_clip(m_c); + cairo_new_path(m_c); + return *this; + } + context& clip(const rect& r) { *this << r; cairo_clip(m_c); diff --git a/src/components/renderer.cpp b/src/components/renderer.cpp index 64fb13ff..9a136ac8 100644 --- a/src/components/renderer.cpp +++ b/src/components/renderer.cpp @@ -13,6 +13,8 @@ POLYBAR_NS +static constexpr double BLOCK_GAP{20.0}; + /** * Create instance */ @@ -210,11 +212,11 @@ void renderer::begin() { m_ol = m_bar.overline.color; // Clear canvas - m_context->clear(); m_context->save(); + m_context->clear(); // Create corner mask - if (m_bar.radius != 0.0) { + if (m_bar.radius != 0.0 && m_cornermask == nullptr) { m_context->save(); m_context->push(); // clang-format off @@ -249,28 +251,21 @@ void renderer::begin() { void renderer::end() { m_log.trace_x("renderer: end"); - for (auto&& b : m_blocks) { - if (block_x(b.first) + block_w(b.first) > (m_rect.width)) { - double x = m_rect.x + block_x(b.first) + block_w(b.first); - if ((x -= x - m_rect.x - m_rect.width + block_x(b.first)) > 0.0) { - // clang-format off - rgba bg1{m_bar.background}; bg1.a = 0.0; - rgba bg2{m_bar.background}; bg2.a = 1.0; - // clang-format on - m_context->save(); - *m_context << cairo::linear_gradient{x - 40.0, 0.0, x, 0.0, {bg1, bg2}}; - m_context->paint(); - m_context->restore(); - } - } - } - for (auto&& a : m_actions) { a.start_x += block_x(a.align) + m_rect.x; a.end_x += block_x(a.align) + m_rect.x; } - flush(m_align); + if (m_align != alignment::NONE) { + m_log.trace_x("renderer: pop(%i)", static_cast(m_align)); + m_context->pop(&m_blocks[m_align].pattern); + + for (auto&& b : m_blocks) { + if (block_w(b.first) != 0.0) { + flush(b.first); + } + } + } m_context->restore(); m_surface->flush(); @@ -282,27 +277,50 @@ void renderer::end() { * 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_log.trace_x("renderer: flush(%i)", static_cast(a)); - m_surface->flush(); - m_context->pop(&m_blocks[m_align].pattern); + double x = block_x(a); + double y = block_y(a); + double w = block_w(a); + double h = block_h(a); + double xw = x + w; - 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_surface->flush(); + m_context->save(); + { + *m_context << cairo::abspos{0.0, 0.0}; + *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; + + if (xw <= m_rect.width) { + m_context->paint(); + } else { + double sx = w - (xw - m_rect.width); + vector falloff{0xFFFFFFFF, 0x00FFFFFF}; + cairo_pattern_t* pattern{}; + + m_context->push(); + *m_context << cairo::linear_gradient{sx - 40.0, 0.0, sx, 0.0, falloff}; + *m_context << CAIRO_OPERATOR_SOURCE; + m_context->paint(); + m_context->pop(&pattern); + m_context->mask(pattern); + m_context->destroy(&pattern); + + // clang-format off + rgba bg1{m_bar.background}; bg1.a = 0.0; + rgba bg2{m_bar.background}; bg2.a = 0.4; + // clang-format on + *m_context << cairo::linear_gradient{sx - 40.0, 0.0, sx, 0.0, {bg1, bg2}}; + *m_context << CAIRO_OPERATOR_OVER; m_context->paint(); - m_surface->flush(); } - m_context->restore(); + m_surface->flush(); - m_context->destroy(&m_blocks[a].pattern); } + m_context->restore(); + m_context->destroy(&m_blocks[a].pattern); } /** @@ -354,12 +372,12 @@ double renderer::block_x(alignment a) const { case alignment::CENTER: if (!m_fixedcenter || m_rect.width / 2.0 + block_w(a) / 2.0 > m_rect.width - block_w(alignment::RIGHT)) { return std::max((m_rect.width - block_w(alignment::RIGHT) + block_w(alignment::LEFT)) / 2.0 - block_w(a) / 2.0, - block_w(alignment::LEFT)); + block_w(alignment::LEFT) + BLOCK_GAP); } else { return std::max(m_rect.width / 2.0 - block_w(a) / 2.0, block_w(alignment::LEFT)); } case alignment::RIGHT: - return std::max(m_rect.width - block_w(a), block_x(alignment::CENTER) + block_w(alignment::CENTER)); + return std::max(m_rect.width - block_w(a), block_x(alignment::CENTER) + BLOCK_GAP + block_w(alignment::CENTER)); default: return 0.0; } @@ -634,11 +652,18 @@ bool renderer::on(const signals::parser::change_alignment& evt) { auto align = static_cast(evt.cast()); if (align != m_align) { m_log.trace_x("renderer: change_alignment(%i)", static_cast(align)); - flush(m_align); - m_context->push(); + + if (m_align != alignment::NONE) { + m_log.trace_x("renderer: pop(%i)", static_cast(m_align)); + m_context->pop(&m_blocks[m_align].pattern); + } + + // flush(m_align); m_align = align; m_blocks[m_align].x = 0.0; m_blocks[m_align].y = 0.0; + m_context->push(); + m_log.trace_x("renderer: push(%i)", static_cast(m_align)); } return true; }