diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 263d77a9f..73dd8bb88 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -1,185 +1,186 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kwin_effects\" -DEFFECT_BUILTINS) include_directories(${KWIN_SOURCE_DIR}) # for xcbutils.h set(kwin_effect_OWN_LIBS kwineffects ) if( KWIN_HAVE_XRENDER_COMPOSITING ) set(kwin_effect_OWN_LIBS ${kwin_effect_OWN_LIBS} kwinxrenderutils) endif() set(kwin_effect_KDE_LIBS KF5::ConfigGui KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::WindowSystem KF5::Plasma # screenedge effect KF5::IconThemes KF5::Service ) set(kwin_effect_QT_LIBS Qt5::Concurrent Qt5::DBus Qt5::Quick Qt5::X11Extras ) set(kwin_effect_XLIB_LIBS ${X11_X11_LIB} ) set(kwin_effect_XCB_LIBS XCB::XCB XCB::IMAGE XCB::XFIXES ) if( KWIN_HAVE_XRENDER_COMPOSITING ) set(kwin_effect_XCB_LIBS ${kwin_effect_XCB_LIBS} XCB::RENDER) endif() set(kwin_effect_OWN_LIBS ${kwin_effect_OWN_LIBS} kwinglutils) macro( KWIN4_ADD_EFFECT_BACKEND name ) add_library( ${name} SHARED ${ARGN} ) target_link_libraries( ${name} PRIVATE ${kwin_effect_OWN_LIBS} ${kwin_effect_KDE_LIBS} ${kwin_effect_QT_LIBS} ${kwin_effect_XLIB_LIBS} ${kwin_effect_XCB_LIBS}) endmacro() # Adds effect plugin with given name. Sources are given after the name macro( KWIN4_ADD_EFFECT name ) kwin4_add_effect_backend(kwin4_effect_${name} ${ARGN}) set_target_properties(kwin4_effect_${name} PROPERTIES VERSION 1.0.0 SOVERSION 1 ) set_target_properties(kwin4_effect_${name} PROPERTIES OUTPUT_NAME ${KWIN_NAME}4_effect_${name}) install(TARGETS kwin4_effect_${name} ${INSTALL_TARGETS_DEFAULT_ARGS} ) endmacro() # Install the KWin/Effect service type install( FILES kwineffect.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} ) # Create initial variables set( kwin4_effect_include_directories ) set( kwin4_effect_builtins_sources logging.cpp effect_builtins.cpp blur/blur.cpp blur/blurshader.cpp cube/cube.cpp cube/cube_proxy.cpp cube/cubeslide.cpp coverswitch/coverswitch.cpp desktopgrid/desktopgrid.cpp diminactive/diminactive.cpp flipswitch/flipswitch.cpp glide/glide.cpp invert/invert.cpp lookingglass/lookingglass.cpp magiclamp/magiclamp.cpp magnifier/magnifier.cpp mouseclick/mouseclick.cpp mousemark/mousemark.cpp presentwindows/presentwindows.cpp presentwindows/presentwindows_proxy.cpp resize/resize.cpp showfps/showfps.cpp thumbnailaside/thumbnailaside.cpp touchpoints/touchpoints.cpp trackmouse/trackmouse.cpp windowgeometry/windowgeometry.cpp wobblywindows/wobblywindows.cpp zoom/zoom.cpp ) qt5_add_resources( kwin4_effect_builtins_sources shaders.qrc ) kconfig_add_kcfg_files(kwin4_effect_builtins_sources blur/blurconfig.kcfgc cube/cubeslideconfig.kcfgc cube/cubeconfig.kcfgc coverswitch/coverswitchconfig.kcfgc desktopgrid/desktopgridconfig.kcfgc diminactive/diminactiveconfig.kcfgc fallapart/fallapartconfig.kcfgc flipswitch/flipswitchconfig.kcfgc glide/glideconfig.kcfgc lookingglass/lookingglassconfig.kcfgc magiclamp/magiclampconfig.kcfgc magnifier/magnifierconfig.kcfgc mouseclick/mouseclickconfig.kcfgc mousemark/mousemarkconfig.kcfgc presentwindows/presentwindowsconfig.kcfgc resize/resizeconfig.kcfgc showfps/showfpsconfig.kcfgc + slidingpopups/slidingpopupsconfig.kcfgc thumbnailaside/thumbnailasideconfig.kcfgc trackmouse/trackmouseconfig.kcfgc windowgeometry/windowgeometryconfig.kcfgc wobblywindows/wobblywindowsconfig.kcfgc zoom/zoomconfig.kcfgc ) # scripted effects add_subdirectory( dialogparent ) add_subdirectory( eyeonscreen ) add_subdirectory( fade ) add_subdirectory( fadedesktop ) add_subdirectory( login ) add_subdirectory( maximize ) add_subdirectory( morphingpopups ) add_subdirectory( scalein ) add_subdirectory( translucency ) add_subdirectory( windowaperture ) ############################################################################### # Built-in effects go here # Common effects add_subdirectory( desktopgrid ) add_subdirectory( diminactive ) include( dimscreen/CMakeLists.txt ) include( fallapart/CMakeLists.txt ) include( highlightwindow/CMakeLists.txt ) include( kscreen/CMakeLists.txt ) add_subdirectory( magiclamp ) include( minimizeanimation/CMakeLists.txt ) add_subdirectory( presentwindows ) add_subdirectory( resize ) include( screenedge/CMakeLists.txt ) add_subdirectory( showfps ) include( showpaint/CMakeLists.txt ) include( slide/CMakeLists.txt ) include( slideback/CMakeLists.txt ) include( slidingpopups/CMakeLists.txt ) add_subdirectory( thumbnailaside ) add_subdirectory( windowgeometry ) add_subdirectory( zoom ) # OpenGL-specific effects add_subdirectory( blur ) include( backgroundcontrast/CMakeLists.txt ) add_subdirectory( coverswitch ) add_subdirectory( cube ) add_subdirectory( flipswitch ) add_subdirectory( glide ) add_subdirectory( invert ) add_subdirectory( lookingglass ) add_subdirectory( magnifier ) add_subdirectory( mouseclick ) add_subdirectory( mousemark ) include( screenshot/CMakeLists.txt ) include( sheet/CMakeLists.txt ) include( snaphelper/CMakeLists.txt ) include( startupfeedback/CMakeLists.txt ) add_subdirectory( trackmouse ) add_subdirectory( wobblywindows ) ############################################################################### # Add the builtins plugin kwin4_add_effect( builtins ${kwin4_effect_builtins_sources} ) diff --git a/effects/slidingpopups/slidingpopups.cpp b/effects/slidingpopups/slidingpopups.cpp index 9f82b9140..174f67b65 100644 --- a/effects/slidingpopups/slidingpopups.cpp +++ b/effects/slidingpopups/slidingpopups.cpp @@ -1,482 +1,482 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2009 Marco Martin notmart@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "slidingpopups.h" +#include "slidingpopupsconfig.h" -#include #include #include #include #include #include namespace KWin { SlidingPopupsEffect::SlidingPopupsEffect() { KWayland::Server::Display *display = effects->waylandDisplay(); if (display) { display->createSlideManager(this)->create(); } mSlideLength = QFontMetrics(qApp->font()).height() * 8; mAtom = effects->announceSupportProperty("_KDE_SLIDE", this); connect(effects, SIGNAL(windowAdded(KWin::EffectWindow*)), this, SLOT(slotWindowAdded(KWin::EffectWindow*))); connect(effects, SIGNAL(windowClosed(KWin::EffectWindow*)), this, SLOT(slotWindowClosed(KWin::EffectWindow*))); connect(effects, SIGNAL(windowDeleted(KWin::EffectWindow*)), this, SLOT(slotWindowDeleted(KWin::EffectWindow*))); connect(effects, SIGNAL(propertyNotify(KWin::EffectWindow*,long)), this, SLOT(slotPropertyNotify(KWin::EffectWindow*,long))); connect(effects, &EffectsHandler::windowShown, this, &SlidingPopupsEffect::startForShow); connect(effects, &EffectsHandler::windowHidden, this, &SlidingPopupsEffect::slotWindowClosed); reconfigure(ReconfigureAll); } SlidingPopupsEffect::~SlidingPopupsEffect() { } void SlidingPopupsEffect::reconfigure(ReconfigureFlags flags) { Q_UNUSED(flags) - KConfigGroup conf = effects->effectConfig(QStringLiteral("SlidingPopups")); - mFadeInTime = animationTime(conf, QStringLiteral("SlideInTime"), 150); - mFadeOutTime = animationTime(conf, QStringLiteral("SlideOutTime"), 250); + SlidingPopupsConfig::self()->read(); + mFadeInTime = animationTime(SlidingPopupsConfig::slideInTime() != 0 ? SlidingPopupsConfig::slideInTime() : 150); + mFadeOutTime = animationTime(SlidingPopupsConfig::slideOutTime() != 0 ? SlidingPopupsConfig::slideOutTime() : 250); QHash< const EffectWindow*, QTimeLine* >::iterator it = mAppearingWindows.begin(); while (it != mAppearingWindows.end()) { it.value()->setDuration(animationTime(mFadeInTime)); ++it; } it = mDisappearingWindows.begin(); while (it != mDisappearingWindows.end()) { it.value()->setDuration(animationTime(mFadeOutTime)); ++it; } QHash< const EffectWindow*, Data >::iterator wIt = mWindowsData.begin(); while (wIt != mWindowsData.end()) { wIt.value().fadeInDuration = mFadeInTime; wIt.value().fadeOutDuration = mFadeOutTime; ++wIt; } } void SlidingPopupsEffect::prePaintScreen(ScreenPrePaintData& data, int time) { effects->prePaintScreen(data, time); } void SlidingPopupsEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) { qreal progress = 1.0; bool appearing = false; if (mAppearingWindows.contains(w)) { mAppearingWindows[ w ]->setCurrentTime(mAppearingWindows[ w ]->currentTime() + time); if (mAppearingWindows[ w ]->currentValue() < 1) { data.setTransformed(); progress = mAppearingWindows[ w ]->currentValue(); appearing = true; } else { delete mAppearingWindows.take(w); w->setData(WindowForceBlurRole, false); if (m_backgroundContrastForced.contains(w) && w->hasAlpha() && w->data(WindowForceBackgroundContrastRole).toBool()) { w->setData(WindowForceBackgroundContrastRole, QVariant()); m_backgroundContrastForced.removeAll(w); } } } else if (mDisappearingWindows.contains(w)) { mDisappearingWindows[ w ]->setCurrentTime(mDisappearingWindows[ w ]->currentTime() + time); progress = mDisappearingWindows[ w ]->currentValue(); if (progress != 1.0) { data.setTransformed(); w->enablePainting(EffectWindow::PAINT_DISABLED | EffectWindow::PAINT_DISABLED_BY_DELETE); } else { delete mDisappearingWindows.take(w); w->addRepaintFull(); if (w->isDeleted()) { w->unrefWindow(); } } } if (progress != 1.0) { const int start = mWindowsData[ w ].start; if (start != 0) { const QRect screenRect = effects->clientArea(FullScreenArea, w->screen(), effects->currentDesktop()); const QRect geo = w->expandedGeometry(); // filter out window quads, but only if the window does not start from the edge int slideLength; if (mWindowsData[ w ].slideLength > 0) { slideLength = mWindowsData[ w ].slideLength; } else { slideLength = mSlideLength; } switch(mWindowsData[ w ].from) { case West: { const double splitPoint = geo.width() - (geo.x() + geo.width() - screenRect.x() - start) + qMin(geo.width(), slideLength) * (appearing ? 1.0 - progress : progress); data.quads = data.quads.splitAtX(splitPoint); WindowQuadList filtered; foreach (const WindowQuad &quad, data.quads) { if (quad.left() >= splitPoint) { filtered << quad; } } data.quads = filtered; break; } case North: { const double splitPoint = geo.height() - (geo.y() + geo.height() - screenRect.y() - start) + qMin(geo.height(), slideLength) * (appearing ? 1.0 - progress : progress); data.quads = data.quads.splitAtY(splitPoint); WindowQuadList filtered; foreach (const WindowQuad &quad, data.quads) { if (quad.top() >= splitPoint) { filtered << quad; } } data.quads = filtered; break; } case East: { const double splitPoint = screenRect.x() + screenRect.width() - geo.x() - start - qMin(geo.width(), slideLength) * (appearing ? 1.0 - progress : progress); data.quads = data.quads.splitAtX(splitPoint); WindowQuadList filtered; foreach (const WindowQuad &quad, data.quads) { if (quad.right() <= splitPoint) { filtered << quad; } } data.quads = filtered; break; } case South: default: { const double splitPoint = screenRect.y() + screenRect.height() - geo.y() - start - qMin(geo.height(), slideLength) * (appearing ? 1.0 - progress : progress); data.quads = data.quads.splitAtY(splitPoint); WindowQuadList filtered; foreach (const WindowQuad &quad, data.quads) { if (quad.bottom() <= splitPoint) { filtered << quad; } } data.quads = filtered; break; } } } } effects->prePaintWindow(w, data, time); } void SlidingPopupsEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) { bool animating = false; bool appearing = false; if (mAppearingWindows.contains(w)) { appearing = true; animating = true; } else if (mDisappearingWindows.contains(w)) { appearing = false; animating = true; } if (animating) { qreal progress; if (appearing) progress = 1.0 - mAppearingWindows[ w ]->currentValue(); else { if (mDisappearingWindows.contains(w)) progress = mDisappearingWindows[ w ]->currentValue(); else progress = 1.0; } const int start = mWindowsData[ w ].start; int slideLength; if (mWindowsData[ w ].slideLength > 0) { slideLength = mWindowsData[ w ].slideLength; } else { slideLength = mSlideLength; } const QRect screenRect = effects->clientArea(FullScreenArea, w->screen(), w->desktop()); int splitPoint = 0; const QRect geo = w->expandedGeometry(); switch(mWindowsData[ w ].from) { case West: if (slideLength < geo.width()) { data.multiplyOpacity(1 - progress); } data.translate(- qMin(geo.width(), slideLength) * progress); splitPoint = geo.width() - (geo.x() + geo.width() - screenRect.x() - start); region = QRegion(geo.x() + splitPoint, geo.y(), geo.width() - splitPoint, geo.height()); break; case North: if (slideLength < geo.height()) { data.multiplyOpacity(1 - progress); } data.translate(0.0, - qMin(geo.height(), slideLength) * progress); splitPoint = geo.height() - (geo.y() + geo.height() - screenRect.y() - start); region = QRegion(geo.x(), geo.y() + splitPoint, geo.width(), geo.height() - splitPoint); break; case East: if (slideLength < geo.width()) { data.multiplyOpacity(1 - progress); } data.translate(qMin(geo.width(), slideLength) * progress); splitPoint = screenRect.x() + screenRect.width() - geo.x() - start; region = QRegion(geo.x(), geo.y(), splitPoint, geo.height()); break; case South: default: if (slideLength < geo.height()) { data.multiplyOpacity(1 - progress); } data.translate(0.0, qMin(geo.height(), slideLength) * progress); splitPoint = screenRect.y() + screenRect.height() - geo.y() - start; region = QRegion(geo.x(), geo.y(), geo.width(), splitPoint); } } effects->paintWindow(w, mask, region, data); } void SlidingPopupsEffect::postPaintWindow(EffectWindow* w) { if (mAppearingWindows.contains(w) || mDisappearingWindows.contains(w)) { w->addRepaintFull(); // trigger next animation repaint } effects->postPaintWindow(w); } void SlidingPopupsEffect::slotWindowAdded(EffectWindow *w) { //X11 slotPropertyNotify(w, mAtom); //Wayland if (auto surf = w->surface()) { slotWaylandSlideOnShowChanged(w); connect(surf, &KWayland::Server::SurfaceInterface::slideOnShowHideChanged, this, [this, surf] { slotWaylandSlideOnShowChanged(effects->findWindow(surf)); }); } startForShow(w); } void SlidingPopupsEffect::startForShow(EffectWindow *w) { if (w->isOnCurrentDesktop() && mWindowsData.contains(w)) { if (!w->data(WindowForceBackgroundContrastRole).isValid() && w->hasAlpha()) { w->setData(WindowForceBackgroundContrastRole, QVariant(true)); m_backgroundContrastForced.append(w); } auto it = mDisappearingWindows.find(w); if (it != mDisappearingWindows.end()) { delete it.value(); mDisappearingWindows.erase(it); } it = mAppearingWindows.find(w); if (it != mAppearingWindows.end()) { delete it.value(); mAppearingWindows.erase(it); } mAppearingWindows.insert(w, new QTimeLine(mWindowsData[ w ].fadeInDuration, this)); mAppearingWindows[ w ]->setCurveShape(QTimeLine::EaseInOutCurve); w->setData(WindowAddedGrabRole, QVariant::fromValue(static_cast(this))); w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast(this))); w->setData(WindowForceBlurRole, true); w->addRepaintFull(); } } void SlidingPopupsEffect::slotWindowClosed(EffectWindow* w) { if (w->isOnCurrentDesktop() && !w->isMinimized() && mWindowsData.contains(w)) { if (w->isDeleted()) { w->refWindow(); } auto it = mAppearingWindows.find(w); if (it != mAppearingWindows.end()) { delete it.value(); mAppearingWindows.erase(it); } // could be already running, better check if (mDisappearingWindows.contains(w)) { return; } mDisappearingWindows.insert(w, new QTimeLine(mWindowsData[ w ].fadeOutDuration, this)); mDisappearingWindows[ w ]->setCurveShape(QTimeLine::EaseInOutCurve); // Tell other windowClosed() effects to ignore this window w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast(this))); w->setData(WindowForceBlurRole, true); if (!w->data(WindowForceBackgroundContrastRole).isValid() && w->hasAlpha()) { w->setData(WindowForceBackgroundContrastRole, QVariant(true)); } w->addRepaintFull(); } m_backgroundContrastForced.removeAll(w); } void SlidingPopupsEffect::slotWindowDeleted(EffectWindow* w) { delete mAppearingWindows.take(w); delete mDisappearingWindows.take(w); mWindowsData.remove(w); effects->addRepaint(w->expandedGeometry()); } void SlidingPopupsEffect::slotPropertyNotify(EffectWindow* w, long a) { if (!w || a != mAtom) return; QByteArray data = w->readProperty(mAtom, mAtom, 32); if (data.length() < 1) { // Property was removed, thus also remove the effect for window w->setData(WindowClosedGrabRole, QVariant()); delete mAppearingWindows.take(w); delete mDisappearingWindows.take(w); mWindowsData.remove(w); return; } auto* d = reinterpret_cast< uint32_t* >(data.data()); Data animData; animData.start = d[ 0 ]; animData.from = (Position)d[ 1 ]; //custom duration animData.slideLength = 0; if (data.length() >= (int)(sizeof(uint32_t) * 3)) { animData.fadeInDuration = d[2]; if (data.length() >= (int)(sizeof(uint32_t) * 4)) //custom fadein animData.fadeOutDuration = d[3]; else //custom fadeout animData.fadeOutDuration = d[2]; //do we want an actual slide? if (data.length() >= (int)(sizeof(uint32_t) * 5)) animData.slideLength = d[5]; } else { animData.fadeInDuration = animationTime(mFadeInTime); animData.fadeOutDuration = animationTime(mFadeOutTime); } mWindowsData[ w ] = animData; setupAnimData(w); } void SlidingPopupsEffect::setupAnimData(EffectWindow *w) { const QRect screenRect = effects->clientArea(FullScreenArea, w->screen(), effects->currentDesktop()); if (mWindowsData[w].start == -1) { switch (mWindowsData[w].from) { case West: mWindowsData[w].start = qMax(w->x() - screenRect.x(), 0); break; case North: mWindowsData[w].start = qMax(w->y() - screenRect.y(), 0); break; case East: mWindowsData[w].start = qMax(screenRect.x() + screenRect.width() - (w->x() + w->width()), 0); break; case South: default: mWindowsData[w].start = qMax(screenRect.y() + screenRect.height() - (w->y() + w->height()), 0); break; } } // sanitize int difference = 0; switch (mWindowsData[w].from) { case West: difference = w->x() - screenRect.x(); break; case North: difference = w->y() - screenRect.y(); break; case East: difference = w->x() + w->width() - (screenRect.x() + screenRect.width()); break; case South: default: difference = w->y() + w->height() - (screenRect.y() + screenRect.height()); break; } mWindowsData[w].start = qMax(mWindowsData[w].start, difference); // Grab the window, so other windowClosed effects will ignore it w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast(this))); } void SlidingPopupsEffect::slotWaylandSlideOnShowChanged(EffectWindow* w) { if (!w) { return; } KWayland::Server::SurfaceInterface *surf = w->surface(); if (!surf) { return; } if (surf->slideOnShowHide()) { Data animData; animData.start = surf->slideOnShowHide()->offset(); switch (surf->slideOnShowHide()->location()) { case KWayland::Server::SlideInterface::Location::Top: animData.from = North; break; case KWayland::Server::SlideInterface::Location::Left: animData.from = West; break; case KWayland::Server::SlideInterface::Location::Right: animData.from = East; break; case KWayland::Server::SlideInterface::Location::Bottom: default: animData.from = South; break; } animData.slideLength = 0; animData.fadeInDuration = animationTime(mFadeInTime); animData.fadeOutDuration = animationTime(mFadeOutTime); mWindowsData[ w ] = animData; setupAnimData(w); } } bool SlidingPopupsEffect::isActive() const { return !mAppearingWindows.isEmpty() || !mDisappearingWindows.isEmpty(); } } // namespace diff --git a/effects/slidingpopups/slidingpopups.kcfg b/effects/slidingpopups/slidingpopups.kcfg new file mode 100644 index 000000000..414cf18a7 --- /dev/null +++ b/effects/slidingpopups/slidingpopups.kcfg @@ -0,0 +1,17 @@ + + + + + + + 0 + + + 0 + + + + diff --git a/effects/slidingpopups/slidingpopupsconfig.kcfgc b/effects/slidingpopups/slidingpopupsconfig.kcfgc new file mode 100644 index 000000000..6a8c915f5 --- /dev/null +++ b/effects/slidingpopups/slidingpopupsconfig.kcfgc @@ -0,0 +1,5 @@ +File=slidingpopups.kcfg +ClassName=SlidingPopupsConfig +NameSpace=KWin +Singleton=true +Mutators=true