Merge branch '86Box:master' into NL_translation_update

This commit is contained in:
sharkbyte16
2025-08-09 06:37:27 +00:00
committed by GitHub
20 changed files with 363 additions and 142 deletions

View File

@@ -62,6 +62,26 @@ if(APPLE AND USE_QT6)
find_package(Qt6Gui/Qt6QICNSPlugin REQUIRED)
endif()
if (UNIX)
find_path(HAS_VDE "libvdeplug.h" PATHS ${VDE_INCLUDE_DIR} "/usr/include /usr/local/include" "/opt/homebrew/include" )
if(HAS_VDE)
find_library(VDE_LIB vdeplug)
if (NOT VDE_LIB)
message(WARNING "Could not find VDE. The library will not be bundled and any related features will be disabled.")
else()
add_compile_definitions(HAS_VDE)
endif()
endif()
endif()
if (UNIX AND NOT APPLE) # Support for TAP on Linux and BSD, supposedly.
find_path(HAS_TAP "linux/if_tun.h" PATHS ${TAP_INCLUDE_DIR} "/usr/include /usr/local/include" "/opt/homebrew/include" )
if(HAS_TAP)
add_compile_definitions(HAS_TAP)
else()
message(WARNING "TAP support not available. Are you on some BSD?")
endif()
endif()
add_library(plat STATIC
qt.c
qt_main.cpp

View File

@@ -662,7 +662,7 @@ plat_chdir(char *path)
}
void
plat_get_global_config_dir(char *outbuf, const uint8_t len)
plat_get_global_config_dir(char *outbuf, const size_t len)
{
const auto dir = QDir(QStandardPaths::standardLocations(QStandardPaths::AppConfigLocation)[0]);
if (!dir.exists()) {
@@ -674,7 +674,7 @@ plat_get_global_config_dir(char *outbuf, const uint8_t len)
}
void
plat_get_global_data_dir(char *outbuf, const uint8_t len)
plat_get_global_data_dir(char *outbuf, const size_t len)
{
const auto dir = QDir(QStandardPaths::standardLocations(QStandardPaths::AppDataLocation)[0]);
if (!dir.exists()) {

View File

@@ -110,7 +110,7 @@ IntroPage(QWidget *parent)
newConfigRadioButton = new QRadioButton(tr("New configuration"));
// auto newDescription = new QLabel(tr("Choose this option to start with a fresh configuration."));
existingConfigRadioButton = new QRadioButton(tr("Use existing configuraion"));
existingConfigRadioButton = new QRadioButton(tr("Use existing configuration"));
// auto existingDescription = new QLabel(tr("Use this option if you'd like to paste in the configuration file from an existing system."));
newConfigRadioButton->setChecked(true);
@@ -223,6 +223,7 @@ WithExistingConfigPage::isComplete() const
NameAndLocationPage::
NameAndLocationPage(QWidget *parent)
{
#ifdef CUSTOM_SYSTEM_LOCATION
setTitle(tr("System name and location"));
#if defined(_WIN32)
@@ -234,6 +235,10 @@ NameAndLocationPage(QWidget *parent)
#endif
const auto topLabel = new QLabel(tr("Enter the name of the system and choose the location"));
#else
setTitle(tr("System name"));
const auto topLabel = new QLabel(tr("Enter the name of the system"));
#endif
topLabel->setWordWrap(true);
const auto chooseDirectoryButton = new QPushButton();
@@ -246,6 +251,7 @@ NameAndLocationPage(QWidget *parent)
registerField("systemName*", systemName);
systemNameValidation = new QLabel();
#ifdef CUSTOM_SYSTEM_LOCATION
const auto systemLocationLabel = new QLabel(tr("System Location"));
systemLocation = new QLineEdit();
// TODO: FIXME: This is using the CLI arg and needs to instead use a proper variable
@@ -253,6 +259,13 @@ NameAndLocationPage(QWidget *parent)
registerField("systemLocation*", systemLocation);
systemLocationValidation = new QLabel();
systemLocationValidation->setWordWrap(true);
#endif
const auto displayNameLabel = new QLabel(tr("Display Name (optional)"));
displayName = new QLineEdit();
// Special event filter to override enter key
displayName->installEventFilter(this);
registerField("displayName*", displayName);
const auto layout = new QGridLayout();
layout->addWidget(topLabel, 0, 0, 1, -1);
@@ -265,6 +278,7 @@ NameAndLocationPage(QWidget *parent)
// Set height on validation because it may not always be present
layout->setRowMinimumHeight(3, 20);
#ifdef CUSTOM_SYSTEM_LOCATION
// Another spacer
layout->setRowMinimumHeight(4, 20);
layout->addWidget(systemLocationLabel, 5, 0);
@@ -273,11 +287,18 @@ NameAndLocationPage(QWidget *parent)
// Validation text
layout->addWidget(systemLocationValidation, 6, 0, 1, -1);
layout->setRowMinimumHeight(6, 20);
#endif
// Another spacer
layout->setRowMinimumHeight(7, 20);
layout->addWidget(displayNameLabel, 8, 0);
layout->addWidget(displayName, 8, 1);
setLayout(layout);
#ifdef CUSTOM_SYSTEM_LOCATION
connect(chooseDirectoryButton, &QPushButton::clicked, this, &NameAndLocationPage::chooseDirectoryLocation);
#endif
}
int
@@ -286,6 +307,7 @@ NameAndLocationPage::nextId() const
return VMManagerAddMachine::Page_Conclusion;
}
#ifdef CUSTOM_SYSTEM_LOCATION
void
NameAndLocationPage::chooseDirectoryLocation()
{
@@ -294,23 +316,31 @@ NameAndLocationPage::chooseDirectoryLocation()
systemLocation->setText(QDir::toNativeSeparators(directory));
emit completeChanged();
}
#endif
bool
NameAndLocationPage::isComplete() const
{
bool nameValid = false;
#ifdef CUSTOM_SYSTEM_LOCATION
bool locationValid = false;
#endif
// return true if complete
if (systemName->text().isEmpty()) {
systemNameValidation->setText(tr("Please enter a system name"));
#ifdef CUSTOM_SYSTEM_LOCATION
} else if (!systemName->text().contains(dirValidate)) {
systemNameValidation->setText(tr("System name cannot contain certain characters"));
} else if (const QDir newDir = QDir::cleanPath(systemLocation->text() + "/" + systemName->text()); newDir.exists()) {
#else
} else if (const QDir newDir = QDir::cleanPath(QString(vmm_path) + "/" + systemName->text()); newDir.exists()) {
#endif
systemNameValidation->setText(tr("System name already exists"));
} else {
systemNameValidation->clear();
nameValid = true;
}
#ifdef CUSTOM_SYSTEM_LOCATION
if (systemLocation->text().isEmpty()) {
systemLocationValidation->setText(tr("Please enter a directory for the system"));
} else if (const auto dir = QDir(systemLocation->text()); !dir.exists()) {
@@ -321,6 +351,9 @@ NameAndLocationPage::isComplete() const
}
return nameValid && locationValid;
#else
return nameValid;
#endif
}
bool
NameAndLocationPage::eventFilter(QObject *watched, QEvent *event)
@@ -354,17 +387,27 @@ ConclusionPage(QWidget *parent)
const auto systemNameLabel = new QLabel(tr("System name:"));
systemNameLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
systemName = new QLabel();
#ifdef CUSTOM_SYSTEM_LOCATION
const auto systemLocationLabel = new QLabel(tr("System location:"));
systemLocationLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
systemLocation = new QLabel();
#endif
displayNameLabel = new QLabel(tr("Display name:"));
displayNameLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
displayName = new QLabel();
const auto layout = new QGridLayout();
layout->addWidget(topLabel, 0, 0, 1, -1);
layout->setRowMinimumHeight(1, 20);
layout->addWidget(systemNameLabel, 2, 0);
layout->addWidget(systemName, 2, 1);
#ifdef CUSTOM_SYSTEM_LOCATION
layout->addWidget(systemLocationLabel, 3, 0);
layout->addWidget(systemLocation, 3, 1);
#endif
layout->addWidget(displayNameLabel, 4, 0);
layout->addWidget(displayName, 4, 1);
setLayout(layout);
}
@@ -373,10 +416,21 @@ ConclusionPage(QWidget *parent)
void
ConclusionPage::initializePage()
{
#ifdef CUSTOM_SYSTEM_LOCATION
const auto finalPath = QDir::cleanPath(field("systemLocation").toString() + "/" + field("systemName").toString());
const auto nativePath = QDir::toNativeSeparators(finalPath);
#endif
const auto systemNameDisplay = field("systemName").toString();
const auto displayNameDisplay = field("displayName").toString();
systemName->setText(systemNameDisplay);
#ifdef CUSTOM_SYSTEM_LOCATION
systemLocation->setText(nativePath);
#endif
if (!displayNameDisplay.isEmpty())
displayName->setText(displayNameDisplay);
else {
displayNameLabel->setVisible(false);
displayName->setVisible(false);
}
}

View File

@@ -90,12 +90,17 @@ public:
[[nodiscard]] int nextId() const override;
private:
QLineEdit *systemName;
#ifdef CUSTOM_SYSTEM_LOCATION
QLineEdit *systemLocation;
#endif
QLineEdit *displayName;
QLabel *systemNameValidation;
#ifdef CUSTOM_SYSTEM_LOCATION
QLabel *systemLocationValidation;
QRegularExpression dirValidate;
private slots:
void chooseDirectoryLocation();
#endif
protected:
[[nodiscard]] bool isComplete() const override;
bool eventFilter(QObject *watched, QEvent *event) override;
@@ -109,7 +114,11 @@ public:
private:
QLabel *topLabel;
QLabel *systemName;
#ifdef CUSTOM_SYSTEM_LOCATION
QLabel *systemLocation;
#endif
QLabel *displayNameLabel;
QLabel *displayName;
protected:
void initializePage() override;
};

View File

@@ -33,6 +33,9 @@ VMManagerConfig::VMManagerConfig(const ConfigType type, const QString& section)
config_type = type;
settings = new QSettings(configFile, QSettings::IniFormat, this);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
settings->setIniCodec("UTF-8");
#endif
settings->setFallbacksEnabled(false);
if(type == ConfigType::System && !section.isEmpty()) {
settings->beginGroup(section);

View File

@@ -107,6 +107,13 @@ VMManagerMain::VMManagerMain(QWidget *parent) :
});
killIcon.setEnabled(selected_sysconfig->process->state() == QProcess::Running);
QAction deleteAction(tr("&Delete"));
contextMenu.addAction(&deleteAction);
connect(&deleteAction, &QAction::triggered, [this, parent] {
deleteSystem(selected_sysconfig);
});
deleteAction.setEnabled(selected_sysconfig->process->state() == QProcess::NotRunning);
contextMenu.addSeparator();
QAction showRawConfigFile(tr("Show &config file"));
@@ -181,11 +188,19 @@ VMManagerMain::currentSelectionChanged(const QModelIndex &current,
return;
}
disconnect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated);
/* hack to prevent strange segfaults when adding a machine after
removing all machines previously */
if (selected_sysconfig->config_signal_connected == true) {
disconnect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated);
selected_sysconfig->config_signal_connected = false;
}
const auto mapped_index = proxy_model->mapToSource(current);
selected_sysconfig = vm_model->getConfigObjectForIndex(mapped_index);
vm_details->updateData(selected_sysconfig);
connect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated);
if (selected_sysconfig->config_signal_connected == false) {
connect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated);
selected_sysconfig->config_signal_connected = true;
}
// Emit that the selection changed, include with the process state
emit selectionChanged(current, selected_sysconfig->process->state());
@@ -349,14 +364,19 @@ VMManagerMain::newMachineWizard()
const auto wizard = new VMManagerAddMachine(this);
if (wizard->exec() == QDialog::Accepted) {
const auto newName = wizard->field("systemName").toString();
#ifdef CUSTOM_SYSTEM_LOCATION
const auto systemDir = wizard->field("systemLocation").toString();
#else
const auto systemDir = QDir(vmm_path).path();
#endif
const auto existingConfiguration = wizard->field("existingConfiguration").toString();
addNewSystem(newName, systemDir, existingConfiguration);
const auto displayName = wizard->field("displayName").toString();
addNewSystem(newName, systemDir, displayName, existingConfiguration);
}
}
void
VMManagerMain::addNewSystem(const QString &name, const QString &dir, const QString &configFile)
VMManagerMain::addNewSystem(const QString &name, const QString &dir, const QString &displayName, const QString &configFile)
{
const auto newSytemDirectory = QDir(QDir::cleanPath(dir + "/" + name));
@@ -419,6 +439,8 @@ VMManagerMain::addNewSystem(const QString &name, const QString &dir, const QStri
delete new_system;
return;
}
auto added_system = vm_model->getConfigObjectForIndex(created_object);
added_system->setDisplayName(displayName);
// Get the index of the newly-created system and select it
const QModelIndex mapped_index = proxy_model->mapFromSource(created_object);
ui->listView->setCurrentIndex(mapped_index);
@@ -426,6 +448,33 @@ VMManagerMain::addNewSystem(const QString &name, const QString &dir, const QStri
});
}
void
VMManagerMain::deleteSystem(VMManagerSystem *sysconfig)
{
QMessageBox msgbox(QMessageBox::Icon::Warning, tr("Warning"), tr("Do you really want to delete the virtual machine \"%1\" and all its files? This action cannot be undone!").arg(sysconfig->displayName), QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, qobject_cast<QWidget *>(this->parent()));
msgbox.exec();
if (msgbox.result() == QMessageBox::Yes) {
auto qrmdir = new QDir(sysconfig->config_dir);
if (const bool rmdirResult = qrmdir->removeRecursively(); !rmdirResult) {
QMessageBox::critical(this, tr("Remove directory failed"), tr("Some files in the machine's directory were unable to be deleted. Please delete them manually."));
return;
}
auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General);
config->remove(sysconfig->uuid);
vm_model->removeConfigFromModel(sysconfig);
delete sysconfig;
if (vm_model->rowCount(QModelIndex()) <= 0) {
/* no machines left - get rid of the last machine's leftovers */
ui->detailsArea->layout()->removeWidget(vm_details);
delete vm_details;
vm_details = new VMManagerDetails();
ui->detailsArea->layout()->addWidget(vm_details);
}
}
}
QStringList
VMManagerMain::getSearchCompletionList() const
{

View File

@@ -70,7 +70,8 @@ public slots:
void shutdownForceButtonPressed() const;
void searchSystems(const QString &text) const;
void newMachineWizard();
void addNewSystem(const QString &name, const QString &dir, const QString &configFile = {});
void deleteSystem(VMManagerSystem *sysconfig);
void addNewSystem(const QString &name, const QString &dir, const QString &displayName = QString(), const QString &configFile = {});
#if __GNUC__ >= 11
[[nodiscard]] QStringList getSearchCompletionList() const;
#else

View File

@@ -140,6 +140,18 @@ VMManagerModel::addConfigToModel(VMManagerSystem *system_config)
connect(system_config, &VMManagerSystem::itemDataChanged, this, &VMManagerModel::modelDataChanged);
endInsertRows();
}
void
VMManagerModel::removeConfigFromModel(VMManagerSystem *system_config)
{
const QModelIndex index = getIndexForConfigFile(system_config->config_file);
disconnect(system_config, &VMManagerSystem::itemDataChanged, this, &VMManagerModel::modelDataChanged);
beginRemoveRows(QModelIndex(), index.row(), index.row());
machines.remove(index.row());
endRemoveRows();
emit systemDataChanged();
}
void
VMManagerModel::modelDataChanged()
{
@@ -177,4 +189,4 @@ VMManagerModel::getActiveMachineCount()
running++;
}
return running;
}
}

View File

@@ -51,6 +51,7 @@ public:
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation,
int role) const override;
void addConfigToModel(VMManagerSystem *system_config);
void removeConfigFromModel(VMManagerSystem *system_config);
[[nodiscard]] VMManagerSystem * getConfigObjectForIndex(const QModelIndex &index) const;
QModelIndex getIndexForConfigFile(const QFileInfo& config_file);

View File

@@ -234,6 +234,9 @@ VMManagerSystem::loadSettings()
}
// qInfo() << "Loaded "<< config_file.filePath() << "status:" << settings.status();
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
settings.setIniCodec("UTF-8");
#endif
// Clear out the config hash in case the config is reloaded
for (const auto &outer_key : config_hash.keys()) {
config_hash[outer_key].clear();

View File

@@ -136,6 +136,7 @@ public:
QProcess *process = new QProcess();
bool window_obscured;
bool config_signal_connected = false;
QString getDisplayValue(VMManager::Display::Name key);
QFileInfoList getScreenshots();

View File

@@ -49,6 +49,13 @@ typedef struct ioctl_t {
WCHAR path[256];
} ioctl_t;
typedef struct _CDROM_FULL_TOC {
UCHAR Length[2];
UCHAR FirstCompleteSession;
UCHAR LastCompleteSession;
CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[MAXIMUM_NUMBER_TRACKS + 2];
} CDROM_FULL_TOC;
static int ioctl_read_dvd_structure(const void *local, uint8_t layer, uint8_t format,
uint8_t *buffer, uint32_t *info);
@@ -124,7 +131,7 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf, int32_t *tracks_num)
const int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX,
&cur_read_toc_ex, sizeof(CDROM_READ_TOC_EX),
cur_full_toc, 65535,
cur_full_toc, sizeof(CDROM_TOC),
(LPDWORD) &size, NULL);
ioctl_log(ioctl->log, "temp = %i\n", temp);
@@ -179,7 +186,7 @@ ioctl_read_raw_toc(ioctl_t *ioctl)
if (!ioctl->is_dvd) {
status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX,
&cur_read_toc_ex, sizeof(CDROM_READ_TOC_EX),
cur_full_toc, 65535,
cur_full_toc, sizeof(CDROM_FULL_TOC),
(LPDWORD) &size, NULL);
ioctl_log(ioctl->log, "status = %i\n", status);
}