summaryrefslogtreecommitdiffstats
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp243
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));
-}