From ca83433ce0a2bf67decb66bc9e0620830c9884a4 Mon Sep 17 00:00:00 2001 From: Michail Vourlakos Date: Sun, 12 Dec 2021 14:34:28 +0200 Subject: [PATCH] multiscreen:disable struts under x11 when overlap --when multiple screens placement have edges that overlap with each other, at that edges struts must be disabled to provide much better windows behavior. For example when dragging a window between such screens and there is an AlwaysVisible panel or dock between them. BUG:445595 FIXED-IN:0.10.5 --- app/screenpool.cpp | 2 + app/screenpool.h | 1 + app/view/visibilitymanager.cpp | 75 ++++++++++++++++++++++++++++++---- app/view/visibilitymanager.h | 4 +- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/app/screenpool.cpp b/app/screenpool.cpp index fd235d85d..9ae99225a 100644 --- a/app/screenpool.cpp +++ b/app/screenpool.cpp @@ -129,6 +129,8 @@ void ScreenPool::updateScreenGeometry(const int &screenId, const QRect &screenGe m_screensTable[scrIdStr].geometry = screenGeometry; save(); + + emit screenGeometryChanged(); } diff --git a/app/screenpool.h b/app/screenpool.h index ee25a2bf5..6003f6f32 100644 --- a/app/screenpool.h +++ b/app/screenpool.h @@ -53,6 +53,7 @@ public: signals: void primaryPoolChanged(); + void screenGeometryChanged(); protected: bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; diff --git a/app/view/visibilitymanager.cpp b/app/view/visibilitymanager.cpp index d34d88368..9fb208f14 100644 --- a/app/view/visibilitymanager.cpp +++ b/app/view/visibilitymanager.cpp @@ -270,7 +270,10 @@ void VisibilityManager::setMode(Latte::Types::Visibility mode) } }); - m_connections[base+3] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() { + //! respect canSetStrut that must be disabled under x11 when an alwaysvisible screen edge is common between two or more screens + m_connections[base+3] = connect(m_corona->screenPool(), &Latte::ScreenPool::screenGeometryChanged, this, &VisibilityManager::updateStrutsAfterTimer); + + m_connections[base+4] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() { updateStrutsBasedOnLayoutsAndActivities(true); }); @@ -397,10 +400,10 @@ void VisibilityManager::updateSidebarState() void VisibilityManager::updateStrutsBasedOnLayoutsAndActivities(bool forceUpdate) { bool inMultipleLayoutsAndCurrent = (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts - && m_latteView->layout() && !m_latteView->positioner()->inRelocationAnimation() - && m_latteView->layout()->isCurrent()); + && m_latteView->layout() && !m_latteView->positioner()->inRelocationAnimation() + && m_latteView->layout()->isCurrent()); - if (m_strutsThickness>0 && (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::SingleLayout || inMultipleLayoutsAndCurrent)) { + if (m_strutsThickness>0 && canSetStrut() && (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::SingleLayout || inMultipleLayoutsAndCurrent)) { QRect computedStruts = acceptableStruts(); if (m_publishedStruts != computedStruts || forceUpdate) { //! Force update is needed when very important events happen in DE and there is a chance @@ -417,6 +420,64 @@ void VisibilityManager::updateStrutsBasedOnLayoutsAndActivities(bool forceUpdate } } +bool VisibilityManager::canSetStrut() const +{ + if (!KWindowSystem::isPlatformX11()) { + return true; + } + + // read the wm name, need to do this every time which means a roundtrip unfortunately + // but WM might have changed + //NETRootInfo rootInfo(QX11Info::connection(), NET::Supported | NET::SupportingWMCheck); + //if (qstricmp(rootInfo.wmName(), "KWin") == 0) { + // KWin since 5.7 can handle this fine, so only exclude for other window managers + //return true; + //} + + if (qGuiApp->screens().count() < 2) { + return true; + } + + const QRect thisScreen = m_latteView->screen()->geometry(); + + // Extended struts against a screen edge near to another screen are really harmful, so windows maximized under the panel is a lesser pain + // TODO: force "windows can cover" in those cases? + for (QScreen *screen : qGuiApp->screens()) { + if (!screen || m_latteView->screen() == screen) { + continue; + } + + const QRect otherScreen = screen->geometry(); + + switch (m_latteView->location()) { + case Plasma::Types::TopEdge: + if (otherScreen.bottom() <= thisScreen.top()) { + return false; + } + break; + case Plasma::Types::BottomEdge: + if (otherScreen.top() >= thisScreen.bottom()) { + return false; + } + break; + case Plasma::Types::RightEdge: + if (otherScreen.left() >= thisScreen.right()) { + return false; + } + break; + case Plasma::Types::LeftEdge: + if (otherScreen.right() <= thisScreen.left()) { + return false; + } + break; + default: + return false; + } + } + + return true; +} + QRect VisibilityManager::acceptableStruts() { QRect calcs; @@ -725,9 +786,9 @@ void VisibilityManager::toggleHiddenState() { if (!m_latteView->inEditMode()) { if (isSidebar()) { - // if (m_blockHidingEvents.contains(Q_FUNC_INFO)) { + // if (m_blockHidingEvents.contains(Q_FUNC_INFO)) { // removeBlockHidingEvent(Q_FUNC_INFO); - // } + // } if (m_mode == Latte::Types::SidebarOnDemand) { m_isRequestedShownSidebarOnDemand = !m_isRequestedShownSidebarOnDemand; @@ -741,7 +802,7 @@ void VisibilityManager::toggleHiddenState() } } } else { - /* if (!m_isHidden && !m_blockHidingEvents.contains(Q_FUNC_INFO)) { + /* if (!m_isHidden && !m_blockHidingEvents.contains(Q_FUNC_INFO)) { addBlockHidingEvent(Q_FUNC_INFO); } else if (m_isHidden) { removeBlockHidingEvent(Q_FUNC_INFO); diff --git a/app/view/visibilitymanager.h b/app/view/visibilitymanager.h index 1d9da2a7a..8c640af7c 100644 --- a/app/view/visibilitymanager.h +++ b/app/view/visibilitymanager.h @@ -211,10 +211,12 @@ private slots: private: void startTimerHide(const int &msec = 0); + bool canSetStrut() const; + private: WindowSystem::AbstractWindowInterface *m_wm; Types::Visibility m_mode{Types::None}; - std::array m_connections; + std::array m_connections; QTimer m_timerShow; QTimer m_timerHide;