aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-06-17 13:38:05 -0500
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-06-17 13:38:05 -0500
commite8b0fa5bd9e83001a82d6501eb39519a71caacdf (patch)
tree2354a7e27b259902d3572112acb1313d3a0f30c6
parent46bc9c9d164ace2c4c0d12a28905e83e2dae74a7 (diff)
Fix bundled font fallback
-rw-r--r--docker/Dockerfile1
-rwxr-xr-xdocker/build-inner.sh61
-rw-r--r--src/src/main.cpp44
-rw-r--r--src/src/moapplication.cpp33
4 files changed, 126 insertions, 13 deletions
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 376f711..a2c0f67 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -12,6 +12,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
# Build essentials
build-essential cmake meson ninja-build ccache \
git curl wget file binutils patchelf pkg-config ca-certificates \
+ fonts-dejavu-core \
# Library dependencies
libboost-all-dev \
libsqlite3-dev \
diff --git a/docker/build-inner.sh b/docker/build-inner.sh
index 135ffff..5c14fce 100755
--- a/docker/build-inner.sh
+++ b/docker/build-inner.sh
@@ -57,6 +57,33 @@ OUT_DIR="/src/build/staging"
rm -rf "${OUT_DIR}"
mkdir -p "${OUT_DIR}/plugins" "${OUT_DIR}/lib"
+# ── Bundled fallback fonts ──
+# The release uses a minimal fontconfig file so bundled fontconfig doesn't try
+# to parse newer host configs. Ship a known Latin UI font so that generic
+# families don't resolve to symbol-only fonts on hosts like Fedora/Bazzite.
+mkdir -p "${OUT_DIR}/fonts" "${OUT_DIR}/licenses"
+DEJAVU_DIR=""
+for candidate in \
+ /usr/share/fonts/truetype/dejavu \
+ /usr/share/fonts/dejavu \
+ /usr/share/fonts/TTF; do
+ if [ -f "${candidate}/DejaVuSans.ttf" ]; then
+ DEJAVU_DIR="${candidate}"
+ break
+ fi
+done
+if [ -z "${DEJAVU_DIR}" ]; then
+ echo "ERROR: DejaVu Sans font not found in build container"
+ exit 1
+fi
+for font in DejaVuSans.ttf DejaVuSans-Bold.ttf DejaVuSansMono.ttf DejaVuSansMono-Bold.ttf; do
+ cp -f "${DEJAVU_DIR}/${font}" "${OUT_DIR}/fonts/"
+done
+if [ -f /usr/share/doc/fonts-dejavu-core/copyright ]; then
+ cp -f /usr/share/doc/fonts-dejavu-core/copyright \
+ "${OUT_DIR}/licenses/fonts-dejavu-core.txt"
+fi
+
# ── Main binary + helpers ──
cp -f "${RUNDIR}/ModOrganizer" "${OUT_DIR}/ModOrganizer-core"
[ -f "${RUNDIR}/README-PORTABLE.txt" ] && cp -f "${RUNDIR}/README-PORTABLE.txt" "${OUT_DIR}/"
@@ -616,19 +643,45 @@ export QT_QPA_PLATFORM_PLUGIN_PATH="${RUN}/qt6plugins/platforms"
# newer /etc/fonts configuration, older bundled fontconfig can warn on syntax
# like xsi:nil and newer generic families. Use a minimal compatible config for
# Fluorine itself; launched games/tools restore the user's original env.
-mkdir -p "${RUN}/etc/fonts"
-cat > "${RUN}/etc/fonts/fonts.conf" <<EOF
+if [ -z "${FLUORINE_DISABLE_FONTCONFIG_FIX:-}" ]; then
+ mkdir -p "${RUN}/etc/fonts"
+ cat > "${RUN}/etc/fonts/fonts.conf" <<EOF
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
+ <dir>${RUN}/fonts</dir>
<dir>/usr/share/fonts</dir>
<dir>/usr/local/share/fonts</dir>
<dir prefix="xdg">fonts</dir>
<cachedir prefix="xdg">fontconfig</cachedir>
+
+ <alias>
+ <family>sans-serif</family>
+ <prefer><family>DejaVu Sans</family></prefer>
+ </alias>
+ <alias>
+ <family>monospace</family>
+ <prefer><family>DejaVu Sans Mono</family></prefer>
+ </alias>
+ <alias>
+ <family>MS Shell Dlg 2</family>
+ <prefer><family>DejaVu Sans</family></prefer>
+ </alias>
+ <alias>
+ <family>Segoe UI</family>
+ <prefer><family>DejaVu Sans</family></prefer>
+ </alias>
+ <alias>
+ <family>Arial</family>
+ <prefer><family>DejaVu Sans</family></prefer>
+ </alias>
</fontconfig>
EOF
-export FONTCONFIG_FILE="${RUN}/etc/fonts/fonts.conf"
-export FONTCONFIG_PATH="${RUN}/etc/fonts"
+ export FONTCONFIG_FILE="${RUN}/etc/fonts/fonts.conf"
+ export FONTCONFIG_PATH="${RUN}/etc/fonts"
+else
+ unset FONTCONFIG_FILE FONTCONFIG_PATH
+fi
# Raise open file descriptor limit — large modlists with FUSE VFS
# can easily exceed the default 1024
diff --git a/src/src/main.cpp b/src/src/main.cpp
index fc10456..74c5aa6 100644
--- a/src/src/main.cpp
+++ b/src/src/main.cpp
@@ -34,15 +34,43 @@ int run(int argc, char* argv[]);
namespace
{
-const char* COMPAT_FONTCONFIG = R"(<?xml version="1.0"?>
+QString compatibleFontconfig(const QString& appDir)
+{
+ const QString fontDir = QDir(appDir).filePath(QStringLiteral("fonts")).toHtmlEscaped();
+
+ return QStringLiteral(R"(<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
+ <dir>%1</dir>
<dir>/usr/share/fonts</dir>
<dir>/usr/local/share/fonts</dir>
<dir prefix="xdg">fonts</dir>
<cachedir prefix="xdg">fontconfig</cachedir>
+
+ <alias>
+ <family>sans-serif</family>
+ <prefer><family>DejaVu Sans</family></prefer>
+ </alias>
+ <alias>
+ <family>monospace</family>
+ <prefer><family>DejaVu Sans Mono</family></prefer>
+ </alias>
+ <alias>
+ <family>MS Shell Dlg 2</family>
+ <prefer><family>DejaVu Sans</family></prefer>
+ </alias>
+ <alias>
+ <family>Segoe UI</family>
+ <prefer><family>DejaVu Sans</family></prefer>
+ </alias>
+ <alias>
+ <family>Arial</family>
+ <prefer><family>DejaVu Sans</family></prefer>
+ </alias>
</fontconfig>
-)";
+)")
+ .arg(fontDir);
+}
void configureCompatibleFontconfig(int argc, char* argv[])
{
@@ -61,13 +89,11 @@ void configureCompatibleFontconfig(int argc, char* argv[])
const QString fontDir = QDir(appDir).filePath(QStringLiteral("etc/fonts"));
const QString configPath = QDir(fontDir).filePath(QStringLiteral("fonts.conf"));
- if (!QFileInfo::exists(configPath)) {
- QDir().mkpath(fontDir);
- QFile config(configPath);
- if (config.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
- config.write(COMPAT_FONTCONFIG);
- config.close();
- }
+ QDir().mkpath(fontDir);
+ QFile config(configPath);
+ if (config.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
+ config.write(compatibleFontconfig(appDir).toUtf8());
+ config.close();
}
if (QFileInfo::exists(configPath)) {
diff --git a/src/src/moapplication.cpp b/src/src/moapplication.cpp
index 16ffb62..9fea4ef 100644
--- a/src/src/moapplication.cpp
+++ b/src/src/moapplication.cpp
@@ -45,6 +45,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QDesktopServices>
#include <QEvent>
#include <QFile>
+#include <QFont>
+#include <QFontDatabase>
#include <QPainter>
#include <QProxyStyle>
#include <QRegularExpression>
@@ -135,6 +137,36 @@ void addLinuxLibrariesToPath()
env::prependToPath(libsPath);
}
+void configureApplicationFont()
+{
+ const QDir fontDir(QCoreApplication::applicationDirPath() + "/fonts");
+ const QStringList bundledFonts{
+ "DejaVuSans.ttf",
+ "DejaVuSans-Bold.ttf",
+ "DejaVuSansMono.ttf",
+ "DejaVuSansMono-Bold.ttf",
+ };
+
+ QString uiFamily;
+ for (const QString& font : bundledFonts) {
+ const int id = QFontDatabase::addApplicationFont(fontDir.filePath(font));
+ if (id < 0 || !uiFamily.isEmpty()) {
+ continue;
+ }
+
+ const QStringList families = QFontDatabase::applicationFontFamilies(id);
+ if (!families.isEmpty()) {
+ uiFamily = families.first();
+ }
+ }
+
+ if (!uiFamily.isEmpty()) {
+ QFont font = QApplication::font();
+ font.setFamily(uiFamily);
+ QApplication::setFont(font);
+ }
+}
+
#ifdef MO2_WEBENGINE
void configureQtWebEngineProcessPath()
{
@@ -205,6 +237,7 @@ void configureQtWebEngineProcessPath()
MOApplication::MOApplication(int& argc, char** argv) : QApplication(argc, argv)
{
TimeThis const tt("MOApplication()");
+ configureApplicationFont();
// Ensure the app name is always "ModOrganizer" regardless of the binary
// filename (settings/profile lookups key off this).