From d25c46521171a84df967131aa4348ee1c9d6d2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 17 Sep 2015 11:06:59 +0200 Subject: [PATCH] Move layer functionality to AbstractClient Merges together the code from ShellClient and Client and removes the starting differences. Long term it's better to have only one implementation to prevent diversions in the implementation. As it doesn't match exactly protected virtual methods are called which allow more specific implementations for a certain aspect of the layer resolving. --- abstract_client.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++++ abstract_client.h | 10 +++++-- client.cpp | 1 - client.h | 13 ++------ layers.cpp | 63 ++++++--------------------------------- shell_client.cpp | 45 ++++++++-------------------- shell_client.h | 2 +- 7 files changed, 105 insertions(+), 101 deletions(-) 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);