summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2018-08-25 21:29:35 +0200
committerSimon Rettberg2018-08-25 21:29:35 +0200
commit615c5a7f858f80ccb1d7201b8ea628e35237db6e (patch)
treec27a134d68d1eb4b17f3b66fc4fcbc1af46fb58c
parentAdd missing include (diff)
downloadbeamergui-615c5a7f858f80ccb1d7201b8ea628e35237db6e.tar.gz
beamergui-615c5a7f858f80ccb1d7201b8ea628e35237db6e.tar.xz
beamergui-615c5a7f858f80ccb1d7201b8ea628e35237db6e.zip
Getting there, slowly
-rw-r--r--src/i18n/de.ts14
-rw-r--r--src/timeoutdialog.cpp48
-rw-r--r--src/timeoutdialog.h23
-rw-r--r--src/widget.cpp141
-rw-r--r--src/widget.h2
-rw-r--r--src/x.cpp55
-rw-r--r--src/x.h2
7 files changed, 206 insertions, 79 deletions
diff --git a/src/i18n/de.ts b/src/i18n/de.ts
index d93a667..6fbd9c4 100644
--- a/src/i18n/de.ts
+++ b/src/i18n/de.ts
@@ -4,7 +4,7 @@
<context>
<name>QCoreApplication</name>
<message>
- <location filename="../widget.cpp" line="122"/>
+ <location filename="../widget.cpp" line="171"/>
<source>%1x%2</source>
<translation type="unfinished"></translation>
</message>
@@ -43,7 +43,7 @@
</message>
<message>
<location filename="../widget.ui" line="102"/>
- <location filename="../widget.cpp" line="92"/>
+ <location filename="../widget.cpp" line="141"/>
<source>Dual Screen</source>
<translation type="unfinished"></translation>
</message>
@@ -58,27 +58,27 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../widget.cpp" line="218"/>
+ <location filename="../widget.cpp" line="274"/>
<source>(off)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../widget.cpp" line="243"/>
+ <location filename="../widget.cpp" line="306"/>
<source>Output</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../widget.cpp" line="244"/>
+ <location filename="../widget.cpp" line="307"/>
<source>Position</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../widget.cpp" line="324"/>
+ <location filename="../widget.cpp" line="387"/>
<source>Do you want to keep this resolution?</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../widget.cpp" line="325"/>
+ <location filename="../widget.cpp" line="388"/>
<source>Keep</source>
<translation type="unfinished"></translation>
</message>
diff --git a/src/timeoutdialog.cpp b/src/timeoutdialog.cpp
index 418d791..f9787fb 100644
--- a/src/timeoutdialog.cpp
+++ b/src/timeoutdialog.cpp
@@ -3,40 +3,46 @@
#include "timeoutdialog.h"
#include <QProgressBar>
+#include <QDebug>
TimeOutDialog::TimeOutDialog(int time, QWidget *parent)
- : QProgressDialog(parent), _time(time)
+ : QProgressDialog(parent), _time(time)
{
- QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
- QObject::connect(this, SIGNAL(canceled()), this, SLOT(cancel()));
-
-
- // QProgressDialog takes ownership of QProgressBar
- QProgressBar *qbar = new QProgressBar(this);
- qbar->setFormat(trUtf8("%v seconds"));
- qbar->setMaximum(_time);
- qbar->setMinimum(0);
- qbar->setValue(_time);
- setBar(qbar);
- _timer.start(1000);
+ QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
+ QObject::connect(this, SIGNAL(canceled()), this, SLOT(cancel()));
+
+
+ // QProgressDialog takes ownership of QProgressBar
+ QProgressBar *qbar = new QProgressBar(this);
+ qbar->setFormat(trUtf8("%v seconds"));
+ qbar->setMaximum(_time);
+ qbar->setMinimum(0);
+ qbar->setValue(_time);
+ setBar(qbar);
+ _timer.start(1000);
}
+void TimeOutDialog::hideEvent(QHideEvent *e)
+{
+ QProgressDialog::hideEvent(e);
+ _timer.stop();
+}
//___________________________________________________________________________
void TimeOutDialog::update()
{
- if (_time == 0) {
- _timer.stop();
- accept();
- }
- else
- setValue(_time);
- --_time;
+ --_time;
+ if (_time == 0) {
+ _timer.stop();
+ accept();
+ } else {
+ setValue(_time);
+ }
}
//___________________________________________________________________________
void TimeOutDialog::cancel()
{
- _timer.stop();
+ _timer.stop();
}
diff --git a/src/timeoutdialog.h b/src/timeoutdialog.h
index eb0f969..eb853f3 100644
--- a/src/timeoutdialog.h
+++ b/src/timeoutdialog.h
@@ -9,21 +9,24 @@
class TimeOutDialog : public QProgressDialog
{
- Q_OBJECT
+ Q_OBJECT
- public:
- TimeOutDialog(int time, QWidget *parent = 0);
+public:
+ TimeOutDialog(int time, QWidget *parent = 0);
bool isActive() const { return _timer.isActive(); }
- private:
- int _time;
- QTimer _timer;
+private:
+ int _time;
+ QTimer _timer;
- public slots:
- void cancel();
+protected:
+ void hideEvent(QHideEvent *event) override;
- private slots:
- void update();
+public slots:
+ void cancel();
+
+private slots:
+ void update();
};
#endif // TIMEOUTDIALOG_H
diff --git a/src/widget.cpp b/src/widget.cpp
index a5f32fa..34684b5 100644
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -7,6 +7,8 @@
#include <QDebug>
#include <QtWidgets/QAction>
#include <QAbstractItemView>
+#include <QScreen>
+#include <QThread>
class ScreenWidget : public QWidget
{
@@ -16,6 +18,10 @@ public:
QWidget::setStyleSheet(".QWidget { border-radius: 3px;border: 2px solid black; }");
QWidget::setLayout(new QVBoxLayout(this));
}
+ void setScaling(float scale)
+ {
+ this->scale = scale;
+ }
protected:
float scale;
void resizeEvent(QResizeEvent *event) override
@@ -59,12 +65,39 @@ static void addBoldListener(QComboBox *combo)
//______________________________________________________________________________
Widget::Widget(QWidget *parent) :
QWidget(parent),
- _ui(new Ui::Widget)
+ _ui(new Ui::Widget),
+ _popupCount(0)
{
_ui->setupUi(this);
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
QTimer *top = new QTimer(this);
connect(top, &QTimer::timeout, [=]() {
+ // Move window to current screen
+ QRect win = this->geometry();
+ QPoint cursor = QCursor::pos();
+ const QScreen *winScreen = nullptr, *mouseScreen = nullptr;
+ //qDebug() << "Mouse at" << cursor << " window at" << win;
+ for (auto screen : _qtScreens) {
+ QRect geo = screen->geometry();
+ if (geo.contains(win)) {
+ winScreen = screen;
+ //qDebug() << "Window on screen" << geo;
+ }
+ if (geo.contains(cursor)) {
+ mouseScreen = screen;
+ //qDebug() << "Mouse on screen" << geo;
+ }
+ }
+ if (mouseScreen != nullptr && mouseScreen != winScreen) {
+ QPoint offset = mouseScreen->geometry().topLeft();
+ QSize spacing = (mouseScreen->size() - this->size()) / 2;
+ offset.rx() += spacing.width();
+ offset.ry() += spacing.height();
+ this->move(offset);
+ }
+ // Raise window if appropriate
+ if (_popupCount > 0)
+ return;
auto combos = this->findChildren<QComboBox*>();
for (auto combo : combos) {
if (combo->view()->isVisible())
@@ -77,6 +110,22 @@ Widget::Widget(QWidget *parent) :
addBoldListener(_ui->cboDualLeft);
addBoldListener(_ui->cboDualRight);
connectButtons();
+ auto fun = [this](const QScreen *scrn) {
+ qDebug() << "QT SEES SCREEN" << scrn->geometry();
+ _qtScreens.append(scrn);
+ /*
+ connect(scrn, &QScreen::geometryChanged, [this](const QRect &geom) {
+
+ });
+ */
+ };
+ for (auto scrn : QGuiApplication::screens()) {
+ fun(scrn);
+ }
+ connect(qApp, &QGuiApplication::screenAdded, fun);
+ connect(qApp, &QGuiApplication::screenRemoved, [this](const QScreen *scrn) {
+ _qtScreens.removeAll(scrn);
+ });
}
//______________________________________________________________________________
@@ -178,7 +227,14 @@ void Widget::initControls()
auto lists = QList<QComboBox*>({_ui->cboDualLeft, _ui->cboDualRight});
int j = 0;
for (int i = 0; i < screenList.size() && j < 2; ++i) {
- fillCombo(lists[j], screenList[i].modes, screenList[i].currentResolution, screenList[i].preferredResolution);
+ QSize selected;
+ if (ScreenSetup::inst()->getCurrentMode() == ScreenMode::Dual) {
+ // When we're not in dualhead mode, pre-select the preferred solution, so in case the user wants
+ // to switch to dualhead, they just need to switch to the "dual" tab and hit apply to get
+ // each screen configured to its preferred resolution.
+ selected = screenList[i].currentResolution;
+ }
+ fillCombo(lists[j], screenList[i].modes, selected, screenList[i].preferredResolution);
lists[j]->setProperty("output", screenList[i].output);
QLabel *sl = ( j == 0 ? _ui->lblDualLeft : _ui->lblDualRight );
sl->setText(screenList[i].output + "\n" + screenList[i].name);
@@ -225,7 +281,7 @@ void Widget::initControls()
res = QSize(16, 9);
}
AdvancedScreen *a = new AdvancedScreen();
- a->screen = new ScreenWidget(float(res.width()) / float(res.height()));
+ a->screen = new ScreenWidget(res.isEmpty() ? 1.33f : float(res.width()) / float(res.height()));
a->desiredResolution = res;
a->cboResolution = new QComboBox();
_ui->advancedContainer->addWidget(a->screen);
@@ -233,12 +289,19 @@ void Widget::initControls()
a->screen->layout()->addWidget(a->cboResolution);
a->screen->layout()->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
positionList.append(QString::number(_advancedScreens.size()));
- connect(a->cboResolution, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index) {
+ connect(a->cboResolution, QOverload<int>::of(&QComboBox::currentIndexChanged), [a, this](int index) {
if (!_ignoreResolutionChange) {
a->desiredResolution = a->cboResolution->itemData(index).toSize();
}
});
addBoldListener(a->cboResolution);
+ connect(a->cboResolution, QOverload<int>::of(&QComboBox::currentIndexChanged), [a, this](int index) {
+ if (index < 0)
+ return;
+ QSize res = a->cboResolution->itemData(index).toSize();
+ a->screen->setScaling(res.isEmpty() ? 1.33f : float(res.width()) / float(res.height()));
+ _ui->advancedContainer->update();
+ });
}
// Header
_ui->advancedCombos->addWidget(new QLabel(tr("Output")), 0, 0);
@@ -262,10 +325,10 @@ void Widget::initControls()
// Logic
cbo->addItems(positionList);
// TODO Signal
- connect(cbo, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index) {
+ connect(cbo, QOverload<int>::of(&QComboBox::currentIndexChanged), [a, this](int index) {
a->info.position = index - 1;
if (a->assignmentLabel->layout() != nullptr) {
- a->assignmentLabel->layout()->removeWidget(cbo);
+ a->assignmentLabel->layout()->removeWidget(a->cboPosition);
}
if (index > 0) {
_advancedScreens[index - 1]->screen->layout()->addWidget(a->assignmentLabel);
@@ -318,23 +381,63 @@ void Widget::initControls()
bool Widget::keepResolution()
{
- // 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();
+ _popupCount += 1;
+ // Qt needs some time to notice the screen setup has changed
+ QCoreApplication::processEvents();
+ QThread::msleep(10);
+ QCoreApplication::processEvents();
+ QList<TimeOutDialog*> list;
+ this->setDisabled(true);
+ for (auto screen : _qtScreens) {
+ QRect geo = screen->geometry();
+ bool skip = false;
+ // See if it overlaps with an existing screen
+ for (auto other : _qtScreens) {
+ if (other == screen)
+ break;
+ if (other->geometry().intersects(geo)) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+ // Show a dialog asking if the res should be kept
+ TimeOutDialog *keepDialog = new TimeOutDialog(15, this);
+ //keepDialog->setWindowModality(Qt::WindowModal);
+ keepDialog->setWindowTitle(" ");
+ keepDialog->setLabelText(trUtf8("Do you want to keep this resolution?"));
+ keepDialog->setCancelButtonText(trUtf8("Keep"));
+ keepDialog->setWindowFlag(Qt::WindowStaysOnTopHint, true);
+ QSize s = (geo.size() - keepDialog->size()) / 2;
+ QPoint tl = geo.topLeft();
+ tl.rx() += s.width();
+ tl.ry() += s.height();
+ keepDialog->move(tl);
+ keepDialog->show();
+ list.append(keepDialog);
+ }
+ bool wasCanceled = false;
+ bool active;
do {
+ active = true;
QCoreApplication::processEvents();
- } while (keepDialog.isActive());
+ for (auto win : list) {
+ active = active && win->isActive();
+ wasCanceled = wasCanceled || win->wasCanceled();
+ }
+ } while (active && !wasCanceled);
+
+ for (auto win : list) {
+ win->deleteLater();
+ }
+
+ this->setDisabled(false);
+
+ _popupCount -= 1;
- return keepDialog.wasCanceled();
+ return wasCanceled;
}
//______________________________________________________________________________
diff --git a/src/widget.h b/src/widget.h
index 96e6f1a..4e3c932 100644
--- a/src/widget.h
+++ b/src/widget.h
@@ -30,6 +30,8 @@ private:
bool _ignoreResolutionChange;
QVector<AdvancedScreen*> _advancedScreens;
QVector<AdvancedOutput*> _advancedOutput;
+ QList<const QScreen *> _qtScreens;
+ bool _popupCount;
void initControls();
void connectButtons();
diff --git a/src/x.cpp b/src/x.cpp
index df257bb..73662c5 100644
--- a/src/x.cpp
+++ b/src/x.cpp
@@ -40,7 +40,9 @@ ScreenInfo::ScreenInfo(const OutputInfo *oi, const ModeMap &om)
if (om.contains(oi->output->modes[i])) {
auto m = om.value(oi->output->modes[i]);
const QSize size(int(m->width), int(m->height));
- modes.append(size);
+ if (!modes.contains(size)) {
+ modes.append(size);
+ }
if (i == 0 && oi->output->npreferred > 0) {
preferredResolution = size;
}
@@ -415,12 +417,12 @@ static QSize getTotalSizeHorz(const QList<QSize> &list)
return ret;
}
-void ScreenSetup::setOutputResolution(OutputInfo *oi, int x, int y, const QSize &size, bool dryRun)
+bool ScreenSetup::setOutputResolution(OutputInfo *oi, int x, int y, const QSize &size, bool dryRun)
{
RRMode mode = getOutputModeForResolution(oi->output, size);
if (mode == None) {
if (oi->output->nmode == 0)
- return;
+ return false;
qDebug() << oi->outputName << "doesn't support" << size << "- falling back to its default";
mode = oi->output->modes[0];
}
@@ -434,18 +436,27 @@ void ScreenSetup::setOutputResolution(OutputInfo *oi, int x, int y, const QSize
&oi->id, 1);
}
qDebug() << "Set" << oi->outputName << "to" << _modeMap[mode]->width << "x" << _modeMap[mode]->height << "-- offset" << x << "/" << y;
+ return true;
}
ScreenMode ScreenSetup::getCurrentMode()
{
- if (_outputMap.size() == 1)
- return ScreenMode::Single;
- if (_outputMap.size() > 2)
- return ScreenMode::Advanced;
+ int numConnected = 0;
+ bool notAtOrigin = false;
for (auto oi : _outputMap) {
- if (oi->crtc->x != 0 || oi->crtc->y != 0)
- return ScreenMode::Dual;
+ if (oi->mode != nullptr) {
+ ++numConnected;
+ if (oi->crtc->x != 0 || oi->crtc->y != 0) {
+ notAtOrigin = true;
+ }
+ }
}
+ if (numConnected == 1)
+ return ScreenMode::Single;
+ if (numConnected > 2)
+ return ScreenMode::Advanced;
+ if (notAtOrigin)
+ return ScreenMode::Dual;
return ScreenMode::Clone;
}
@@ -471,6 +482,7 @@ ScreenMode ScreenSetup::setDefaultMode(bool dryRun)
return ScreenMode::Advanced; // Dunno lol
QSize screenSize = getTotalSizeHorz(outputSizes);
if (!dryRun) {
+ XGrabServer(_display);
disconnectAllCrtcs();
// Set new screen size
setScreenSize(screenSize);
@@ -489,7 +501,10 @@ ScreenMode ScreenSetup::setDefaultMode(bool dryRun)
}
offset += size.width();
}
- XSync(_display, False);
+ if (!dryRun) {
+ XUngrabServer(_display);
+ XSync(_display, False);
+ }
updateScreenResources(); // Re-Read
if (outputSizes.size() == 1) // One output size, at least 2 outputs in total -- clone mode
return ScreenMode::Clone;
@@ -661,16 +676,14 @@ void ScreenSetup::createCrtcBackup()
bool ScreenSetup::setClone(const QSize &resolution)
{
createCrtcBackup();
+ XGrabServer(_display);
disconnectAllCrtcs();
setScreenSize(resolution);
bool ok = false;
for (auto oi : _outputMap) {
- RRMode mode = getOutputModeForResolution(oi->output, resolution);
- if (mode != None) {
- XRRSetCrtcConfig(_display, _screenResources, oi->output->crtc, CurrentTime, 0, 0, mode, RR_Rotate_0, &oi->id, 1);
- ok = true;
- }
+ ok = setOutputResolution(oi, 0, 0, resolution) || ok;
}
+ XUngrabServer(_display);
XSync(_display, False);
return ok;
}
@@ -685,6 +698,7 @@ bool ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &list)
auto screenSize = getTotalSizeHorz(sizes);
if (screenSize.isEmpty())
return false;
+ XGrabServer(_display);
disconnectAllCrtcs();
setScreenSize(screenSize);
int x = 0;
@@ -695,15 +709,12 @@ bool ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &list)
for (auto oi : _outputMap) {
if (oi->outputName != outputName)
continue;
- RRMode mode = getOutputModeForResolution(oi->output, res);
- if (mode == None)
- continue;
- XRRSetCrtcConfig(_display, _screenResources, oi->output->crtc, CurrentTime, x, 0, mode, RR_Rotate_0, &oi->id, 1);
- ok = true;
+ ok = setOutputResolution(oi, x, 0, res) || ok;
}
}
x += res.width();
}
+ XUngrabServer(_display);
XSync(_display, False);
return ok;
}
@@ -713,6 +724,7 @@ void ScreenSetup::revertChanges()
if (_crtcBackup.isEmpty())
return;
qDebug() << "Starting revert";
+ XGrabServer(_display);
disconnectAllCrtcs();
QSize screenSize;
for (auto e : _crtcBackup) {
@@ -727,7 +739,8 @@ void ScreenSetup::revertChanges()
XRRSetCrtcConfig(_display, _screenResources, it.key(), CurrentTime,
e->x, e->y, e->mode, e->rotation, e->outputs, e->noutput);
}
- XSync (_display, False);
+ XUngrabServer(_display);
+ XSync(_display, False);
}
static bool modeBiggerThan(const QSize &a, const QSize &b)
diff --git a/src/x.h b/src/x.h
index 8a37b62..b5df6e0 100644
--- a/src/x.h
+++ b/src/x.h
@@ -48,7 +48,6 @@ public:
void initModes();
XRRModeInfo* getPreferredMode(OutputInfo *oi) const;
QList<QSize> getTotalSize(const QList<OutputInfo*> &projectors, const QList<OutputInfo*> &screens) const;
- void setOutputResolution(OutputInfo *oi, int x, int y, const QSize &size, bool dryRun = false);
ScreenMode getCurrentMode();
ScreenMode setDefaultMode(bool dryRun = false);
void copyModesToAll(RROutput id, int num);
@@ -80,6 +79,7 @@ private:
RRMode getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const;
RRMode getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const;
RRCrtc getFreeCrtc(const XRROutputInfo* output) const;
+ bool setOutputResolution(OutputInfo *oi, int x, int y, const QSize &size, bool dryRun = false);
static ScreenSetup * _instance;
Display* _display;