From 4736b8a46262a8b6e951ba564b7b77d8ceef4cdb Mon Sep 17 00:00:00 2001 From: Raphael Robatsch Date: Wed, 27 Oct 2021 18:36:57 +0200 Subject: [PATCH] packaging --- .gitignore | 1 + README.md | 41 ++++++++++++++++++----- meson.build | 9 +++-- screenshot.png | Bin 0 -> 6715 bytes src/config.def.hpp | 2 +- src/main.cpp | 81 +++++++++++++++++++++++++++++++++------------ 6 files changed, 102 insertions(+), 32 deletions(-) create mode 100644 screenshot.png diff --git a/.gitignore b/.gitignore index 02f9372..50d749b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ compile_commands.json build .cache +src/config.hpp diff --git a/README.md b/README.md index b2dd51d..73ec38f 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,58 @@ # somebar - dwl-like bar for dwm -This is extremely work in progress. +![Screenshot](screenshot.png) + +This project is rather new. Beware of bugs. ## Dependencies * c++ compiler, meson, and ninja -* Qt 5 GUI -* libwayland * wayland-scanner +* libwayland-client +* libwayland-cursor +* libcairo +* libpango +* libpangocairo - sudo apt install build-essential meson ninja qtbase5-dev libqt5core5a libqt5gui5 \ - libwayland-bin libwayland-client0 libwayland-cursor0 libwayland-dev +``` +sudo apt install build-essential meson ninja \ + libwayland-bin libwayland-client0 libwayland-cursor0 libwayland-dev \ + libcairo2 libcairo2-dev \ + libpango-1.0-0 libpango1.0-dev libpangocairo-1.0-0 +``` -dwl must have the [wayland-ipc patch](https://gitlab.com/raphaelr/dwl/-/raw/master/patches/wayland-ipc.patch) applied, +**dwl must have the [wayland-ipc patch](https://gitlab.com/raphaelr/dwl/-/raw/master/patches/wayland-ipc.patch) applied**, since that's how the bar communicates with dwl. ## Configuration -src/config.hpp +Copy `src/config.def.hpp` to `src/config.hpp`, and adjust if needed. ## Building meson setup build ninja -C build + ./build/somebar ## Usage somebar doesn't use dwl's status feature. You can start somebar using dwl's `-s` option, -but if you do, close stdout. +but if you do, close stdin, as somebar will not read from it. + +Somebar can be controlled by writing to `$XDG_RUNTIME_DIR/somebar-0`. The following +commands are supported: + +* `status TEXT`: Updates the status bar +* `hide MONITOR` Hides somebar on the specified monitor +* `shows MONITOR` Shows somebar on the specified monitor +* `toggle MONITOR` Toggles somebar on the specified monitor + +MONITOR is an zxdg_output_v1 name, which can be determined e.g. using `weston-info`. +Additionally, MONITOR can be `all` (all monitors) or `selected` (the monitor with focus). + +Commands can be sent either by writing to the file name above, or equivalently by calling +somebar with the `-c` argument. For example: `somebar -c toggle all`. This is recommended +for shell scripts, as there is no race-free way to write to a file only if it exists. ## License diff --git a/meson.build b/meson.build index 4043100..3adaa19 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,9 @@ project('somebar', ['c', 'cpp'], - default_options: ['cpp_std=c++17', 'cpp_args=-Wno-parentheses']) + version: '0.1.0', + default_options: [ + 'cpp_std=c++17', + 'cpp_args=-Wno-parentheses', + ]) wayland_dep = dependency('wayland-client') wayland_cursor_dep = dependency('wayland-cursor') @@ -20,4 +24,5 @@ executable('somebar', cairo_dep, pango_dep, pangocairo_dep, - ]) + ], + cpp_args: '-DSOMEBAR_VERSION="@0@"'.format(meson.project_version())) diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..7a800fbe6783f907f596c4bf26089736d8d9683a GIT binary patch literal 6715 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 literal 0 HcmV?d00001 diff --git a/src/config.def.hpp b/src/config.def.hpp index 38f4909..2af8c14 100644 --- a/src/config.def.hpp +++ b/src/config.def.hpp @@ -22,5 +22,5 @@ constexpr Button buttons[] = { { ClkTagBar, BTN_MIDDLE, toggletag, {0} }, { ClkLayoutSymbol, BTN_LEFT, setlayout, {.ui = 0} }, { ClkLayoutSymbol, BTN_RIGHT, setlayout, {.ui = 2} }, - { ClkWinTitle, BTN_RIGHT, spawn, {.v = termcmd} }, + { ClkStatusText, BTN_RIGHT, spawn, {.v = termcmd} }, }; diff --git a/src/main.cpp b/src/main.cpp index e7f6294..9b4126d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h" #include "common.hpp" #include "bar.hpp" +#include "line_buffer.hpp" struct Monitor { uint32_t registryName; @@ -101,7 +102,7 @@ void toggletag(Monitor &m, const Arg &arg) } void spawn(Monitor&, const Arg &arg) { - if (fork()) { + if (fork() == 0) { auto argv = static_cast(arg.v); setsid(); execvp(argv[0], argv); @@ -334,29 +335,31 @@ static void updateVisibility(const std::string &name, T updater) } } +static LineBuffer<512> _statusBuffer; static void onStatus() { - // this doesn't handle cases where there's multiple or partial lines in the buffer - char buffer[512]; - auto n = read(statusFifoFd, buffer, sizeof(buffer)); - auto str = std::string {buffer, (unsigned long) n}; - auto trailer = str.rfind('\n'); - if (trailer != std::string::npos) str.erase(trailer); - if (str.rfind(prefixStatus, 0) == 0) { - lastStatus = str.substr(prefixStatus.size()); - for (auto &monitor : monitors) { - if (monitor.bar) { - monitor.bar->setStatus(lastStatus); - monitor.bar->invalidate(); + _statusBuffer.readLines( + [](void *p, size_t size) { + return read(statusFifoFd, p, size); + }, + [](const char *buffer, size_t n) { + auto str = std::string {buffer, n}; + if (str.rfind(prefixStatus, 0) == 0) { + lastStatus = str.substr(prefixStatus.size()); + for (auto &monitor : monitors) { + if (monitor.bar) { + monitor.bar->setStatus(lastStatus); + monitor.bar->invalidate(); + } + } + } else if (str.rfind(prefixShow, 0) == 0) { + updateVisibility(str.substr(prefixShow.size()), [](bool) { return true; }); + } else if (str.rfind(prefixHide, 0) == 0) { + updateVisibility(str.substr(prefixHide.size()), [](bool) { return false; }); + } else if (str.rfind(prefixToggle, 0) == 0) { + updateVisibility(str.substr(prefixToggle.size()), [](bool vis) { return !vis; }); } - } - } else if (str.rfind(prefixShow, 0) == 0) { - updateVisibility(str.substr(prefixShow.size()), [](bool) { return true; }); - } else if (str.rfind(prefixHide, 0) == 0) { - updateVisibility(str.substr(prefixHide.size()), [](bool) { return false; }); - } else if (str.rfind(prefixToggle, 0) == 0) { - updateVisibility(str.substr(prefixToggle.size()), [](bool vis) { return !vis; }); - } + }); } struct HandleGlobalHelper { @@ -411,6 +414,41 @@ static const struct wl_registry_listener registry_listener = { int main(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "chv")) != -1) { + switch (opt) { + case 'h': + printf("Usage: %s [-h] [-v] [-c command]\n", argv[0]); + printf(" -h: Show this help\n"); + printf(" -v: Show somebar version\n"); + printf(" -c: Sends a command to sombar. See README for details.\n"); + printf("If any of these are specified, somebar exits after the action.\n"); + printf("Otherwise, somebar will display itself.\n"); + exit(0); + case 'v': + printf("somebar " SOMEBAR_VERSION "\n"); + exit(0); + case 'c': + if (optind >= argc) { + die("Expected command"); + } + auto path = std::string {getenv("XDG_RUNTIME_DIR")} + "/somebar-0"; + int fd = open(path.c_str(), O_WRONLY | O_CLOEXEC); + if (fd < 0) { + fprintf(stderr, "could not open %s: ", path.c_str()); + perror(""); + exit(1); + } + auto str = std::string {}; + for (auto i = optind; i optind) str += " "; + str += argv[i]; + } + str += "\n"; + write(fd, str.c_str(), str.size()); + exit(0); + } + } static sigset_t blockedsigs; sigemptyset(&blockedsigs); sigaddset(&blockedsigs, SIGINT); @@ -506,6 +544,7 @@ void waylandFlush() } void die(const char *why) { + fprintf(stderr, "%s\n", why); cleanup(); exit(1); }