From 7f69f00ed25bd0c34eb2d9e4dba4b2b032e703dc Mon Sep 17 00:00:00 2001 From: aubymori Date: Mon, 2 Feb 2026 19:15:31 -0600 Subject: [PATCH 01/13] Query UI font from system on Windows Previously, we determined the UI font from a predefined set of fonts each mapped to a language. This works well if the user doesn't change their Windows UI font, but if one does, they will get the default UI font associated with their language instead of the one the set. This commit replaces ProgSettings::getFontName with ProgSettings::getUIFont, which uses the SystemParametersInfo API to query the message font from the system, which will allow users to have a custom font. It will also not interfere with different languages, as the message font will be appropriately set by default there. --- src/qt/qt_main.cpp | 2 +- src/qt/qt_mainwindow.cpp | 2 +- src/qt/qt_progsettings.cpp | 56 ++++++++++++++++++++---------- src/qt/qt_progsettings.hpp | 2 +- src/qt/qt_vmmanager_details.cpp | 2 +- src/qt/qt_vmmanager_mainwindow.cpp | 2 +- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 8a12dd44120..fd4bc5610d0 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -622,7 +622,7 @@ main(int argc, char *argv[]) fprintf(stderr, "Qt: version %s, platform \"%s\"\n", qVersion(), QApplication::platformName().toUtf8().data()); ProgSettings::loadTranslators(&app); #ifdef Q_OS_WINDOWS - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); SetCurrentProcessExplicitAppUserModelID(L"86Box.86Box"); #endif diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index f6195389c67..1133b26c09e 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -2431,7 +2431,7 @@ MainWindow::changeEvent(QEvent *event) #ifdef Q_OS_WINDOWS if (event->type() == QEvent::LanguageChange) { auto size = this->centralWidget()->size(); - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); QApplication::processEvents(); main_window->centralWidget()->setFixedSize(size); QApplication::processEvents(); diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 62b63bbcc14..d3ebfa9e80a 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -28,6 +28,8 @@ #ifdef Q_OS_WINDOWS # include # include +# define WIN32_LEAN_AND_MEAN +# include #endif extern "C" { @@ -158,26 +160,42 @@ ProgSettings::~ProgSettings() } #ifdef Q_OS_WINDOWS -/* Return the standard font name on Windows, which is overridden per-language - to prevent CJK fonts with embedded bitmaps being chosen as a fallback. */ -QString -ProgSettings::getFontName(int langId) +/* Returns the standard UI font for Windows, which by default varies for different + languages. It can also be changed via external tools, if the user wants that. + + We use the message font here since that is what most Windows components and + other third-party programs use. */ +QFont +ProgSettings::getUIFont() { - QString langCode = languageIdToCode(lang_id); - if (langCode == "ja-JP") { - /* Check for Windows 10 or later to choose the appropriate system font */ - if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) - return "Yu Gothic UI"; - else - return "Meiryo UI"; - } else if (langCode == "ko-KR") - return "Malgun Gothic"; - else if (langCode == "zh-CN") - return "Microsoft YaHei"; - else if (langCode == "zh-TW") - return "Microsoft JhengHei"; - else - return "Segoe UI"; + // Get the system (primary monitor) DPI. The font returned by + // SystemParametersInfo is scaled according to this and we need + // to get the font size in points to pass into QFont's constructor. + HDC hdc = GetDC(NULL); + int systemDpi = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(NULL, hdc); + + // Get the font metrics. + NONCLIENTMETRICSW ncm = {}; + ncm.cbSize = sizeof(ncm); + // This should never happen, but just to be safe, return Segoe UI if + // SPI fails. + if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) + { + return QFont("Segoe UI", 9); + } + + QString fontName = QString::fromWCharArray(ncm.lfMessageFont.lfFaceName); + // Windows' conversion from points to pixels goes as follows: + // + // -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72) + // + // (source: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfontw) + // + // Let's reverse that calculation to get the point size from the message font. + int fontSize = -MulDiv(ncm.lfMessageFont.lfHeight, 72, systemDpi); + + return QFont(fontName, fontSize); } #endif diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp index 2ada8c2bfaa..579c5abf7d2 100644 --- a/src/qt/qt_progsettings.hpp +++ b/src/qt/qt_progsettings.hpp @@ -15,7 +15,7 @@ class ProgSettings : public QDialog { explicit ProgSettings(QWidget *parent = nullptr); ~ProgSettings(); #ifdef Q_OS_WINDOWS - static QString getFontName(int langId); + static QFont getUIFont(); #endif static int languageCodeToId(QString langCode); static QString languageIdToCode(int id); diff --git a/src/qt/qt_vmmanager_details.cpp b/src/qt/qt_vmmanager_details.cpp index 40d0fb18569..300e227e25a 100644 --- a/src/qt/qt_vmmanager_details.cpp +++ b/src/qt/qt_vmmanager_details.cpp @@ -165,7 +165,7 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) connect(this, &VMManagerDetails::styleUpdated, portsSection, &VMManagerDetailSection::updateStyle); connect(this, &VMManagerDetails::styleUpdated, otherSection, &VMManagerDetailSection::updateStyle); - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); #endif sysconfig = new VMManagerSystem(); diff --git a/src/qt/qt_vmmanager_mainwindow.cpp b/src/qt/qt_vmmanager_mainwindow.cpp index 17bd898bda3..a520026533a 100644 --- a/src/qt/qt_vmmanager_mainwindow.cpp +++ b/src/qt/qt_vmmanager_mainwindow.cpp @@ -269,7 +269,7 @@ VMManagerMainWindow::changeEvent(QEvent *event) { #ifdef Q_OS_WINDOWS if (event->type() == QEvent::LanguageChange) { - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(QFont(ProgSettings::getUIFont())); } #endif QWidget::changeEvent(event); From 657155ac9747f7e034a3193ea6a18f0109e61ebd Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 3 Feb 2026 03:29:38 +0100 Subject: [PATCH 02/13] Work around Windows' inappropriate, ugly default fonts when using an East Asian language when it is not also the system language. --- src/qt/qt_progsettings.cpp | 57 ++++++++++++++++++++++++++++++++++++++ src/qt/qt_progsettings.hpp | 1 + 2 files changed, 58 insertions(+) diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index d3ebfa9e80a..9be40c1cb71 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -159,6 +159,8 @@ ProgSettings::~ProgSettings() delete ui; } +static QString sys_lang; + #ifdef Q_OS_WINDOWS /* Returns the standard UI font for Windows, which by default varies for different languages. It can also be changed via external tools, if the user wants that. @@ -168,6 +170,28 @@ ProgSettings::~ProgSettings() QFont ProgSettings::getUIFont() { + QString langCode = languageIdToCode(lang_id); + + if ((langCode != sys_lang) && ((langCode == "ja-JP") || (langCode == "ko-KR") || + (langCode == "zh-CN") || (langCode == "zh-TW"))) { + /* + Work around Windows' inappropriate, ugly default fonts when using an East Asian + language when it is not also the system language. + */ + if (langCode == "ja-JP") { + /* Check for Windows 10 or later to choose the appropriate system font */ + if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) + return QFont("Yu Gothic UI", 9); + else + return QFont("Meiryo UI", 9); + } else if (langCode == "ko-KR") + return QFont("Malgun Gothic", 9); + else if (langCode == "zh-CN") + return QFont("Microsoft YaHei", 9); + else if (langCode == "zh-TW") + return QFont("Microsoft JhengHei", 9); + } + // Get the system (primary monitor) DPI. The font returned by // SystemParametersInfo is scaled according to this and we need // to get the font size in points to pass into QFont's constructor. @@ -219,9 +243,42 @@ ProgSettings::languageIdToCode(int id) return languages[id].first; } +void +ProgSettings::getSysLang(QObject *parent) +{ + if (qtTranslator) { + QApplication::removeTranslator(qtTranslator); + qtTranslator = nullptr; + } + if (translator) { + QApplication::removeTranslator(translator); + translator = nullptr; + } + qtTranslator = new QTranslator(parent); + translator = new CustomTranslator(parent); + QString localetofilename = ""; + for (int i = 0; i < QLocale::system().uiLanguages().size(); i++) { + localetofilename = QLocale::system().uiLanguages()[i]; + if (translator->load(QLatin1String("86box_") + localetofilename, QLatin1String(":/"))) { + qDebug() << "Translations loaded."; + QCoreApplication::installTranslator(translator); + /* First try qtbase */ + if (!loadQtTranslations(QLatin1String("qtbase_") + localetofilename.replace('-', '_'))) + /* If that fails, try legacy qt_* translations */ + if (!loadQtTranslations(QLatin1String("qt_") + localetofilename.replace('-', '_'))) + qDebug() << "Failed to find Qt translations!"; + if (QCoreApplication::installTranslator(qtTranslator)) + qDebug() << "Qt translations loaded."; + sys_lang = localetofilename; + break; + } + } +} + void ProgSettings::loadTranslators(QObject *parent) { + getSysLang(parent); if (qtTranslator) { QApplication::removeTranslator(qtTranslator); qtTranslator = nullptr; diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp index 579c5abf7d2..cebfa8177bc 100644 --- a/src/qt/qt_progsettings.hpp +++ b/src/qt/qt_progsettings.hpp @@ -19,6 +19,7 @@ class ProgSettings : public QDialog { #endif static int languageCodeToId(QString langCode); static QString languageIdToCode(int id); + static void getSysLang(QObject *parent = nullptr); static void loadTranslators(QObject *parent = nullptr); static void reloadStrings(); class CustomTranslator : public QTranslator { From 419a3acb85dbe58f59e86668f3dfd4d99d70d84b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Feb 2026 00:21:50 +0100 Subject: [PATCH 03/13] MDS v2/MDX: Actually use nvr_path() when removing the temporary file, fixes the piling up them. --- src/cdrom/cdrom_image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index fdde472515d..20977f48b19 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -2965,7 +2965,7 @@ image_close(void *local) free(img); if (temp_file[0] != 0x00) { - remove(temp_file); + remove(nvr_path(temp_file)); temp_file[0] = 0x00; } } From a0e6566eb8e32994a06aa6ab6db1c28cc4a88017 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Feb 2026 02:35:35 +0100 Subject: [PATCH 04/13] Add the ADD-X Normerel Xenon - original patch by Kotochi, plus my fixes. --- src/chipset/opti499.c | 4 +++ src/include/86box/machine.h | 3 +++ src/include/86box/mem.h | 1 + src/machine/m_at_socket3.c | 23 ++++++++++++++++ src/machine/machine_table.c | 53 +++++++++++++++++++++++++++++++++---- src/mem/mem.c | 11 ++++---- 6 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c index ed7c269b015..132754ac77b 100644 --- a/src/chipset/opti499.c +++ b/src/chipset/opti499.c @@ -28,6 +28,7 @@ #include <86box/device.h> #include <86box/mem.h> #include <86box/port_92.h> +#include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> #include <86box/chipset.h> @@ -176,6 +177,9 @@ opti499_write(uint16_t addr, uint8_t val, void *priv) break; case 0x22: + mem_a20_chipset = (val & 0x02); + mem_a20_recalc(); + fallthrough; case 0x23: case 0x26: case 0x2d: diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index ea5d5625762..82418367304 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -749,6 +749,9 @@ extern int machine_at_4gpv5_init(const machine_t *); /* Contaq 82C597 */ extern int machine_at_greenb_init(const machine_t *); +/* OPTi 499 */ +extern int machine_at_xenon_init(const machine_t *); + /* OPTi 895 */ #ifdef EMU_DEVICE_H extern const device_t j403tg_device; diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 9051189a635..1fc95c047e4 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -307,6 +307,7 @@ extern int read_type; extern int mem_a20_state; extern int mem_a20_alt; +extern int mem_a20_chipset; extern int mem_a20_key; extern uint8_t read_mem_b(uint32_t addr); diff --git a/src/machine/m_at_socket3.c b/src/machine/m_at_socket3.c index 008394505fc..bd044d65c66 100644 --- a/src/machine/m_at_socket3.c +++ b/src/machine/m_at_socket3.c @@ -166,6 +166,29 @@ machine_at_greenb_init(const machine_t *model) return ret; } +/* OPTi 499 */ +int +machine_at_xenon_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/xenon/addx-bios-7-71-i28f001.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti499_device); + device_add(&ide_vlb_device); + device_add_params(&fdc37c6xx_device, (void *) (FDC37C661 | FDC37C6XX_IDE_PRI)); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add(&intel_flash_bxt_device); + + return ret; +} + /* OPTi 895 */ static const device_config_t j403tg_config[] = { // clang-format off diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bf13025ff78..c64e15af8b0 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8761,6 +8761,50 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has AMIKey F KBC firmware. */ + { + .name = "[OPTi 499] ADD-X Normerel Xenon", + .internal_name = "xenon", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_OPTI_499, + .init = machine_at_xenon_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_VLB, + .flags = MACHINE_IDE | MACHINE_APM, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_AMI | 0x00004600, + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Version 1.0 has an AMIKEY-2, version 2.0 has a VIA VT82C42N KBC. */ { .name = "[OPTi 895] Jetway J-403TG", @@ -18511,11 +18555,10 @@ const machine_t machines[] = { .block = CPU_BLOCK(CPU_CYRIX3S), .min_bus = 66666667, .max_bus = 83333333, - /* TODO: to find the actual voltage and multiplier bus speeds. */ - .min_voltage = 1800, - .max_voltage = 3500, - .min_multi = 1.5, - .max_multi = 8.0 + .min_voltage = 2050, + .max_voltage = 3100, + .min_multi = 3.5, + .max_multi = 5.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, diff --git a/src/mem/mem.c b/src/mem/mem.c index 91fa277be95..c456c840a7e 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -106,9 +106,10 @@ int cachesize = 256; uint32_t get_phys_virt; uint32_t get_phys_phys; -int mem_a20_key = 0; -int mem_a20_alt = 0; -int mem_a20_state = 0; +int mem_a20_key = 0; +int mem_a20_alt = 0; +int mem_a20_chipset = 0; +int mem_a20_state = 0; int mmuflush = 0; @@ -3109,12 +3110,12 @@ mem_a20_recalc(void) if (!is286) { rammask = 0xfffff; flushmmucache(); - mem_a20_key = mem_a20_alt = mem_a20_state = 0; + mem_a20_key = mem_a20_alt = mem_a20_state = mem_a20_chipset = 0; return; } - state = mem_a20_key | mem_a20_alt; + state = mem_a20_key | mem_a20_alt | mem_a20_chipset; if (state && !mem_a20_state) { rammask = cpu_16bitbus ? 0xffffff : 0xffffffff; if (is6117) From 2d01fb45603a3515ede2385c16f2ed0a9db196e7 Mon Sep 17 00:00:00 2001 From: DimMan88 Date: Wed, 4 Feb 2026 12:06:59 +0000 Subject: [PATCH 05/13] Translated using Weblate (Greek) Currently translated at 100.0% (1005 of 1005 strings) Translation: 86Box/86Box Translate-URL: https://weblate.86box.net/projects/86box/86box/el/ --- src/qt/languages/el-GR.po | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/qt/languages/el-GR.po b/src/qt/languages/el-GR.po index 6933075a563..1442183df9d 100644 --- a/src/qt/languages/el-GR.po +++ b/src/qt/languages/el-GR.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-01-26 17:57+0000\n" +"PO-Revision-Date: 2026-02-04 18:32+0000\n" "Last-Translator: DimMan88 \n" "Language-Team: Greek \n" "Language: el-GR\n" @@ -61,7 +61,7 @@ msgid "Remember size && position" msgstr "Απομνήμευση μεγέθους && θέσης" msgid "Re&nderer" -msgstr "Re&nderer" +msgstr "&Απεικονιστής" msgid "&Qt (Software)" msgstr "&Qt (Software)" @@ -397,7 +397,7 @@ msgid "Enabled (UTC)" msgstr "Ενεργό (UTC)" msgid "Dynamic Recompiler" -msgstr "Dynamic Recompiler" +msgstr "Δυναμικός Αναμεταγλωττιστής" msgid "CPU frame size" msgstr "Μέγεθος πλαισίου CPU" @@ -619,7 +619,7 @@ msgid "Image Format:" msgstr "Τύπος Εικόνας:" msgid "Block Size:" -msgstr "Block Size:" +msgstr "Μέγεθος Block:" msgid "Floppy drives:" msgstr "Οδηγοί δισκέτας:" @@ -721,10 +721,10 @@ msgid "Turbo" msgstr "Turbo" msgid "On" -msgstr "On" +msgstr "Ενεργό" msgid "Off" -msgstr "Off" +msgstr "Ανενεργό" msgid "All images" msgstr "Όλες οι εικόνες" @@ -1080,7 +1080,7 @@ msgid "Cartridge %1: %2" msgstr "Κασέτα δεδομένων %1: %2" msgid "Car&tridge %1: %2" -msgstr "Car&tridge %1: %2" +msgstr "&Κασέτα δεδομένων %1: %2" msgid "Cartridge images" msgstr "Εικόνες κασέτας δεδομένων" @@ -1460,13 +1460,13 @@ msgid "HDX image" msgstr "Εικόνα HDX" msgid "Fixed-size VHD" -msgstr "Fixed-size VHD" +msgstr "Σταθερό-μέγεθος VHD" msgid "Dynamic-size VHD" -msgstr "Dynamic-size VHD" +msgstr "Δυναμικό-μέγεθος VHD" msgid "Differencing VHD" -msgstr "Differencing VHD" +msgstr "Διαφοροποίηση VHD" msgid "(N/A)" msgstr "(Μ/Δ)" @@ -1481,19 +1481,19 @@ msgid "HDX image (.hdx)" msgstr "Εικόνα HDX (.hdx)" msgid "Fixed-size VHD (.vhd)" -msgstr "Fixed-size VHD (.vhd)" +msgstr "Σταθερό-μέγεθος VHD (.vhd)" msgid "Dynamic-size VHD (.vhd)" -msgstr "Dynamic-size VHD (.vhd)" +msgstr "Δυναμικό-μέγεθος VHD (.vhd)" msgid "Differencing VHD (.vhd)" -msgstr "Differencing VHD (.vhd)" +msgstr "Διαφοροποίηση VHD (.vhd)" msgid "Large blocks (2 MB)" -msgstr "Large blocks (2 MB)" +msgstr "Μεγάλα blocks (2 MB)" msgid "Small blocks (512 KB)" -msgstr "Small blocks (512 KB)" +msgstr "Μικρά blocks (512 KB)" msgid "VHD files" msgstr "Αρχεία VHD" @@ -2964,7 +2964,7 @@ msgid "version" msgstr "έκδοση" msgid "build" -msgstr "build" +msgstr "δομή" msgid "You are currently running version %1." msgstr "Τρέχετε την έκδοση %1." From 460c8c73939364dc167b745f81d948631b2f2252 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Wed, 4 Feb 2026 20:07:21 -0600 Subject: [PATCH 06/13] Headland: Make ROMCS Disable bit only affect E0000-EFFFF per the HT18 datasheet --- src/chipset/headland.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 48076610361..1c122e12676 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -220,9 +220,10 @@ memmap_state_default(headland_t *dev, uint8_t ht_romcs) mem_mapping_disable(&dev->mid_mapping); if (ht_romcs) - mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); + mem_set_mem_state(0x0e0000, 0x10000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); else - mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x0e0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x0f0000, 0x10000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); mem_mapping_disable(&dev->shadow_mapping[0]); From ad2f5c381d59acece210aca3cabe8a623393f953 Mon Sep 17 00:00:00 2001 From: Jeffrey Hope Date: Thu, 5 Feb 2026 05:28:13 +0000 Subject: [PATCH 07/13] Translated using Weblate (Spanish) Currently translated at 100.0% (1005 of 1005 strings) Translation: 86Box/86Box Translate-URL: https://weblate.86box.net/projects/86box/86box/es/ --- src/qt/languages/es-ES.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 4f34c34f552..af2e1e75e66 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2025-11-29 00:34+0000\n" -"Last-Translator: OBattler \n" +"PO-Revision-Date: 2026-02-06 05:57+0000\n" +"Last-Translator: Jeffrey Hope \n" "Language-Team: Spanish \n" "Language: es-ES\n" "MIME-Version: 1.0\n" @@ -1108,7 +1108,7 @@ msgid "Not running" msgstr "No en ejecución" msgid "Running" -msgstr "En ejeución" +msgstr "En ejecución" msgid "Paused" msgstr "En pausa" From 50b961e0b63644657f08d8a46fd5f8aca5b8ef52 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Fri, 6 Feb 2026 20:02:32 +0100 Subject: [PATCH 08/13] ESC/P 2: Add "Auto LF" DIP switch --- src/printer/prt_escp.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index e8ccb74f97c..ad8d2745b42 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -265,6 +265,8 @@ typedef struct escp_t { uint8_t ctrl; PALETTE palcol; + + uint8_t auto_lf; } escp_t; /* Codepage table, needed for ESC t ( */ @@ -1749,7 +1751,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x0d: /* Carriage Return (CR) */ dev->curr_x = dev->left_margin; - if (!dev->autofeed) + if (!dev->autofeed && !dev->auto_lf) return 1; fallthrough; @@ -2214,7 +2216,9 @@ escp_init(const device_t *info) dev->page_height = LETTER_PAGE_HEIGHT; } - dev->dpi = dev->lang >= LANG_ESCP ? 360 : 240; + dev->auto_lf = device_get_config_int("auto_lf"); + + dev->dpi = dev->lang >= LANG_ESCP ? 360 : 240; /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *) malloc(sizeof(psurface_t)); @@ -2328,6 +2332,17 @@ static const device_config_t lpt_prt_escp_config[] = { }, .bios = { { 0 } } }, + { + .name = "auto_lf", + .description = "Auto LF", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on From c3094d022dc52d8e292103a9019cc2312927289d Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Fri, 6 Feb 2026 22:32:46 +0100 Subject: [PATCH 09/13] ESC/P 2: Exact paper sizes, 1/36" margins --- src/include/86box/prt_papersizes.h | 24 ++++++++++++------------ src/printer/prt_escp.c | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/include/86box/prt_papersizes.h b/src/include/86box/prt_papersizes.h index e468abb35bb..f0c9e626acd 100644 --- a/src/include/86box/prt_papersizes.h +++ b/src/include/86box/prt_papersizes.h @@ -28,27 +28,27 @@ #define LEDGER_PAGE_HEIGHT 17.0 /* Standard A0 */ -#define A0_PAGE_WIDTH 33.125 -#define A0_PAGE_HEIGHT 46.75 +#define A0_PAGE_WIDTH 33.110236 +#define A0_PAGE_HEIGHT 46.811023 /* Standard A1 */ -#define A1_PAGE_WIDTH 23.375 -#define A1_PAGE_HEIGHT 33.125 +#define A1_PAGE_WIDTH 23.385826 +#define A1_PAGE_HEIGHT 33.110236 /* Standard A2 */ -#define A2_PAGE_WIDTH 16.5 -#define A2_PAGE_HEIGHT 23.375 +#define A2_PAGE_WIDTH 16.535433 +#define A2_PAGE_HEIGHT 23.385826 /* Standard A3 */ -#define A3_PAGE_WIDTH 11.75 -#define A3_PAGE_HEIGHT 16.5 +#define A3_PAGE_WIDTH 11.692913 +#define A3_PAGE_HEIGHT 16.535433 /* Standard A4 */ -#define A4_PAGE_WIDTH 8.25 -#define A4_PAGE_HEIGHT 11.75 +#define A4_PAGE_WIDTH 8.267716 +#define A4_PAGE_HEIGHT 11.692913 /* Standard B4 */ -#define B4_PAGE_WIDTH 9.875 -#define B4_PAGE_HEIGHT 13.875 +#define B4_PAGE_WIDTH 9.8425197 +#define B4_PAGE_HEIGHT 13.897637 #endif /*EMU_PLAT_FALLTHROUGH_H*/ diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index ad8d2745b42..7164ec83561 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -542,7 +542,7 @@ init_codepage(escp_t *dev, uint16_t num) static void reset_printer(escp_t *dev) { - dev->top_margin = dev->left_margin = 0.0; + dev->top_margin = dev->left_margin = 1.0 / 36.0; dev->right_margin = dev->page_width; switch (dev->paper_size) { case PAPER_A4: @@ -558,7 +558,7 @@ reset_printer(escp_t *dev) default: dev->page_height = LETTER_PAGE_HEIGHT; } - dev->bottom_margin = dev->page_height; + dev->bottom_margin = dev->page_height - 1.0 / 36.0; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; dev->curr_x = dev->curr_y = 0.0; From eaa4c7063fcac9474add27d52b5e7b69ae0309a5 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Fri, 6 Feb 2026 17:25:34 -0800 Subject: [PATCH 10/13] SLiRP: Support for changing the network. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the default 10.0.2.0/24 (or 10.0.3.0... etc) address can conflict with a LAN (as it does in my case), this feature now adds the ability to set custom network prefixes in the configuration file. I believe this is an “advanced” usage feature (like port forwarding) and should not be exposed in the GUI, therefore no GUI changes have been made. In the `[Network]` section of 86box.cfg, each of the four NICs can be set to have a custom address like such: ``` net_01_addr = 10.80.88.0 net_02_addr = 10.82.86.0 net_03_addr = 10.84.86.0 net_04_addr = 10.85.86.0 ``` The last octet of the address is effectively ignored and always set to 0 again when the configuration file is saved. Only a /24 CIDR (netmask 255.255.255.0) is supported. IPv4 has three local-scope ranges: 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0. Finding a network prefix within these that do not conflict with your real LAN should not pose a problem. --- src/config.c | 36 ++++++++++++++++++++++++++++++++++-- src/include/86box/network.h | 1 + src/network/net_slirp.c | 31 ++++++++++++++++++++++++------- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/config.c b/src/config.c index 52eb05daeb9..01bffb7f7cb 100644 --- a/src/config.c +++ b/src/config.c @@ -27,6 +27,11 @@ * -DANSI_CFG for use on these systems. */ +#ifdef _WIN32 +# include +#else +# include +#endif #include #ifdef ENABLE_CONFIG_LOG #include @@ -886,6 +891,25 @@ load_network(void) } else strcpy(nc->host_dev_name, "none"); + if (nc->net_type == NET_TYPE_SLIRP) { + sprintf(temp, "net_%02i_addr", c + 1); + p = ini_section_get_string(cat, temp, ""); + if (p && *p) { + struct in_addr addr; + if (inet_aton(p, &addr)) { + uint8_t *bytes = (uint8_t *)&addr.s_addr; + bytes[3] = 0; + sprintf(nc->slirp_net, "%d.%d.%d.0", bytes[0], bytes[1], bytes[2]); + } else { + nc->slirp_net[0] = '\0'; + } + } else { + nc->slirp_net[0] = '\0'; + } + } else { + nc->slirp_net[0] = '\0'; + } + sprintf(temp, "net_%02i_switch_group", c + 1); nc->switch_group = ini_section_get_int(cat, temp, NET_SWITCH_GRP_MIN); if (nc->switch_group < NET_SWITCH_GRP_MIN) @@ -1458,7 +1482,7 @@ load_floppy_and_cdrom_drives(void) int c; int d; int count = cdrom_get_type_count(); - + #ifndef DISABLE_FDD_AUDIO fdd_audio_load_profiles(); #endif @@ -1532,7 +1556,7 @@ load_floppy_and_cdrom_drives(void) fdd_set_audio_profile(c, d); #else fdd_set_audio_profile(c, 0); -#endif +#endif for (int i = 0; i < MAX_PREV_IMAGES; i++) { fdd_image_history[c][i] = (char *) calloc((MAX_IMAGE_PATH_LEN + 1) << 1, sizeof(char)); @@ -2987,6 +3011,14 @@ save_network(void) else ini_section_set_int(cat, temp, nc->link_state); + if (nc->net_type == NET_TYPE_SLIRP && nc->slirp_net[0] != '\0') { + sprintf(temp, "net_%02i_addr", c + 1); + ini_section_set_string(cat, temp, nc->slirp_net); + } else { + sprintf(temp, "net_%02i_addr", c + 1); + ini_section_delete_var(cat, temp); + } + sprintf(temp, "net_%02i_switch_group", c + 1); if (nc->switch_group == NET_SWITCH_GRP_MIN) ini_section_delete_var(cat, temp); diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 2c91a6d9f5f..f3f1b1f8a98 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -99,6 +99,7 @@ typedef struct netcard_conf_t { uint32_t link_state; uint8_t switch_group; uint8_t promisc_mode; + char slirp_net[16]; char nrs_hostname[128]; } netcard_conf_t; diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index c7243baacb2..f291227278f 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -493,13 +493,30 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv slirp->pfd = calloc(1, slirp->pfd_size); #endif - /* Set the IP addresses to use. */ - struct in_addr net = { .s_addr = htonl(0x0a000000 | (slirp_card_num << 8)) }; /* 10.0.x.0 */ - struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ - struct in_addr host = { .s_addr = htonl(0x0a000002 | (slirp_card_num << 8)) }; /* 10.0.x.2 */ - struct in_addr dhcp = { .s_addr = htonl(0x0a00000f | (slirp_card_num << 8)) }; /* 10.0.x.15 */ - struct in_addr dns = { .s_addr = htonl(0x0a000003 | (slirp_card_num << 8)) }; /* 10.0.x.3 */ - struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ + struct in_addr net; + struct in_addr host; + struct in_addr dhcp; + struct in_addr dns; + + /* Set the IP addresses to use. + Use a configured address if set, otherwise 10.0.x.0 */ + const char *slirp_net = net_cards_conf[card->card_num].slirp_net; + if (slirp_net[0] != '\0') { + struct in_addr addr; + inet_aton(slirp_net, &addr); + net.s_addr = htonl(ntohl(addr.s_addr) & 0xffffff00); + host.s_addr = htonl(ntohl(addr.s_addr) + 2); + dhcp.s_addr = htonl(ntohl(addr.s_addr) + 15); + dns.s_addr = htonl(ntohl(addr.s_addr) + 3); + } else { + net.s_addr = htonl(0x0a000000 | (slirp_card_num << 8)); /* 10.0.x.0 */ + host.s_addr = htonl(0x0a000002 | (slirp_card_num << 8)); /* 10.0.x.2 */ + dhcp.s_addr = htonl(0x0a00000f | (slirp_card_num << 8)); /* 10.0.x.15 */ + dns.s_addr = htonl(0x0a000003 | (slirp_card_num << 8)); /* 10.0.x.3 */ + } + + struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ + struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ const SlirpConfig slirp_config = { #if SLIRP_CHECK_VERSION(4, 9, 0) From 85e4122f9f7612db323cac0ca7add0fcbb9b3664 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Fri, 6 Feb 2026 17:49:02 -0800 Subject: [PATCH 11/13] Try to fix the build on Windows. Still untested on the OS, but Grok pointed me to the alternative function to use. Hope it works. --- src/config.c | 6 +++++- src/network/net_slirp.c | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index 01bffb7f7cb..fed9541e716 100644 --- a/src/config.c +++ b/src/config.c @@ -28,7 +28,7 @@ */ #ifdef _WIN32 -# include +# include #else # include #endif @@ -896,7 +896,11 @@ load_network(void) p = ini_section_get_string(cat, temp, ""); if (p && *p) { struct in_addr addr; +#ifdef _WIN32 if (inet_aton(p, &addr)) { +#else + if (inet_pton(AF_INET, p, &addr)) { +#endif uint8_t *bytes = (uint8_t *)&addr.s_addr; bytes[3] = 0; sprintf(nc->slirp_net, "%d.%d.%d.0", bytes[0], bytes[1], bytes[2]); diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index f291227278f..569891b86cf 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -43,6 +43,7 @@ #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include +# include #else # include #endif @@ -503,7 +504,11 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv const char *slirp_net = net_cards_conf[card->card_num].slirp_net; if (slirp_net[0] != '\0') { struct in_addr addr; +#ifdef _WIN32 + inet_pton(AF_INET, slirp_net, &addr); +#else inet_aton(slirp_net, &addr); +#endif net.s_addr = htonl(ntohl(addr.s_addr) & 0xffffff00); host.s_addr = htonl(ntohl(addr.s_addr) + 2); dhcp.s_addr = htonl(ntohl(addr.s_addr) + 15); From 441f396ca10bdfdce22bd2b1ca67f7c46853438d Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Fri, 6 Feb 2026 17:58:42 -0800 Subject: [PATCH 12/13] Use `inet_pton` instead of `inet_aton` This exists on all platforms, no messy #ifdef needed. --- src/config.c | 4 ---- src/network/net_slirp.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/config.c b/src/config.c index fed9541e716..06049713ceb 100644 --- a/src/config.c +++ b/src/config.c @@ -896,11 +896,7 @@ load_network(void) p = ini_section_get_string(cat, temp, ""); if (p && *p) { struct in_addr addr; -#ifdef _WIN32 - if (inet_aton(p, &addr)) { -#else if (inet_pton(AF_INET, p, &addr)) { -#endif uint8_t *bytes = (uint8_t *)&addr.s_addr; bytes[3] = 0; sprintf(nc->slirp_net, "%d.%d.%d.0", bytes[0], bytes[1], bytes[2]); diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 569891b86cf..86c0896a72c 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -504,11 +504,7 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv const char *slirp_net = net_cards_conf[card->card_num].slirp_net; if (slirp_net[0] != '\0') { struct in_addr addr; -#ifdef _WIN32 inet_pton(AF_INET, slirp_net, &addr); -#else - inet_aton(slirp_net, &addr); -#endif net.s_addr = htonl(ntohl(addr.s_addr) & 0xffffff00); host.s_addr = htonl(ntohl(addr.s_addr) + 2); dhcp.s_addr = htonl(ntohl(addr.s_addr) + 15); From 6fa6e5c1ea7882f7a52c20fdbc773a56b8abc9b2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 7 Feb 2026 18:37:11 +0100 Subject: [PATCH 13/13] Fix video initialization on four 486 machines and the IDE SET DRIVE PARAMETERS command. --- src/disk/hdc_ide.c | 4 ++-- src/machine/m_at_socket1.c | 2 ++ src/machine/m_at_socket2.c | 4 ++++ src/machine/m_at_socket3.c | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 56548766ab7..8b955c315af 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -2610,8 +2610,8 @@ ide_callback(void *priv) err = ABRT_ERR; else { /* Only accept after RESET or DIAG. */ - if (ide->params_specified) { - ide->cfg_spt = ide->tf->secount; + if (!ide->params_specified) { + ide->cfg_spt = (ide->tf->secount == 0) ? 256 : ide->tf->secount; ide->cfg_hpc = ide->tf->head + 1; ide->params_specified = 1; diff --git a/src/machine/m_at_socket1.c b/src/machine/m_at_socket1.c index 7d16e138186..ac836e05f2b 100644 --- a/src/machine/m_at_socket1.c +++ b/src/machine/m_at_socket1.c @@ -396,6 +396,8 @@ machine_at_tuliptc38_init(const machine_t *model) device_add(&ide_isa_device); device_add_params(&fdc37c6xx_device, (void *) (FDC37C651 | FDC37C6XX_IDE_PRI)); + video_reset(gfxcard[0]); + if (gfxcard[0] == VID_INTERNAL) { bios_load_aux_linear("roms/machines/tuliptc38/VBIOS.BIN", 0x000c0000, 32768, 0); diff --git a/src/machine/m_at_socket2.c b/src/machine/m_at_socket2.c index d8fdd79f128..5ec4039b2b6 100644 --- a/src/machine/m_at_socket2.c +++ b/src/machine/m_at_socket2.c @@ -311,6 +311,8 @@ machine_at_dell466np_init(const machine_t *model) machine_at_common_init(model); device_add(&sis_85c461_device); + video_reset(gfxcard[0]); + if (gfxcard[0] == VID_INTERNAL) device_add(machine_get_vid_device(machine)); else { @@ -354,6 +356,8 @@ machine_at_valuepoint433_init(const machine_t *model) // hangs without the PS/2 if (fdc_current[0] == FDC_INTERNAL) device_add(&fdc_at_device); + video_reset(gfxcard[0]); + if (gfxcard[0] != VID_INTERNAL) { for (uint16_t i = 0; i < 32768; i++) rom[i] = mem_readb_phys(0x000c0000 + i); diff --git a/src/machine/m_at_socket3.c b/src/machine/m_at_socket3.c index bd044d65c66..7c8c801f6e6 100644 --- a/src/machine/m_at_socket3.c +++ b/src/machine/m_at_socket3.c @@ -490,6 +490,8 @@ machine_at_tg486g_init(const machine_t *model) device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + video_reset(gfxcard[0]); + if (gfxcard[0] != VID_INTERNAL) { for (uint16_t i = 0; i < 32768; i++) rom[i] = mem_readb_phys(0x000c0000 + i);