wip(refactor): Cairo drawing
This commit is contained in:
parent
13633f715d
commit
8b9461e63e
@ -19,6 +19,9 @@
|
||||
POLYBAR_NS
|
||||
|
||||
namespace cairo {
|
||||
/**
|
||||
* @brief Cairo context
|
||||
*/
|
||||
class context {
|
||||
public:
|
||||
explicit context(const surface& surface, const logger& log) : m_c(cairo_create(surface)), m_log(log) {
|
||||
@ -99,9 +102,18 @@ namespace cairo {
|
||||
return *this;
|
||||
}
|
||||
|
||||
context& operator<<(const displace& d) {
|
||||
cairo_set_operator(m_c, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_surface(m_c, cairo_get_target(m_c), d.x - d.w, d.y);
|
||||
cairo_rectangle(m_c, d.x - d.w, d.y, d.x + d.dx, d.y + d.dy);
|
||||
cairo_fill(m_c);
|
||||
cairo_surface_flush(cairo_get_target(m_c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
context& operator<<(const linear_gradient& l) {
|
||||
if (l.steps.size() >= 2) {
|
||||
auto pattern = cairo_pattern_create_linear(l.x0, l.y0, l.x1, l.y1);
|
||||
auto pattern = cairo_pattern_create_linear(l.x1, l.y1, l.x2, l.y2);
|
||||
*this << pattern;
|
||||
auto stops = l.steps.size();
|
||||
auto step = 1.0 / (stops - 1);
|
||||
@ -149,7 +161,7 @@ namespace cairo {
|
||||
});
|
||||
|
||||
string utf8 = string(t.contents);
|
||||
unicode_charlist chars;
|
||||
utils::unicode_charlist chars;
|
||||
utils::utf8_to_ucs4((const unsigned char*)utf8.c_str(), chars);
|
||||
|
||||
while (!chars.empty()) {
|
||||
@ -167,55 +179,32 @@ namespace cairo {
|
||||
end++;
|
||||
}
|
||||
|
||||
// encapsulate the vert. centering
|
||||
save();
|
||||
// Use the font
|
||||
f->use();
|
||||
|
||||
// Get subset extents
|
||||
cairo_text_extents_t extents;
|
||||
f->textwidth(subset, &extents);
|
||||
|
||||
save(true);
|
||||
{
|
||||
*this << abspos{x, y};
|
||||
|
||||
f->use();
|
||||
|
||||
cairo_text_extents_t extents;
|
||||
f->textwidth(utf8, &extents);
|
||||
double dx{0.0}, dy{0.0};
|
||||
|
||||
if (t.align == alignment::CENTER) {
|
||||
dx -= extents.x_advance / 2.0;
|
||||
|
||||
save();
|
||||
{
|
||||
cairo_rectangle(m_c, x, y, extents.x_advance / 2.0, extents.height);
|
||||
auto pattern = cairo_pattern_create_rgba(1.0, 0.0, 0.0, 0.0);
|
||||
cairo_set_source(m_c, pattern);
|
||||
cairo_translate(m_c, dx, 0.0);
|
||||
cairo_set_operator(m_c, CAIRO_OPERATOR_DEST);
|
||||
cairo_fill(m_c);
|
||||
cairo_pattern_destroy(pattern);
|
||||
}
|
||||
restore();
|
||||
} else if (t.align == alignment::RIGHT) {
|
||||
dx -= extents.x_advance;
|
||||
|
||||
save();
|
||||
{
|
||||
cairo_rectangle(m_c, x, y, extents.x_advance, extents.height);
|
||||
auto pattern = cairo_pattern_create_rgba(0.0, 0.0, 0.0, 0.0);
|
||||
cairo_set_source(m_c, pattern);
|
||||
cairo_set_operator(m_c, CAIRO_OPERATOR_DEST);
|
||||
cairo_translate(m_c, dx, 0.0);
|
||||
cairo_fill(m_c);
|
||||
cairo_pattern_destroy(pattern);
|
||||
}
|
||||
restore();
|
||||
}
|
||||
|
||||
auto fontextents = f->extents();
|
||||
f->render(subset, x + dx,
|
||||
y + dy - (extents.height / 2.0 + extents.y_bearing + fontextents.descent) + f->offset());
|
||||
position(&x, nullptr);
|
||||
x += dx;
|
||||
y += dy;
|
||||
*this << t.bg;
|
||||
cairo_set_operator(m_c, static_cast<cairo_operator_t>(t.bg_operator));
|
||||
cairo_rectangle(m_c, t.bg_rect.x, t.bg_rect.y, t.bg_rect.w + extents.x_advance, t.bg_rect.h);
|
||||
cairo_fill(m_c);
|
||||
}
|
||||
restore();
|
||||
restore(true);
|
||||
|
||||
// Render subset
|
||||
auto fontextents = f->extents();
|
||||
f->render(subset, x, y - (extents.height / 2.0 + extents.y_bearing + fontextents.descent) + f->offset());
|
||||
|
||||
// Get updated position
|
||||
position(&x, nullptr);
|
||||
|
||||
// Increase position
|
||||
*t.x_advance += extents.x_advance;
|
||||
*t.y_advance += extents.y_advance;
|
||||
|
||||
chars.erase(chars.begin(), end);
|
||||
break;
|
||||
@ -227,7 +216,7 @@ namespace cairo {
|
||||
continue;
|
||||
}
|
||||
|
||||
char unicode[5]{'\0'};
|
||||
char unicode[6]{'\0'};
|
||||
utils::ucs4_to_utf8(unicode, chars.begin()->codepoint);
|
||||
m_log.warn("Dropping unmatched character %s (U+%04x)", unicode, chars.begin()->codepoint);
|
||||
utf8.erase(chars.begin()->offset, chars.begin()->length);
|
||||
@ -237,7 +226,7 @@ namespace cairo {
|
||||
chars.erase(chars.begin(), ++chars.begin());
|
||||
}
|
||||
|
||||
*this << abspos{x, y};
|
||||
// *this << abspos{x, y};
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -247,7 +236,7 @@ namespace cairo {
|
||||
return *this;
|
||||
}
|
||||
|
||||
context& save(bool save_point = true) {
|
||||
context& save(bool save_point = false) {
|
||||
if (save_point) {
|
||||
m_points.emplace_front(make_pair<double, double>(0.0, 0.0));
|
||||
position(&m_points.front().first, &m_points.front().second);
|
||||
@ -256,9 +245,9 @@ namespace cairo {
|
||||
return *this;
|
||||
}
|
||||
|
||||
context& restore(bool restore_point = true) {
|
||||
context& restore(bool restore_point = false) {
|
||||
cairo_restore(m_c);
|
||||
if (restore_point) {
|
||||
if (restore_point && !m_points.empty()) {
|
||||
*this << abspos{m_points.front().first, m_points.front().first};
|
||||
m_points.pop_front();
|
||||
}
|
||||
@ -284,9 +273,19 @@ namespace cairo {
|
||||
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_paint(m_c);
|
||||
cairo_restore(m_c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
context& clip(const rect& r) {
|
||||
*this << r;
|
||||
cairo_clip(m_c);
|
||||
cairo_new_path(m_c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cairo/cairo-ft.h>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "cairo/types.hpp"
|
||||
#include "cairo/utils.hpp"
|
||||
#include "common.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "settings.hpp"
|
||||
@ -15,47 +14,10 @@
|
||||
POLYBAR_NS
|
||||
|
||||
namespace cairo {
|
||||
namespace details {
|
||||
/**
|
||||
* @brief Global pointer to the Freetype library handler
|
||||
*/
|
||||
static FT_Library g_ftlib;
|
||||
|
||||
/**
|
||||
* @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) : m_font(font) {
|
||||
m_face = cairo_ft_scaled_font_lock_face(m_font);
|
||||
}
|
||||
~ft_face_lock() {
|
||||
cairo_ft_scaled_font_unlock_face(m_font);
|
||||
}
|
||||
|
||||
operator FT_Face() const {
|
||||
return 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
|
||||
* @brief Global pointer to the Freetype library handler
|
||||
*/
|
||||
struct unicode_character {
|
||||
explicit unicode_character() : codepoint(0), offset(0), length(0) {}
|
||||
|
||||
unsigned long codepoint;
|
||||
int offset;
|
||||
int length;
|
||||
};
|
||||
using unicode_charlist = std::list<unicode_character>;
|
||||
static FT_Library g_ftlib;
|
||||
|
||||
/**
|
||||
* @brief Abstract font face
|
||||
@ -76,8 +38,8 @@ namespace cairo {
|
||||
cairo_set_font_face(m_cairo, cairo_font_face_reference(m_font_face));
|
||||
}
|
||||
|
||||
virtual size_t match(unicode_charlist& charlist) = 0;
|
||||
virtual size_t render(const string& text, double x = 0.0, double y = 0.0, bool reverse = false) = 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:
|
||||
@ -109,7 +71,7 @@ namespace cairo {
|
||||
throw application_error(sstream() << "cairo_scaled_font_create(): " << cairo_status_to_string(status));
|
||||
}
|
||||
|
||||
auto lock = make_unique<details::ft_face_lock>(m_scaled);
|
||||
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) {
|
||||
@ -166,8 +128,8 @@ namespace cairo {
|
||||
cairo_set_scaled_font(m_cairo, m_scaled);
|
||||
}
|
||||
|
||||
size_t match(unicode_charlist& charlist) override {
|
||||
auto lock = make_unique<details::ft_face_lock>(m_scaled);
|
||||
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) {
|
||||
@ -181,16 +143,12 @@ namespace cairo {
|
||||
return available_chars;
|
||||
}
|
||||
|
||||
size_t render(const string& text, double x = 0.0, double y = 0.0, bool reverse = false) override {
|
||||
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;
|
||||
|
||||
if (reverse) {
|
||||
cf = CAIRO_TEXT_CLUSTER_FLAG_BACKWARD;
|
||||
}
|
||||
|
||||
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);
|
||||
@ -222,12 +180,16 @@ namespace cairo {
|
||||
}
|
||||
|
||||
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_rel_move_to(m_cairo, extents.x_advance, 0.0);
|
||||
// cairo_glyph_path(m_cairo, glyphs, nglyphs);
|
||||
cairo_fill_preserve(m_cairo);
|
||||
cairo_fill(m_cairo);
|
||||
cairo_move_to(m_cairo, x + extents.x_advance, 0.0);
|
||||
}
|
||||
|
||||
cairo_glyph_free(glyphs);
|
||||
@ -276,12 +238,12 @@ namespace cairo {
|
||||
static bool fc_init{false};
|
||||
if (!fc_init && !(fc_init = FcInit())) {
|
||||
throw application_error("Could not load fontconfig");
|
||||
} else if (FT_Init_FreeType(&details::g_ftlib) != FT_Err_Ok) {
|
||||
} else if (FT_Init_FreeType(&g_ftlib) != FT_Err_Ok) {
|
||||
throw application_error("Could not load FreeType");
|
||||
}
|
||||
|
||||
static auto fc_cleanup = scope_util::make_exit_handler([] {
|
||||
FT_Done_FreeType(details::g_ftlib);
|
||||
FT_Done_FreeType(g_ftlib);
|
||||
FcFini();
|
||||
});
|
||||
|
||||
|
@ -4,11 +4,16 @@
|
||||
|
||||
#include "cairo/types.hpp"
|
||||
#include "common.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "utils/color.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
namespace cairo {
|
||||
/**
|
||||
* @brief Base surface
|
||||
*/
|
||||
class surface {
|
||||
public:
|
||||
explicit surface(cairo_surface_t* s) : m_s(s) {}
|
||||
@ -20,30 +25,51 @@ namespace cairo {
|
||||
return m_s;
|
||||
}
|
||||
|
||||
surface& flush() {
|
||||
void flush() {
|
||||
cairo_surface_flush(m_s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
surface& dirty() {
|
||||
void show(bool clear = true) {
|
||||
if (clear) {
|
||||
cairo_surface_show_page(m_s);
|
||||
} else {
|
||||
cairo_surface_copy_page(m_s);
|
||||
}
|
||||
}
|
||||
|
||||
void dirty() {
|
||||
cairo_surface_mark_dirty(m_s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
surface& dirty(const rect& r) {
|
||||
void dirty(const rect& r) {
|
||||
cairo_surface_mark_dirty_rectangle(m_s, r.x, r.y, r.w, r.h);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void write_png(const string& dst) {
|
||||
auto status = cairo_surface_write_to_png(m_s, dst.c_str());
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
throw application_error(sstream() << "cairo_surface_write_to_png(): " << cairo_status_to_string(status));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
cairo_surface_t* m_s;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Surface for xcb
|
||||
*/
|
||||
class xcb_surface : public surface {
|
||||
public:
|
||||
explicit xcb_surface(xcb_connection_t* c, xcb_pixmap_t p, xcb_visualtype_t* v, int w, int h)
|
||||
: surface(cairo_xcb_surface_create(c, p, v, w, h)) {}
|
||||
|
||||
~xcb_surface() override {}
|
||||
|
||||
void set_drawable(xcb_drawable_t d, int w, int h) {
|
||||
cairo_surface_flush(m_s);
|
||||
cairo_xcb_surface_set_drawable(m_s, d, w, h);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,10 @@ POLYBAR_NS
|
||||
enum class alignment;
|
||||
|
||||
namespace cairo {
|
||||
struct point {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
struct abspos {
|
||||
double x;
|
||||
double y;
|
||||
@ -16,14 +20,12 @@ namespace cairo {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
struct rect {
|
||||
double x;
|
||||
double y;
|
||||
double w;
|
||||
double h;
|
||||
};
|
||||
|
||||
struct line {
|
||||
double x1;
|
||||
double y1;
|
||||
@ -31,15 +33,21 @@ namespace cairo {
|
||||
double y2;
|
||||
double w;
|
||||
};
|
||||
|
||||
struct displace {
|
||||
double x;
|
||||
double y;
|
||||
double w;
|
||||
double h;
|
||||
double dx;
|
||||
double dy;
|
||||
};
|
||||
struct linear_gradient {
|
||||
double x0;
|
||||
double y0;
|
||||
double x1;
|
||||
double y1;
|
||||
double x2;
|
||||
double y2;
|
||||
vector<unsigned int> steps;
|
||||
};
|
||||
|
||||
struct rounded_corners {
|
||||
double x;
|
||||
double y;
|
||||
@ -47,11 +55,15 @@ namespace cairo {
|
||||
double h;
|
||||
double radius;
|
||||
};
|
||||
|
||||
struct textblock {
|
||||
alignment align;
|
||||
string contents;
|
||||
int fontindex;
|
||||
unsigned int bg;
|
||||
int bg_operator;
|
||||
rect bg_rect;
|
||||
double *x_advance;
|
||||
double *y_advance;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
#include "cairo/font.hpp"
|
||||
#include "common.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
@ -11,6 +11,66 @@ 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) {
|
||||
auto status = cairo_device_acquire(device);
|
||||
if (status == CAIRO_STATUS_SUCCESS) {
|
||||
m_device = device;
|
||||
}
|
||||
}
|
||||
~device_lock() {
|
||||
cairo_device_release(m_device);
|
||||
}
|
||||
operator bool() const {
|
||||
return m_device != nullptr;
|
||||
}
|
||||
operator cairo_device_t*() const {
|
||||
return m_device;
|
||||
}
|
||||
|
||||
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) : m_font(font) {
|
||||
m_face = cairo_ft_scaled_font_lock_face(m_font);
|
||||
}
|
||||
~ft_face_lock() {
|
||||
cairo_ft_scaled_font_unlock_face(m_font);
|
||||
}
|
||||
|
||||
operator FT_Face() const {
|
||||
return 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() : codepoint(0), offset(0), length(0) {}
|
||||
|
||||
unsigned long codepoint;
|
||||
int offset;
|
||||
int length;
|
||||
};
|
||||
using unicode_charlist = std::list<unicode_character>;
|
||||
|
||||
/**
|
||||
* @see <cairo/cairo.h>
|
||||
*/
|
||||
|
@ -45,7 +45,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
||||
unique_ptr<inotify_watch>&&);
|
||||
~controller();
|
||||
|
||||
bool run(bool writeback = false);
|
||||
bool run(bool writeback, string snapshot_dst);
|
||||
|
||||
bool enqueue(event&& evt);
|
||||
bool enqueue(string&& input_data);
|
||||
@ -84,6 +84,11 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
||||
*/
|
||||
std::atomic<bool> m_process_events{false};
|
||||
|
||||
/**
|
||||
* @brief Destination path of generated snapshot
|
||||
*/
|
||||
string m_snapshot_dst;
|
||||
|
||||
/**
|
||||
* @brief Controls weather the output gets printed to stdout
|
||||
*/
|
||||
@ -133,6 +138,11 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
||||
* @brief Thread for the eventqueue loop
|
||||
*/
|
||||
std::thread m_event_thread;
|
||||
|
||||
/**
|
||||
* @brief Misc threads
|
||||
*/
|
||||
vector<std::thread> m_threads;
|
||||
};
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -21,8 +21,14 @@ class logger;
|
||||
|
||||
using std::map;
|
||||
|
||||
struct alignment_block {
|
||||
xcb_pixmap_t pixmap;
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
class renderer
|
||||
: public signal_receiver<SIGN_PRIORITY_RENDERER, signals::parser::change_background,
|
||||
: 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::offset_pixel,
|
||||
signals::parser::attribute_set, signals::parser::attribute_unset, signals::parser::attribute_toggle,
|
||||
@ -50,9 +56,13 @@ class renderer
|
||||
void draw_text(const string& contents);
|
||||
|
||||
protected:
|
||||
void adjust_clickable_areas(double width);
|
||||
double block_x(alignment a) const;
|
||||
double block_y(alignment a) const;
|
||||
double block_w(alignment a) const;
|
||||
|
||||
void highlight_clickable_areas();
|
||||
|
||||
bool on(const signals::ui::request_snapshot& evt);
|
||||
bool on(const signals::parser::change_background& evt);
|
||||
bool on(const signals::parser::change_foreground& evt);
|
||||
bool on(const signals::parser::change_underline& evt);
|
||||
@ -80,9 +90,6 @@ class renderer
|
||||
const logger& m_log;
|
||||
const bar_settings& m_bar;
|
||||
|
||||
xcb_rectangle_t m_rect{0, 0, 0U, 0U};
|
||||
reserve_area m_cleararea{};
|
||||
|
||||
int m_depth{32};
|
||||
xcb_window_t m_window;
|
||||
xcb_colormap_t m_colormap;
|
||||
@ -90,31 +97,32 @@ class renderer
|
||||
xcb_gcontext_t m_gcontext;
|
||||
xcb_pixmap_t m_pixmap;
|
||||
|
||||
vector<action_block> m_actions;
|
||||
xcb_rectangle_t m_rect{0, 0, 0U, 0U};
|
||||
reserve_area m_cleararea{};
|
||||
|
||||
// bool m_autosize{false};
|
||||
|
||||
unique_ptr<cairo::context> m_context;
|
||||
unique_ptr<cairo::surface> m_surface;
|
||||
unique_ptr<cairo::xcb_surface> m_surface;
|
||||
map<alignment, alignment_block> m_blocks;
|
||||
|
||||
cairo_operator_t m_compositing_background;
|
||||
cairo_operator_t m_compositing_foreground;
|
||||
cairo_operator_t m_compositing_overline;
|
||||
cairo_operator_t m_compositing_underline;
|
||||
cairo_operator_t m_compositing_borders;
|
||||
cairo_operator_t m_comp_bg;
|
||||
cairo_operator_t m_comp_fg;
|
||||
cairo_operator_t m_comp_ol;
|
||||
cairo_operator_t m_comp_ul;
|
||||
cairo_operator_t m_comp_border;
|
||||
|
||||
alignment m_alignment{alignment::NONE};
|
||||
std::bitset<2> m_attributes;
|
||||
alignment m_align;
|
||||
std::bitset<3> m_attr;
|
||||
int m_font;
|
||||
unsigned int m_bg;
|
||||
unsigned int m_fg;
|
||||
unsigned int m_ol;
|
||||
unsigned int m_ul;
|
||||
vector<action_block> m_actions;
|
||||
|
||||
int m_fontindex;
|
||||
|
||||
unsigned int m_color_background;
|
||||
unsigned int m_color_foreground;
|
||||
unsigned int m_color_overline;
|
||||
unsigned int m_color_underline;
|
||||
|
||||
double m_x{0.0};
|
||||
double m_y{0.0};
|
||||
bool m_fixedcenter;
|
||||
string m_snapshot_dst;
|
||||
};
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -39,17 +39,7 @@ enum class syntaxtag {
|
||||
u, // underline color
|
||||
};
|
||||
|
||||
enum class mousebtn {
|
||||
NONE = 0,
|
||||
LEFT,
|
||||
MIDDLE,
|
||||
RIGHT,
|
||||
SCROLL_UP,
|
||||
SCROLL_DOWN,
|
||||
DOUBLE_LEFT,
|
||||
DOUBLE_MIDDLE,
|
||||
DOUBLE_RIGHT
|
||||
};
|
||||
enum class mousebtn { NONE = 0, LEFT, MIDDLE, RIGHT, SCROLL_UP, SCROLL_DOWN, DOUBLE_LEFT, DOUBLE_MIDDLE, DOUBLE_RIGHT };
|
||||
|
||||
enum class strut {
|
||||
LEFT = 0,
|
||||
|
@ -111,6 +111,9 @@ namespace signals {
|
||||
struct unshade_window : public detail::base_signal<unshade_window> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
struct request_snapshot : public detail::value_signal<request_snapshot, string> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
}
|
||||
|
||||
namespace ui_tray {
|
||||
|
@ -35,6 +35,7 @@ namespace signals {
|
||||
struct dim_window;
|
||||
struct shade_window;
|
||||
struct unshade_window;
|
||||
struct request_snapshot;
|
||||
}
|
||||
namespace ui_tray {
|
||||
struct mapped_clients;
|
||||
|
@ -208,7 +208,7 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
|
||||
m_opts.foreground = parse_or_throw("foreground", color_util::hex<uint16_t>(m_opts.foreground));
|
||||
|
||||
// Load over-/underline
|
||||
auto line_color = m_conf.get(bs, "line-color", "#f00"s);
|
||||
auto line_color = m_conf.get(bs, "line-color", "#ffff0000"s);
|
||||
auto line_size = m_conf.get(bs, "line-size", 0);
|
||||
|
||||
m_opts.overline.size = m_conf.get(bs, "overline-size", line_size);
|
||||
@ -217,7 +217,7 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
|
||||
m_opts.underline.color = parse_or_throw("underline-color", line_color);
|
||||
|
||||
// Load border settings
|
||||
auto border_color = m_conf.get(bs, "border-color", ""s);
|
||||
auto border_color = m_conf.get(bs, "border-color", "#00000000"s);
|
||||
auto border_size = m_conf.get(bs, "border-size", 0);
|
||||
|
||||
m_opts.borders.emplace(edge::TOP, border_settings{});
|
||||
@ -494,11 +494,13 @@ void bar::handle(const evt::destroy_notify& evt) {
|
||||
* _NET_WM_WINDOW_OPACITY atom value
|
||||
*/
|
||||
void bar::handle(const evt::enter_notify&) {
|
||||
#if 0
|
||||
#ifdef DEBUG_SHADED
|
||||
if (m_opts.origin == edge::TOP) {
|
||||
m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(signals::ui::unshade_window{}); });
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (m_opts.dimmed) {
|
||||
@ -518,11 +520,13 @@ void bar::handle(const evt::enter_notify&) {
|
||||
* _NET_WM_WINDOW_OPACITY atom value
|
||||
*/
|
||||
void bar::handle(const evt::leave_notify&) {
|
||||
#if 0
|
||||
#ifdef DEBUG_SHADED
|
||||
if (m_opts.origin == edge::TOP) {
|
||||
m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(signals::ui::shade_window{}); });
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!m_opts.dimmed) {
|
||||
|
@ -47,10 +47,10 @@ string builder::flush() {
|
||||
if (m_tags[syntaxtag::u]) {
|
||||
underline_color_close();
|
||||
}
|
||||
if ((m_attributes >> static_cast<int>(attribute::UNDERLINE)) & 1U) {
|
||||
if ((m_attributes >> static_cast<int>(attribute::UNDERLINE)) & 1) {
|
||||
underline_close();
|
||||
}
|
||||
if ((m_attributes >> static_cast<int>(attribute::OVERLINE)) & 1U) {
|
||||
if ((m_attributes >> static_cast<int>(attribute::OVERLINE)) & 1) {
|
||||
overline_close();
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "x11/tray_manager.hpp"
|
||||
#include "x11/types.hpp"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
array<int, 2> g_eventpipe{{-1, -1}};
|
||||
@ -37,6 +39,10 @@ void interrupt_handler(int signum) {
|
||||
}
|
||||
}
|
||||
|
||||
void handler(int signum) {
|
||||
printf("atestin %i\n", signum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build controller instance
|
||||
*/
|
||||
@ -141,15 +147,25 @@ controller::~controller() {
|
||||
m_log.info("Deconstruction of %s took %lu ms.", module_name, cleanup_ms);
|
||||
}
|
||||
}
|
||||
|
||||
m_log.trace("controller: Joining threads");
|
||||
for (auto&& t : m_threads) {
|
||||
if (t.joinable()) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the main loop
|
||||
*/
|
||||
bool controller::run(bool writeback) {
|
||||
bool controller::run(bool writeback, string snapshot_dst) {
|
||||
m_log.info("Starting application");
|
||||
assert(!m_connection.connection_has_error());
|
||||
|
||||
m_writeback = writeback;
|
||||
m_snapshot_dst = move(snapshot_dst);
|
||||
|
||||
m_sig.attach(this);
|
||||
|
||||
size_t started_modules{0};
|
||||
@ -434,6 +450,7 @@ bool controller::process_update(bool force) {
|
||||
bool is_left = false;
|
||||
bool is_center = false;
|
||||
bool is_right = false;
|
||||
bool is_first = true;
|
||||
|
||||
if (block.first == alignment::LEFT) {
|
||||
is_left = true;
|
||||
@ -448,7 +465,14 @@ bool controller::process_update(bool force) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string module_contents{module->contents()};
|
||||
string module_contents;
|
||||
|
||||
try {
|
||||
module_contents = module->contents();
|
||||
} catch (const exception& err) {
|
||||
m_log.err("Failed to get contents for \"%s\" (err: %s)", module->name(), err.what());
|
||||
}
|
||||
|
||||
if (module_contents.empty()) {
|
||||
continue;
|
||||
}
|
||||
@ -461,12 +485,14 @@ bool controller::process_update(bool force) {
|
||||
block_contents += separator;
|
||||
}
|
||||
|
||||
if (!block_contents.empty() && !margin_left.empty() && !(is_left && module == block.second.front())) {
|
||||
if (!block_contents.empty() && !margin_left.empty() && !(is_left && is_first)) {
|
||||
block_contents += margin_left;
|
||||
}
|
||||
|
||||
block_contents.reserve(module_contents.size());
|
||||
block_contents += module_contents;
|
||||
|
||||
is_first = false;
|
||||
}
|
||||
|
||||
if (block_contents.empty()) {
|
||||
@ -558,6 +584,15 @@ bool controller::on(const signals::eventqueue::check_state&) {
|
||||
bool controller::on(const signals::ui::ready&) {
|
||||
m_process_events = true;
|
||||
enqueue(make_update_evt(true));
|
||||
|
||||
if (!m_snapshot_dst.empty()) {
|
||||
m_threads.emplace_back(thread([&]{
|
||||
this_thread::sleep_for(3s);
|
||||
m_sig.emit(signals::ui::request_snapshot{move(m_snapshot_dst)});
|
||||
enqueue(make_update_evt(true));
|
||||
}));
|
||||
}
|
||||
|
||||
// let the event bubble
|
||||
return false;
|
||||
}
|
||||
|
@ -92,13 +92,13 @@ renderer::renderer(
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
m_log.trace("renderer: Allocate window pixmap");
|
||||
m_log.trace("renderer: Allocate window pixmaps");
|
||||
{
|
||||
m_pixmap = m_connection.generate_id();
|
||||
m_connection.create_pixmap(m_depth, m_pixmap, m_window, m_bar.size.w, m_bar.size.h);
|
||||
}
|
||||
|
||||
m_log.trace("renderer: Allocate graphic context");
|
||||
m_log.trace("renderer: Allocate graphic contexts");
|
||||
{
|
||||
unsigned int mask{0};
|
||||
unsigned int value_list[32]{0};
|
||||
@ -110,10 +110,23 @@ renderer::renderer(
|
||||
m_connection.create_gc(m_gcontext, m_pixmap, mask, value_list);
|
||||
}
|
||||
|
||||
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_log.trace("renderer: Allocate cairo components");
|
||||
{
|
||||
m_surface = make_unique<cairo::xcb_surface>(m_connection, m_pixmap, m_visual, m_bar.size.w, m_bar.size.h);
|
||||
m_context = make_unique<cairo::context>(*m_surface.get(), m_log);
|
||||
m_context = make_unique<cairo::context>(*m_surface, m_log);
|
||||
}
|
||||
|
||||
m_log.trace("renderer: Load fonts");
|
||||
@ -138,16 +151,13 @@ renderer::renderer(
|
||||
}
|
||||
}
|
||||
|
||||
m_compositing_background =
|
||||
cairo::utils::str2operator(m_conf.get("settings", "compositing-background", ""s), CAIRO_OPERATOR_SOURCE);
|
||||
m_compositing_foreground =
|
||||
cairo::utils::str2operator(m_conf.get("settings", "compositing-foreground", ""s), CAIRO_OPERATOR_OVER);
|
||||
m_compositing_overline =
|
||||
cairo::utils::str2operator(m_conf.get("settings", "compositing-overline", ""s), CAIRO_OPERATOR_OVER);
|
||||
m_compositing_underline =
|
||||
cairo::utils::str2operator(m_conf.get("settings", "compositing-underline", ""s), CAIRO_OPERATOR_OVER);
|
||||
m_compositing_borders =
|
||||
cairo::utils::str2operator(m_conf.get("settings", "compositing-border", ""s), CAIRO_OPERATOR_SOURCE);
|
||||
m_comp_bg = cairo::utils::str2operator(m_conf.get("settings", "compositing-background", ""s), CAIRO_OPERATOR_SOURCE);
|
||||
m_comp_fg = cairo::utils::str2operator(m_conf.get("settings", "compositing-foreground", ""s), CAIRO_OPERATOR_OVER);
|
||||
m_comp_ol = cairo::utils::str2operator(m_conf.get("settings", "compositing-overline", ""s), CAIRO_OPERATOR_OVER);
|
||||
m_comp_ul = cairo::utils::str2operator(m_conf.get("settings", "compositing-underline", ""s), CAIRO_OPERATOR_OVER);
|
||||
m_comp_border = cairo::utils::str2operator(m_conf.get("settings", "compositing-border", ""s), CAIRO_OPERATOR_SOURCE);
|
||||
|
||||
m_fixedcenter = m_conf.get(m_conf.section(), "fixed-center", true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,27 +189,22 @@ void renderer::begin() {
|
||||
|
||||
// Reset state
|
||||
m_actions.clear();
|
||||
m_attributes.reset();
|
||||
m_alignment = alignment::NONE;
|
||||
m_attr.reset();
|
||||
m_align = alignment::NONE;
|
||||
m_rect = m_bar.inner_area();
|
||||
m_x = 0.0;
|
||||
|
||||
// Reset colors
|
||||
m_color_background = 0;
|
||||
m_color_foreground = m_bar.foreground;
|
||||
m_color_underline = m_bar.underline.color;
|
||||
m_color_overline = m_bar.overline.color;
|
||||
m_bg = 0;
|
||||
m_fg = m_bar.foreground;
|
||||
m_ul = m_bar.underline.color;
|
||||
m_ol = m_bar.overline.color;
|
||||
|
||||
m_context->save();
|
||||
|
||||
// Clear canvas
|
||||
m_context->save();
|
||||
*m_context << CAIRO_OPERATOR_SOURCE;
|
||||
*m_context << rgba{0.0, 0.0, 0.0, 0.0};
|
||||
m_context->paint();
|
||||
m_context->restore();
|
||||
m_surface->set_drawable(m_pixmap, m_bar.size.w, m_bar.size.h);
|
||||
m_context->clear();
|
||||
|
||||
m_context->save();
|
||||
|
||||
fill_background();
|
||||
fill_borders();
|
||||
|
||||
// clang-format off
|
||||
@ -209,6 +214,8 @@ void renderer::begin() {
|
||||
static_cast<double>(m_rect.width),
|
||||
static_cast<double>(m_rect.height)});
|
||||
// clang-format on
|
||||
|
||||
fill_background();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -217,10 +224,30 @@ void renderer::begin() {
|
||||
void renderer::end() {
|
||||
m_log.trace_x("renderer: end");
|
||||
|
||||
highlight_clickable_areas();
|
||||
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_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();
|
||||
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;
|
||||
}
|
||||
|
||||
m_context->restore();
|
||||
m_surface->flush();
|
||||
|
||||
flush();
|
||||
}
|
||||
@ -231,6 +258,31 @@ void renderer::end() {
|
||||
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
|
||||
#ifdef DEBUG_SHADED
|
||||
if (m_bar.shaded && m_bar.origin == edge::TOP) {
|
||||
m_log.trace_x(
|
||||
@ -246,11 +298,54 @@ void renderer::flush() {
|
||||
m_connection.flush();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
m_log.trace_x("renderer: copy pixmap (geom=%dx%d+%d+%d)", m_rect.width, m_rect.height, m_rect.x, m_rect.y);
|
||||
m_connection.copy_area(m_pixmap, m_window, m_gcontext, 0, 0, 0, 0, m_bar.size.w, m_bar.size.h);
|
||||
m_connection.flush();
|
||||
|
||||
if (!m_snapshot_dst.empty()) {
|
||||
try {
|
||||
m_surface->write_png(m_snapshot_dst);
|
||||
m_log.info("Successfully wrote %s", m_snapshot_dst);
|
||||
} catch (const exception& err) {
|
||||
m_log.err("Failed to write snapshot (err: %s)", err.what());
|
||||
}
|
||||
m_snapshot_dst.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get x position of block for given alignment
|
||||
*/
|
||||
double renderer::block_x(alignment a) const {
|
||||
switch (a) {
|
||||
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));
|
||||
} 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));
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get y position of block for given alignment
|
||||
*/
|
||||
double renderer::block_y(alignment) const {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block width for given alignment
|
||||
*/
|
||||
double renderer::block_w(alignment a) const {
|
||||
return m_blocks.at(a).x;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -293,7 +388,7 @@ void renderer::reserve_space(edge side, unsigned int w) {
|
||||
*/
|
||||
void renderer::fill_background() {
|
||||
m_context->save();
|
||||
*m_context << m_compositing_background;
|
||||
*m_context << m_comp_bg;
|
||||
|
||||
if (m_bar.radius != 0.0) {
|
||||
// clang-format off
|
||||
@ -326,11 +421,11 @@ void renderer::fill_background() {
|
||||
* Fill overline color
|
||||
*/
|
||||
void renderer::fill_overline(double x, double w) {
|
||||
if (m_bar.overline.size && m_attributes.test(static_cast<int>(attribute::OVERLINE))) {
|
||||
if (m_bar.overline.size && m_attr.test(static_cast<int>(attribute::OVERLINE))) {
|
||||
m_log.trace_x("renderer: overline(x=%f, w=%f)", x, w);
|
||||
m_context->save();
|
||||
*m_context << m_compositing_overline;
|
||||
*m_context << m_color_overline;
|
||||
*m_context << m_comp_ol;
|
||||
*m_context << m_ol;
|
||||
*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();
|
||||
@ -341,11 +436,11 @@ 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_attributes.test(static_cast<int>(attribute::UNDERLINE))) {
|
||||
if (m_bar.underline.size && m_attr.test(static_cast<int>(attribute::UNDERLINE))) {
|
||||
m_log.trace_x("renderer: underline(x=%f, w=%f)", x, w);
|
||||
m_context->save();
|
||||
*m_context << m_compositing_underline;
|
||||
*m_context << m_color_underline;
|
||||
*m_context << m_comp_ul;
|
||||
*m_context << m_ul;
|
||||
*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();
|
||||
@ -358,7 +453,7 @@ void renderer::fill_underline(double x, double w) {
|
||||
*/
|
||||
void renderer::fill_borders() {
|
||||
m_context->save();
|
||||
*m_context << m_compositing_borders;
|
||||
*m_context << m_comp_border;
|
||||
|
||||
cairo::rect top{0.0, 0.0, 0.0, 0.0};
|
||||
top.x += m_bar.borders.at(edge::LEFT).size;
|
||||
@ -397,54 +492,44 @@ void renderer::fill_borders() {
|
||||
void renderer::draw_text(const string& contents) {
|
||||
m_log.trace_x("renderer: text(%s)", contents.c_str());
|
||||
|
||||
cairo::abspos origin{static_cast<double>(m_rect.x), static_cast<double>(m_rect.y)};
|
||||
origin.y += m_rect.height / 2.0;
|
||||
cairo::abspos origin{};
|
||||
origin.x = m_rect.x + m_blocks[m_align].x;
|
||||
origin.y = m_rect.y + m_rect.height / 2.0;
|
||||
|
||||
if (m_alignment == alignment::CENTER) {
|
||||
origin.x += m_rect.width / 2.0;
|
||||
// adjust_clickable_areas(extents.width / 2.0);
|
||||
} else if (m_alignment == alignment::RIGHT) {
|
||||
origin.x += m_rect.width;
|
||||
// adjust_clickable_areas(extents.width);
|
||||
} else {
|
||||
origin.x += m_x;
|
||||
cairo::textblock block{};
|
||||
block.align = m_align;
|
||||
block.contents = contents;
|
||||
block.fontindex = m_font;
|
||||
block.bg = 0;
|
||||
block.bg_rect = cairo::rect{0.0, 0.0, 0.0, 0.0};
|
||||
block.bg_operator = 0;
|
||||
block.x_advance = &m_blocks[m_align].x;
|
||||
block.y_advance = &m_blocks[m_align].y;
|
||||
|
||||
if (m_bg && m_bg != m_bar.background) {
|
||||
block.bg = m_bg;
|
||||
block.bg_operator = m_comp_bg;
|
||||
block.bg_rect.x = m_rect.x + m_blocks[m_align].x;
|
||||
block.bg_rect.y = m_rect.y;
|
||||
block.bg_rect.h = m_rect.height;
|
||||
}
|
||||
|
||||
// if (m_color_background && m_color_background != m_bar.background) {
|
||||
// m_context->save();
|
||||
// *m_context << m_color_background;
|
||||
// *m_context << m_compositing_background;
|
||||
// *m_context << cairo::rect{origin.x, origin.y, extents.width, static_cast<double>(m_rect.height)};
|
||||
// m_context->fill();
|
||||
// m_context->restore();
|
||||
// }
|
||||
|
||||
m_context->save();
|
||||
*m_context << origin;
|
||||
*m_context << m_compositing_foreground;
|
||||
*m_context << m_color_foreground;
|
||||
*m_context << cairo::textblock{m_alignment, contents, m_fontindex};
|
||||
m_context->position(&m_x, &m_y);
|
||||
*m_context << m_comp_fg;
|
||||
*m_context << m_fg;
|
||||
*m_context << block;
|
||||
m_context->restore();
|
||||
|
||||
fill_underline(origin.x, m_x - origin.x);
|
||||
fill_overline(origin.x, m_x - origin.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move clickable areas position by given delta
|
||||
*/
|
||||
void renderer::adjust_clickable_areas(double delta) {
|
||||
for (auto&& action : m_actions) {
|
||||
if (!action.active && action.align == m_alignment) {
|
||||
action.start_x -= delta;
|
||||
action.end_x -= delta;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw boxes at the location of each created action block
|
||||
* Colorize the bounding box of created action blocks
|
||||
*/
|
||||
void renderer::highlight_clickable_areas() {
|
||||
#ifdef DEBUG_HINTS
|
||||
@ -452,128 +537,132 @@ void renderer::highlight_clickable_areas() {
|
||||
for (auto&& action : m_actions) {
|
||||
if (!action.active) {
|
||||
int n = hint_num.find(action.align)->second++;
|
||||
double x = action.start_x + n * DEBUG_HINTS_OFFSET_X;
|
||||
double y = m_bar.pos.y + m_rect.y + n * DEBUG_HINTS_OFFSET_Y;
|
||||
double x = action.start_x;
|
||||
double y = m_rect.y;
|
||||
double w = action.width();
|
||||
double h = m_rect.height;
|
||||
|
||||
m_context->save();
|
||||
*m_context << CAIRO_OPERATOR_OVERLAY << (n % 2 ? 0x55FF0000 : 0x5500FF00);
|
||||
*m_context << CAIRO_OPERATOR_DIFFERENCE << (n % 2 ? 0xFF00FF00 : 0xFFFF0000);
|
||||
*m_context << cairo::rect{x, y, w, h};
|
||||
m_context->fill();
|
||||
m_context->restore();
|
||||
}
|
||||
}
|
||||
m_surface->flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool renderer::on(const signals::ui::request_snapshot& evt) {
|
||||
m_snapshot_dst = evt.cast();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool renderer::on(const signals::parser::change_background& evt) {
|
||||
const unsigned int color{evt.cast()};
|
||||
if (color != m_color_background) {
|
||||
m_color_background = color;
|
||||
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 unsigned int color{evt.cast()};
|
||||
if (color != m_color_foreground) {
|
||||
m_color_foreground = color;
|
||||
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 unsigned int color{evt.cast()};
|
||||
if (color != m_color_underline) {
|
||||
m_color_underline = color;
|
||||
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 unsigned int color{evt.cast()};
|
||||
if (color != m_color_overline) {
|
||||
m_color_overline = color;
|
||||
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) {
|
||||
m_fontindex = evt.cast();
|
||||
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_alignment) {
|
||||
m_alignment = align;
|
||||
m_x = 0.0;
|
||||
if (align != m_align) {
|
||||
m_log.trace_x("renderer: change_alignment(%i)", static_cast<int>(align));
|
||||
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;
|
||||
}
|
||||
|
||||
bool renderer::on(const signals::parser::offset_pixel& evt) {
|
||||
(void)evt;
|
||||
// m_x += evt.cast();
|
||||
m_log.trace_x("renderer: offset_pixel(%f)", evt.cast());
|
||||
m_blocks[m_align].x += evt.cast();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool renderer::on(const signals::parser::attribute_set& evt) {
|
||||
m_attributes.set(static_cast<int>(evt.cast()), true);
|
||||
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_attributes.set(static_cast<int>(evt.cast()), false);
|
||||
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_attributes.flip(static_cast<int>(evt.cast()));
|
||||
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) {
|
||||
(void)evt;
|
||||
// auto a = evt.cast();
|
||||
// action_block action{};
|
||||
// action.button = a.button == mousebtn::NONE ? mousebtn::LEFT : a.button;
|
||||
// action.align = m_alignment;
|
||||
// action.start_x = m_x;
|
||||
// action.command = string_util::replace_all(a.command, ":", "\\:");
|
||||
// action.active = true;
|
||||
// m_actions.emplace_back(action);
|
||||
auto a = evt.cast();
|
||||
m_log.trace_x("renderer: action_begin(btn=%i, command=%s)", static_cast<int>(a.button), a.command);
|
||||
action_block action{};
|
||||
action.button = a.button == mousebtn::NONE ? mousebtn::LEFT : a.button;
|
||||
action.align = m_align;
|
||||
action.start_x = m_blocks.at(m_align).x;
|
||||
action.command = string_util::replace_all(a.command, ":", "\\:");
|
||||
action.active = true;
|
||||
m_actions.emplace_back(action);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool renderer::on(const signals::parser::action_end& evt) {
|
||||
(void)evt;
|
||||
// auto btn = evt.cast();
|
||||
// int clickable_width = 0;
|
||||
// for (auto action = m_actions.rbegin(); action != m_actions.rend(); action++) {
|
||||
// if (action->active && action->align == m_alignment && action->button == btn) {
|
||||
// switch (action->align) {
|
||||
// case alignment::NONE:
|
||||
// break;
|
||||
// case alignment::LEFT:
|
||||
// action->end_x = m_x;
|
||||
// break;
|
||||
// case alignment::CENTER:
|
||||
// clickable_width = m_x - action->start_x;
|
||||
// action->start_x = m_rect.width / 2 - clickable_width / 2 + action->start_x / 2;
|
||||
// action->end_x = action->start_x + clickable_width;
|
||||
// break;
|
||||
// case alignment::RIGHT:
|
||||
// action->start_x = m_rect.width - m_x + action->start_x;
|
||||
// action->end_x = m_rect.width;
|
||||
// break;
|
||||
// }
|
||||
// action->start_x += m_rect.x;
|
||||
// action->end_x += m_rect.x;
|
||||
// action->active = false;
|
||||
// }
|
||||
// }
|
||||
auto btn = evt.cast();
|
||||
m_log.trace_x("renderer: action_end(btn=%i)", static_cast<int>(btn));
|
||||
for (auto action = m_actions.rbegin(); action != m_actions.rend(); action++) {
|
||||
if (action->active && action->align == m_align && action->button == btn) {
|
||||
action->end_x = m_blocks.at(action->align).x;
|
||||
action->active = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
auto ctrl = controller::make(move(ipc), move(config_watch));
|
||||
|
||||
if (!ctrl->run(cli->has("stdout"))) {
|
||||
if (!ctrl->run(cli->has("stdout"), cli->get("png"))) {
|
||||
reload = true;
|
||||
}
|
||||
} catch (const exception& err) {
|
||||
|
Loading…
Reference in New Issue
Block a user