Increase Qt requirement to 5.12 and remove pre-5.12 workarounds

This commit is contained in:
Cameron Gutman 2025-10-11 11:03:33 -05:00
commit 2b3e0803de
7 changed files with 17 additions and 65 deletions

View file

@ -54,7 +54,7 @@ Hosting for Moonlight's Debian and L4T package repositories is graciously provid
* [create-dmg](https://github.com/sindresorhus/create-dmg) (only if building DMGs for use on non-development Macs) * [create-dmg](https://github.com/sindresorhus/create-dmg) (only if building DMGs for use on non-development Macs)
### Linux/Unix Build Requirements ### Linux/Unix Build Requirements
* Qt 6 is recommended, but Qt 5.9 or later is also supported (replace `qmake6` with `qmake` when using Qt 5). * Qt 6 is recommended, but Qt 5.12 or later is also supported (replace `qmake6` with `qmake` when using Qt 5).
* GCC or Clang * GCC or Clang
* FFmpeg 4.0 or later * FFmpeg 4.0 or later
* Install the required packages: * Install the required packages:
@ -75,7 +75,7 @@ Hosting for Moonlight's Debian and L4T package repositories is graciously provid
### Build Setup Steps ### Build Setup Steps
1. Install the latest Qt SDK (and optionally, the Qt Creator IDE) from https://www.qt.io/download 1. Install the latest Qt SDK (and optionally, the Qt Creator IDE) from https://www.qt.io/download
* You can install Qt via Homebrew on macOS, but you will need to use `brew install qt --with-debug` to be able to create debug builds of Moonlight. * You can install Qt via Homebrew on macOS, but you will need to use `brew install qt --with-debug` to be able to create debug builds of Moonlight.
* You may also use your Linux distro's package manager for the Qt SDK as long as the packages are Qt 5.9 or later. * You may also use your Linux distro's package manager for the Qt SDK as long as the packages are Qt 5.12 or later.
* This step is not required for building on Steam Link, because the Steam Link SDK includes Qt 5.14. * This step is not required for building on Steam Link, because the Steam Link SDK includes Qt 5.14.
2. Run `git submodule update --init --recursive` from within `moonlight-qt/` 2. Run `git submodule update --init --recursive` from within `moonlight-qt/`
3. Open the project in Qt Creator or build from qmake on the command line. 3. Open the project in Qt Creator or build from qmake on the command line.

View file

@ -9,8 +9,7 @@
#include <QThread> #include <QThread>
#include <QThreadPool> #include <QThreadPool>
#include <QCoreApplication> #include <QCoreApplication>
#include <QRandomGenerator>
#include <random>
#define SER_HOSTS "hosts" #define SER_HOSTS "hosts"
#define SER_HOSTS_BACKUP "hostsbackup" #define SER_HOSTS_BACKUP "hostsbackup"
@ -966,14 +965,9 @@ void ComputerManager::addNewHost(NvAddress address, bool mdns, NvAddress mdnsIpv
QThreadPool::globalInstance()->start(addTask); QThreadPool::globalInstance()->start(addTask);
} }
// TODO: Use QRandomGenerator when we drop Qt 5.9 support
QString ComputerManager::generatePinString() QString ComputerManager::generatePinString()
{ {
std::uniform_int_distribution<int> dist(0, 9999); return QString::asprintf("%04u", QRandomGenerator::system()->bounded(10000));
std::random_device rd;
std::mt19937 engine(rd());
return QString::asprintf("%04u", dist(engine));
} }
#include "computermanager.moc" #include "computermanager.moc"

View file

@ -38,7 +38,7 @@ CenteredGridView {
activated = true activated = true
// Highlight the first item if a gamepad is connected // Highlight the first item if a gamepad is connected
if (currentIndex == -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) { if (currentIndex === -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) {
currentIndex = 0 currentIndex = 0
} }
@ -94,9 +94,9 @@ CenteredGridView {
// the image size checks if this is not an app collector game. We know the officially // the image size checks if this is not an app collector game. We know the officially
// supported games all have box art, so this check is not required. // supported games all have box art, so this check is not required.
if (!model.isAppCollectorGame && if (!model.isAppCollectorGame &&
((sourceSize.width == 130 && sourceSize.height == 180) || // GFE 2.0 placeholder image ((sourceSize.width === 130 && sourceSize.height === 180) || // GFE 2.0 placeholder image
(sourceSize.width == 628 && sourceSize.height == 888) || // GFE 3.0 placeholder image (sourceSize.width === 628 && sourceSize.height === 888) || // GFE 3.0 placeholder image
(sourceSize.width == 200 && sourceSize.height == 266))) // Our no_app_image.png (sourceSize.width === 200 && sourceSize.height === 266))) // Our no_app_image.png
{ {
isPlaceholder = true isPlaceholder = true
} }
@ -299,18 +299,15 @@ CenteredGridView {
sourceComponent: NavigableMenu { sourceComponent: NavigableMenu {
id: appContextMenu id: appContextMenu
NavigableMenuItem { NavigableMenuItem {
parentMenu: appContextMenu
text: model.running ? qsTr("Resume Game") : qsTr("Launch Game") text: model.running ? qsTr("Resume Game") : qsTr("Launch Game")
onTriggered: launchOrResumeSelectedApp(true) onTriggered: launchOrResumeSelectedApp(true)
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: appContextMenu
text: qsTr("Quit Game") text: qsTr("Quit Game")
onTriggered: doQuitGame() onTriggered: doQuitGame()
visible: model.running visible: model.running
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: appContextMenu
checkable: true checkable: true
checked: model.directLaunch checked: model.directLaunch
text: qsTr("Direct Launch") text: qsTr("Direct Launch")
@ -323,7 +320,6 @@ CenteredGridView {
ToolTip.visible: hovered ToolTip.visible: hovered
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: appContextMenu
checkable: true checkable: true
checked: model.hidden checked: model.hidden
text: qsTr("Hide Game") text: qsTr("Hide Game")

View file

@ -2,10 +2,6 @@ import QtQuick 2.9
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
GridView { GridView {
// Detect Qt 5.11 or earlier using presence of synchronousDrag.
// Prior to 5.12, the leftMargin and rightMargin values did not work.
property bool hasBrokenMargins: this.synchronousDrag === undefined
property int minMargin: 10 property int minMargin: 10
property real availableWidth: (parent.width - 2 * minMargin) property real availableWidth: (parent.width - 2 * minMargin)
property int itemsPerRow: availableWidth / cellWidth property int itemsPerRow: availableWidth / cellWidth
@ -15,11 +11,6 @@ GridView {
function updateMargins() { function updateMargins() {
leftMargin = horizontalMargin leftMargin = horizontalMargin
rightMargin = horizontalMargin rightMargin = horizontalMargin
if (hasBrokenMargins) {
anchors.leftMargin = leftMargin
anchors.rightMargin = rightMargin
}
} }
onHorizontalMarginChanged: { onHorizontalMarginChanged: {
@ -27,15 +18,6 @@ GridView {
} }
Component.onCompleted: { Component.onCompleted: {
if (hasBrokenMargins) {
// This will cause an anchor conflict with the parent StackView
// which breaks animation, but otherwise the grid will not be
// centered in the window.
anchors.fill = parent
anchors.topMargin = topMargin
anchors.bottomMargin = bottomMargin
}
updateMargins() updateMargins()
} }

View file

@ -2,10 +2,6 @@ import QtQuick 2.0
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
MenuItem { MenuItem {
// Qt 5.10 has a menu property, but we need to support 5.9
// so we must make our own.
property Menu parentMenu
// Ensure focus can't be given to an invisible item // Ensure focus can't be given to an invisible item
enabled: visible enabled: visible
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
@ -15,7 +11,7 @@ MenuItem {
// We must close the context menu first or // We must close the context menu first or
// it can steal focus from any dialogs that // it can steal focus from any dialogs that
// onTriggered may spawn. // onTriggered may spawn.
parentMenu.close() menu.close()
} }
Keys.onReturnPressed: { Keys.onReturnPressed: {
@ -27,6 +23,6 @@ MenuItem {
} }
Keys.onEscapePressed: { Keys.onEscapePressed: {
parentMenu.close() menu.close()
} }
} }

View file

@ -35,7 +35,7 @@ CenteredGridView {
ComputerManager.computerAddCompleted.connect(addComplete) ComputerManager.computerAddCompleted.connect(addComplete)
// Highlight the first item if a gamepad is connected // Highlight the first item if a gamepad is connected
if (currentIndex == -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) { if (currentIndex === -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) {
currentIndex = 0 currentIndex = 0
} }
} }
@ -169,7 +169,6 @@ CenteredGridView {
enabled: false enabled: false
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: pcContextMenu
text: qsTr("View All Apps") text: qsTr("View All Apps")
onTriggered: { onTriggered: {
var component = Qt.createComponent("AppView.qml") var component = Qt.createComponent("AppView.qml")
@ -179,13 +178,11 @@ CenteredGridView {
visible: model.online && model.paired visible: model.online && model.paired
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: pcContextMenu
text: qsTr("Wake PC") text: qsTr("Wake PC")
onTriggered: computerModel.wakeComputer(index) onTriggered: computerModel.wakeComputer(index)
visible: !model.online && model.wakeable visible: !model.online && model.wakeable
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: pcContextMenu
text: qsTr("Test Network") text: qsTr("Test Network")
onTriggered: { onTriggered: {
computerModel.testConnectionForComputer(index) computerModel.testConnectionForComputer(index)
@ -194,7 +191,6 @@ CenteredGridView {
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: pcContextMenu
text: qsTr("Rename PC") text: qsTr("Rename PC")
onTriggered: { onTriggered: {
renamePcDialog.pcIndex = index renamePcDialog.pcIndex = index
@ -203,7 +199,6 @@ CenteredGridView {
} }
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: pcContextMenu
text: qsTr("Delete PC") text: qsTr("Delete PC")
onTriggered: { onTriggered: {
deletePcDialog.pcIndex = index deletePcDialog.pcIndex = index
@ -212,7 +207,6 @@ CenteredGridView {
} }
} }
NavigableMenuItem { NavigableMenuItem {
parentMenu: pcContextMenu
text: qsTr("View Details") text: qsTr("View Details")
onTriggered: { onTriggered: {
showPcDetailsDialog.pcDetails = model.details showPcDetailsDialog.pcDetails = model.details

View file

@ -205,20 +205,10 @@ ApplicationWindow {
SdlGamepadKeyNavigation.notifyWindowFocus(visible && active) SdlGamepadKeyNavigation.notifyWindowFocus(visible && active)
} }
// Workaround for lack of instanceof in Qt 5.9.
//
// Based on https://stackoverflow.com/questions/13923794/how-to-do-a-is-a-typeof-or-instanceof-in-qml
function qmltypeof(obj, className) { // QtObject, string -> bool
// className plus "(" is the class instance without modification
// className plus "_QML" is the class instance with user-defined properties
var str = obj.toString();
return str.startsWith(className + "(") || str.startsWith(className + "_QML");
}
function navigateTo(url, objectType) function navigateTo(url, objectType)
{ {
var existingItem = stackView.find(function(item, index) { var existingItem = stackView.find(function(item, index) {
return qmltypeof(item, objectType) return item instanceof objectType
}) })
if (existingItem !== null) { if (existingItem !== null) {
@ -285,7 +275,7 @@ ApplicationWindow {
Label { Label {
id: versionLabel id: versionLabel
visible: qmltypeof(stackView.currentItem, "SettingsView") visible: stackView.currentItem instanceof SettingsView
text: qsTr("Version %1").arg(SystemProperties.versionString) text: qsTr("Version %1").arg(SystemProperties.versionString)
font.pointSize: 12 font.pointSize: 12
horizontalAlignment: Qt.AlignRight horizontalAlignment: Qt.AlignRight
@ -295,7 +285,7 @@ ApplicationWindow {
NavigableToolButton { NavigableToolButton {
id: discordButton id: discordButton
visible: SystemProperties.hasBrowser && visible: SystemProperties.hasBrowser &&
qmltypeof(stackView.currentItem, "SettingsView") stackView.currentItem instanceof SettingsView
iconSource: "qrc:/res/discord.svg" iconSource: "qrc:/res/discord.svg"
@ -314,7 +304,7 @@ ApplicationWindow {
NavigableToolButton { NavigableToolButton {
id: addPcButton id: addPcButton
visible: qmltypeof(stackView.currentItem, "PcView") visible: stackView.currentItem instanceof PcView
iconSource: "qrc:/res/ic_add_to_queue_white_48px.svg" iconSource: "qrc:/res/ic_add_to_queue_white_48px.svg"
@ -412,7 +402,7 @@ ApplicationWindow {
iconSource: "qrc:/res/ic_videogame_asset_white_48px.svg" iconSource: "qrc:/res/ic_videogame_asset_white_48px.svg"
onClicked: navigateTo("qrc:/gui/GamepadMapper.qml", "GamepadMapper") onClicked: navigateTo("qrc:/gui/GamepadMapper.qml", GamepadMapper)
Keys.onDownPressed: { Keys.onDownPressed: {
stackView.currentItem.forceActiveFocus(Qt.TabFocus) stackView.currentItem.forceActiveFocus(Qt.TabFocus)
@ -424,7 +414,7 @@ ApplicationWindow {
iconSource: "qrc:/res/settings.svg" iconSource: "qrc:/res/settings.svg"
onClicked: navigateTo("qrc:/gui/SettingsView.qml", "SettingsView") onClicked: navigateTo("qrc:/gui/SettingsView.qml", SettingsView)
Keys.onDownPressed: { Keys.onDownPressed: {
stackView.currentItem.forceActiveFocus(Qt.TabFocus) stackView.currentItem.forceActiveFocus(Qt.TabFocus)