summaryrefslogtreecommitdiffstats
path: root/src/widget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widget.cpp')
-rw-r--r--src/widget.cpp588
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;
-}
////////////////////////////////////////////////////////////////////////////////