From a7f41f26bbed92c153d2b47fb4ad295713f2f8e6 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Fri, 26 May 2023 18:09:04 +0300 Subject: [PATCH] Make show desktop mode hide windows After porting the desktop background window to the layer-shell protocol, the desktop window is not raised up in the stack anymore when the showing desktop window is activated. The main reason to avoid this is to avoid fighting and overriding layer shell logic. As another way to implement the show desktop mode, this change makes the workspace hide windows that don't belong to desktop. It's a better solution for a couple of reasons: "keep above" and other overlay windows will be properly hidden and it lets us avoid touching the stacking order. BUG: 387593 BUG: 406101 BUG: 469827 --- src/activation.cpp | 5 + src/effects.cpp | 1 + src/effects.h | 1 + src/input.cpp | 4 +- src/internalwindow.cpp | 2 +- src/libkwineffects/kwinanimationeffect.cpp | 2 +- src/libkwineffects/kwineffects.h | 6 + .../eyeonscreen/package/contents/code/main.js | 103 ++++-------------- .../package/contents/code/main.js | 13 +-- src/scene/windowitem.cpp | 3 +- src/scripting/workspace_wrapper.cpp | 2 +- src/waylandwindow.cpp | 2 +- src/window.cpp | 31 ++++-- src/window.h | 7 +- src/workspace.cpp | 40 +++---- src/x11window.cpp | 31 +++--- src/x11window.h | 3 +- src/xdgshellwindow.cpp | 3 - 18 files changed, 103 insertions(+), 156 deletions(-) diff --git a/src/activation.cpp b/src/activation.cpp index d6fd5eebdd..36788018bd 100644 --- a/src/activation.cpp +++ b/src/activation.cpp @@ -289,6 +289,11 @@ void Workspace::activateWindow(Window *window, bool force) if (window->isDeleted()) { return; } + if (window->isHiddenByShowDesktop()) { + ++block_focus; + setShowingDesktop(false); + --block_focus; + } raiseWindow(window); if (!window->isOnCurrentDesktop()) { ++block_focus; diff --git a/src/effects.cpp b/src/effects.cpp index 0af8d30bad..b61b8166f7 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -1961,6 +1961,7 @@ WINDOW_HELPER(pid_t, pid, pid) WINDOW_HELPER(QUuid, internalId, internalId) WINDOW_HELPER(bool, isMinimized, isMinimized) WINDOW_HELPER(bool, isHidden, isHiddenInternal) +WINDOW_HELPER(bool, isHiddenByShowDesktop, isHiddenByShowDesktop) WINDOW_HELPER(bool, isModal, isModal) WINDOW_HELPER(bool, isFullScreen, isFullScreen) WINDOW_HELPER(bool, keepAbove, keepAbove) diff --git a/src/effects.h b/src/effects.h index ad7d7682a4..ceed49b507 100644 --- a/src/effects.h +++ b/src/effects.h @@ -374,6 +374,7 @@ public: bool isDeleted() const override; bool isMinimized() const override; bool isHidden() const override; + bool isHiddenByShowDesktop() const override; double opacity() const override; QStringList activities() const override; diff --git a/src/input.cpp b/src/input.cpp index 30445ef467..6d2816f716 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -2563,7 +2563,7 @@ private: if (!window->isClient()) { continue; } - if (!window->isOnCurrentActivity() || !window->isOnCurrentDesktop() || window->isMinimized() || window->isHiddenInternal()) { + if (!window->isOnCurrentActivity() || !window->isOnCurrentDesktop() || window->isMinimized() || window->isHiddenInternal() || window->isHiddenByShowDesktop()) { continue; } if (!window->readyForPainting()) { @@ -3203,7 +3203,7 @@ Window *InputRedirection::findToplevel(const QPointF &pos) // a deleted window doesn't get mouse events continue; } - if (!window->isOnCurrentActivity() || !window->isOnCurrentDesktop() || window->isMinimized() || window->isHiddenInternal()) { + if (!window->isOnCurrentActivity() || !window->isOnCurrentDesktop() || window->isMinimized() || window->isHiddenInternal() || window->isHiddenByShowDesktop()) { continue; } if (!window->readyForPainting()) { diff --git a/src/internalwindow.cpp b/src/internalwindow.cpp index d293cfbdcf..b3bdaebad2 100644 --- a/src/internalwindow.cpp +++ b/src/internalwindow.cpp @@ -244,7 +244,7 @@ bool InternalWindow::isOutline() const bool InternalWindow::isShown() const { - return readyForPainting(); + return readyForPainting() && !isHiddenByShowDesktop(); } bool InternalWindow::isHiddenInternal() const diff --git a/src/libkwineffects/kwinanimationeffect.cpp b/src/libkwineffects/kwinanimationeffect.cpp index b168c0679f..c92fc91e69 100644 --- a/src/libkwineffects/kwinanimationeffect.cpp +++ b/src/libkwineffects/kwinanimationeffect.cpp @@ -258,7 +258,7 @@ quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int AniData &animation = it->first.last(); animation.id = ret_id; - animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP | EffectWindow::PAINT_DISABLED_BY_DELETE); + animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP | EffectWindow::PAINT_DISABLED_BY_DELETE | EffectWindow::PAINT_DISABLED); animation.timeLine.setDirection(TimeLine::Forward); animation.timeLine.setDuration(std::chrono::milliseconds(ms)); animation.timeLine.setEasingCurve(curve); diff --git a/src/libkwineffects/kwineffects.h b/src/libkwineffects/kwineffects.h index bb7852b4a2..4de976d90e 100644 --- a/src/libkwineffects/kwineffects.h +++ b/src/libkwineffects/kwineffects.h @@ -2296,6 +2296,11 @@ class KWINEFFECTS_EXPORT EffectWindow : public QObject */ Q_PROPERTY(bool lockScreen READ isLockScreen CONSTANT) + /** + * Whether this EffectWindow is hidden because the show desktop mode is active. + */ + Q_PROPERTY(bool hiddenByShowDesktop READ isHiddenByShowDesktop) + public: /** Flags explaining why painting should be disabled */ enum { @@ -2325,6 +2330,7 @@ public: virtual bool isDeleted() const = 0; virtual bool isHidden() const = 0; + virtual bool isHiddenByShowDesktop() const = 0; virtual bool isMinimized() const = 0; virtual double opacity() const = 0; diff --git a/src/plugins/eyeonscreen/package/contents/code/main.js b/src/plugins/eyeonscreen/package/contents/code/main.js index 5c1ac7c8ca..7263029be3 100644 --- a/src/plugins/eyeonscreen/package/contents/code/main.js +++ b/src/plugins/eyeonscreen/package/contents/code/main.js @@ -15,30 +15,11 @@ var eyeOnScreenEffect = { loadConfig: function () { eyeOnScreenEffect.duration = animationTime(250); }, - delevateWindow: function(window) { - if (window.desktopWindow) { - if (window.eyeOnScreenShowsDesktop) { - window.eyeOnScreenShowsDesktop = false; - var stackingOrder = effects.stackingOrder; - for (var i = 0; i < stackingOrder.length; ++i) { - var w = stackingOrder[i]; - if (w.eyeOnScreenOpacityKeeper === undefined) - continue; - cancel(w.eyeOnScreenOpacityKeeper); - delete w.eyeOnScreenOpacityKeeper; - } - } - } else if (window.elevatedByEyeOnScreen) { - effects.setElevatedWindow(window, false); - window.elevatedByEyeOnScreen = false; - } - }, slurp: function (showing) { var stackingOrder = effects.stackingOrder; var screenGeo = effects.virtualScreenGeometry; var center = { value1: screenGeo.x + screenGeo.width/2, value2: screenGeo.y + screenGeo.height/2 }; - var screenNum = 0; for (var i = 0; i < stackingOrder.length; ++i) { var w = stackingOrder[i]; if (!w.visible || !(showing || w.slurpedByEyeOnScreen)) { @@ -63,80 +44,43 @@ var eyeOnScreenEffect = { to: 0.0 }] }); - ++screenNum; - if (showing && screenNum >= effects.numScreens) // (when not showing, pretty much everything would be above) - break; // ignore windows above the desktop } else { - effects.setElevatedWindow(w, showing); if (showing) { - w.elevatedByEyeOnScreen = true; - if (w.dock) { - animate({ - // this is a HACK - we need to trigger an animationEnded to delevate the dock in time, or it'll flicker :-( - // TODO? "var timer = new QTimer;" causes an error in effect scripts - window: w, - animations: [{ - type: Effect.Opacity, - curve: QEasingCurve.Linear, - duration: eyeOnScreenEffect.duration, - to: 0.9 - }] - }); - } else { - animate({ - window: w, - animations: [{ - type: Effect.Scale, - curve: QEasingCurve.InCubic, - duration: eyeOnScreenEffect.duration, - to: 0.0 - }, { - type: Effect.Position, - curve: QEasingCurve.InCubic, - duration: eyeOnScreenEffect.duration, - to: center - }] - }); - } - w.eyeOnScreenOpacityKeeper = set({ + animate({ window: w, animations: [{ - type: Effect.Opacity, - curve: QEasingCurve.InCubic, - duration: eyeOnScreenEffect.duration, - to: 0.0 + type: Effect.Scale, + curve: QEasingCurve.InCubic, + duration: eyeOnScreenEffect.duration, + to: 0.0 + }, { + type: Effect.Position, + curve: QEasingCurve.InCubic, + duration: eyeOnScreenEffect.duration, + to: center + }, { + type: Effect.Opacity, + curve: QEasingCurve.InCubic, + duration: eyeOnScreenEffect.duration, + to: 0.0 }] }); } else { - w.elevatedByEyeOnScreen = false; - if (!w.dock) { - animate({ - window: w, - duration: eyeOnScreenEffect.duration, - delay: eyeOnScreenEffect.duration, - animations: [{ - type: Effect.Scale, - curve: QEasingCurve.OutCubic, - from: 0.0 - }, { - type: Effect.Position, - curve: QEasingCurve.OutCubic, - from: center - }] - }); - } - if (w.eyeOnScreenOpacityKeeper !== undefined) { - cancel(w.eyeOnScreenOpacityKeeper); - delete w.eyeOnScreenOpacityKeeper; - } animate({ window: w, duration: eyeOnScreenEffect.duration, delay: eyeOnScreenEffect.duration, animations: [{ + type: Effect.Scale, + curve: QEasingCurve.OutCubic, + from: 0.0 + }, { + type: Effect.Position, + curve: QEasingCurve.OutCubic, + from: center + }, { type: Effect.Opacity, curve: QEasingCurve.OutCubic, - duration: eyeOnScreenEffect.duration, from: 0.0 }] }); @@ -147,7 +91,6 @@ var eyeOnScreenEffect = { init: function () { eyeOnScreenEffect.loadConfig(); effects.showingDesktopChanged.connect(eyeOnScreenEffect.slurp); - effect.animationEnded.connect(eyeOnScreenEffect.delevateWindow); } }; diff --git a/src/plugins/windowaperture/package/contents/code/main.js b/src/plugins/windowaperture/package/contents/code/main.js index e06b6982a2..ed34dd4a72 100644 --- a/src/plugins/windowaperture/package/contents/code/main.js +++ b/src/plugins/windowaperture/package/contents/code/main.js @@ -33,20 +33,14 @@ var badBadWindowsEffect = { for (var i = 0; i < stackingOrder.length; ++i) { var w = stackingOrder[i]; - // ignore windows above the desktop - // (when not showing, pretty much everything would be) - if (w.desktopWindow) { - if (frozenTime <= 0) - break - else - continue; + if (!w.hiddenByShowDesktop) { + continue; } // ignore invisible windows and such that do not have to be restored if (!w.visible) { if (w.offToCornerId) { // if it was visible when the effect was activated delete its animation data - effects.setElevatedWindow(w, false); cancel(w.offToCornerId); delete w.offToCornerId; delete w.apertureCorner; @@ -123,9 +117,6 @@ var badBadWindowsEffect = { if (w.apertureCorner === undefined && w.offToCornerId === undefined) continue; - // keep windows above the desktop visually - effects.setElevatedWindow(w, showing); - if (w.dock) { continue; } diff --git a/src/scene/windowitem.cpp b/src/scene/windowitem.cpp index 5a272518f5..06ad55f4ed 100644 --- a/src/scene/windowitem.cpp +++ b/src/scene/windowitem.cpp @@ -41,6 +41,7 @@ WindowItem::WindowItem(Window *window, Scene *scene, Item *parent) connect(window, &Window::lockScreenOverlayChanged, this, &WindowItem::updateVisibility); connect(window, &Window::minimizedChanged, this, &WindowItem::updateVisibility); connect(window, &Window::hiddenChanged, this, &WindowItem::updateVisibility); + connect(window, &Window::hiddenByShowDesktopChanged, this, &WindowItem::updateVisibility); connect(window, &Window::activitiesChanged, this, &WindowItem::updateVisibility); connect(window, &Window::desktopsChanged, this, &WindowItem::updateVisibility); connect(workspace(), &Workspace::currentActivityChanged, this, &WindowItem::updateVisibility); @@ -169,7 +170,7 @@ bool WindowItem::computeVisibility() const return false; } } - if (m_window->isHiddenInternal()) { + if (m_window->isHiddenInternal() || m_window->isHiddenByShowDesktop()) { if (m_forceVisibleByHiddenCount == 0) { return false; } diff --git a/src/scripting/workspace_wrapper.cpp b/src/scripting/workspace_wrapper.cpp index c29c229c34..05241a8a03 100644 --- a/src/scripting/workspace_wrapper.cpp +++ b/src/scripting/workspace_wrapper.cpp @@ -317,7 +317,7 @@ QList WorkspaceWrapper::windowAt(const QPointF &pos, int count) if (window->isDeleted()) { continue; } - if (!window->isOnCurrentActivity() || !window->isOnCurrentDesktop() || window->isMinimized() || window->isHiddenInternal()) { + if (!window->isOnCurrentActivity() || !window->isOnCurrentDesktop() || window->isMinimized() || window->isHiddenInternal() || window->isHiddenByShowDesktop()) { continue; } if (window->hitTest(pos)) { diff --git a/src/waylandwindow.cpp b/src/waylandwindow.cpp index 03a951c9af..b07bd2a1bd 100644 --- a/src/waylandwindow.cpp +++ b/src/waylandwindow.cpp @@ -240,7 +240,7 @@ void WaylandWindow::cleanGrouping() bool WaylandWindow::isShown() const { - return !isDeleted() && !isHidden() && !isMinimized(); + return !isDeleted() && !isHidden() && !isHiddenByShowDesktop() && !isMinimized(); } bool WaylandWindow::isHiddenInternal() const diff --git a/src/window.cpp b/src/window.cpp index ff86301c74..702f1bb468 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -572,11 +572,6 @@ void Window::updateLayer() Layer Window::belongsToLayer() const { - // NOTICE while showingDesktop, desktops move to the AboveLayer - // (interchangeable w/ eg. yakuake etc. which will at first remain visible) - // and the docks move into the NotificationLayer (which is between Above- and - // ActiveLayer, so that active fullscreen windows will still cover everything) - // Since the desktop is also activated, nothing should be in the ActiveLayer, though if (isUnmanaged() || isInternal()) { return UnmanagedLayer; } @@ -590,15 +585,12 @@ Layer Window::belongsToLayer() const return UnmanagedLayer; } if (isDesktop()) { - return workspace()->showingDesktop() ? AboveLayer : DesktopLayer; + return DesktopLayer; } if (isSplash()) { // no damn annoying splashscreens return NormalLayer; // getting in the way of everything else } if (isDock() || isAppletPopup()) { - if (workspace()->showingDesktop()) { - return NotificationLayer; - } return layerForDock(); } if (isPopupWindow()) { @@ -613,9 +605,6 @@ Layer Window::belongsToLayer() const if (isCriticalNotification()) { return CriticalNotificationLayer; } - if (workspace()->showingDesktop() && belongsToDesktop()) { - return AboveLayer; - } if (keepBelow()) { return BelowLayer; } @@ -3578,6 +3567,10 @@ void Window::doSetQuickTileMode() { } +void Window::doSetHiddenByShowDesktop() +{ +} + QRectF Window::moveToArea(const QRectF &geometry, const QRectF &oldArea, const QRectF &newArea) { QRectF ret = geometry; @@ -4221,6 +4214,20 @@ WindowOffscreenRenderRef::~WindowOffscreenRenderRef() } } +bool Window::isHiddenByShowDesktop() const +{ + return m_hiddenByShowDesktop; +} + +void Window::setHiddenByShowDesktop(bool hidden) +{ + if (m_hiddenByShowDesktop != hidden) { + m_hiddenByShowDesktop = hidden; + doSetHiddenByShowDesktop(); + Q_EMIT hiddenByShowDesktopChanged(); + } +} + } // namespace KWin #include "moc_window.cpp" diff --git a/src/window.h b/src/window.h index 9fd10cdb63..7dfbc5dde5 100644 --- a/src/window.h +++ b/src/window.h @@ -936,6 +936,8 @@ public: virtual bool isHiddenInternal() const = 0; virtual void hideClient() = 0; virtual void showClient() = 0; + bool isHiddenByShowDesktop() const; + void setHiddenByShowDesktop(bool hidden); // TODO: remove boolean trap virtual Window *findModal(bool allow_itself = false) = 0; virtual bool isTransient() const; @@ -1238,6 +1240,7 @@ public: }; Q_DECLARE_FLAGS(SameApplicationChecks, SameApplicationCheck) static bool belongToSameApplication(const Window *c1, const Window *c2, SameApplicationChecks checks = SameApplicationChecks()); + virtual bool belongsToDesktop() const; bool hasApplicationMenu() const; bool applicationMenuActive() const @@ -1421,6 +1424,7 @@ Q_SIGNALS: void unresponsiveChanged(bool); void decorationChanged(); void hiddenChanged(); + void hiddenByShowDesktopChanged(); void lockScreenOverlayChanged(); protected: @@ -1498,6 +1502,7 @@ protected: virtual void doSetSkipSwitcher(); virtual void doSetDemandsAttention(); virtual void doSetQuickTileMode(); + virtual void doSetHiddenByShowDesktop(); void setupWindowManagementInterface(); void destroyWindowManagementInterface(); @@ -1506,7 +1511,6 @@ protected: void handlePaletteChange(); virtual Layer belongsToLayer() const; - virtual bool belongsToDesktop() const; bool isActiveFullScreen() const; virtual Layer layerForDock() const; @@ -1720,6 +1724,7 @@ protected: QRectF m_clientGeometry; QRectF m_bufferGeometry; bool ready_for_painting; + bool m_hiddenByShowDesktop = false; int m_refCount = 1; QUuid m_internalId; diff --git a/src/workspace.cpp b/src/workspace.cpp index 0cfd93a3f0..a43bbbfcba 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -1534,34 +1534,22 @@ void Workspace::setShowingDesktop(bool showing, bool animated) } showing_desktop = showing; - Window *topDesk = nullptr; - - { // for the blocker RAII - StackingUpdatesBlocker blocker(this); // updateLayer & lowerWindow would invalidate stacking_order - for (int i = stacking_order.count() - 1; i > -1; --i) { - auto window = stacking_order.at(i); - if (window->isClient() && window->isOnCurrentDesktop()) { - if (window->isDock()) { - window->updateLayer(); - } else if (window->isDesktop() && window->isShown()) { - window->updateLayer(); - lowerWindow(window); - if (!topDesk) { - topDesk = window; - } - if (auto group = window->group()) { - const auto members = group->members(); - for (X11Window *cm : members) { - cm->updateLayer(); - } - } - } - } + for (int i = stacking_order.count() - 1; i > -1; --i) { + auto window = stacking_order.at(i); + if (window->isDeleted() || window->isUnmanaged()) { + continue; } - } // ~StackingUpdatesBlocker + if (window->isDock() || window->isDesktop() || window->belongsToDesktop()) { + continue; + } + window->setHiddenByShowDesktop(showing_desktop); + } - if (showing_desktop && topDesk) { - requestFocus(topDesk); + if (showing_desktop) { + Window *desktop = findDesktop(true, VirtualDesktopManager::self()->currentDesktop()); + if (desktop) { + requestFocus(desktop); + } } else if (!showing_desktop && changed) { const auto window = m_focusChain->getForActivation(VirtualDesktopManager::self()->currentDesktop()); if (window) { diff --git a/src/x11window.cpp b/src/x11window.cpp index f0f3c83caf..82ab77f682 100644 --- a/src/x11window.cpp +++ b/src/x11window.cpp @@ -1823,6 +1823,17 @@ void X11Window::updateVisibility() } return; } + if (isHiddenByShowDesktop()) { + if (waylandServer()) { + return; + } + if (Compositor::compositing() && options->hiddenPreviews() != HiddenPreviewsNever) { + internalKeep(); + } else { + internalHide(); + } + return; + } setSkipTaskbar(originalSkipTaskbar()); // Reset from 'hidden' if (isMinimized()) { info->setState(NET::Hidden, NET::Hidden); @@ -2184,6 +2195,11 @@ void X11Window::doSetDemandsAttention() info->setState(isDemandingAttention() ? NET::DemandsAttention : NET::States(), NET::DemandsAttention); } +void X11Window::doSetHiddenByShowDesktop() +{ + updateVisibility(); +} + void X11Window::doSetOnActivities(const QStringList &activityList) { #if KWIN_BUILD_ACTIVITIES @@ -2240,21 +2256,6 @@ bool X11Window::takeFocus() sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus); } workspace()->setShouldGetFocus(this); - - bool breakShowingDesktop = !keepAbove(); - if (breakShowingDesktop) { - const auto members = group()->members(); - for (const X11Window *c : members) { - if (c->isDesktop()) { - breakShowingDesktop = false; - break; - } - } - } - if (breakShowingDesktop) { - workspace()->setShowingDesktop(false); - } - return true; } diff --git a/src/x11window.h b/src/x11window.h index c602628796..646889500f 100644 --- a/src/x11window.h +++ b/src/x11window.h @@ -343,6 +343,7 @@ protected: void doSetSkipTaskbar() override; void doSetSkipSwitcher() override; void doSetDemandsAttention() override; + void doSetHiddenByShowDesktop() override; bool belongsToDesktop() const override; bool doStartInteractiveMoveResize() override; bool isWaitingForInteractiveMoveResizeSync() const override; @@ -585,7 +586,7 @@ inline Group *X11Window::group() inline bool X11Window::isShown() const { - return !isMinimized() && !hidden; + return !isMinimized() && !hidden && !isHiddenByShowDesktop(); } inline bool X11Window::isHiddenInternal() const diff --git a/src/xdgshellwindow.cpp b/src/xdgshellwindow.cpp index 918599c90c..2d6ba9f95c 100644 --- a/src/xdgshellwindow.cpp +++ b/src/xdgshellwindow.cpp @@ -836,9 +836,6 @@ bool XdgToplevelWindow::takeFocus() sendPing(PingReason::FocusWindow); setActive(true); } - if (!keepAbove() && !isOnScreenDisplay() && !belongsToDesktop()) { - workspace()->setShowingDesktop(false); - } return true; }