summaryrefslogtreecommitdiffstats
path: root/src/widget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widget.cpp')
-rw-r--r--src/widget.cpp321
1 files changed, 250 insertions, 71 deletions
diff --git a/src/widget.cpp b/src/widget.cpp
index 994f3d1..d2a6765 100644
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -1,98 +1,277 @@
#include "widget.h"
#include "ui_widget.h"
+#include "config.h"
#include <QString>
#include <QSet>
#include <algorithm>
+#include <iostream>
+//___________________________________________________________________________
+int compareModeString (const QString & a, const QString & b) {
+ if (a.size() == b.size())
+ return a.compare(b);
+ else
+ if (a.size() > b.size())
+ return -1;
+ else
+ return 1;
+}
+//___________________________________________________________________________
Widget::Widget(QWidget *parent) :
QWidget(parent),
- ui(new Ui::Widget)
+ _ui(new Ui::Widget)
{
- ui->setupUi(this);
-
- X::OutputList outputs = X::Screen::inst()->getConnectedOutputList();
-
- switch ( X::Screen::inst()->getConnectedOutputList().size() ){
- /*************************************************************************/
- case 1:// In case of one connected output - xrandr --auto
- qDebug() << "Normal output";
- exit(0);
- break;
- /*************************************************************************/
- case 2: // In case of two connected outputs
-
- // If one of the two connected outputs is a beamer
- if (true)
- //X::Screen::inst()->getOutputMap()[outputs[0]]->isProjector()
- // || X::Screen::inst()->getOutputMap()[outputs[1]]->isProjector() )
- {
- qDebug() << "Cloned output";
- /*****************************************************************/
- // If the beamer transmits no reliable EDID data add modes
- if ( ! ( X::Screen::inst()->getOutputMap()[outputs[0]]->hasReliableEDID()
- && X::Screen::inst()->getOutputMap()[outputs[1]]->hasReliableEDID() ) )
- {
- // TODO ADD MODES
- qDebug() << "Normal output";
- }
+ _ui->setupUi(this);
- // Get a set of unique modes as string. Ugly but same resolutions may
- // have different ids. This means modes are compared by name which is
- X::ModeSet ModeSet1 = X::Screen::inst()->getOutputMap()[outputs[0]]->getModeSet();
- X::ModeSet ModeSet2 = X::Screen::inst()->getOutputMap()[outputs[1]]->getModeSet();
- QSet<QString> ModeNames1, ModeNames2;
- for (X::ModeSet::iterator i = ModeSet1.begin();
- i != ModeSet1.end(); ++i)
- ModeNames1.insert(X::Screen::inst()->getModeMap()[*i]._name);
- for (X::ModeSet::iterator i = ModeSet2.begin();
- i != ModeSet2.end(); ++i)
- ModeNames2.insert(X::Screen::inst()->getModeMap()[*i]._name);
- ModeNames1.intersect(ModeNames2);
-
- // Fill widget with data
- for ( QSet<QString>::iterator i = ModeNames1.begin(); i != ModeNames1.end(); ++i )
- ui->comboBox->addItem(*i);
- }
- /*********************************************************************/
- // If NEITHER of the outputs is a beamer (likely dualscreen setup)
- else
- {
- // TODO(manuel): Furture feature. Setup dualscreen
- qDebug() << "Dual output";
+ // Get initial data (to be freed)
+ _display = XOpenDisplay(NULL);
+ _screenResources = XRRGetScreenResourcesCurrent(_display, DefaultRootWindow(_display));
+
+ // Get the information about the X elements
+ updateScreenResources();
+
+ switch ( _connectedOutputList.size() ){
+ /*************************************************************************/
+ case 1:// In case of one connected output - xrandr --auto
+ qDebug() << "Normal output";
exit(0);
- }
- break;
- /*************************************************************************/
- default:
- // If there are more than 3 outputs
- // its up to the user. Quit.
- qDebug() << ">2 outputs. Quit.";
- exit(0);
- break;
- }
- /*************************************************************************/
+ break;
+ /*************************************************************************/
+ case 2: // In case of two connected outputs
+ // Check if one of the connected outputs is a beamer. This program only
+ // adresses cases in which eiter of the outouts is a beamer. Meaning
+ // either output one has dimension zero or output tow has no dimension.
+ // The case of two beamers is not covered.
+ if (/*true*/((_outputMap[_connectedOutputList[0]]->mm_width == 0
+ && _outputMap[_connectedOutputList[0]]->mm_height == 0 )
+ && ! (_outputMap[_connectedOutputList[1]]->mm_width == 0
+ && _outputMap[_connectedOutputList[1]]->mm_height == 0 ))
+ || ( ! (_outputMap[_connectedOutputList[0]]->mm_width == 0
+ && _outputMap[_connectedOutputList[0]]->mm_height == 0 )
+ && (_outputMap[_connectedOutputList[1]]->mm_width == 0
+ && _outputMap[_connectedOutputList[1]]->mm_height == 0 ))) {
+ std::cout << "BEAMER CONNECTED!" << std::endl;
+ // Get a human readable reference
+ if (_outputMap[_connectedOutputList[0]]->mm_width == 0
+ && _outputMap[_connectedOutputList[0]]->mm_height == 0 ) {
+ _beamer = _connectedOutputList[0];
+ _monitor = _connectedOutputList[1];
+ } else {
+ _beamer = _connectedOutputList[1];
+ _monitor = _connectedOutputList[0];
+ }
+ // Check if the beamer transmitted reliable data.
+ bool gotEDID = false;
+ int nprop;
+ Atom *props = XRRListOutputProperties(_display, _beamer, &nprop);
+ for (int i = 0; i < nprop; ++i) {
+ char *atom_name = XGetAtomName (_display, props[i]);
+ if ( strcmp (atom_name, "EDID") == 0) {
+ gotEDID = true;
+ break;
+ }
+ }
+ free(props);
+ // // TO BE DONE VIA BASH
+// // Iterate over the modes in the config file
+// for (QList<QString>::const_iterator it =
+// Config::inst()->getModeLines().begin();
+// it != Config::inst()->getModeLines().end(); ++it) {
+// // Add mode to xrandr
+// QProcess p;
+// QStringList arguments;
+// arguments << "--current" << "--newmode"
+// << it->split(" ", QString::SkipEmptyParts);
+// p.start("xrandr", arguments);
+// p.waitForFinished();
+// }
+ // Get the names of the modes and intersect
+ QSet<XRRModeInfo*> beamerModes, monitorModes;
+ for (int i = 0; i < _outputMap[_beamer]->nmode; ++i)
+ beamerModes.insert(_modeMap[_outputMap[_beamer]->modes[i]]);
+ for (int i = 0; i < _outputMap[_beamer]->nmode; ++i)
+ monitorModes.insert(_modeMap[_outputMap[_monitor]->modes[i]]);
- // Remove borders and stuff COMMENT FOR DEBUIGGIN
- //setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
+ // Intersect them by the resolution sorted
+ // dont care about O(n³)
+ QList<XRRModeInfo*> commonModes;
+ for (QSet<XRRModeInfo*>::iterator i = beamerModes.begin();
+ i != beamerModes.end(); ++i) {
+ for (QSet<XRRModeInfo*>::iterator j = monitorModes.begin();
+ j != monitorModes.end(); ++j) {
+ QList<XRRModeInfo*>::iterator k = commonModes.begin();
+ for (;;) {
+ if (k == commonModes.end()){
+ commonModes.insert(k, *i);
+ break;
+ }
+ if ( (*i)->width == (*k)->width ) {
+ if ( (*i)->height == (*k)->height )
+ break;
+ if ( (*i)->height > (*k)->height ) {
+ commonModes.insert(k, *i);
+ break;
+ }
+ }
+ if ( (*i)->width > (*k)->width ) {
+ commonModes.insert(k, *i);
+ break;
+ }
+ ++k;
+ }
+ }
+ }
- // Resize widget to its content
- resize(sizeHint());
+ // If the beamer transmits no reliable EDID data add modes
+ if (gotEDID) {
+ std::cout << "GOT EDID!" << std::endl;
+ // Extract the preferred mode of the beamer
+ RRMode preferredBeamerModeId;
+ for (int i = 0; i < _outputMap[_beamer]->nmode; ++i) {
+ if (i < _outputMap[_beamer]->npreferred) {
+ preferredBeamerModeId = _outputMap[_beamer]->modes[i];
+ break;
+ }
+ }
- // Center dialog on screenbottom
- const QRect desktopRect = QApplication::desktop()->screenGeometry();
- this->move( desktopRect.width()/2-this->width()/2,
- desktopRect.height()-this->height());
+ // Compute the aspect ratio of the beamer
+ float aspectRatio = (float)_modeMap[preferredBeamerModeId]->width
+ / _modeMap[preferredBeamerModeId]->height;
+
+ // Fill widget with data
+ for ( QList<XRRModeInfo*>::iterator i = commonModes.begin();
+ i != commonModes.end(); ++i ) {
+ float modeAspectRatio = ((float)(*i)->width / (*i)->height);
+ if ( modeAspectRatio == aspectRatio ) // TODO APPROX
+ _ui->comboBox->addItem((*i)->name);
+ }
+
+// // TO BE DONE VIA BASH
+// // Iterate over all modes and add them to the outputs,
+// // if the AR matches.
+// for(ModeMap::iterator it = _modeMap.begin();
+// it != _modeMap.end(); ++it) {
+// float MODEAR = ((float)(*it)->width / (*it)->height);
+// if ( MODEAR == AR ) {
+// XRRAddOutputMode(_display, _beamer, (*it)->id);
+// XRRAddOutputMode(_display, _monitor, (*it)->id);
+// }
+// }
+ } else {
+ std::cout << "NO EDID!" << std::endl;
+ // Fill widget with data without AR match
+ // Fill widget with data
+ for ( QList<XRRModeInfo*>::iterator i = commonModes.begin();
+ i != commonModes.end(); ++i ) {
+ _ui->comboBox->addItem((*i)->name);
+ }
+ // TO BE DONE VIA BASH
+// // Iterate over all modes and add them to the outputs
+// for(ModeMap::iterator it = _modeMap.begin();
+// it != _modeMap.end(); ++it) {
+// XRRAddOutputMode(_display, _beamer, (*it)->id);
+// XRRAddOutputMode(_display, _monitor, (*it)->id);
+// }
+ }
+
+ // Remove borders and stuff COMMENT FOR DEBUIGGIN
+ setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
+
+ // Resize widget to its content
+ resize(sizeHint());
+
+ // Center dialog on screenbottom
+ const QRect desktopRect = QApplication::desktop()->screenGeometry();
+ this->move( desktopRect.width()/2-this->width()/2,
+ desktopRect.height()-this->height());
+
+
+ } // End of the beamer section
+ /*********************************************************************/
+ // If NEITHER of the outputs is a beamer (likely dualscreen setup)
+ else {
+ // TODO(manuel): Furture feature. Setup dualscreen
+ qDebug() << "Dual output";
+ exit(0);
+ }
+ break;
+ /*************************************************************************/
+ default:
+ // If there are more than 3 outputs
+ // its up to the user. Quit.
+ qDebug() << ">2 outputs. Quit.";
+ exit(0);
+ break;
+ }
+ /*************************************************************************/
+}
+
+//___________________________________________________________________________
+void Widget::updateScreenResources()
+{
+ // Clear the modemap (nothing to be freed, stored in screenResources)
+ _modeMap.clear();
+
+ // Create the modemap
+ for (int i = 0; i < _screenResources->nmode; ++i) {
+ _modeMap.insert(
+ _screenResources->modes[i].id,
+ &_screenResources->modes[i]);
+ }
+
+ // Clear the crtmap
+ for (CrtcMap::iterator it = _crtcMap.begin();
+ it != _crtcMap.end();) {
+ XRRFreeCrtcInfo(*it);
+ it = _crtcMap.erase(it);
+ }
+
+ // Create crtcMap
+ for (int i = 0; i < _screenResources->ncrtc; ++i) {
+ XRRCrtcInfo * info = XRRGetCrtcInfo(
+ _display,
+ _screenResources,
+ _screenResources->crtcs[i]);
+ _crtcMap.insert(
+ _screenResources->crtcs[i],
+ info);
+ }
+
+ // Clear the outputmap
+ for (OutputMap::iterator it = _outputMap.begin();
+ it != _outputMap.end();) {
+ XRRFreeOutputInfo(*it);
+ it = _outputMap.erase(it);
+ }
+
+ // Create outputmap and connectedOutputMap
+ for (int i = 0; i < _screenResources->noutput; ++i) {
+ XRROutputInfo* info = XRRGetOutputInfo(
+ _display,
+ _screenResources,
+ _screenResources->outputs[i]);
+ _outputMap.insert(
+ _screenResources->outputs[i],
+ info);
+
+ // Store the connected ones separate
+ if ( info->connection == RR_Connected )
+ _connectedOutputList.push_back(_screenResources->outputs[i]);
+ }
}
+//___________________________________________________________________________
Widget::~Widget()
{
- delete ui;
+ delete _ui;
+ XCloseDisplay(_display);
+ XRRFreeScreenResources(_screenResources);
}