556 lines
16 KiB
C++
Executable File
556 lines
16 KiB
C++
Executable File
#include "lts_screen_container.h"
|
|
#include "lts_dummy_widget.h"
|
|
|
|
#include <LtsWidgets/lts_base_layout_widget.h>
|
|
|
|
#include <QHBoxLayout>
|
|
#include <QResizeEvent>
|
|
#include <QRect>
|
|
#include <QTimer>
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
namespace LtsMultiMonitor
|
|
{
|
|
QString LtsScreenContainer::geoStr() const
|
|
{
|
|
return QStringLiteral("%1:%2:")
|
|
.arg(QString::number(m_screenGeo.x()).rightJustified(4, QLatin1Char(' ')))
|
|
.arg(QString::number(m_screenGeo.y()).rightJustified(4, QLatin1Char(' ')))
|
|
;
|
|
}
|
|
|
|
LtsScreenContainer::LtsScreenContainer(QRect screenGeo)
|
|
: m_layout(new QHBoxLayout)
|
|
, m_screenGeo(screenGeo)
|
|
{
|
|
//m_layout->setContentsMargins(300, 300, 300, 300);
|
|
m_layout->setMargin(0);
|
|
m_layout->setSpacing(0);
|
|
m_layout->setStretch(0, 999); // ?????
|
|
|
|
setContentsMargins(0, 0, 0, 0);
|
|
vanish();
|
|
setLayout(m_layout);
|
|
|
|
|
|
|
|
QTimer *t = new QTimer(this);
|
|
t->setInterval(3000);
|
|
#ifdef LTS_DEBUG
|
|
t->start();
|
|
#endif
|
|
connect(t, &QTimer::timeout,
|
|
this, [this, screenGeo]()
|
|
{
|
|
QString old(QStringLiteral("<#!UNKNOWN!#>"));
|
|
|
|
if (m_oldActiveWidget == nullptr)
|
|
old = QStringLiteral("null");
|
|
else if (m_oldActiveWidget == &m_mainWidget)
|
|
old = QStringLiteral("MAIN");
|
|
else if (m_oldActiveWidget == &m_secondaryWidget)
|
|
old = QStringLiteral("SECONDARY");
|
|
|
|
//qWarning() << geoStr() << "OLD = " << old << "main" << m_mainWidget << " - sec" << m_secondaryWidget;
|
|
});
|
|
}
|
|
|
|
|
|
bool LtsScreenContainer::isInactiveWidgetOccupied() const
|
|
{
|
|
if (m_activeWidget == &m_mainWidget && m_secondaryWidget != nullptr)
|
|
return true;
|
|
if (m_activeWidget == &m_secondaryWidget && m_mainWidget != nullptr)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
QIcon LtsScreenContainer::mainWindowIcon() const
|
|
{
|
|
if (m_mainWidget != nullptr)
|
|
return m_mainWidget->windowIcon();
|
|
return {};
|
|
}
|
|
|
|
|
|
QIcon LtsScreenContainer::secondaryWindowIcon() const
|
|
{
|
|
if (m_secondaryWidget != nullptr)
|
|
return m_secondaryWidget->windowIcon();
|
|
return {};
|
|
}
|
|
|
|
|
|
bool LtsScreenContainer::mainAndSecondaryOccupied() const
|
|
{
|
|
return (m_mainWidget != nullptr && m_secondaryWidget != nullptr);
|
|
}
|
|
|
|
|
|
LtsScreenBase::WidgetType LtsScreenContainer::activeWidgetType() const
|
|
{
|
|
if (m_activeWidget == &m_mainWidget)
|
|
return LtsScreenBase::WidgetType::MainWidget;
|
|
if (m_activeWidget == &m_secondaryWidget)
|
|
return LtsScreenBase::WidgetType::SecondaryWidget;
|
|
|
|
assert(false);
|
|
return LtsScreenBase::WidgetType::None;
|
|
}
|
|
|
|
|
|
void LtsScreenContainer::toggle()
|
|
{
|
|
//qWarning() << geoStr() << "SC TOGGLE";
|
|
switchToTemp((*m_activeWidget == m_mainWidget) ? LtsScreenBase::WidgetType::SecondaryWidget : LtsScreenBase::WidgetType::MainWidget);
|
|
|
|
QWidget *w = activeWidget();
|
|
|
|
assert(w != nullptr);
|
|
if (w == nullptr) // bail for prod ...
|
|
{
|
|
revertSwitch();
|
|
return;
|
|
}
|
|
|
|
if (!tryPutDummyUnmanaged(w))
|
|
w->show(); // if not fullscreen video, show the widget - don't show fullscreen video dummy widget as it's just an invisible helper
|
|
|
|
finalizeSwitch();
|
|
}
|
|
|
|
|
|
bool LtsScreenContainer::isIrreplaceable() const
|
|
{
|
|
if (m_activeWidget == nullptr)
|
|
return false;
|
|
|
|
auto *blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget *>(activeWidget());
|
|
if (blw == nullptr) // can't be irreplacable if it's not an blw
|
|
return false;
|
|
|
|
return blw->isIrreplaceable();
|
|
}
|
|
|
|
|
|
QWidget *LtsScreenContainer::activeWidget() const
|
|
{
|
|
assert(m_activeWidget != nullptr);
|
|
|
|
// if (m_mainWidget != nullptr && m_mainWidget->isVisible())
|
|
// return m_mainWidget;
|
|
// if (m_secondaryWidget != nullptr && m_secondaryWidget->isVisible())
|
|
// return m_secondaryWidget;
|
|
// return nullptr;
|
|
return *m_activeWidget;
|
|
}
|
|
|
|
|
|
QWidget **LtsScreenContainer::activeWidgetPtr()
|
|
{
|
|
assert(m_activeWidget != nullptr);
|
|
|
|
// if (m_mainWidget != nullptr && m_mainWidget->isVisible())
|
|
// return &m_mainWidget;
|
|
// if (m_secondaryWidget != nullptr && m_secondaryWidget->isVisible())
|
|
// return &m_secondaryWidget;
|
|
// return nullptr;
|
|
return m_activeWidget;
|
|
}
|
|
|
|
|
|
void LtsScreenContainer::vanish()
|
|
{
|
|
return;
|
|
|
|
|
|
|
|
//setAttribute(Qt::WA_NoSystemBackground, true);
|
|
//setAttribute(Qt::WA_TranslucentBackground, true);
|
|
//setAttribute(Qt::WA_PaintOnScreen); // workaround for Qt < 5.3
|
|
|
|
|
|
|
|
// qWarning() << "m_layout" << (quintptr)m_layout;
|
|
m_layout->setParent(nullptr);
|
|
}
|
|
|
|
|
|
void LtsScreenContainer::reappear()
|
|
{
|
|
return;
|
|
|
|
|
|
|
|
//setAttribute(Qt::WA_NoSystemBackground, false);
|
|
setAttribute(Qt::WA_TranslucentBackground, false);
|
|
//setAttribute(Qt::WA_PaintOnScreen, false); // workaround for Qt < 5.3
|
|
|
|
|
|
|
|
// qWarning() << "m_layout" << (quintptr)m_layout;
|
|
if (m_layout->parent() == nullptr) // FIXME: does Qt optimize this?
|
|
setLayout(m_layout);
|
|
}
|
|
|
|
|
|
//void LtsScreenContainer::slotOverlayDestroyed()
|
|
//{
|
|
// qWarning() << "!!! mep" << QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
|
|
// if (sender() == static_cast<QWidget *>(m_widget)) // only show if it's REALLY that widget that was destroyed
|
|
// {
|
|
// qWarning() << "!!! mep" << QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
|
|
// vanish();
|
|
// }
|
|
//}
|
|
|
|
|
|
QWidget *LtsScreenContainer::stealWidget() noexcept(false)
|
|
{
|
|
//qWarning() << "mep" << QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
|
|
|
|
QWidget **widgetPtr = activeWidgetPtr();
|
|
QWidget *widget = *widgetPtr;
|
|
|
|
if (widget == nullptr)
|
|
{
|
|
//qWarning() << "!!! mep" << __FILE__ << __LINE__;
|
|
throw "stealWidget: no widget to steal";
|
|
}
|
|
|
|
//qWarning() << "stealWidget: stealing widget from" << (quintptr)this;
|
|
|
|
//vanish();
|
|
widget->setParent(nullptr);
|
|
vanish();
|
|
|
|
// do NOT send a signal if the widget was stolen instead of closed, etc.
|
|
disconnect(widget, &QWidget::destroyed,
|
|
this, &LtsScreenContainer::slotChildDestroyed);
|
|
|
|
// FullscreenVideoDummyWidget *dummy = qobject_cast<FullscreenVideoDummyWidget *>(m_widget);
|
|
// if (dummy != nullptr)
|
|
// {
|
|
// disconnect(dummy, &FullscreenVideoDummyWidget::destroyed,
|
|
// this, &LtsScreenContainer::slotOverlayDestroyed);
|
|
// }
|
|
|
|
QWidget *oldWidget = widget;
|
|
*widgetPtr = nullptr;
|
|
//emit check();
|
|
return oldWidget;
|
|
}
|
|
|
|
|
|
bool LtsScreenContainer::hasWidget(QWidget *widget) const
|
|
{
|
|
if (m_mainWidget != nullptr && m_mainWidget == widget)
|
|
return true;
|
|
if (m_secondaryWidget != nullptr && m_secondaryWidget == widget)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
bool LtsScreenContainer::isEmpty() const
|
|
{
|
|
QWidget **currentWidgetPtr = m_activeWidget;
|
|
if (currentWidgetPtr == nullptr)
|
|
return true;
|
|
return (*currentWidgetPtr == nullptr);
|
|
}
|
|
|
|
bool LtsScreenContainer::hasMainWidget()
|
|
{
|
|
return m_mainWidget != nullptr;
|
|
}
|
|
|
|
bool LtsScreenContainer::hasSecondaryWidget()
|
|
{
|
|
return m_secondaryWidget != nullptr;
|
|
}
|
|
|
|
bool LtsScreenContainer::tryPutDummyUnmanaged(QWidget *widget)
|
|
{
|
|
auto *dummy = qobject_cast<FullscreenVideoDummyWidget *>(widget);
|
|
|
|
if (dummy == nullptr)
|
|
return false;
|
|
|
|
// qWarning() << "dummy" << (quintptr)dummy;
|
|
// qWarning() << "mep" << QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
|
|
|
|
|
|
//QRect r(dummy->mapToGlobal(dummy->geometry().topLeft()), dummy->size());
|
|
QRect r(mapToGlobal(rect().topLeft()), rect().size());
|
|
//qWarning() << geoStr() << "LtsScreenContainer::tryPutDummyUnmanaged => dummy->signalWidgetPlaced";
|
|
emit dummy->signalWidgetPlaced(r);
|
|
|
|
// qWarning() << "mep" << QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
|
|
|
|
//vanish(); // get out of the video's way [not needed as containers are always stay-on-bottom
|
|
// QWidget **widgetPtr = activeWidgetPtr();
|
|
// *widgetPtr = widget;
|
|
|
|
// qWarning() << "mep" << QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
|
|
|
|
emit signalSetCornerIcons();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void LtsScreenContainer::switchToTemp(LtsScreenBase::WidgetType widgetType)
|
|
{
|
|
// fprintf(stderr, "switchToTemp: (%s)\n", geoStr().toStdString().c_str());
|
|
|
|
Q_ASSERT(widgetType != LtsScreenBase::WidgetType::None);
|
|
|
|
if ((m_activeWidget == &m_mainWidget && widgetType == LtsScreenBase::WidgetType::MainWidget) ||
|
|
(m_activeWidget == &m_secondaryWidget && widgetType == LtsScreenBase::WidgetType::SecondaryWidget))
|
|
{
|
|
// fprintf(stderr, "switchToTemp: null switch (%s)\n", geoStr().toStdString().c_str());
|
|
//qWarning() << geoStr() << "switchToTemp: null switch!! widgetType:" << (int)widgetType;
|
|
m_nullSwitchActive = true;
|
|
return; // do nothing if already on requested widget
|
|
}
|
|
|
|
if (widgetType == LtsScreenBase::WidgetType::MainWidget)
|
|
m_oldActiveWidget = &m_secondaryWidget;
|
|
else if (widgetType == LtsScreenBase::WidgetType::SecondaryWidget)
|
|
m_oldActiveWidget = &m_mainWidget;
|
|
else
|
|
Q_ASSERT(false);
|
|
|
|
//m_oldActiveWidget = m_activeWidget; // can still be 0ptr (e.g. at first start)
|
|
|
|
// qWarning() << geoStr() << "switchToTemp:" << ((widgetType == LtsScreenBase::WidgetType::MainWidget) ? QStringLiteral("Main") : QStringLiteral("Secondary")) << "m_activeWidget before" << m_activeWidget << "(which means that m_oldActiveWidget is now exactly that)";
|
|
m_activeWidget = (widgetType == LtsScreenBase::WidgetType::SecondaryWidget ? &m_secondaryWidget : &m_mainWidget);
|
|
// qWarning() << geoStr() << "switchToTemp: m_activeWidget now" << m_activeWidget;
|
|
// fprintf(stderr, "switchToTemp: m_activeWidget is now %d, %lld\n", (int)widgetType, (qintptr)m_activeWidget);
|
|
}
|
|
|
|
|
|
void LtsScreenContainer::finalizeSwitch()
|
|
{
|
|
// fprintf(stderr, "finalizeSwitch: (%s)\n", geoStr().toStdString().c_str());
|
|
|
|
QWidget **oldActiveWidget = m_oldActiveWidget;
|
|
m_oldActiveWidget = nullptr;
|
|
//qWarning() << geoStr() << "finalizeSwitch: m_oldActiveWidget set to nullptr !";
|
|
|
|
if (m_nullSwitchActive)
|
|
{
|
|
// qWarning() << geoStr() << "finalizeSwitch: was null switch!";
|
|
m_nullSwitchActive = false;
|
|
return;
|
|
}
|
|
|
|
if (oldActiveWidget == nullptr)
|
|
{
|
|
// qWarning() << geoStr() << "finalizeSwitch: m_oldActiveWidget == nullptr";
|
|
return;
|
|
}
|
|
|
|
if (*oldActiveWidget == nullptr)
|
|
{
|
|
// qWarning() << geoStr() << "finalizeSwitch: *m_oldActiveWidget == nullptr";
|
|
return;
|
|
}
|
|
|
|
// not needed anymore because of check for null switch (?)
|
|
// if (*oldActiveWidget == *m_activeWidget)
|
|
// {
|
|
// qWarning() << "finalizeSwitch: (*m_oldActiveWidget == *m_activeWidget) - old:" << (quintptr)*oldActiveWidget << "active:" << (quintptr)*m_activeWidget << *m_activeWidget << (*m_activeWidget)->windowTitle();
|
|
// return;
|
|
// }
|
|
|
|
// qWarning() << geoStr() << "finalizeSwitch: (info): old:" << (quintptr)*oldActiveWidget << "active" << (quintptr)*m_activeWidget << *m_activeWidget;
|
|
|
|
// if the active widget changed now, hide the old widget before showing the new one
|
|
QWidget *widget = *oldActiveWidget;
|
|
auto *dummy = qobject_cast<FullscreenVideoDummyWidget *>(widget);
|
|
if (dummy != nullptr)
|
|
{
|
|
// qWarning() << geoStr() << "LtsScreenContainer::finalizeSwitch() => dummy->hideVideo()";
|
|
dummy->hideVideo(); // widget is always hidden, so a simple hide would do nothing - special case here
|
|
}
|
|
else // in any other case it's sufficient to just hide the widget
|
|
{
|
|
// qWarning() << geoStr() << "LtsScreenContainer::finalizeSwitch() => widget->hide()";
|
|
widget->hide();
|
|
}
|
|
|
|
QWidget *widget2 = *m_activeWidget;
|
|
auto *dummy2 = qobject_cast<FullscreenVideoDummyWidget *>(widget2);
|
|
if (dummy2 != nullptr)
|
|
{
|
|
dummy2->showVideo();
|
|
}
|
|
|
|
emit signalSetCornerIcons();
|
|
}
|
|
|
|
|
|
void LtsScreenContainer::revertSwitch()
|
|
{
|
|
// fprintf(stderr, "revertSwitch: (%s)\n", geoStr().toStdString().c_str());
|
|
|
|
QWidget **oldActiveWidgetBackup = m_oldActiveWidget;
|
|
m_oldActiveWidget = nullptr;
|
|
// qWarning() << geoStr() << "revertSwitch: m_oldActiveWidget set to nullptr !";
|
|
|
|
if (m_nullSwitchActive)
|
|
{
|
|
// qWarning() << geoStr() << "revertSwitch: was null switch!";
|
|
m_nullSwitchActive = false;
|
|
return;
|
|
}
|
|
|
|
//qWarning() << geoStr() << "revertSwitch: REVERT #1";
|
|
//assert(m_oldActiveWidget != nullptr);
|
|
if (oldActiveWidgetBackup == nullptr)
|
|
return;
|
|
// qWarning() << geoStr() << "revertSwitch: REVERT #2";
|
|
m_activeWidget = oldActiveWidgetBackup;
|
|
// qWarning() << geoStr() << "revertSwitch: m_activeWidget set to oldActiveWidgetBackup" << oldActiveWidgetBackup;
|
|
}
|
|
|
|
|
|
void LtsScreenContainer::setWidget(QWidget *widget)
|
|
{
|
|
// fprintf(stderr, "setWidget: (%s)\n", geoStr().toStdString().c_str());
|
|
|
|
// NOTE: switch to main widget or secondary widget has to be done by the selector prior to calling this method
|
|
|
|
QWidget **widgetPtr = activeWidgetPtr();
|
|
|
|
qWarning() << geoStr() << "setWidget: m_activeWidget" << m_activeWidget;
|
|
|
|
QWidget *currentWidget = *widgetPtr;
|
|
|
|
Q_ASSERT(currentWidget == nullptr); // don't set a widget if there is already one (LtsMultiMonitorSelector*'s responsibility to handle this correctly)
|
|
// if (m_widget != nullptr)
|
|
// qWarning() << "LtsScreenContainer::setWidget: m_widget is not empty!!!";
|
|
|
|
//qWarning() << (quintptr)widget << "hier" << __LINE__;
|
|
|
|
*widgetPtr = widget;
|
|
reappear();
|
|
|
|
connect(widget, &QWidget::destroyed,
|
|
this, &LtsScreenContainer::slotChildDestroyed,
|
|
Qt::UniqueConnection);
|
|
|
|
if (tryPutDummyUnmanaged(widget))
|
|
return;
|
|
|
|
//qWarning() << "hier" << __LINE__;
|
|
|
|
//m_widget->setAutoFillBackground(true); // as the background itself is transparent
|
|
|
|
// qWarning() << "!!>>> B1" << m_widget << m_widget->parent();
|
|
m_layout->addWidget(widget);
|
|
// qWarning() << "!!>>> B2" << m_widget << m_widget->parent();
|
|
|
|
// qWarning() << "!!>>> B4" << m_widget << m_widget->parent();
|
|
// QMetaObject::invokeMethod(this, [currentWidget]
|
|
// {
|
|
// qWarning() << "!!>>> 4F" << w << w->parent();
|
|
// });
|
|
|
|
widget->show();
|
|
|
|
emit signalSetCornerIcons();
|
|
}
|
|
|
|
|
|
void LtsScreenContainer::slotChildDestroyed()
|
|
{
|
|
if (sender() == static_cast<QObject *>(m_mainWidget))
|
|
{
|
|
m_mainWidget = nullptr;
|
|
qWarning() << geoStr() << "m_mainWidget set to nullptr!";
|
|
|
|
if (*m_activeWidget == m_mainWidget) // switch to sec if not already sec
|
|
{
|
|
qWarning() << "slotChildDestroyed: switching to sec";
|
|
switchToTemp(LtsScreenBase::WidgetType::SecondaryWidget);
|
|
|
|
QWidget *widget = activeWidget();
|
|
|
|
if (widget != nullptr)
|
|
{
|
|
auto *dummy = qobject_cast<FullscreenVideoDummyWidget *>(widget);
|
|
if (dummy != nullptr)
|
|
{
|
|
QRect r(mapToGlobal(rect().topLeft()), rect().size());
|
|
qWarning() << geoStr() << "LtsScreenContainer::slotChildDestroyed => (main) dummy->signalWidgetPlaced";
|
|
emit dummy->signalWidgetPlaced(r);
|
|
}
|
|
else // in any other case it's sufficient to just hide the widget
|
|
{
|
|
widget->show();
|
|
}
|
|
}
|
|
|
|
finalizeSwitch();
|
|
}
|
|
}
|
|
else if (sender() == static_cast<QObject *>(m_secondaryWidget))
|
|
{
|
|
m_secondaryWidget = nullptr;
|
|
qWarning() << geoStr() << "m_secondaryWidget set to nullptr!";
|
|
|
|
if (*m_activeWidget == m_secondaryWidget) // switch to main if not already main
|
|
{
|
|
qWarning() << "slotChildDestroyed: switching to main";
|
|
switchToTemp(LtsScreenBase::WidgetType::MainWidget);
|
|
|
|
QWidget *widget = activeWidget();
|
|
|
|
if (widget != nullptr)
|
|
{
|
|
auto *dummy = qobject_cast<FullscreenVideoDummyWidget *>(widget);
|
|
if (dummy != nullptr)
|
|
{
|
|
QRect r(mapToGlobal(rect().topLeft()), rect().size());
|
|
qWarning() << geoStr() << "LtsScreenContainer::slotChildDestroyed => (sec) dummy->signalWidgetPlaced";
|
|
emit dummy->signalWidgetPlaced(r);
|
|
}
|
|
else // in any other case it's sufficient to just hide the widget
|
|
{
|
|
widget->show();
|
|
}
|
|
}
|
|
|
|
finalizeSwitch();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qWarning() << geoStr() << "slotChildDestroyed NOT received from any known widget !!";
|
|
Q_ASSERT(false);
|
|
}
|
|
|
|
vanish();
|
|
emit check();
|
|
}
|
|
|
|
|
|
QWidget *LtsScreenContainer::widget() noexcept(false)
|
|
{
|
|
QWidget **widgetPtr = m_activeWidget;
|
|
if (widgetPtr != nullptr && *widgetPtr != nullptr)
|
|
return *widgetPtr;
|
|
throw "no widget in container";
|
|
}
|
|
|
|
} // namespace LtsMultiMonitor
|