diff --git a/abstract_client.cpp b/abstract_client.cpp index 5befc37839..dc6a312547 100644 --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -189,8 +189,17 @@ void AbstractClient::doSetActive() { } +Layer AbstractClient::layer() const +{ + if (m_layer == UnknownLayer) + const_cast< AbstractClient* >(this)->m_layer = belongsToLayer(); + return m_layer; +} + void AbstractClient::updateLayer() { + if (layer() == belongsToLayer()) + return; StackingUpdatesBlocker blocker(workspace()); invalidateLayer(); // invalidate, will be updated when doing restacking for (auto it = transients().constBegin(), @@ -200,6 +209,57 @@ void AbstractClient::updateLayer() void AbstractClient::invalidateLayer() { + m_layer = UnknownLayer; +} + +Layer AbstractClient::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 (isDesktop()) + return workspace()->showingDesktop() ? AboveLayer : DesktopLayer; + if (isSplash()) // no damn annoying splashscreens + return NormalLayer; // getting in the way of everything else + if (isDock()) { + if (workspace()->showingDesktop()) + return NotificationLayer; + return layerForDock(); + } + if (isOnScreenDisplay()) + return OnScreenDisplayLayer; + if (isNotification()) + return NotificationLayer; + if (workspace()->showingDesktop() && belongsToDesktop()) { + return AboveLayer; + } + if (keepBelow()) + return BelowLayer; + if (isActiveFullScreen()) + return ActiveLayer; + if (keepAbove()) + return AboveLayer; + + return NormalLayer; +} + +bool AbstractClient::belongsToDesktop() const +{ + return false; +} + +Layer AbstractClient::layerForDock() const +{ + // slight hack for the 'allow window to cover panel' Kicker setting + // don't move keepbelow docks below normal window, but only to the same + // layer, so that both may be raised to cover the other + if (keepBelow()) + return NormalLayer; + if (keepAbove()) // slight hack for the autohiding panels + return AboveLayer; + return DockLayer; } void AbstractClient::setKeepAbove(bool b) @@ -909,4 +969,16 @@ void AbstractClient::removeTransientFromList(AbstractClient *cl) m_transients.removeAll(cl); } +bool AbstractClient::isActiveFullScreen() const +{ + if (!isFullScreen()) + return false; + + const auto ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker + // according to NETWM spec implementation notes suggests + // "focused windows having state _NET_WM_STATE_FULLSCREEN" to be on the highest layer. + // we'll also take the screen into account + return ac && (ac == this || ac->screen() != screen()); +} + } diff --git a/abstract_client.h b/abstract_client.h index d0468f7558..fdcf2eea72 100644 --- a/abstract_client.h +++ b/abstract_client.h @@ -384,7 +384,8 @@ public: * @param mode The tile mode (left/right) to give this window. */ virtual void setQuickTileMode(QuickTileMode mode, bool keyboard = false) = 0; - virtual void updateLayer(); + Layer layer() const override; + void updateLayer(); enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet }; virtual void move(int x, int y, ForceGeometry_t force = NormalGeometrySet) = 0; @@ -505,7 +506,11 @@ protected: **/ void removeTransientFromList(AbstractClient* cl); - virtual void invalidateLayer(); + Layer belongsToLayer() const; + virtual bool belongsToDesktop() const; + void invalidateLayer(); + virtual bool isActiveFullScreen() const; + virtual Layer layerForDock() const; private: void handlePaletteChange(); @@ -537,6 +542,7 @@ private: AbstractClient *m_transientFor = nullptr; QList m_transients; bool m_modal = false; + Layer m_layer = UnknownLayer; }; inline void AbstractClient::move(const QPoint& p, ForceGeometry_t force) diff --git a/client.cpp b/client.cpp index ca05c58210..71c80f7d43 100644 --- a/client.cpp +++ b/client.cpp @@ -116,7 +116,6 @@ Client::Client() , m_colormap(XCB_COLORMAP_NONE) , in_group(NULL) , tab_group(NULL) - , in_layer(UnknownLayer) , ping_timer(NULL) , m_killHelperPID(0) , m_pingTimestamp(XCB_TIME_CURRENT_TIME) diff --git a/client.h b/client.h index 593d622e75..bb1d0e324b 100644 --- a/client.h +++ b/client.h @@ -251,7 +251,6 @@ public: bool isFullScreen() const override; bool isFullScreenable() const override; bool isFullScreenable(bool fullscreen_hack) const; - bool isActiveFullScreen() const; bool userCanSetFullScreen() const override; QRect geometryFSRestore() const { return geom_fs_restore; // Only for session saving @@ -265,9 +264,6 @@ public: bool userCanSetNoBorder() const override; void checkNoBorder(); - virtual Layer layer() const; - Layer belongsToLayer() const; - void updateLayer() override; int sessionStackingOrder() const; // Auxiliary functions, depend on the windowType @@ -520,7 +516,8 @@ protected: void doMinimize() override; void doSetSkipPager() override; void doSetSkipTaskbar() override; - void invalidateLayer() override; + bool belongsToDesktop() const override; + bool isActiveFullScreen() const override; private Q_SLOTS: void delayedSetShortcut(); @@ -734,7 +731,6 @@ private: QString cap_normal, cap_iconic, cap_suffix, cap_deco; Group* in_group; TabGroup* tab_group; - Layer in_layer; QTimer* ping_timer; qint64 m_killHelperPID; xcb_timestamp_t m_pingTimestamp; @@ -894,11 +890,6 @@ inline xcb_colormap_t Client::colormap() const return m_colormap; } -inline void Client::invalidateLayer() -{ - in_layer = UnknownLayer; -} - inline int Client::sessionStackingOrder() const { return sm_stacking_order; diff --git a/layers.cpp b/layers.cpp index 6113ebab49..cd3c2b3d18 100644 --- a/layers.cpp +++ b/layers.cpp @@ -820,61 +820,13 @@ void Client::doSetKeepBelow() tabGroup()->updateStates(this, TabGroup::Layer); } -Layer Client::layer() const +bool Client::belongsToDesktop() const { - if (in_layer == UnknownLayer) - const_cast< Client* >(this)->in_layer = belongsToLayer(); - return in_layer; -} - -Layer Client::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 (isDesktop()) - return workspace()->showingDesktop() ? AboveLayer : DesktopLayer; - if (isSplash()) // no damn annoying splashscreens - return NormalLayer; // getting in the way of everything else - if (isDock()) { - if (workspace()->showingDesktop()) - return NotificationLayer; - // slight hack for the 'allow window to cover panel' Kicker setting - // don't move keepbelow docks below normal window, but only to the same - // layer, so that both may be raised to cover the other - if (keepBelow()) - return NormalLayer; - if (keepAbove()) // slight hack for the autohiding panels - return AboveLayer; - return DockLayer; + foreach (const Client *c, group()->members()) { + if (c->isDesktop()) + return true; } - if (isOnScreenDisplay()) - return OnScreenDisplayLayer; - if (isNotification()) - return NotificationLayer; - if (workspace()->showingDesktop()) { - foreach (const Client *c, group()->members()) { - if (c->isDesktop()) - return AboveLayer; - } - } - if (keepBelow()) - return BelowLayer; - if (isActiveFullScreen()) - return ActiveLayer; - if (keepAbove()) - return AboveLayer; - - return NormalLayer; -} - -void Client::updateLayer() -{ - if (layer() == belongsToLayer()) - return; - AbstractClient::updateLayer(); + return false; } bool rec_checkTransientOnTop(const QList &transients, const Client *topmost) @@ -889,6 +841,9 @@ bool rec_checkTransientOnTop(const QList &transients, const Cli bool Client::isActiveFullScreen() const { + if (AbstractClient::isActiveFullScreen()) { + return true; + } if (!isFullScreen()) return false; @@ -896,7 +851,7 @@ bool Client::isActiveFullScreen() const // according to NETWM spec implementation notes suggests // "focused windows having state _NET_WM_STATE_FULLSCREEN" to be on the highest layer. // we'll also take the screen into account - return ac && (ac == this || this->group() == ac->group() || ac->screen() != screen()); + return ac && (this->group() == ac->group()); } } // namespace diff --git a/shell_client.cpp b/shell_client.cpp index f4d9260002..2784eb2f4f 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -148,42 +148,23 @@ void ShellClient::debug(QDebug &stream) const Q_UNUSED(stream) } -Layer ShellClient::layer() const +Layer ShellClient::layerForDock() const { - // TODO: implement the rest - if (isDesktop()) - return workspace()->showingDesktop() ? AboveLayer : DesktopLayer; - if (isDock()) { - if (workspace()->showingDesktop()) - return NotificationLayer; - if (m_plasmaShellSurface) { - switch (m_plasmaShellSurface->panelBehavior()) { - case PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover: - return NormalLayer; - case PlasmaShellSurfaceInterface::PanelBehavior::AutoHide: - return AboveLayer; - case PlasmaShellSurfaceInterface::PanelBehavior::WindowsGoBelow: - case PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible: - return DockLayer; - default: - Q_UNREACHABLE(); - break; - } - } - // slight hack for the 'allow window to cover panel' Kicker setting - // don't move keepbelow docks below normal window, but only to the same - // layer, so that both may be raised to cover the other - if (keepBelow()) + if (m_plasmaShellSurface) { + switch (m_plasmaShellSurface->panelBehavior()) { + case PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover: return NormalLayer; - if (keepAbove()) // slight hack for the autohiding panels + case PlasmaShellSurfaceInterface::PanelBehavior::AutoHide: return AboveLayer; - return DockLayer; + case PlasmaShellSurfaceInterface::PanelBehavior::WindowsGoBelow: + case PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible: + return DockLayer; + default: + Q_UNREACHABLE(); + break; + } } - if (isOnScreenDisplay()) - return OnScreenDisplayLayer; - if (isFullScreen() && isActive()) - return ActiveLayer; - return KWin::NormalLayer; + return AbstractClient::layerForDock(); } bool ShellClient::shouldUnredirect() const diff --git a/shell_client.h b/shell_client.h index cf770531ad..fa64253a4f 100644 --- a/shell_client.h +++ b/shell_client.h @@ -45,7 +45,6 @@ public: QStringList activities() const override; QPoint clientPos() const override; QSize clientSize() const override; - Layer layer() const override; QRect transparentRect() const override; bool shouldUnredirect() const override; NET::WindowType windowType(bool direct = false, int supported_types = 0) const override; @@ -119,6 +118,7 @@ protected: void addDamage(const QRegion &damage) override; bool belongsToSameApplication(const AbstractClient *other, bool active_hack) const override; void doSetActive() override; + Layer layerForDock() const override; private Q_SLOTS: void clientFullScreenChanged(bool fullScreen);