From 7298730969f1501ae76c187c33b37aadc19e0d73 Mon Sep 17 00:00:00 2001 From: Raphael Robatsch Date: Mon, 25 Oct 2021 19:02:35 +0200 Subject: [PATCH] dont deadlock while receiving events --- .../net-tapesoftware-dwl-wm-unstable-v1.xml | 6 + src/bar.cpp | 46 ++++--- src/bar.hpp | 8 +- src/common.hpp | 16 +++ src/main.cpp | 114 +++++++++++------- src/shm_buffer.cpp | 13 +- src/shm_buffer.hpp | 11 +- 7 files changed, 134 insertions(+), 80 deletions(-) diff --git a/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml b/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml index 967a729..7c957bc 100644 --- a/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml +++ b/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml @@ -66,6 +66,12 @@ + + + + + + diff --git a/src/bar.cpp b/src/bar.cpp index 8294522..c61154e 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -27,25 +27,25 @@ static QFont getFont() font.setBold(fontBold); return font; } +static QFont font = getFont(); +static QFontMetrics fontMetrics = QFontMetrics {font}; Bar::Bar(const wl_output *output) - : _font {getFont()} - , _fontMetrics {_font} { - _surface = wl_compositor_create_surface(compositor); - _layerSurface = zwlr_layer_shell_v1_get_layer_surface(wlrLayerShell, - _surface, nullptr, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "net.tapesoftware.Somebar"); - zwlr_layer_surface_v1_add_listener(_layerSurface, &_layerSurfaceListener, this); + _surface.reset(wl_compositor_create_surface(compositor)); + _layerSurface.reset(zwlr_layer_shell_v1_get_layer_surface(wlrLayerShell, + _surface.get(), nullptr, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "net.tapesoftware.Somebar")); + zwlr_layer_surface_v1_add_listener(_layerSurface.get(), &_layerSurfaceListener, this); auto anchor = topbar ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - zwlr_layer_surface_v1_set_anchor(_layerSurface, + zwlr_layer_surface_v1_set_anchor(_layerSurface.get(), anchor | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); - auto barSize = _fontMetrics.ascent() + _fontMetrics.descent() + paddingY * 2; - _textY = _fontMetrics.ascent() + paddingY; + auto barSize = fontMetrics.ascent() + fontMetrics.descent() + paddingY * 2; + _textY = fontMetrics.ascent() + paddingY; - zwlr_layer_surface_v1_set_size(_layerSurface, 0, barSize); - zwlr_layer_surface_v1_set_exclusive_zone(_layerSurface, barSize); - wl_surface_commit(_surface); + zwlr_layer_surface_v1_set_size(_layerSurface.get(), 0, barSize); + zwlr_layer_surface_v1_set_exclusive_zone(_layerSurface.get(), barSize); + wl_surface_commit(_surface.get()); for (auto tag : tagNames) { _tags.push_back({ tag, false }); @@ -54,11 +54,7 @@ Bar::Bar(const wl_output *output) _status = "Status"; } -Bar::~Bar() -{ - wl_surface_destroy(_surface); - zwlr_layer_surface_v1_destroy(_layerSurface); -} +const wl_surface* Bar::surface() const { return _surface.get(); } void Bar::click(int x, int) { @@ -75,9 +71,9 @@ void Bar::invalidate() { if (_invalid) return; _invalid = true; - auto frame = wl_surface_frame(_surface); + auto frame = wl_surface_frame(_surface.get()); wl_callback_add_listener(frame, &_frameListener, this); - wl_surface_commit(_surface); + wl_surface_commit(_surface.get()); } void Bar::setStatus(const QString &status) @@ -88,7 +84,7 @@ void Bar::setStatus(const QString &status) void Bar::layerSurfaceConfigure(uint32_t serial, uint32_t width, uint32_t height) { - zwlr_layer_surface_v1_ack_configure(_layerSurface, serial); + zwlr_layer_surface_v1_ack_configure(_layerSurface.get(), serial); _bufs.emplace(width, height, WL_SHM_FORMAT_XRGB8888); render(); } @@ -105,7 +101,7 @@ void Bar::render() auto painter = QPainter {&img}; _painter = &painter; _x = 0; - painter.setFont(_font); + painter.setFont(font); setColorScheme(colorActive); painter.fillRect(0, 0, img.width(), img.height(), painter.brush()); @@ -115,9 +111,9 @@ void Bar::render() renderStatus(); _painter = nullptr; - wl_surface_attach(_surface, _bufs->buffer(), 0, 0); - wl_surface_damage(_surface, 0, 0, INT_MAX, INT_MAX); - wl_surface_commit(_surface); + wl_surface_attach(_surface.get(), _bufs->buffer(), 0, 0); + wl_surface_damage(_surface.get(), 0, 0, INT_MAX, INT_MAX); + wl_surface_commit(_surface.get()); _bufs->flip(); _invalid = false; } @@ -156,5 +152,5 @@ void Bar::renderStatus() int Bar::textWidth(const QString &text) { - return _fontMetrics.size(Qt::TextSingleLine, text).width(); + return fontMetrics.size(Qt::TextSingleLine, text).width(); } diff --git a/src/bar.hpp b/src/bar.hpp index f60588c..f904e2f 100644 --- a/src/bar.hpp +++ b/src/bar.hpp @@ -22,11 +22,9 @@ class Bar { static const zwlr_layer_surface_v1_listener _layerSurfaceListener; static const wl_callback_listener _frameListener; - wl_surface *_surface {nullptr}; - zwlr_layer_surface_v1 *_layerSurface {nullptr}; + wl_unique_ptr _surface; + wl_unique_ptr _layerSurface; QPainter *_painter {nullptr}; - QFont _font; - QFontMetrics _fontMetrics; std::optional _bufs; int _textY, _x; bool _invalid {false}; @@ -45,7 +43,7 @@ class Bar { void invalidate(); public: explicit Bar(const wl_output *output); + const wl_surface* surface() const; void setStatus(const QString &status); void click(int x, int y); - ~Bar(); }; diff --git a/src/common.hpp b/src/common.hpp index b5bf993..a45bd5f 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -3,10 +3,12 @@ #pragma once #include +#include #include #include #include #include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h" extern wl_display *display; extern wl_compositor *compositor; @@ -17,3 +19,17 @@ extern std::vector tagNames; struct ColorScheme { QColor fg, bg; }; + +// wayland smart pointers +template +struct wl_deleter; +#define WL_DELETER(type, fn) template<> struct wl_deleter { void operator()(type *v) { if(v) fn(v); } } + +template +using wl_unique_ptr = std::unique_ptr>; + +WL_DELETER(wl_surface, wl_surface_destroy); +WL_DELETER(zwlr_layer_surface_v1, zwlr_layer_surface_v1_destroy); +WL_DELETER(wl_buffer, wl_buffer_destroy); +WL_DELETER(wl_output, wl_output_release); +WL_DELETER(znet_tapesoftware_dwl_wm_monitor_v1, znet_tapesoftware_dwl_wm_monitor_v1_release); diff --git a/src/main.cpp b/src/main.cpp index 30572ad..e2db4af 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,8 +24,8 @@ struct Monitor { uint32_t name; - wl_output *wlOutput; - znet_tapesoftware_dwl_wm_monitor_v1 *dwlMonitor; + wl_unique_ptr wlOutput; + wl_unique_ptr dwlMonitor; std::optional bar; }; @@ -42,8 +42,8 @@ wl_shm *shm; zwlr_layer_shell_v1 *wlrLayerShell; znet_tapesoftware_dwl_wm_v1 *dwlWm; std::vector tagNames; +static bool ready; static std::vector monitors; -static std::optional bar; static std::string statusFifoName; static int statusFifoFd {-1}; static int statusFifoWriter {-1}; @@ -57,7 +57,7 @@ static const struct xdg_wm_base_listener xdgWmBaseListener = { } }; -struct PointerState { +struct SeatState { wl_pointer *pointer; wl_surface *cursorSurface; wl_cursor_image *cursorImage; @@ -65,33 +65,40 @@ struct PointerState { int x, y; bool leftButtonClick; }; -static PointerState pointerState; +static SeatState seatState; +static Bar* barFromSurface(const wl_surface *surface) +{ + auto fbar = std::find_if(begin(monitors), end(monitors), [surface](const Monitor &mon) { + return mon.bar && mon.bar->surface() == surface; + }); + return fbar != end(monitors) && fbar->bar ? &*fbar->bar : nullptr; +} static const struct wl_pointer_listener pointerListener = { .enter = [](void*, wl_pointer *pointer, uint32_t serial, - wl_surface*, wl_fixed_t x, wl_fixed_t y) + wl_surface *surface, wl_fixed_t x, wl_fixed_t y) { - pointerState.focusedBar = &bar.value(); - wl_pointer_set_cursor(pointer, serial, pointerState.cursorSurface, - pointerState.cursorImage->hotspot_x, pointerState.cursorImage->hotspot_y); + seatState.focusedBar = barFromSurface(surface); + wl_pointer_set_cursor(pointer, serial, seatState.cursorSurface, + seatState.cursorImage->hotspot_x, seatState.cursorImage->hotspot_y); }, .leave = [](void*, wl_pointer*, uint32_t serial, wl_surface*) { - pointerState.focusedBar = nullptr; + seatState.focusedBar = nullptr; }, .motion = [](void*, wl_pointer*, uint32_t, wl_fixed_t x, wl_fixed_t y) { - pointerState.x = wl_fixed_to_int(x); - pointerState.y = wl_fixed_to_int(y); + seatState.x = wl_fixed_to_int(x); + seatState.y = wl_fixed_to_int(y); }, .button = [](void*, wl_pointer*, uint32_t, uint32_t, uint32_t button, uint32_t pressed) { if (button == BTN_LEFT) { - pointerState.leftButtonClick = pressed == WL_POINTER_BUTTON_STATE_PRESSED; + seatState.leftButtonClick = pressed == WL_POINTER_BUTTON_STATE_PRESSED; } }, .axis = [](void*, wl_pointer*, uint32_t, uint32_t, wl_fixed_t) { }, .frame = [](void*, wl_pointer*) { - if (!pointerState.focusedBar) return; - if (pointerState.leftButtonClick) { - pointerState.leftButtonClick = false; - pointerState.focusedBar->click(pointerState.x, pointerState.y); + if (!seatState.focusedBar) return; + if (seatState.leftButtonClick) { + seatState.leftButtonClick = false; + seatState.focusedBar->click(seatState.x, seatState.y); } }, .axis_source = [](void*, wl_pointer*, uint32_t) { }, @@ -103,16 +110,16 @@ static wl_seat *seat; static const struct wl_seat_listener seatListener = { [](void*, wl_seat*, uint32_t cap) { - if (!pointerState.pointer && WL_SEAT_CAPABILITY_POINTER) { + if (!seatState.pointer && WL_SEAT_CAPABILITY_POINTER) { auto cursorTheme = wl_cursor_theme_load(NULL, 24, shm); auto cursorImage = wl_cursor_theme_get_cursor(cursorTheme, "left_ptr")->images[0]; - pointerState.cursorImage = cursorImage; - pointerState.cursorSurface = wl_compositor_create_surface(compositor); - wl_surface_attach(pointerState.cursorSurface, + seatState.cursorImage = cursorImage; + seatState.cursorSurface = wl_compositor_create_surface(compositor); + wl_surface_attach(seatState.cursorSurface, wl_cursor_image_get_buffer(cursorImage), 0, 0); - wl_surface_commit(pointerState.cursorSurface); - pointerState.pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(pointerState.pointer, &pointerListener, nullptr); + wl_surface_commit(seatState.cursorSurface); + seatState.pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(seatState.pointer, &pointerListener, nullptr); } }, [](void*, wl_seat*, const char *name) { } @@ -125,21 +132,26 @@ static const struct znet_tapesoftware_dwl_wm_v1_listener dwlWmListener = { }; static const struct znet_tapesoftware_dwl_wm_monitor_v1_listener dwlWmMonitorListener { - .tag = [](void*, znet_tapesoftware_dwl_wm_monitor_v1*, int tag, int active, int numClients) { - printf("tag %s: active=%d, num_clients=%d\n", qPrintable(tagNames[tag]), active, numClients); + .tag = [](void*, znet_tapesoftware_dwl_wm_monitor_v1*, int tag, int active, int numClients, int urgent) { + printf("tag %s: active=%d, num_clients=%d, urgent=%d\n", qPrintable(tagNames[tag]), active, numClients, urgent); + }, + .frame = [](void *mv, znet_tapesoftware_dwl_wm_monitor_v1*) { + auto mon = static_cast(mv); + if (!mon->bar) { + mon->bar.emplace(mon->wlOutput.get()); + } } }; -static void setupOutput(Monitor &monitor) { - monitor.dwlMonitor = znet_tapesoftware_dwl_wm_v1_get_monitor(dwlWm, monitor.wlOutput); - znet_tapesoftware_dwl_wm_monitor_v1_add_listener(monitor.dwlMonitor, &dwlWmMonitorListener, &monitor); - monitor.bar.emplace(monitor.wlOutput); +static void setupMonitor(Monitor &monitor) { + monitor.dwlMonitor.reset(znet_tapesoftware_dwl_wm_v1_get_monitor(dwlWm, monitor.wlOutput.get())); + znet_tapesoftware_dwl_wm_monitor_v1_add_listener(monitor.dwlMonitor.get(), &dwlWmMonitorListener, &monitor); } -static void onOutput(int name, wl_output *output) { - auto& monitor = monitors.emplace_back(name, output); - if (dwlWm) { - setupOutput(monitor); +static void onOutput(uint32_t name, wl_output *output) { + auto& m = monitors.emplace_back(Monitor {name, wl_unique_ptr {output}}); + if (ready) { + setupMonitor(m); } } @@ -153,10 +165,9 @@ static void onReady() requireGlobal(dwlWm, "znet_tapesoftware_dwl_wm_v1"); setupStatusFifo(); wl_display_roundtrip(display); // roundtrip so we receive all dwl tags etc. + ready = true; for (auto& monitor : monitors) { - auto monitor = znet_tapesoftware_dwl_wm_v1_get_monitor(dwlWm, output); - printf("created monitor %p for output %p\n", monitor, output); - bar.emplace(output); + setupMonitor(monitor); } } @@ -198,8 +209,10 @@ static void onStatus() char buffer[512]; auto n = read(statusFifoFd, buffer, sizeof(buffer)); auto str = QString::fromUtf8(buffer, n); - if (bar) { - bar->setStatus(str); + for (auto &monitor : monitors) { + if (monitor.bar) { + monitor.bar->setStatus(str); + } } } @@ -230,13 +243,23 @@ static void registryHandleGlobal(void*, wl_registry *registry, uint32_t name, co wl_seat_add_listener(seat, &seatListener, nullptr); } if (wl_output *output; reg.handle(output, wl_output_interface, 1)) { - outputs.push_back(output); + onOutput(name, output); } if (reg.handle(dwlWm, znet_tapesoftware_dwl_wm_v1_interface, 1)) { znet_tapesoftware_dwl_wm_v1_add_listener(dwlWm, &dwlWmListener, nullptr); } } -static const struct wl_registry_listener registry_listener = { registryHandleGlobal, nullptr }; +static void registryHandleRemove(void*, wl_registry *registry, uint32_t name) +{ + auto it = std::find_if(begin(monitors), end(monitors), [name](const Monitor &m) { return m.name == name; }); + if (it != end(monitors)) { + monitors.erase(it); + } +} +static const struct wl_registry_listener registry_listener = { + .global = registryHandleGlobal, + .global_remove = registryHandleRemove, +}; int main(int argc, char **argv) { @@ -273,7 +296,14 @@ int main(int argc, char **argv) QSocketNotifier displayReadNotifier(wl_display_get_fd(display), QSocketNotifier::Read); displayReadNotifier.setEnabled(true); - QObject::connect(&displayReadNotifier, &QSocketNotifier::activated, [=]() { wl_display_dispatch(display); }); + QObject::connect(&displayReadNotifier, &QSocketNotifier::activated, [=]() { + auto res = wl_display_dispatch(display); + if (res < 0) { + perror("wl_display_dispatch"); + cleanup(); + exit(1); + } + }); displayWriteNotifier = new QSocketNotifier(wl_display_get_fd(display), QSocketNotifier::Write); displayWriteNotifier->setEnabled(false); QObject::connect(displayWriteNotifier, &QSocketNotifier::activated, waylandWriteReady); diff --git a/src/shm_buffer.cpp b/src/shm_buffer.cpp index 5c7c7ee..fc16265 100644 --- a/src/shm_buffer.cpp +++ b/src/shm_buffer.cpp @@ -22,20 +22,21 @@ ShmBuffer::ShmBuffer(int w, int h, wl_shm_format format) close(fd); for (auto i=0; i { wl_shm_pool_create_buffer(pool, offset, width, height, stride, format) }, + }; } wl_shm_pool_destroy(pool); } ShmBuffer::~ShmBuffer() { - munmap(_buffers[0].data, _totalSize); - for (auto i=0; i #include +#include "common.hpp" // double buffered shm // format is must be 32-bit class ShmBuffer { struct Buf { uint8_t *data {nullptr}; - wl_buffer *buffer {nullptr}; + wl_unique_ptr buffer; }; std::array _buffers; int _current {0}; size_t _totalSize {0}; public: int width, height, stride; + explicit ShmBuffer(int width, int height, wl_shm_format format); + ShmBuffer(const ShmBuffer&) = delete; + ShmBuffer(ShmBuffer&&) = default; + ShmBuffer& operator=(const ShmBuffer&) = delete; + ShmBuffer& operator=(ShmBuffer&&) = default; + ~ShmBuffer(); + uint8_t* data() const; wl_buffer* buffer() const; void flip(); - ~ShmBuffer(); };