On Windows 7, if a user disconnects a monitor, my program crashes.
I've done a lot of testing to track down the problem. I am attaching a sample application that crashes every time. After changing screens, click on the tab that is not showing, and the program will crash.
There are a few issues in the code that I found.
First, QWidgetWindow::repaintWindow() calls QBackingStore::markDirty() without checking if the rect is empty, which leads to a failed assertion in QWidgetBackingStore::markDirty. If you fix that issue you will see other issues.
The main issue is that when a QScreen is destroyed, the QWindow::destroy() method is called. This method recursively destroys child windows. After that the QWindow::create() method is called to recreate the window, but this is not recursive. So you have a bunch of child QWindows that have deleted their QPlatformWindows.
You can see this right away as the log fills up with messages like this:
QBackingStore::flush() called for QWidgetWindow(0xd200d8, name = "centralWidgetWindow") which does not have a handle.
You can fix this by recursively creating child windows when handling the screenDestroyed signal.
Then you are still left with the bug reported in
QTBUG-38650, which is that the window doesn't appear on the screen when you unplug the monitor. Although it will come back if make these changes and then plug the monitor back in.
There are some changes in the 5.4 branch regarding screen changes. I was hopeful that they might address these issues, but as of today (2014-08-15), they do not.
Analysis of the crashes (see qtbug40187_stack.txt): The mainwindow as such re-creates fine, crashes occur later when fex switching tabs. This invokes setVisible(true) on the label window. QWindow::setVisible() calls create on the label window, which fails in the QPA plugin since it cannot create child windows with the missing parent (tab page widget). platformWindow->setVisible() then crashes. On XCB, this does not crash, but the child windows are created as top levels.