diff options
-rw-r--r-- | qt-lightdm-greeter.qrc | 1 | ||||
-rw-r--r-- | resources/gnome-face-tired.svg | 376 | ||||
-rw-r--r-- | src/main.cpp | 243 | ||||
-rw-r--r-- | src/mainwindow.cpp | 186 | ||||
-rw-r--r-- | src/mainwindow.h | 42 | ||||
-rw-r--r-- | src/snake.cpp | 4 |
6 files changed, 273 insertions, 579 deletions
diff --git a/qt-lightdm-greeter.qrc b/qt-lightdm-greeter.qrc index eed73f9..aa7accd 100644 --- a/qt-lightdm-greeter.qrc +++ b/qt-lightdm-greeter.qrc @@ -4,6 +4,5 @@ <file>resources/backIcon.svg</file> <file>resources/leaveIcon.svg</file> <file>resources/bwlp.svg</file> - <file>resources/gnome-face-tired.svg</file> </qresource> </RCC> diff --git a/resources/gnome-face-tired.svg b/resources/gnome-face-tired.svg deleted file mode 100644 index de43b1a..0000000 --- a/resources/gnome-face-tired.svg +++ /dev/null @@ -1,376 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - viewBox="0 0 47.001228 49.000003" - version="1.0" - id="svg2" - height="52.26667" - width="50.134644"> - <defs - id="defs4"> - <linearGradient - id="linearGradient8431"> - <stop - id="stop8433" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop8435" - offset="1" - style="stop-color:#ffffff;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient4487"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop4489" /> - <stop - id="stop4491" - offset="0.58888888" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop4493" /> - </linearGradient> - <linearGradient - id="linearGradient3752"> - <stop - style="stop-color:white;stop-opacity:1" - offset="0" - id="stop3754" /> - <stop - id="stop3756" - offset="0.80000001" - style="stop-color:#fce94f;stop-opacity:1;" /> - <stop - style="stop-color:#edd400;stop-opacity:1" - offset="1" - id="stop3758" /> - </linearGradient> - <linearGradient - id="linearGradient3734"> - <stop - id="stop3736" - offset="0" - style="stop-color:black;stop-opacity:1;" /> - <stop - id="stop3738" - offset="1" - style="stop-color:black;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient3712"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop3714" /> - <stop - style="stop-color:white;stop-opacity:0.50570345" - offset="1" - id="stop3716" /> - </linearGradient> - <linearGradient - id="linearGradient3704"> - <stop - id="stop3706" - offset="0" - style="stop-color:white;stop-opacity:1;" /> - <stop - id="stop3708" - offset="1" - style="stop-color:white;stop-opacity:0;" /> - </linearGradient> - <radialGradient - r="10.049342" - fy="7.8025141" - fx="9.3747082" - cy="7.8025141" - cx="9.3747082" - gradientTransform="matrix(1.200799,0,0,1.200799,-1.921023,-1.565398)" - gradientUnits="userSpaceOnUse" - id="radialGradient4412" - xlink:href="#linearGradient3752" /> - <radialGradient - r="10.108456" - fy="3.2659137" - fx="5.3851099" - cy="3.2659137" - cx="5.3851099" - gradientTransform="matrix(1.242401,0,0,1.242401,-1.281477,-0.839422)" - gradientUnits="userSpaceOnUse" - id="radialGradient4414" - xlink:href="#linearGradient3712" /> - <linearGradient - y2="-134.38734" - x2="19.23638" - y1="-140.43388" - x1="18.825819" - gradientUnits="userSpaceOnUse" - id="linearGradient8741" - xlink:href="#linearGradient8431" /> - <radialGradient - r="9.546875" - fy="10.046875" - fx="12.046875" - cy="10.046875" - cx="12.046875" - gradientUnits="userSpaceOnUse" - id="radialGradient7956" - xlink:href="#linearGradient3734" /> - <radialGradient - r="7.0416665" - fy="50.736225" - fx="-84.320526" - cy="50.736225" - cx="-84.320526" - gradientTransform="matrix(0.86849,0,0,0.86849,-11.05505,6.701792)" - gradientUnits="userSpaceOnUse" - id="radialGradient2230" - xlink:href="#linearGradient4487" /> - <radialGradient - r="7.0416665" - fy="50.736225" - fx="-84.320526" - cy="50.736225" - cx="-84.320526" - gradientTransform="matrix(0.86849,0,0,0.86849,-11.05505,6.701792)" - gradientUnits="userSpaceOnUse" - id="radialGradient2232" - xlink:href="#linearGradient4487" /> - <radialGradient - r="11.89852" - fy="66.5" - fx="-79.065781" - cy="66.5" - cx="-79.065781" - gradientTransform="matrix(1.172092,0,0,0.779118,114.2479,-215.3113)" - gradientUnits="userSpaceOnUse" - id="radialGradient2234" - xlink:href="#linearGradient3704" /> - <linearGradient - id="linearGradient2967"> - <stop - style="stop-color:#729fcf;stop-opacity:1;" - offset="0" - id="stop2969" /> - <stop - style="stop-color:white;stop-opacity:1" - offset="1" - id="stop2971" /> - </linearGradient> - <linearGradient - id="linearGradient2982"> - <stop - style="stop-color:#8db1d8;stop-opacity:1;" - offset="0" - id="stop2984" /> - <stop - style="stop-color:#3465a4;stop-opacity:1;" - offset="1" - id="stop2986" /> - </linearGradient> - <linearGradient - y2="-1.7008253" - x2="16" - y1="4.5018396" - x1="17.763865" - gradientTransform="translate(12,15)" - gradientUnits="userSpaceOnUse" - id="linearGradient3394" - xlink:href="#linearGradient2967" /> - <linearGradient - y2="9.2939177" - x2="46.404255" - y1="1.9139081" - x1="40.416721" - gradientTransform="scale(1.032655,0.968377)" - gradientUnits="userSpaceOnUse" - id="linearGradient3397" - xlink:href="#linearGradient2982" /> - <linearGradient - y2="5.7135463" - x2="31.59153" - y1="13.15625" - x1="32.875" - gradientUnits="userSpaceOnUse" - id="linearGradient3399" - xlink:href="#linearGradient2967" /> - </defs> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - <dc:creator> - <cc:Agent> - <dc:title>Lapo Calamandrei</dc:title> - </cc:Agent> - </dc:creator> - <cc:license - rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" /> - <dc:relation>emoticon, emots, smiley, saint, angel, smile</dc:relation> - </cc:Work> - <cc:License - rdf:about="http://creativecommons.org/licenses/GPL/2.0/"> - <cc:permits - rdf:resource="http://web.resource.org/cc/Reproduction" /> - <cc:permits - rdf:resource="http://web.resource.org/cc/Distribution" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/Notice" /> - <cc:permits - rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/ShareAlike" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/SourceCode" /> - </cc:License> - </rdf:RDF> - </metadata> - <g - transform="translate(-1.0000003)" - style="display:inline" - id="layer1"> - <g - transform="translate(-106,-6)" - id="g7909" /> - <g - id="g3901"> - <circle - style="display:inline;opacity:0.4;fill:url(#radialGradient7956);fill-opacity:1;stroke:none;stroke-width:0.46570092;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path7954" - transform="matrix(2.4091653,0,0,1.2045827,-5.022913,25.39771)" - cx="12.046875" - cy="10.046875" - r="9.546875" /> - <circle - style="display:inline;fill:url(#radialGradient4412);fill-opacity:1;stroke:#c4a000;stroke-width:0.46570092;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path4380" - transform="matrix(2.1473,0,0,2.1473,-1.8687,3.4268)" - cx="12.046875" - cy="10.046875" - r="9.546875" /> - <ellipse - style="display:inline;fill:url(#linearGradient8741);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.69999993;stroke-opacity:1" - id="path8739" - transform="matrix(2.2078305,-0.5915864,0.4553048,1.6992208,40.743051,260.37364)" - cx="19.5625" - cy="-135.96875" - rx="6.125" - ry="5.96875" /> - <circle - style="display:inline;fill:none;fill-opacity:1;stroke:url(#radialGradient4414);stroke-width:0.48958337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path4382" - transform="matrix(2.042553,0,0,2.042553,-0.6064,4.4787)" - cx="12.046875" - cy="10.046875" - r="9.546875" /> - <g - id="g4499" - transform="translate(0,-22)" - style="opacity:0.65"> - <circle - transform="matrix(0.923077,0,0,0.923077,95.6154,0.57692)" - id="path4481" - style="display:inline;opacity:1;fill:url(#radialGradient2230);fill-opacity:1;stroke:none;stroke-width:1.08333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - cx="-83" - cy="53" - r="6.5" /> - <circle - transform="matrix(0.923077,0,0,0.923077,105.6154,0.57692)" - id="path4495" - style="display:inline;opacity:1;fill:url(#radialGradient2232);fill-opacity:1;stroke:none;stroke-width:1.08333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - cx="-83" - cy="53" - r="6.5" /> - </g> - <g - id="g7846" - transform="translate(0,205)"> - <path - id="path4515" - d="m 15.5,-176.5 c 1.962489,1.29412 3.958976,1.41533 6,0" - style="display:inline;opacity:0.81226059;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" /> - <path - id="path4517" - d="m 31.5,-176.5 c -1.962489,1.29412 -3.958976,1.41533 -6,0" - style="display:inline;opacity:0.81226059;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" /> - <path - id="path4509" - d="m 15.5,-175.5 c 1.962489,1.29412 3.958976,1.41533 6,0" - style="fill:none;fill-rule:evenodd;stroke:#888a85;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" /> - <path - id="path4513" - d="m 31.5,-175.5 c -1.962489,1.29412 -3.958976,1.41533 -6,0" - style="display:inline;fill:none;fill-rule:evenodd;stroke:#888a85;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" /> - </g> - <g - id="g4531" - transform="matrix(0.3112951,0,0,1,17.520421,204)"> - <path - id="path4527" - d="M 15.557761,-163.5 H 32.435777" - style="display:inline;opacity:0.8;fill:none;fill-rule:evenodd;stroke:url(#radialGradient2234);stroke-width:1.79231215px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" /> - </g> - <path - style="fill:none;fill-rule:evenodd;stroke:#c4a000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" - d="m 22.5,39.5 h 5" - id="path5373" /> - <path - id="path2898" - d="m 28.5,15.5 v 2 h 2 l -2,2.5 v 1.5 h 5 v -2 h -2 l 2,-2.5 v -1.5 z" - style="fill:url(#linearGradient3394);fill-opacity:1;stroke:#3465a4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <g - id="g1975" - transform="translate(3.000005)"> - <path - id="path2946" - d="m 31,9 4.999995,2e-6 v 1.053572 L 32.79543,14 H 36 l -5e-6,1.000004 h -5 L 31,13.946429 34.210006,10.000002 31,10 Z" - style="font-style:normal;font-weight:bold;font-size:11.05665684px;font-family:'Bitstream Vera Sans Mono';fill:#729fcf;fill-opacity:1;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - id="text2929" - d="m 31,9 4.999995,2e-6 v 1.053572 L 32.79543,14 H 36 l -5e-6,1.000004 h -5 L 31,13.946429 34.210006,10.000002 31,10 V 9" - style="font-style:normal;font-weight:bold;font-size:11.05665684px;font-family:'Bitstream Vera Sans Mono';fill:url(#linearGradient3399);fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> - </g> - <g - id="g1967" - transform="translate(-0.005991)"> - <path - id="path2949" - d="m 40,1 7.000003,-6.5e-7 0.006,2.07142925 L 43,7 h 4 l 3e-6,2.0000161 h -7.000019 l -2e-6,-2.0714448 L 44,3 l -3.994011,7e-7 z" - style="font-style:normal;font-weight:bold;font-size:15.10630894px;font-family:'Bitstream Vera Sans Mono';fill:#729fcf;fill-opacity:1;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - id="text2933" - d="m 40,1 7.000003,-6.5e-7 0.006,2.07142925 L 43,7 h 4 l 3e-6,2.0000161 h -7.000019 l -2e-6,-2.0714448 L 44,3 l -3.994011,7e-7 L 40,1" - style="font-style:normal;font-weight:bold;font-size:15.10630894px;font-family:'Bitstream Vera Sans Mono';fill:url(#linearGradient3397);fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> - <g - style="opacity:0.5" - id="g3008"> - <path - style="opacity:1;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" - d="m 40.5,2.5 v -1 h 6" - id="path2951" /> - <path - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" - d="M 43.0625,7 C 42.786358,7.0258883 42.583487,7.2707326 42.609375,7.546875 42.635263,7.8230174 42.880108,8.0258883 43.15625,8 H 47 V 7 H 43.15625 C 43.12507,6.99706 43.09368,6.99706 43.0625,7 Z" - id="path2953" /> - <path - style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" - d="M 44.09375,3 C 44.00794,3.03114 43.932288,3.085176 43.875,3.15625 L 40.15625,6.78125 40,6.9375 V 7.15625 9 h 1 V 7.34375 l 3.5625,-3.5 C 44.724254,3.6862744 44.760437,3.4399497 44.650803,3.2426093 44.54117,3.0452688 44.31291,2.9458567 44.09375,3 Z" - id="path2955" /> - </g> - </g> - </g> - </g> -</svg> 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)); -} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1e08f0f..7c75489 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -32,106 +32,138 @@ MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, QWidget *parent) : QWidget(parent), m_ScreenRect(screenRect), - m_Primary(primary), m_LoginForm(nullptr), m_messages(nullptr), m_Clock(nullptr), - m_Snake(nullptr) + m_Snake(nullptr), + m_Banner(nullptr), + m_News(nullptr) { setObjectName(QString("MainWindow_%1").arg(screen)); - setGeometry(screenRect); - - setBackground(); - // TODO: Check if testMode == false and greeter == NULL, if so display big error message // instead of exiting/crashing // display login dialog only in the main screen + if (primary) { + m_LoginForm = new LoginForm(this); + // This hack ensures that the primary screen will have focus + // if there are more screens (move the mouse cursor in the center + // of primary screen - not in the center of all X area). It + // won't affect single-screen environments. + int centerX = screenRect.width()/2 + screenRect.x(); + int centerY = screenRect.height()/2 + screenRect.y(); + QCursor::setPos(centerX, centerY); + } + // Banner + if (!Settings::bannerImageFile().isEmpty()) { + qWarning() << "Have banner " << Settings::bannerImageFile(); + m_Banner = new QSvgWidget(Settings::bannerImageFile(), this); + } + + createLogWindow(); + createClock(); + createNewsWindow(); + + setGeometry(screenRect); +} + +void MainWindow::resizeEvent(QResizeEvent *event) +{ + if (m_Snake != nullptr) { + delete m_Snake; + m_Snake = nullptr; + } + + QWidget::resizeEvent(event); + m_ScreenRect = QRect(this->pos(), event->size()); + setBackground(); /* * Everything is layed out manually here, since I don't know how to represent the size constraints * and interactions of everything using layout classes. You're welcome to improve this, but I double * dare you to not break any combination of having/not having certain logos or elements displayed. */ - int newsY = 100; - int newsX = screenRect.width() / 2; - int newsBottom = screenRect.height(); + int newsX = m_ScreenRect.width() / 2; + int newsBottom = m_ScreenRect.height(); - int spaceY = screenRect.height() / 2; - - if (showLoginForm()) { - m_LoginForm = new LoginForm(this); + int spaceY = m_ScreenRect.height() / 2; + + if (m_LoginForm != nullptr) { spaceY -= m_LoginForm->height() / 2; - int maxX = screenRect.width() - m_LoginForm->width(); - int maxY = screenRect.height() - m_LoginForm->height(); + int maxX = m_ScreenRect.width() - m_LoginForm->width(); + int maxY = m_ScreenRect.height() - m_LoginForm->height(); int defaultX = 50*maxX/100; int defaultY = 50*maxY/100; int offsetX = getOffset(Settings::offsetX(), maxX, defaultX); int offsetY = getOffset(Settings::offsetY(), maxY, defaultY); - + m_LoginForm->move(offsetX, offsetY); m_LoginForm->show(); - - // This hack ensures that the primary screen will have focus - // if there are more screens (move the mouse cursor in the center - // of primary screen - not in the center of all X area). It - // won't affect single-screen environments. - int centerX = screenRect.width()/2 + screenRect.x(); - int centerY = screenRect.height()/2 + screenRect.y(); - QCursor::setPos(centerX, centerY); newsX = m_LoginForm->geometry().right() + 5; } // Banner - if (!Settings::bannerImageFile().isEmpty()) { - qWarning() << "Have banner " << Settings::bannerImageFile(); - QSvgWidget *banner = new QSvgWidget(Settings::bannerImageFile(), this); - qWarning() << banner->sizeHint(); - if (banner->renderer()->isValid()) { + if (m_Banner != nullptr) { + qWarning() << m_Banner->sizeHint(); + if (m_Banner->renderer()->isValid()) { QSize sh; int offs = 0; do { offs += 20; - sh = banner->sizeHint().scaled(screenRect.width() - offs, spaceY - offs - 50, Qt::KeepAspectRatio); - } while (offs < 200 && sh.width() > screenRect.width() / 2 && sh.height() > spaceY / 2); + sh = m_Banner->sizeHint().scaled(m_ScreenRect.width() - offs, spaceY - offs - 50, Qt::KeepAspectRatio); + } while (offs < 200 && sh.width() > m_ScreenRect.width() / 2 && sh.height() > spaceY / 2); int yoff = (spaceY - sh.height()); if (yoff < 100) { yoff = 100; } - banner->setGeometry((screenRect.width() - sh.width()) / 2, yoff / 2, sh.width(), sh.height()); - newsY = banner->geometry().bottom() + 10; + m_Banner->setGeometry((m_ScreenRect.width() - sh.width()) / 2, yoff / 2, sh.width(), sh.height()); + newsY = m_Banner->geometry().bottom() + 10; } } + for (QWidget *w : m_DecoItems) { + w->setParent(nullptr); + w->deleteLater(); + } + // Distro and custom icons left/right bottom + m_DecoItems.clear(); int ls = (spaceY > 500 ? 500 : spaceY); - if (ls > screenRect.height() / 5) ls = screenRect.height() / 5; - if (ls > screenRect.width() / 5) ls = screenRect.width() / 5; - QRect logoRect(QPoint(0, screenRect.height() / 3), QSize(ls, screenRect.height() * 2 / 3)); + if (ls > m_ScreenRect.height() / 5) ls = m_ScreenRect.height() / 5; + if (ls > m_ScreenRect.width() / 5) ls = m_ScreenRect.width() / 5; + QRect logoRect(QPoint(0, m_ScreenRect.height() / 3), QSize(ls, m_ScreenRect.height() * 2 / 3)); QSize logoSize = createLogo(logoRect); - QRect distroRect(QPoint(screenRect.width() - ls, screenRect.height() - ls), QSize(ls, ls)); + QRect distroRect(QPoint(m_ScreenRect.width() - ls, m_ScreenRect.height() - ls), QSize(ls, ls)); QSize distroSize = createDistro(distroRect); if (distroSize.height() > 0) { newsBottom -= distroSize.height() - 10; } - if (showLoginForm()) { - // Log window - QRect lwSize(QPoint(logoSize.width(), screenRect.height() * 3/4), QPoint(screenRect.width() - distroSize.width(), screenRect.height())); + // Log window + if (m_messages != nullptr) { + QRect lwSize(QPoint(logoSize.width(), m_ScreenRect.height() * 3/4), QPoint(m_ScreenRect.width() - distroSize.width(), m_ScreenRect.height())); lwSize.adjust(10, 10, -10, -10); - if (createLogWindow(lwSize)) { - newsBottom = lwSize.top(); - } + m_messages->setGeometry(lwSize); + int ps = lwSize.height() / 20; + if (ps > 20) ps = 20; + m_messages->setFontPointSize(ps); + newsBottom = lwSize.top(); + } + if (m_Clock != nullptr) { + m_Clock->setFixedWidth(m_ScreenRect.width()); + m_Clock->parentWidget()->setFixedWidth(m_ScreenRect.width()); } - createClock(); // News widget - QRect newsSize(QPoint(newsX, newsY), QPoint(screenRect.width() - 10, newsBottom - 10)); - createNewsWindow(newsSize); -} - -MainWindow::~MainWindow() -{ + if (m_News != nullptr) { + QRect newsSize(QPoint(newsX, newsY), QPoint(m_ScreenRect.width() - 10, newsBottom - 10)); + if (newsSize.width() < 200 || newsSize.height() < 80) { + m_News->hide(); + } else { + m_News->setGeometry(newsSize); + m_News->show(); + } + } } void MainWindow::paintEvent(QPaintEvent *event) @@ -194,14 +226,19 @@ void MainWindow::createNextLogo(QRect &max, QSize &retval, const QString &path) if (max.height() <= 0) return; QSvgWidget *img = new QSvgWidget(path, this); - if (!img->renderer()->isValid()) + if (!img->renderer()->isValid()) { + img->deleteLater(); return; + } QSize virtualSize = img->sizeHint().scaled(max.width(), max.height(), Qt::KeepAspectRatio); QSize realSize = img->sizeHint().scaled(max.width() - 20, max.height() - 20, Qt::KeepAspectRatio); - if (virtualSize.width() == 0 || virtualSize.height() == 0) + if (virtualSize.width() == 0 || virtualSize.height() == 0) { + img->deleteLater(); return; + } QRect c(max.left() + 10, max.bottom() - realSize.height() - 10, realSize.width(), realSize.height()); img->setGeometry(c); + m_DecoItems.append(img); max.setHeight(max.height() - virtualSize.height()); retval.setWidth(qMax(retval.width(), virtualSize.width())); retval.setHeight(retval.height() + virtualSize.height()); @@ -222,13 +259,14 @@ QSize MainWindow::createDistro(const QRect &max) } QPixmap pixmap(QPixmap::fromImage(img)); QLabel *lbl = new QLabel(this); + m_DecoItems.append(lbl); lbl->setPixmap(pixmap); QRect c(max.right() - realSize.width() - 10, max.bottom() - realSize.height() - 10, realSize.width(), realSize.height()); lbl->setGeometry(c); return virtualSize; } -bool MainWindow::createLogWindow(const QRect& geom) +bool MainWindow::createLogWindow() { QString path = Settings::logMessageFile(); if (path.isEmpty()) @@ -237,10 +275,6 @@ bool MainWindow::createLogWindow(const QRect& geom) if (f.size() == 0 || !f.open(QFile::ReadOnly)) return false; m_messages = new QTextEdit(this); - m_messages->setGeometry(geom); - int ps = geom.height() / 20; - if (ps > 20) ps = 20; - m_messages->setFontPointSize(ps); QTextStream stream(&f); const QColor black(Qt::black); while (!stream.atEnd()) { @@ -265,21 +299,18 @@ bool MainWindow::createLogWindow(const QRect& geom) return true; } -void MainWindow::createNewsWindow(const QRect &size) +void MainWindow::createNewsWindow() { - if (size.width() < 100 || size.height() < 100) - return; QString path = Settings::newsHtmlFile(); if (path.isEmpty()) return; QFile f(path); if (f.size() == 0 || !f.open(QFile::ReadOnly)) return; - QTextEdit *news = new QTextEdit(this); - news->setReadOnly(true); - news->setStyleSheet("border:none; background:rgba(255,255,255,.33); border-radius:5px"); - news->setHtml(QString::fromUtf8(f.readAll())); - news->setGeometry(size); + m_News = new QTextEdit(this); + m_News->setReadOnly(true); + m_News->setStyleSheet("border:none; background:rgba(255,255,255,.33); border-radius:5px"); + m_News->setHtml(QString::fromUtf8(f.readAll())); } void MainWindow::createClock() @@ -329,7 +360,7 @@ void MainWindow::createClock() bool MainWindow::showLoginForm() { - return m_Primary; + return m_LoginForm != nullptr; } void MainWindow::setFocus(Qt::FocusReason reason) @@ -368,6 +399,7 @@ int MainWindow::getOffset(QString settingsOffset, int maxVal, int defaultVal) void MainWindow::setBackground() { + m_background = QImage(); Qt::AspectRatioMode arMode = Qt::KeepAspectRatioByExpanding; QString bgPath = Settings::backgrundImageFile(); if (bgPath.length() != 0) { @@ -407,28 +439,6 @@ void MainWindow::setBackground() this->setPalette(palette); } -void MainWindow::showStandby() -{ - if (m_LoginForm != nullptr) { - m_LoginForm->hide(); - } - QSvgWidget *img = new QSvgWidget(":/resources/gnome-face-tired.svg", this); - if (img->renderer()->isValid()) { - QSize sh = img->sizeHint().scaled(this->width() / 2, this->height() / 2, Qt::KeepAspectRatio); - img->setGeometry((this->width() - sh.width()) / 2, (this->height() - sh.height()) / 2, sh.width(), sh.height()); - img->show(); - } else { - qWarning() << "Shice!"; - } - QTimer::singleShot(4000, [this, img]() { - img->hide(); - img->deleteLater(); - if (this->m_LoginForm != nullptr) { - m_LoginForm->show(); - } - }); -} - void MainWindow::updateClock() { int next = drawClock(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 8f9245e..fc0249b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -14,6 +14,7 @@ #include <QRect> #include <QSize> #include <QLabel> +#include <QList> #include "loginform.h" @@ -22,6 +23,7 @@ namespace Ui { } class QTextEdit; +class QSvgWidget; class GameCore; @@ -30,51 +32,51 @@ class MainWindow : public QWidget Q_OBJECT public: - explicit MainWindow(bool primary, int screen, const QRect &rect, QWidget *parent = 0); - ~MainWindow(); + explicit MainWindow(bool primary, int screen, const QRect &rect, QWidget *parent = nullptr); void setFocus(Qt::FocusReason reason); - QSize createLogo(QRect max); + bool showLoginForm(); - void createNextLogo(QRect &max, QSize &retval, const QString &path); + LoginForm* stealLoginForm() { LoginForm *p = m_LoginForm; m_LoginForm = nullptr; return p; } - QSize createDistro(const QRect &max); +protected: + virtual void paintEvent(QPaintEvent *event) override; - bool createLogWindow(const QRect& geom); + virtual void mouseDoubleClickEvent(QMouseEvent *) override; - void createNewsWindow(const QRect &size); + virtual void keyPressEvent(QKeyEvent *) override; - void createClock(); + virtual void resizeEvent(QResizeEvent *) override; - bool showLoginForm(); +public slots: + void updateClock(); - QImage& getBackground() { return m_background; } +private: - LoginForm* loginForm() { return m_LoginForm; } + QSize createLogo(QRect max); -protected: - virtual void paintEvent(QPaintEvent *event); + void createNextLogo(QRect &max, QSize &retval, const QString &path); - virtual void mouseDoubleClickEvent(QMouseEvent *); + QSize createDistro(const QRect &max); - virtual void keyPressEvent(QKeyEvent *); + bool createLogWindow(); -public slots: - void showStandby(); - void updateClock(); + void createNewsWindow(); -private: + void createClock(); int getOffset(QString offset, int maxVal, int defaultVal); void setBackground(); int drawClock(); QRect m_ScreenRect; - bool m_Primary; LoginForm* m_LoginForm; QImage m_background; QTextEdit *m_messages; QLabel *m_Clock; GameCore *m_Snake; + QSvgWidget *m_Banner; + QList<QWidget*> m_DecoItems; + QTextEdit *m_News; }; #endif // MAINWINDOW_H diff --git a/src/snake.cpp b/src/snake.cpp index 9c7fefa..2ce1a0d 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -215,7 +215,7 @@ GameCore::GameCore(QWidget *widget) snake->parts.append(QPoint(snake->x, snake->y)); } // If no food was picked up within a minute, spawn more - if (QDateTime::currentMSecsSinceEpoch() - _lastMeal > 60000) { + if (!_snakes.isEmpty() && QDateTime::currentMSecsSinceEpoch() - _lastMeal > 60000) { _lastMeal = QDateTime::currentMSecsSinceEpoch(); addFood(); } @@ -424,7 +424,7 @@ void GameCore::addSnake() int x = qrand() % _width; int y = qrand() % _height; if (FIELD(x, y)->isFree()) { - if (qrand() % 2 == 0) { + if (_snakes.count() <= _balls.count()) { qDebug() << "Adding Snake at" << x << y; _snakes.append(new Snake(x, y)); } else { |