mirror of
https://github.com/86Box/86Box.git
synced 2026-02-22 09:35:32 -07:00
352 lines
12 KiB
C++
352 lines
12 KiB
C++
/*
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
* running old operating systems and software designed for IBM
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
* system designs based on the PCI bus.
|
|
*
|
|
* This file is part of the 86Box distribution.
|
|
*
|
|
* 86Box VM manager main window
|
|
*
|
|
* Authors: cold-brewed
|
|
*
|
|
* Copyright 2024 cold-brewed
|
|
*/
|
|
#include "qt_vmmanager_mainwindow.hpp"
|
|
#include "qt_vmmanager_main.hpp"
|
|
#include "qt_vmmanager_preferences.hpp"
|
|
#include "qt_vmmanager_windarkmodefilter.hpp"
|
|
#include "ui_qt_vmmanager_mainwindow.h"
|
|
#if EMU_BUILD_NUM != 0
|
|
# include "qt_updatecheckdialog.hpp"
|
|
#endif
|
|
#include "qt_about.hpp"
|
|
#include "qt_progsettings.hpp"
|
|
#include "qt_util.hpp"
|
|
|
|
#include <QCloseEvent>
|
|
#include <QDesktopServices>
|
|
|
|
extern "C" {
|
|
extern void config_load_global();
|
|
extern void config_save_global();
|
|
}
|
|
|
|
VMManagerMainWindow *vmm_main_window = nullptr;
|
|
extern WindowsDarkModeFilter *vmm_dark_mode_filter;
|
|
|
|
VMManagerMainWindow::
|
|
VMManagerMainWindow(QWidget *parent)
|
|
: ui(new Ui::VMManagerMainWindow)
|
|
, vmm(new VMManagerMain(this))
|
|
, statusLeft(new QLabel)
|
|
, statusRight(new QLabel)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
vmm_main_window = this;
|
|
|
|
runIcon = QIcon(":/menuicons/qt/icons/run.ico");
|
|
pauseIcon = QIcon(":/menuicons/qt/icons/pause.ico");
|
|
|
|
// Connect signals from the VMManagerMain widget
|
|
connect(vmm, &VMManagerMain::selectionOrStateChanged, this, &VMManagerMainWindow::vmmStateChanged);
|
|
|
|
setWindowTitle(tr("%1 VM Manager").arg(EMU_NAME));
|
|
setCentralWidget(vmm);
|
|
|
|
// Set up the buttons
|
|
connect(ui->actionNew_Machine, &QAction::triggered, vmm, &VMManagerMain::newMachineWizard);
|
|
connect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::startButtonPressed);
|
|
connect(ui->actionSettings, &QAction::triggered, vmm, &VMManagerMain::settingsButtonPressed);
|
|
connect(ui->actionHard_Reset, &QAction::triggered, vmm, &VMManagerMain::restartButtonPressed);
|
|
connect(ui->actionForce_Shutdown, &QAction::triggered, vmm, &VMManagerMain::shutdownForceButtonPressed);
|
|
connect(ui->actionCtrl_Alt_Del, &QAction::triggered, vmm, &VMManagerMain::cadButtonPressed);
|
|
|
|
// Set up menu actions
|
|
// (Disable this if the EMU_BUILD_NUM == 0)
|
|
#if EMU_BUILD_NUM == 0
|
|
ui->actionCheck_for_updates->setVisible(false);
|
|
#else
|
|
connect(ui->actionCheck_for_updates, &QAction::triggered, this, &VMManagerMainWindow::checkForUpdatesTriggered);
|
|
#endif
|
|
|
|
// Set up the toolbar
|
|
ui->actionStartPause->setEnabled(false);
|
|
ui->actionStartPause->setIcon(runIcon);
|
|
ui->actionStartPause->setText(tr("Start"));
|
|
ui->actionStartPause->setToolTip(tr("Start"));
|
|
ui->actionHard_Reset->setEnabled(false);
|
|
ui->actionForce_Shutdown->setEnabled(false);
|
|
ui->actionCtrl_Alt_Del->setEnabled(false);
|
|
ui->actionSettings->setEnabled(false);
|
|
|
|
// Preferences
|
|
connect(ui->actionPreferences, &QAction::triggered, this, &VMManagerMainWindow::preferencesTriggered);
|
|
|
|
#ifdef Q_OS_WINDOWS
|
|
ui->toolBar->setBackgroundRole(QPalette::Light);
|
|
#endif
|
|
|
|
// Status bar widgets
|
|
statusLeft->setAlignment(Qt::AlignLeft);
|
|
statusRight->setAlignment(Qt::AlignRight);
|
|
ui->statusbar->addPermanentWidget(statusLeft, 1);
|
|
ui->statusbar->addPermanentWidget(statusRight, 1);
|
|
connect(vmm, &VMManagerMain::updateStatusLeft, this, &VMManagerMainWindow::setStatusLeft);
|
|
connect(vmm, &VMManagerMain::updateStatusRight, this, &VMManagerMainWindow::setStatusRight);
|
|
|
|
// Inform the main view when preferences are updated
|
|
connect(this, &VMManagerMainWindow::preferencesUpdated, vmm, &VMManagerMain::onPreferencesUpdated);
|
|
connect(this, &VMManagerMainWindow::languageUpdated, vmm, &VMManagerMain::onLanguageUpdated);
|
|
#ifdef Q_OS_WINDOWS
|
|
connect(this, &VMManagerMainWindow::darkModeUpdated, vmm, &VMManagerMain::onDarkModeUpdated);
|
|
connect(this, &VMManagerMainWindow::preferencesUpdated, []() { vmm_dark_mode_filter->reselectDarkMode(); });
|
|
#endif
|
|
|
|
{
|
|
auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General);
|
|
ui->actionHide_tool_bar->setChecked(!!config->getStringValue("hide_tool_bar").toInt());
|
|
if (ui->actionHide_tool_bar->isChecked())
|
|
ui->toolBar->setVisible(false);
|
|
if (!!config->getStringValue("window_remember").toInt()) {
|
|
QString coords = config->getStringValue("window_coordinates");
|
|
if (!coords.isEmpty()) {
|
|
QStringList list = coords.split(',');
|
|
for (auto &cur : list) {
|
|
cur = cur.trimmed();
|
|
}
|
|
QRect geom;
|
|
geom.setX(list[0].toInt());
|
|
geom.setY(list[1].toInt());
|
|
geom.setWidth(list[2].toInt());
|
|
geom.setHeight(list[3].toInt());
|
|
|
|
setGeometry(geom);
|
|
}
|
|
|
|
if (!!config->getStringValue("window_maximized").toInt()) {
|
|
setWindowState(windowState() | Qt::WindowMaximized);
|
|
}
|
|
|
|
QString splitter = config->getStringValue("window_splitter");
|
|
if (!splitter.isEmpty()) {
|
|
QStringList list = splitter.split(',');
|
|
for (auto &cur : list) {
|
|
cur = cur.trimmed();
|
|
}
|
|
QList<int> paneSizes;
|
|
paneSizes.append(list[0].toInt());
|
|
paneSizes.append(list[1].toInt());
|
|
|
|
vmm->setPaneSizes(paneSizes);
|
|
}
|
|
} else {
|
|
config->setStringValue("window_coordinates", "");
|
|
config->setStringValue("window_maximized", "");
|
|
config->setStringValue("window_splitter", "");
|
|
}
|
|
delete config;
|
|
}
|
|
}
|
|
|
|
VMManagerMainWindow::~VMManagerMainWindow()
|
|
= default;
|
|
|
|
void
|
|
VMManagerMainWindow::vmmStateChanged(const VMManagerSystem *sysconfig) const
|
|
{
|
|
if (sysconfig == nullptr) {
|
|
// This doubles both as a safety check and a way to disable
|
|
// all machine-related buttons when no machines are present
|
|
ui->actionStartPause->setEnabled(false);
|
|
ui->actionSettings->setEnabled(false);
|
|
ui->actionHard_Reset->setEnabled(false);
|
|
ui->actionForce_Shutdown->setEnabled(false);
|
|
ui->actionCtrl_Alt_Del->setEnabled(false);
|
|
return;
|
|
}
|
|
const bool running = sysconfig->process->state() == QProcess::ProcessState::Running;
|
|
|
|
if (running) {
|
|
if (sysconfig->getProcessStatus() == VMManagerSystem::ProcessStatus::Running) {
|
|
ui->actionStartPause->setIcon(pauseIcon);
|
|
ui->actionStartPause->setText(tr("&Pause"));
|
|
ui->actionStartPause->setToolTip(tr("Pause"));
|
|
ui->actionStartPause->setIconText(tr("Pause"));
|
|
} else {
|
|
ui->actionStartPause->setIcon(runIcon);
|
|
ui->actionStartPause->setText(tr("&Continue"));
|
|
ui->actionStartPause->setToolTip(tr("Continue"));
|
|
ui->actionStartPause->setIconText(tr("Continue"));
|
|
}
|
|
disconnect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::startButtonPressed);
|
|
disconnect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::pauseButtonPressed);
|
|
connect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::pauseButtonPressed);
|
|
} else {
|
|
ui->actionStartPause->setIcon(runIcon);
|
|
ui->actionStartPause->setText(tr("&Start"));
|
|
ui->actionStartPause->setToolTip(tr("Start"));
|
|
ui->actionStartPause->setIconText(tr("Start"));
|
|
disconnect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::pauseButtonPressed);
|
|
disconnect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::startButtonPressed);
|
|
connect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::startButtonPressed);
|
|
}
|
|
|
|
ui->actionStartPause->setEnabled(!sysconfig->window_obscured);
|
|
ui->actionSettings->setEnabled(!sysconfig->window_obscured);
|
|
ui->actionHard_Reset->setEnabled(sysconfig->window_obscured ? false : running);
|
|
ui->actionForce_Shutdown->setEnabled(sysconfig->window_obscured ? false : running);
|
|
ui->actionCtrl_Alt_Del->setEnabled(sysconfig->window_obscured ? false : running);
|
|
}
|
|
void
|
|
VMManagerMainWindow::preferencesTriggered()
|
|
{
|
|
bool machinesRunning = (vmm->getActiveMachineCount() > 0);
|
|
auto old_vmm_path = QString(vmm_path_cfg);
|
|
const auto prefs = new VMManagerPreferences(this, machinesRunning);
|
|
if (prefs->exec() == QDialog::Accepted) {
|
|
emit preferencesUpdated();
|
|
updateLanguage();
|
|
|
|
auto new_vmm_path = QString(vmm_path_cfg);
|
|
if (!machinesRunning && (new_vmm_path != old_vmm_path)) {
|
|
qDebug() << "Machine path changed: old path " << old_vmm_path << ", new path " << new_vmm_path;
|
|
strncpy(vmm_path, vmm_path_cfg, sizeof(vmm_path));
|
|
vmm->reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::updateSettings()
|
|
{
|
|
config_load_global();
|
|
emit preferencesUpdated();
|
|
updateLanguage();
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::saveSettings() const
|
|
{
|
|
const auto currentSelection = vmm->getCurrentSelection();
|
|
const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General);
|
|
config->setStringValue("last_selection", currentSelection);
|
|
config->setStringValue("hide_tool_bar", (ui->toolBar->isVisible() ? "0" : "1"));
|
|
if (!!config->getStringValue("window_remember").toInt()) {
|
|
config->setStringValue("window_coordinates", QString::asprintf("%i, %i, %i, %i", this->geometry().x(), this->geometry().y(), this->geometry().width(), this->geometry().height()));
|
|
config->setStringValue("window_maximized", this->isMaximized() ? "1" : "");
|
|
config->setStringValue("window_splitter", QString::asprintf("%i, %i", vmm->getPaneSizes()[0], vmm->getPaneSizes()[1]));
|
|
} else {
|
|
config->setStringValue("window_coordinates", "");
|
|
config->setStringValue("window_maximized", "");
|
|
config->setStringValue("window_splitter", "");
|
|
}
|
|
// Sometimes required to ensure the settings save before the app exits
|
|
config->sync();
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::updateLanguage()
|
|
{
|
|
ProgSettings::loadTranslators(QCoreApplication::instance());
|
|
ProgSettings::reloadStrings();
|
|
ui->retranslateUi(this);
|
|
setWindowTitle(tr("%1 VM Manager").arg(EMU_NAME));
|
|
emit languageUpdated();
|
|
}
|
|
|
|
#ifdef Q_OS_WINDOWS
|
|
void
|
|
VMManagerMainWindow::updateDarkMode()
|
|
{
|
|
emit darkModeUpdated();
|
|
}
|
|
#endif
|
|
|
|
void
|
|
VMManagerMainWindow::changeEvent(QEvent *event)
|
|
{
|
|
#ifdef Q_OS_WINDOWS
|
|
if (event->type() == QEvent::LanguageChange) {
|
|
QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9));
|
|
}
|
|
#endif
|
|
QWidget::changeEvent(event);
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
int running = vmm->getActiveMachineCount();
|
|
if (running > 0) {
|
|
QMessageBox warningbox(QMessageBox::Icon::Warning, tr("%1 VM Manager").arg(EMU_NAME), tr("%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?", "", running), QMessageBox::Yes | QMessageBox::No, this);
|
|
warningbox.exec();
|
|
if (warningbox.result() == QMessageBox::No) {
|
|
event->ignore();
|
|
return;
|
|
}
|
|
}
|
|
saveSettings();
|
|
QMainWindow::closeEvent(event);
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::setStatusLeft(const QString &text) const
|
|
{
|
|
statusLeft->setText(text);
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::setStatusRight(const QString &text) const
|
|
{
|
|
statusRight->setText(text);
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::on_actionHide_tool_bar_triggered()
|
|
{
|
|
const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General);
|
|
int isHidden = config->getStringValue("hide_tool_bar").toInt();
|
|
ui->toolBar->setVisible(!!isHidden);
|
|
config->setStringValue("hide_tool_bar", (isHidden ? "0" : "1"));
|
|
}
|
|
|
|
#if EMU_BUILD_NUM != 0
|
|
void
|
|
VMManagerMainWindow::checkForUpdatesTriggered()
|
|
{
|
|
auto updateChannel = UpdateCheck::UpdateChannel::CI;
|
|
# ifdef RELEASE_BUILD
|
|
updateChannel = UpdateCheck::UpdateChannel::Stable;
|
|
# endif
|
|
const auto updateCheck = new UpdateCheckDialog(updateChannel, this);
|
|
updateCheck->exec();
|
|
}
|
|
#endif
|
|
|
|
void
|
|
VMManagerMainWindow::on_actionExit_triggered()
|
|
{
|
|
this->close();
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::on_actionAbout_Qt_triggered()
|
|
{
|
|
QApplication::aboutQt();
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::on_actionAbout_86Box_triggered()
|
|
{
|
|
const auto msgBox = new About(this);
|
|
msgBox->exec();
|
|
}
|
|
|
|
void
|
|
VMManagerMainWindow::on_actionDocumentation_triggered()
|
|
{
|
|
QDesktopServices::openUrl(QUrl(EMU_DOCS_URL));
|
|
}
|