diff options
Diffstat (limited to 'src/widget.cpp')
-rw-r--r-- | src/widget.cpp | 588 |
1 files changed, 156 insertions, 432 deletions
diff --git a/src/widget.cpp b/src/widget.cpp index bef88db..751c69d 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1,383 +1,126 @@ -// Copyright 2013, University of Freiburg, -// Author: Manuel Schneider <ms1144> - -#include <iostream> -#include <algorithm> - -#include <QDebug> -#include <QtWidgets/QAction> - #include "widget.h" #include "ui_widget.h" #include "timeoutdialog.h" -#include "math.h" +#include "x.h" +#include "main.h" + +#include <QDebug> +#include <QtWidgets/QAction> //______________________________________________________________________________ -Widget::Widget(bool testMode, QWidget *parent) : - QWidget(parent), - _ui(new Ui::Widget) +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(); - - if (testMode) { - while (_connectedOutputList.size() > 2) { - _connectedOutputList.pop_front(); - } - } - - switch ( _connectedOutputList.size() ){ - /*************************************************************************/ - case 1:// In case of one connected output - xrandr --auto - qDebug() << "One connected output"; - exit(0); - break; - case 2: // In case of two connected outputs - - qDebug() << "Two connected outputs"; - - // Check if we are in clone mode - if (testMode || cloneMode()) { - - qDebug() << "Dual output with cloned screen!"; - - // TODO make that mess nice and clean - double_t w0 = _outputMap[_connectedOutputList[0]]->mm_width; - double_t h0 = _outputMap[_connectedOutputList[0]]->mm_height; - - double_t w1 = _outputMap[_connectedOutputList[1]]->mm_width; - double_t h1 = _outputMap[_connectedOutputList[1]]->mm_height; - - // Get a human readable reference - if (w0 == 0 && h0 == 0) { - _beamer = _connectedOutputList[0]; - _monitor = _connectedOutputList[1]; - } else if (w1 == 0 && h1 == 0) { - _beamer = _connectedOutputList[1]; - _monitor = _connectedOutputList[0]; - } else { - double_t d0 = sqrt((pow(w0, 2) + pow(h0, 2))); - double_t d1 = sqrt((pow(w1, 2) + pow(h1, 2))); - - if (d0 > d1) { - _beamer = _connectedOutputList[0]; - _monitor = _connectedOutputList[1]; - } else { - _beamer = _connectedOutputList[1]; - _monitor = _connectedOutputList[0]; - } - } - - // Intersect them by the resolution sorted, dont care about O(n³) - QList<QPair<XRRModeInfo*, XRRModeInfo*> > commonModes; - - // Iterate over the modes the monitor supports - for (int i = 0; i < _outputMap[_monitor]->nmode; ++i) { - - XRRModeInfo* monitorMode = _modeMap[_outputMap[_monitor]->modes[i]]; - - // Skip interlace modes - if ( monitorMode->modeFlags & RR_Interlace ) - continue; - - // Iterate over the modes the beamer supports - for (int j = 0; j < _outputMap[_beamer]->nmode; ++j) { - - XRRModeInfo* beamerMode = _modeMap[_outputMap[_beamer]->modes[j]]; - - // Skip interlace modes - if ( beamerMode->modeFlags & RR_Interlace ) - continue; - - // Only if the modes have the same size, list them in common modes - if ( monitorMode->height == beamerMode->height - && monitorMode->width == beamerMode->width ) { - - // Build a sorted list of common modes in descending order - QList<QPair<XRRModeInfo*, XRRModeInfo*> >::iterator k - = commonModes.begin(); - for (;;++k) { - - // If at the end, the mode to insert is the smallest, insert. - // This has to be first to avoid segfaults - if (k == commonModes.end()) { - - commonModes.insert(k, qMakePair (monitorMode, beamerMode)); - break; - } - - // If the mode to insert is larger than k, insert. - if ( monitorMode->width > k->first->width) { - commonModes.insert(k, qMakePair (monitorMode, beamerMode)); - break; - } - - // If the width is the same ... - if ( monitorMode->width == k->first->width ) { - - // ... and the height is the same, the mode already exists - if ( monitorMode->height == k->first->height ) { - break; - } - - // ... and the height is larger, insert. - if ( monitorMode->height > k->first->height ) { - commonModes.insert(k, qMakePair (monitorMode, beamerMode)); - break; - } - } - } - } - } - } - - - // 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; - XFree (atom_name); - break; - } - XFree (atom_name); - } - free(props); - - // If the beamer transmits no reliable EDID data add modes -#ifdef QT_DEBUG - gotEDID = false; -#endif - if (gotEDID) { - - qDebug() << "GOT EDID!"; - - // Extract the preferred mode of the beamer - RRMode preferredBeamerModeId = 0; - 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<QPair<XRRModeInfo*, XRRModeInfo*> >::iterator i - = commonModes.begin(); i != commonModes.end(); ++i ) { - float modeAspectRatio = ((float)i->first->width / i->first->height); - if ( abs(modeAspectRatio - aspectRatio) < 0.05 ) // APPROX - _ui->comboBox->addItem(i->first->name, - QList<QVariant>() - << QVariant((qulonglong)i->first->id) - << QVariant((qulonglong)i->second->id)); - } - } else { - - qDebug() << "NO EDID!"; - - // Fill widget with data without AR match - // Fill widget with data - for ( QList<QPair<XRRModeInfo*, XRRModeInfo*> >::iterator i - = commonModes.begin(); i != commonModes.end(); ++i ) { - qDebug() << "Insert into QComboBox" - << i->first->width << "x" << i->first->height - << "(" << i->first->id << ")"; - _ui->comboBox->addItem(i->first->name, - QList<QVariant>() - << QVariant((qulonglong)i->first->id) - << QVariant((qulonglong)i->second->id)); - } - } - - // Set the current resolution highlighted - QString n = _modeMap[_crtcMap[_outputMap[_monitor]->crtc]->mode]->name; - int index = _ui->comboBox->findText(n); - _ui->comboBox->setCurrentIndex(index); - - // Remove borders and stuff - setWindowFlags(Qt::Widget | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); - //setStyleSheet("background:transparent;"); - //setAttribute(Qt::WA_TranslucentBackground); - - // Resize widget to its content - resize(sizeHint()); - show(); - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(bringToTopTimer())); - timer->start(1000); - - // 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())); - } - /*********************************************************************/ - // If NEITHER of the outputs is a beamer (likely dualscreen setup) - else { - // TODO(manuel): Future feature. Setup dualscreen - qDebug() << "Dual output with extended screen!"; - exit(0); - } - break; - /*************************************************************************/ - default: - // If there are more than 3 outputs - // its up to the user. Quit. - qDebug() << "More than two outputs. Quit."; - exit(0); - break; - } - /*************************************************************************/ + _ui->setupUi(this); + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); } void Widget::bringToTopTimer() { - if (_ui->comboBox->view()->isVisible()) return; - raise(); + auto combos = this->findChildren<QComboBox*>(); + for (auto combo : combos) { + if (combo->view()->isVisible()) + return; + } + raise(); } //______________________________________________________________________________ -void Widget::updateScreenResources() -{ - // Clear the modemap (nothing to be freed, stored in screenResources) - _modeMap.clear(); - - // Create the modemap - qDebug() << "_MODES_"; - for (int i = 0; i < _screenResources->nmode; ++i) { - _modeMap.insert( - _screenResources->modes[i].id, - &_screenResources->modes[i]); - qDebug() << _screenResources->modes[i].id << "\t" - << _screenResources->modes[i].width << "x" - << _screenResources->modes[i].height; - } - - // 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); +Widget::~Widget() { - // 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::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + ScreenMode mode = ScreenSetup::inst()->getCurrentMode(); + if (ScreenSetup::inst()->getOutputCount() == 2 || mode == ScreenMode::Dual) { + if (_ui->tabWidget->widget(1) != _ui->tabDual) { + _ui->tabWidget->insertTab(1, _ui->tabDual, tr("Dual Screen")); + } + } else { + if (_ui->tabWidget->widget(1) == _ui->tabDual) { + _ui->tabWidget->removeTab(1); + } + } + switch (mode) { + case ScreenMode::Single: + case ScreenMode::Clone: + _ui->tabWidget->setCurrentWidget(_ui->tabClone); + break; + case ScreenMode::Dual: + _ui->tabWidget->setCurrentWidget(_ui->tabDual); + break; + case ScreenMode::Advanced: + _ui->tabWidget->setCurrentWidget(_ui->tabAdvanced); + break; + } + initControls(); } +void Widget::initControls() +{ + auto modes = ScreenSetup::inst()->getCommonModes(); + for (auto mode : modes) { + _ui->cboCloneResolution->addItem(QString::asprintf("%ux%u", mode.first, mode.second)); + } + // Clear advanced controls + auto widgets = _ui->advancedCombos->findChildren<QWidget*>(); + for (auto w : widgets) { + _ui->advancedCombos->removeWidget(w); + w->deleteLater(); + } + // Create new + QHash<QString, int> positions = ScreenSetup::inst()->getScreenPositions(); + ScreenSetup::ResolutionVector resolutions = ScreenSetup::inst()->getVirtualResolutions(); + int row = 0; + for (auto it = positions.begin(); it != positions.end(); ++it) { + _ui->advancedCombos->addWidget(new QLabel(it.key()), row, 0, 1, -1); + _ui->advancedCombos->addWidget(new QComboBox(), row, 2); + row++; + } +} //______________________________________________________________________________ -void Widget::handleButton(){ +void Widget::handleButton() { + // Apply - /*************************** Backup the crtcinfos ***************************/ - - qDebug() << "Backup the crtc infos"; - - CrtcMap backup; - for ( CrtcMap::iterator it = _crtcMap.begin(); - it != _crtcMap.end(); ++it ) { - backup[it.key()] = new XRRCrtcInfo; - backup[it.key()]->x = it.value()->x; - backup[it.key()]->y = it.value()->y; - backup[it.key()]->mode = it.value()->mode; - backup[it.key()]->rotation = it.value()->rotation; - backup[it.key()]->noutput = it.value()->noutput; - backup[it.key()]->outputs = new RROutput[it.value()->noutput]; - for (int i = 0; i < it.value()->noutput; ++i) { - backup[it.key()]->outputs[i] = it.value()->outputs[i]; - } - } - - /**************************** Apply the resolution **************************/ + /* // Get the modes which has to be applied from QComboBox QList<QVariant> modes = - _ui->comboBox->itemData( _ui->comboBox->currentIndex()).toList(); + _ui->comboBox->itemData( _ui->comboBox->currentIndex()).toList(); XRRModeInfo* monitorMode = _modeMap[modes[0].toULongLong()]; XRRModeInfo* beamerMode = _modeMap[modes[1].toULongLong()]; // First disconnect all crts to avoid conflicts for(CrtcMap::iterator it = _crtcMap.begin(); it != _crtcMap.end(); ++it) { Status st = XRRSetCrtcConfig(_display, _screenResources, it.key(), CurrentTime, - 0, 0, None, RR_Rotate_0, NULL, 0); + 0, 0, None, RR_Rotate_0, nullptr, 0); qDebug() << "Disconnecting" << it.key() << ":" << st; } // Set screensize XRRSetScreenSize(_display, DefaultRootWindow(_display), - monitorMode->width, monitorMode->height, - 25.4 * monitorMode->width / 96, // standard dpi that X uses - 25.4 * monitorMode->height / 96); // standard dpi that X uses + monitorMode->width, monitorMode->height, + 25.4 * monitorMode->width / 96, // standard dpi that X uses + 25.4 * monitorMode->height / 96); // standard dpi that X uses // Apply the modes Status stMon = XRRSetCrtcConfig(_display, _screenResources, - _outputMap[_monitor]->crtc, - CurrentTime, - 0, 0, monitorMode->id, - RR_Rotate_0, - &_monitor, 1); + _outputMap[_monitor]->crtc, + CurrentTime, + 0, 0, monitorMode->id, + RR_Rotate_0, + &_monitor, 1); Status stBem = XRRSetCrtcConfig(_display, - _screenResources, - _outputMap[_beamer]->crtc, - CurrentTime, - 0, 0, beamerMode->id, - RR_Rotate_0, + _screenResources, + _outputMap[_beamer]->crtc, + CurrentTime, + 0, 0, beamerMode->id, + RR_Rotate_0, &_beamer, 1); // Sync... whatever... @@ -391,112 +134,93 @@ void Widget::handleButton(){ // Set the mouse pointer in the middle of the screen QCursor::setPos(monitorMode->width/2, monitorMode->height/2); - /*************************** ASK for confirmtion ****************************/ + */ + + /*************************** ASK for confirmtion ****************************/ - // Show a dialog asking if the res should be kept - TimeOutDialog keepDialog(15, this); - keepDialog.setWindowModality(Qt::ApplicationModal); - keepDialog.setWindowTitle(" "); - keepDialog.setLabelText(trUtf8("Do you want to keep this resolution?")); - keepDialog.setCancelButtonText(trUtf8("Keep")); + // Show a dialog asking if the res should be kept + TimeOutDialog keepDialog(15, this); + keepDialog.setWindowModality(Qt::ApplicationModal); + keepDialog.setWindowTitle(" "); + keepDialog.setLabelText(trUtf8("Do you want to keep this resolution?")); + keepDialog.setCancelButtonText(trUtf8("Keep")); + /* keepDialog.move(monitorMode->width/2 - this->width()/2, - monitorMode->height/2 - this->height()); - keepDialog.show(); + monitorMode->height/2 - this->height()); + */ + keepDialog.show(); - while (keepDialog.isActive()) { - QCoreApplication::processEvents(); - } + while (keepDialog.isActive()) { + QCoreApplication::processEvents(); + } + /* // If the dialog was not canceled revert the resolution if ( !keepDialog.wasCanceled()) { qDebug() << "User did not cancel timeout, reverting!"; - /**************************** Apply the backup ****************************/ - - // First disconnect all crts to avoid conflicts - for(CrtcMap::iterator it = _crtcMap.begin(); it != _crtcMap.end(); ++it) { - XRRSetCrtcConfig(_display, _screenResources, it.key(), CurrentTime, - 0, 0, None, RR_Rotate_0, NULL, 0); - } - - // Then calc backed up screensize - QSize ScreenSize(0,0); - for ( CrtcMap::iterator it = backup.begin(); - it != backup.end(); ++it ) { - // Dangerzone. Only access existing modes! - if ( it.value()->mode != None ) { - ScreenSize.setWidth( - std::max((uint)ScreenSize.width(), - it.value()->x+_modeMap[it.value()->mode]->width)); - ScreenSize.setHeight( - std::max((uint)ScreenSize.height(), - it.value()->y+_modeMap[it.value()->mode]->height)); - } - } - - // Set screensize - XRRSetScreenSize(_display, DefaultRootWindow(_display), - ScreenSize.width(), ScreenSize.height(), - 25.4 * ScreenSize.width() / 96, // dpi used by X - 25.4 * ScreenSize.height() / 96); // dpi used by X - - // Apply the backup - for ( CrtcMap::iterator it = backup.begin(); - it != backup.end(); ++it ) { - XRRSetCrtcConfig(_display, - _screenResources, - it.key(), - CurrentTime, - it.value()->x, - it.value()->y, - it.value()->mode, - it.value()->rotation, - it.value()->outputs, - it.value()->noutput); - } - - // Sync... whatever... - XSync (_display, False); - - // center dialog on screenbottom - qDebug() << "Again center dialog on screenbottom"; - this->move( ScreenSize.width()/2 - this->width()/2, - ScreenSize.height() - this->height()); - - // Set the mouse pointer in the middle of the screen - QCursor::setPos(monitorMode->width/2, monitorMode->height/2); + // First disconnect all crts to avoid conflicts + for(CrtcMap::iterator it = _crtcMap.begin(); it != _crtcMap.end(); ++it) { + XRRSetCrtcConfig(_display, _screenResources, it.key(), CurrentTime, + 0, 0, None, RR_Rotate_0, nullptr, 0); + } + + // Then calc backed up screensize + QSize ScreenSize(0,0); + for ( CrtcMap::iterator it = backup.begin(); + it != backup.end(); ++it ) { + // Dangerzone. Only access existing modes! + if ( it.value()->mode != None ) { + ScreenSize.setWidth( + std::max((uint)ScreenSize.width(), + it.value()->x+_modeMap[it.value()->mode]->width)); + ScreenSize.setHeight( + std::max((uint)ScreenSize.height(), + it.value()->y+_modeMap[it.value()->mode]->height)); + } + } + + // Set screensize + XRRSetScreenSize(_display, DefaultRootWindow(_display), + ScreenSize.width(), ScreenSize.height(), + 25.4 * ScreenSize.width() / 96, // dpi used by X + 25.4 * ScreenSize.height() / 96); // dpi used by X + + // Apply the backup + for ( CrtcMap::iterator it = backup.begin(); + it != backup.end(); ++it ) { + XRRSetCrtcConfig(_display, + _screenResources, + it.key(), + CurrentTime, + it.value()->x, + it.value()->y, + it.value()->mode, + it.value()->rotation, + it.value()->outputs, + it.value()->noutput); + } + + // Sync... whatever... + XSync (_display, False); + + // center dialog on screenbottom + qDebug() << "Again center dialog on screenbottom"; + this->move( ScreenSize.width()/2 - this->width()/2, + ScreenSize.height() - this->height()); + + // Set the mouse pointer in the middle of the screen + QCursor::setPos(monitorMode->width/2, monitorMode->height/2); } // Delete the backup for ( CrtcMap::iterator it = backup.begin(); - it != backup.end(); ++it ) { - delete[] it.value()->outputs; - delete it.value(); + it != backup.end(); ++it ) { + delete[] it.value()->outputs; + delete it.value(); } - // Intenal settings changed. Update! - updateScreenResources(); + */ } -bool Widget::cloneMode() -{ - bool cloneMode = true; - - for (CrtcMap::iterator it = _crtcMap.begin(); it != _crtcMap.end(); it++) { - XRRCrtcInfo* crtc = it.value(); - - // check if x starts on upper left corner - if (crtc->x != 0 || crtc->y != 0) { - cloneMode = false; - } - - qDebug() << "width: " << crtc->width - << "height: " << crtc->height - << "x: " << crtc->x - << "y: " << crtc->y - << "mode: " << crtc->mode; - } - - return cloneMode; -} //////////////////////////////////////////////////////////////////////////////// |