Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,15 @@ if (BUILD_TESTING)
add_subdirectory(autotests)
endif()

if (NOT WIN32)
install(FILES zone.xiv.umbra.desktop DESTINATION ${KDE_INSTALL_APPDIR})
install(FILES zone.xiv.umbra.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
install(FILES zone.xiv.umbra.svg DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps)

ecm_qt_install_logging_categories(
EXPORT UMBRA
FILE umbra.categories
SORT DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
)
endif()
install(FILES zone.xiv.umbra.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
install(FILES zone.xiv.umbra.svg DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps)
install(FILES zone.xiv.umbra.desktop DESTINATION ${KDE_INSTALL_APPDIR})

ecm_qt_install_logging_categories(
EXPORT UMBRA
FILE umbra.categories
SORT DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
)

feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

Expand Down
11 changes: 1 addition & 10 deletions launcher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,22 +121,13 @@ qt_target_qml_sources(umbra_static
ui/Settings/ProfileSettings.qml
ui/Settings/ProfilesPage.qml
ui/Settings/SettingsPage.qml
ui/Settings/TroubleshootingPage.qml
ui/Setup/AccountSetup.qml
ui/Setup/AddSquareEnix.qml
ui/Setup/SetupPage.qml
ui/Main.qml
)

set_source_files_properties(../zone.xiv.umbra.svg PROPERTIES
QT_RESOURCE_ALIAS /zone.xiv.umbra.svg
)

qt_target_qml_sources(umbra_static
PREFIX /
RESOURCES
../zone.xiv.umbra.svg
)

target_link_libraries(umbra PRIVATE
umbra_static
umbra_staticplugin
Expand Down
3 changes: 3 additions & 0 deletions launcher/config.kcfg
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ SPDX-License-Identifier: CC0-1.0
</entry>
<entry name="AutoLoginProfile" type="String">
</entry>
<entry name="VerboseLogging" type="bool">
<default>false</default>
</entry>
</group>
<group name="Sync">
<entry name="EnableSync" type="bool">
Expand Down
7 changes: 4 additions & 3 deletions launcher/src/gamepatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "accountconfig.h"
#include "profile.h"
#include "profileconfig.h"
#include "umbra_log.h"

#include <KLocalizedString>
#include <QDir>
Expand All @@ -22,14 +23,14 @@ QString patchGameExecutable(const Profile &profile)

if (!QFile::exists(backupExePath)) {
if (!QFile::copy(originalGameExecutable, backupExePath)) {
qWarning() << "Failed to copy original game EXE for patching!";
qCWarning(UMBRA_LOG) << "Failed to copy original game EXE for patching!";
return i18n("Failed to copy original game EXE for patching!");
}
}

QFile originalExe(backupExePath);
if (!originalExe.open(QIODevice::ReadOnly)) {
qWarning() << "Failed to patch:" << originalExe.errorString();
qCWarning(UMBRA_LOG) << "Failed to patch:" << originalExe.errorString();
return i18n("Failed to patch: %1").arg(originalExe.errorString());
}

Expand All @@ -53,7 +54,7 @@ QString patchGameExecutable(const Profile &profile)

QFile newExe(originalGameExecutable);
if (!newExe.open(QIODevice::WriteOnly)) {
qWarning() << "Failed to patch:" << newExe.errorString();
qCWarning(UMBRA_LOG) << "Failed to patch:" << newExe.errorString();
return i18n("Failed to patch: %1").arg(newExe.errorString());
}
newExe.write(exeData);
Expand Down
4 changes: 4 additions & 0 deletions launcher/src/launchercore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ LauncherCore::LauncherCore()
: QObject()
{
m_config = new Config(KSharedConfig::openConfig(QStringLiteral("umbrarc"), KConfig::SimpleConfig, QStandardPaths::AppConfigLocation), this);
if (config()->verboseLogging()) {
QLoggingCategory::setFilterRules(QStringLiteral("zone.xiv.umbra*=true"));
}

m_mgr = new QNetworkAccessManager(this);
m_squareEnixLogin = new SquareEnixLogin(*this, this);
m_profileManager = new ProfileManager(this);
Expand Down
44 changes: 28 additions & 16 deletions launcher/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@
#include <KLocalizedString>
#include <KirigamiApp>
#include <QApplication> // NOTE: do not remove this, if your IDE suggests to do so
#include <QIcon>
#include <QQuickStyle>
#include <kdsingleapplication.h>
#include <kdsingleapplication_version.h>
#include <physis.hpp>
#include <qcoroqml.h>

#ifdef Q_OS_WINDOWS
#include <QStyleFactory>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "umbra_log.h"
#endif

#include "umbra-version.h"
#include "launchercore.h"
#include "logger.h"
#include "umbra-version.h"
#include "umbra_log.h"
#include "utility.h"

using namespace Qt::StringLiterals;
Expand Down Expand Up @@ -57,6 +59,7 @@ int main(int argc, char *argv[])

const KDSingleApplication singleApplication;
if (!singleApplication.isPrimaryInstance()) {
qCWarning(UMBRA_LOG) << "Umbra is already running";
return 0;
}

Expand All @@ -66,13 +69,16 @@ int main(int argc, char *argv[])
}

KLocalizedString::setApplicationDomain("umbra");
// This needs to be set before fromAppStreamForApplication can be used, so don't remove this!
QGuiApplication::setDesktopFileName(u"zone.xiv.umbra"_s);

KAboutData about(QStringLiteral("umbra"),
i18n("Umbra"),
QStringLiteral(UMBRA_VERSION_STRING),
i18n("FFXIV 1.x Launcher"),
KAboutLicense::GPL_V3,
i18n("© 2026 Joshua Goins"));
auto about = KAboutData::fromAppStreamForApplication();
about.setVersion(QByteArrayLiteral(UMBRA_VERSION_STRING));
// Works around bug fixed with https://invent.kde.org/frameworks/kcoreaddons/-/merge_requests/582
#if KCOREADDONS_VERSION < QT_VERSION_CHECK(6, 28, 0)
about.setComponentName(QStringLiteral("umbra"));
#endif
about.setCopyrightStatement(i18n("© 2026 Joshua Goins"));
about.setOtherText(
i18n("FINAL FANTASY, FINAL FANTASY XIV, FFXIV, SQUARE ENIX, and the SQUARE ENIX logo are registered trademarks or "
"trademarks of Square Enix Holdings Co., Ltd."));
Expand All @@ -81,19 +87,24 @@ int main(int argc, char *argv[])
QStringLiteral("josh@redstrate.com"),
QStringLiteral("https://redstrate.com/"),
QUrl(QStringLiteral("https://redstrate.com/rss-image.png")));
about.setHomepage(QStringLiteral("https://xiv.zone/umbra"));
about.addComponent(QStringLiteral("physis"),
i18n("Library for reading and writing FFXIV data."),
QString::fromLatin1(physis_get_physis_version()),
QStringLiteral("https://xiv.zone/physis"),
KAboutLicense::GPL_V3);
about.addComponent(QStringLiteral("libphysis"),
i18n("C/C++ bindings for Physis."),
QString::fromLatin1(physis_get_libphysis_version()),
QStringLiteral("https://github.com/redstrate/libphysis"),
KAboutLicense::GPL_V3);
about.addComponent(QStringLiteral("KDSingleApplication"),
i18n("Helper class for single-instance policy applications."),
QStringLiteral("1.1.1"),
QString::fromLatin1(KDSINGLEAPPLICATION_VERSION_STRING),
QStringLiteral("https://github.com/KDAB/KDSingleApplication"),
KAboutLicense::MIT);
about.setDesktopFileName(QStringLiteral("zone.xiv.umbra"));
about.setBugAddress(QByteArrayLiteral("https://github.com/redstrate/umbra/issues"));
about.setComponentName(QStringLiteral("umbra"));
about.setProgramLogo(QStringLiteral("zone.xiv.umbra"));
about.setOrganizationDomain(QByteArrayLiteral("xiv.zone"));

KAboutData::setApplicationData(about);
QGuiApplication::setWindowIcon(QIcon::fromTheme(u"zone.xiv.umbra"_s));

initializeLogging();

Expand Down Expand Up @@ -121,6 +132,7 @@ int main(int argc, char *argv[])

engine.loadFromModule(QStringLiteral("zone.xiv.umbra"), QStringLiteral("Main"));
if (engine.rootObjects().isEmpty()) {
qCWarning(UMBRA_LOG) << "Failed to start application due to QML failing to load!";
return -1;
}

Expand Down
6 changes: 6 additions & 0 deletions launcher/ui/Settings/SettingsPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ KirigamiSettings.ConfigurationView {
page: () => Qt.createComponent("zone.xiv.umbra", "DeveloperSettings")
visible: LauncherCore.config.showDevTools
},
KirigamiSettings.ConfigurationModule {
moduleId: "troubleshooting"
text: i18n("Troubleshooting")
icon.name: "error-symbolic"
page: () => Qt.createComponent("zone.xiv.umbra", "TroubleshootingPage")
},
KirigamiSettings.ConfigurationModule {
moduleId: "about"
text: i18n("About Umbra")
Expand Down
47 changes: 47 additions & 0 deletions launcher/ui/Settings/TroubleshootingPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2026 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later

import QtCore
import QtQuick
import QtQuick.Layouts

import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard

import zone.xiv.umbra

import "../Components"

FormCard.FormCardPage {
id: page

title: i18nc("@title:window", "Troubleshooting")

FormCard.FormCard {
Layout.topMargin: Kirigami.Units.largeSpacing * 4

FormCard.FormCheckDelegate {
id: verboseLoggingDelegate

text: i18n("Enable Verbose Logging")
description: i18n("Requires a restart of Umbra to take effect.")
checked: LauncherCore.config.verboseLogging
onCheckedChanged: {
LauncherCore.config.verboseLogging = checked;
LauncherCore.config.save();
}
}

FormCard.FormDelegateSeparator {
above: verboseLoggingDelegate
below: logsFolderDelegate
}

FormCard.FormButtonDelegate {
id: logsFolderDelegate

text: i18nc("@action:button", "Open Logs Folder")
onClicked: Qt.openUrlExternally(StandardPaths.writableLocation(StandardPaths.AppDataLocation) + "/log")
}
}
}
8 changes: 4 additions & 4 deletions launcher/ui/Setup/SetupPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ FormCard.FormCardPage {
}
}

Image {
source: "qrc:/zone.xiv.umbra.svg"
Kirigami.Icon {
source: "zone.xiv.umbra"

fillMode: Image.PreserveAspectFit
visible: !LauncherCore.profileManager.hasAnyExistingInstallations()

Layout.preferredWidth: Math.round(Kirigami.Units.iconSizes.huge * 1.5)
Layout.preferredHeight: Math.round(Kirigami.Units.iconSizes.huge * 1.5)
Layout.fillWidth: true
Layout.fillHeight: true
Layout.margins: Kirigami.Units.largeSpacing * 3
Expand Down
28 changes: 22 additions & 6 deletions zone.xiv.umbra.appdata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
<id>zone.xiv.umbra</id>
<metadata_license>CC0-1.0</metadata_license>
<name>Umbra</name>
<summary>Linux FFXIV Launcher</summary>
<summary>Unofficial FFXIV launcher for 1.x</summary>
<description>
<p>A unofficial FFXIV launcher for 1.x clients.</p>
<p>Linux FFXIV launcher that supports profiles, multiple accounts!</p>
</description>
<categories>
<category>Game</category>
Expand All @@ -19,9 +19,8 @@
<keyword translate="no">ffxiv</keyword>
<keyword translate="no">ff14</keyword>
</keywords>
<url type="homepage">https://xiv.zone/umbra</url>
<url type="bugtracker">https://github.com/redstrate/umbra/issues</url>
<url type="faq">https://xiv.zone/umbra/faq</url>
<url type="homepage">https://xiv.zone/software/umbra</url>
<url type="bugtracker">https://github.com/redstrate/umbra/issues/new</url>
<url type="contact">https://redstrate.com/contact</url>
<url type="vcs-browser">https://github.com/redstrate/umbra</url>
<launchable type="desktop-id">zone.xiv.umbra.desktop</launchable>
Expand All @@ -45,10 +44,27 @@
<control>touch</control>
</supports>
<project_license>GPL-3.0</project_license>
<developer_name>redstrate</developer_name>
<developer id="com.redstrate">
<name>redstrate</name>
</developer>
<screenshots>
<screenshot type="default">
<image width="1033" height="667">https://xiv.zone/umbra/main-screenshot.png</image>
</screenshot>
</screenshots>
<branding>
<color type="primary" scheme_preference="light">#8d3535</color>
<color type="primary" scheme_preference="dark">#8d3535</color>
</branding>
<content_rating type="oars-1.1">
<content_attribute id="violence-fantasy">intense</content_attribute>
<content_attribute id="violence-bloodshed">moderate</content_attribute>
<content_attribute id="violence-desecration">mild</content_attribute>
<content_attribute id="drugs-alcohol">mild</content_attribute>
<content_attribute id="sex-nudity">mild</content_attribute>
<content_attribute id="sex-themes">mild</content_attribute>
<content_attribute id="language-profanity">moderate</content_attribute>
<content_attribute id="language-humor">mild</content_attribute>
<content_attribute id="social-chat">moderate</content_attribute>
</content_rating>
</component>
Loading