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
This commit is contained in:
Vlad Zahorodnii 2023-05-26 18:09:04 +03:00
parent bc43be9c00
commit a7f41f26bb
18 changed files with 103 additions and 156 deletions

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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()) {

View file

@ -244,7 +244,7 @@ bool InternalWindow::isOutline() const
bool InternalWindow::isShown() const
{
return readyForPainting();
return readyForPainting() && !isHiddenByShowDesktop();
}
bool InternalWindow::isHiddenInternal() const

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
};

View file

@ -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;
}

View file

@ -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;
}

View file

@ -317,7 +317,7 @@ QList<KWin::Window *> 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)) {

View file

@ -240,7 +240,7 @@ void WaylandWindow::cleanGrouping()
bool WaylandWindow::isShown() const
{
return !isDeleted() && !isHidden() && !isMinimized();
return !isDeleted() && !isHidden() && !isHiddenByShowDesktop() && !isMinimized();
}
bool WaylandWindow::isHiddenInternal() const

View file

@ -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"

View file

@ -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;

View file

@ -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) {

View file

@ -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;
}

View file

@ -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

View file

@ -836,9 +836,6 @@ bool XdgToplevelWindow::takeFocus()
sendPing(PingReason::FocusWindow);
setActive(true);
}
if (!keepAbove() && !isOnScreenDisplay() && !belongsToDesktop()) {
workspace()->setShowingDesktop(false);
}
return true;
}