From 7433a1ff990635b7f200c07306d5b69ceaa64a7b Mon Sep 17 00:00:00 2001 From: Raphael Robatsch Date: Thu, 30 Nov 2023 17:11:26 +0100 Subject: [PATCH 1/4] Loosen required zwlr_layer_shell_v1 version Version 1 is enough for somebar. dwl exports version 3 but we don't even need to go that high. --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 6274959..15a749a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -403,7 +403,7 @@ void onGlobalAdd(void*, wl_registry* registry, uint32_t name, const char* interf auto reg = HandleGlobalHelper { registry, name, interface }; if (reg.handle(compositor, wl_compositor_interface, 4)) return; if (reg.handle(shm, wl_shm_interface, 1)) return; - if (reg.handle(wlrLayerShell, zwlr_layer_shell_v1_interface, 4)) return; + if (reg.handle(wlrLayerShell, zwlr_layer_shell_v1_interface, 1)) return; if (reg.handle(xdgOutputManager, zxdg_output_manager_v1_interface, 3)) return; if (reg.handle(xdgWmBase, xdg_wm_base_interface, 2)) { xdg_wm_base_add_listener(xdgWmBase, &xdgWmBaseListener, nullptr); From 6572b98d697fef50473366bf4b598e66c0be3e54 Mon Sep 17 00:00:00 2001 From: jeron Date: Tue, 26 Dec 2023 20:22:13 -0300 Subject: [PATCH 2/4] Fix status bar background color I don't know if this is the best way to do it but this one-liner makes it look exactly like dwm's. Co-authored-by: Raphael Robatsch --- src/bar.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bar.cpp b/src/bar.cpp index af92f49..2f88fa3 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -266,7 +266,11 @@ void Bar::renderStatus() cairo_fill(_painter); _x = start; - renderComponent(_statusCmp); + setColorScheme(colorInactive, false); + if (_statusCmp.width() > 0) + { + renderComponent(_statusCmp); + } } void Bar::setColorScheme(const ColorScheme& scheme, bool invert) From 022248188758eda315b906bcdde4810b1b9638f6 Mon Sep 17 00:00:00 2001 From: Mahesh Asolkar Date: Sun, 18 Feb 2024 11:08:52 -0800 Subject: [PATCH 3/4] Support for DWL IPC v2 * More customizations for indicators --- protocols/dwl-ipc-unstable-v2.xml | 181 ++++++++++++++++++++++++++++++ protocols/meson.build | 1 + src/bar.cpp | 72 ++++++++++-- src/bar.hpp | 4 + src/common.hpp | 12 ++ src/main.cpp | 111 +++++++++++++++++- 6 files changed, 368 insertions(+), 13 deletions(-) create mode 100644 protocols/dwl-ipc-unstable-v2.xml diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml new file mode 100644 index 0000000..0a6e7e5 --- /dev/null +++ b/protocols/dwl-ipc-unstable-v2.xml @@ -0,0 +1,181 @@ + + + + + This protocol allows clients to update and get updates from dwl. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible + changes may be added together with the corresponding interface + version bump. + Backward incompatible changes are done by bumping the version + number in the protocol and interface names and resetting the + interface version. Once the protocol is to be declared stable, + the 'z' prefix and the version number in the protocol and + interface names are removed and the interface version number is + reset. + + + + + This interface is exposed as a global in wl_registry. + + Clients can use this interface to get a dwl_ipc_output. + After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. + The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. + + + + + Indicates that the client will not the dwl_ipc_manager object anymore. + Objects created through this instance are not affected. + + + + + + Get a dwl_ipc_outout for the specified wl_output. + + + + + + + + This event is sent after binding. + A roundtrip after binding guarantees the client recieved all tags. + + + + + + + This event is sent after binding. + A roundtrip after binding guarantees the client recieved all layouts. + + + + + + + + Observe and control a dwl output. + + Events are double-buffered: + Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. + + Request are not double-buffered: + The compositor will update immediately upon request. + + + + + + + + + + + Indicates to that the client no longer needs this dwl_ipc_output. + + + + + + Indicates the client should hide or show themselves. + If the client is visible then hide, if hidden then show. + + + + + + Indicates if the output is active. Zero is invalid, nonzero is valid. + + + + + + + Indicates that a tag has been updated. + + + + + + + + + + Indicates a new layout is selected. + + + + + + + Indicates the title has changed. + + + + + + + Indicates the appid has changed. + + + + + + + Indicates the layout has changed. Since layout symbols are dynamic. + As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. + You can ignore the zdwl_ipc_output.layout event. + + + + + + + Indicates that a sequence of status updates have finished and the client should redraw. + + + + + + + + + + + + The tags are updated as follows: + new_tags = (current_tags AND and_tags) XOR xor_tags + + + + + + + + + + + + + + Indicates if the selected client on this output is fullscreen. + + + + + + + Indicates if the selected client on this output is floating. + + + + + diff --git a/protocols/meson.build b/protocols/meson.build index 7bd222b..0f6f808 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -15,6 +15,7 @@ wayland_xmls = [ wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml', wl_protocol_dir + '/unstable/xdg-output/xdg-output-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml', + 'dwl-ipc-unstable-v2.xml', ] wayland_sources = [ wayland_scanner_code.process(wayland_xmls), diff --git a/src/bar.cpp b/src/bar.cpp index 2f88fa3..b731220 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -87,8 +87,9 @@ Bar::Bar() if (!_pangoContext) { die("pango_font_map_create_context"); } - for (const auto& tagName : tagNames) { - _tags.push_back({ TagState::None, 0, 0, createComponent(tagName) }); + //for (const auto& tagName : tagNames) { + for (int ti = 1; ti < 10; ti++ ) { + _tags.push_back({ TagState::None, 0, 0, createComponent(std::to_string(ti)) }); } _layoutCmp = createComponent(); _titleCmp = createComponent(); @@ -142,6 +143,16 @@ void Bar::setTag(int tag, int state, int numClients, int focusedClient) t.focusedClient = focusedClient; } +uint32_t Bar::getSelectedTagNumClients() +{ + for (auto &tag : _tags) { + if (tag.state == TagState::Active) { + return tag.numClients; + } + } + return 0; +} + void Bar::setSelected(bool selected) { _selected = selected; @@ -241,22 +252,52 @@ void Bar::render() void Bar::renderTags() { for (auto &tag : _tags) { - setColorScheme( - tag.state & TagState::Active ? colorActive : colorInactive, - tag.state & TagState::Urgent); + setTagColorScheme(tag); renderComponent(tag.component); auto indicators = std::min(tag.numClients, static_cast(_bufs->height/2)); - for (auto ind = 0; ind < indicators; ind++) { - 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); + if (showIndicators == 1) { + renderSingleIndicator(tag, indicators); + } else if (showIndicators == 2) { + renderMultiIndicators(tag, indicators); } } } +void Bar::renderMultiIndicators(const Tag& t, int inds) +{ + for (auto ind = 0; ind < inds; ind++) { + auto w = ind == t.focusedClient ? 7 : 3; + cairo_move_to(_painter, t.component.x, ind*2+0.5); + cairo_rel_line_to(_painter, w, 0); + cairo_close_path(_painter); + cairo_set_line_width(_painter, 3); + cairo_stroke(_painter); + } +} + +void Bar::renderSingleIndicator(const Tag& t, int inds) +{ + if (inds > 0) { + auto w = 4; + setColorScheme(colorIndicator); + cairo_move_to(_painter, t.component.x+1, 1); + cairo_rel_line_to(_painter, w, 0); + cairo_rel_line_to(_painter, 0, w); + cairo_rel_line_to(_painter, -w, 0); + cairo_close_path(_painter); + cairo_set_line_width(_painter, 1); + beginFg(); + cairo_stroke_preserve(_painter); + if (t.state == TagState::Active) { + beginBg(); + } else { + setTagColorScheme(t); + beginBg(); + } + cairo_fill(_painter); + } +} + void Bar::renderStatus() { pango_cairo_update_layout(_painter, _statusCmp.pangoLayout.get()); @@ -273,6 +314,13 @@ void Bar::renderStatus() } } +void Bar::setTagColorScheme(const Tag& t) +{ + setColorScheme( + t.state & TagState::Active ? colorActive : colorInactive, + t.state & TagState::Urgent); +} + void Bar::setColorScheme(const ColorScheme& scheme, bool invert) { _colorScheme = invert diff --git a/src/bar.hpp b/src/bar.hpp index 176a1bc..1c45961 100644 --- a/src/bar.hpp +++ b/src/bar.hpp @@ -50,9 +50,12 @@ class Bar { void layerSurfaceConfigure(uint32_t serial, uint32_t width, uint32_t height); void render(); void renderTags(); + void renderMultiIndicators(const Tag& t, int inds); + void renderSingleIndicator(const Tag& t, int inds); void renderStatus(); // low-level rendering + void setTagColorScheme(const Tag& t); void setColorScheme(const ColorScheme& scheme, bool invert = false); void beginFg(); void beginBg(); @@ -65,6 +68,7 @@ public: void show(wl_output* output); void hide(); void setTag(int tag, int state, int numClients, int focusedClient); + uint32_t getSelectedTagNumClients(); void setSelected(bool selected); void setLayout(const std::string& layout); void setTitle(const std::string& title); diff --git a/src/common.hpp b/src/common.hpp index c905358..28e9faf 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -5,11 +5,14 @@ #include #include #include +#include +#include #include #include #include #include #include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "dwl-ipc-unstable-v2-client-protocol.h" struct Color { Color() {} @@ -38,6 +41,14 @@ extern wl_display* display; extern wl_compositor* compositor; extern wl_shm* shm; extern zwlr_layer_shell_v1* wlrLayerShell; +static std::vector tagNames; +static std::vector layoutNames; + +void view(Monitor& m, const Arg& arg); +void toggleview(Monitor& m, const Arg& arg); +void setlayout(Monitor& m, const Arg& arg); +void tag(Monitor& m, const Arg& arg); +void toggletag(Monitor& m, const Arg& arg); void spawn(Monitor&, const Arg& arg); void setCloexec(int fd); @@ -65,6 +76,7 @@ WL_DELETER(wl_output, wl_output_release_checked); WL_DELETER(wl_pointer, wl_pointer_release); WL_DELETER(wl_seat, wl_seat_release); WL_DELETER(wl_surface, wl_surface_destroy); +WL_DELETER(zdwl_ipc_output_v2, zdwl_ipc_output_v2_destroy); WL_DELETER(zwlr_layer_surface_v1, zwlr_layer_surface_v1_destroy); WL_DELETER(cairo_t, cairo_destroy); diff --git a/src/main.cpp b/src/main.cpp index 15a749a..937fd8e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,6 +21,7 @@ #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" +#include "dwl-ipc-unstable-v2-client-protocol.h" #include "common.hpp" #include "config.hpp" #include "bar.hpp" @@ -34,6 +35,7 @@ struct Monitor { bool desiredVisibility {true}; bool hasData; uint32_t tags; + wl_unique_ptr dwlMonitor; }; struct SeatPointer { @@ -67,6 +69,8 @@ wl_display* display; wl_compositor* compositor; wl_shm* shm; zwlr_layer_shell_v1* wlrLayerShell; +zdwl_ipc_manager_v2* dwlWm; +char* log_txt; static xdg_wm_base* xdgWmBase; static zxdg_output_manager_v1* xdgOutputManager; static wl_surface* cursorSurface; @@ -85,6 +89,26 @@ static int statusFifoFd {-1}; static int statusFifoWriter {-1}; static bool quitting {false}; +void view(Monitor& m, const Arg& arg) +{ + zdwl_ipc_output_v2_set_tags(m.dwlMonitor.get(), arg.ui, 1); +} +void toggleview(Monitor& m, const Arg& arg) +{ + zdwl_ipc_output_v2_set_tags(m.dwlMonitor.get(), m.tags ^ arg.ui, 0); +} +void setlayout(Monitor& m, const Arg& arg) +{ + zdwl_ipc_output_v2_set_layout(m.dwlMonitor.get(), arg.ui); +} +void tag(Monitor& m, const Arg& arg) +{ + zdwl_ipc_output_v2_set_client_tags(m.dwlMonitor.get(), 0, arg.ui); +} +void toggletag(Monitor& m, const Arg& arg) +{ + zdwl_ipc_output_v2_set_client_tags(m.dwlMonitor.get(), ~0, arg.ui); +} void spawn(Monitor&, const Arg& arg) { if (fork() == 0) { @@ -189,11 +213,88 @@ static const struct wl_seat_listener seatListener = { .name = [](void*, wl_seat*, const char* name) { } }; +static const struct zdwl_ipc_manager_v2_listener dwlWmListener = { + .tags = [](void*, zdwl_ipc_manager_v2*, uint32_t tag_cnt) { + for (uint32_t ti=0; ti<=tag_cnt; ti++) { + tagNames.push_back(std::to_string(ti)); + } + }, + .layout = [](void*, zdwl_ipc_manager_v2*, const char* name) { + layoutNames.push_back(name); + }, +}; + +static const struct zdwl_ipc_output_v2_listener dwlWmMonitorListener { + .toggle_visibility = [](void* mv, zdwl_ipc_output_v2*) { + }, + .active = [](void* mv, zdwl_ipc_output_v2*, uint32_t active) { + auto mon = static_cast(mv); + if (active) { + selmon = mon; + } else if (selmon == mon) { + selmon = nullptr; + } + mon->bar.setSelected(active); + }, + .tag = [](void* mv, zdwl_ipc_output_v2*, uint32_t tag, uint32_t state, uint32_t numClients, uint32_t focusedClient) { + auto mon = static_cast(mv); + int tagState = TagState::None; + if (state & ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE) + tagState |= TagState::Active; + if (state & ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT) + tagState |= TagState::Urgent; + mon->bar.setTag(tag, tagState, numClients, focusedClient); + uint32_t mask = 1 << tag; + if (tagState & TagState::Active) { + mon->tags |= mask; + } else { + mon->tags &= ~mask; + } + }, + .layout = [](void* mv, zdwl_ipc_output_v2*, uint32_t layout) { + auto mon = static_cast(mv); + if (layout == 2) { + char lout[4] = "[M]"; + uint32_t numc = mon->bar.getSelectedTagNumClients(); + if (numc > 0) { + sprintf(lout, "[%d]", numc); + } + mon->bar.setLayout(lout); + } else { + mon->bar.setLayout(layoutNames[layout]); + } + }, + .title = [](void* mv, zdwl_ipc_output_v2*, const char* title) { + auto mon = static_cast(mv); + mon->bar.setTitle(title); + }, + .appid = [](void* mv, zdwl_ipc_output_v2*, const char* appid) { + //auto mon = static_cast(mv); + }, + .layout_symbol = [](void* mv, zdwl_ipc_output_v2*, const char* layout) { + auto mon = static_cast(mv); + mon->bar.setLayout(layout); + }, + .frame = [](void* mv, zdwl_ipc_output_v2*) { + auto mon = static_cast(mv); + mon->hasData = true; + updatemon(*mon); + }, + .fullscreen = [](void* mv, zdwl_ipc_output_v2*, uint32_t is_fullscreen) { + // auto mon = static_cast(mv); + }, + .floating = [](void* mv, zdwl_ipc_output_v2*, uint32_t is_floating) { + //auto mon = static_cast(mv); + } +}; + void setupMonitor(uint32_t name, wl_output* output) { auto& monitor = monitors.emplace_back(Monitor {name, {}, wl_unique_ptr {output}}); monitor.bar.setStatus(lastStatus); auto xdgOutput = zxdg_output_manager_v1_get_xdg_output(xdgOutputManager, monitor.wlOutput.get()); zxdg_output_v1_add_listener(xdgOutput, &xdgOutputListener, &monitor); + monitor.dwlMonitor.reset(zdwl_ipc_manager_v2_get_output(dwlWm, monitor.wlOutput.get())); + zdwl_ipc_output_v2_add_listener(monitor.dwlMonitor.get(), &dwlWmMonitorListener, &monitor); } void updatemon(Monitor& mon) @@ -219,6 +320,7 @@ void onReady() requireGlobal(shm, "wl_shm"); requireGlobal(wlrLayerShell, "zwlr_layer_shell_v1"); requireGlobal(xdgOutputManager, "zxdg_output_manager_v1"); + requireGlobal(dwlWm, "zdwl_ipc_manager_v2_interface"); setupStatusFifo(); wl_display_roundtrip(display); // roundtrip so we receive all dwl tags etc. @@ -232,7 +334,8 @@ void onReady() bool createFifo(std::string path) { auto result = mkfifo(path.c_str(), 0666); - if (result == 0) { + // if (result == 0) { + if ((result == 0) || (errno == EEXIST)) { auto fd = open(path.c_str(), O_CLOEXEC | O_NONBLOCK | O_RDONLY); if (fd < 0) { diesys("open status fifo reader"); @@ -276,6 +379,7 @@ void setupStatusFifo() static LineBuffer<512> stdinBuffer; static void onStdin() { + return; auto res = stdinBuffer.readLines( [](void* p, size_t size) { return read(0, p, size); }, [](char* p, size_t size) { handleStdin({p, size}); }); @@ -409,6 +513,10 @@ void onGlobalAdd(void*, wl_registry* registry, uint32_t name, const char* interf xdg_wm_base_add_listener(xdgWmBase, &xdgWmBaseListener, nullptr); return; } + if (reg.handle(dwlWm, zdwl_ipc_manager_v2_interface, 1)) { + zdwl_ipc_manager_v2_add_listener(dwlWm, &dwlWmListener, nullptr); + return; + } if (wl_seat* wlSeat; reg.handle(wlSeat, wl_seat_interface, 7)) { auto& seat = seats.emplace_back(Seat {name, wl_unique_ptr {wlSeat}}); wl_seat_add_listener(wlSeat, &seatListener, &seat); @@ -436,6 +544,7 @@ static const struct wl_registry_listener registry_listener = { int main(int argc, char* argv[]) { int opt; + while ((opt = getopt(argc, argv, "chvs:")) != -1) { switch (opt) { case 's': From 566bd7ce9688b893b1ae109d4b9e816aa924477c Mon Sep 17 00:00:00 2001 From: Mahesh Asolkar Date: Sat, 24 Feb 2024 13:34:58 -0800 Subject: [PATCH 4/4] Fixed background color of status component --- src/bar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bar.cpp b/src/bar.cpp index b731220..3bfd7ff 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -307,7 +307,6 @@ void Bar::renderStatus() cairo_fill(_painter); _x = start; - setColorScheme(colorInactive, false); if (_statusCmp.width() > 0) { renderComponent(_statusCmp);