diff options
Diffstat (limited to 'gtk3-stackrpms/gtk3-nocsd/gtk3-nocsd-gh-82ff5a0da54aa6da27232b55eb93e5f4b5de22f2.patch')
-rw-r--r-- | gtk3-stackrpms/gtk3-nocsd/gtk3-nocsd-gh-82ff5a0da54aa6da27232b55eb93e5f4b5de22f2.patch | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/gtk3-stackrpms/gtk3-nocsd/gtk3-nocsd-gh-82ff5a0da54aa6da27232b55eb93e5f4b5de22f2.patch b/gtk3-stackrpms/gtk3-nocsd/gtk3-nocsd-gh-82ff5a0da54aa6da27232b55eb93e5f4b5de22f2.patch new file mode 100644 index 0000000..c01529d --- /dev/null +++ b/gtk3-stackrpms/gtk3-nocsd/gtk3-nocsd-gh-82ff5a0da54aa6da27232b55eb93e5f4b5de22f2.patch @@ -0,0 +1,193 @@ +From 82ff5a0da54aa6da27232b55eb93e5f4b5de22f2 Mon Sep 17 00:00:00 2001 +From: Christian Seiler <christian@iwakd.de> +Date: Fri, 17 Jun 2016 17:27:27 +0200 +Subject: [PATCH] Properly handle the case when both gtk2 and gtk3 are loaded + +In case both gtk2 and gtk3 are loaded, but only gtk2 is used (which can +happen if a piece of software is linked against neither, but has +different plugins, some of which link against gtk2, others against +gtk3, all loaded at the same time, but only one of the variants used), +make sure that gtk3-nocsd detects that, doesn't actually inject any +code and calls all the gtk2 functions, instead of the gtk3 variants. +(Because they are incompatible and mixing calls will lead to crashes.) + +Fixes Github issue #18. +--- + ChangeLog | 2 ++ + gtk3-nocsd.c | 74 +++++++++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 66 insertions(+), 10 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index 53cbd33..3e93cba 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -7,6 +7,8 @@ New in version 4 (unreleased) + * Support python-gi again by not caching the result of the version + check if Gtk is not yet loaded. (python-gi loads Glib before it + loads Gtk.) ++ * Handle the case when both Gtk+3 and Gtk+2 are loaded (e.g. via ++ different plugins), but Gtk+2 is used. + + New in version 3 + ---------------- +diff --git a/gtk3-nocsd.c b/gtk3-nocsd.c +index 804fbd5..f9c0d70 100644 +--- 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> +@@ -111,6 +112,12 @@ static void * volatile library_handles[NUM_LIBRARIES * 2] = { + 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. +@@ -140,6 +147,12 @@ static void *find_orig_function(int try_gtk2, int library_id, const char *symbol + 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) +@@ -374,6 +387,42 @@ static void static_g_log(const gchar *log_domain, GLogLevelFlags log_level, cons + va_end (args); + } + ++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) +@@ -414,18 +463,16 @@ 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_equal2(3, 10, 0, >k_loaded)) { ++ 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; + } + /* 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, +@@ -433,10 +480,10 @@ static gboolean is_compatible_gtk_version() { + * loaded later. To circumvent this, cache the value only if we know that + * Gtk is loaded. */ + if (gtk_loaded) +- checked = TRUE; ++ is_compatible_gtk_version_checked = TRUE; + } + +- return compatible; ++ return is_compatible_gtk_version_cached; + } + + static void set_has_custom_title(GtkWindow* window, gboolean set) { +@@ -1023,6 +1070,7 @@ GType g_type_register_static_simple (GType parent_type, const gchar *type_name, + 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; +@@ -1035,6 +1083,7 @@ GType g_type_register_static_simple (GType parent_type, const gchar *type_name, + 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; +@@ -1047,6 +1096,7 @@ GType g_type_register_static_simple (GType parent_type, const gchar *type_name, + 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; +@@ -1059,6 +1109,7 @@ GType g_type_register_static_simple (GType parent_type, const gchar *type_name, + 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; +@@ -1112,6 +1163,9 @@ static void fake_gtk_dialog_buildable_interface_init (GtkBuildableIface *iface, + } + + 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 |