summaryrefslogblamecommitdiffstats
path: root/src/widget.cpp
blob: 4254530e0e1d80bf8e1d296591ac441fe363c757 (plain) (tree)
1
2
3
4
5
6
7
8
9

                      
                   
 

                  
                    
                   
 






                                              
 
                                                                             

                                 
                       
 
                     
 










                                                                                         
              


                                                                               
 



                                                                             
                                                                    





                                                                    
                                                                         
                                                      
 







                                                                       
 
         
 











                                                                         
 












                                                                  
 





                                                                        
 




























                                                                     
 
                                                                  
                               








                                                                    
 


















































                                                                            


                                                                                


















                                                                               





 





















































                                                                             
 
 
                                                                             

                 


                                           
 














































































                                                                                               
#include "widget.h"
#include "ui_widget.h"
#include "config.h"

#include <QString>
#include <QSet>
#include <algorithm>
#include <iostream>

//void setRefreshSpeed::on_okButton_clicked()
//{
//    QApplication::beep();
//    MainWindow::freq = ui->spinBox->value();
//    ui->setupUi(this);
//    setRefreshSpeed::close();
//}

//___________________________________________________________________________
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    _ui(new Ui::Widget)
{
  _ui->setupUi(this);

  // 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;
    /*************************************************************************/
    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]]);

        // 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;
            }
          }
        }

        // If the beamer transmits no reliable EDID data add modes
        if (false/*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;
            }
          }

          // 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());

        // Connect button signal to appropriate slot
        connect(_ui->pushButton, SIGNAL(clicked()), this, SLOT(handleButton()));


      } // 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;
  XCloseDisplay(_display);
  XRRFreeScreenResources(_screenResources);
}

void Widget::handleButton()
{

//  QProcess p;
//  QStringList arguments;
//  arguments << "--output" << _outputMap[_monitor]->name
//            << "--mode" << _ui->comboBox->currentText()
//            << "--output" << _outputMap[_beamer]->name
//            << "--mode" << _ui->comboBox->currentText()
//            << "--same-as" <<_outputMap[_monitor]->name;

//  p.start("xrandr", arguments);
//  p.waitForFinished();

  XGrabServer(_display);

  // First get a useful representation
  unsigned int width, height;
  QStringList modeAsStrings = _ui->comboBox->currentText().split("x", QString::SkipEmptyParts);
  width = modeAsStrings.at(0).toInt();
  height = modeAsStrings.at(1).toInt();

  // Find a mode that matches the string
  RRMode m1,m2;
  for (int i = 0; i < _outputMap[_monitor]->nmode; ++i){
    if ( width == _modeMap[_outputMap[_monitor]->modes[i]]->width
         && height == _modeMap[_outputMap[_monitor]->modes[i]]->height )
      m1 = _modeMap[_outputMap[_monitor]->modes[i]]->id;
  }
  for (int i = 0; i < _outputMap[_beamer]->nmode; ++i){
    if ( width == _modeMap[_outputMap[_beamer]->modes[i]]->width
         && height == _modeMap[_outputMap[_beamer]->modes[i]]->height )
      m2 = _modeMap[_outputMap[_beamer]->modes[i]]->id;
  }

  qDebug()  << _modeMap[m1]->width << _modeMap[m1]->height;
  qDebug()  << _modeMap[m2]->width << _modeMap[m2]->height;



  /* values from xrandr */
  float dpi = (25.4 * DisplayHeight(_display, 0)) / DisplayHeightMM(_display, 0);
  int widthMM =  (int) ((25.4 * width) / dpi);
  int heightMM = (int) ((25.4 * height) / dpi);

  // Set screensize
  XRRSetScreenSize(_display, DefaultRootWindow(_display),
                 width, height,
                 widthMM, heightMM);

  // Apply the modes
  XRRSetCrtcConfig(_display,
                   _screenResources,
                   _outputMap[_monitor]->crtc,
                   CurrentTime,
                   0, 0,
                   m1,
                   RR_Rotate_0,
                   &_monitor,
                   1);

  XRRSetCrtcConfig(_display,
                   _screenResources,
                   _outputMap[_beamer]->crtc,
                   CurrentTime,
                   0, 0,
                   m2,
                   RR_Rotate_0,
                   &_beamer,
                   1);


  XUngrabServer(_display);

  // Center dialog on screenbottom
  this->move( width/2  - this->width()/2,
              height - this->height());
}