#include "lts_screen_container.h" #include "lts_dummy_widget.h" #include #include #include #include #include #include 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(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(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(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(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(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(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(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(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(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(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