From 491fda343c43fa761acd01dca1dab044284aaf5c Mon Sep 17 00:00:00 2001 From: Manuel Schneider Date: Wed, 27 Nov 2013 20:53:54 +0100 Subject: [Experimental] Finally list is sorted --- src/widget.cpp | 321 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 250 insertions(+), 71 deletions(-) (limited to 'src/widget.cpp') 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 #include #include +#include +//___________________________________________________________________________ +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 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::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::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 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 commonModes; + for (QSet::iterator i = beamerModes.begin(); + i != beamerModes.end(); ++i) { + for (QSet::iterator j = monitorModes.begin(); + j != monitorModes.end(); ++j) { + QList::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::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::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); } -- cgit v1.2.3-55-g7522