copy just enough gstreamer plugins and handle deps for Windows build

- Added custom command to copy libZUpdater.dll for deployment
- Updated win-deploy.cmake to copy specific GStreamer plugins
- Introduced install scripts for Apple drivers and WinFsp
- Improved DiagnoseWidget UI with scroll area and process indicators
- Adjusted WelcomeWidget to include DiagnoseWidget on non-Apple platforms
This commit is contained in:
uncor3
2025-11-02 11:39:17 -08:00
parent d3f4c74fbc
commit 7eaed96a85
11 changed files with 367 additions and 106 deletions
+12
View File
@@ -387,3 +387,15 @@ if(WIN32)
endif()
include(CPack)
# FIXME: move to win-deploy.cmake
if(WIN32)
# Ensure libZUpdater.dll is copied next to the main executable for deployment
add_custom_command(TARGET iDescriptor POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:ZUpdater>
$<TARGET_FILE_DIR:iDescriptor>
COMMENT "Copying libZUpdater.dll to executable directory"
)
endif()
+49 -18
View File
@@ -19,7 +19,6 @@ message(" MSYS2_BIN_PATH: ${MSYS2_BIN_PATH}")
if(NOT EXISTS ${EXECUTABLE_PATH})
message(STATUS "Executable not found: ${EXECUTABLE_PATH}")
message(STATUS "Checking if it's a path issue...")
# Try to find the executable with different path formats
get_filename_component(DIR_PATH ${EXECUTABLE_PATH} DIRECTORY)
@@ -75,7 +74,7 @@ file(GET_RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES "^api-ms-" "^ext-ms-" "^AVRT" "^avrt" "^MSVCP" "^VCRUNTIME" "^ucrtbase" "^libgcc_s_seh-1\\.dll$" "^libstdc\\+\\+-6\\.dll$" "^libwinpthread-1\\.dll$" "^Qt.*\\.dll$" "^libgstreamer-1\\.0-0\\.dll$" "^libgstbase-1\\.0-0\\.dll$" "^libgobject-2\\.0-0\\.dll$" "^libglib-2\\.0-0\\.dll$" "^libintl-8\\.dll$" "^libiconv-2\\.dll$"
#PRE_EXCLUDE_REGEXES "^api-ms-" "^ext-ms-" "^AVRT" "^avrt" "^MSVCP" "^VCRUNTIME" "^ucrtbase"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll" ".*SysWOW64/.*\\.dll" ".*Windows/.*\\.dll" ".*Microsoft.VC.*" ".*Qt.*\\.dll$"
DIRECTORIES ${QT_BIN_PATH} ${MSYS2_BIN_PATH} "C:/lxqt/lib" $ENV{PATH}
DIRECTORIES ${BUILD_DIR} ${QT_BIN_PATH} ${MSYS2_BIN_PATH} "C:/lxqt/lib" $ENV{PATH}
)
set(COPIED_DLLS 0)
@@ -119,23 +118,52 @@ message("Processed ${TOTAL_DLLS} runtime dependencies, copied ${COPIED_DLLS} fil
# Step 3: Copy GStreamer plugins
message("Copying GStreamer plugins...")
file(GLOB GSTREAMER_PLUGINS "${MSYS2_BIN_PATH}/../lib/gstreamer-1.0/*.dll")
# OLD: file(GLOB GSTREAMER_PLUGINS "${MSYS2_BIN_PATH}/../lib/gstreamer-1.0/*.dll")
# Replace broad copy with targeted list (matches versioned names via glob)
set(GSTREAMER_PLUGIN_DIR "${MSYS2_BIN_PATH}/../lib/gstreamer-1.0")
if(GSTREAMER_PLUGINS)
# Create gstreamer-1.0 directory in output
file(MAKE_DIRECTORY ${OUTPUT_DIR}/gstreamer-1.0)
foreach(PLUGIN ${GSTREAMER_PLUGINS})
get_filename_component(PLUGIN_NAME ${PLUGIN} NAME)
message("Copying GStreamer plugin: ${PLUGIN_NAME}")
file(COPY ${PLUGIN} DESTINATION ${OUTPUT_DIR}/gstreamer-1.0)
endforeach()
list(LENGTH GSTREAMER_PLUGINS PLUGIN_COUNT)
message("Successfully copied ${PLUGIN_COUNT} GStreamer plugins")
else()
message(WARNING "No GStreamer plugins found in ${MSYS2_BIN_PATH}/../lib/gstreamer-1.0/")
endif()
# List of plugin basenames to copy (no extension or version). Add items as needed.
set(WANTED_PLUGINS
"libgstaudioconvert"
"libgstvolume"
"libgstcoreelements"
"libgstautodetect"
"libgstdirectsound"
"libgstlibav"
"libgstapp"
"libgstlevel"
"libgstwasapi"
"libgstplayback"
"libgstaudioresample"
"libgstaudiomixer"
"libgstaudiotestsrc"
"libgstmediafoundation"
"libgstdecodebin"
"libgsttypefindfunctions"
"libgstvideoscale"
"libgstvideoconvert"
"libgstvideorate"
"libgstoverlaycomposition"
)
file(MAKE_DIRECTORY "${OUTPUT_DIR}/gstreamer-1.0")
set(COPIED_PLUGIN_COUNT 0)
foreach(BASENAME ${WANTED_PLUGINS})
# match any versioned filename starting with the basename
file(GLOB MATCHES "${GSTREAMER_PLUGIN_DIR}/${BASENAME}*.dll")
if(MATCHES)
foreach(PLUGIN_PATH ${MATCHES})
get_filename_component(PLUGIN_NAME ${PLUGIN_PATH} NAME)
message("Copying GStreamer plugin: ${PLUGIN_NAME}")
file(COPY "${PLUGIN_PATH}" DESTINATION "${OUTPUT_DIR}/gstreamer-1.0")
math(EXPR COPIED_PLUGIN_COUNT "${COPIED_PLUGIN_COUNT} + 1")
endforeach()
else()
message(WARNING "Requested GStreamer plugin not found: ${BASENAME} (searched ${GSTREAMER_PLUGIN_DIR})")
endif()
endforeach()
message("Successfully copied ${COPIED_PLUGIN_COUNT} requested GStreamer plugins")
# Step 4: Manually copy the correct MSYS2 MinGW runtime DLLs.
# This ensures the versions required by GStreamer/FFmpeg are used.
@@ -204,5 +232,8 @@ file(COPY "${GST_LIBEXEC_PATH}/gst-ptp-helper.exe" DESTINATION "${OUTPUT_DIR}/li
message("Copying executables")
file(COPY C:/msys64/mingw64/bin/iproxy.exe DESTINATION ${OUTPUT_DIR})
message("Copying required scripts")
file(COPY "${CMAKE_SOURCE_DIR}/install-apple-drivers.ps1" DESTINATION ${OUTPUT_DIR})
file(COPY "${CMAKE_SOURCE_DIR}/install-win-fsp.silent.bat" DESTINATION ${OUTPUT_DIR})
message("=== Windows deployment completed ===")
+68
View File
@@ -0,0 +1,68 @@
## Taken from https://github.com/NelloKudo/Apple-Mobile-Drivers-Installer
## Apple USB and Mobile Device Ethernet drivers installer!
## Please report any issues at GitHub: https://github.com/NelloKudo/Apple-Mobile-Drivers-Installer
## Download links for Apple USB Drivers and Apple Mobile Ethernet USB Drivers respectively.
## All of these are downloaded from Microsoft's Update Catalog, which you can browse yourself at here: https://www.catalog.update.microsoft.com/
$AppleDri1 = "https://catalog.s.download.windowsupdate.com/d/msdownload/update/driver/drvs/2020/11/01d96dfd-2f6f-46f7-8bc3-fd82088996d2_a31ff7000e504855b3fa124bf27b3fe5bc4d0893.cab"
$AppleDri2 = "https://catalog.s.download.windowsupdate.com/c/msdownload/update/driver/drvs/2017/11/netaapl_7503681835e08ce761c52858949731761e1fa5a1.cab"
$AppleITunesLink = "https://www.apple.com/itunes/download/win64"
Write-Host ""
Write-Host -ForegroundColor Cyan "Welcome to Apple USB and Mobile Device Ethernet drivers installer!!"
Write-Host ""
## Checking if the script is being run as admin..
if (-not ([Security.Principal.WindowsIdentity]::GetCurrent().Groups -contains 'S-1-5-32-544')) {
Write-Host -ForegroundColor Yellow "This script requires administrative privileges!"
Write-Host -ForegroundColor Yellow "Please run the script as an administrator if you want to install drivers."
pause
exit 1
}
## Preparing the system to actually download drivers..
$destinationFolder = [System.IO.Path]::Combine($env:TEMP, "AppleDriTemp")
if (-not (Test-Path $destinationFolder)) {
New-Item -ItemType Directory -Path $destinationFolder | Out-Null
}
try {
$currentPath = $PWD.Path
Write-Host -ForegroundColor Yellow "Downloading Apple iTunes and installing AppleMobileDeviceSupport64.msi.."
Write-Host -ForegroundColor Yellow "(It might take a while! Script is not frozen!)"
(New-Object System.Net.WebClient).DownloadFile($AppleITunesLink, [System.IO.Path]::Combine($destinationFolder, "iTunes64Setup.exe"))
cd "$destinationFolder"
Start-Process -FilePath "$destinationFolder\iTunes64Setup.exe" -ArgumentList "/extract" -Wait
cd "$currentPath"
Start-Process -FilePath "$destinationFolder\AppleMobileDeviceSupport64.msi" -ArgumentList "/qn" -Wait
Write-Host -ForegroundColor Yellow "Downloading Apple USB and Mobile Device Ethernet drivers from Microsoft..."
Invoke-WebRequest -Uri $AppleDri1 -OutFile ([System.IO.Path]::Combine($destinationFolder, "AppleUSB-486.0.0.0-driv.cab"))
Invoke-WebRequest -Uri $AppleDri2 -OutFile ([System.IO.Path]::Combine($destinationFolder, "AppleNet-1.8.5.1-driv.cab"))
Write-Host -ForegroundColor Yellow "Extracting drivers..."
& expand.exe -F:* "$destinationFolder\AppleUSB-486.0.0.0-driv.cab" "$destinationFolder" >$null 2>&1
& expand.exe -F:* "$destinationFolder\AppleNet-1.8.5.1-driv.cab" "$destinationFolder" >$null 2>&1
## Installing drivers..
Write-Host -ForegroundColor Yellow "Installing Apple USB and Mobile Device Ethernet drivers!"
Write-Host -ForegroundColor Yellow "If any of your peripherals stop working for a few seconds that's due to Apple stuff installing."
Write-Host ""
Get-ChildItem -Path "$destinationFolder\*.inf" | ForEach-Object {
pnputil /add-driver $_.FullName /install
Write-Host ""
Write-Host -ForegroundColor Yellow "Driver installed.."
Write-Host ""
}
## Cleaning..
Remove-Item -Path $destinationFolder -Recurse -Force
} catch {
Write-Host -ForegroundColor Red "Failed to complete installation. Error: $_"
}
Write-Host ""
Write-Host -ForegroundColor Cyan "Installation complete! Enjoy your Apple devices!!"
Write-Host -ForegroundColor Yellow "(If devices are still not working, a reboot might be needed!!)"
+29
View File
@@ -0,0 +1,29 @@
@echo off
setlocal enabledelayedexpansion
net session >nul 2>&1
if %errorlevel% neq 0 (
exit /b 1
)
echo Installing WinFsp...
set "DOWNLOAD_URL=https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi"
set "CACHE_DIR=%TEMP%\winfsp-install"
set "MSI_FILE=%CACHE_DIR%\winfsp-2.1.25156.msi"
if not exist "%CACHE_DIR%" mkdir "%CACHE_DIR%"
curl -L -o "%MSI_FILE%" "%DOWNLOAD_URL%"
if %errorlevel% neq 0 (
exit /b 1
)
msiexec /i "%MSI_FILE%" /quiet /norestart
if %errorlevel% neq 0 (
rmdir /s /q "%CACHE_DIR%"
exit /b 1
)
rmdir /s /q "%CACHE_DIR%"
exit /b 0
-2
View File
@@ -20,8 +20,6 @@
<file>resources/icons/MdiGithub.png</file>
<file>resources/icons/app-icon/icon.ico</file>
<file>qml/MapView.qml</file>
<!-- TODO: -->
<!-- <file>resources/dump.js</file> -->
<file>resources/iphone.png</file>
<file>resources/ios-wallpapers/iphone-ios4.png</file>
<file>resources/ios-wallpapers/iphone-ios5.png</file>
-31
View File
@@ -28,10 +28,6 @@
#include <QMenuBar>
#include <QMessageBox>
#ifdef WIN32
#include "platform/windows/diagnose_widget.h"
#endif
void handleCallback(const idevice_event_t *event, void *userData)
{
printf("Device event received: ");
@@ -79,7 +75,6 @@ void handleCallback(const idevice_event_t *event, void *userData)
default:
qDebug() << "Unhandled event: " << event->event;
}
// return;
}
void handleCallbackRecovery(const irecv_device_event_t *event, void *userData)
@@ -117,10 +112,7 @@ MainWindow::MainWindow(QWidget *parent)
const QSize minSize(900, 600);
setMinimumSize(minSize);
resize(minSize);
// TODO
// setWindowIcon(QIcon(":/resources/icons/icon.png"));
// Create custom tab widget
m_ZTabWidget = new ZTabWidget(this);
m_ZTabWidget->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, false);
@@ -131,31 +123,8 @@ MainWindow::MainWindow(QWidget *parent)
#endif
setCentralWidget(m_ZTabWidget);
// Create device manager and stacked widget for main tab
m_mainStackedWidget = new QStackedWidget();
// Welcome page (shown when no devices are connected)
WelcomeWidget *welcomePage = new WelcomeWidget(this);
// No devices page
QWidget *noDevicesPage = new QWidget();
QVBoxLayout *noDeviceLayout = new QVBoxLayout(noDevicesPage);
noDeviceLayout->addStretch();
QHBoxLayout *labelLayout = new QHBoxLayout();
labelLayout->addStretch();
QLabel *noDeviceLabel = new QLabel("No devices detected");
noDeviceLabel->setAlignment(Qt::AlignCenter);
labelLayout->addWidget(noDeviceLabel);
labelLayout->addStretch();
noDeviceLayout->addLayout(labelLayout);
#ifdef WIN32
// Add diagnose widget to check dependencies
// DiagnoseWidget *diagnoseWidget = new DiagnoseWidget();
// noDeviceLayout->addWidget(diagnoseWidget);
#endif
noDeviceLayout->addStretch();
m_deviceManager = new DeviceManagerWidget(this);
m_mainStackedWidget->addWidget(welcomePage);
+6 -1
View File
@@ -16,10 +16,15 @@ DiagnoseDialog::DiagnoseDialog(QWidget *parent) : QDialog(parent)
void DiagnoseDialog::setupUI()
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QScrollArea *scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
mainLayout->setContentsMargins(10, 10, 10, 10);
// Add the main diagnose widget
m_diagnoseWidget = new DiagnoseWidget();
scrollArea->setWidget(m_diagnoseWidget);
// Close button
QHBoxLayout *buttonLayout = new QHBoxLayout();
@@ -33,7 +38,7 @@ void DiagnoseDialog::setupUI()
buttonLayout->addWidget(m_closeButton);
// Layout assembly
mainLayout->addWidget(m_diagnoseWidget, 1);
mainLayout->addWidget(scrollArea);
mainLayout->addLayout(buttonLayout);
}
+176 -46
View File
@@ -1,12 +1,15 @@
#include "diagnose_widget.h"
#ifdef WIN32
#include "check_deps.h"
#endif
#include <QApplication>
#include <QCoreApplication>
#include <QDesktopServices>
#include <QMessageBox>
#include <QProcess>
#include <QTimer>
#include <QUrl>
DependencyItem::DependencyItem(const QString &name, const QString &description,
QWidget *parent)
: QWidget(parent), m_name(name)
@@ -37,7 +40,8 @@ DependencyItem::DependencyItem(const QString &name, const QString &description,
m_statusLabel->setAlignment(Qt::AlignCenter);
// Right side - actions
QVBoxLayout *actionLayout = new QVBoxLayout();
QHBoxLayout *actionLayout = new QHBoxLayout();
actionLayout->setContentsMargins(0, 0, 0, 0);
m_installButton = new QPushButton("Install");
m_installButton->setMinimumWidth(80);
@@ -45,13 +49,13 @@ DependencyItem::DependencyItem(const QString &name, const QString &description,
connect(m_installButton, &QPushButton::clicked, this,
&DependencyItem::onInstallClicked);
m_progressBar = new QProgressBar();
m_progressBar->setRange(0, 0); // Indeterminate
m_progressBar->setVisible(false);
m_progressBar->setMaximumHeight(20);
m_processIndicator = new QProcessIndicator();
m_processIndicator->setType(QProcessIndicator::line_rotate);
m_processIndicator->setFixedSize(24, 24);
m_processIndicator->setVisible(false);
actionLayout->addWidget(m_processIndicator);
actionLayout->addWidget(m_installButton);
actionLayout->addWidget(m_progressBar);
actionLayout->addStretch();
layout->addLayout(infoLayout, 1);
@@ -80,28 +84,47 @@ void DependencyItem::setChecking(bool checking)
m_statusLabel->setText("Checking...");
m_statusLabel->setStyleSheet("color: gray;");
m_installButton->setVisible(false);
m_progressBar->setVisible(false);
m_processIndicator->setVisible(false);
m_processIndicator->stop();
}
}
void DependencyItem::setInstalling(bool installing)
{
if (installing) {
m_statusLabel->setText("Installing...");
m_statusLabel->setStyleSheet("color: gray;");
m_installButton->setVisible(false);
m_processIndicator->setVisible(true);
m_processIndicator->start();
} else {
m_processIndicator->stop();
m_processIndicator->setVisible(false);
}
}
void DependencyItem::onInstallClicked() { emit installRequested(m_name); }
DiagnoseWidget::DiagnoseWidget(QWidget *parent) : QWidget(parent)
DiagnoseWidget::DiagnoseWidget(QWidget *parent)
: QWidget(parent), m_isExpanded(false)
{
setupUI();
#ifdef WIN32
// Add dependency items
addDependencyItem("Apple Mobile Device Support",
"Required for iOS device communication");
addDependencyItem("WinFsp",
"Required for filesystem operations and mounting");
#endif
// Auto-check on startup
QTimer::singleShot(100, this, &DiagnoseWidget::checkDependencies);
QTimer::singleShot(100, this, [this]() { checkDependencies(); });
}
void DiagnoseWidget::setupUI()
{
setAutoFillBackground(true);
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setSpacing(10);
@@ -115,40 +138,43 @@ void DiagnoseWidget::setupUI()
m_summaryLabel = new QLabel("Checking system dependencies...");
// Check button
m_checkButton = new QPushButton("Refresh Check");
m_checkButton = new QPushButton("Refresh Check(s)");
m_checkButton->setMaximumWidth(150);
connect(m_checkButton, &QPushButton::clicked, this,
&DiagnoseWidget::checkDependencies);
[this]() { checkDependencies(false); });
// Scroll area for dependency items
m_scrollArea = new QScrollArea();
m_scrollArea->setWidgetResizable(true);
// m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarNever);
m_scrollArea->setMinimumHeight(200);
// Toggle button
m_toggleButton = new QPushButton("");
m_toggleButton->setFixedSize(24, 24);
m_toggleButton->setCheckable(true);
connect(m_toggleButton, &QPushButton::clicked, this,
&DiagnoseWidget::onToggleExpand);
m_itemsWidget = new QWidget();
// m_itemsWidget->setSizePolicy(QSizePolicy::Expanding,
// QSizePolicy::Preferred);
m_itemsWidget->setFixedHeight(400);
m_itemsLayout = new QVBoxLayout(m_itemsWidget);
m_itemsLayout->setSpacing(5);
m_itemsLayout->addStretch();
m_scrollArea->setWidget(m_itemsWidget);
m_itemsWidget->setVisible(m_isExpanded);
// Layout assembly
QHBoxLayout *headerLayout = new QHBoxLayout();
headerLayout->addWidget(titleLabel);
headerLayout->addStretch();
headerLayout->addWidget(m_checkButton);
headerLayout->addWidget(m_toggleButton);
m_mainLayout->addLayout(headerLayout);
m_mainLayout->addWidget(m_summaryLabel);
m_mainLayout->addWidget(m_scrollArea, 1);
m_mainLayout->addWidget(m_itemsWidget);
}
void DiagnoseWidget::addDependencyItem(const QString &name,
const QString &description)
{
DependencyItem *item = new DependencyItem(name, description);
item->setProperty("name", name); // Set the name property for identification
item->setProperty("name", name);
connect(item, &DependencyItem::installRequested, this,
&DiagnoseWidget::onInstallRequested);
@@ -158,18 +184,16 @@ void DiagnoseWidget::addDependencyItem(const QString &name,
m_itemsLayout->insertWidget(m_itemsLayout->count() - 1, item);
}
void DiagnoseWidget::checkDependencies()
void DiagnoseWidget::checkDependencies(bool autoExpand)
{
m_summaryLabel->setText("Checking system dependencies...");
m_checkButton->setEnabled(false);
// Reset all items to checking state
for (DependencyItem *item : m_dependencyItems) {
item->setChecking(true);
}
// Simulate async checking with timer
QTimer::singleShot(500, [this]() {
QTimer::singleShot(500, [this, autoExpand]() {
int installedCount = 0;
int totalCount = m_dependencyItems.size();
@@ -177,30 +201,37 @@ void DiagnoseWidget::checkDependencies()
bool installed = false;
QString itemName = item->property("name").toString();
#ifdef WIN32
if (itemName == "Apple Mobile Device Support") {
installed = IsAppleMobileDeviceSupportInstalled();
} else if (itemName == "WinFsp") {
installed = IsWinFspInstalled();
}
#endif
item->setInstalled(installed);
if (installed)
installedCount++;
}
// Update summary
if (installedCount == totalCount) {
m_summaryLabel->setText(
QString("All dependencies are installed (%1/%2)")
.arg(installedCount)
.arg(totalCount));
m_summaryLabel->setStyleSheet("color: green; font-weight: bold;");
if (m_isExpanded && autoExpand) {
onToggleExpand();
}
} else {
m_summaryLabel->setText(
QString("Missing dependencies (%1/%2 installed)")
.arg(installedCount)
.arg(totalCount));
m_summaryLabel->setStyleSheet("color: red; font-weight: bold;");
if (!m_isExpanded && autoExpand) {
onToggleExpand();
}
}
m_checkButton->setEnabled(true);
@@ -209,26 +240,125 @@ void DiagnoseWidget::checkDependencies()
void DiagnoseWidget::onInstallRequested(const QString &name)
{
QString url;
QString message;
#ifdef WIN32
if (name == "Apple Mobile Device Support") {
url = "https://support.apple.com/downloads/itunes";
message = "Apple Mobile Device Support is typically installed with "
"iTunes.\n\n"
"Would you like to open the iTunes download page?";
} else if (name == "WinFsp") {
url = "https://winfsp.dev/rel/";
message = "WinFsp can be downloaded from the official website.\n\n"
"Would you like to open the WinFsp download page?";
}
if (!url.isEmpty()) {
int ret = QMessageBox::question(this, "Install " + name, message,
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
QDesktopServices::openUrl(QUrl(url));
DependencyItem *itemToInstall = nullptr;
for (DependencyItem *item : m_dependencyItems) {
if (item->property("name").toString() == name) {
itemToInstall = item;
break;
}
}
if (!itemToInstall)
return;
itemToInstall->setInstalling(true);
QString scriptPath = QCoreApplication::applicationDirPath() +
"/install-apple-drivers.ps1";
QProcess *installProcess = new QProcess(this);
connect(
installProcess, &QProcess::finished, this,
[this, installProcess,
itemToInstall](int exitCode, QProcess::ExitStatus exitStatus) {
if (exitStatus != QProcess::NormalExit || exitCode != 0) {
QString errorOutput =
installProcess->readAllStandardError();
if (errorOutput.isEmpty()) {
errorOutput = installProcess->readAllStandardOutput();
}
QMessageBox::warning(
this, "Installation Failed",
"Failed to launch the installation script. This "
"might be a "
"permissions issue or an internal error.\n\n"
"Details: " +
errorOutput.trimmed());
checkDependencies(false); // Revert UI on failure
} else {
// FIXME: we need to track process completion
QMessageBox::information(
this, "Installation Started",
"The installation process has been started.\n"
"Please approve the administrator prompt (UAC) if it "
"appears.\n"
"After installation, please re-run the dependency "
"check");
itemToInstall->setInstalling(false);
}
installProcess->deleteLater();
});
// Correctly launch powershell.exe elevated, and pass the script to it.
// The -Wait parameter is removed as it does not work with -Verb RunAs.
QString command =
QString("Start-Process -FilePath powershell.exe -Verb RunAs "
"-ArgumentList '-NoProfile -ExecutionPolicy Bypass -File "
"\"%1\"'")
.arg(scriptPath);
QStringList args;
args << "-NoProfile"
<< "-ExecutionPolicy"
<< "Bypass"
<< "-Command" << command;
installProcess->start("powershell.exe", args);
return;
}
if (name == "WinFsp") {
DependencyItem *itemToInstall = nullptr;
for (DependencyItem *item : m_dependencyItems) {
if (item->property("name").toString() == name) {
itemToInstall = item;
break;
}
}
if (!itemToInstall)
return;
itemToInstall->setInstalling(true);
QString scriptPath = QCoreApplication::applicationDirPath() +
"/install-win-fsp.silent.bat";
QProcess *installProcess = new QProcess(this);
connect(
installProcess, &QProcess::finished, this,
[this, installProcess](int exitCode,
QProcess::ExitStatus exitStatus) {
if (exitStatus != QProcess::NormalExit || exitCode != 0) {
QMessageBox::warning(
this, "Installation Failed",
"The installation script failed to run correctly. "
"This might be because the action was cancelled or an "
"error occurred.\n\nPlease try again.");
}
checkDependencies(false);
installProcess->deleteLater();
});
QStringList args;
args << "-NoProfile"
<< "-ExecutionPolicy"
<< "Bypass"
<< "-Command"
<< QString("Start-Process -FilePath \"%1\" -Verb RunAs -Wait;")
.arg(scriptPath);
installProcess->start("powershell.exe", args);
}
#endif
}
void DiagnoseWidget::onToggleExpand()
{
m_isExpanded = !m_isExpanded;
m_itemsWidget->setVisible(m_isExpanded);
m_toggleButton->setText(m_isExpanded ? "" : "");
}
+7 -3
View File
@@ -10,6 +10,7 @@
#include <QVBoxLayout>
#include <QWidget>
#include "../../qprocessindicator.h"
class DependencyItem : public QWidget
{
@@ -20,6 +21,7 @@ public:
QWidget *parent = nullptr);
void setInstalled(bool installed);
void setChecking(bool checking);
void setInstalling(bool installing);
signals:
void installRequested(const QString &name);
@@ -33,7 +35,7 @@ private:
QLabel *m_descriptionLabel;
QLabel *m_statusLabel;
QPushButton *m_installButton;
QProgressBar *m_progressBar;
QProcessIndicator *m_processIndicator;
};
class DiagnoseWidget : public QWidget
@@ -44,10 +46,11 @@ public:
explicit DiagnoseWidget(QWidget *parent = nullptr);
public slots:
void checkDependencies();
void checkDependencies(bool autoExpand = true);
private slots:
void onInstallRequested(const QString &name);
void onToggleExpand();
private:
void setupUI();
@@ -56,9 +59,10 @@ private:
QVBoxLayout *m_mainLayout;
QVBoxLayout *m_itemsLayout;
QPushButton *m_checkButton;
QPushButton *m_toggleButton;
QLabel *m_summaryLabel;
QScrollArea *m_scrollArea;
QWidget *m_itemsWidget;
bool m_isExpanded;
QList<DependencyItem *> m_dependencyItems;
};
+11 -5
View File
@@ -9,13 +9,17 @@
#include <QPalette>
#include <QUrl>
#ifdef WIN32
#include "platform/windows/diagnose_widget.h"
#endif
WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) { setupUI(); }
void WelcomeWidget::setupUI()
{
// Main layout with proper spacing and margins
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setContentsMargins(5, 5, 5, 5);
m_mainLayout->setContentsMargins(0, 0, 0, 0);
m_mainLayout->setSpacing(0);
// Add top stretch
@@ -85,11 +89,13 @@ void WelcomeWidget::setupUI()
m_mainLayout->addWidget(m_githubLabel);
// Add bottom stretch
m_mainLayout->addStretch(1);
// no additional deps needed on macOS
#ifndef __APPLE__
DiagnoseWidget *diagnoseWidget = new DiagnoseWidget();
m_mainLayout->addWidget(diagnoseWidget);
#endif
// Set minimum size
// setMinimumSize(600, 500);
m_mainLayout->addStretch(1);
}
ZLabel *WelcomeWidget::createStyledLabel(const QString &text, int fontSize,
+9
View File
@@ -9,7 +9,12 @@
ZTab::ZTab(const QString &text, QWidget *parent) : QPushButton(text, parent)
{
setCheckable(true);
#ifndef WIN32
setFixedHeight(50);
#else
setFixedHeight(40);
#endif
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
}
@@ -21,7 +26,11 @@ ZTabWidget::ZTabWidget(QWidget *parent) : QWidget(parent), m_currentIndex(0)
// Create tab bar container
m_tabBar = new QWidget();
#ifndef WIN32
m_tabBar->setFixedHeight(50);
#else
m_tabBar->setFixedHeight(40);
#endif
m_tabBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_tabLayout = new QHBoxLayout(m_tabBar);
m_tabLayout->setSpacing(0);