264 lines
8.1 KiB
Bash
264 lines
8.1 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT="$(pwd)"
|
|
SRC_DIR="$ROOT/src"
|
|
PATCH_OUT="$ROOT/ubuntu-lts-gtkmm4.generated.patch"
|
|
|
|
COMPAT_HPP="$SRC_DIR/GtkCompat.hpp"
|
|
|
|
if [[ ! -d "$SRC_DIR" ]]; then
|
|
echo "ERROR: src/ not found. Run from project root." >&2
|
|
exit 1
|
|
fi
|
|
|
|
mapfile -t FILES_TO_PATCH < <(find "$SRC_DIR" -type f -name "*.cpp" | sort)
|
|
|
|
TMPDIR="$(mktemp -d)"
|
|
trap 'rm -rf "$TMPDIR"' EXIT
|
|
|
|
backup_key() { echo "$1" | sed 's|/|__|g'; }
|
|
|
|
echo "[1/6] Backups"
|
|
for f in "${FILES_TO_PATCH[@]}"; do
|
|
[[ -f "$f" ]] || continue
|
|
cp -a "$f" "$TMPDIR/$(backup_key "$f").orig"
|
|
done
|
|
|
|
if [[ -f "$COMPAT_HPP" ]]; then
|
|
cp -a "$COMPAT_HPP" "$TMPDIR/GtkCompat.hpp.orig"
|
|
else
|
|
: > "$TMPDIR/GtkCompat.hpp.orig"
|
|
fi
|
|
|
|
echo "[2/6] Writing $COMPAT_HPP (Qt macro-safe)"
|
|
cat > "$COMPAT_HPP" <<'EOF'
|
|
#pragma once
|
|
|
|
#if defined(_MSC_VER) || defined(__clang__) || defined(__GNUC__)
|
|
#define GTKCOMPAT_HAS_PUSH_POP_MACRO 1
|
|
#else
|
|
#define GTKCOMPAT_HAS_PUSH_POP_MACRO 0
|
|
#endif
|
|
|
|
#if GTKCOMPAT_HAS_PUSH_POP_MACRO
|
|
#ifdef signals
|
|
#pragma push_macro("signals")
|
|
#undef signals
|
|
#define GTKCOMPAT_RESTORE_signals 1
|
|
#endif
|
|
#ifdef slots
|
|
#pragma push_macro("slots")
|
|
#undef slots
|
|
#define GTKCOMPAT_RESTORE_slots 1
|
|
#endif
|
|
#ifdef emit
|
|
#pragma push_macro("emit")
|
|
#undef emit
|
|
#define GTKCOMPAT_RESTORE_emit 1
|
|
#endif
|
|
#ifdef foreach
|
|
#pragma push_macro("foreach")
|
|
#undef foreach
|
|
#define GTKCOMPAT_RESTORE_foreach 1
|
|
#endif
|
|
#ifdef Q_FOREACH
|
|
#pragma push_macro("Q_FOREACH")
|
|
#undef Q_FOREACH
|
|
#define GTKCOMPAT_RESTORE_Q_FOREACH 1
|
|
#endif
|
|
#else
|
|
#ifdef signals
|
|
#undef signals
|
|
#endif
|
|
#ifdef slots
|
|
#undef slots
|
|
#endif
|
|
#ifdef emit
|
|
#undef emit
|
|
#endif
|
|
#ifdef foreach
|
|
#undef foreach
|
|
#endif
|
|
#ifdef Q_FOREACH
|
|
#undef Q_FOREACH
|
|
#endif
|
|
#endif
|
|
|
|
#include <gtkmm.h>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <functional>
|
|
|
|
namespace GtkCompat
|
|
{
|
|
inline void for_each_child(Gtk::Widget& parent, const std::function<void(Gtk::Widget*)>& fn)
|
|
{
|
|
for (auto* child = parent.get_first_child(); child != nullptr; child = child->get_next_sibling())
|
|
fn(child);
|
|
}
|
|
|
|
inline std::vector<Gtk::Widget*> children(Gtk::Widget& parent)
|
|
{
|
|
std::vector<Gtk::Widget*> out;
|
|
for_each_child(parent, [&](Gtk::Widget* w){ out.push_back(w); });
|
|
return out;
|
|
}
|
|
|
|
inline void listbox_clear(Gtk::ListBox& lb)
|
|
{
|
|
for (auto* child = lb.get_first_child(); child != nullptr; )
|
|
{
|
|
auto* next = child->get_next_sibling();
|
|
lb.remove(*child);
|
|
child = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline bool operator==(const Glib::ustring& lhs, const std::string& rhs) { return lhs.raw() == rhs; }
|
|
inline bool operator==(const std::string& lhs, const Glib::ustring& rhs) { return lhs == rhs.raw(); }
|
|
inline bool operator!=(const Glib::ustring& lhs, const std::string& rhs) { return !(lhs == rhs); }
|
|
inline bool operator!=(const std::string& lhs, const Glib::ustring& rhs) { return !(lhs == rhs); }
|
|
|
|
#if GTKCOMPAT_HAS_PUSH_POP_MACRO
|
|
#ifdef GTKCOMPAT_RESTORE_Q_FOREACH
|
|
#pragma pop_macro("Q_FOREACH")
|
|
#undef GTKCOMPAT_RESTORE_Q_FOREACH
|
|
#endif
|
|
#ifdef GTKCOMPAT_RESTORE_foreach
|
|
#pragma pop_macro("foreach")
|
|
#undef GTKCOMPAT_RESTORE_foreach
|
|
#endif
|
|
#ifdef GTKCOMPAT_RESTORE_emit
|
|
#pragma pop_macro("emit")
|
|
#undef GTKCOMPAT_RESTORE_emit
|
|
#endif
|
|
#ifdef GTKCOMPAT_RESTORE_slots
|
|
#pragma pop_macro("slots")
|
|
#undef GTKCOMPAT_RESTORE_slots
|
|
#endif
|
|
#ifdef GTKCOMPAT_RESTORE_signals
|
|
#pragma pop_macro("signals")
|
|
#undef GTKCOMPAT_RESTORE_signals
|
|
#endif
|
|
#endif
|
|
|
|
#undef GTKCOMPAT_HAS_PUSH_POP_MACRO
|
|
EOF
|
|
|
|
echo "[3/6] Ensuring includes"
|
|
for f in "${FILES_TO_PATCH[@]}"; do
|
|
[[ -f "$f" ]] || continue
|
|
if ! grep -q '^[[:space:]]*#include[[:space:]]*"GtkCompat\.hpp"[[:space:]]*$' "$f"; then
|
|
perl -0777 -i -pe '
|
|
if (s/(#include\s+"[^"]+\.hpp"\s*\n)/$1#include "GtkCompat.hpp"\n/s) {
|
|
} else {
|
|
$_ = "#include \"GtkCompat.hpp\"\n" . $_;
|
|
}
|
|
' "$f"
|
|
fi
|
|
done
|
|
|
|
echo "[4/6] Fix ListBox::remove_all()"
|
|
perl -pi -e 's/\b([A-Za-z_][A-Za-z0-9_]*)\.remove_all\(\)\s*;/GtkCompat::listbox_clear($1);/g' "${FILES_TO_PATCH[@]}"
|
|
|
|
echo "[5/6] Fix get_children() vars and loops (supports auto, auto&, auto*, braced and single-line)"
|
|
for f in "${FILES_TO_PATCH[@]}"; do
|
|
[[ -f "$f" ]] || continue
|
|
|
|
perl -i -pe '
|
|
s/\bauto\s+(\w+)\s*=\s*([A-Za-z_][A-Za-z0-9_:>\-\.\(\)\s]*)\s*\.get_children\s*\(\s*\)\s*;/
|
|
auto $1 = GtkCompat::children($2);/gx
|
|
' "$f"
|
|
|
|
perl -i -pe '
|
|
s/\bauto\s+(\w+)\s*=\s*([A-Za-z_][A-Za-z0-9_:>\-\.\(\)\s]*)\s*->get_children\s*\(\s*\)\s*;/
|
|
auto $1 = GtkCompat::children(*($2));/gx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s/for\s*\(\s*auto\s+(\w+)\s*:\s*([^\)]+?)\.get_children\s*\(\s*\)\s*\)\s*\{/
|
|
for (auto* $1 = ($2).get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s/for\s*\(\s*auto\s*&\s*(\w+)\s*:\s*([^\)]+?)\.get_children\s*\(\s*\)\s*\)\s*\{/
|
|
for (auto* $1 = ($2).get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s/for\s*\(\s*auto\s*\*\s*(\w+)\s*:\s*([^\)]+?)\.get_children\s*\(\s*\)\s*\)\s*\{/
|
|
for (auto* $1 = ($2).get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s/for\s*\(\s*auto\s+(\w+)\s*:\s*([^\)]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\{/
|
|
for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s/for\s*\(\s*auto\s*&\s*(\w+)\s*:\s*([^\)]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\{/
|
|
for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s/for\s*\(\s*auto\s*\*\s*(\w+)\s*:\s*([^\)]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\{/
|
|
for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s@for\s*\(\s*auto\s+(\w+)\s*:\s*([^\n;]+?)\.get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
|
|
$3for (auto* $1 = ($2).get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s@for\s*\(\s*auto\s*&\s*(\w+)\s*:\s*([^\n;]+?)\.get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
|
|
$3for (auto* $1 = ($2).get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s@for\s*\(\s*auto\s*\*\s*(\w+)\s*:\s*([^\n;]+?)\.get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
|
|
$3for (auto* $1 = ($2).get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s@for\s*\(\s*auto\s+(\w+)\s*:\s*([^\n;]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
|
|
$3for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s@for\s*\(\s*auto\s*&\s*(\w+)\s*:\s*([^\n;]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
|
|
$3for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
|
|
' "$f"
|
|
|
|
perl -0777 -i -pe '
|
|
s@for\s*\(\s*auto\s*\*\s*(\w+)\s*:\s*([^\n;]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
|
|
$3for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
|
|
' "$f"
|
|
done
|
|
|
|
echo "[6/6] Generate patch artifact: $PATCH_OUT"
|
|
{
|
|
echo "--- a/src/GtkCompat.hpp"
|
|
echo "+++ b/src/GtkCompat.hpp"
|
|
diff -u "$TMPDIR/GtkCompat.hpp.orig" "$COMPAT_HPP" || true
|
|
echo
|
|
|
|
for f in "${FILES_TO_PATCH[@]}"; do
|
|
[[ -f "$f" ]] || continue
|
|
orig="$TMPDIR/$(backup_key "$f").orig"
|
|
[[ -f "$orig" ]] || continue
|
|
|
|
rel="${f#$ROOT/}"
|
|
echo "--- a/$rel"
|
|
echo "+++ b/$rel"
|
|
diff -u "$orig" "$f" || true
|
|
echo
|
|
done
|
|
} > "$PATCH_OUT"
|
|
|
|
echo "DONE. Residual get_children() occurrences (should be 0):"
|
|
grep -R --line-number "get_children()" -n "$SRC_DIR" || true
|
|
echo
|
|
echo "Patch written to: $PATCH_OUT"
|