diff --git a/meson.build b/meson.build index b12b3bc..e81761b 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,9 @@ project('somebar', ['c', 'cpp'], wayland_dep = dependency('wayland-client') wayland_cursor_dep = dependency('wayland-cursor') -qt5_dep = dependency('qt5', modules: ['Core', 'Gui']) +cairo_dep = dependency('cairo') +pango_dep = dependency('pango') +pangocairo_dep = dependency('pangocairo') subdir('protocols') @@ -12,4 +14,10 @@ executable('somebar', 'src/shm_buffer.cpp', 'src/bar.cpp', wayland_sources, - dependencies: [wayland_dep, wayland_cursor_dep, qt5_dep]) + dependencies: [ + wayland_dep, + wayland_cursor_dep, + cairo_dep, + pango_dep, + pangocairo_dep, + ]) diff --git a/src/bar.cpp b/src/bar.cpp index 41fa578..09ddd3c 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -1,11 +1,14 @@ -// somebar - dwl bar +// somebar - dwl barbar // See LICENSE file for copyright and license details. -#include -#include -#include +#include +#include #include "bar.hpp" +#include "cairo.h" #include "config.hpp" +#include "pango/pango-font.h" +#include "pango/pango-fontmap.h" +#include "pango/pango-layout.h" const zwlr_layer_surface_v1_listener Bar::_layerSurfaceListener = { [](void *owner, zwlr_layer_surface_v1*, uint32_t serial, uint32_t width, uint32_t height) @@ -21,25 +24,60 @@ const wl_callback_listener Bar::_frameListener = { } }; -static QFont getFont() +struct Font { + PangoFontDescription *description; + int height {0}; +}; +static Font getFont() { - QFont font {fontFamily, fontSizePt}; - font.setBold(fontBold); - return font; -} -static QFont font = getFont(); -static QFontMetrics fontMetrics = QFontMetrics {font}; + auto fontMap = pango_cairo_font_map_get_default(); + auto fontDesc = pango_font_description_from_string(font); + auto tempContext = pango_font_map_create_context(fontMap); + auto font = pango_font_map_load_font(fontMap, tempContext, fontDesc); + auto metrics = pango_font_get_metrics(font, pango_language_get_default()); -const wl_surface* Bar::surface() const { return _surface.get(); } + auto res = Font {}; + res.description = fontDesc; + res.height = PANGO_PIXELS(pango_font_metrics_get_height(metrics)); + + pango_font_metrics_unref(metrics); + g_object_unref(font); + g_object_unref(tempContext); + g_object_unref(fontMap); + return res; +} +static Font barfont = getFont(); + +BarComponent::BarComponent() { } +BarComponent::BarComponent(wl_unique_ptr layout) : pangoLayout {std::move(layout)} {} +int BarComponent::width() const +{ + int w, h; + pango_layout_get_size(pangoLayout.get(), &w, &h); + return PANGO_PIXELS(w); +} +void BarComponent::setText(const std::string &text) +{ + auto chars = new char[text.size()]; + text.copy(chars, text.size()); + _text.reset(chars); + pango_layout_set_text(pangoLayout.get(), chars, text.size()); +} Bar::Bar(Monitor *mon) { _mon = mon; + _pangoContext.reset(pango_font_map_create_context(pango_cairo_font_map_get_default())); for (auto i=0u; i _statusX) { + if (x > _statusCmp.x) { control = ClkStatusText; - } else if (x > _titleX) { + } else if (x > _titleCmp.x) { control = ClkWinTitle; - } else if (x > _layoutX) { + } else if (x > _layoutCmp.x) { control = ClkLayoutSymbol; } else for (auto tag = _tags.size()-1; tag >= 0; tag--) { - if (x > _tags[tag].x) { + if (x > _tags[tag].component.x) { control = ClkTagBar; arg.ui = 1< {cairo_image_surface_create_for_data( _bufs->data(), + CAIRO_FORMAT_ARGB32, _bufs->width, _bufs->height, - _bufs->stride, - QImage::Format_ARGB32 - }; - auto painter = QPainter {&img}; - _painter = &painter; + _bufs->stride + )}; + auto painter = wl_unique_ptr {cairo_create(img.get())}; + _painter = painter.get(); + pango_cairo_update_context(_painter, _pangoContext.get()); _x = 0; - painter.setFont(font); renderTags(); setColorScheme(_selected ? colorActive : colorInactive); - _layoutX = _x; - renderText(layoutNames[_layout]); - _titleX = _x; - renderText(_title); + renderComponent(_layoutCmp); + renderComponent(_titleCmp); renderStatus(); _painter = nullptr; @@ -145,50 +179,68 @@ void Bar::render() _invalid = false; } -void Bar::setColorScheme(const ColorScheme &scheme, bool invert) -{ - _painter->setBrush(QBrush {invert ? scheme.fg : scheme.bg}); - _painter->setPen(QPen {QBrush {invert ? scheme.bg : scheme.fg}, 1}); -} - void Bar::renderTags() { - for (auto i=0u; i<_tags.size(); i++) { - auto& tag = _tags[i]; - tag.x = _x; + for (auto &tag : _tags) { setColorScheme( tag.state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_ACTIVE ? colorActive : colorInactive, tag.state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_URGENT); - renderText(tagNames[i]); - auto indicators = qMin(tag.numClients, _bufs->height/2); + renderComponent(tag.component); + auto indicators = std::min(tag.numClients, _bufs->height/2); for (auto ind = 0; ind < indicators; ind++) { - if (ind == tag.focusedClient) { - _painter->drawLine(tag.x, ind*2, tag.x+5, ind*2); - } else { - _painter->drawPoint(tag.x, ind*2); - } + auto w = ind == tag.focusedClient ? 7 : 1; + cairo_move_to(_painter, tag.component.x, ind*2+0.5); + cairo_rel_line_to(_painter, w, 0); + cairo_close_path(_painter); + cairo_set_line_width(_painter, 1); + cairo_stroke(_painter); } } } -void Bar::renderText(const QString &text) +void Bar::renderStatus() { - auto size = textWidth(text) + paddingX*2; - _painter->fillRect(_x, 0, size, _bufs->height, _painter->brush()); - _painter->drawText(paddingX+_x, _textY, text); + pango_cairo_update_layout(_painter, _statusCmp.pangoLayout.get()); + beginBg(); + auto start = _bufs->width - _statusCmp.width() - paddingX*2; + cairo_rectangle(_painter, _x, 0, _bufs->width-_x+start, _bufs->height); + cairo_fill(_painter); + + _x = start; + renderComponent(_statusCmp); +} + +void Bar::setColorScheme(const ColorScheme &scheme, bool invert) +{ + _colorScheme = invert + ? ColorScheme {scheme.bg, scheme.fg} + : ColorScheme {scheme.fg, scheme.bg}; +} +static void setColor(cairo_t *painter, const Color &color) { cairo_set_source_rgba(painter, color.r/255.0, color.g/255.0, color.b/255.0, color.a/255.0); } +void Bar::beginFg() { setColor(_painter, _colorScheme.fg); } +void Bar::beginBg() { setColor(_painter, _colorScheme.bg); } + +void Bar::renderComponent(BarComponent &component) +{ + pango_cairo_update_layout(_painter, component.pangoLayout.get()); + auto size = component.width() + paddingX*2; + component.x = _x; + + beginBg(); + cairo_rectangle(_painter, _x, 0, size, _bufs->height); + cairo_fill(_painter); + cairo_move_to(_painter, _x+paddingX, paddingY); + + beginFg(); + pango_cairo_show_layout(_painter, component.pangoLayout.get()); _x += size; } -void Bar::renderStatus() +BarComponent Bar::createComponent(const std::string &initial) { - _painter->fillRect(_x, 0, _bufs->width-_x, _bufs->height, _painter->brush()); - auto size = textWidth(_status) + paddingX; - _statusX = _bufs->width - size; - _painter->drawText(paddingX+_statusX, _textY, _status); - _x = _bufs->width; -} - -int Bar::textWidth(const QString &text) -{ - return fontMetrics.size(Qt::TextSingleLine, text).width(); + auto layout = pango_layout_new(_pangoContext.get()); + pango_layout_set_font_description(layout, barfont.description); + auto res = BarComponent {wl_unique_ptr {layout}}; + res.setText(initial); + return res; } diff --git a/src/bar.hpp b/src/bar.hpp index dc48b50..bb0cc33 100644 --- a/src/bar.hpp +++ b/src/bar.hpp @@ -3,20 +3,29 @@ #pragma once #include +#include #include #include -#include -#include -#include #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "common.hpp" #include "shm_buffer.hpp" +class BarComponent { + std::unique_ptr _text; +public: + BarComponent(); + explicit BarComponent(wl_unique_ptr layout); + int width() const; + void setText(const std::string &text); + wl_unique_ptr pangoLayout; + int x {0}; +}; + struct Tag { znet_tapesoftware_dwl_wm_monitor_v1_tag_state state; int numClients; int focusedClient; - int x; + BarComponent component; }; struct Monitor; @@ -26,35 +35,39 @@ class Bar { wl_unique_ptr _surface; wl_unique_ptr _layerSurface; + wl_unique_ptr _pangoContext; Monitor *_mon; - QPainter *_painter {nullptr}; std::optional _bufs; - int _textY, _x; - int _statusX, _titleX, _layoutX; + std::vector _tags; + BarComponent _layoutCmp, _titleCmp, _statusCmp; + bool _selected; bool _invalid {false}; - std::vector _tags; - int _layout; - bool _selected; - QString _title; - QString _status; + // only vaild during render() + cairo_t *_painter {nullptr}; + int _x; + ColorScheme _colorScheme; void layerSurfaceConfigure(uint32_t serial, uint32_t width, uint32_t height); void render(); void renderTags(); void renderStatus(); - void renderText(const QString &text); - int textWidth(const QString &text); + + // low-level rendering void setColorScheme(const ColorScheme &scheme, bool invert=false); + void beginFg(); + void beginBg(); + void renderComponent(BarComponent &component); + BarComponent createComponent(const std::string &initial = {}); public: Bar(Monitor *mon); const wl_surface* surface() const; void create(wl_output *output); - void setSelected(bool selected); void setTag(int tag, znet_tapesoftware_dwl_wm_monitor_v1_tag_state state, int numClients, int focusedClient); + void setSelected(bool selected); void setLayout(int layout); - void setTitle(const char *title); - void setStatus(const QString &status); + void setTitle(const std::string &title); + void setStatus(const std::string &status); void invalidate(); void click(int x, int y, int btn); }; diff --git a/src/common.hpp b/src/common.hpp index 65aea42..f1c568a 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -3,16 +3,22 @@ #pragma once #include +#include #include #include #include -#include -#include +#include +#include #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h" +struct Color { + Color() {} + constexpr Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255) : r(r), g(g), b(b), a(a) { } + uint8_t r, g, b, a {255}; +}; struct ColorScheme { - QColor fg, bg; + Color fg, bg; }; union Arg { unsigned int ui; @@ -32,8 +38,8 @@ extern wl_display *display; extern wl_compositor *compositor; extern wl_shm *shm; extern zwlr_layer_shell_v1 *wlrLayerShell; -extern std::vector tagNames; -extern std::vector layoutNames; +extern std::vector tagNames; +extern std::vector layoutNames; void view(Monitor &m, const Arg &arg); void toggleview(Monitor &m, const Arg &arg); @@ -57,3 +63,9 @@ WL_DELETER(wl_seat, wl_seat_release); WL_DELETER(wl_surface, wl_surface_destroy); WL_DELETER(znet_tapesoftware_dwl_wm_monitor_v1, znet_tapesoftware_dwl_wm_monitor_v1_release); WL_DELETER(zwlr_layer_surface_v1, zwlr_layer_surface_v1_destroy); + +WL_DELETER(cairo_t, cairo_destroy); +WL_DELETER(cairo_surface_t, cairo_surface_destroy); + +WL_DELETER(PangoContext, g_object_unref); +WL_DELETER(PangoLayout, g_object_unref); diff --git a/src/config.hpp b/src/config.hpp index 753d3db..8ef8813 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -9,12 +9,11 @@ constexpr bool topbar = true; constexpr int paddingX = 10; constexpr int paddingY = 3; -constexpr const char *fontFamily = "Source Sans Pro"; -constexpr int fontSizePt = 12; -constexpr bool fontBold = false; +// See https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html +constexpr const char *font = "Source Sans Pro 12"; -constexpr ColorScheme colorInactive = {QColor(0xbb, 0xbb, 0xbb), QColor(0x22, 0x22, 0x22)}; -constexpr ColorScheme colorActive = {QColor(0xee, 0xee, 0xee), QColor(0x00, 0x55, 0x77)}; +constexpr ColorScheme colorInactive = {Color(0xbb, 0xbb, 0xbb), Color(0x22, 0x22, 0x22)}; +constexpr ColorScheme colorActive = {Color(0xee, 0xee, 0xee), Color(0x00, 0x55, 0x77)}; constexpr const char *termcmd[] = {"foot", nullptr}; constexpr Button buttons[] = { diff --git a/src/main.cpp b/src/main.cpp index 87ecbb0..e6491fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,14 @@ // somebar - dwl bar // See LICENSE file for copyright and license details. -#include +#include #include #include #include +#include +#include +#include +#include #include #include #include @@ -12,13 +16,8 @@ #include #include #include -#include -#include -#include #include #include -#include -#include #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" #include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h" @@ -57,15 +56,15 @@ wl_compositor *compositor; wl_shm *shm; zwlr_layer_shell_v1 *wlrLayerShell; znet_tapesoftware_dwl_wm_v1 *dwlWm; -std::vector tagNames; -std::vector layoutNames; +std::vector tagNames; +std::vector layoutNames; static xdg_wm_base *xdgWmBase; static wl_surface *cursorSurface; static wl_cursor_image *cursorImage; static bool ready; static std::list monitors; static std::list seats; -static QString lastStatus; +static std::string lastStatus; static std::string statusFifoName; static int epoll {-1}; static int displayFd {-1}; @@ -277,7 +276,7 @@ static void onStatus() { char buffer[512]; auto n = read(statusFifoFd, buffer, sizeof(buffer)); - lastStatus = QString::fromUtf8(buffer, n); + lastStatus = {buffer, (unsigned long) n}; for (auto &monitor : monitors) { if (monitor.bar) { monitor.bar->setStatus(lastStatus); @@ -343,8 +342,6 @@ int main(int argc, char **argv) sigaddset(&blockedsigs, SIGTERM); sigprocmask(SIG_BLOCK, &blockedsigs, nullptr); - QGuiApplication app {argc, argv}; - epoll_event epollEv = {0}; std::array epollEvents; epoll = epoll_create1(EPOLL_CLOEXEC);