You are not logged in.
You may try something like this:
On Excalibur
Install the Build-Deps
sudo apt build-dep gtk3-nocsdmkdir BUILD
cd BUILDCopy the patch into BUILD
$ ls
add-gtk4-support.patch Download the source into BUILD
apt source gtk3-nocsd $ ls -1
add-gtk4-support.patch
gtk3-nocsd-<version> # it is the sourcedir
...cd to the sourcedir
cd gtk3-nocsd-* Apply the patch
patch -Np1 -i ../add-gtk4-support.patch --verbose _https://www.man7.org/linux/man-pages/man1/patch.1.html
Build the deb package
dpkg-buildpackage -us -uc -b cd ..
ls -1 *.deb EDIT:
It works on Devuan 5 Daedalus
➤ inxi -b | grep Host -A1 Host: devuan Kernel: 6.1.0-37-amd64 arch: x86_64 bits: 64 Desktop: MATE v: 1.26.0 Distro: Devuan GNU/Linux 5 (daedalus)➤ cd gtk3-nocsd-* ➤ patch -Np1 -i ../add-gtk4-support.patch patching file gtk3-nocsd.c ➤ dpkg-buildpackage -us -uc -b ➤ ls -1 ../*.deb ../gtk3-nocsd_3-1_all.deb ../libgtk3-nocsd0_3-1_amd64.deb ../libgtk3-nocsd0-dbgsym_3-1_amd64.deb
greenjeans and other Neo-Luddites may try to patch and rebuild gtk3-nocsd.
Although, of course, it might be difficult to follow the instruction (because of dementia, perhaps).
It might be a test for diagnosing dementia.
Thanks!
➤ dget --extract --allow-unauthenticated https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/gtk3-nocsd/3-1ubuntu3/gtk3-nocsd_3-1ubuntu3.dsc
dget: retrieving https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/gtk3-nocsd/3-1ubuntu3/gtk3-nocsd_3-1ubuntu3.dsc
...
dpkg-source: info: extracting gtk3-nocsd in gtk3-nocsd-3
dpkg-source: info: unpacking gtk3-nocsd_3.orig.tar.gz
dpkg-source: info: unpacking gtk3-nocsd_3-1ubuntu3.debian.tar.xz
dpkg-source: info: using patch list from debian/patches/series
dpkg-source: info: applying debian-specifics-in-manpage.patch
dpkg-source: info: applying add-gtk4-support.patch➤ ls -1
gtk3-nocsd-3
gtk3-nocsd_3-1ubuntu3.debian.tar.xz
gtk3-nocsd_3-1ubuntu3.dsc
gtk3-nocsd_3.orig.tar.gz➤ ls -1 gtk3-nocsd-3/debian/patches
add-gtk4-support.patch
debian-specifics-in-manpage.patch
series➤ cat gtk3-nocsd-3/debian/patches/add-gtk4-support.patch
Description: add some description: Add Gtk4 Support
Imported new upstream version 4 and fixed logic error in gtk_window_set_titlebar
Imported from https://github.com/ZaWertun/gtk3-nocsd
Author: Brett Bogert <bbogert24@gmail.com>
Bug: https://bugs.launchpad.net/ubuntu/+source/gtk3-nocsd/+bug/1946161
--- a/gtk3-nocsd.c
+++ b/gtk3-nocsd.c
@@ -22,6 +22,7 @@
#define _GNU_SOURCE
#include <dlfcn.h>
+#include <link.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
@@ -38,6 +39,16 @@
#include <gobject/gvaluecollector.h>
+#ifdef __FreeBSD__
+#include <sys/elf_generic.h>
+#define ElfW(t) Elf##_##t
+#endif
+
+#ifdef G_TYPE_INSTANCE_GET_PRIVATE
+# undef G_TYPE_INSTANCE_GET_PRIVATE
+#endif
+#define G_TYPE_INSTANCE_GET_PRIVATE(instance, g_type, c_type) ((c_type*) g_type_instance_get_private ((GTypeInstance*) (instance),(g_type)))
+
typedef void (*gtk_window_buildable_add_child_t) (GtkBuildable *buildable, GtkBuilder *builder, GObject *child, const gchar *type);
typedef GObject* (*gtk_dialog_constructor_t) (GType type, guint n_construct_properties, GObjectConstructParam *construct_params);
typedef char *(*gtk_check_version_t) (guint required_major, guint required_minor, guint required_micro);
@@ -111,12 +122,17 @@ static void * volatile library_handles[N
static pthread_key_t key_tls;
static pthread_once_t key_tls_once = PTHREAD_ONCE_INIT;
+/* Marking both as volatile here saves the trouble of caring about
+ * memory barriers. */
+static volatile gboolean is_compatible_gtk_version_cached = FALSE;
+static volatile gboolean is_compatible_gtk_version_checked = FALSE;
+static volatile int gtk2_active;
+
typedef struct gtk3_nocsd_tls_data_t {
// When set to true, this override gdk_screen_is_composited() and let it
// return FALSE temporarily. Then, client-side decoration (CSD) cannot be initialized.
volatile int disable_composite;
volatile int signal_capture_handler;
- volatile int fake_global_decoration_layout;
volatile int in_info_collect;
const char *volatile signal_capture_name;
volatile gpointer signal_capture_instance;
@@ -140,6 +156,12 @@ static void *find_orig_function(int try_
void *handle;
void *symptr;
+ /* Ok, so in case both gtk2 + gtk3 are loaded, but we are using
+ * gtk2, we don't know what RTLD_NEXT is going to choose - so we
+ * must explicitly pick up the gtk2 versions... */
+ if (try_gtk2 && gtk2_active)
+ goto try_gtk2_version;
+
/* This will work in most cases, and is completely thread-safe. */
handle = dlsym(RTLD_NEXT, symbol);
if (handle)
@@ -248,10 +270,12 @@ RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY,
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_header_bar_set_show_close_button, void, (GtkHeaderBar *bar, gboolean setting), (bar, setting))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_header_bar_set_decoration_layout, void, (GtkHeaderBar *bar, const gchar *layout), (bar, layout))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_header_bar_get_decoration_layout, const gchar *, (GtkHeaderBar *bar), (bar))
+RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_header_bar_get_custom_title, GtkWidget *, (GtkHeaderBar *bar), (bar))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_style_context_add_class, void, (GtkStyleContext *context, const gchar *class_name), (context, class_name))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_style_context_remove_class, void, (GtkStyleContext *context, const gchar *class_name), (context, class_name))
-RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_style_context_add_provider, void, (GtkStyleContext *context, GtkStyleProvider *provider, guint priority), (context, provider, priority))
+RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_style_context_add_provider_for_screen, void, (GdkScreen *screen, GtkStyleProvider *provider, guint priority), (screen, provider, priority))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_style_provider_get_type, GType, (), ())
+RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_widget_hide, void, (GtkWidget *widget), (widget))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_widget_destroy, void, (GtkWidget *widget), (widget))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_widget_get_mapped, gboolean, (GtkWidget *widget), (widget))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_widget_get_realized, gboolean, (GtkWidget *widget), (widget))
@@ -262,6 +286,7 @@ RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY,
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_widget_realize, void, (GtkWidget *widget), (widget))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_widget_get_settings, GtkSettings *, (GtkWidget *widget), (widget))
RUNTIME_IMPORT_FUNCTION(0, GTK_LIBRARY, gtk_widget_get_toplevel, GtkWidget *, (GtkWidget *widget), (widget))
+RUNTIME_IMPORT_FUNCTION(0, GDK_LIBRARY, gdk_screen_get_default, GdkScreen *, (), ())
RUNTIME_IMPORT_FUNCTION(0, GDK_LIBRARY, gdk_window_get_user_data, void, (GdkWindow *window, gpointer *data), (window, data))
RUNTIME_IMPORT_FUNCTION(1, GDK_LIBRARY, gdk_screen_is_composited, gboolean, (GdkScreen *screen), (screen))
RUNTIME_IMPORT_FUNCTION(1, GDK_LIBRARY, gdk_window_set_decorations, void, (GdkWindow *window, GdkWMDecoration decorations), (window, decorations))
@@ -287,6 +312,7 @@ RUNTIME_IMPORT_FUNCTION(0, GOBJECT_LIBRA
RUNTIME_IMPORT_FUNCTION(0, GOBJECT_LIBRARY, g_value_unset, void, (GValue *value), (value))
RUNTIME_IMPORT_FUNCTION(0, GOBJECT_LIBRARY, g_value_get_string, const gchar *, (const GValue *value), (value))
RUNTIME_IMPORT_FUNCTION(0, GOBJECT_LIBRARY, g_value_get_boolean, gboolean, (const GValue *value), (value))
+RUNTIME_IMPORT_FUNCTION(0, GOBJECT_LIBRARY, g_type_name, const gchar *, (GType type), (type))
RUNTIME_IMPORT_FUNCTION(0, GLIB_LIBRARY, g_getenv, gchar *, (const char *name), (name))
RUNTIME_IMPORT_FUNCTION(0, GLIB_LIBRARY, g_logv, void, (const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, va_list args), (log_domain, log_level, format, args))
RUNTIME_IMPORT_FUNCTION(0, GLIB_LIBRARY, g_free, void, (gpointer mem), (mem))
@@ -314,10 +340,12 @@ RUNTIME_IMPORT_FUNCTION(0, GIREPOSITORY_
#define orig_gtk_header_bar_set_show_close_button rtlookup_gtk_header_bar_set_show_close_button
#define orig_gtk_header_bar_set_decoration_layout rtlookup_gtk_header_bar_set_decoration_layout
#define orig_gtk_header_bar_get_decoration_layout rtlookup_gtk_header_bar_get_decoration_layout
+#define gtk_header_bar_get_custom_title rtlookup_gtk_header_bar_get_custom_title
#define gtk_style_context_add_class rtlookup_gtk_style_context_add_class
#define gtk_style_context_remove_class rtlookup_gtk_style_context_remove_class
-#define gtk_style_context_add_provider rtlookup_gtk_style_context_add_provider
+#define gtk_style_context_add_provider_for_screen rtlookup_gtk_style_context_add_provider_for_screen
#define gtk_style_provider_get_type rtlookup_gtk_style_provider_get_type
+#define gtk_widget_hide rtlookup_gtk_widget_hide
#define gtk_widget_destroy rtlookup_gtk_widget_destroy
#define gtk_widget_get_mapped rtlookup_gtk_widget_get_mapped
#define gtk_widget_get_realized rtlookup_gtk_widget_get_realized
@@ -326,9 +354,11 @@ RUNTIME_IMPORT_FUNCTION(0, GIREPOSITORY_
#define gtk_widget_set_parent rtlookup_gtk_widget_set_parent
#define gtk_widget_unrealize rtlookup_gtk_widget_unrealize
#define gtk_widget_realize rtlookup_gtk_widget_realize
+#define gdk_screen_get_default rtlookup_gdk_screen_get_default
#define gdk_window_get_user_data rtlookup_gdk_window_get_user_data
#define orig_gdk_screen_is_composited rtlookup_gdk_screen_is_composited
#define orig_gdk_window_set_decorations rtlookup_gdk_window_set_decorations
+#define g_list_free rtlookup_g_list_free
#define g_object_get_data rtlookup_g_object_get_data
#define g_object_set_data rtlookup_g_object_set_data
#define g_type_check_class_cast rtlookup_g_type_check_class_cast
@@ -337,12 +367,16 @@ RUNTIME_IMPORT_FUNCTION(0, GIREPOSITORY_
#define g_object_class_find_property rtlookup_g_object_class_find_property
#define g_object_get_valist rtlookup_g_object_get_valist
#define g_object_get_property rtlookup_g_object_get_property
+#ifdef g_object_ref
+# undef g_object_ref
+#endif
#define g_object_ref rtlookup_g_object_ref
#define g_object_unref rtlookup_g_object_unref
#define g_value_init rtlookup_g_value_init
#define g_value_unset rtlookup_g_value_unset
#define g_value_get_string rtlookup_g_value_get_string
#define g_value_get_boolean rtlookup_g_value_get_boolean
+#define g_type_name rtlookup_g_type_name
#define orig_g_type_register_static_simple rtlookup_g_type_register_static_simple
#define orig_g_type_add_interface_static rtlookup_g_type_add_interface_static
#define orig_g_type_add_instance_private rtlookup_g_type_add_instance_private
@@ -374,7 +408,43 @@ static void static_g_log(const gchar *lo
va_end (args);
}
-static gboolean is_gtk_version_larger_or_equal(guint major, guint minor, guint micro) {
+int check_gtk2_callback(struct dl_phdr_info *info, size_t size, void *pointer)
+{
+ ElfW(Half) n;
+
+ if (G_UNLIKELY(strstr(info->dlpi_name, GDK_LIBRARY_SONAME_V2))) {
+ for (n = 0; n < info->dlpi_phnum; n++) {
+ uintptr_t start = (uintptr_t) (info->dlpi_addr + info->dlpi_phdr[n].p_vaddr);
+ uintptr_t end = start + (uintptr_t) info->dlpi_phdr[n].p_memsz;
+ if ((uintptr_t) pointer >= start && (uintptr_t) pointer < end) {
+ gtk2_active = 1;
+ /* The gtk version check could have already been cached
+ * before we were able to determine that gtk2 is in
+ * use, so force this to FALSE. (Regardless of the
+ * _checked value.) */
+ is_compatible_gtk_version_cached = FALSE;
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static void detect_gtk2(void *pointer)
+{
+ if (gtk2_active)
+ return;
+ /* There is a corner case where a program with plugins loads
+ * multiple plugins, some of which are linked against gtk2, while
+ * others are linked against gtk3. If the gtk2 plugins are used,
+ * this causes problems if we detect gtk3 just on the fact of
+ * whether gtk3 is loaded. Hence we iterate over all loaded
+ * libraries and if the pointer passed to us is within the memory
+ * region of gtk2, we set a global flag. */
+ dl_iterate_phdr(check_gtk2_callback, pointer);
+}
+
+static gboolean is_gtk_version_larger_or_equal2(guint major, guint minor, guint micro, int* gtk_loaded) {
static gtk_check_version_t orig_func = NULL;
if(!orig_func)
orig_func = (gtk_check_version_t)find_orig_function(0, GTK_LIBRARY, "gtk_check_version");
@@ -388,9 +458,19 @@ static gboolean is_gtk_version_larger_or
* will give us a reference to gtk_check_version. But since
* that symbol is compatible with gtk3, this doesn't hurt.
*/
- if (orig_func)
+ if (orig_func) {
+ if (gtk_loaded)
+ *gtk_loaded = TRUE;
return (orig_func(major, minor, micro) == NULL);
- return FALSE;
+ } else {
+ if (gtk_loaded)
+ *gtk_loaded = FALSE;
+ return FALSE;
+ }
+}
+
+static gboolean is_gtk_version_larger_or_equal(guint major, guint minor, guint micro) {
+ return is_gtk_version_larger_or_equal2(major, minor, micro, NULL);
}
static gboolean are_csd_disabled() {
@@ -404,22 +484,27 @@ static gboolean are_csd_disabled() {
}
static gboolean is_compatible_gtk_version() {
- /* Marking both as volatile here saves the trouble of caring about
- * memory barriers. */
- static volatile gboolean checked = FALSE;
- static volatile gboolean compatible = FALSE;
+ int gtk_loaded = FALSE;
- if(G_UNLIKELY(!checked)) {
- if (!is_gtk_version_larger_or_equal(3, 10, 0)) {
+ if(G_UNLIKELY(!is_compatible_gtk_version_checked)) {
+ if (gtk2_active) {
+ is_compatible_gtk_version_cached = FALSE;
+ } else if (!is_gtk_version_larger_or_equal2(3, 10, 0, >k_loaded)) {
/* CSD was introduced there */
- compatible = FALSE;
+ is_compatible_gtk_version_cached = FALSE;
} else {
- compatible = TRUE;
+ is_compatible_gtk_version_cached = TRUE;
}
- checked = TRUE;
+ /* If in a dynamical program (e.g. using python-gi) Glib is loaded before
+ * Gtk, then the Gtk version check is executed before Gtk is even loaded,
+ * returning FALSE and caching it. This will not disable CSD if Gtk is
+ * loaded later. To circumvent this, cache the value only if we know that
+ * Gtk is loaded. */
+ if (gtk_loaded)
+ is_compatible_gtk_version_checked = TRUE;
}
- return compatible;
+ return is_compatible_gtk_version_cached;
}
static void set_has_custom_title(GtkWindow* window, gboolean set) {
@@ -479,11 +564,18 @@ static GtkStyleProvider *get_custom_css_
" border-color: transparent;\n"
"}\n"
".background:not(.tiled):not(.maximized) .titlebar:backdrop,\n"
- ".background:not(.tiled):not(.maximized) .titlebar {\n"
+ ".background:not(.tiled):not(.maximized) .titlebar,"
+ ".background:not(.tiled):not(.maximized) .titlebar headerbar {\n"
" border-top-left-radius: 0;\n"
" border-top-right-radius: 0;\n"
- "}\n"
- "";
+ "}\n";
+ static int title_skipped = 0;
+
+ const char* env_show_header = getenv("GTK3NOCSD_SHOW_HEADER");
+ if (env_show_header && !strncmp(env_show_header, "1", 2) && !title_skipped) {
+ custom_css += 39; // skip CSS rule that hides title
+ title_skipped = 1;
+ }
if (G_UNLIKELY (provider == NULL)) {
GtkCssProvider *new_provider;
@@ -507,16 +599,15 @@ static GtkStyleProvider *get_custom_css_
static void add_custom_css (GtkWidget *widget)
{
- GtkStyleContext *context = gtk_widget_get_style_context (widget);
GtkStyleProvider *my_provider = get_custom_css_provider ();
-
- if (!context || !my_provider)
+ if (!my_provider)
return;
/* Use a higher priority than SETTINGS, but lower than APPLICATION.
* add_provider will make sure a given provider is not added twice.
*/
- gtk_style_context_add_provider (context, my_provider, GTK_STYLE_PROVIDER_PRIORITY_SETTINGS + 50);
+ GdkScreen *screen = gdk_screen_get_default ();
+ gtk_style_context_add_provider_for_screen (screen, my_provider, GTK_STYLE_PROVIDER_PRIORITY_SETTINGS + 50);
}
// This API exists since gtk+ 3.10
@@ -554,12 +645,6 @@ extern void gtk_window_set_titlebar (Gtk
}
}
- /* Remove any potential old title bar. We can't call
- * the static unset_titlebar() directly (not available),
- * so we call the full function; that shouldn't have
- * any side effects. */
- orig_gtk_window_set_titlebar (window, NULL);
-
/* The solid-csd class is not removed when the titlebar
* is unset in Gtk (it's probably a bug), so unset it
* here explicitly, in case it's set. */
@@ -577,6 +662,13 @@ extern void gtk_window_set_titlebar (Gtk
g_signal_connect (titlebar, "notify::title",
G_CALLBACK (private_info.on_titlebar_title_notify), window);
private_info.on_titlebar_title_notify (GTK_HEADER_BAR (titlebar), NULL, window);
+
+ /* Hiding GtkHeaderBar when custom title wasn't set (only for GtkDialog windows) */
+ const GtkWidget* custom = gtk_header_bar_get_custom_title(GTK_HEADER_BAR (titlebar));
+ const gchar* window_type = G_OBJECT_TYPE_NAME(window);
+ if (custom == NULL && strcmp(window_type, "GtkDialog")) {
+ gtk_widget_hide(GTK_WIDGET (titlebar));
+ }
}
gtk_style_context_add_class (gtk_widget_get_style_context (titlebar),
@@ -665,14 +757,10 @@ static void _gtk_header_bar_update_windo
r = _remove_buttons_from_layout (new_layout, *decoration_layout_ptr);
if (r == 0)
*decoration_layout_ptr = new_layout;
- } else {
- TLSD->fake_global_decoration_layout = 1;
}
info.update_window_buttons (bar);
if (*decoration_layout_ptr) {
*decoration_layout_ptr = orig_layout;
- } else {
- TLSD->fake_global_decoration_layout = 0;
}
}
@@ -725,7 +813,7 @@ extern void g_object_get (gpointer _obje
* g_object_get(). */
va_start (var_args, first_property_name);
- if (G_UNLIKELY (TLSD->fake_global_decoration_layout)) {
+ if (are_csd_disabled()) {
name = first_property_name;
while (name) {
GValue value = G_VALUE_INIT;
@@ -746,6 +834,10 @@ extern void g_object_get (gpointer _obje
if (r == 0)
s = new_layout;
*v = g_strdup (s);
+ } else if (G_UNLIKELY (strcmp (name, "gtk-dialogs-use-header") == 0)) {
+ gboolean *v = va_arg (var_args, gboolean *);
+ // Save dialog will break if this prop has been set to TRUE (see #13)
+ *v = FALSE;
} else {
G_VALUE_LCOPY (&value, var_args, 0, &error);
if (error) {
@@ -789,6 +881,11 @@ extern void gtk_header_bar_set_decoratio
}
}
+extern gboolean gtk_window_get_decorated (GtkWindow *window)
+{
+ return FALSE;
+}
+
extern gboolean gdk_screen_is_composited (GdkScreen *screen) {
/* With Gtk+3 3.16.1+ we reimplement gtk_window_set_titlebar ourselves, hence
* we don't want to re-use the compositing hack, especially since it causes
@@ -1006,6 +1103,7 @@ GType g_type_register_static_simple (GTy
if(type_name && G_UNLIKELY(strcmp(type_name, "GtkWindow") == 0)) {
// override GtkWindowClass
orig_gtk_window_class_init = class_init;
+ detect_gtk2((void *) class_init);
if(is_compatible_gtk_version() && are_csd_disabled()) {
class_init = (GClassInitFunc)fake_gtk_window_class_init;
save_type = >k_window_type;
@@ -1018,6 +1116,7 @@ GType g_type_register_static_simple (GTy
if(type_name && G_UNLIKELY(strcmp(type_name, "GtkDialog") == 0)) {
// override GtkDialogClass
orig_gtk_dialog_class_init = class_init;
+ detect_gtk2((void *) class_init);
if(is_compatible_gtk_version() && are_csd_disabled()) {
class_init = (GClassInitFunc)fake_gtk_dialog_class_init;
save_type = >k_dialog_type;
@@ -1030,6 +1129,7 @@ GType g_type_register_static_simple (GTy
if(type_name && G_UNLIKELY(strcmp(type_name, "GtkHeaderBar") == 0)) {
// override GtkHeaderBarClass
orig_gtk_header_bar_class_init = class_init;
+ detect_gtk2((void *) class_init);
if(is_compatible_gtk_version() && are_csd_disabled()) {
class_init = (GClassInitFunc)fake_gtk_header_bar_class_init;
save_type = >k_header_bar_type;
@@ -1042,6 +1142,7 @@ GType g_type_register_static_simple (GTy
if(type_name && G_UNLIKELY(strcmp(type_name, "GtkShortcutsWindow") == 0)) {
// override GtkShortcutsWindowClass
orig_gtk_shortcuts_window_init = instance_init;
+ detect_gtk2((void *) instance_init);
if(is_compatible_gtk_version() && are_csd_disabled()) {
instance_init = (GInstanceInitFunc) fake_gtk_shortcuts_window_init;
goto out;
@@ -1095,6 +1196,9 @@ static void fake_gtk_dialog_buildable_in
}
void g_type_add_interface_static (GType instance_type, GType interface_type, const GInterfaceInfo *info) {
+ if (info && info->interface_init)
+ detect_gtk2((void *) info->interface_init);
+
if(is_compatible_gtk_version() && are_csd_disabled() && (instance_type == gtk_window_type || instance_type == gtk_dialog_type)) {
if(interface_type == GTK_TYPE_BUILDABLE) {
// register GtkBuildable interface for GtkWindow/GtkDialog class
@@ -1248,7 +1352,7 @@ out:
static gtk_header_bar_private_info_t gtk_header_bar_private_info ()
{
- static volatile gtk_header_bar_private_info_t info = { (gsize) -1, NULL };
+ static volatile gtk_header_bar_private_info_t info = { (gsize) -1, NULL, NULL };
if (G_UNLIKELY (info.decoration_layout_offset == (gsize) -1)) {
/* Was only introduced in Gtk+3 >= 3.12. Unlikely that someone is
* still using such an old version, but be safe nevertheless. */Since the patch is rather old, it may work with an old source, e.g. that of Excalibur.
The available Build-Deps for gtk3-nocsd can be installed with "apt build-dep"
apt build-dep gtk3-nocsd --simulatesudo apt build-dep gtk3-nocsdIf you are "a complete beginner", you may better try to reproduce my experiments.
It is not a problem. It is a meta-package.
You can install everything you need manually
➤ apt info packaging-dev
Package: packaging-dev
...
Depends: build-essential, debhelper, devscripts, dput-ng | dput | dupload, lintian, sbuild | cowbuilder | pbuilder, quilt
Recommends: apt-file, autoconf, automake, autopkgtest, autotools-dev, bzr-debian, cdbs, cmake, debian-policy, developers-reference | developers-reference-de | developers-reference-fr | developers-reference-ja, dh-autoreconf, dh-make, git-buildpackage, gnome-pkg-tools, gnupg, libtool, piuparts, pkg-kde-tools, svn-buildpackage
Suggests: mercurial-buildpackageYou need "Depends" and "Recommends".
Do not forget quilt
sudo apt install quilt➤ dpkg -l | grep dput
ii dput 1.1.3 all Debian package upload tool➤ dpkg -l | grep sbuild
ii libsbuild-perl 0.85.0 all Library for building Debian binary packages from Debian sources
ii sbuild 0.85.0 all Tool for building Debian binary packages from Debian sourcesThe available Build-Deps for gtk3-nocsd can be installed with "apt build-dep"
apt build-dep gtk3-nocsd --simulatesudo apt build-dep gtk3-nocsdYou may try to build from Debian sources (e.g. unstable)
_https://tracker.debian.org/pkg/gtk3-nocsd
_https://packages.debian.org/source/unstable/gtk3-nocsd
Example: _https://dev1galaxy.org/viewtopic.php?id=7179
You may also try to build from Ubuntu sources.
All sorts of examples are available here:
_https://dev1galaxy.org/viewforum.php?id=25
It makes sense to start from Debian sources to get all the Build-Deps you need.
You may also try to build it from git
_https://aur.archlinux.org/packages/gtk3-nocsd-git
_https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=gtk3-nocsd-git
Luckily, with gtk3-nocsd, we still have a way to (partially) turn it off.
_https://github.com/ZaWertun/gtk3-nocsd
It may mean that it may not always work.
All problems with Mate (Gnome2) and ALSA were already solved in 2009 (Mate is a fork of Gnome2).
gnome-media (deb) was recompiled and patched by the OSS4 community.
Today, if you remove PulseAudio, Mate will install PipeWire (and other way round).
If you remove them both, Mate will automatically enable ALSA for mate-settings-daemon and mate-volume-control-status-icon (sound applet in the tray)
$ sudo apt-get purge pulseaudio pulseaudio-utils pavucontrol pulseaudio-module-bluetooth pipewire pipewire-bin pipewire-pulseThis will also remove "mate-desktop-environment". It is a meta-package which can be safely removed.
Then, you have to reboot, or kill pulseaudio and reload ALSA
$ sudo /etc/init.d/alsa-utils force-reload
Shutting down ALSA...done.
Setting up ALSA...done. On Linix Mint MATE, you should also remove pipewire-alsa, etc.
➤ fuser -av $(find /dev/snd -type c 2>/dev/null)
USER PID ACCESS COMMAND
/dev/snd/controlC0: igor 2245 F.... mate-settings-d
igor 2344 F.... mate-volume-con
/dev/snd/pcmC0D0c:
/dev/snd/pcmC0D0p: igor 3166 F...m firefox-esr
/dev/snd/seq:
/dev/snd/timer: igor 3166 f.... firefox-esr➤ ps -A u | grep mate-volume-con
igor 2344 0.0 0.7 483040 59088 ? Sl 16:27 0:10 mate-volume-control-status-icon➤ ps -A u | grep mate-settings-d
igor 2245 0.1 0.6 968348 53544 ? Sl 16:27 0:28 /usr/bin/mate-settings-daemon➤ apt-file find /usr/bin/mate-volume-control-status-icon
mate-media: /usr/bin/mate-volume-control-status-icon➤ apt info mate-media
Package: mate-media
...
Description: MATE media utilities
MATE media utilities are the audio mixer and the volume
control applet.See also:
_https://dev1galaxy.org/viewtopic.php?pid=49837#p49837
It seems that the problem was in pulseaudio.
It means that sound may disappear in any moment.
Post the output of fuser and inxi:
fuser -av $(find /dev/snd -type c 2>/dev/null)inxi -Ainxi: everything you need to know about your computer
_https://easylinuxtipsproject.blogspot.com/p/inxi.html
sudo apt install inxiOn Ubuntu, the NTFS driver (read and write) was installed and enabled by default since 2007.
It worked without problems and "compatibility issues".
It seems that this particular security problem occurred about ten years ago, for example:
_https://unix.stackexchange.com/questions/296967/how-to-recursively-remove-execute-permissions-from-files-without-touching-folder
_https://unix.stackexchange.com/q/296967
Nothing was done to fix it.
You may not believe, but computer science students (and their professors, perhaps), usually do not notice that this problem exists. They simply install Ubuntu and use it for their projects.
It might be obvious that this strange phenomenon correlates with pulseaudio and systemd.
It is very probable that it is a symptom of dementia caused by pulseaudio and enhanced by pipewire.
EDIT:
Because of dementia, it might be difficult to understand that what kind of security problem it is.
It is a backdoor in Devuan.
It seems that Stuxnet is already forgotten (because of dementia).
It is typically introduced to the target environment via an infected USB flash drive, thus crossing any air gap. The worm then propagates across the network, scanning for Siemens Step7 software on computers controlling a PLC.
_https://en.wikipedia.org/wiki/Stuxnet
Uh-oh. How just inserting a USB drive can pwn a Linux box
_https://www.bitdefender.com/en-us/blog/hotforsecurity/uh-oh-how-just-inserting-a-usb-drive-can-pwn-a-linux-box
CVE-2025-37986 is a vulnerability discovered in the Linux kernel's USB Type-C device pointer handling system, disclosed on May 20, 2025.
_https://www.wiz.io/vulnerability-database/cve/cve-2025-37986
Linux USB Subsystem Vulnerabilities
Fourteen vulnerabilities have been found to be affecting the USB subsystem on Linux. The vulnerabilities affect all Linux devices with USB ports. However, physical access is required to initiate them.Threat ID:
CC-1777
Category:
Exploit
Threat Severity:
Low
Threat Vector:
Published:
14 November 2017 12:00 AM
_https://digital.nhs.uk/cyber-alerts/2017/cc-1777
Researchers found 26 new vulnerabilities in the USB drivers used in Windows, Linux, macOS and other systems.
_https://www.hugdiy.com/blog/you-wouldnt-know-until-you-test-it-how-to-restore-all-these-usb-vulnerabilities/
The latest version of Linux Mint (22.1) has the same security problem.
USB Drives (NTFS, exFAT) are automatically mounted with all files executable.
Nobody complains, and nobody is trying to fix the problem.
This seems to be a symptom of dementia caused by pulseaudio and pipewire.
It may also explain a strange phenomenon of Neo-Luddism and AI hate
_https://en.wikipedia.org/wiki/Neo-Luddism
_https://en.wikipedia.org/wiki/Luddite
Perhaps, it is too late to do something about Devuan Wiki.
You may post the output of this command:
fuser -av $(find /dev/snd -type c 2>/dev/null)For example:
➤ fuser -av $(find /dev/snd -type c 2>/dev/null)
USER PID ACCESS COMMAND
/dev/snd/controlC0: igor 2235 F.... mate-settings-d
igor 2326 F.... mate-volume-con
/dev/snd/pcmC0D0c:
/dev/snd/pcmC0D0p: igor 3201 F...m firefox-esr
/dev/snd/seq:
/dev/snd/timer: igor 3201 f.... firefox-esrAnd the output of
inxi -Asudo apt install inxiinxi: everything you need to know about your computer
_https://easylinuxtipsproject.blogspot.com/p/inxi.html
➤ apt-file find /etc/alsa/conf.d
...
libasound2-plugins: /etc/alsa/conf.d/10-rate-lav.conf
libasound2-plugins: /etc/alsa/conf.d/10-samplerate.conf
libasound2-plugins: /etc/alsa/conf.d/10-speexrate.conf
libasound2-plugins: /etc/alsa/conf.d/50-arcam-av-ctl.conf
libasound2-plugins: /etc/alsa/conf.d/50-jack.conf
libasound2-plugins: /etc/alsa/conf.d/50-oss.conf
libasound2-plugins: /etc/alsa/conf.d/50-pulseaudio.conf
libasound2-plugins: /etc/alsa/conf.d/60-a52-encoder.conf
libasound2-plugins: /etc/alsa/conf.d/60-speex.conf
libasound2-plugins: /etc/alsa/conf.d/60-upmix.conf
libasound2-plugins: /etc/alsa/conf.d/60-vdownmix.conf
libasound2-plugins: /etc/alsa/conf.d/98-usb-stream.conf
libasound2-plugins: /etc/alsa/conf.d/99-pulseaudio-default.conf.example
...See also:
_https://www.commandlinux.com/man-page/man1/apt-file.1.html
If you google "No suitable destination host found by cups-browsed," you get:
"SOLVED: no suitable destination host found by cups-browsed"
_https://forums.linuxmint.com/viewtopic.php?t=380704
“No suitable Destination Host found by cups-browsed”
_https://askubuntu.com/questions/1128164/no-suitable-destination-host-found-by-cups-browsed
and a lot of similar links
Possible solutions:
apt purge cups-browsed_https://forums.linuxmint.com/viewtopic.php?t=380704
First: uninstall cups-browsed
sudo apt-get purge --autoremove cups-browsedNext: Restart your computer
Finally manually add your printer
_https://askubuntu.com/a/1128869
It is very human to do nothing, but a sort of wiki might be needed.
"...but i'm no expert at documentation or linux".
You can simply imagine that you are. It will work.
If you are a student, this is the best way to learn Linux.
To a socially responsible expert on Linux documentation, that is, to you.
Have you noticed that the Devuan wiki is almost empty?
It means that all knowledge might be forgotten because of dementia.
Since you are the only person who really knows how to write technical documentation, you may try to fill the Devuan wiki with exact technical knowledge. Perhaps, you should try, if you are a socially responsible Linux user.
Social responsibility is an ethical concept in which a person works and cooperates with other people and organizations for the benefit of the community.
_https://en.wikipedia.org/wiki/Social_responsibility
⟡ AI Overview
To write effective technical documentation, focus on understanding your audience, organizing information logically, and presenting content clearly and concisely. Use visuals, gather feedback, and prioritize consistency to create documentation that meets user needs.
Perhaps, one may try
SoundDriver = ALSASee: _https://wiki.archlinux.org/title/MOC#Configuration
There might be some other options...
To use MOC with OSS v4.1 you must change OSSMixerDevice to /dev/ossmix in your configuration file (located in ~/.moc). For issues with the interface try changing the OSSMixerChannel by pressing w in mocp (to change to the sofware mixer).
_https://wiki.archlinux.org/title/Open_Sound_System#MOC
@delgado
If you pretend to be more intelligent than AI, you may try to help MLEvD to solve the problem.
I am ignorant in the topic. But I had already burnt one GPU, experimenting with a very old notebook. Perhaps, one may better ask AI: What is the quietest PC fan?
Yes, pulseaudio is quite "intrusive"; it installs itself as the default audio path handler into the ALSA configuration
It is not exactly the case. ALSA was stripped off software mixer to be raped by pulseaudio. The problem is that the secret esoteric technology of configuring software mixers for ALSA was somehow forgotten, largely because of dementia, perhaps. If ALSA is such a problem, one may try OSS4. It is not very difficult to compile. The PKGBUILD and patches are available here:
_https://aur.archlinux.org/packages/oss-git
OSS was designed as a classical sound system. More exactly, it was the first one.
ALSA was designed as a sort of universal software mixer. That is why it does not permit "exclusive mode".
ALSA without a correctly configured software mixer is like a car without a motor and wheels.
⟡ AI Overview
ALSA has both a userspace component and a kernel component. The kernel component provides drivers that directly interact with sound hardware, while the userspace component provides a higher-level API for applications to interact with the sound devices. The userspace component offers more general functions like mixing, routing, and effects, abstracting away the complexities of different hardware
Portable CMake is available here:
_https://github.com/Kitware/CMake
Portable Ninja is available here:
_https://github.com/ninja-build/ninja
Portable GCC is available here:
_https://github.com/Frogging-Family/mostlyportable-gccPortable CMake and Ninja are ready to use.
Portable GCC is easy to compile.
➤ gcc --version
gcc (TkG-mostlyportable) 15.1.1 20250601
➤ g++ --version
g++ (TkG-mostlyportable) 15.1.1 20250601
➤ cmake --version
cmake version 4.0.2
➤ ninja --version
1.12.1 1. Generating the Buildsystem
cmake -S wxmaxima -B build -G Ninja -DCMAKE_BUILD_TYPE="Release" -DCPACK_DEBIAN_PACKAGE_MAINTAINER=Daedalus -DCMAKE_INSTALL_PREFIX='/usr' -DwxWidgets_CONFIG_EXECUTABLE=/usr/bin/wx-config -DWXM_INTERPROCEDURAL_OPTIMIZATION=ON -Wno-dev -- The CXX compiler identification is GNU 15.1.1
...
-- CMake version: 4.0.2
-- CMake build type: Release
...
-- Found Doxygen: /usr/bin/doxygen (found version "1.9.4") found components: doxygen dot
-- Found po4a: /usr/bin/po4a (found version "0.73")
...
-- Found pandoc: /usr/bin/pandoc (found version "2.17.1.1")
-- Found LATEX: /usr/bin/latex found components: XELATEX LUALATEX
-- Found ImageMagick: /usr/bin/identify (found version "6.9.11-60")
-- Found Gettext: /usr/bin/msgmerge (found version "0.21")
...
-- Found Maxima: /usr/bin/maxima (found version "5.47post")
-- Found appstreamcli: /usr/bin/appstreamcli (found version "0.16.1") 2. Compiling with invisible Ninja
cmake --build build 3. Making a Debian package with CPack
cpack --config build/CPackConfig.cmake -G DEB ➤ cpack --config build/CPackConfig.cmake -G DEB
CPack: Create package using DEB
CPack: Install projects
CPack: - Install project: wxMaxima []
CPack: Create package
CPackDeb: - Generating dependency list
CPack: - package:.../Build1/wxmaxima_25.04.0-1_amd64.deb generated.
➤ ls -1
build
_CPack_Packages
wxmaxima
wxmaxima_25.04.0-1_amd64.deb ➤ tree -L 5 _CPack_Packages
_CPack_Packages
└── Linux
└── DEB
├── wxmaxima_25.04.0-1_amd64.deb
└── wxMaxima-25.04.0-Linux
├── control
├── control.tar.gz
├── data.tar.gz
├── debian-binary
├── md5sums
└── usr
├── bin
└── share ➤ dpkg --info wxmaxima_25.04.0-1_amd64.deb | grep Depends
Depends: libc6 (>= 2.34), libgcc-s1 (>= 3.3.1), libstdc++6 (>= 11), libwxbase3.2-1 (>= 3.2.2+dfsg), libwxgtk-webview3.2-1 (>= 3.2.2+dfsg), libwxgtk3.2-1 (>= 3.2.1+dfsg-2) These dependencies are very good in the sense that the package can be installed on Devuan 5.
The only problem is that they are wrong. This can be easily verified:
➤ cd _CPack_Packages/Linux/DEB/wxMaxima-25.04.0-Linux/usr/bin
➤ ls
wxmaxima
➤ ./wxmaxima
./wxmaxima: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.32' not found (required by ./wxmaxima)
./wxmaxima: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `CXXABI_1.3.15' not found (required by ./wxmaxima) It means that wxMaxima depends on certain libraries compiled together with the portable gcc-15. This problem can be easily fixed, but, first of all, we have to find the cause of the deception.
Debian is deceptive, and, perhaps, fundamentally wrong by design.
We have several hypotheses to verify:
1. The CMake developers do not know the secret esoteric method with which to calculate dependencies.
2. The secret esoteric method is wrong.
3. The Debian "dependency system" is fundamentally wrong.
➤ cd ../../../
➤ ls -1
wxmaxima_25.04.0-1_amd64.deb
wxMaxima-25.04.0-Linux
➤ mkdir debian
➤ ls -1
debian
wxmaxima_25.04.0-1_amd64.deb
wxMaxima-25.04.0-Linux
➤ echo -e "Source: wxmaxima\nPackage: wxmaxima\nDepends: \${shlibs:Depends}" >> debian/control
➤ cat debian/control
Source: wxmaxima
Package: wxmaxima
Depends: ${shlibs:Depends} dpkg-shlibdeps -v -xwxmaxima --ignore-missing-info -e $(find wxMaxima-25.04.0-Linux -type f 2>/dev/null) ➤ cat debian/substvars
shlibs:Depends=libc6 (>= 2.34), libgcc-s1 (>= 3.3.1), libstdc++6 (>= 11), libwxbase3.2-1 (>= 3.2.2+dfsg), libwxgtk-webview3.2-1 (>= 3.2.2+dfsg), libwxgtk3.2-1 (>= 3.2.1+dfsg-2)dpkg-shlibdeps produced the same wrong dependencies.
CONCLUSION: The CMake developers are using the same secret esoteric method to calculate dependencies of Debian packages, and this method is wrong.
The method is secret, simply because the system is buggy.
dpkg-shlibdeps cannot be trusted. It is as reliable as weather forecast. Sometimes it is true. Sometimes it is wrong.
The Debian packaging system is either logically inconsistent, or fundamentally wrong by design. This may require a further investigation.
It seems that dpkg-shlibdeps is capable of calculating imaginary esoteric virtual dependencies which are somehow related to the real world dependencies. It might be a product of "demented artificial intelligence", perhaps.
Nevertheless, these dependencies a very good, for they do not prevent installation of the package. The only problem to fix is that of shared libraries. It has a standard solution.
sudo apt install fakeroot patchelf ➤ fakeroot
# mkdir debdir
# ls -1
debdir
debian
wxmaxima_25.04.0-1_amd64.deb
wxMaxima-25.04.0-Linux
# dpkg-deb -R wxmaxima_25.04.0-1_amd64.deb debdir
# patchelf --print-rpath debdir/usr/bin/wxmaxima
<empty>
# patchelf --set-rpath $HOME/.CTools/gcc-15.1.1/lib64 debdir/usr/bin/wxmaxima
# patchelf --print-rpath debdir/usr/bin/wxmaxima
~/.CTools/gcc-15.1.1/lib64
# exit
exit ➤ ./debdir/usr/bin/wxmaxima --version
wxMaxima 25.04.0 (Git version: 583c11f) ➤ cd debdir
➤ mv -v DEBIAN/md5sums ..
renamed 'DEBIAN/md5sums' -> '../md5sums'
➤ fakeroot
# find . -type f -not -path "./DEBIAN/*" -exec md5sum {} + | sort -k 2 | sed 's/\.\/\(.*\)/\1/' > DEBIAN/md5sums
# ls -1 DEBIAN
control
md5sums
# cd ..
# chmod 0644 -- debdir/DEBIAN/md5sums
# dpkg-deb -b debdir wxmaxima_25.04.0-1_amd64-fixed.deb
dpkg-deb: building package 'wxmaxima' in 'wxmaxima_25.04.0-1_amd64-fixed.deb'.
# exit
exit
➤ cd ..
➤ ls -1 *.deb
wxmaxima_25.04.0-1_amd64.deb
wxmaxima_25.04.0-1_amd64-fixed.deb Now we can install wxMaxima
sudo dpkg -i wxmaxima_25.04.0-1_amd64-fixed.deb ➤ wxmaxima --version
wxMaxima 25.04.0 (Git version: 583c11f)@greenjeans
Coffee may not help, if you are not initiated into the secret knowledge.
You may better google "Anthropology of GNU/Linux".
Do you know another method to calculate dependencies (>=) of Debian packages?
It might be very useful for verification.
@greenjeans
It is not difficult to unpack a Debian package, edit "control" with a text editor (nano, pluma, or mousepad, or else), and pack it again.
What is the "Best Kept Secret" is how to calculate the true dependencies.
That is why you have to fake a "sourcedir" (create a fake debian/control).
Then you can run "dpkg-shlibdeps". Otherwise, it may complain about missing "debian/control", for example:
➤ dpkg-shlibdeps /usr/bin/whereis
dpkg-shlibdeps: error: cannot read debian/control: No such file or directory Why is it a sort of secret knowledge? It is about a ritual justification of social status.
⟡AI Overview
Secular rituals, which are non-religious customs and practices, can influence social status by fostering social bonding and positive affect, similar to religious rituals. Studies have shown that secular rituals, like those at Sunday Assemblies, can increase social connection, boost positive emotions, and decrease negative emotions, potentially leading to improved mental well-being.
Here's a more detailed look at how secular rituals impact social status:
1. Fostering Social Bonding:
Secular rituals, such as family traditions, celebrations, or community gatherings, can create a sense of belonging and connection among participants.
Rituals can reinforce shared values and beliefs, strengthening social bonds within a group.
Studies have found that the increase in social bonding in secular rituals is comparable to religious rituals.
2. Boosting Positive Affect and Reducing Negative Affect:
Participating in secular rituals can lead to increased positive emotions and decreased negative emotions.
These positive emotions can, in turn, contribute to a greater sense of social connection and well-being.
The "broaden and build" hypothesis suggests that positive emotions broaden attention, leading to more social connections and improved mental well-being.
3. Examples of Secular Rituals:
Family traditions: Celebrating holidays, birthdays, or other milestones with specific rituals.
Community gatherings: Participating in local festivals, community events, or sporting events.
Rites of passage: Celebrating graduations, weddings, or other life transitions with rituals.
Creating your own secular rituals: Developing personal practices that mark important moments or foster connections.
4. Social Status and Secular Rituals:
Participating in secular rituals can contribute to a higher social status by strengthening social bonds and fostering a sense of belonging.
By actively engaging in these rituals, individuals may be perceived as more connected, engaged, and socially skilled.
Rituals can also serve as a way to express shared values and beliefs, reinforcing group identity and social cohesion.
5. Secular Rituals as an Alternative to Religious Rituals:
For individuals who do not identify with religious traditions, secular rituals can provide a means of experiencing social bonding and positive affect.
Secular rituals can serve as an alternative way to create meaning and purpose in life while still fostering social connection.
By participating in secular rituals, individuals may feel more connected to their community and less isolated.
United on Sunday: The effects of secular rituals on social bonding and affect
27 Jan 2021PubMed
United on Sunday: The effects of secular rituals on social ...
Results showed the increase in social bonding taking place in secular rituals is comparable to religious rituals. We also found th...
PubMed Central
The effects of secular rituals on social bonding and affect - PLOS
27 Jan 2021 — However, whether the social bonding effect reported from religious rituals is also seen in secular rituals that mimic t...AI responses may include mistakes.
$ apt-cache policy
...
Pinned packages:
pipewire-pulse -> 0.3.65-3+deb12u1 with priority -1
pulseaudio -> 16.1+dfsg1-2+b1 with priority -1
pipewire -> 0.3.65-3+deb12u1 with priority -1
pavucontrol -> 5.0-2 with priority -1
gstreamer1.0-alsa -> 1.22.0-3+deb12u4 with priority -1
gstreamer1.0-alsa -> 1.22.0-3+deb12u3 with priority -1
gstreamer1.0-pipewire -> 0.3.65-3+deb12u1 with priority -1
pipewire-bin -> 0.3.65-3+deb12u1 with priority -1
pulseaudio-module-bluetooth -> 16.1+dfsg1-2+b1 with priority -1
gstreamer1.0-pulseaudio -> 1.22.0-5+deb12u2 with priority -1
ALSA users have to install gstreamer1.0-alsa and remove gstreamer1.0-pulseaudio in order to improve sound quality with gstreamer.
OSS4 users have to remove gstreamer1.0-alsa and gstreamer1.0-pulseaudio. This automatically enables the gstreamer OSS4 backend (if OSS4 is installed).
gstreamer1.0-pipewire should also be removed.
The unwanted plugins should also be pinned.