diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 9ae180d1f..1c2e000ab 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -171,6 +171,8 @@ extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index); extern MainWindow *main_window; +bool MainWindow::s_adjustingForce43 = false; + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) @@ -1016,11 +1018,75 @@ void MainWindow::updateShortcuts() ui->actionMute_Unmute->setShortcut(seq); } +void +MainWindow::adjustForForce43(const QSize &newWinSize) +{ + // Only act in resizable mode with Force 4:3 enabled and not fullscreen + if (!(vid_resize == 1 && force_43 > 0) || video_fullscreen || s_adjustingForce43) + return; + + s_adjustingForce43 = true; + + // Height consumed by menu/status/toolbars + int chromeH = menuBar()->height() + + (hide_status_bar ? 0 : statusBar()->height()) + + (hide_tool_bar ? 0 : ui->toolBar->height()); + + // Compute client area size in device‑independent pixels + double dpr = (!dpi_scale ? util::screenOfWidget(this)->devicePixelRatio() : 1.0); + int winW = newWinSize.width(); + int winH = newWinSize.height(); + int clientW = static_cast(winW / dpr); + int clientH = static_cast((winH - chromeH) / dpr); + + if (clientW <= 0 || clientH <= 0) { + s_adjustingForce43 = false; + return; + } + + // Decide which dimension the user changed most – adjust the other + int curW = static_cast(width() / dpr); + int curH = static_cast((height() - chromeH) / dpr); + bool widthChanged = std::abs(clientW - curW) >= std::abs(clientH - curH); + + int targetW, targetH; + if (widthChanged) { + // user dragged width – compute matching height for 4:3 + targetW = clientW; + targetH = (clientW * 3) / 4; + } else { + // user dragged height – compute matching width for 4:3 + targetH = clientH; + targetW = (clientH * 4) / 3; + } + + // Convert back to window size including chrome and apply + int newW = static_cast(targetW * dpr); + int newH = static_cast(targetH * dpr) + chromeH; + if (newW != winW || newH != winH) + resize(newW, newH); + + // Update emulator framebuffer size and notify platform + monitors[0].mon_scrnsz_x = targetW; + monitors[0].mon_scrnsz_y = targetH; + plat_resize_request(targetW, targetH, 0); + + // Allow renderer widget to grow and recompute scaling + ui->stackedWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + ui->stackedWidget->onResize(width(), height()); + + s_adjustingForce43 = false; +} + void MainWindow::resizeEvent(QResizeEvent *event) { //qDebug() << pos().x() + event->size().width(); //qDebug() << pos().y() + event->size().height(); + + // Enforce 4:3 aspect ratio in resizable mode when the option is set + adjustForForce43(event->size()); + if (vid_resize == 1 || video_fullscreen) return; @@ -2075,6 +2141,17 @@ void MainWindow::on_actionForce_4_3_display_ratio_triggered() { video_toggle_option(ui->actionForce_4_3_display_ratio, &force_43); + + // When turning on Force 4:3 in resizable mode, immediately snap to 4:3 + if (vid_resize == 1 && !video_fullscreen) { + ui->stackedWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + if (force_43 > 0) { + adjustForForce43(size()); + } else { + // Turning off: refresh renderer scaling + ui->stackedWidget->onResize(width(), height()); + } + } } void diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 6a255ac85..792685f42 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -176,6 +176,9 @@ private: std::unique_ptr status; std::shared_ptr mm; + static bool s_adjustingForce43; // guard against recursion + void adjustForForce43(const QSize &newWinSize); + void updateShortcuts(); void processKeyboardInput(bool down, uint32_t keycode); #ifdef Q_OS_MACOS