Files
86Box/src/qt/qt_main.cpp

354 lines
11 KiB
C++
Raw Normal View History

2022-02-07 15:00:02 +06:00
/*
2023-01-06 15:36:05 -05:00
* 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.
2022-02-07 15:00:02 +06:00
*
2023-01-06 15:36:05 -05:00
* This file is part of the 86Box distribution.
2022-02-07 15:00:02 +06:00
*
2023-01-06 15:36:05 -05:00
* Main entry point module
2022-02-07 15:00:02 +06:00
*
*
2023-01-06 15:36:05 -05:00
* Authors: Joakim L. Gilje <jgilje@jgilje.net>
2022-02-07 15:00:02 +06:00
* Cacodemon345
* Teemu Korhonen
*
2023-01-06 15:36:05 -05:00
* Copyright 2021 Joakim L. Gilje
* Copyright 2021-2022 Cacodemon345
* Copyright 2021-2022 Teemu Korhonen
2022-02-07 15:00:02 +06:00
*/
2021-11-25 10:20:56 +01:00
#include <QApplication>
#include <QSurfaceFormat>
2021-11-25 10:20:56 +01:00
#include <QDebug>
#include <QElapsedTimer>
#include <QThread>
#include <QTimer>
2021-12-31 12:36:55 +06:00
#include <QTranslator>
#include <QDirIterator>
#include <QLibraryInfo>
#include <QString>
2022-02-12 01:50:50 +06:00
#include <QFont>
#include <QDialog>
#include <QMessageBox>
2021-11-25 10:20:56 +01:00
2021-12-06 17:31:25 +02:00
#ifdef QT_STATIC
/* Static builds need plugin imports */
2022-11-19 08:49:04 -05:00
# include <QtPlugin>
2021-12-06 17:31:25 +02:00
Q_IMPORT_PLUGIN(QICOPlugin)
2022-11-19 08:49:04 -05:00
# ifdef Q_OS_WINDOWS
2021-12-06 17:31:25 +02:00
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin)
2022-11-19 08:49:04 -05:00
# endif
2021-12-06 17:31:25 +02:00
#endif
#ifdef Q_OS_WINDOWS
2022-11-19 08:49:04 -05:00
# include "qt_winrawinputfilter.hpp"
# include "qt_winmanagerfilter.hpp"
# include <86box/win.h>
2023-02-14 20:37:58 -05:00
# include <shobjidl.h>
#endif
2022-11-19 08:49:04 -05:00
extern "C" {
2021-11-25 10:20:56 +01:00
#include <86box/86box.h>
#include <86box/config.h>
2021-11-25 10:20:56 +01:00
#include <86box/plat.h>
#include <86box/ui.h>
#include <86box/video.h>
#ifdef DISCORD
# include <86box/discord.h>
#endif
2022-03-16 00:33:01 -03:00
#include <86box/gdbstub.h>
}
2021-11-25 10:20:56 +01:00
#include <thread>
2021-12-31 12:36:55 +06:00
#include <iostream>
#include <memory>
2021-11-25 10:20:56 +01:00
#include "qt_mainwindow.hpp"
2022-01-08 16:39:51 +06:00
#include "qt_progsettings.hpp"
#include "qt_settings.hpp"
#include "cocoa_mouse.hpp"
#include "qt_styleoverride.hpp"
#include "qt_unixmanagerfilter.hpp"
2022-02-15 02:34:13 +06:00
2021-11-25 10:20:56 +01:00
// Void Cast
2022-11-19 08:49:04 -05:00
#define VC(x) const_cast<wchar_t *>(x)
2021-11-25 10:20:56 +01:00
extern QElapsedTimer elapsed_timer;
2022-11-19 08:49:04 -05:00
extern MainWindow *main_window;
2021-11-25 10:20:56 +01:00
extern "C" {
2021-12-19 23:49:47 +02:00
#include <86box/timer.h>
#include <86box/nvr.h>
2022-11-19 08:49:04 -05:00
extern int qt_nvr_save(void);
2021-11-25 10:20:56 +01:00
}
void qt_set_sequence_auto_mnemonic(bool b);
2021-11-25 10:20:56 +01:00
void
main_thread_fn()
{
2023-05-29 01:30:51 -04:00
uint64_t old_time;
uint64_t new_time;
int drawits;
int frames;
2021-11-25 10:20:56 +01:00
QThread::currentThread()->setPriority(QThread::HighestPriority);
framecountx = 0;
2022-11-19 08:49:04 -05:00
// title_update = 1;
2021-11-25 10:20:56 +01:00
old_time = elapsed_timer.elapsed();
drawits = frames = 0;
while (!is_quit && cpu_thread_run) {
/* See if it is time to run a frame of code. */
new_time = elapsed_timer.elapsed();
2022-03-16 00:33:01 -03:00
#ifdef USE_GDBSTUB
if (gdbstub_next_asap && (drawits <= 0))
2022-11-19 08:49:04 -05:00
drawits = 10;
2022-03-16 00:33:01 -03:00
else
#endif
2022-11-19 08:49:04 -05:00
drawits += (new_time - old_time);
2021-11-25 10:20:56 +01:00
old_time = new_time;
if (drawits > 0 && !dopause) {
/* Yes, so do one frame now. */
drawits -= 10;
if (drawits > 50)
drawits = 0;
#ifdef USE_INSTRUMENT
uint64_t start_time = elapsed_timer.nsecsElapsed();
#endif
2021-11-25 10:20:56 +01:00
/* Run a block of code. */
pc_run();
#ifdef USE_INSTRUMENT
if (instru_enabled) {
2022-11-19 08:49:04 -05:00
uint64_t elapsed_us = (elapsed_timer.nsecsElapsed() - start_time) / 1000;
uint64_t total_elapsed_ms = (uint64_t) ((double) tsc / cpu_s->rspeed * 1000);
2022-08-06 14:51:42 +02:00
printf("[instrument] %llu, %llu\n", total_elapsed_ms, elapsed_us);
if (instru_run_ms && total_elapsed_ms >= instru_run_ms)
break;
}
#endif
2021-11-25 10:20:56 +01:00
/* Every 200 frames we save the machine status. */
if (++frames >= 200 && nvr_dosave) {
qt_nvr_save();
nvr_dosave = 0;
2022-11-19 08:49:04 -05:00
frames = 0;
2021-11-25 10:20:56 +01:00
}
} else {
/* Just so we dont overload the host OS. */
if (dopause)
ack_pause();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
2021-11-25 10:20:56 +01:00
}
is_quit = 1;
if (gfxcard[1]) {
ui_deinit_monitor(1);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
QTimer::singleShot(0, QApplication::instance(), []() { QApplication::processEvents(); QApplication::instance()->quit(); });
2021-11-25 10:20:56 +01:00
}
2022-11-19 08:49:04 -05:00
static std::thread *main_thread;
2022-07-04 01:50:42 +06:00
2022-11-19 08:49:04 -05:00
int
main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2022-02-09 20:57:58 +06:00
QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, false);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
QApplication app(argc, argv);
QLocale::setDefault(QLocale::C);
qt_set_sequence_auto_mnemonic(false);
2021-12-31 12:36:55 +06:00
Q_INIT_RESOURCE(qt_resources);
Q_INIT_RESOURCE(qt_translations);
QSurfaceFormat fmt = QSurfaceFormat::defaultFormat();
fmt.setSwapInterval(0);
QSurfaceFormat::setDefaultFormat(fmt);
app.setStyle(new StyleOverride());
2022-01-08 16:39:51 +06:00
#ifdef __APPLE__
CocoaEventFilter cocoafilter;
app.installNativeEventFilter(&cocoafilter);
#endif
2021-11-25 10:20:56 +01:00
elapsed_timer.start();
2022-11-19 08:49:04 -05:00
if (!pc_init(argc, argv)) {
return 0;
}
bool startMaximized = window_remember && monitor_settings[0].mon_window_maximized;
fprintf(stderr, "Qt: version %s, platform \"%s\"\n", qVersion(), QApplication::platformName().toUtf8().data());
2022-01-08 16:39:51 +06:00
ProgSettings::loadTranslators(&app);
#ifdef Q_OS_WINDOWS
auto font_name = QObject::tr("FONT_NAME");
auto font_size = QObject::tr("FONT_SIZE");
QApplication::setFont(QFont(font_name, font_size.toInt()));
SetCurrentProcessExplicitAppUserModelID(L"86Box.86Box");
#endif
#ifdef RELEASE_BUILD
app.setWindowIcon(QIcon(":/settings/win/icons/86Box-green.ico"));
#elif defined ALPHA_BUILD
app.setWindowIcon(QIcon(":/settings/win/icons/86Box-red.ico"));
#elif defined BETA_BUILD
app.setWindowIcon(QIcon(":/settings/win/icons/86Box-yellow.ico"));
#else
app.setWindowIcon(QIcon(":/settings/win/icons/86Box-gray.ico"));
#endif
2022-11-19 08:49:04 -05:00
if (!pc_init_modules()) {
ui_msgbox_header(MBX_FATAL, (void *) IDS_2121, (void *) IDS_2056);
return 6;
}
2021-11-25 10:20:56 +01:00
2022-11-19 08:49:04 -05:00
if (settings_only) {
Settings settings;
2022-11-19 08:49:04 -05:00
if (settings.exec() == QDialog::Accepted) {
settings.save();
config_save();
}
return 0;
}
/* Warn the user about unsupported configs */
if (cpu_override) {
QMessageBox warningbox(QMessageBox::Icon::Warning, QObject::tr("You are loading an unsupported configuration"),
QObject::tr("CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid."),
QMessageBox::NoButton);
warningbox.addButton(QObject::tr("Continue"), QMessageBox::AcceptRole);
warningbox.addButton(QObject::tr("Exit"), QMessageBox::RejectRole);
warningbox.exec();
if (warningbox.result() == QDialog::Accepted)
return 0;
}
#ifdef DISCORD
discord_load();
#endif
2021-11-29 12:25:27 +01:00
main_window = new MainWindow();
if (startMaximized) {
main_window->showMaximized();
} else {
main_window->show();
}
2021-12-05 15:57:46 +06:00
app.installEventFilter(main_window);
#ifdef Q_OS_WINDOWS
/* Setup VM-manager messages */
std::unique_ptr<WindowsManagerFilter> wmfilter;
2022-11-19 08:49:04 -05:00
if (source_hwnd) {
HWND main_hwnd = (HWND) main_window->winId();
wmfilter.reset(new WindowsManagerFilter());
2022-01-22 12:40:15 +02:00
QObject::connect(wmfilter.get(), &WindowsManagerFilter::showsettings, main_window, &MainWindow::showSettings);
QObject::connect(wmfilter.get(), &WindowsManagerFilter::pause, main_window, &MainWindow::togglePause);
QObject::connect(wmfilter.get(), &WindowsManagerFilter::reset, main_window, &MainWindow::hardReset);
QObject::connect(wmfilter.get(), &WindowsManagerFilter::request_shutdown, main_window, &MainWindow::close);
2022-11-19 08:49:04 -05:00
QObject::connect(wmfilter.get(), &WindowsManagerFilter::force_shutdown, []() {
do_stop();
emit main_window->close();
});
2022-11-19 08:49:04 -05:00
QObject::connect(wmfilter.get(), &WindowsManagerFilter::ctrlaltdel, []() { pc_send_cad(); });
QObject::connect(wmfilter.get(), &WindowsManagerFilter::dialogstatus, [main_hwnd](bool open) {
PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDDLGSTATUS, (WPARAM) (open ? 1 : 0), (LPARAM) main_hwnd);
});
/* Native filter to catch VM-managers commands */
app.installNativeEventFilter(wmfilter.get());
/* Filter to catch main window being blocked (by modal dialog) */
main_window->installEventFilter(wmfilter.get());
/* Send main window HWND to manager */
2022-11-19 08:49:04 -05:00
PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDHWND, (WPARAM) unique_id, (LPARAM) main_hwnd);
/* Send shutdown message to manager */
2022-11-19 08:49:04 -05:00
QObject::connect(&app, &QApplication::destroyed, [main_hwnd](QObject *) {
PostMessage((HWND) (uintptr_t) source_hwnd, WM_HAS_SHUTDOWN, (WPARAM) 0, (LPARAM) main_hwnd);
});
}
/* Setup raw input */
auto rawInputFilter = WindowsRawInputFilter::Register(main_window);
2022-11-19 08:49:04 -05:00
if (rawInputFilter) {
app.installNativeEventFilter(rawInputFilter.get());
main_window->setSendKeyboardInput(false);
2022-02-20 02:26:27 -05:00
}
#endif
UnixManagerSocket socket;
2022-11-19 08:49:04 -05:00
if (qgetenv("86BOX_MANAGER_SOCKET").size()) {
QObject::connect(&socket, &UnixManagerSocket::showsettings, main_window, &MainWindow::showSettings);
QObject::connect(&socket, &UnixManagerSocket::pause, main_window, &MainWindow::togglePause);
QObject::connect(&socket, &UnixManagerSocket::resetVM, main_window, &MainWindow::hardReset);
QObject::connect(&socket, &UnixManagerSocket::request_shutdown, main_window, &MainWindow::close);
2022-11-19 08:49:04 -05:00
QObject::connect(&socket, &UnixManagerSocket::force_shutdown, []() {
do_stop();
emit main_window->close();
});
2022-11-19 08:49:04 -05:00
QObject::connect(&socket, &UnixManagerSocket::ctrlaltdel, []() { pc_send_cad(); });
main_window->installEventFilter(&socket);
socket.connectToServer(qgetenv("86BOX_MANAGER_SOCKET"));
}
2022-11-19 08:49:04 -05:00
// pc_reset_hard_init();
2021-11-25 10:20:56 +01:00
QTimer onesec;
QObject::connect(&onesec, &QTimer::timeout, &app, [] {
pc_onesec();
});
onesec.setTimerType(Qt::PreciseTimer);
onesec.start(1000);
#ifdef DISCORD
QTimer discordupdate;
if (discord_loaded) {
QTimer::singleShot(1000, &app, [] {
if (enable_discord) {
discord_init();
discord_update_activity(dopause);
} else
discord_close();
});
QObject::connect(&discordupdate, &QTimer::timeout, &app, [] {
discord_run_callbacks();
});
discordupdate.start(1000);
}
#endif
2021-11-25 10:20:56 +01:00
/* Initialize the rendering window, or fullscreen. */
2022-11-19 08:49:04 -05:00
QTimer::singleShot(0, &app, [] {
2022-07-04 01:50:42 +06:00
pc_reset_hard_init();
main_thread = new std::thread(main_thread_fn);
/* Set the PAUSE mode depending on the renderer. */
#ifdef USE_VNC
if (vnc_enabled && vid_api != 6)
plat_pause(1);
else
#endif
plat_pause(0);
2021-11-25 10:20:56 +01:00
});
2022-11-19 08:49:04 -05:00
auto ret = app.exec();
2021-11-25 10:20:56 +01:00
cpu_thread_run = 0;
2022-07-04 01:50:42 +06:00
main_thread->join();
pc_close(nullptr);
endblit();
2021-11-25 10:20:56 +01:00
socket.close();
2021-11-25 10:20:56 +01:00
return ret;
}