Merge remote-tracking branch 'upstream/develop' into shallow-lazy-otherlogs

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
TheKodeToad 2025-04-28 10:31:48 +01:00
commit 1e3c197222
No known key found for this signature in database
GPG Key ID: 5E39D70B4C93C38E
63 changed files with 651 additions and 633 deletions

2
.envrc
View File

@ -1,2 +1,2 @@
use flake
use nix
watch_file nix/*.nix

View File

@ -0,0 +1,103 @@
# This file incorporates work covered by the following copyright and
# permission notice
#
# Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
name: Get merge commit
description: Get a merge commit of a given pull request
inputs:
repository:
description: Repository containing the pull request
required: false
pull-request-id:
description: ID of a pull request
required: true
outputs:
merge-commit-sha:
description: Git SHA of a merge commit
value: ${{ steps.query.outputs.merge-commit-sha }}
runs:
using: composite
steps:
- name: Wait for GitHub to report merge commit
id: query
shell: bash
env:
GITHUB_REPO: ${{ inputs.repository || github.repository }}
PR_ID: ${{ inputs.pull-request-id }}
# https://github.com/NixOS/nixpkgs/blob/8f77f3600f1ee775b85dc2c72fd842768e486ec9/ci/get-merge-commit.sh
run: |
set -euo pipefail
log() {
echo "$@" >&2
}
# Retry the API query this many times
retryCount=5
# Start with 5 seconds, but double every retry
retryInterval=5
while true; do
log "Checking whether the pull request can be merged"
prInfo=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$GITHUB_REPO/pulls/$PR_ID")
# Non-open PRs won't have their mergeability computed no matter what
state=$(jq -r .state <<<"$prInfo")
if [[ "$state" != open ]]; then
log "PR is not open anymore"
exit 1
fi
mergeable=$(jq -r .mergeable <<<"$prInfo")
if [[ "$mergeable" == "null" ]]; then
if ((retryCount == 0)); then
log "Not retrying anymore. It's likely that GitHub is having internal issues: check https://www.githubstatus.com/"
exit 3
else
((retryCount -= 1)) || true
# null indicates that GitHub is still computing whether it's mergeable
# Wait a couple seconds before trying again
log "GitHub is still computing whether this PR can be merged, waiting $retryInterval seconds before trying again ($retryCount retries left)"
sleep "$retryInterval"
((retryInterval *= 2)) || true
fi
else
break
fi
done
if [[ "$mergeable" == "true" ]]; then
echo "merge-commit-sha=$(jq -r .merge_commit_sha <<<"$prInfo")" >> "$GITHUB_OUTPUT"
else
echo "# 🚨 The PR has a merge conflict!" >>> "$GITHUB_STEP_SUMMARY"
exit 2
fi

View File

@ -52,13 +52,6 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
qt_ver: 5
qt_host: linux
qt_arch: ""
qt_version: "5.15.2"
qt_modules: "qtnetworkauth"
- os: ubuntu-22.04
qt_ver: 6
qt_host: linux
@ -254,7 +247,7 @@ jobs:
arch: ${{ matrix.vcvars_arch }}
- name: Prepare AppImage (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
if: runner.os == 'Linux'
env:
APPIMAGEUPDATE_HASH: ${{ matrix.appimageupdate_hash }}
LINUXDEPLOY_HASH: ${{ matrix.linuxdeploy_hash }}
@ -287,7 +280,7 @@ jobs:
##
- name: Configure CMake (macOS)
if: runner.os == 'macOS' && matrix.qt_ver == 6
if: runner.os == 'macOS'
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
@ -502,7 +495,7 @@ jobs:
}
- name: Package AppImage (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
if: runner.os == 'Linux'
shell: bash
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
@ -598,29 +591,22 @@ jobs:
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-Setup.exe
- name: Upload binary tarball (Linux, portable, Qt 5)
if: runner.os == 'Linux' && matrix.qt_ver != 6
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-portable.tar.gz
- name: Upload binary tarball (Linux, portable, Qt 6)
if: runner.os == 'Linux' && matrix.qt_ver != 5
- name: Upload binary tarball (Linux, portable)
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-portable.tar.gz
- name: Upload AppImage (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
- name: Upload AppImage Zsync (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync

View File

@ -1,6 +1,39 @@
name: "CodeQL Code Scanning"
on: [ push, pull_request, workflow_dispatch ]
on:
push:
# NOTE: `!` doesn't work with `paths-ignore` :(
# So we a catch-all glob instead
# https://github.com/orgs/community/discussions/25369#discussioncomment-3247674
paths:
- "**"
- "!.github/**"
- ".github/workflows/codeql.yml"
- "!flatpak/"
- "!nix/"
- "!scripts/"
- "!.git*"
- "!.envrc"
- "!**.md"
- "COPYING.md"
- "!renovate.json"
pull_request:
# See above
paths:
- "**"
- "!.github/**"
- ".github/workflows/codeql.yml"
- "!flatpak/"
- "!nix/"
- "!scripts/"
- "!.git*"
- "!.envrc"
- "!**.md"
- "COPYING.md"
- "!renovate.json"
workflow_dispatch:
jobs:
CodeQL:
@ -10,7 +43,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: 'true'
submodules: "true"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
@ -20,14 +53,25 @@ jobs:
languages: cpp, java
- name: Install Dependencies
run:
sudo apt-get -y update
run: sudo apt-get -y update
sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 libqt5networkauth5 libqt5networkauth5-dev libqt5opengl5 libqt5opengl5-dev
sudo apt-get -y install ninja-build extra-cmake-modules scdoc
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
aqtversion: "==3.1.*"
py7zrversion: ">=0.20.2"
version: "6.8.1"
host: "linux"
target: "desktop"
arch: ""
modules: "qt5compat qtimageformats qtnetworkauth"
tools: ""
- name: Configure and Build
run: |
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DLauncher_QT_VERSION_MAJOR=5 -G Ninja
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -G Ninja
cmake --build build

View File

@ -2,22 +2,38 @@ name: Flatpak
on:
push:
paths-ignore:
- "**.md"
- "**/LICENSE"
- ".github/ISSUE_TEMPLATE/**"
- ".markdownlint**"
- "nix/**"
# We don't do anything with these artifacts on releases. They go to Flathub
tags-ignore:
- "*"
# NOTE: `!` doesn't work with `paths-ignore` :(
# So we a catch-all glob instead
# https://github.com/orgs/community/discussions/25369#discussioncomment-3247674
paths:
- "**"
- "!.github/**"
- ".github/workflows/flatpak.yml"
- "!nix/"
- "!scripts/"
- "!.git*"
- "!.envrc"
- "!**.md"
- "COPYING.md"
- "!renovate.json"
pull_request:
paths-ignore:
- "**.md"
- "**/LICENSE"
- ".github/ISSUE_TEMPLATE/**"
- ".markdownlint**"
- "nix/**"
# See above
paths:
- "**"
- "!.github/**"
- ".github/workflows/flatpak.yml"
- "!nix/"
- "!scripts/"
- "!.git*"
- "!.envrc"
- "!**.md"
- "COPYING.md"
- "!renovate.json"
workflow_dispatch:
permissions:

View File

@ -1,9 +1,15 @@
name: Merged Blocking Pull Request Automation
on:
pull_request:
pull_request_target:
types:
- closed
workflow_dispatch:
inputs:
pr_id:
description: Local Pull Request number to work on
required: true
type: number
jobs:
update-blocked-status:
@ -12,7 +18,7 @@ jobs:
# a pr that was a `blocking:<id>` label was merged.
# find the open pr's it was blocked by and trigger a refresh of their state
if: github.event.pull_request.merged == true && contains( join( github.event.pull_request.labels.*.name, ',' ), 'blocking' )
if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'blocking') }}
steps:
- name: Generate token
@ -26,11 +32,11 @@ jobs:
id: gather_deps
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_NUMBER: ${{ inputs.pr_id || github.event.pull_request.number }}
run: |
blocked_prs=$(
gh -R ${{ github.repository }} pr list --label 'blocked' --json 'number,body' \
| jq -c --argjson pr "${{ github.event.pull_request.number }}" '
| jq -c --argjson pr "$PR_NUMBER" '
reduce ( .[] | select(
.body |
scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") |

View File

@ -4,28 +4,34 @@ on:
push:
tags:
- "*"
paths-ignore:
- ".github/**"
- "!.github/workflows/nix.yml"
- "flatpak/"
- "scripts/"
# NOTE: `!` doesn't work with `paths-ignore` :(
# So we a catch-all glob instead
# https://github.com/orgs/community/discussions/25369#discussioncomment-3247674
paths:
- "**"
- "!.github/**"
- ".github/workflows/nix.yml"
- "!flatpak/"
- "!scripts/"
- ".git*"
- ".envrc"
- "**.md"
- "!COPYING.md"
- "renovate.json"
- "!.git*"
- "!.envrc"
- "!**.md"
- "COPYING.md"
- "!renovate.json"
pull_request_target:
paths-ignore:
- ".github/**"
- "flatpak/"
- "scripts/"
paths:
- "**"
- "!.github/**"
- ".github/workflows/nix.yml"
- "!flatpak/"
- "!scripts/"
- ".git*"
- ".envrc"
- "**.md"
- "!COPYING.md"
- "renovate.json"
- "!.git*"
- "!.envrc"
- "!**.md"
- "COPYING.md"
- "!renovate.json"
workflow_dispatch:
permissions:
@ -61,11 +67,20 @@ jobs:
id-token: write
steps:
- name: Get merge commit
if: ${{ github.event_name == 'pull_request_target' }}
id: merge-commit
uses: PrismLauncher/PrismLauncher/.github/actions/get-merge-commit@develop
with:
pull-request-id: ${{ github.event.pull_request.id }}
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ steps.merge-commit.outputs.merge-commit-sha || github.sha }}
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@v16
uses: DeterminateSystems/nix-installer-action@v17
with:
determinate: ${{ env.USE_DETERMINATE }}

View File

@ -4,21 +4,39 @@ on:
push:
branches-ignore:
- "renovate/**"
paths-ignore:
- "**.md"
- "**/LICENSE"
- "flake.lock"
- "packages/**"
- ".github/ISSUE_TEMPLATE/**"
- ".markdownlint**"
# NOTE: `!` doesn't work with `paths-ignore` :(
# So we a catch-all glob instead
# https://github.com/orgs/community/discussions/25369#discussioncomment-3247674
paths:
- "**"
- "!.github/**"
- ".github/workflows/build.yml"
- ".github/workflows/trigger_builds.yml"
- "!flatpak/"
- "!nix/"
- "!scripts/"
- "!.git*"
- "!.envrc"
- "!**.md"
- "COPYING.md"
- "!renovate.json"
pull_request:
paths-ignore:
- "**.md"
- "**/LICENSE"
- "flake.lock"
- "packages/**"
- ".github/ISSUE_TEMPLATE/**"
- ".markdownlint**"
# See above
paths:
- "**"
- "!.github/**"
- ".github/workflows/build.yml"
- ".github/workflows/trigger_builds.yml"
- "!flatpak/"
- "!nix/"
- "!scripts/"
- "!.git*"
- "!.envrc"
- "!**.md"
- "COPYING.md"
- "!renovate.json"
workflow_dispatch:
jobs:

View File

@ -46,7 +46,6 @@ jobs:
run: |
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-Linux-Qt5-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
@ -89,7 +88,6 @@ jobs:
draft: true
prerelease: false
files: |
PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-x86_64.AppImage
PrismLauncher-Linux-x86_64.AppImage.zsync
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz

View File

@ -17,7 +17,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@d1ca217b388ee87b2507a9a93bf01368bde7cec2 # v31
- uses: cachix/install-nix-action@754537aaedb35f72ab11a60cc162c49ef3016495 # v31
- uses: DeterminateSystems/update-flake-lock@v24
with:

View File

@ -88,10 +88,8 @@ else()
endif()
endif()
# Fix build with Qt 5.13
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_WARN_DEPRECATED_UP_TO=0x060200")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_UP_TO=0x060000")
# Fix aarch64 build for toml++
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
@ -310,23 +308,7 @@ endif()
# Find the required Qt parts
include(QtVersionlessBackport)
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
set(QT_VERSION_MAJOR 5)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml NetworkAuth OpenGL)
find_package(Qt5 COMPONENTS DBus)
list(APPEND Launcher_QT_DBUS Qt5::DBus)
if(NOT Launcher_FORCE_BUNDLED_LIBS)
find_package(QuaZip-Qt5 1.3 QUIET)
endif()
if (NOT QuaZip-Qt5_FOUND)
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
set(FORCE_BUNDLED_QUAZIP 1)
endif()
# Qt 6 sets these by default. Notably causes Windows APIs to use UNICODE strings.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
set(QT_VERSION_MAJOR 6)
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat NetworkAuth OpenGL)
find_package(Qt6 COMPONENTS DBus)
@ -344,22 +326,12 @@ else()
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
endif()
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
include(ECMQueryQt)
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
else()
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS})
set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS})
set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
endif()
# NOTE: Qt 6 already sets this by default
if (Qt5_POSITION_INDEPENDENT_CODE)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if(NOT Launcher_FORCE_BUNDLED_LIBS)
# Find toml++
find_package(tomlplusplus 3.2.0 QUIET)

View File

@ -108,7 +108,7 @@
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
## Qt 5/6
## Qt 6
Copyright (C) 2022 The Qt Company Ltd and other contributors.
Contact: https://www.qt.io/licensing

18
flake.lock generated
View File

@ -3,11 +3,11 @@
"libnbtplusplus": {
"flake": false,
"locked": {
"lastModified": 1699286814,
"narHash": "sha256-yy0q+bky80LtK1GWzz7qpM+aAGrOqLuewbid8WT1ilk=",
"lastModified": 1744811532,
"narHash": "sha256-qhmjaRkt+O7A+gu6HjUkl7QzOEb4r8y8vWZMG2R/C6o=",
"owner": "PrismLauncher",
"repo": "libnbtplusplus",
"rev": "23b955121b8217c1c348a9ed2483167a6f3ff4ad",
"rev": "531449ba1c930c98e0bcf5d332b237a8566f9d78",
"type": "github"
},
"original": {
@ -18,11 +18,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1744463964,
"narHash": "sha256-LWqduOgLHCFxiTNYi3Uj5Lgz0SR+Xhw3kr/3Xd0GPTM=",
"lastModified": 1744932701,
"narHash": "sha256-fusHbZCyv126cyArUwwKrLdCkgVAIaa/fQJYFlCEqiU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2631b0b7abcea6e640ce31cd78ea58910d31e650",
"rev": "b024ced1aac25639f8ca8fdfc2f8c4fbd66c48ef",
"type": "github"
},
"original": {
@ -35,11 +35,11 @@
"qt-qrcodegenerator": {
"flake": false,
"locked": {
"lastModified": 1731907326,
"narHash": "sha256-5+iYwsbX8wjKZPCy7ENj5HCYgOqzeSNLs/YrX2Vc7CQ=",
"lastModified": 1737616857,
"narHash": "sha256-6SugPt0lp1Gz7nV23FLmsmpfzgFItkSw7jpGftsDPWc=",
"owner": "nayuki",
"repo": "QR-Code-generator",
"rev": "f40366c40d8d1956081f7ec643d240c02a81df52",
"rev": "2c9044de6b049ca25cb3cd1649ed7e27aa055138",
"type": "github"
},
"original": {

View File

@ -138,6 +138,8 @@
{
default = pkgs.mkShell {
name = "prism-launcher";
inputsFrom = [ packages'.prismlauncher-unwrapped ];
packages = with pkgs; [

View File

@ -125,6 +125,7 @@
#include <FileSystem.h>
#include <LocalPeer.h>
#include <QStringLiteral>
#include <stdlib.h>
#include <sys.h>
#include "SysInfo.h"
@ -153,11 +154,16 @@
#endif
#if defined Q_OS_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <QStyleHints>
#include "WindowsConsole.h"
#include "console/WindowsConsole.h"
#endif
#include "console/Console.h"
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
@ -165,6 +171,63 @@ static const QLatin1String liveCheckFile("live.check");
PixmapCache* PixmapCache::s_instance = nullptr;
static bool isANSIColorConsole;
static QString defaultLogFormat = QStringLiteral(
"%{time process}"
" "
"%{if-debug}Debug:%{endif}"
"%{if-info}Info:%{endif}"
"%{if-warning}Warning:%{endif}"
"%{if-critical}Critical:%{endif}"
"%{if-fatal}Fatal:%{endif}"
" "
"%{if-category}[%{category}] %{endif}"
"%{message}"
" "
"(%{function}:%{line})");
#define ansi_reset "\x1b[0m"
#define ansi_bold "\x1b[1m"
#define ansi_reset_bold "\x1b[22m"
#define ansi_faint "\x1b[2m"
#define ansi_italic "\x1b[3m"
#define ansi_red_fg "\x1b[31m"
#define ansi_green_fg "\x1b[32m"
#define ansi_yellow_fg "\x1b[33m"
#define ansi_blue_fg "\x1b[34m"
#define ansi_purple_fg "\x1b[35m"
#define ansi_inverse "\x1b[7m"
// clang-format off
static QString ansiLogFormat = QStringLiteral(
ansi_faint "%{time process}" ansi_reset
" "
"%{if-debug}" ansi_bold ansi_green_fg "D:" ansi_reset "%{endif}"
"%{if-info}" ansi_bold ansi_blue_fg "I:" ansi_reset "%{endif}"
"%{if-warning}" ansi_bold ansi_yellow_fg "W:" ansi_reset_bold "%{endif}"
"%{if-critical}" ansi_bold ansi_red_fg "C:" ansi_reset_bold "%{endif}"
"%{if-fatal}" ansi_bold ansi_inverse ansi_red_fg "F:" ansi_reset_bold "%{endif}"
" "
"%{if-category}" ansi_bold "[%{category}]" ansi_reset_bold " %{endif}"
"%{message}"
" "
ansi_reset ansi_faint "(%{function}:%{line})" ansi_reset
);
// clang-format on
#undef ansi_inverse
#undef ansi_purple_fg
#undef ansi_blue_fg
#undef ansi_yellow_fg
#undef ansi_green_fg
#undef ansi_red_fg
#undef ansi_italic
#undef ansi_faint
#undef ansi_bold
#undef ansi_reset_bold
#undef ansi_reset
namespace {
/** This is used so that we can output to the log file in addition to the CLI. */
@ -173,11 +236,24 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt
static std::mutex loggerMutex;
const std::lock_guard<std::mutex> lock(loggerMutex); // synchronized, QFile logFile is not thread-safe
if (isANSIColorConsole) {
// ensure default is set for log file
qSetMessagePattern(defaultLogFormat);
}
QString out = qFormatLogMessage(type, context, msg);
out += QChar::LineFeed;
APPLICATION->logFile->write(out.toUtf8());
APPLICATION->logFile->flush();
if (isANSIColorConsole) {
// format ansi for console;
qSetMessagePattern(ansiLogFormat);
out = qFormatLogMessage(type, context, msg);
out += QChar::LineFeed;
}
QTextStream(stderr) << out.toLocal8Bit();
fflush(stderr);
}
@ -218,8 +294,18 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
// attach the parent console if stdout not already captured
if (AttachWindowsConsole()) {
consoleAttached = true;
if (auto err = EnableAnsiSupport(); !err) {
isANSIColorConsole = true;
} else {
std::cout << "Error setting up ansi console" << err.message() << std::endl;
}
}
#else
if (console::isConsole()) {
isANSIColorConsole = true;
}
#endif
setOrganizationName(BuildConfig.LAUNCHER_NAME);
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
setApplicationName(BuildConfig.LAUNCHER_NAME);
@ -448,27 +534,14 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
return;
}
qInstallMessageHandler(appDebugOutput);
qSetMessagePattern(
"%{time process}"
" "
"%{if-debug}D%{endif}"
"%{if-info}I%{endif}"
"%{if-warning}W%{endif}"
"%{if-critical}C%{endif}"
"%{if-fatal}F%{endif}"
" "
"|"
" "
"%{if-category}[%{category}]: %{endif}"
"%{message}");
qSetMessagePattern(defaultLogFormat);
bool foundLoggingRules = false;
auto logRulesFile = QStringLiteral("qtlogging.ini");
auto logRulesPath = FS::PathCombine(dataPath, logRulesFile);
qDebug() << "Testing" << logRulesPath << "...";
qInfo() << "Testing" << logRulesPath << "...";
foundLoggingRules = QFile::exists(logRulesPath);
// search the dataPath()
@ -476,7 +549,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
if (!foundLoggingRules && !isPortable() && dirParam.isEmpty() && dataDirEnv.isEmpty()) {
logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile));
if (!logRulesPath.isEmpty()) {
qDebug() << "Found" << logRulesPath << "...";
qInfo() << "Found" << logRulesPath << "...";
foundLoggingRules = true;
}
}
@ -487,28 +560,28 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
#else
logRulesPath = FS::PathCombine(m_rootPath, logRulesFile);
#endif
qDebug() << "Testing" << logRulesPath << "...";
qInfo() << "Testing" << logRulesPath << "...";
foundLoggingRules = QFile::exists(logRulesPath);
}
if (foundLoggingRules) {
// load and set logging rules
qDebug() << "Loading logging rules from:" << logRulesPath;
qInfo() << "Loading logging rules from:" << logRulesPath;
QSettings loggingRules(logRulesPath, QSettings::IniFormat);
loggingRules.beginGroup("Rules");
QStringList rule_names = loggingRules.childKeys();
QStringList rules;
qDebug() << "Setting log rules:";
qInfo() << "Setting log rules:";
for (auto rule_name : rule_names) {
auto rule = QString("%1=%2").arg(rule_name).arg(loggingRules.value(rule_name).toString());
rules.append(rule);
qDebug() << " " << rule;
qInfo() << " " << rule;
}
auto rules_str = rules.join("\n");
QLoggingCategory::setFilterRules(rules_str);
}
qDebug() << "<> Log initialized.";
qInfo() << "<> Log initialized.";
}
{
@ -525,33 +598,33 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
}
{
qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
qDebug() << "Version : " << BuildConfig.printableVersionString();
qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM;
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
qDebug() << "Compiled for : " << BuildConfig.systemID();
qDebug() << "Compiled by : " << BuildConfig.compilerID();
qDebug() << "Build Artifact : " << BuildConfig.BUILD_ARTIFACT;
qDebug() << "Updates Enabled : " << (updaterEnabled() ? "Yes" : "No");
qInfo() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
qInfo() << "Version : " << BuildConfig.printableVersionString();
qInfo() << "Platform : " << BuildConfig.BUILD_PLATFORM;
qInfo() << "Git commit : " << BuildConfig.GIT_COMMIT;
qInfo() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
qInfo() << "Compiled for : " << BuildConfig.systemID();
qInfo() << "Compiled by : " << BuildConfig.compilerID();
qInfo() << "Build Artifact : " << BuildConfig.BUILD_ARTIFACT;
qInfo() << "Updates Enabled : " << (updaterEnabled() ? "Yes" : "No");
if (adjustedBy.size()) {
qDebug() << "Work dir before adjustment : " << origcwdPath;
qDebug() << "Work dir after adjustment : " << QDir::currentPath();
qDebug() << "Adjusted by : " << adjustedBy;
qInfo() << "Work dir before adjustment : " << origcwdPath;
qInfo() << "Work dir after adjustment : " << QDir::currentPath();
qInfo() << "Adjusted by : " << adjustedBy;
} else {
qDebug() << "Work dir : " << QDir::currentPath();
qInfo() << "Work dir : " << QDir::currentPath();
}
qDebug() << "Binary path : " << binPath;
qDebug() << "Application root path : " << m_rootPath;
qInfo() << "Binary path : " << binPath;
qInfo() << "Application root path : " << m_rootPath;
if (!m_instanceIdToLaunch.isEmpty()) {
qDebug() << "ID of instance to launch : " << m_instanceIdToLaunch;
qInfo() << "ID of instance to launch : " << m_instanceIdToLaunch;
}
if (!m_serverToJoin.isEmpty()) {
qDebug() << "Address of server to join :" << m_serverToJoin;
qInfo() << "Address of server to join :" << m_serverToJoin;
} else if (!m_worldToJoin.isEmpty()) {
qDebug() << "Name of the world to join :" << m_worldToJoin;
qInfo() << "Name of the world to join :" << m_worldToJoin;
}
qDebug() << "<> Paths set.";
qInfo() << "<> Paths set.";
}
if (m_liveCheck) {
@ -818,7 +891,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
PixmapCache::setInstance(new PixmapCache(this));
qDebug() << "<> Settings loaded.";
qInfo() << "<> Settings loaded.";
}
#ifndef QT_NO_ACCESSIBILITY
@ -834,7 +907,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
QString user = settings()->get("ProxyUser").toString();
QString pass = settings()->get("ProxyPass").toString();
updateProxySettings(proxyTypeStr, addr, port, user, pass);
qDebug() << "<> Network done.";
qInfo() << "<> Network done.";
}
// load translations
@ -842,8 +915,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_translations.reset(new TranslationsModel("translations"));
auto bcp47Name = m_settings->get("Language").toString();
m_translations->selectLanguage(bcp47Name);
qDebug() << "Your language is" << bcp47Name;
qDebug() << "<> Translations loaded.";
qInfo() << "Your language is" << bcp47Name;
qInfo() << "<> Translations loaded.";
}
// Instance icons
@ -854,7 +927,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_icons.reset(new IconList(instFolders, setting->get().toString()));
connect(setting.get(), &Setting::SettingChanged,
[this](const Setting&, QVariant value) { m_icons->directoryChanged(value.toString()); });
qDebug() << "<> Instance icons initialized.";
qInfo() << "<> Instance icons initialized.";
}
// Themes
@ -866,25 +939,25 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
// instance path: check for problems with '!' in instance path and warn the user in the log
// and remember that we have to show him a dialog when the gui starts (if it does so)
QString instDir = InstDirSetting->get().toString();
qDebug() << "Instance path : " << instDir;
qInfo() << "Instance path : " << instDir;
if (FS::checkProblemticPathJava(QDir(instDir))) {
qWarning() << "Your instance path contains \'!\' and this is known to cause java problems!";
}
m_instances.reset(new InstanceList(m_settings, instDir, this));
connect(InstDirSetting.get(), &Setting::SettingChanged, m_instances.get(), &InstanceList::on_InstFolderChanged);
qDebug() << "Loading Instances...";
qInfo() << "Loading Instances...";
m_instances->loadList();
qDebug() << "<> Instances loaded.";
qInfo() << "<> Instances loaded.";
}
// and accounts
{
m_accounts.reset(new AccountList(this));
qDebug() << "Loading accounts...";
qInfo() << "Loading accounts...";
m_accounts->setListFilePath("accounts.json", true);
m_accounts->loadList();
m_accounts->fillQueue();
qDebug() << "<> Accounts loaded.";
qInfo() << "<> Accounts loaded.";
}
// init the http meta cache
@ -905,7 +978,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_metacache->addBase("meta", QDir("meta").absolutePath());
m_metacache->addBase("java", QDir("cache/java").absolutePath());
m_metacache->Load();
qDebug() << "<> Cache initialized.";
qInfo() << "<> Cache initialized.";
}
// now we have network, download translation updates

View File

@ -99,7 +99,7 @@ set(CORE_SOURCES
MTPixmapCache.h
)
if (UNIX AND NOT CYGWIN AND NOT APPLE)
set(CORE_SOURCES
set(CORE_SOURCES
${CORE_SOURCES}
# MangoHud
@ -589,8 +589,8 @@ set(ATLAUNCHER_SOURCES
)
set(LINKEXE_SOURCES
WindowsConsole.cpp
WindowsConsole.h
console/WindowsConsole.h
console/WindowsConsole.cpp
filelink/FileLink.h
filelink/FileLink.cpp
@ -659,6 +659,14 @@ set(PRISMUPDATER_SOURCES
)
if(WIN32)
set(PRISMUPDATER_SOURCES
console/WindowsConsole.h
console/WindowsConsole.cpp
${PRISMUPDATER_SOURCES}
)
endif()
######## Logging categories ########
ecm_qt_declare_logging_category(CORE_SOURCES
@ -786,6 +794,9 @@ SET(LAUNCHER_SOURCES
SysInfo.h
SysInfo.cpp
# console utils
console/Console.h
# GUI - general utilities
DesktopServices.h
DesktopServices.cpp
@ -1154,7 +1165,7 @@ SET(LAUNCHER_SOURCES
)
if (NOT Apple)
set(LAUNCHER_SOURCES
set(LAUNCHER_SOURCES
${LAUNCHER_SOURCES}
ui/dialogs/UpdateAvailableDialog.h
@ -1164,8 +1175,8 @@ endif()
if(WIN32)
set(LAUNCHER_SOURCES
WindowsConsole.cpp
WindowsConsole.h
console/WindowsConsole.h
console/WindowsConsole.cpp
${LAUNCHER_SOURCES}
)
endif()
@ -1325,11 +1336,11 @@ if(APPLE)
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
if(Launcher_ENABLE_UPDATER)
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
add_compile_definitions(SPARKLE_ENABLED)
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
add_compile_definitions(SPARKLE_ENABLED)
endif()
target_link_libraries(Launcher_logic
@ -1339,7 +1350,7 @@ if(APPLE)
"-framework ApplicationServices"
)
if(Launcher_ENABLE_UPDATER)
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
endif()
endif()

View File

@ -37,11 +37,7 @@ void DataMigrationTask::dryRunFinished()
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
#else
if (!m_copyFuture.result()) {
#endif
emitFailed(tr("Failed to scan source path."));
return;
}
@ -75,11 +71,7 @@ void DataMigrationTask::copyFinished()
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
#else
if (!m_copyFuture.result()) {
#endif
emitFailed(tr("Some paths could not be copied!"));
return;
}

View File

@ -282,11 +282,7 @@ void FileIgnoreProxy::loadBlockedPathsFromFile(const QString& fileName)
}
auto ignoreData = ignoreFile.readAll();
auto string = QString::fromUtf8(ignoreData);
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
setBlockedPaths(string.split('\n', Qt::SkipEmptyParts));
#else
setBlockedPaths(string.split('\n', QString::SkipEmptyParts));
#endif
}
void FileIgnoreProxy::saveBlockedPathsToFile(const QString& fileName)

View File

@ -679,9 +679,6 @@ bool deletePath(QString path)
bool trash(QString path, QString* pathInTrash)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
return false;
#else
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
if (DesktopServices::isFlatpak())
return false;
@ -690,7 +687,6 @@ bool trash(QString path, QString* pathInTrash)
return false;
#endif
return QFile::moveToTrash(path, pathInTrash);
#endif
}
QString PathCombine(const QString& path1, const QString& path2)
@ -724,11 +720,7 @@ int pathDepth(const QString& path)
QFileInfo info(path);
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), QString::SkipEmptyParts);
#else
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), Qt::SkipEmptyParts);
#endif
int numParts = parts.length();
numParts -= parts.count(".");
@ -748,11 +740,7 @@ QString pathTruncate(const QString& path, int depth)
return pathTruncate(trunc, depth);
}
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), QString::SkipEmptyParts);
#else
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), Qt::SkipEmptyParts);
#endif
if (parts.startsWith(".") && !path.startsWith(".")) {
parts.removeFirst();

View File

@ -139,64 +139,80 @@ bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes)
return true;
}
GZipStream::GZipStream(const QString& filePath) : GZipStream(new QFile(filePath)) {}
GZipStream::GZipStream(QFile* file) : m_file(file) {}
bool GZipStream::initStream()
int inf(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
{
memset(&m_strm, 0, sizeof(m_strm));
return (inflateInit2(&m_strm, 16 + MAX_WBITS) == Z_OK);
}
constexpr auto CHUNK = 16384;
int ret;
unsigned have;
z_stream strm;
memset(&strm, 0, sizeof(strm));
char in[CHUNK];
unsigned char out[CHUNK];
bool GZipStream::unzipBlockByBlock(QByteArray& uncompressedBytes)
{
uncompressedBytes.clear();
if (!m_file->isOpen()) {
if (!m_file->open(QIODevice::ReadOnly)) {
qWarning() << "Failed to open file:" << (m_file->fileName());
return false;
ret = inflateInit2(&strm, (16 + MAX_WBITS));
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = source->read(in, CHUNK);
if (source->error()) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
}
if (strm.avail_in == 0)
break;
strm.next_in = reinterpret_cast<Bytef*>(in);
if (!m_strm.state && !initStream()) {
return false;
}
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
if (!handleBlock(QByteArray(reinterpret_cast<const char*>(out), have))) {
(void)inflateEnd(&strm);
return Z_OK;
}
QByteArray compressedBlock;
unsigned int blockSize = 4096;
} while (strm.avail_out == 0);
compressedBlock = m_file->read(blockSize);
if (compressedBlock.isEmpty()) {
return true; // End of file reached
}
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
bool done = processBlock(compressedBlock, uncompressedBytes);
if (inflateEnd(&m_strm) != Z_OK || !done) {
return false;
}
return done;
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
bool GZipStream::processBlock(const QByteArray& compressedBlock, QByteArray& uncompressedBytes)
QString zerr(int ret)
{
m_strm.next_in = (Bytef*)compressedBlock.data();
m_strm.avail_in = compressedBlock.size();
unsigned int uncompLength = uncompressedBytes.size();
if (m_strm.total_out >= uncompLength) {
uncompressedBytes.resize(uncompLength * 2);
uncompLength *= 2;
switch (ret) {
case Z_ERRNO:
return QObject::tr("error handling file");
case Z_STREAM_ERROR:
return QObject::tr("invalid compression level");
case Z_DATA_ERROR:
return QObject::tr("invalid or incomplete deflate data");
case Z_MEM_ERROR:
return QObject::tr("out of memory");
case Z_VERSION_ERROR:
return QObject::tr("zlib version mismatch!");
}
m_strm.next_out = reinterpret_cast<Bytef*>(uncompressedBytes.data() + m_strm.total_out);
m_strm.avail_out = uncompLength - m_strm.total_out;
int err = inflate(&m_strm, Z_NO_FLUSH);
if (err != Z_OK && err != Z_STREAM_END) {
qWarning() << "Decompression failed with error code" << err;
return false;
}
return true;
return {};
}
QString GZip::readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
{
auto ret = inf(source, handleBlock);
return zerr(ret);
}

View File

@ -1,28 +1,11 @@
#pragma once
#include <zlib.h>
#include <QByteArray>
#include <QFile>
class GZip {
public:
static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
};
namespace GZip {
class GZipStream {
public:
explicit GZipStream(const QString& filePath);
explicit GZipStream(QFile* file);
bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
QString readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock);
// Decompress the next block and return the decompressed data
bool unzipBlockByBlock(QByteArray& uncompressedBytes);
private:
bool initStream();
bool processBlock(const QByteArray& compressedBlock, QByteArray& uncompressedBytes);
private:
QFile* m_file;
z_stream m_strm;
};
} // namespace GZip

View File

@ -428,7 +428,7 @@ static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>&
QList<InstanceId> InstanceList::discoverInstances()
{
qDebug() << "Discovering instances in" << m_instDir;
qInfo() << "Discovering instances in" << m_instDir;
QList<InstanceId> out;
QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks);
while (iter.hasNext()) {
@ -447,13 +447,9 @@ QList<InstanceId> InstanceList::discoverInstances()
}
auto id = dirInfo.fileName();
out.append(id);
qDebug() << "Found instance ID" << id;
qInfo() << "Found instance ID" << id;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
instanceSet = QSet<QString>(out.begin(), out.end());
#else
instanceSet = out.toSet();
#endif
m_instancesProbed = true;
return out;
}
@ -468,7 +464,7 @@ InstanceList::InstListError InstanceList::loadList()
if (existingIds.contains(id)) {
auto instPair = existingIds[id];
existingIds.remove(id);
qDebug() << "Should keep and soft-reload" << id;
qInfo() << "Should keep and soft-reload" << id;
} else {
InstancePtr instPtr = loadInstance(id);
if (instPtr) {

View File

@ -53,7 +53,7 @@ static inline QChar getNextChar(const QString& s, int location)
int StringUtils::naturalCompare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs)
{
int l1 = 0, l2 = 0;
while (l1 <= s1.count() && l2 <= s2.count()) {
while (l1 <= s1.size() && l2 <= s2.size()) {
// skip spaces, tabs and 0's
QChar c1 = getNextChar(s1, l1);
while (c1.isSpace())

View File

@ -72,22 +72,14 @@ class Version {
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto numPart = QStringView{ m_fullString }.left(cutoff);
#else
auto numPart = m_fullString.leftRef(cutoff);
#endif
if (!numPart.isEmpty()) {
m_isNull = false;
m_numPart = numPart.toInt();
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto stringPart = QStringView{ m_fullString }.mid(cutoff);
#else
auto stringPart = m_fullString.midRef(cutoff);
#endif
if (!stringPart.isEmpty()) {
m_isNull = false;

View File

@ -0,0 +1,33 @@
#pragma once
#include <QString>
#include <ostream>
#if defined Q_OS_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#else
#include <unistd.h>
#include <cstdio>
#endif
namespace console {
inline bool isConsole()
{
#if defined Q_OS_WIN32
DWORD procIDs[2];
DWORD maxCount = 2;
DWORD result = GetConsoleProcessList((LPDWORD)procIDs, maxCount);
return result > 1;
#else
if (isatty(fileno(stdout))) {
return true;
}
return false;
#endif
}
} // namespace console

View File

@ -16,13 +16,18 @@
*
*/
#include "WindowsConsole.h"
#include <system_error>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <windows.h>
#include <cstddef>
#include <iostream>
void RedirectHandle(DWORD handle, FILE* stream, const char* mode)
@ -126,3 +131,29 @@ bool AttachWindowsConsole()
return false;
}
std::error_code EnableAnsiSupport()
{
// ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
// Using `CreateFileW("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected
HANDLE console_handle = CreateFileW(L"CONOUT$", FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if (console_handle == INVALID_HANDLE_VALUE) {
return std::error_code(GetLastError(), std::system_category());
}
// ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode
DWORD console_mode;
if (0 == GetConsoleMode(console_handle, &console_mode)) {
return std::error_code(GetLastError(), std::system_category());
}
// VT processing not already enabled?
if ((console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0) {
// https://docs.microsoft.com/en-us/windows/console/setconsolemode
if (0 == SetConsoleMode(console_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
return std::error_code(GetLastError(), std::system_category());
}
}
return {};
}

View File

@ -21,5 +21,8 @@
#pragma once
#include <system_error>
void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr);
bool AttachWindowsConsole();
std::error_code EnableAnsiSupport();

View File

@ -37,7 +37,10 @@
#include <sys.h>
#if defined Q_OS_WIN32
#include "WindowsConsole.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include "console/WindowsConsole.h"
#endif
#include <filesystem>

View File

@ -137,11 +137,7 @@ QString formatName(const QDir& iconsDir, const QFileInfo& iconFile)
/// Split into a separate function because the preprocessing impedes readability
QSet<QString> toStringSet(const QList<QString>& list)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QSet<QString> set(list.begin(), list.end());
#else
QSet<QString> set = list.toSet();
#endif
return set;
}

View File

@ -137,11 +137,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
QMap<QString, QString> results;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList lines = m_stdout.split("\n", Qt::SkipEmptyParts);
#else
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
#endif
for (QString line : lines) {
line = line.trimmed();
// NOTE: workaround for GH-4125, where garbage is getting printed into stdout on bedrock linux
@ -149,11 +145,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
continue;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
auto parts = line.split('=', Qt::SkipEmptyParts);
#else
auto parts = line.split('=', QString::SkipEmptyParts);
#endif
if (parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty()) {
continue;
} else {

View File

@ -49,14 +49,10 @@ void PostLaunchCommand::executeTask()
{
auto cmd = m_parent->substituteVariables(m_command);
emit logLine(tr("Running Post-Launch command: %1").arg(cmd), MessageLevel::Launcher);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
auto args = QProcess::splitCommand(cmd);
const QString program = args.takeFirst();
m_process.start(program, args);
#else
m_process.start(cmd);
#endif
}
void PostLaunchCommand::on_state(LoggedProcess::State state)

View File

@ -49,13 +49,9 @@ void PreLaunchCommand::executeTask()
{
auto cmd = m_parent->substituteVariables(m_command);
emit logLine(tr("Running Pre-Launch command: %1").arg(cmd), MessageLevel::Launcher);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
auto args = QProcess::splitCommand(cmd);
const QString program = args.takeFirst();
m_process.start(program, args);
#else
m_process.start(cmd);
#endif
}
void PreLaunchCommand::on_state(LoggedProcess::State state)

View File

@ -757,11 +757,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, Mine
token_mapping["assets_root"] = absAssetsDir;
token_mapping["assets_index_name"] = assets->id;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList parts = args_pattern.split(' ', Qt::SkipEmptyParts);
#else
QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts);
#endif
for (int i = 0; i < parts.length(); i++) {
parts[i] = replaceTokensIn(parts[i], token_mapping);
}
@ -816,11 +812,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftT
auto mainWindow = qobject_cast<QMainWindow*>(w);
if (mainWindow) {
auto m = mainWindow->windowHandle()->frameMargins();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
screenGeometry = screenGeometry.shrunkBy(m);
#else
screenGeometry = { screenGeometry.width() - m.left() - m.right(), screenGeometry.height() - m.top() - m.bottom() };
#endif
break;
}
}

View File

@ -645,11 +645,7 @@ void PackProfile::move(const int index, const MoveDirection direction)
return;
}
beginMoveRows(QModelIndex(), index, index, QModelIndex(), togap);
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
d->components.swapItemsAt(index, theirIndex);
#else
d->components.swap(index, theirIndex);
#endif
endMoveRows();
invalidateLaunchProfile();
scheduleSave();

View File

@ -309,11 +309,7 @@ class WorldMimeData : public QMimeData {
QStringList formats() const { return QMimeData::formats() << "text/uri-list"; }
protected:
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QVariant retrieveData(const QString& mimetype, QMetaType type) const
#else
QVariant retrieveData(const QString& mimetype, QVariant::Type type) const
#endif
{
QList<QUrl> urls;
for (auto& world : m_worlds) {

View File

@ -106,11 +106,7 @@ QPixmap MinecraftAccount::getFace() const
return QPixmap();
}
QPixmap skin = QPixmap(8, 8);
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
skin.fill(QColorConstants::Transparent);
#else
skin.fill(QColor(0, 0, 0, 0));
#endif
QPainter painter(&skin);
painter.drawPixmap(0, 0, skinTexture.copy(8, 8, 8, 8));
painter.drawPixmap(0, 0, skinTexture.copy(40, 8, 8, 8));
@ -290,13 +286,8 @@ QUuid MinecraftAccount::uuidFromUsername(QString username)
// basically a reimplementation of Java's UUID#nameUUIDFromBytes
QByteArray digest = QCryptographicHash::hash(input, QCryptographicHash::Md5);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto bOr = [](QByteArray& array, int index, char value) { array[index] = array.at(index) | value; };
auto bAnd = [](QByteArray& array, int index, char value) { array[index] = array.at(index) & value; };
#else
auto bOr = [](QByteArray& array, qsizetype index, char value) { array[index] |= value; };
auto bAnd = [](QByteArray& array, qsizetype index, char value) { array[index] &= value; };
#endif
bAnd(digest, 6, (char)0x0f); // clear version
bOr(digest, 6, (char)0x30); // set to version 3
bAnd(digest, 8, (char)0x3f); // clear variant

View File

@ -315,11 +315,7 @@ bool parseMinecraftProfileMojang(QByteArray& data, MinecraftProfile& output)
auto value = pObj.value("value");
if (value.isString()) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
texturePayload = QByteArray::fromBase64(value.toString().toUtf8(), QByteArray::AbortOnBase64DecodingErrors);
#else
texturePayload = QByteArray::fromBase64(value.toString().toUtf8());
#endif
}
if (!texturePayload.isEmpty()) {

View File

@ -168,13 +168,8 @@ void MSAStep::perform()
m_oauth2.setRefreshToken(m_data->msaToken.refresh_token);
m_oauth2.refreshAccessToken();
} else {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // QMultiMap param changed in 6.0
m_oauth2.setModifyParametersFunction(
[](QAbstractOAuth::Stage stage, QMultiMap<QString, QVariant>* map) { map->insert("prompt", "select_account"); });
#else
m_oauth2.setModifyParametersFunction(
[](QAbstractOAuth::Stage stage, QMap<QString, QVariant>* map) { map->insert("prompt", "select_account"); });
#endif
*m_data = AccountData();
m_data->msaClientID = m_clientId;

View File

@ -363,16 +363,11 @@ void ResourceFolderModel::onUpdateSucceeded()
auto& new_resources = update_results->resources;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
auto current_list = m_resources_index.keys();
QSet<QString> current_set(current_list.begin(), current_list.end());
auto new_list = new_resources.keys();
QSet<QString> new_set(new_list.begin(), new_list.end());
#else
QSet<QString> current_set(m_resources_index.keys().toSet());
QSet<QString> new_set(new_resources.keys().toSet());
#endif
applyUpdates(current_set, new_set, new_resources);
}

View File

@ -678,13 +678,8 @@ void PackInstallTask::extractConfigs()
return;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), QOverload<QString, QString>::of(MMCZip::extractDir), archivePath,
extractDir.absolutePath() + "/minecraft");
#else
m_extractFuture =
QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/minecraft");
#endif
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, [this]() { downloadMods(); });
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, [this]() { emitAborted(); });
m_extractFutureWatcher.setFuture(m_extractFuture);
@ -897,13 +892,8 @@ void PackInstallTask::onModsDownloaded()
jobPtr.reset();
if (!modsToExtract.empty() || !modsToDecomp.empty() || !modsToCopy.empty()) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_modExtractFuture =
QtConcurrent::run(QThreadPool::globalInstance(), &PackInstallTask::extractMods, this, modsToExtract, modsToDecomp, modsToCopy);
#else
m_modExtractFuture =
QtConcurrent::run(QThreadPool::globalInstance(), this, &PackInstallTask::extractMods, modsToExtract, modsToDecomp, modsToCopy);
#endif
connect(&m_modExtractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &PackInstallTask::onModsExtracted);
connect(&m_modExtractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, &PackInstallTask::emitAborted);
m_modExtractFutureWatcher.setFuture(m_modExtractFuture);

View File

@ -79,7 +79,7 @@ void PackFetchTask::fetchPrivate(const QStringList& toFetch)
QObject::connect(job, &NetJob::succeeded, this, [this, job, data, packCode] {
ModpackList packs;
parseAndAddPacks(*data, PackType::Private, packs);
foreach (Modpack currentPack, packs) {
for (auto& currentPack : packs) {
currentPack.packCode = packCode;
emit privateFileDownloadFinished(currentPack);
}

View File

@ -108,13 +108,8 @@ void PackInstallTask::unzip()
return;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), QOverload<QString, QString>::of(MMCZip::extractDir), archivePath,
extractDir.absolutePath() + "/unzip");
#else
m_extractFuture =
QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/unzip");
#endif
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &PackInstallTask::onUnzipFinished);
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, &PackInstallTask::onUnzipCanceled);
m_extractFutureWatcher.setFuture(m_extractFuture);
@ -165,7 +160,7 @@ void PackInstallTask::install()
// we only care about the libs
QJsonArray libs = doc.object().value("libraries").toArray();
foreach (const QJsonValue& value, libs) {
for (const auto& value : libs) {
QString nameValue = value.toObject().value("name").toString();
if (!nameValue.startsWith("net.minecraftforge")) {
continue;

View File

@ -44,12 +44,8 @@ namespace LegacyFTB {
void PrivatePackManager::load()
{
try {
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
auto foo = QString::fromUtf8(FS::read(m_filename)).split('\n', Qt::SkipEmptyParts);
currentPacks = QSet<QString>(foo.begin(), foo.end());
#else
currentPacks = QString::fromUtf8(FS::read(m_filename)).split('\n', QString::SkipEmptyParts).toSet();
#endif
dirty = false;
} catch (...) {

View File

@ -104,12 +104,10 @@ void NetRequest::executeTask()
header_proxy->writeHeaders(request);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
#if defined(LAUNCHER_APPLICATION)
request.setTransferTimeout(APPLICATION->settings()->get("RequestTimeout").toInt() * 1000);
#else
request.setTransferTimeout();
#endif
#endif
m_last_progress_time = m_clock.now();
@ -122,11 +120,7 @@ void NetRequest::executeTask()
connect(rep, &QNetworkReply::uploadProgress, this, &NetRequest::onProgress);
connect(rep, &QNetworkReply::downloadProgress, this, &NetRequest::onProgress);
connect(rep, &QNetworkReply::finished, this, &NetRequest::downloadFinished);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15
connect(rep, &QNetworkReply::errorOccurred, this, &NetRequest::downloadError);
#else
connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &NetRequest::downloadError);
#endif
connect(rep, &QNetworkReply::sslErrors, this, &NetRequest::sslErrors);
connect(rep, &QNetworkReply::readyRead, this, &NetRequest::downloadReadyRead);
}
@ -323,11 +317,7 @@ auto NetRequest::abort() -> bool
{
m_state = State::AbortedByUser;
if (m_reply) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15
disconnect(m_reply.get(), &QNetworkReply::errorOccurred, nullptr, nullptr);
#else
disconnect(m_reply.get(), QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), nullptr, nullptr);
#endif
m_reply->abort();
}
return true;

View File

@ -130,11 +130,7 @@ void PasteUpload::executeTask()
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
connect(rep, &QNetworkReply::finished, this, &PasteUpload::downloadFinished);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
connect(rep, &QNetworkReply::errorOccurred, this, &PasteUpload::downloadError);
#else
connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &PasteUpload::downloadError);
#endif
m_reply = std::shared_ptr<QNetworkReply>(rep);

View File

@ -480,7 +480,7 @@ bool TranslationsModel::selectLanguage(QString key)
bool successful = false;
// FIXME: this is likely never present. FIX IT.
d->m_qt_translator.reset(new QTranslator());
if (d->m_qt_translator->load("qt_" + langCode, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
if (d->m_qt_translator->load("qt_" + langCode, QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
qDebug() << "Loading Qt Language File for" << langCode.toLocal8Bit().constData() << "...";
if (!QCoreApplication::installTranslator(d->m_qt_translator.get())) {
qCritical() << "Loading Qt Language File failed.";

View File

@ -721,7 +721,7 @@ void MainWindow::changeActiveAccount()
QAction* sAction = (QAction*)sender();
// Profile's associated Mojang username
if (sAction->data().type() != QVariant::Type::Int)
if (sAction->data().typeId() != QMetaType::Int)
return;
QVariant action_data = sAction->data();
@ -811,11 +811,7 @@ void MainWindow::updateNewsLabel()
QList<int> stringToIntList(const QString& string)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList split = string.split(',', Qt::SkipEmptyParts);
#else
QStringList split = string.split(',', QString::SkipEmptyParts);
#endif
QList<int> out;
for (int i = 0; i < split.size(); ++i) {
out.append(split.at(i).toInt());

View File

@ -136,11 +136,7 @@ NewInstanceDialog::NewInstanceDialog(const QString& initialGroup,
if (APPLICATION->settings()->get("NewInstanceGeometry").isValid()) {
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("NewInstanceGeometry").toByteArray()));
} else {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
auto screen = parent->screen();
#else
auto screen = QGuiApplication::primaryScreen();
#endif
auto geometry = screen->availableSize();
resize(width(), qMin(geometry.height() - 50, 710));
}

View File

@ -76,8 +76,8 @@ void SkinOpenGLWindow::mousePressEvent(QMouseEvent* e)
void SkinOpenGLWindow::mouseMoveEvent(QMouseEvent* event)
{
if (m_isMousePressed) {
int dx = event->x() - m_mousePosition.x();
int dy = event->y() - m_mousePosition.y();
int dx = event->position().x() - m_mousePosition.x();
int dy = event->position().y() - m_mousePosition.y();
m_yaw += dx * 0.5f;
m_pitch += dy * 0.5f;

View File

@ -400,12 +400,8 @@ void InstanceView::mouseReleaseEvent(QMouseEvent* event)
if (event->button() == Qt::LeftButton) {
emit clicked(index);
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QStyleOptionViewItem option;
initViewItemOption(&option);
#else
QStyleOptionViewItem option = viewOptions();
#endif
if (m_pressedAlreadySelected) {
option.state |= QStyle::State_Selected;
}
@ -422,7 +418,7 @@ void InstanceView::mouseDoubleClickEvent(QMouseEvent* event)
QModelIndex index = indexAt(event->pos());
if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index)) {
QMouseEvent me(QEvent::MouseButtonPress, event->localPos(), event->windowPos(), event->screenPos(), event->button(),
QMouseEvent me(QEvent::MouseButtonPress, event->position(), event->scenePosition(), event->globalPosition(), event->button(),
event->buttons(), event->modifiers());
mousePressEvent(&me);
return;
@ -431,12 +427,8 @@ void InstanceView::mouseDoubleClickEvent(QMouseEvent* event)
QPersistentModelIndex persistent = index;
emit doubleClicked(persistent);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QStyleOptionViewItem option;
initViewItemOption(&option);
#else
QStyleOptionViewItem option = viewOptions();
#endif
if ((model()->flags(index) & Qt::ItemIsEnabled) && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this)) {
emit activated(index);
}
@ -472,12 +464,8 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event)
painter.setOpacity(1.0);
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QStyleOptionViewItem option;
initViewItemOption(&option);
#else
QStyleOptionViewItem option = viewOptions();
#endif
option.widget = this;
if (model()->rowCount() == 0) {
@ -610,7 +598,7 @@ void InstanceView::dragEnterEvent(QDragEnterEvent* event)
if (!isDragEventAccepted(event)) {
return;
}
m_lastDragPosition = event->pos() + offset();
m_lastDragPosition = event->position().toPoint() + offset();
viewport()->update();
event->accept();
}
@ -622,7 +610,7 @@ void InstanceView::dragMoveEvent(QDragMoveEvent* event)
if (!isDragEventAccepted(event)) {
return;
}
m_lastDragPosition = event->pos() + offset();
m_lastDragPosition = event->position().toPoint() + offset();
viewport()->update();
event->accept();
}
@ -648,7 +636,7 @@ void InstanceView::dropEvent(QDropEvent* event)
if (event->source() == this) {
if (event->possibleActions() & Qt::MoveAction) {
std::pair<VisualGroup*, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
std::pair<VisualGroup*, VisualGroup::HitResults> dropPos = rowDropPos(event->position().toPoint());
const VisualGroup* group = dropPos.first;
auto hitResult = dropPos.second;
@ -732,12 +720,8 @@ QRect InstanceView::geometryRect(const QModelIndex& index) const
int x = pos.first;
// int y = pos.second;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QStyleOptionViewItem option;
initViewItemOption(&option);
#else
QStyleOptionViewItem option = viewOptions();
#endif
QRect out;
out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index));
@ -784,12 +768,8 @@ QPixmap InstanceView::renderToPixmap(const QModelIndexList& indices, QRect* r) c
QPixmap pixmap(r->size());
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QStyleOptionViewItem option;
initViewItemOption(&option);
#else
QStyleOptionViewItem option = viewOptions();
#endif
option.state |= QStyle::State_Selected;
for (int j = 0; j < paintPairs.count(); ++j) {
option.rect = paintPairs.at(j).first.translated(-r->topLeft());

View File

@ -73,12 +73,8 @@ void VisualGroup::update()
positionInRow = 0;
maxRowHeight = 0;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QStyleOptionViewItem viewItemOption;
view->initViewItemOption(&viewItemOption);
#else
QStyleOptionViewItem viewItemOption = view->viewOptions();
#endif
auto itemHeight = view->itemDelegate()->sizeHint(viewItemOption, item).height();
if (itemHeight > maxRowHeight) {

View File

@ -174,48 +174,6 @@ void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index)
}
}
class ReadLineAbstract {
public:
ReadLineAbstract(QFile* file) : m_file(file)
{
if (file->fileName().endsWith(".gz"))
m_gz = new GZipStream(file);
}
~ReadLineAbstract() { delete m_gz; }
QString readLine()
{
if (!m_gz)
return QString::fromUtf8(m_file->readLine());
QString line;
for (;;) {
if (!m_decodedData.isEmpty()) {
int newlineIndex = m_decodedData.indexOf('\n');
if (newlineIndex != -1) {
line += QString::fromUtf8(m_decodedData).left(newlineIndex);
m_decodedData.remove(0, newlineIndex + 1);
return line;
}
line += QString::fromUtf8(m_decodedData);
m_decodedData.clear();
}
if (!m_gz->unzipBlockByBlock(m_decodedData)) { // If error occurs during unzipping
m_decodedData.clear();
return QObject::tr("The content of the file(%1) could not be decoded.").arg(m_file->fileName());
}
}
}
bool done() { return m_gz ? m_decodedData.isEmpty() : m_file->atEnd(); }
private:
QFile* m_file;
GZipStream* m_gz = nullptr;
QByteArray m_decodedData;
};
void OtherLogsPage::on_btnReload_clicked()
{
if (m_currentFile.isEmpty()) {
@ -243,15 +201,9 @@ void OtherLogsPage::on_btnReload_clicked()
showTooBig();
return;
}
ReadLineAbstract stream(&file);
// Try to determine a level for each line
ui->text->clear();
ui->text->setModel(nullptr);
m_model->clear();
auto line = stream.readLine();
while (!stream.done()) { // just read until the model is full or the file ended
auto handleLine = [this](QString line) {
if (line.isEmpty())
return false;
if (line.back() == '\n')
line = line.remove(line.size() - 1, 1);
MessageLevel::Enum level = MessageLevel::Unknown;
@ -268,10 +220,40 @@ void OtherLogsPage::on_btnReload_clicked()
}
m_model->append(level, line);
if (m_model->isOverFlow())
break;
return m_model->isOverFlow();
};
line = stream.readLine();
// Try to determine a level for each line
ui->text->clear();
ui->text->setModel(nullptr);
m_model->clear();
if (file.fileName().endsWith(".gz")) {
QString line;
auto error = GZip::readGzFileByBlocks(&file, [&line, handleLine](const QByteArray& d) {
auto block = d;
int newlineIndex = block.indexOf('\n');
while (newlineIndex != -1) {
line += QString::fromUtf8(block).left(newlineIndex);
block.remove(0, newlineIndex + 1);
if (handleLine(line)) {
line.clear();
return false;
}
line.clear();
newlineIndex = block.indexOf('\n');
}
line += QString::fromUtf8(block);
return true;
});
if (!error.isEmpty()) {
setPlainText(tr("The file (%1) encountered an error when reading: %2.").arg(file.fileName(), error));
return;
} else if (!line.isEmpty()) {
handleLine(line);
}
} else {
while (!file.atEnd() && !handleLine(QString::fromUtf8(file.readLine()))) {
}
}
ui->text->setModel(m_proxy);
ui->text->scrollToBottom();

View File

@ -255,11 +255,7 @@ class ServersModel : public QAbstractListModel {
return false;
}
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row - 1);
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
m_servers.swapItemsAt(row - 1, row);
#else
m_servers.swap(row - 1, row);
#endif
endMoveRows();
scheduleSave();
return true;
@ -275,11 +271,7 @@ class ServersModel : public QAbstractListModel {
return false;
}
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row + 2);
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
m_servers.swapItemsAt(row + 1, row);
#else
m_servers.swap(row + 1, row);
#endif
endMoveRows();
scheduleSave();
return true;

View File

@ -46,11 +46,8 @@
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <windows.h>
#include <iostream>
#include "console/WindowsConsole.h"
#endif
#include <filesystem>
@ -87,112 +84,12 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt
}
}
#if defined Q_OS_WIN32
// taken from https://stackoverflow.com/a/25927081
// getting a proper output to console with redirection support on windows is apparently hell
void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr)
{
// Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been
// observed that the file number of our standard handle file objects can be assigned internally to a value of -2
// when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our
// call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value
// before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to
// use the "nul" device, which will place them into a valid state, after which we can redirect them to our target
// using the "_dup2" function.
if (bindStdIn) {
FILE* dummyFile;
freopen_s(&dummyFile, "nul", "r", stdin);
}
if (bindStdOut) {
FILE* dummyFile;
freopen_s(&dummyFile, "nul", "w", stdout);
}
if (bindStdErr) {
FILE* dummyFile;
freopen_s(&dummyFile, "nul", "w", stderr);
}
// Redirect unbuffered stdin from the current standard input handle
if (bindStdIn) {
HANDLE stdHandle = GetStdHandle(STD_INPUT_HANDLE);
if (stdHandle != INVALID_HANDLE_VALUE) {
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
if (fileDescriptor != -1) {
FILE* file = _fdopen(fileDescriptor, "r");
if (file != NULL) {
int dup2Result = _dup2(_fileno(file), _fileno(stdin));
if (dup2Result == 0) {
setvbuf(stdin, NULL, _IONBF, 0);
}
}
}
}
}
// Redirect unbuffered stdout to the current standard output handle
if (bindStdOut) {
HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (stdHandle != INVALID_HANDLE_VALUE) {
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
if (fileDescriptor != -1) {
FILE* file = _fdopen(fileDescriptor, "w");
if (file != NULL) {
int dup2Result = _dup2(_fileno(file), _fileno(stdout));
if (dup2Result == 0) {
setvbuf(stdout, NULL, _IONBF, 0);
}
}
}
}
}
// Redirect unbuffered stderr to the current standard error handle
if (bindStdErr) {
HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);
if (stdHandle != INVALID_HANDLE_VALUE) {
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
if (fileDescriptor != -1) {
FILE* file = _fdopen(fileDescriptor, "w");
if (file != NULL) {
int dup2Result = _dup2(_fileno(file), _fileno(stderr));
if (dup2Result == 0) {
setvbuf(stderr, NULL, _IONBF, 0);
}
}
}
}
}
// Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the
// standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In
// versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything
// has been read from or written to the targets or not.
if (bindStdIn) {
std::wcin.clear();
std::cin.clear();
}
if (bindStdOut) {
std::wcout.clear();
std::cout.clear();
}
if (bindStdErr) {
std::wcerr.clear();
std::cerr.clear();
}
}
#endif
PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, argv)
{
#if defined Q_OS_WIN32
// attach the parent console if stdout not already captured
auto stdout_type = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
if (stdout_type == FILE_TYPE_CHAR || stdout_type == FILE_TYPE_UNKNOWN) {
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
BindCrtHandlesToStdHandles(true, true, true);
consoleAttached = true;
}
if (AttachWindowsConsole()) {
consoleAttached = true;
}
#endif
setOrganizationName(BuildConfig.LAUNCHER_NAME);

View File

@ -1,9 +1,7 @@
cmake_minimum_required(VERSION 3.15)
project(LocalPeer)
if(QT_VERSION_MAJOR EQUAL 5)
find_package(Qt5 COMPONENTS Core Network REQUIRED)
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
find_package(Qt6 COMPONENTS Core Network Core5Compat REQUIRED)
list(APPEND LocalPeer_LIBS Qt${QT_VERSION_MAJOR}::Core5Compat)
endif()

View File

@ -75,7 +75,7 @@ ApplicationId ApplicationId::fromTraditionalApp()
prefix.remove(QRegularExpression("[^a-zA-Z]"));
prefix.truncate(6);
QByteArray idc = protoId.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
quint16 idNum = qChecksum(idc);
auto socketName = QLatin1String("pl") + prefix + QLatin1Char('-') + QString::number(idNum, 16).left(12);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {

View File

@ -97,6 +97,19 @@ public final class StandardLauncher extends AbstractLauncher {
gameArgs.add(worldName);
}
StringBuilder joinedGameArgs = new StringBuilder();
for (String gameArg : gameArgs) {
if (joinedGameArgs.length() > 0) {
joinedGameArgs.append('\u001F'); // unit separator, designed for this purpose
}
joinedGameArgs.append(gameArg);
}
// pass the real main class and game arguments in so mods can access them
System.setProperty("org.prismlauncher.launch.mainclass", mainClassName);
// unit separator ('\u001F') delimited list of game args
System.setProperty("org.prismlauncher.launch.gameargs", joinedGameArgs.toString());
// find and invoke the main method
MethodHandle method = ReflectionUtils.findMainMethod(mainClassName);
method.invokeExact(gameArgs.toArray(new String[0]));

View File

@ -1,9 +1,7 @@
cmake_minimum_required(VERSION 3.15)
project(qdcss)
if(QT_VERSION_MAJOR EQUAL 5)
find_package(Qt5 COMPONENTS Core REQUIRED)
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
find_package(Qt6 COMPONENTS Core Core5Compat REQUIRED)
list(APPEND qdcss_LIBS Qt${QT_VERSION_MAJOR}::Core5Compat)
endif()

View File

@ -1,9 +1,7 @@
cmake_minimum_required(VERSION 3.15)
project(rainbow)
if(QT_VERSION_MAJOR EQUAL 5)
find_package(Qt5 COMPONENTS Core Gui REQUIRED)
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
find_package(Qt6 COMPONENTS Core Gui REQUIRED)
endif()

View File

@ -1,8 +1,6 @@
project(systeminfo)
if(QT_VERSION_MAJOR EQUAL 5)
find_package(Qt5 COMPONENTS Core REQUIRED)
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
find_package(Qt6 COMPONENTS Core Core5Compat REQUIRED)
list(APPEND systeminfo_LIBS Qt${QT_VERSION_MAJOR}::Core5Compat)
endif()

View File

@ -145,11 +145,7 @@ void Sys::lsb_postprocess(Sys::LsbInfo& lsb, Sys::DistributionInfo& out)
vers = lsb.codename;
} else {
// ubuntu, debian, gentoo, scientific, slackware, ... ?
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
auto parts = dist.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
#else
auto parts = dist.split(QRegularExpression("\\s+"), QString::SkipEmptyParts);
#endif
if (parts.size()) {
dist = parts[0];
}
@ -182,11 +178,7 @@ QString Sys::_extract_distribution(const QString& x)
if (release.startsWith("suse linux enterprise")) {
return "sles";
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList list = release.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
#else
QStringList list = release.split(QRegularExpression("\\s+"), QString::SkipEmptyParts);
#endif
if (list.size()) {
return list[0];
}
@ -196,11 +188,7 @@ QString Sys::_extract_distribution(const QString& x)
QString Sys::_extract_version(const QString& x)
{
QRegularExpression versionish_string(QRegularExpression::anchoredPattern("\\d+(?:\\.\\d+)*$"));
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList list = x.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
#else
QStringList list = x.split(QRegularExpression("\\s+"), QString::SkipEmptyParts);
#endif
for (int i = list.size() - 1; i >= 0; --i) {
QString chunk = list[i];
if (versionish_string.match(chunk).hasMatch()) {

View File

@ -98,9 +98,6 @@ stdenv.mkDerivation {
++ lib.optionals (msaClientID != null) [
(lib.cmakeFeature "Launcher_MSA_CLIENT_ID" (toString msaClientID))
]
++ lib.optionals (lib.versionOlder kdePackages.qtbase.version "6") [
(lib.cmakeFeature "Launcher_QT_VERSION_MAJOR" "5")
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
# we wrap our binary manually
(lib.cmakeFeature "INSTALL_BUNDLE" "nodeps")

4
shell.nix Normal file
View File

@ -0,0 +1,4 @@
(import (fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/ff81ac966bb2cae68946d5ed5fc4994f96d0ffec.tar.gz";
sha256 = "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=";
}) { src = ./.; }).shellNix