#include "widget.h" #include "main.h" #include "xx.h" #include "bus.h" #include #include #include #include #include #include namespace { bool _testMode, _autoSetup, _showGui, _backgroundMode, _wakeup, _center, _dumpScreens; QString _resList, _outputMapping; } namespace CommandLine { bool testMode() { return _testMode; } bool autoSetup() { return _autoSetup; } bool showGui() { return _showGui; } bool backgroundMode() { return _backgroundMode; } bool wakeup() { return _wakeup; } bool center() { return _center; } bool dumpScreens() { return _dumpScreens; } } static void parseCommandLine(const QCoreApplication &a); static void dumpScreens(); int main(int argc, char *argv[]) { QCoreApplication *a; bool gui = true; for (int i = 0; i < argc; ++i) { if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--wakeup") == 0) { gui = false; } } if (gui) { a = new QApplication(argc, argv); } else { a = new QCoreApplication(argc, argv); } QCoreApplication::setApplicationName("BeamerGUI XP - Home Edition"); QCoreApplication::setApplicationVersion("2.0"); // System strings QTranslator *qtTranslator = new QTranslator(a); qtTranslator->load(QLocale::system(), "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath)); a->installTranslator(qtTranslator); // App specific QTranslator *translator = new QTranslator(a); translator->load(QLocale::system(), ":"); a->installTranslator(translator); parseCommandLine(*a); if (CommandLine::wakeup()) { return Bus::inst()->registerService() ? 0 : 1; } if (CommandLine::dumpScreens()) { dumpScreens(); return 0; } ScreenSetup::inst()->addMissingEdidResolutions(); ScreenSetup::inst()->initModes(); if (CommandLine::center()) { ScreenSetup::inst()->setCenteredClone(); } else if (CommandLine::autoSetup()) { ScreenMode mode; ScreenSetup::inst()->setDefaultMode(mode); } else if (!_resList.isEmpty()) { ScreenSetup::inst()->setResolutionsFromString(_resList, _outputMapping); } else { ScreenSetup::inst()->getCurrentMode(); } Widget *w = nullptr; if (CommandLine::backgroundMode() || CommandLine::showGui()) { w = new Widget(); if (CommandLine::showGui() || ScreenSetup::inst()->hasScreenWithoutEdid()) { w->show(); } } if (w == nullptr) return 0; return a->exec(); } static void parseCommandLine(const QCoreApplication &a) { // Command line QCommandLineParser parser; parser.setApplicationDescription("Utility for detecting and configuring screen setup"); parser.addHelpOption(); parser.addVersionOption(); // Option for adding modes and trying to auto-setup QCommandLineOption oAutoSetup(QStringList() << "a" << "auto", QCoreApplication::translate("main", "Automatically configure modes and set up screens.")); parser.addOption(oAutoSetup); // Show config GUI if more than one screen QCommandLineOption oShowGui(QStringList() << "g" << "gui", QCoreApplication::translate("main", "Show config GUI right away.")); parser.addOption(oShowGui); // Keep running and detect screen setup changes QCommandLineOption oBackground(QStringList() << "b" << "background", QCoreApplication::translate("main", "Keep running in background and show GUI when number of screens changes.")); parser.addOption(oBackground); // Test mode -- pretend to do setup QCommandLineOption oTest(QStringList() << "t" << "test", QCoreApplication::translate("main", "Test mode, don't actually apply any changes.")); parser.addOption(oTest); // Wakeup beamergui daemon via DBus connect QCommandLineOption oWakeup(QStringList() << "w" << "wakeup", QCoreApplication::translate("main", "Connect to system bus to trigger wakeup of wainting beamergui.")); parser.addOption(oWakeup); // Set all outputs to clone mode and center them according to the largest output QCommandLineOption oCenter(QStringList() << "c" << "center", QCoreApplication::translate("main", "Set all outputs to clone mode. If size differs, center outputs according to largest output.")); parser.addOption(oCenter); // Dump all screens, non-overlapping (ie. exclude clones) QCommandLineOption oDumpScreens(QStringList() << "d" << "dump", QCoreApplication::translate("main", "Dump all non-overlapping screens.")); parser.addOption(oDumpScreens); // Pre-configured setup QCommandLineOption oResList("resolutions", QCoreApplication::translate("main", "Space separated list of resolutions to apply to outputs." " Outputs will be assigned in alphabetical order, if no additional" " output mapping is given."), "WxH [WxH ...]"); parser.addOption(oResList); QCommandLineOption oMapping("mapping", QCoreApplication::translate("main", "Map resolutions (from --resolutions) to output names." " The list of resolutions is zero-based."), "= [...]"); parser.addOption(oMapping); // PARSE parser.process(a); _testMode = parser.isSet(oTest); _autoSetup = parser.isSet(oAutoSetup); _showGui = parser.isSet(oShowGui); _backgroundMode = parser.isSet(oBackground); _wakeup = parser.isSet(oWakeup); _center = parser.isSet(oCenter); _dumpScreens = parser.isSet(oDumpScreens); _resList = parser.value(oResList); _outputMapping = parser.value(oMapping); } QTextStream& qStdOut() { static QTextStream ts(stdout); return ts; } static int findConfig(QVector &list) { int area = 0; bool overlap = false; struct { QVector list; int area = 0; } best; for (int i = 0; i < list.size(); ++i) { const QRect &first = list[i]; for (int j = i + 1; j < list.size(); ++j) { if (!list[j].intersects(first)) continue; overlap = true; QVector copy1 = list, copy2 = list; copy1.remove(i); copy2.remove(j); int a1 = findConfig(copy1); int a2 = findConfig(copy2); if (a1 > best.area && a1 > a2) { best.area = a1; best.list = copy1; } else if (a2 > best.area) { best.area = a2; best.list = copy2; } } area += first.width() * first.height(); } if (!overlap) return area; list = best.list; return best.area; } static void dumpScreens() { QVector list; for (auto scr : ScreenSetup::inst()->getScreenPositions()) { list.append(QRect(scr.location, scr.currentResolution)); } findConfig(list); qSort(list.begin(), list.end(), [](const QRect &one, const QRect &other) -> bool { return one.y() < other.y() || (one.y() == other.y() && one.x() < other.x()); }); if (list.empty()) { // Fallback to desktop size QRect s = qApp->desktop()->screenGeometry(); if (s.width() > 0 && s.height() > 0) { list.append(s); } } int nextX = 0; int lastY = 0; qStdOut() << "# x y width height" << endl; for (const auto &geo : list) { if (geo.x() != nextX) { qStdOut() << "# Warning: Next screen has gap to previous one" << endl; } qStdOut() << geo.x() << ' ' << geo.y() << ' ' << geo.width() << ' ' << geo.height() << endl; if (lastY == geo.y()) { nextX += geo.width(); } else { lastY = 0; } lastY = geo.y(); } }