diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 243 |
1 files changed, 151 insertions, 92 deletions
diff --git a/src/main.cpp b/src/main.cpp index d248718..17d07bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,7 @@ #include <QPainter> #include <QMap> #include <QSocketNotifier> +#include <QScreen> #include <fcntl.h> /* Obtain O_* constant definitions */ #include <unistd.h> @@ -32,9 +33,15 @@ Settings *s_settings = new Settings(); static int sockets[2]; +static QMap<int, MainWindow*> currentWindows; + +static QTimer setupDelay; + static void createSimpleBackground(); -static void sigUsr1(int); +static void watch(const QScreen *scrn); + +static void setupScreens(); static void messageHandler(QtMsgType type, const QMessageLogContext&, const QString& msg) { @@ -43,16 +50,16 @@ static void messageHandler(QtMsgType type, const QMessageLogContext&, const QStr static inline int size(const QRect& r) { - return r.width() * r.height(); + return r.width() * r.height(); } int main(int argc, char *argv[]) { - if (argc > 1 && QString(argv[1]) == QString("--test")) { - Global::enableTestMode(); - } + if (argc > 1 && QString(argv[1]) == QString("--test")) { + Global::enableTestMode(); + } - QApplication a(argc, argv); + QApplication a(argc, argv); // I have no idea why, but Qt's stock qWarning() output never makes it // to /var/log/lightdm/x-0-greeter.log, so we use std::cerr instead.. @@ -63,36 +70,85 @@ int main(int argc, char *argv[]) } if (!Global::testMode() && !Settings::autoLoginCheckCmd().isEmpty()) { - QProcess p; + QProcess p; int ret = QProcess::execute(Settings::autoLoginCheckCmd()); - if (ret == 0) { - if (Global::autoLoginGuest()) { - qWarning() << "Guest login ok"; + if (ret == 0) { + if (Global::autoLoginGuest()) { + qWarning() << "Guest login ok"; createSimpleBackground(); return a.exec(); - } else { - qWarning() << "Guest login failed"; - // TODO: Set error message, display somewhere - } - } + } else { + qWarning() << "Guest login failed"; + // TODO: Set error message, display somewhere + } + } } - // Build background for X server, in case we start a session that - // doesn't set one on its own this will make sure it's not simply - // black - QImage entire; + QObject::connect(&setupDelay, &QTimer::timeout, []() { + setupScreens(); + }); + setupDelay.setInterval(100); + setupDelay.setSingleShot(true); + setupDelay.start(); - // Get a list of non-overlapping screens, as this might lead to a broken - // greeter with main windows covering other login forms - QMap<int, QRect> screens; + if (!Global::testMode()) { + for (const auto scrn : QGuiApplication::screens()) { + watch(scrn); + } + QObject::connect(qApp, &QGuiApplication::screenAdded, [](const QScreen *scrn) { + setupDelay.start(); + watch(scrn); + }); + auto cb = [](const QScreen *) { + setupDelay.start(); + }; + QObject::connect(qApp, &QGuiApplication::screenRemoved, cb); + QObject::connect(qApp, &QGuiApplication::primaryScreenChanged, cb); + } + + /* + if (!entire.isNull()) { + qWarning() << "Setting x background"; + AddPixmapToBackground(entire.constBits(), entire.width(), entire.height(), + 24, entire.bytesPerLine(), entire.byteCount()); + } + */ + + return a.exec(); +} + +static void watch(const QScreen *scrn) +{ + QObject::connect(scrn, &QScreen::geometryChanged, [](const QRect &geom) { + setupDelay.start(); + }); +} + +static void createSimpleBackground() +{ + QImage img = Global::getConfigGradient(); + if (img.isNull()) + return; + img = img.scaled(QApplication::desktop()->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + AddPixmapToBackground(img.constBits(), img.width(), img.height(), + 24, img.bytesPerLine(), img.byteCount()); +} + +static QList<QRect> allOld; +static int primaryOld = -1; + +void setupScreens() +{ + // Get a list of non-overlapping screens, as this might lead to a broken + // greeter with main windows covering other login forms + QMap<int, QRect> screens; + QList<QRect> allNew; if (Global::testMode()) { screens.insert(0, QRect(0, 0, 1024, 768)); } else { - QSize desktopSize = QApplication::desktop()->size(); - qWarning() << "Desktop full size is " << desktopSize; - entire = QImage(desktopSize, QImage::Format_RGB32); for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { QRect r = QApplication::desktop()->screenGeometry(i); + allNew.append(r); QMutableMapIterator<int, QRect>it(screens); while (it.hasNext()) { it.next(); @@ -112,79 +168,82 @@ int main(int argc, char *argv[]) } } - // Determine primary screen - int primary; - if (screens.contains(QApplication::desktop()->primaryScreen())) { - // Primary screen still in selection - primary = QApplication::desktop()->primaryScreen(); - } else { - // Fallback to first one - primary = screens.begin().key(); - } - - struct sigaction usr1; - - usr1.sa_handler = &sigUsr1; - sigemptyset(&usr1.sa_mask); - usr1.sa_flags = SA_RESTART; - - QSocketNotifier *sn = nullptr; - if (sigaction(SIGUSR1, &usr1, nullptr) == 0 && ::socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0) { - sn = new QSocketNotifier(sockets[1], QSocketNotifier::Read); - QObject::connect(sn, &QSocketNotifier::activated, [](int fd) { - char tmp[1000]; - read(fd, tmp, sizeof tmp); - }); - } - - // Now set up all the screens - QPainter painter(&entire); - MainWindow *focusWindow = nullptr; + // Spurious event? + int primaryNew = QApplication::desktop()->primaryScreen(); + if (primaryNew == primaryOld && allOld == allNew) + return; + primaryOld = primaryNew; + allOld = allNew; + + // Determine primary screen + int primary; + if (screens.contains(primaryNew)) { + // Primary screen still in selection + primary = primaryNew; + } else { + // Fallback to first one + primary = screens.begin().key(); + } + + // Try to reuse as many mainwindows as possible + QMap<int, MainWindow*> remaining = currentWindows; + do { + currentWindows.clear(); + QMutableMapIterator<int, QRect> it(screens); + while (it.hasNext()) { + it.next(); + MainWindow *old = remaining.take(it.key()); + if (old != nullptr) { + // Existing + qDebug() << "Re-using existing window"; + old->setGeometry(it.value()); + if (old->showLoginForm() && primary != it.key()) { + qDebug() << "Destroying old login form"; + LoginForm *logForm = old->stealLoginForm(); + if (logForm != nullptr) { + logForm->setParent(nullptr); + logForm->deleteLater(); + } + } + currentWindows.insert(it.key(), old); + it.remove(); + } + } + } while(0); + + // Now set up remaining screens QMapIterator<int, QRect> it(screens); while (it.hasNext()) { - it.next(); - MainWindow *w = new MainWindow(primary == it.key(), it.key(), it.value()); - w->show(); - if (sn != nullptr) { - QObject::connect(sn, SIGNAL(activated(int)), w, SLOT(showStandby())); - } - if (w->showLoginForm()) { - focusWindow = w; + it.next(); + MainWindow *old = nullptr; + if (!remaining.empty()) { + qDebug() << "This should never happen, reusing old window II"; + old = remaining.take(remaining.firstKey()); + if (old != nullptr) { + if (old->showLoginForm() && primary != it.key()) { + LoginForm *logForm = old->stealLoginForm(); + if (logForm != nullptr) { + logForm->setParent(nullptr); + logForm->deleteLater(); + } + } + old->setGeometry(it.value()); + } } - if (!entire.isNull()) { - QPoint p = it.value().topLeft(); - painter.drawImage(p, w->getBackground()); + if (old == nullptr) { + qDebug() << "Adding a window"; + old = new MainWindow(primary == it.key(), it.key(), it.value()); + old->show(); + } + currentWindows.insert(it.key(), old); + if (old->showLoginForm()) { + old->setFocus(Qt::OtherFocusReason); + old->activateWindow(); } } - if (!entire.isNull()) { - qWarning() << "Setting x background"; - AddPixmapToBackground(entire.constBits(), entire.width(), entire.height(), - 24, entire.bytesPerLine(), entire.byteCount()); - } - - // Ensure we set the primary screen's widget as active when there - // are more screens - if (focusWindow) { - focusWindow->setFocus(Qt::OtherFocusReason); - focusWindow->activateWindow(); + for (MainWindow *old : remaining) { + old->deleteLater(); } - - return a.exec(); -} - -static void createSimpleBackground() -{ - QImage img = Global::getConfigGradient(); - if (img.isNull()) - return; - img = img.scaled(QApplication::desktop()->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - AddPixmapToBackground(img.constBits(), img.width(), img.height(), - 24, img.bytesPerLine(), img.byteCount()); } -static void sigUsr1(int) -{ - char a = 1; - ::write(sockets[0], &a, sizeof(a)); -} |