In Qt 5, what's the right way to show multi-monitor full screen QWidget windows?
-
I have a Windows & Mac program that switches into full-screen mode on multiple monitors. In Qt 4, it seems (I can't find explicit documentation on how to do this) like the 'correct' way to go about this is by creating N QMainWindow's for the N monitors on the machine, calling QWidget::move() to the N monitor's top-left x,y coordinates, and then calling QWidget::setWindowState(Qt::WindowFullScreen). I don't know whether this is The Right Thing To Do - again, I can't find any documentation or examples anywhere that do this in Qt.
This seems to be 'broken' (if it was ever the Right Thing To Do in the first place) in Qt 5.4.1, especially on Windows 7. I'm still trying to isolate the problem, but it seems like the QMainWindows are dropping out of full-screen mode.
Just so I'm clear about this, what is the right way to do this? I found this forum post which seems to suggest that I should be setting the QScreen on the underlying QWindow objects that are held by the QMainWindows, but this doesn't seem to work in my tests. Here's an example program that I wrote:
app.h:
#include <vector> #include <QObject> class QMainWindow; class app : public QObject { Q_OBJECT public: int run(int argc, char** argv); public slots: void add_window(); void remove_window(); void windows_go_to_screens(); void windows_go_to_screens_old(); void windows_go_to_primary_screen(); void windows_fullscreen(); void windows_nonfullscreen(); private: QMainWindow * create_window(const char * id); void init_menus( QMainWindow * w ); std::vector<QMainWindow *> m_windows; };
app.cpp:
#include <assert.h> #include <algorithm> #include <iostream> #include <vector> #include <QObject> #include <QMainWindow> #include <QApplication> #include <QMenubar> #include <QAction> #include <QScreen> #include <QWindow> #include <QLayout> #include <QLabel> #include <QStyle> #include "app.h" using namespace std; int app::run(int argc, char** argv) { QApplication a(argc, argv); QMainWindow * w = create_window("0"); m_windows.push_back(w); w->show(); return a.exec(); } void app::add_window() { static const char * nums[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; m_windows.push_back(create_window(nums[m_windows.size()])); m_windows.back()->show(); } void app::remove_window() { if (m_windows.size() > 1) { QMainWindow * w = m_windows.back(); m_windows.pop_back(); w->close(); w->deleteLater(); } } void app::windows_go_to_screens() { QList<QScreen*> screens = qApp->screens(); for (unsigned i = 0; i < std::min((unsigned)m_windows.size(), (unsigned)screens.size()); ++i) { QMainWindow * mw = m_windows[i]; QScreen * screen = screens[i]; QWindow * wh = mw->windowHandle(); wh->setScreen(screen); } } void app::windows_go_to_screens_old() { QList<QScreen*> screens = qApp->screens(); for (unsigned i = 0; i < std::min((unsigned)m_windows.size(), (unsigned)screens.size()); ++i) { QMainWindow * mw = m_windows[i]; QScreen * screen = screens[i]; mw->move(screen->geometry().left(), screen->geometry().top()); } } void app::windows_go_to_primary_screen() { QList<QScreen*> screens = qApp->screens(); for (unsigned i = 0; i < std::min((unsigned)m_windows.size(), (unsigned)screens.size()); ++i) { QMainWindow * mw = m_windows[i]; QScreen * screen = screens[0]; QWindow * wh = mw->windowHandle(); wh->setScreen(screen); } } void app::windows_fullscreen() { for (unsigned i = 0; i < m_windows.size(); ++i) { QMainWindow * mw = m_windows[i]; mw->showFullScreen(); } } void app::windows_nonfullscreen() { for (unsigned i = 0; i < m_windows.size(); ++i) { QMainWindow * mw = m_windows[i]; mw->showNormal(); } } QMainWindow * app::create_window(const char * id) { QMainWindow * w = new QMainWindow(NULL); init_menus(w); QWidget * cw = new QWidget(w); w->setCentralWidget(cw); QHBoxLayout * l = new QHBoxLayout(cw); cw->setLayout(l); QLabel * lab = new QLabel(id, cw); QPalette pal(lab->palette()); pal.setColor(QPalette::Background, Qt::red); lab->setAutoFillBackground(true); lab->setPalette(pal); lab->setScaledContents(true); lab->setAlignment(Qt::AlignCenter); l->addWidget( lab ); return w; } void app::init_menus( QMainWindow * w ) { QMenuBar * menubar = w->menuBar(); QMenu * view_menu = new QMenu(tr("View"), w); view_menu->addAction("Add Window", this, SLOT(add_window())); view_menu->addAction("Remove Window", this, SLOT(remove_window())); view_menu->addAction("Windows Go To Screens", this, SLOT(windows_go_to_screens())); view_menu->addAction("Windows Go To Screens (old method)", this, SLOT(windows_go_to_screens_old())); view_menu->addAction("Windows Go To Primary Screen", this, SLOT(windows_go_to_primary_screen())); view_menu->addAction("Windows Fullscreen", this, SLOT(windows_fullscreen())); view_menu->addAction("Windows Non-Fullscreen", this, SLOT(windows_nonfullscreen())); menubar->addMenu(view_menu); }
main.cpp:
#include "app.h" int main(int argc, char** argv) { app a; return a.run(argc, argv); }
When I run this program on OS X, the "Windows Go To Screens" function does nothing - none of the windows move. Neither does the "Windows Go To Primary Screen" (poorly named - should be 0 screen?). Creating more than N windows on an N window Mac is interesting - in that case calling "Windows Fullscreen" several times will actually switch the QMainWindows into fullscreen mode one at a time?!
Even more interesting is what happens on a multi-monitor OS X machine when you do this: "Add Window" until you have as many windows as displays. "Windows Go To Screens (old method)" will send each window to the top-left of each monitor. "Windows Fullscreen" will make all windows go full-screen on all monitors. "Remove Window" until you have only 1 window left. Then "Windows Non-FullScreen", and you'll get an interesting surprise. Go into Mission Control to see what's going on.
Can anyone tell me what the RIGHT way of doing this is? I've looked through the Qt5 examples - there's the player application that seems to be broken (it can play a video in full-screen mode once, and then subsequent plays are in a separate desktop window), the sub game only maximizes to a single display, and none of the other examples seem to utilize full-screen mode, and certainly not on multiple monitors.
-
Hi,
Sounds like you may have found a regression. You should take a look at the bug report system to see if it's something known. If not please consider opening a new report providing a minimal compilable example showing the behavior