2 * Copyright 2008 Aike J Sommer <dev@aikesommer.name>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "xmlconfigurations.h"
23 #include "xml/configurations_xml.h"
24 #include "outputs/backendoutputs.h"
25 #include "kephal/screens.h"
33 XMLConfiguration::XMLConfiguration(XMLConfigurations
* parent
, ConfigurationXML
* config
)
34 : BackendConfiguration(parent
),
35 m_configuration(config
)
39 ConfigurationXML
* XMLConfiguration::configuration()
41 return m_configuration
;
44 QString
XMLConfiguration::name()
46 return m_configuration
->name();
49 bool XMLConfiguration::isModifiable()
51 return m_configuration
->modifiable();
54 bool XMLConfiguration::isActivated()
56 return this == m_parent
->activeConfiguration();
59 void XMLConfiguration::activate()
64 void XMLConfiguration::setLayout(const QMap
<int, QPoint
> & layout
) {
68 int XMLConfiguration::primaryScreen() {
69 return m_configuration
->primaryScreen();
72 QMap
<int, QPoint
> XMLConfiguration::layout() {
73 if (! m_layout
.empty()) {
77 QMap
<int, ScreenXML
*> remaining
;
78 foreach (ScreenXML
* screen
, m_configuration
->screens()) {
79 remaining
.insert(screen
->id(), screen
);
82 QMap
<int, QPoint
> layout
;
86 QSet
<ScreenXML
*> added
;
87 foreach (ScreenXML
* screen
, remaining
) {
93 } else if (layout
.contains(screen
->rightOf())) {
94 pos
= QPoint(layout
[screen
->rightOf()]);
97 } else if (layout
.contains(screen
->bottomOf())) {
98 pos
= QPoint(layout
[screen
->bottomOf()]);
104 layout
.insert(screen
->id(), pos
);
106 remaining
.remove(screen
->id());
107 added
.insert(screen
);
112 while (! added
.empty()) {
113 QSet
<ScreenXML
*>::iterator i
= added
.begin();
114 while (i
!= added
.end()) {
116 if (remaining
.contains(s
->rightOf()) && ! layout
.contains(s
->rightOf())) {
117 ScreenXML
* toAdd
= remaining
[s
->rightOf()];
118 QPoint pos
= QPoint(layout
[s
->id()]);
121 layout
.insert(toAdd
->id(), pos
);
123 remaining
.remove(toAdd
->id());
126 if (remaining
.contains(s
->bottomOf()) && ! layout
.contains(s
->bottomOf())) {
127 ScreenXML
* toAdd
= remaining
[s
->bottomOf()];
128 QPoint pos
= QPoint(layout
[s
->id()]);
131 layout
.insert(toAdd
->id(), pos
);
133 remaining
.remove(toAdd
->id());
142 if (! remaining
.empty()) {
143 //qDebug() << "invalid configuration (remaining):" << name() << remaining;
144 INVALID_CONFIGURATION("remaining screens")
148 Configurations::translateOrigin(layout
);
155 XMLConfigurations::XMLConfigurations(QObject
* parent
)
156 : BackendConfigurations(parent
),
157 m_activeConfiguration(0),
158 m_markedConfiguration(0),
160 m_currentOutputsKnown(false),
161 m_confirmTimer(new QTimer(this)),
163 m_awaitingConfirm(false)
165 QDir dir
= QDir::home();
167 m_configPath
= dir
.filePath("screen-configurations.xml");
169 m_externalConfiguration
= new ExternalConfiguration(this);
170 connect(m_externalConfiguration
, SIGNAL(activateExternal()), this, SLOT(activateExternal()));
172 connect(m_confirmTimer
, SIGNAL(timeout()), this, SLOT(confirmTimerTimeout()));
177 QMap
<QString
, Configuration
*> XMLConfigurations::configurations()
179 QMap
<QString
, Configuration
*> result
;
180 for (QMap
<QString
, XMLConfiguration
*>::const_iterator i
= m_configurations
.constBegin();
181 i
!= m_configurations
.constEnd(); ++i
) {
182 result
.insert(i
.key(), i
.value());
188 void XMLConfigurations::init()
193 m_configXml
= new ConfigurationsXML();
196 * Create default single layout
198 ConfigurationXML
* config
= new ConfigurationXML();
199 config
->setParent(m_configXml
);
200 m_configXml
->configurations().append(config
);
202 config
->setName("single");
203 config
->setModifiable(false);
205 ScreenXML
* screen
= new ScreenXML();
206 screen
->setParent(config
);
207 config
->screens().append(screen
);
210 screen
->setPrivacy(false);
214 * Create default extended-right layout
216 config
= new ConfigurationXML();
217 config
->setParent(m_configXml
);
218 m_configXml
->configurations().append(config
);
220 config
->setName("extended-right");
221 config
->setModifiable(false);
223 screen
= new ScreenXML();
224 screen
->setParent(config
);
225 config
->screens().append(screen
);
228 screen
->setPrivacy(false);
230 screen
= new ScreenXML();
231 screen
->setParent(config
);
232 config
->screens().append(screen
);
235 screen
->setPrivacy(false);
236 screen
->setRightOf(0);
240 * Create default extended-left layout
242 config
= new ConfigurationXML();
243 config
->setParent(m_configXml
);
244 m_configXml
->configurations().append(config
);
246 config
->setName("extended-left");
247 config
->setModifiable(false);
249 screen
= new ScreenXML();
250 screen
->setParent(config
);
251 config
->screens().append(screen
);
254 screen
->setPrivacy(false);
255 screen
->setRightOf(1);
257 screen
= new ScreenXML();
258 screen
->setParent(config
);
259 config
->screens().append(screen
);
262 screen
->setPrivacy(false);
266 * Create outputs section for single output
268 OutputsXML
* outputs
= new OutputsXML();
269 outputs
->setParent(m_configXml
);
270 m_configXml
->outputs().append(outputs
);
272 outputs
->setConfiguration("external");
274 OutputXML
* output
= new OutputXML();
275 output
->setParent(outputs
);
276 outputs
->outputs().append(output
);
278 output
->setName("*");
279 output
->setScreen(0);
280 output
->setVendor("*");
284 * Create outputs section for 2 screens
286 outputs
= new OutputsXML();
287 outputs
->setParent(m_configXml
);
288 m_configXml
->outputs().append(outputs
);
290 outputs
->setConfiguration("external");
292 output
= new OutputXML();
293 output
->setParent(outputs
);
294 outputs
->outputs().append(output
);
296 output
->setName("*");
297 output
->setScreen(0);
298 output
->setVendor("*");
300 output
= new OutputXML();
301 output
->setParent(outputs
);
302 outputs
->outputs().append(output
);
304 output
->setName("*");
305 output
->setScreen(1);
306 output
->setVendor("*");
310 * Save the default xml
315 QList
<ConfigurationXML
*> configs
= m_configXml
->configurations();
316 for (int i
= 0; i
< configs
.size(); i
++) {
317 ConfigurationXML
* config
= configs
[i
];
319 XMLConfiguration
* c
= new XMLConfiguration(this, config
);
320 m_configurations
.insert(config
->name(), c
);
321 connect(c
, SIGNAL(activate(XMLConfiguration
*)), this, SLOT(activate(XMLConfiguration
*)));
327 Configuration
* XMLConfigurations::findConfiguration()
329 qDebug() << "looking for a matching configuration...";
331 if (! m_currentOutputs
) {
334 qDebug() << "found outputs, known:" << m_currentOutputsKnown
;
336 if (m_currentOutputs
->configuration() == "external") {
337 return m_externalConfiguration
;
340 XMLConfiguration
* config
= m_configurations
[m_currentOutputs
->configuration()];
342 //qDebug() << "config" << m_currentOutputs->configuration() << "does not exist!!";
343 CONFIGURATION_NOT_FOUND(m_currentOutputs
->configuration())
350 void XMLConfigurations::findOutputs()
352 m_currentOutputsKnown
= true;
353 m_currentOutputs
= findKnownOutputs();
354 if (! m_currentOutputs
) {
355 m_currentOutputsKnown
= false;
356 m_currentOutputs
= findBestOutputs();
360 OutputsXML
* XMLConfigurations::findKnownOutputs()
362 QList
<Output
*> currentOutputs
= Outputs::self()->outputs();
364 foreach (Output
* output
, currentOutputs
) {
365 if (output
->isConnected()) {
370 foreach (OutputsXML
* knownOutputs
, m_configXml
->outputs()) {
371 if (knownOutputs
->outputs().size() != connected
) {
375 bool matchedAll
= true;
376 foreach (Output
* current
, currentOutputs
) {
377 if (! current
->isConnected()) {
381 bool matched
= false;
382 foreach (OutputXML
* known
, knownOutputs
->outputs()) {
383 if (known
->name() != current
->id()) {
387 if ((current
->vendor() == known
->vendor())
388 && (current
->productId() == known
->product())
389 && (current
->serialNumber() == known
->serial())) {
409 OutputsXML
* XMLConfigurations::findBestOutputs()
411 QList
<Output
*> currentOutputs
= Outputs::self()->outputs();
413 foreach (Output
* output
, currentOutputs
) {
414 if (output
->isConnected()) {
419 qDebug() << "connected:" << connected
;
421 qreal scoreAllMax
= 0.01;
422 OutputsXML
* knownAllMax
= 0;
423 foreach (OutputsXML
* knownOutputs
, m_configXml
->outputs()) {
424 if (knownOutputs
->outputs().size() != connected
) {
429 QSet
<OutputXML
*> knownTaken
;
430 foreach (Output
* current
, currentOutputs
) {
431 if (! current
->isConnected()) {
435 qDebug() << "looking for current" << current
->id();
437 qreal scoreMax
= 0.01;
438 OutputXML
* knownMax
= 0;
439 foreach (OutputXML
* known
, knownOutputs
->outputs()) {
440 if (knownTaken
.contains(known
)) {
445 score
*= match(known
->name(), current
->id());
446 score
*= match(known
->vendor(), current
->vendor());
447 score
*= match(known
->product(), current
->productId());
449 qDebug() << "known" << known
->name() << "has score:" << score
;
450 if (score
> scoreMax
) {
457 scoreAll
*= scoreMax
;
458 knownTaken
.insert(knownMax
);
459 knownMax
->setActualOutput(current
->id());
466 if (scoreAll
> scoreAllMax
) {
467 scoreAllMax
= scoreAll
;
468 knownAllMax
= knownOutputs
;
475 qreal
XMLConfigurations::match(QString known
, QString current
) {
476 if (known
== current
) {
478 } else if (known
== "*") {
485 qreal
XMLConfigurations::match(int known
, int current
) {
486 if (known
== current
) {
488 } else if (known
== -1) {
495 QList
<Configuration
*> XMLConfigurations::alternateConfigurations() {
496 QList
<Configuration
*> configs
;
497 foreach (XMLConfiguration
* config
, m_configurations
) {
498 if (config
->layout().size() <= m_currentOutputs
->outputs().size()) {
499 configs
.append(config
);
506 QList
<XMLConfiguration
*> XMLConfigurations::equivalentConfigurations(int numScreens
) {
507 qDebug() << "looking for equivalent configurations with" << numScreens
<< "screens";
509 QList
<XMLConfiguration
*> result
;
510 foreach (XMLConfiguration
* config
, m_configurations
) {
511 if ((! config
->isModifiable()) && (config
->layout().size() == numScreens
)) {
512 qDebug() << "found:" << config
->name();
513 result
.append(config
);
520 QList
<QPoint
> XMLConfigurations::possiblePositions(Output
* output
) {
521 QList
<QPoint
> result
;
523 if (! output
->isConnected()) {
527 if (! m_activeConfiguration
) {
528 qDebug() << "don't have an active configuration";
532 QMap
<XMLConfiguration
*, QPoint
> positions
;
533 if (! m_activeConfiguration
->isModifiable()) {
534 positions
= equivalentConfigurationsPositions(output
);
535 foreach (const QPoint
& point
, positions
) {
536 unique
.insert(point
);
539 positions
= simpleConfigurationsPositions(output
, true);
540 foreach (const QPoint
& point
, positions
) {
541 unique
.insert(point
);
544 positions
= sameConfigurationsPositions(output
, false);
545 foreach (const QPoint
& point
, positions
) {
546 unique
.insert(point
);
549 positions
= simpleConfigurationsPositions(output
, false);
550 foreach (const QPoint
& point
, positions
) {
551 unique
.insert(point
);
555 foreach (const QPoint
& p
, unique
) {
561 bool XMLConfigurations::move(Output
* output
, const QPoint
& position
) {
562 if ((! m_activeConfiguration
) || (! output
->isConnected())) {
565 if (position
== output
->position()) {
569 QMap
<XMLConfiguration
*, QPoint
> positions
;
570 if (! m_activeConfiguration
->isModifiable()) {
571 positions
= equivalentConfigurationsPositions(output
);
572 qDebug() << "equiv pos for:" << output
->id() << position
<< positions
;
573 for (QMap
<XMLConfiguration
*, QPoint
>::const_iterator i
= positions
.constBegin(); i
!= positions
.constEnd(); ++i
) {
574 if (i
.value() == position
) {
576 if (! activate(i
.key())) {
584 positions
= simpleConfigurationsPositions(output
, true);
585 foreach (const QPoint
& point
, positions
) {
587 FIX_ME("handle moving of output");
590 positions
= sameConfigurationsPositions(output
, false);
591 foreach (const QPoint
& point
, positions
) {
593 FIX_ME("handle moving of output");
596 positions
= simpleConfigurationsPositions(output
, false);
597 foreach (const QPoint
& point
, positions
) {
599 FIX_ME("handle moving of output");
606 QMap
<int, QRect
> XMLConfigurations::resizeLayout(Output
* output
, const QSize
& size
, QMap
<Output
*, int> & outputScreens
, QMap
<Output
*, QSize
> & outputSizes
) {
607 outputScreens
.unite(currentOutputScreens());
608 QMap
<int, QPoint
> simpleLayout
= m_activeConfiguration
->layout();
610 foreach (Output
* o
, outputScreens
.keys()) {
612 outputSizes
.insert(output
, size
);
613 } else if (o
->isActivated()) {
614 outputSizes
.insert(o
, o
->isActivated() ? o
->size() : o
->preferredSize());
618 return m_activeConfiguration
->realLayout(simpleLayout
, outputScreens
, outputSizes
);
621 bool XMLConfigurations::resize(Output
* output
, const QSize
& size
) {
622 qDebug() << "XMLConfigurations::resize() called" << output
->id() << size
;
623 if ((! m_activeConfiguration
) || (! output
->isConnected()) || (! output
->isActivated())) {
626 if (size
== output
->size()) {
630 QMap
<Output
*, QSize
> outputSizes
;
631 QMap
<Output
*, int> outputScreens
;
632 QMap
<int, QRect
> layout
= resizeLayout(output
, size
, outputScreens
, outputSizes
);
635 if (activateLayout(layout
, outputScreens
, outputSizes
)) {
636 OutputXML
* o
= outputXml(output
->id());
638 o
->setWidth(size
.width());
639 o
->setHeight(size
.height());
648 QMap
<XMLConfiguration
*, QMap
<int, QPoint
> > XMLConfigurations::matchingConfigurationsLayouts(const QMap
<int, QPoint
> & currentLayout
, int removedOutputs
) {
649 //qDebug() << "searching matching layouts for" << currentLayout;
650 QMap
<XMLConfiguration
*, QMap
<int, QPoint
> > result
;
651 QList
<XMLConfiguration
*> configurations
= equivalentConfigurations(currentLayout
.size() + removedOutputs
);
652 foreach (XMLConfiguration
* configuration
, configurations
) {
653 QMap
<int, QPoint
> layout
= configuration
->layout();
654 QMap
<int, int> match
= matchLayouts(currentLayout
, layout
);
655 if (! match
.empty()) {
656 result
.insert(configuration
, layout
);
663 QMap
<int, int> XMLConfigurations::matchLayouts(const QMap
<int, QPoint
> & currentLayout
, const QMap
<int, QPoint
> & layout
) {
664 QList
<int> indexes
= layout
.keys();
665 if (! currentLayout
.empty()) {
666 indexes
.insert(0, currentLayout
.keys()[0]);
669 QPoint origin
= currentLayout
.begin().value();
670 QMap
<int, int> result
;
671 foreach (int i
, indexes
) {
672 QMap
<int, QPoint
> l
= layout
;
673 translateOrigin(l
, l
[i
] - origin
);
674 for (QMap
<int, QPoint
>::const_iterator j
= currentLayout
.constBegin(); j
!= currentLayout
.constEnd(); ++j
) {
676 for (QMap
<int, QPoint
>::iterator k
= l
.begin(); k
!= l
.end(); ++k
) {
677 if (j
.value() == k
.value()) {
679 result
.insert(j
.key(), k
.key());
688 if (! result
.empty()) {
690 for (QMap
<int, QPoint
>::const_iterator k
= l
.constBegin(); k
!= l
.constEnd(); ++k
) {
691 result
.insert(j
, k
.key());
701 QMap
<int, QRect
> XMLConfigurations::calcMatchingLayout(const QMap
<int, QPoint
> & currentLayout
, XMLConfiguration
* configuration
, QMap
<int, QPoint
> layout
, Output
* output
, int * outputScreen
) {
702 QMap
<int, int> match
= matchLayouts(currentLayout
, layout
);
703 qDebug() << "match:" << match
;
704 QMap
<Output
*, int> outputs
;
705 Output
* add
= (match
.contains(-1) ? output
: 0);
706 Output
* remove
= (add
? 0 : output
);
707 foreach (Output
* o
, Outputs::self()->outputs()) {
708 Screen
* screen
= o
->screen();
709 if (remove
&& (remove
== o
)) {
710 outputs
.insert(o
, -1);
712 } else if (screen
&& match
.contains(screen
->id())) {
713 outputs
.insert(o
, match
[screen
->id()]);
714 } else if (add
&& (add
== o
)) {
715 outputs
.insert(o
, match
[-1]);
718 *outputScreen
= match
[-1];
723 QMap
<int, QRect
> realLayout
= configuration
->realLayout(layout
, outputs
);
724 translateToOther(realLayout
, output
, match
);
729 void XMLConfigurations::translateToOther(QMap
<int, QRect
> & layout
, Output
* output
, QMap
<int, int> match
) {
730 foreach (Output
* o
, Outputs::self()->outputs()) {
735 Screen
* screen
= o
->screen();
736 if (screen
&& (match
.empty() || match
.contains(screen
->id()))) {
737 QPoint offset
= layout
[match
.empty() ? screen
->id() : match
[screen
->id()]].topLeft() - o
->position();
738 translateOrigin(layout
, offset
);
744 QMap
<XMLConfiguration
*, QPoint
> XMLConfigurations::equivalentConfigurationsPositions(Output
* output
) {
746 if (! output
->isActivated()) {
749 foreach (Output
* o
, Outputs::self()->outputs()) {
753 if (o
->screen() == output
->screen()) {
760 QMap
<XMLConfiguration
*, QPoint
> positions
;
761 QMap
<int, QPoint
> currentLayout
= m_activeConfiguration
->layout();
762 QMap
<XMLConfiguration
*, QMap
<int, QPoint
> > layouts
;
763 QMap
<int, QPoint
> cloneLayout
;
764 XMLConfiguration
* cloneConfig
= 0;
766 currentLayout
.remove(output
->screen()->id());
767 translateOrigin(currentLayout
);
768 layouts
= matchingConfigurationsLayouts(currentLayout
, 0);
769 if (! layouts
.empty()) {
770 QMap
<XMLConfiguration
*, QMap
<int, QPoint
> >::const_iterator i
= layouts
.constBegin();
771 cloneLayout
= i
.value();
772 cloneConfig
= i
.key();
775 cloneLayout
= currentLayout
;
776 cloneConfig
= m_activeConfiguration
;
780 QMap
<int, QRect
> layout
= calcMatchingLayout(currentLayout
, cloneConfig
, cloneLayout
, output
);
781 foreach (const QRect
& geom
, layout
) {
782 positions
.insertMulti(cloneConfig
, geom
.topLeft());
786 qDebug() << "current layout:" << currentLayout
;
787 layouts
= matchingConfigurationsLayouts(currentLayout
, 1);
788 for (QMap
<XMLConfiguration
*, QMap
<int, QPoint
> >::const_iterator i
= layouts
.constBegin(); i
!= layouts
.constEnd(); ++i
) {
789 qDebug() << "matching layout:" << i
.key()->name() << i
.value();
790 int outputScreen
= -1;
791 QMap
<int, QRect
> layout
= calcMatchingLayout(currentLayout
, i
.key(), i
.value(), output
, & outputScreen
);
792 qDebug() << "results in:" << layout
;
793 if (layout
.contains(outputScreen
)) {
794 positions
.insertMulti(i
.key(), layout
[outputScreen
].topLeft());
798 for (QMap
<XMLConfiguration
*, QPoint
>::iterator i
= positions
.begin(); i
!= positions
.end();) {
799 QPoint pos
= i
.value();
800 for (QMap
<XMLConfiguration
*, QPoint
>::iterator j
= i
+ 1; j
!= positions
.end();) {
801 if (j
.value() == pos
) {
802 j
= positions
.erase(j
);
813 QMap
<XMLConfiguration
*, QPoint
> XMLConfigurations::simpleConfigurationsPositions(Output
* output
, bool sameCount
) {
814 Screen
* screen
= output
->screen();
816 if (! output
->isActivated()) {
820 foreach (Output
* o
, Outputs::self()->outputs()) {
821 if (o
->isActivated()) {
827 if (o
->screen() == screen
) {
834 return QMap
<XMLConfiguration
*, QPoint
>();
838 QMap
<XMLConfiguration
*, QPoint
> positions
;
839 QMap
<int, QPoint
> currentLayout
= m_activeConfiguration
->layout();
840 QMap
<XMLConfiguration
*, QMap
<int, QPoint
> > layouts
;
841 QMap
<int, QPoint
> cloneLayout
= currentLayout
;
842 XMLConfiguration
* cloneConfig
= 0;
843 QMap
<int, QPoint
> noCloneLayout
= currentLayout
;
844 XMLConfiguration
* noCloneConfig
= 0;
847 cloneLayout
= m_activeConfiguration
->cloneLayout(screen
->id());
848 cloneConfig
= simpleConfiguration(currentLayout
.size() - 1);
849 cloneConfig
->setLayout(cloneLayout
);
852 noCloneConfig
= simpleConfiguration(currentLayout
.size());
856 cloneConfig
= m_activeConfiguration
;
859 noCloneConfig
= simpleConfiguration(currentLayout
.size() + 1);
863 QMap
<int, QRect
> layout
= calcMatchingLayout(currentLayout
, cloneConfig
, cloneLayout
, output
);
864 foreach (const QRect
& geom
, layout
) {
865 positions
.insertMulti(cloneConfig
, geom
.topLeft());
870 noCloneConfig
->setLayout(noCloneLayout
);
873 while (noCloneLayout
.contains(screenId
)) {
877 screenId
= screen
->id();
879 QSet
<QPoint
> possible
= noCloneConfig
->possiblePositions(screenId
);
881 //qDebug() << "trying" << possible << "as" << screenId << "in layout" << noCloneConfig->name() << noCloneLayout;
883 QMap
<Output
*, int> outputIndexes
;
884 foreach (Output
* o
, Outputs::self()->outputs()) {
885 Screen
* s
= o
->screen();
886 outputIndexes
.insert(o
, (s
? s
->id() : -1));
888 outputIndexes
.insert(output
, screenId
);
890 foreach (const QPoint
& p
, possible
) {
891 noCloneLayout
.insert(screenId
, p
);
892 //qDebug() << "layout:" << noCloneLayout;
893 QMap
<int, QRect
> layout
= noCloneConfig
->realLayout(noCloneLayout
, outputIndexes
);
894 if (layout
.contains(screenId
)) {
895 translateToOther(layout
, output
);
896 //qDebug() << "results in:" << layout;
897 positions
.insertMulti(noCloneConfig
, layout
[screenId
].topLeft());
905 QMap
<XMLConfiguration
*, QPoint
> XMLConfigurations::sameConfigurationsPositions(Output
* output
, bool sameCount
) {
908 Screen
* screen
= output
->screen();
910 if (! output
->isActivated()) {
913 foreach (Output
* o
, Outputs::self()->outputs()) {
917 if (o
->screen() == screen
) {
924 QMap
<XMLConfiguration
*, QPoint
> positions
;
925 QMap
<int, QPoint
> currentLayout
= m_activeConfiguration
->layout();
926 QMap
<XMLConfiguration
*, QMap
<int, QPoint
> > layouts
;
927 int screenId
= (screen
? screen
->id() : currentLayout
.keys()[0]);
929 QSet
<QPoint
> possible
= (cloned
? m_activeConfiguration
->positions() : m_activeConfiguration
->possiblePositions(screenId
));
931 //qDebug() << "trying" << possible << "as" << screenId << "in layout" << m_activeConfiguration->name() << currentLayout;
933 QMap
<Output
*, int> outputIndexes
;
934 foreach (Output
* o
, Outputs::self()->outputs()) {
935 Screen
* s
= o
->screen();
936 outputIndexes
.insert(o
, (s
? s
->id() : -1));
938 outputIndexes
.insert(output
, screenId
);
940 foreach (const QPoint
& p
, possible
) {
941 currentLayout
.insert(screenId
, p
);
942 //qDebug() << "layout:" << currentLayout;
943 QMap
<int, QRect
> layout
= m_activeConfiguration
->realLayout(currentLayout
, outputIndexes
);
944 if (layout
.contains(screenId
)) {
945 translateToOther(layout
, output
);
946 //qDebug() << "results in:" << layout;
947 positions
.insertMulti(m_activeConfiguration
, layout
[screenId
].topLeft());
954 void XMLConfigurations::activateExternal() {
955 qDebug() << "activate external configuration!!";
956 m_activeConfiguration
= 0;
959 bool XMLConfigurations::activate(XMLConfiguration
* configuration
) {
960 qDebug() << "activate configuration:" << configuration
->name();
961 if (configuration
== m_activeConfiguration
) {
964 QMap
<int, QPoint
> layout
= configuration
->layout();
966 if (! m_currentOutputsKnown
) {
967 qDebug() << "saving xml for current outputs...";
969 OutputsXML
* known
= new OutputsXML();
970 known
->setParent(m_configXml
);
971 m_configXml
->outputs().append(known
);
973 known
->setConfiguration(configuration
->name());
975 QMap
<QString
, OutputXML
*> currentMap
;
976 foreach (OutputXML
* o
, m_currentOutputs
->outputs()) {
977 currentMap
.insert(o
->actualOutput(), o
);
980 QList
<Output
*> outputs
= Outputs::self()->outputs();
981 foreach (Output
* output
, outputs
) {
982 if (! output
->isConnected()) {
985 if (! currentMap
.contains(output
->id())) {
986 INVALID_CONFIGURATION("m_currentOutputs not up to date");
990 OutputXML
* outputXml
= new OutputXML();
991 outputXml
->setParent(known
);
992 known
->outputs().append(outputXml
);
994 outputXml
->setName(output
->id());
995 outputXml
->setScreen(currentMap
[output
->id()]->screen());
996 outputXml
->setVendor(output
->vendor());
997 outputXml
->setProduct(output
->productId());
998 outputXml
->setSerial(output
->serialNumber());
999 outputXml
->setWidth(output
->size().width());
1000 outputXml
->setHeight(output
->size().height());
1003 m_currentOutputs
= known
;
1004 m_currentOutputsKnown
= true;
1006 m_currentOutputs
->setConfiguration(configuration
->name());
1007 matchOutputScreens(layout
);
1009 if (! m_awaitingConfirm
) {
1013 QMap
<Output
*, int> outputScreens
= currentOutputScreens();
1014 QMap
<int, QRect
> screens
= configuration
->realLayout(layout
, outputScreens
);
1015 if (activateLayout(screens
, outputScreens
)) {
1016 m_activeConfiguration
= configuration
;
1017 emit
configurationActivated(configuration
);
1021 qDebug() << "failed to activate configuration:" << configuration
->name();
1025 void XMLConfigurations::matchOutputScreens(const QMap
<int, QPoint
> & layout
) {
1026 QMap
<QString
, int> outputScreens
;
1028 QSet
<int> unknownScreens
;
1029 QSet
<int> takenScreens
;
1030 QSet
<QString
> cloned
;
1031 foreach (int screen
, layout
.keys()) {
1035 if (screens
.size() > m_currentOutputs
->outputs().size()) {
1036 INVALID_CONFIGURATION("configuration and outputs don't match");
1039 foreach (OutputXML
* output
, m_currentOutputs
->outputs()) {
1040 if (output
->screen() >= 0) {
1041 if (screens
.contains(output
->screen())) {
1042 outputScreens
.insert(output
->name(), output
->screen());
1043 if (takenScreens
.contains(output
->screen())) {
1044 cloned
<< output
->name();
1046 takenScreens
<< output
->screen();
1048 unknownScreens
<< output
->screen();
1053 foreach (int taken
, outputScreens
) {
1054 screens
.remove(taken
);
1057 while (! (screens
.empty() || unknownScreens
.empty())) {
1058 int from
= * unknownScreens
.begin();
1059 unknownScreens
.remove(from
);
1060 int to
= * screens
.begin();
1063 foreach (OutputXML
* output
, m_currentOutputs
->outputs()) {
1064 if (output
->screen() == from
) {
1065 outputScreens
.insert(output
->name(), to
);
1070 while (! (screens
.empty() || cloned
.empty())) {
1071 QString o
= * cloned
.begin();
1073 int to
= * screens
.begin();
1075 outputScreens
.insert(o
, to
);
1078 foreach (OutputXML
* output
, m_currentOutputs
->outputs()) {
1079 if (outputScreens
.contains(output
->name())) {
1080 output
->setScreen(outputScreens
[output
->name()]);
1082 output
->setScreen(-1);
1087 QMap
<Output
*, int> XMLConfigurations::currentOutputScreens() {
1088 QMap
<Output
*, int> outputScreens
;
1089 foreach (Output
* output
, Outputs::self()->outputs()) {
1090 int screen
= this->screen(output
);
1092 outputScreens
.insert(output
, screen
);
1095 return outputScreens
;
1098 bool XMLConfigurations::activateLayout(const QMap
<int, QRect
> & screensLayout
, const QMap
<Output
*, int> & outputScreens
) {
1099 QMap
<Output
*, QSize
> outputSizes
;
1100 foreach (Output
* output
, outputScreens
.keys()) {
1101 outputSizes
.insert(output
, output
->isActivated() ? output
->size() : output
->preferredSize());
1103 return activateLayout(screensLayout
, outputScreens
, outputSizes
);
1106 bool XMLConfigurations::activateLayout(const QMap
<int, QRect
> & screensLayout
, const QMap
<Output
*, int> & outputScreens
, const QMap
<Output
*, QSize
> & outputSizes
) {
1107 if (screensLayout
.empty()) {
1108 INVALID_CONFIGURATION("layout is empty");
1112 if (! BackendOutputs::self()) {
1116 QMap
<Output
*, QRect
> layout
;
1117 for (QMap
<int, QRect
>::const_iterator i
= screensLayout
.constBegin(); i
!= screensLayout
.constEnd(); ++i
) {
1118 for (QMap
<Output
*, int>::const_iterator j
= outputScreens
.constBegin(); j
!= outputScreens
.constEnd(); ++j
) {
1119 if (j
.value() == i
.key()) {
1120 layout
.insert(j
.key(), QRect(i
.value().topLeft(), outputSizes
[j
.key()]));
1125 qDebug() << "layout:" << layout
;
1126 if (! m_awaitingConfirm
) {
1127 foreach (BackendOutput
* o
, BackendOutputs::self()->backendOutputs()) {
1132 if (! BackendOutputs::self()->activateLayout(layout
)) {
1133 if (! m_awaitingConfirm
) {
1134 foreach (BackendOutput
* o
, BackendOutputs::self()->backendOutputs()) {
1144 Configuration
* XMLConfigurations::activeConfiguration() {
1145 return m_activeConfiguration
? (Configuration
*) m_activeConfiguration
: (Configuration
*) m_externalConfiguration
;
1148 XMLConfiguration
* XMLConfigurations::simpleConfiguration(int numScreens
) {
1149 QString name
= "simple-" + QString::number(numScreens
);
1150 if (m_configurations
.contains(name
)) {
1151 return m_configurations
[name
];
1154 ConfigurationXML
* config
= new ConfigurationXML();
1155 config
->setParent(m_configXml
);
1156 m_configXml
->configurations().append(config
);
1158 config
->setName(name
);
1159 config
->setModifiable(true);
1161 for (int i
= 0; i
< numScreens
; ++i
) {
1162 ScreenXML
* screen
= new ScreenXML();
1163 screen
->setParent(config
);
1164 config
->screens().append(screen
);
1167 screen
->setPrivacy(false);
1168 screen
->setRightOf(i
- 1);
1173 m_configurations
.insert(name
, new XMLConfiguration(this, config
));
1174 return m_configurations
[name
];
1177 void XMLConfigurations::saveXml() {
1178 qDebug() << "save xml";
1179 ConfigurationsXMLFactory
* factory
= new ConfigurationsXMLFactory();
1180 factory
->save(m_configXml
, m_configPath
);
1184 void XMLConfigurations::loadXml() {
1185 qDebug() << "load xml";
1186 ConfigurationsXMLFactory
* factory
= new ConfigurationsXMLFactory();
1187 m_configXml
= (ConfigurationsXML
*) factory
->load(m_configPath
);
1191 int XMLConfigurations::screen(Output
* output
) {
1192 foreach (OutputXML
* o
, m_currentOutputs
->outputs()) {
1193 if (output
->id() == o
->name()) {
1200 void XMLConfigurations::applyOutputSettings() {
1201 if (! BackendOutputs::self()) {
1206 if (! m_currentOutputs
) {
1210 foreach (OutputXML
* o
, m_currentOutputs
->outputs()) {
1211 BackendOutput
* output
= BackendOutputs::self()->backendOutput(o
->name());
1213 bool failed
= false;
1216 Rotation rotation
= (Rotation
) o
->rotation();
1217 bool reflectX
= o
->reflectX();
1218 bool reflectY
= o
->reflectY();
1219 if ((rotation
!= output
->rotation()) || (reflectX
!= output
->reflectX()) || (reflectY
!= output
->reflectY())) {
1220 qDebug() << "applying orientation to" << output
->id() << rotation
<< reflectX
<< reflectY
;
1221 if (! output
->applyOrientation(rotation
, reflectX
, reflectY
)) {
1222 OPERATION_FAILED("apply orientation")
1227 QSize
size(o
->width(), o
->height());
1228 float rate
= o
->rate();
1229 if ((! failed
) && (! size
.isEmpty()) && ((size
!= output
->size()) || ((rate
> 1) && (! qFuzzyCompare(rate
, output
->rate()))))) {
1230 qDebug() << "applying geom to" << output
->id() << size
<< rate
;
1231 if (! output
->applyGeom(QRect(output
->position(), size
), rate
)) {
1232 OPERATION_FAILED("apply geometry")
1238 qDebug() << "reverting output" << output
->id();
1245 OutputXML
* XMLConfigurations::outputXml(const QString
& id
) {
1246 foreach (OutputXML
* o
, m_currentOutputs
->outputs()) {
1247 if (o
->name() == id
) {
1254 bool XMLConfigurations::rotate(Output
* output
, Rotation rotation
) {
1255 if (! BackendOutputs::self()) {
1259 if (! m_activeConfiguration
) {
1263 BackendOutput
* o
= BackendOutputs::self()->backendOutput(output
->id());
1265 bool resizeNeeded
= ((output
->rotation() + rotation
) % 180) != 0;
1267 qDebug() << "resize is needed for changing rotation from" << output
->rotation() << "to" << rotation
;
1269 QSize
size(output
->size().height(), output
->size().width());
1271 QMap
<Output
*, QSize
> outputSizes
;
1272 QMap
<Output
*, int> outputScreens
;
1273 QMap
<int, QRect
> layout
= resizeLayout(output
, size
, outputScreens
, outputSizes
);
1275 if (layout
.empty()) {
1276 INVALID_CONFIGURATION("layout is empty")
1281 if (o
->applyOrientation(rotation
, o
->reflectX(), o
->reflectY()) && activateLayout(layout
, outputScreens
, outputSizes
)) {
1282 OutputXML
* xml
= outputXml(output
->id());
1284 xml
->setWidth(size
.width());
1285 xml
->setHeight(size
.height());
1286 xml
->setRotation(rotation
);
1292 qDebug() << "setting rotation to" << rotation
<< "for" << o
->id() << "failed";
1299 if (o
->applyOrientation(rotation
, o
->reflectX(), o
->reflectY())) {
1300 OutputXML
* xml
= outputXml(o
->id());
1302 xml
->setRotation(rotation
);
1308 qDebug() << "setting rotation to" << rotation
<< "for" << o
->id() << "failed";
1319 bool XMLConfigurations::reflectX(Output
* output
, bool reflect
) {
1320 if (! BackendOutputs::self()) {
1324 BackendOutput
* o
= BackendOutputs::self()->backendOutput(output
->id());
1327 if (o
->applyOrientation(o
->rotation(), reflect
, o
->reflectY())) {
1328 OutputXML
* xml
= outputXml(o
->id());
1330 xml
->setReflectX(reflect
);
1335 qDebug() << "setting reflect-x to" << reflect
<< "for" << o
->id() << "failed";
1343 bool XMLConfigurations::reflectY(Output
* output
, bool reflect
) {
1344 if (! BackendOutputs::self()) {
1348 BackendOutput
* o
= BackendOutputs::self()->backendOutput(output
->id());
1351 if (o
->applyOrientation(o
->rotation(), o
->reflectX(), reflect
)) {
1352 OutputXML
* xml
= outputXml(o
->id());
1354 xml
->setReflectY(reflect
);
1359 qDebug() << "setting reflect-y to" << reflect
<< "for" << o
->id() << "failed";
1367 bool XMLConfigurations::changeRate(Output
* output
, float rate
) {
1368 if (! BackendOutputs::self()) {
1372 BackendOutput
* o
= BackendOutputs::self()->backendOutput(output
->id());
1375 if (o
->applyGeom(o
->geom(), rate
)) {
1376 OutputXML
* xml
= outputXml(o
->id());
1383 qDebug() << "setting rate to" << rate
<< "for" << o
->id() << "failed";
1391 void XMLConfigurations::setPolling(bool polling
) {
1392 if (polling
!= this->polling()) {
1393 m_configXml
->setPolling(polling
);
1396 emit
pollingActivated();
1398 emit
pollingDeactivated();
1403 bool XMLConfigurations::polling() {
1404 return m_configXml
->polling();
1407 void XMLConfigurations::confirmTimerTimeout() {
1409 if (m_confirmLeft
<= 0) {
1412 emit
confirmTimeout(m_confirmLeft
);
1416 void XMLConfigurations::confirm() {
1417 m_confirmTimer
->stop();
1418 m_awaitingConfirm
= false;
1423 void XMLConfigurations::revert() {
1424 m_confirmTimer
->stop();
1425 if (! m_awaitingConfirm
) {
1429 m_awaitingConfirm
= false;
1431 m_activeConfiguration
= m_markedConfiguration
;
1432 if (BackendOutputs::self()) {
1433 foreach (BackendOutput
* o
, BackendOutputs::self()->backendOutputs()) {
1439 if (m_activeConfiguration
) {
1440 emit
configurationActivated(m_activeConfiguration
);
1446 void XMLConfigurations::requireConfirm() {
1447 if (! BackendOutputs::self()) {
1451 m_confirmLeft
= CONFIRMATION_TIME
;
1452 if (! m_awaitingConfirm
) {
1453 m_awaitingConfirm
= true;
1454 m_confirmTimer
->start(1000);
1456 foreach (BackendOutput
* o
, BackendOutputs::self()->backendOutputs()) {
1459 m_markedConfiguration
= m_activeConfiguration
;
1462 emit
confirmTimeout(m_confirmLeft
);