/* * Copyright 2008 Aike J Sommer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "backendconfigurations.h" #include "outputs.h" #include "backend.h" #include namespace Kephal { BackendConfigurations * BackendConfigurations::self() { return BackendConfigurations::s_instance; } BackendConfigurations::BackendConfigurations(QObject * parent) : Configurations(parent)/*, m_status(new StatusMessage(this))*/ { BackendConfigurations::s_instance = this; } BackendConfigurations::~BackendConfigurations() { BackendConfigurations::s_instance = 0; } BackendConfigurations * BackendConfigurations::s_instance = 0; BackendConfiguration * BackendConfigurations::activeBackendConfiguration() { return (BackendConfiguration *) activeConfiguration(); } BackendConfiguration::BackendConfiguration(QObject * parent) : Configuration(parent) { } QMap BackendConfiguration::realLayout() { QMap outputScreens; foreach (Output * output, Outputs::self()->outputs()) { int screen = Configurations::self()->screen(output); outputScreens.insert(output, screen); } return realLayout(outputScreens); } QMap BackendConfiguration::realLayout(const QMap & outputScreens) { QMap simpleLayout = layout(); return realLayout(simpleLayout, outputScreens); } QMap BackendConfiguration::realLayout(const QMap & sLayout, const QMap & outputScreens) { QMap outputSizes; foreach (Output * output, outputScreens.keys()) { outputSizes.insert(output, output->isActivated() ? output->size() : output->preferredSize()); } return realLayout(sLayout, outputScreens, outputSizes); } QMap BackendConfiguration::realLayout(const QMap & sLayout, const QMap & outputScreens, const QMap & outputSizes) { //kDebug() << "calculating real layout for:" << sLayout << outputScreens; QMap screens; QMap simpleLayout = sLayout; QMap screenSizes; foreach (int screen, simpleLayout.keys()) { screenSizes.insert(screen, QSize()); } foreach (Output * output, outputScreens.keys()) { if (outputScreens[output] < 0) { continue; } if (! screenSizes.contains(outputScreens[output])) { INVALID_CONFIGURATION("outputs and configuration don't match"); return screens; } screenSizes[outputScreens[output]] = screenSizes[outputScreens[output]].expandedTo(outputSizes[output]); } int begin = simpleLayout.begin().key(); screens.insert(begin, QRect(QPoint(0, 0), screenSizes[begin])); simpleToReal(simpleLayout, screenSizes, begin, screens); Configurations::translateOrigin(screens); for (QMap::const_iterator i = screens.constBegin(); i != screens.constEnd(); ++i) { for (QMap::const_iterator j = (i + 1); j != screens.constEnd(); ++j) { if (i.value().intersects(j.value())) { INVALID_CONFIGURATION("overlapping screens"); screens.clear(); return screens; } } } return screens; } void BackendConfiguration::simpleToReal(QMap & simpleLayout, const QMap & screenSizes, int index, QMap & screens) const { QPoint pos = simpleLayout.take(index); // to the right QPoint nextPos(pos.x() + 1, pos.y()); int nextIndex = simpleLayout.key(nextPos, -1); if (nextIndex >= 0) { screens.insert(nextIndex, QRect(screens[index].topRight() + QPoint(1, 0), screenSizes[nextIndex])); simpleToReal(simpleLayout, screenSizes, nextIndex, screens); } // to the left nextPos = QPoint(pos.x() - 1, pos.y()); nextIndex = simpleLayout.key(nextPos, -1); if (nextIndex >= 0) { QSize screenSize = screenSizes[nextIndex]; screens.insert(nextIndex, QRect(screens[index].topLeft() - QPoint(screenSize.width(), 0), screenSize)); simpleToReal(simpleLayout, screenSizes, nextIndex, screens); } // to the bottom nextPos = QPoint(pos.x(), pos.y() + 1); nextIndex = simpleLayout.key(nextPos, -1); if (nextIndex >= 0) { screens.insert(nextIndex, QRect(screens[index].bottomLeft() + QPoint(0, 1), screenSizes[nextIndex])); simpleToReal(simpleLayout, screenSizes, nextIndex, screens); } // to the top nextPos = QPoint(pos.x(), pos.y() - 1); nextIndex = simpleLayout.key(nextPos, -1); if (nextIndex >= 0) { QSize screenSize = screenSizes[nextIndex]; screens.insert(nextIndex, QRect(screens[index].topLeft() - QPoint(0, screenSize.height()), screenSize)); simpleToReal(simpleLayout, screenSizes, nextIndex, screens); } } QMap BackendConfiguration::cloneLayout(int screen) { QSet positions = clonePositions(screen); QMap layout; int i = 0; foreach (const QPoint& p, positions) { layout.insert(i, p); ++i; } Configurations::translateOrigin(layout); return layout; } QSet BackendConfiguration::clonePositions(int screen) { QList > partitions = partition(screen); if (partitions.size() == 1) { return partitions[0]; } return QSet(); } QSet BackendConfiguration::positions() { QSet result; foreach (const QPoint& p, layout()) { result << p; } return result; } QSet BackendConfiguration::possiblePositions(int screen) const { QList > partitions = partition(screen); QSet result = border(partitions[0]); foreach (const QSet &partition, partitions) { result.intersect(border(partition)); } return result; } /*WILL: used by clonePositions and possiblePositions*/ QList > BackendConfiguration::partition(int screen) const { QHash * > partitions; QMap layout = this->layout(); bool exclude = layout.contains(screen); QPoint excludePoint; if (exclude) { excludePoint = layout[screen]; } foreach (const QPoint& p, layout) { if (exclude && (p == excludePoint)) { continue; } partitions.insert(p, new QSet()); partitions[p]->insert(p); } foreach (const QPoint& p, layout) { if (exclude && (p == excludePoint)) { continue; } QList connected; if (partitions.contains(p + QPoint(1, 0))) { connected.append(p + QPoint(1, 0)); } if (partitions.contains(p + QPoint(0, 1))) { connected.append(p + QPoint(0, 1)); } foreach (const QPoint& c, connected) { if (partitions[p] == partitions[c]) { continue; } partitions[p]->unite(* (partitions[c])); delete partitions[c]; partitions[c] = partitions[p]; } } QSet * > unique; foreach (QSet * partition, partitions) { unique.insert(partition); } QList > result; foreach (QSet * partition, unique) { result.append(* partition); delete partition; } return result; } QSet BackendConfiguration::border(QSet screens) const { QSet result; QList borders; borders << QPoint(1, 0) << QPoint(0, 1) << QPoint(-1, 0) << QPoint(0, -1); foreach (const QPoint& p, screens) { foreach (const QPoint& border, borders) { if (! screens.contains(p + border)) { result.insert(p + border); } } } return result; } } #ifndef NO_KDE #include "moc_backendconfigurations.cpp" #endif