fix(app): build waybar output with nlohmann/json, not format strings

The hand-rolled std::format strings embedded literal newline and
Unicode characters via C++ universal character name escapes (\u23f8,
\u2014, \u25b6, \n), which the compiler converts to actual control
characters in the output. Raw newlines inside JSON strings are
invalid, so waybar's parser failed and displayed the raw JSON text
instead of the widget. Build the status line with nlohmann::json,
which escapes everything correctly.
This commit is contained in:
2026-09-08 20:51:24 +02:00
parent 5c39662cc2
commit eb86905e67
+25 -10
View File
@@ -7,6 +7,8 @@
#include "screencast/network/discovery.h" #include "screencast/network/discovery.h"
#include "screencast/network/signaling.h" #include "screencast/network/signaling.h"
#include <nlohmann/json.hpp>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
@@ -205,10 +207,19 @@ void spawn_detached_sender(const std::string& peer, int bitrate_kbps) {
void print_waybar_status() { void print_waybar_status() {
const auto state = sc::read_sender_state(); const auto state = sc::read_sender_state();
// Built with nlohmann::json so all escaping (newlines in tooltips,
// non-ASCII characters) is handled correctly. Hand-rolled format
// strings produced literal control characters that broke waybar's
// JSON parser.
nlohmann::json json = nlohmann::json::object();
if (!state.has_value()) { if (!state.has_value()) {
std::cout << std::format("{{\"text\":\"\u23f8\",\"alt\":\"idle\",\"class\":\"idle\"," json["text"] = "\u23f8"; // pause symbol
"\"tooltip\":\"screencast idle \u2014 click to stream to the last receiver\n" json["alt"] = "idle";
"right-click: open the panel\"}}\n"); json["class"] = "idle";
json["tooltip"] = "screencast idle \u2014 click to stream to the last receiver\nright-click: open the panel";
std::cout << json.dump() << '\n';
return; return;
} }
@@ -218,13 +229,17 @@ void print_waybar_status() {
state->started_epoch_ms; state->started_epoch_ms;
const std::int64_t minutes = elapsed_ms / 60000; const std::int64_t minutes = elapsed_ms / 60000;
const std::int64_t seconds = (elapsed_ms / 1000) % 60; const std::int64_t seconds = (elapsed_ms / 1000) % 60;
std::cout << std::format("{{\"text\":\"\u25b6\",\"alt\":\"streaming\",\"class\":\"streaming\","
"\"tooltip\":\"screencast \u2192 {}\\n{} kbps \u00b7 {}m {:02}s\\nsession {}\"}}\n", json["text"] = "\u25b6"; // play symbol
state->receiver, json["alt"] = "streaming";
state->bitrate_kbps, json["class"] = "streaming";
minutes, json["tooltip"] = std::format("screencast \u2192 {}\n{} kbps \u00b7 {}m {:02}s\nsession {}",
seconds, state->receiver,
state->session_id); state->bitrate_kbps,
minutes,
seconds,
state->session_id);
std::cout << json.dump() << '\n';
} }
int run_waybar(const sc::WaybarCommand& command) { int run_waybar(const sc::WaybarCommand& command) {