KScreen::ConfigPtr Generator::idealConfig(const KScreen::ConfigPtr ¤tConfig) { Q_ASSERT(currentConfig); // KDebug::Block idealBlock("Ideal Config"); KScreen::ConfigPtr config = currentConfig->clone(); disableAllDisconnectedOutputs(config->outputs()); KScreen::OutputList connectedOutputs = config->connectedOutputs(); qCDebug(KSCREEN_KDED) << "Connected outputs: " << connectedOutputs.count(); if (connectedOutputs.isEmpty()) { return config; } if (connectedOutputs.count() == 1) { singleOutput(connectedOutputs); return config; } if (isLaptop()) { laptop(connectedOutputs); return fallbackIfNeeded(config); } qCDebug(KSCREEN_KDED) << "Extend to Right"; extendToRight(connectedOutputs); return fallbackIfNeeded(config); }
KScreen::ConfigPtr Generator::fallbackIfNeeded(const KScreen::ConfigPtr &config) { qCDebug(KSCREEN_KDED) << "fallbackIfNeeded()"; KScreen::ConfigPtr newConfig; //If the ideal config can't be applied, try clonning if (!KScreen::Config::canBeApplied(config)) { if (isLaptop()) { newConfig = displaySwitch(Generator::Clone); // Try to clone at our best } else { newConfig = config; KScreen::OutputList connectedOutputs = config->connectedOutputs(); if (connectedOutputs.isEmpty()) { return config; } connectedOutputs.value(connectedOutputs.keys().first())->setPrimary(true); cloneScreens(connectedOutputs); } } else { newConfig = config; } //If after trying to clone at our best, we fail... return current if (!KScreen::Config::canBeApplied(newConfig)) { qCDebug(KSCREEN_KDED) << "Config cannot be applied"; newConfig = config; } return config; }
MonitorWidget::MonitorWidget(KScreen::OutputPtr output, KScreen::ConfigPtr config, QWidget* parent) : QGroupBox(parent) { this->output = output; this->config = config; ui.setupUi(this); ui.enabledCheckbox->setChecked(output->isEnabled()); QList <KScreen::ModePtr> modeList = output->modes().values(); // Remove duplicate sizes QMap<QString, KScreen::ModePtr> noDuplicateModes; for(const KScreen::ModePtr &mode : qAsConst(modeList)) { if( noDuplicateModes.keys().contains(modeToString(mode)) ) { KScreen::ModePtr actual = noDuplicateModes[modeToString(mode)]; bool isActualPreferred = output->preferredModes().contains(actual->id()); bool isModePreferred = output->preferredModes().contains(mode->id()); if( ( mode->refreshRate() > actual->refreshRate() && !isActualPreferred ) || isModePreferred ) noDuplicateModes[modeToString(mode)] = mode; } else noDuplicateModes[modeToString(mode)] = mode; } // Sort modes by size modeList = noDuplicateModes.values(); qSort(modeList.begin(), modeList.end(), sizeBiggerThan); // Add each mode to the list for (const KScreen::ModePtr &mode : qAsConst(modeList)) { ui.resolutionCombo->addItem(modeToString(mode), mode->id()); if(output->preferredModes().contains(mode->id())) { // Make bold preferredModes QFont font = ui.resolutionCombo->font(); font.setBold(true); ui.resolutionCombo->setItemData(ui.resolutionCombo->count()-1, font, Qt::FontRole); } } connect(ui.resolutionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onResolutionChanged(int))); // Select actual mode in list if (output->currentMode()) { // Set the current mode in dropdown int idx = ui.resolutionCombo->findData(output->currentMode()->id()); if (idx < 0) { // Select mode with same size for (const KScreen::ModePtr &mode : qAsConst(modeList)) { if( mode->size() == output->currentMode()->size() ) idx = ui.resolutionCombo->findData(output->currentMode()->id()); } } if(idx < 0) idx = ui.resolutionCombo->findData(output->preferredMode()->id()); if (idx >= 0) ui.resolutionCombo->setCurrentIndex(idx); } updateRefreshRates(); // Update EDID information // KScreen doesn't make much public but that's ok... KScreen::Edid* edid = output->edid(); if (edid && edid->isValid()) { ui.outputInfoLabel->setText( tr("Name: %1\n").arg(edid->name()) % tr("Vendor: %1\n").arg(edid->vendor()) % tr("Serial: %1\n").arg(edid->serial()) % tr("Display size: %1cm x %2cm\n").arg(edid->width()).arg(edid->height()) % tr("Serial number: %1\n").arg(edid->serial()) % tr("EISA device ID: %1\n").arg(edid->eisaId()) ); } if (config->connectedOutputs().count() == 1) { setOnlyMonitor(true); // There isn't always a primary output. Gross. output->setPrimary(true); } ui.xPosSpinBox->setValue(output->pos().x()); ui.yPosSpinBox->setValue(output->pos().y()); // Behavior chooser if (output->isPrimary()) ui.behaviorCombo->setCurrentIndex(PrimaryDisplay); else ui.behaviorCombo->setCurrentIndex(ExtendDisplay); // Insert orientations ui.orientationCombo->addItem(tr("None"), KScreen::Output::None); ui.orientationCombo->addItem(tr("Left"), KScreen::Output::Left); ui.orientationCombo->addItem(tr("Right"), KScreen::Output::Right); ui.orientationCombo->addItem(tr("Inverted"), KScreen::Output::Inverted); switch(output->rotation()) { case KScreen::Output::None: ui.orientationCombo->setCurrentIndex(0); break; case KScreen::Output::Left: ui.orientationCombo->setCurrentIndex(1); break; case KScreen::Output::Right: ui.orientationCombo->setCurrentIndex(2); break; case KScreen::Output::Inverted: ui.orientationCombo->setCurrentIndex(3); break; } connect(ui.enabledCheckbox, SIGNAL(toggled(bool)), this, SLOT(onEnabledChanged(bool))); connect(ui.behaviorCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onBehaviorChanged(int))); connect(ui.xPosSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onPositionChanged(int))); connect(ui.yPosSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onPositionChanged(int))); connect(ui.orientationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onOrientationChanged(int))); // Force update behavior visibility onBehaviorChanged(ui.behaviorCombo->currentIndex()); }
KScreen::ConfigPtr Generator::displaySwitch(DisplaySwitchAction action) { // KDebug::Block switchBlock("Display Switch"); KScreen::ConfigPtr config = m_currentConfig; Q_ASSERT(config); KScreen::OutputList connectedOutputs = config->connectedOutputs(); // There's not much else we can do with only one output if (connectedOutputs.count() < 2) { singleOutput(connectedOutputs); return config; } // We cannot try all possible combinations with two and more outputs if (connectedOutputs.count() > 2) { extendToRight(connectedOutputs); return config; } KScreen::OutputPtr embedded, external; embedded = embeddedOutput(connectedOutputs); // If we don't have an embedded output (desktop with two external screens // for instance), then pretend one of them is embedded if (!embedded) { embedded = connectedOutputs.value(connectedOutputs.keys().first()); } // Just to be sure if (embedded->modes().isEmpty()) { return config; } if (action == Generator::Clone) { qCDebug(KSCREEN_KDED) << "Cloning"; embedded->setPrimary(true); cloneScreens(connectedOutputs); return config; } connectedOutputs.remove(embedded->id()); external = connectedOutputs.value(connectedOutputs.keys().first()); // Just to be sure if (external->modes().isEmpty()) { return config; } switch (action) { case Generator::ExtendToLeft: { qCDebug(KSCREEN_KDED) << "Extend to left"; external->setPos(QPoint(0,0)); external->setEnabled(true); const KScreen::ModePtr extMode = bestModeForOutput(external); Q_ASSERT(extMode); external->setCurrentModeId(extMode->id()); Q_ASSERT(external->currentMode()); // we must have a mode now const QSize size = external->currentMode()->size(); embedded->setPos(QPoint(size.width(), 0)); embedded->setEnabled(true); embedded->setPrimary(true); const KScreen::ModePtr embeddedMode = bestModeForOutput(embedded); Q_ASSERT(embeddedMode); embedded->setCurrentModeId(embeddedMode->id()); return config; } case Generator::TurnOffEmbedded: { qCDebug(KSCREEN_KDED) << "Turn off embedded (laptop)"; embedded->setEnabled(false); embedded->setPrimary(false); external->setEnabled(true); external->setPrimary(true); const KScreen::ModePtr extMode = bestModeForOutput(external); Q_ASSERT(extMode); external->setCurrentModeId(extMode->id()); return config; } case Generator::TurnOffExternal: { qCDebug(KSCREEN_KDED) << "Turn off external screen"; embedded->setPos(QPoint(0,0)); embedded->setEnabled(true); embedded->setPrimary(true); const KScreen::ModePtr embeddedMode = bestModeForOutput(embedded); Q_ASSERT(embeddedMode); embedded->setCurrentModeId(embeddedMode->id()); external->setEnabled(false); external->setPrimary(false); return config; } case Generator::ExtendToRight: { qCDebug(KSCREEN_KDED) << "Extend to the right"; embedded->setPos(QPoint(0,0)); embedded->setEnabled(true); embedded->setPrimary(true); const KScreen::ModePtr embeddedMode = bestModeForOutput(embedded); Q_ASSERT(embeddedMode); embedded->setCurrentModeId(embeddedMode->id()); Q_ASSERT(embedded->currentMode()); // we must have a mode now const QSize size = embedded->currentMode()->size(); external->setPos(QPoint(size.width(), 0)); external->setEnabled(true); external->setPrimary(false); const KScreen::ModePtr extMode = bestModeForOutput(external); Q_ASSERT(extMode); external->setCurrentModeId(extMode->id()); return config; } default: // None: just return config // Clone: handled above break; } // switch return config; }