Skip to content

WIP: Qt6 transition#11651

Open
varjolintu wants to merge 24 commits intokeepassxreboot:developfrom
varjolintu:qt6_ver2
Open

WIP: Qt6 transition#11651
varjolintu wants to merge 24 commits intokeepassxreboot:developfrom
varjolintu:qt6_ver2

Conversation

@varjolintu
Copy link
Copy Markdown
Member

Continues work from #10267, using #11003 as the base.

Fixes #7774.

Type of change

  • ✅ Refactor (significant modification to existing code)

@varjolintu varjolintu added pr: refactoring Pull request refactors code Qt labels Jan 12, 2025
@varjolintu varjolintu added this to the v2.8.0 milestone Jan 12, 2025
@varjolintu varjolintu mentioned this pull request Jan 12, 2025
7 tasks
@varjolintu varjolintu changed the title Qt6 ver2 WIP: Qt6 transition Jan 12, 2025
# TODO: Increase minimum to 2.19.1 and drop Argon2 package
find_package(Botan REQUIRED)
if(BOTAN_VERSION VERSION_GREATER_EQUAL "3.0.0")
set(WITH_BOTAN3 TRUE)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is still a reference to the old define in src/fdosecrets/objects/SessionCipher.cpp:#ifdef WITH_XC_BOTAN3

@Hasshu
Copy link
Copy Markdown

Hasshu commented Feb 16, 2025

Any chance of this making it into v2.7.10? Apparently, Qt 5 is pretty much unsupported at this point.

@varjolintu
Copy link
Copy Markdown
Member Author

Any chance of this making it into v2.7.10? Apparently, Qt 5 is pretty much unsupported at this point.

No. This needs more work.

@Hasshu
Copy link
Copy Markdown

Hasshu commented Feb 17, 2025

@varjolintu Gotcha. Keep up the good work!

@xgqt
Copy link
Copy Markdown

xgqt commented May 8, 2025

QT5 in Gentoo and other (GNU/)Linux distros will be gettting slowly removed. Please see also: https://bugs.gentoo.org/949231
Sadly, I do not have time to help with code for porting. Could help with testing though.
Thanks in advance and very sorry for the noise! :D

#ifdef WITH_XC_X11
auto keycode = XKeysymToKeycode(dpy, qcharToNativeKeyCode(key));
#ifdef WITH_X11
auto keycode = XKeysymToKeycode(dpy, qcharToNativeKeyCode(QChar(key)));
Copy link
Copy Markdown

@ghost ghost Jul 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to make this change:

-    auto keycode = XKeysymToKeycode(dpy, qcharToNativeKeyCode(QChar(key)));
+    auto keycode = XKeysymToKeycode(dpy, qcharToNativeKeyCode(QChar(static_cast<uint>(key))));

to get it to build on my setup.

Copy link
Copy Markdown

@0xIO32 0xIO32 Jul 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this pr already usable?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I this pr already usable?

It builds, runs and can open my KDBX database. I haven't tested further. There might be a showstopping bug somewhere that @varjolintu isn't happy with since he mentioned it "needs more work"... I can't tell.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything just needs to be checked. It's possible that we merge this when possible and the do more fixes later when possible problems are found.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't make sense to force a Qt::Key to QChar. We should use qtToNativeKeyCode directly.

Suggested change
auto keycode = XKeysymToKeycode(dpy, qcharToNativeKeyCode(QChar(key)));
auto keycode = XKeysymToKeycode(dpy, qtToNativeKeyCode(key));

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Aetf This is on my fix list too. I'll update this branch this week when I have the time.

@ghost
Copy link
Copy Markdown

ghost commented Jul 26, 2025

Stuff under /src/fdosecrets seems to be completely broken. I'm not familiar with the codebase but I assume this is a custom DBus layer. @varjolintu I recommend looking at the testguifdosecrets GUI tests, they're failing because the DBus layer broke.
@Aetf Since you wrote the original implementation, could you help out?

@Aetf
Copy link
Copy Markdown
Contributor

Aetf commented Jul 27, 2025

I may be able to take a look this weekend. Too sad that I couldn't spend more time on this.

What is breaking about fdosecrets? It has some custom code to make handling fdosecrets secret service related dbus objects easier. I don't remember anything too out of ordinary from top of my head that would break due to Qt6 though...

@ghost
Copy link
Copy Markdown

ghost commented Jul 27, 2025

I may be able to take a look this weekend. Too sad that I couldn't spend more time on this.

What is breaking about fdosecrets? It has some custom code to make handling fdosecrets secret service related dbus objects easier. I don't remember anything too out of ordinary from top of my head that would break due to Qt6 though...

For one, DBusMgr::deliverMethod is failing for (probably) all the tests:

QWARN  : TestGuiFdoSecrets::testServiceEnable() Internal error: Failed to convert message output to type 65540
QDEBUG : TestGuiFdoSecrets::testServiceEnable() Failed to deliver method QDBusMessage(type=MethodCall, service=":1.0", path="/org/freedesktop/secrets", interface="org.freedesktop.Secret.Service", member="ReadAlias", signature="s", contents=("default") )

The type ID 65540 seems to be QDBusObjectPath.

bool DBusMgr::deliverMethod(...)
{
    ...

    // output args need to be converted before they can be directly sent out:
    for (int i = 0; i != outputArgs.size(); ++i) {
        auto& outputArg = outputArgs[i];
        if (!outputArg.convert(method.outputTargetTypes.at(i))) {
            qWarning() << "Internal error: Failed to convert message output to type"
                       << method.outputTargetTypes.at(i);
            return false;
        }
    }

    ...

The qWarning() ... line is being reached and outputArg.metaType() isn't even a different type from method.outputTargetTypes.at(i). If I skip this check, it crashes.

// Under CollectionProxy of FdoSecretsProxy.h
inline PropertyReply<bool> locked() const
{
    IMPL_GET_PROPERTY(Locked); // crashes here, specifically at the QDBusConnection::call call, inside of which stack traces aren't available
}

@ghost
Copy link
Copy Markdown

ghost commented Jul 27, 2025

image I don't think this does what you think it does?

@ghost
Copy link
Copy Markdown

ghost commented Jul 27, 2025

@Aetf Turns out the QVariant() constructor calls are not supposed to take type IDs anymore in Qt 6.

https://doc.qt.io/qt-6/qvariant-obsolete.html

Same with the convert calls on output args after calling qt_metacall - they're supposed to take QMetaType now.

What I've done so far:

diff --git a/src/fdosecrets/dbus/DBusDispatch.cpp b/src/fdosecrets/dbus/DBusDispatch.cpp
index eee63bdb..0165c62d 100644
--- a/src/fdosecrets/dbus/DBusDispatch.cpp
+++ b/src/fdosecrets/dbus/DBusDispatch.cpp
@@ -20,7 +20,6 @@
 
 #include <QDBusMetaType>
 #include <QThread>
-#include <QtDBus>
 
 namespace FdoSecrets
 {
@@ -32,29 +31,37 @@ namespace FdoSecrets
         return camel.at(0).toUpper() + camel.mid(1);
     }
 
-    bool prepareInputParams(const QVector<int>& inputTypes,
+    bool prepareInputParams(const DBusClientPtr& client,
+                            const QVector<int>& inputTypes,
+                            bool needsCallingClient,
                             const QVariantList& args,
+                            DBusResult& ret,
                             QVarLengthArray<void*, 10>& params,
                             QVariantList& auxParams)
     {
-        // prepare params
+        // reserve to avoid reallocation
+        auxParams.reserve(inputTypes.size() + (needsCallingClient ? 1 : 0));
+
+        // fill auxParams
+        if (needsCallingClient) {
+            auxParams.append(QVariant::fromValue(client));
+        }
+
         for (int count = 0; count != inputTypes.size(); ++count) {
             const auto& id = inputTypes.at(count);
             const auto& arg = args.at(count);
 
             if (arg.userType() == id) {
-                // shortcut for no conversion
-                params.append(const_cast<void*>(arg.constData()));
+                // skip conversion
+                auxParams.append(arg);
                 continue;
             }
 
-            // we need at least one conversion, allocate a slot in auxParams
-            auxParams.append(QVariant(id));
-            auto& out = auxParams.last();
-            // first handle QDBusArgument to wire types
+            QVariant out{QMetaType(id)};
+
             if (arg.userType() == qMetaTypeId<QDBusArgument>()) {
                 QMetaType wireId(typeToWireType(id).dbusTypeId);
-                out = QVariant(wireId, nullptr);
+                out = QVariant(QMetaType(wireId), nullptr);
 
                 const auto& in = arg.value<QDBusArgument>();
                 if (!QDBusMetaType::demarshall(in, wireId, out.data())) {
@@ -63,18 +70,24 @@ namespace FdoSecrets
                     return false;
                 }
             } else {
-                // make a copy to store the converted value
                 out = arg;
             }
-            // other conversions are handled here
-            if (!out.convert(id)) {
-                qDebug() << "Internal error: failed conversion from" << arg << "to type" << QMetaType::typeName(id)
-                         << id;
+
+            if (!out.convert(QMetaType(id))) {
+                qDebug() << "Internal error: failed conversion from" << arg << "to type"
+                         << QMetaType::typeName(id) << id;
                 return false;
             }
-            // good to go
-            params.append(const_cast<void*>(out.constData()));
+
+            auxParams.append(std::move(out));
+        }
+
+        // fill params from auxParams
+        params.append(&ret); // first slot for return value
+        for (const QVariant& var : auxParams) {
+            params.append(const_cast<void*>(var.constData()));
         }
+
         return true;
     }
 
@@ -341,16 +354,8 @@ namespace FdoSecrets
         QVarLengthArray<void*, 10> params;
         QVariantList auxParams;
 
-        // the first one is for return type
-        params.append(&ret);
-
-        if (method.needsCallingClient) {
-            auxParams.append(QVariant::fromValue(client));
-            params.append(const_cast<void*>(auxParams.last().constData()));
-        }
-
         // prepare input
-        if (!prepareInputParams(method.inputTypes, args, params, auxParams)) {
+        if (!prepareInputParams(client, method.inputTypes, method.needsCallingClient, args, ret, params, auxParams)) {
             qDebug() << "Failed to prepare input params";
             return false;
         }
@@ -358,7 +363,7 @@ namespace FdoSecrets
         // prepare output args
         outputArgs.reserve(outputArgs.size() + method.outputTypes.size());
         for (const auto& outputType : asConst(method.outputTypes)) {
-            outputArgs.append(QVariant(outputType));
+            outputArgs.append(QVariant(QMetaType(outputType)));
             params.append(const_cast<void*>(outputArgs.last().constData()));
         }
 
@@ -378,10 +383,17 @@ namespace FdoSecrets
         // output args need to be converted before they can be directly sent out:
         for (int i = 0; i != outputArgs.size(); ++i) {
             auto& outputArg = outputArgs[i];
-            if (!outputArg.convert(method.outputTargetTypes.at(i))) {
-                qWarning() << "Internal error: Failed to convert message output to type"
-                           << method.outputTargetTypes.at(i);
+
+            QMetaType fromType = outputArg.metaType();
+            QMetaType toType = QMetaType(method.outputTargetTypes.at(i));
+
+            QVariant result(toType); // default-construct target type
+            if (!QMetaType::convert(fromType, outputArg.constData(), toType, result.data())) {
+                qWarning() << "Internal error: Failed to convert message output from type"
+                           << fromType.name() << "to type" << toType.name();
                 return false;
+            } else {
+                outputArg = result;
             }
         }

This should get a handful of tests to pass.

Some test cases under testguifdosecrets are still failing/crashing, I'll try to find out what went wrong with those. For now @varjolintu if you can, please apply the patch above to DBusDispatch.cpp.

@ghost
Copy link
Copy Markdown

ghost commented Jul 28, 2025

TestGuiFdoSecrets::testCollectionDeleteConcurrent currently crashes because DatabaseWidget::performSave calls QApplication::processEvents which in turns calls DatabaseWidget::performSave again.

@Aetf
Copy link
Copy Markdown
Contributor

Aetf commented Jul 28, 2025

Working on the code now. Also need the following patch to get gui tests to compile, due to QScopedPointer requires no inline constructor, destructor and assignment operators. https://doc.qt.io/qt-6/qscopedpointer.html#forward-declared-pointers

diff --git a/tests/gui/TestGuiFdoSecrets.cpp b/tests/gui/TestGuiFdoSecrets.cpp
index fc7e218e..88d20db5 100644
--- a/tests/gui/TestGuiFdoSecrets.cpp
+++ b/tests/gui/TestGuiFdoSecrets.cpp
@@ -131,6 +131,7 @@ char* toString(const QDBusObjectPath& path)
     return QTest::toString("ObjectPath(" + path.path() + ")");
 }
 
+TestGuiFdoSecrets::TestGuiFdoSecrets() = default;
 TestGuiFdoSecrets::~TestGuiFdoSecrets() = default;
 
 void TestGuiFdoSecrets::initTestCase()
diff --git a/tests/gui/TestGuiFdoSecrets.h b/tests/gui/TestGuiFdoSecrets.h
index 1624eed4..c6809f38 100644
--- a/tests/gui/TestGuiFdoSecrets.h
+++ b/tests/gui/TestGuiFdoSecrets.h
@@ -55,6 +55,7 @@ class TestGuiFdoSecrets : public QObject
     Q_OBJECT
 
 public:
+    explicit TestGuiFdoSecrets();
     ~TestGuiFdoSecrets() override;
 
 private slots:
@@ -145,6 +146,8 @@ private:
     }
 
 private:
+    Q_DISABLE_COPY(TestGuiFdoSecrets)
+
     QScopedPointer<MainWindow> m_mainWindow;
     QPointer<DatabaseTabWidget> m_tabWidget;
     QPointer<DatabaseWidget> m_dbWidget;

@varjolintu
Copy link
Copy Markdown
Member Author

Thank you :) This makes our job a little bit easier.

@Aetf
Copy link
Copy Markdown
Contributor

Aetf commented Jul 28, 2025

@mutativesystems Thanks for spotting the deprecated QVariant methods. That's super hard to debug! However I think your patch for DBusDispatch.cpp only works because you effectively removed the IsNull check in QVariant::convert. Your impl is exactly the same as Qt's internal impl except that check: https://codebrowser.dev/qt6/qtbase/src/corelib/kernel/qvariant.cpp.html#2137

Therefore after the patch even if the code can progress, there are multiple other errors.

The real issue is outputArgs are all null somehow after qt_metacall. Here's the log output after I added more debug logging:

QWARN  : TestGuiFdoSecrets::testServiceEnable() readAlias "default"
QWARN  : TestGuiFdoSecrets::testServiceEnable() readAlias got collection FdoSecrets::Collection(0x7ccbcaf53620)
QWARN  : TestGuiFdoSecrets::testServiceEnable() outputArg is null true
QWARN  : TestGuiFdoSecrets::testServiceEnable() outputArg is valid true
QWARN  : TestGuiFdoSecrets::testServiceEnable() outputArg type is QVariant(FdoSecrets::Collection*, 0x7ccbcaf53620) usertype: 65592 type id: 65592
QWARN  : TestGuiFdoSecrets::testServiceEnable() outputTargetTypes.at(i) i: 0 value: 65540 is QMetaType(QDBusObjectPath)
QWARN  : TestGuiFdoSecrets::testServiceEnable() Internal error: Failed to convert message output QVariant(QDBusObjectPath, QDBusObjectPath(""))  to type QMetaType(QDBusObjectPath)
FAIL!  : TestGuiFdoSecrets::testServiceEnable() 'rep.isValid()' returned FALSE. (org.qtproject.QtDBus.Error.InternalError)

I still don't get why outputArg is null... Too late for me so I have to stop here. But I feel we are close if we can manage to fix this.

@ghost
Copy link
Copy Markdown

ghost commented Jul 28, 2025

@mutativesystems Thanks for spotting the deprecated QVariant methods. That's super hard to debug! However I think your patch for DBusDispatch.cpp only works because you effectively removed the IsNull check in QVariant::convert. Your impl is exactly the same as Qt's internal impl except that check: https://codebrowser.dev/qt6/qtbase/src/corelib/kernel/qvariant.cpp.html#2137

Therefore after the patch even if the code can progress, there are multiple other errors.

That test case actually passes just fine for me. I edited my comment several times, so make sure you have the new prepareInputParams fix which previously mutilated the pointers in the params QList in deliverMethod.

Edit 1: I take it back, you're right. I'll debug this some more.

Edit 2: this can be fixed like so:

diff --git a/src/fdosecrets/dbus/DBusDispatch.cpp b/src/fdosecrets/dbus/DBusDispatch.cpp
index 0165c62d..6c5f1abd 100644
--- a/src/fdosecrets/dbus/DBusDispatch.cpp
+++ b/src/fdosecrets/dbus/DBusDispatch.cpp
@@ -363,7 +363,7 @@ namespace FdoSecrets
         // prepare output args
         outputArgs.reserve(outputArgs.size() + method.outputTypes.size());
         for (const auto& outputType : asConst(method.outputTypes)) {
-            outputArgs.append(QVariant(QMetaType(outputType)));
+            outputArgs.append(QVariant(QMetaType(outputType), QMetaType(outputType).create()));
             params.append(const_cast<void*>(outputArgs.last().constData()));
         }
 
@@ -383,17 +383,12 @@ namespace FdoSecrets
         // output args need to be converted before they can be directly sent out:
         for (int i = 0; i != outputArgs.size(); ++i) {
             auto& outputArg = outputArgs[i];
+            auto toType = QMetaType(method.outputTargetTypes.at(i));
 
-            QMetaType fromType = outputArg.metaType();
-            QMetaType toType = QMetaType(method.outputTargetTypes.at(i));
-
-            QVariant result(toType); // default-construct target type
-            if (!QMetaType::convert(fromType, outputArg.constData(), toType, result.data())) {
+            if (!outputArg.convert(toType)) {
                 qWarning() << "Internal error: Failed to convert message output from type"
-                           << fromType.name() << "to type" << toType.name();
+                           << outputArg.metaType().name() << "to type" << toType.name();
                 return false;
-            } else {
-                outputArg = result;
             }
         }

Basically to make a QVariant containing a default value instead of a null, we have to use QVariant(QMetaType(outputType), QMetaType(outputType).create()) instead of just QVariant(QMetaType(outputType))

@ghost
Copy link
Copy Markdown

ghost commented Jul 28, 2025

TestGuiFdoSecrets::testCollectionDeleteConcurrent currently crashes because DatabaseWidget::performSave calls QApplication::processEvents which in turns calls DatabaseWidget::performSave again.

For this I'll wait for someone else to figure this out - I'm not familiar with Qt or KPXC's codebase; for now I'm just self-compiling and using it with fdosecrets disabled in CMake.

@varjolintu
Copy link
Copy Markdown
Member Author

varjolintu commented Aug 4, 2025

TestGuiFdoSecrets::testCollectionDeleteConcurrent currently crashes because DatabaseWidget::performSave calls QApplication::processEvents which in turns calls DatabaseWidget::performSave again.

For this I'll wait for someone else to figure this out - I'm not familiar with Qt or KPXC's codebase; for now I'm just self-compiling and using it with fdosecrets disabled in CMake.

I took a quick look, but couldn't find the reason yet. I'm pretty sure it's related to the new code changes in DBusDispatch.cpp, and not the events or performSave() itself.

EDIT: If I revert the line outputArgs.append(QVariant(QMetaType(outputType), QMetaType(outputType).create())); back to the version without .create(), then the tests just fail but won't crash.

varjolintu and others added 17 commits March 15, 2026 08:54
- Fix missing X11 library for linker
- Other Linux fixes

NOTE: FDOSECRETS CURRENTLY CRASHES WHEN ATTEMPTING TO BE USED
* Also reduce minimum Qt version to 6.4.2 to align with Ubuntu 24.04
* Remove Qt6 from vcpkg, prefer use of installed libraries using Qt6_DIR CMake variable.
* Update baseline to latest and remove version minimums since they are not actually minimums but just "something newer than the baseline". See https://devblogs.microsoft.com/cppblog/take-control-of-your-vcpkg-dependencies-with-versioning-support/#how-versioning-works-in-vcpkg
* Revert back to using char instead of wchar_t for PCSC function calls. Linux and macOS don't support widechar calls yet
* Fix signal/slot break in Password Generator
* Add missing POST_BUILD parameters to cmake custom command calls
@droidmonkey
Copy link
Copy Markdown
Member

droidmonkey commented Mar 15, 2026

FDO Secrets is now fully functional! Thanks to Claude for spotting the real issue.

Here was the chat log from the agent for posterity:

I’m going to trace how deliverMethod builds output arguments and performs QVariant::convert under Qt6, then compare that against Qt6 metatype/data-pointer semantics to pinpoint the break and validate a targeted fix.

Searched for regex deliverMethod\(|QVariant\(mtype\)|constData\(\)|convert\(mtype\)|QMetaType::type\( (**/src/fdosecrets/dbus/**), 12 results

Read src/fdosecrets/dbus/DBusDispatch.cpp#1-1, lines 1 to 260

Read src/fdosecrets/dbus/DBusDispatch.cpp#260-260, lines 260 to 394

I found a likely Qt6-specific break: pointer stability and writable variant storage handling changed, and this function is passing constData() pointers (casted) where Qt writes output refs. I’m applying a minimal fix to use writable storage and prevent pointer invalidation during aux parameter growth.

Generating patch (42 lines) in src/fdosecrets/dbus/DBusDispatch.cpp

Checked src/fdosecrets/dbus/DBusDispatch.cpp, 21 problems found

Searched for regex qt_metacall\(|constData\(\)\) (**/src/fdosecrets/**), 5 results

I’ve patched the likely Qt6 regression path in the dispatcher and now I’m verifying the exact changed lines so I can explain the failure mechanism precisely.

Read src/fdosecrets/dbus/DBusDispatch.cpp#34-34, lines 34 to 398

Read changed files in the active git repository

I’ve isolated the failure mode and applied a fix; I’ll do one quick memory check now and then summarize the root cause and why Qt6 exposed it.

Root cause is in how pointers to QVariant payloads are passed into qt_metacall, not in DBus metatype registration.

In Qt6, this code path is much more sensitive to writable storage and pointer stability:

  1. Output/reference arguments were passed using constData() with const-cast, which is unsafe for parameters Qt writes into.
  2. Pointers into auxParams could become invalid when QVariantList grows, because Qt6 QList/QVariantList storage is contiguous and reallocation can move elements.

That combination causes output values to be left invalid or corrupted before the final convert step, so convert fails even though converters are registered.

I applied a targeted fix in DBusDispatch.cpp:

  1. Reserve auxParams capacity before adding entries to keep payload pointers stable: DBusDispatch.cpp, DBusDispatch.cpp
  2. Use writable QVariant storage for arguments that may be written by qt_metacall:
    • calling-client argument pointer now uses data(): DBusDispatch.cpp
    • output refs are initialized with explicit QMetaType and passed via data(): DBusDispatch.cpp, DBusDispatch.cpp
  3. Kept conversion explicit with QMetaType in the output conversion loop: DBusDispatch.cpp

I could not run a full project build/test in this turn, so the next best validation is:

  1. Build the Qt6 branch and exercise one fdosecrets method that returns Secret, Item* or QList<Object*> outputs.
  2. Confirm the conversion warning path in deliverMethod no longer triggers.

Made changes.

if (fd->open(fopen("nul", "w"), QIODevice::WriteOnly)) {
#else
fd->open(fopen("/dev/null", "w"), QIODevice::WriteOnly);
if (fd->open(fopen("/dev/null", "w"), QIODevice::WriteOnly)) {

Check failure

Code scanning / CodeQL

File created without restricting permissions High

A file may be created here with mode 0666, which would make it world-writable.

const auto encoding = QStringConverter::encodingForName("Windows-1252");
QStringEncoder encoder(encoding.value_or(QStringConverter::System));
QByteArray passwordDataCorrect = encoder(password);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be encoder.encode(password). It still doesn't fix the problem though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Qt 6 upgrade