Details
-
Bug
-
Resolution: Fixed
-
P2: Important
-
None
-
6.3.1, 6.6.1, 6.7.0
-
None
-
Windows 11, two monitors both 1080p, one at 125% and the other at 100%.
Description
Sometimes when moving a window across two monitors with different DPIs a window which contains an OpenGL widget, the window gets incorrect bounds. This shows by either having block borders or the content getting clipped.
Example code:
#include <QApplication> #include <QOpenGLWidget> #include <QMainWindow> #include <QGridLayout> #include <QOpenGLPaintDevice> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow() { auto* widget = new QWidget; auto* layout = new QGridLayout; auto* openGLWidget = new QOpenGLWidget; setCentralWidget(widget); setStyleSheet("background: red"); widget->setLayout(layout); layout->addWidget(openGLWidget); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); auto* window = new MainWindow; window->show(); return a.exec(); } #include "main.moc"
Normal screenshot:
Bugged state screenshots:
Reproduction steps:
In this video I reproduce the bug by dragging the border across two monitors with different DPI's (125% & 100%).
https://drive.google.com/file/d/1e7YDHMjwfVC6diTvfocn-lbU8ePtJR60/view?usp=sharing
It is also possible to reproduce this using windows snap, however I find it much harder to consistently achieve.
When reproducing the bug I also noticed that once in this state the bug persists until a resize occurs, moving the window kept the bad bounds.
I also noticed that whether or not there was an OpenGL widget, the last resizeEvent (when windows changes the DPI as it's a different screen) has a different event->size() to this->size(). Calling this->size() seems to provide the new updated size, but the events size seemingly doesn't reflect the updated DPI and the docs say they should be the same.
A somewhat fix we found was to add this into the MainWindow class:
void resizeEvent(QResizeEvent* event) override { QMainWindow::resizeEvent(event); if (event->size() != this->size()) { QSize diff = event->size() - event->oldSize(); QSize offset = QSize(std::clamp(diff.width(), -1, 1), std::clamp(diff.height(), -1, 1)); resize(this->size() + offset); } }
For the majority of cases this resolved the issue as it forced a resize to occur (resizing with the same size gets ignored), though with a bit of flickering. It also didn't fix the cases where the sizes happened to stay the same after the DPI change.