Pipewire for some reason insists on using GTK4 for its UI though, which hangs X cold if you use any of the popovers in it. I didn't even know it was possible to hang X like that.
What do you mean by a Pipewire UI? It's a background daemon (or three: pipewire, a session manager, and pipewire-pulse).
EDIT: Perhaps the parent means Helvum, which ldd says links to libgtk-4.so.1 => /usr/lib/libgtk-4.so.1. However, I can't figure out how to open a popover (https://python-gtk-3-tutorial.readthedocs.io/en/latest/popov...) in the app; all I can do is drag to create or break connections.
Try to set up https://github.com/jaakkopasanen/AutoEq impulse responses for headphones, and you _will_ inevitably hang your X. Daemon isn't terribly useful on its own if you can't set it up to do what you need. So anyone considering Pipewire as a "better" alternative to anything should also know, at a minimum, that it's difficult/impossible to uninstall and buggy AF.
To clarify things, PipeWire is an audio daemon, completely unaffiliated with https://github.com/jaakkopasanen/AutoEq which is a set of headphone impulse responses. It just so happens that the recommended way to apply these impulse responses on Linux is EasyEffects, which now depends on both PipeWire and GTK4. Nonetheless, PipeWire is not EasyEffects and not AutoEq, and "Pipewire for some reason insists on using GTK4 for its UI though" is untrue because EasyEffects is not PipeWire's official GUI, and doesn't even come up when I search `pipewire gui`.
I haven't tested EasyEffects. With that in mind, PipeWire is buggy AF for the time being, and I've been working over the past week to clean things up (fixed a few bugs in plasmashell and pipewire so far, but I'm still learning and there's a great deal of bugs I haven't diagnosed and explained to the maintainers, it will probably take weeks longer for me to work through everything, and I'd very much prefer the program was written to handle race conditions and edge cases properly, instead of leaving users to discover bugs and trace the root cause through the labyrinthine IPC-heavy event-driven codebase after the fact).
My guess is that Pipewire is written in C because the author likes C (or at least somewhat dislikes C++). And it has "abstraction"... in the form of hand-baked vtables and observers created out of nested macros, void*, and intrusive linked lists.
An advantage of C is that it comes with a stable ABI, where Rust is unstable and C++ is a subject of conflict (though you can achieve a stable ABI by restricting your external API to C functions, and if you want cross-shared-object virtual calls like Pipewire, you might have to write the same pile of macros as PipeWire, which you were trying to save yourself from). The downsides are memory and type unsafety (surprisingly the only crash I've seen so far is a null pointer dereference, and I haven't hit any obvious memory or type errors), and a complete absence of "vocabulary" or templated types (they've created their own slotmap-like ID allocator but without a generation count resulting in ever-present "logical use-after-frees" in library and application code, and an intrusive linked list which they use even when hashmaps might provide somewhat faster iteration and asymptotically faster search).
I assumed the C ABI, and thus the cobbled-up vtables. Where the author might have used C++ to advantage would be automating other, internal details of the code. There is nothing quite like bugs you don't have because you didn't need to write the code where they would have been, or because you could run code at compile time to generate or at least verify your cobbled-together apparatus.
The saving grace is that it can at any time be switched over to be built with a C++ compiler, and then start to be modernized incrementally.
What you say is true. Unfortunately I don't think you can trivially switch it to a C++ compiler, because they use {[FOO] = ...} initialization.
It would be cool (not necessarily useful, probably not a good use of time) to rewrite it in Rust while keeping the dependency count in the single digits. It would be helpful to contributors to add architectural documentation.
C++20 added dot initialization, which has been supported in MSVC/GCC/Clang for over a year now. No released version of the C++ standard supports array index initialization, and jcelerier says Clang but not GCC supports it as an extension.