12#include "slidingpopupsconfig.h"
19#include <QFontMetrics>
20#include <QGuiApplication>
24#include <KWindowEffects>
31SlideManagerInterface *SlidingPopupsEffect::s_slideManager =
nullptr;
32QTimer *SlidingPopupsEffect::s_slideManagerRemoveTimer =
nullptr;
40 if (!s_slideManagerRemoveTimer) {
41 s_slideManagerRemoveTimer =
new QTimer(QCoreApplication::instance());
42 s_slideManagerRemoveTimer->setSingleShot(
true);
43 s_slideManagerRemoveTimer->callOnTimeout([]() {
45 s_slideManager =
nullptr;
48 s_slideManagerRemoveTimer->stop();
49 if (!s_slideManager) {
54 m_slideLength = QFontMetrics(QGuiApplication::font()).height() * 8;
65 this, &SlidingPopupsEffect::stopAnimations);
67 this, &SlidingPopupsEffect::stopAnimations);
69 this, &SlidingPopupsEffect::stopAnimations);
75 setupSlideData(window);
83 s_slideManagerRemoveTimer->start(1000);
89 m_animationsData.clear();
99 SlidingPopupsConfig::self()->read();
100 m_slideInDuration = std::chrono::milliseconds(
101 static_cast<int>(
animationTime(SlidingPopupsConfig::slideInTime() != 0 ? SlidingPopupsConfig::slideInTime() : 150)));
102 m_slideOutDuration = std::chrono::milliseconds(
103 static_cast<int>(
animationTime(SlidingPopupsConfig::slideOutTime() != 0 ? SlidingPopupsConfig::slideOutTime() : 250)));
105 auto animationIt = m_animations.begin();
106 while (animationIt != m_animations.end()) {
107 const auto duration = ((*animationIt).kind == AnimationKind::In)
109 : m_slideOutDuration;
110 (*animationIt).timeLine.setDuration(duration);
114 auto dataIt = m_animationsData.begin();
115 while (dataIt != m_animationsData.end()) {
116 (*dataIt).slideInDuration = m_slideInDuration;
117 (*dataIt).slideOutDuration = m_slideOutDuration;
124 auto animationIt = m_animations.find(w);
125 if (animationIt == m_animations.end()) {
130 (*animationIt).timeLine.advance(presentTime);
138 auto animationIt = m_animations.constFind(w);
139 if (animationIt == m_animations.constEnd()) {
144 const AnimationData &animData = m_animationsData[w];
145 const qreal slideLength = (animData.slideLength > 0) ? animData.slideLength : m_slideLength;
150 const qreal t = (*animationIt).timeLine.value();
152 switch (animData.location) {
154 if (slideLength < geo.width()) {
158 splitPoint = geo.width() - (geo.x() + geo.width() - screenRect.x() - animData.offset);
159 region &= QRegion(geo.x() + splitPoint, geo.y(), geo.width() - splitPoint, geo.height());
162 if (slideLength < geo.height()) {
166 splitPoint = geo.height() - (geo.y() + geo.height() - screenRect.y() - animData.offset);
167 region &= QRegion(geo.x(), geo.y() + splitPoint, geo.width(), geo.height() - splitPoint);
169 case Location::Right:
170 if (slideLength < geo.width()) {
174 splitPoint = screenRect.x() + screenRect.width() - geo.x() - animData.offset;
175 region &= QRegion(geo.x(), geo.y(), splitPoint, geo.height());
177 case Location::Bottom:
179 if (slideLength < geo.height()) {
183 splitPoint = screenRect.y() + screenRect.height() - geo.y() - animData.offset;
184 region &= QRegion(geo.x(), geo.y(), geo.width(), splitPoint);
192 auto animationIt = m_animations.find(w);
193 if (animationIt != m_animations.end()) {
195 if ((*animationIt).timeLine.done()) {
200 m_animations.erase(animationIt);
207void SlidingPopupsEffect::setupSlideData(
EffectWindow *w)
214 if (m_atom != XCB_ATOM_NONE) {
215 slotPropertyNotify(w, m_atom);
219 if (
auto surf = w->
surface()) {
220 slotWaylandSlideOnShowChanged(w);
227 internal->installEventFilter(
this);
228 setupInternalWindowSlide(w);
232void SlidingPopupsEffect::slotWindowAdded(EffectWindow *w)
235 if (!w->isHidden()) {
240void SlidingPopupsEffect::slotWindowClosed(EffectWindow *w)
242 if (!w->isHidden()) {
247void SlidingPopupsEffect::slotWindowDeleted(EffectWindow *w)
249 m_animationsData.remove(w);
252void SlidingPopupsEffect::slotPropertyNotify(EffectWindow *w,
long atom)
254 if (!w || atom != m_atom || m_atom == XCB_ATOM_NONE) {
271 const QByteArray rawAtomData = w->readProperty(m_atom, m_atom, 32);
273 if (rawAtomData.isEmpty()) {
278 m_animations.remove(w);
279 m_animationsData.remove(w);
284 if (
static_cast<size_t>(rawAtomData.size()) <
sizeof(uint32_t) * 2) {
288 const auto *atomData =
reinterpret_cast<const uint32_t *
>(rawAtomData.data());
289 AnimationData &animData = m_animationsData[w];
290 animData.offset = atomData[0];
292 switch (atomData[1]) {
294 animData.location = Location::Left;
297 animData.location = Location::Top;
300 animData.location = Location::Right;
304 animData.location = Location::Bottom;
308 if (
static_cast<size_t>(rawAtomData.size()) >=
sizeof(uint32_t) * 3) {
309 animData.slideInDuration = std::chrono::milliseconds(atomData[2]);
310 if (
static_cast<size_t>(rawAtomData.size()) >=
sizeof(uint32_t) * 4) {
311 animData.slideOutDuration = std::chrono::milliseconds(atomData[3]);
313 animData.slideOutDuration = animData.slideInDuration;
316 animData.slideInDuration = m_slideInDuration;
317 animData.slideOutDuration = m_slideOutDuration;
320 if (
static_cast<size_t>(rawAtomData.size()) >=
sizeof(uint32_t) * 5) {
321 animData.slideLength = atomData[4];
323 animData.slideLength = 0;
329void SlidingPopupsEffect::slotWindowFrameGeometryChanged(EffectWindow *w,
const QRectF &)
332 setupInputPanelSlide();
336void SlidingPopupsEffect::setupAnimData(EffectWindow *w)
339 const QRectF windowGeo = w->frameGeometry();
340 AnimationData &animData = m_animationsData[w];
342 if (animData.offset == -1) {
343 switch (animData.location) {
345 animData.offset = std::max<qreal>(windowGeo.left() - screenRect.left(), 0);
348 animData.offset = std::max<qreal>(windowGeo.top() - screenRect.top(), 0);
350 case Location::Right:
351 animData.offset = std::max<qreal>(screenRect.right() - windowGeo.right(), 0);
353 case Location::Bottom:
355 animData.offset = std::max<qreal>(screenRect.bottom() - windowGeo.bottom(), 0);
360 switch (animData.location) {
362 animData.offset = std::max<qreal>(windowGeo.left() - screenRect.left(), animData.offset);
365 animData.offset = std::max<qreal>(windowGeo.top() - screenRect.top(), animData.offset);
367 case Location::Right:
368 animData.offset = std::max<qreal>(screenRect.right() - windowGeo.right(), animData.offset);
370 case Location::Bottom:
372 animData.offset = std::max<qreal>(screenRect.bottom() - windowGeo.bottom(), animData.offset);
376 animData.slideInDuration = (animData.slideInDuration.count() != 0)
377 ? animData.slideInDuration
380 animData.slideOutDuration = (animData.slideOutDuration.count() != 0)
381 ? animData.slideOutDuration
382 : m_slideOutDuration;
388void SlidingPopupsEffect::slotWaylandSlideOnShowChanged(EffectWindow *w)
394 SurfaceInterface *surf = w->surface();
399 if (surf->slideOnShowHide()) {
400 AnimationData &animData = m_animationsData[w];
402 animData.offset = surf->slideOnShowHide()->offset();
404 switch (surf->slideOnShowHide()->location()) {
406 animData.location = Location::Top;
409 animData.location = Location::Left;
412 animData.location = Location::Right;
416 animData.location = Location::Bottom;
419 animData.slideLength = 0;
420 animData.slideInDuration = m_slideInDuration;
421 animData.slideOutDuration = m_slideOutDuration;
427void SlidingPopupsEffect::setupInternalWindowSlide(EffectWindow *w)
432 auto internal = w->internalWindow();
436 const QVariant slideProperty = internal->property(
"kwin_slide");
437 if (!slideProperty.isValid()) {
441 switch (slideProperty.value<KWindowEffects::SlideFromLocation>()) {
442 case KWindowEffects::BottomEdge:
443 location = Location::Bottom;
445 case KWindowEffects::TopEdge:
446 location = Location::Top;
448 case KWindowEffects::RightEdge:
449 location = Location::Right;
451 case KWindowEffects::LeftEdge:
452 location = Location::Left;
457 AnimationData &animData = m_animationsData[w];
458 animData.location = location;
460 animData.offset = internal->property(
"kwin_slide_offset").toInt(&intOk);
462 animData.offset = -1;
464 animData.slideLength = 0;
465 animData.slideInDuration = m_slideInDuration;
466 animData.slideOutDuration = m_slideOutDuration;
471void SlidingPopupsEffect::setupInputPanelSlide()
479 AnimationData &animData = m_animationsData[w];
480 animData.location = Location::Bottom;
482 animData.slideLength = 0;
483 animData.slideInDuration = m_slideInDuration;
484 animData.slideOutDuration = m_slideOutDuration;
493 auto internal = qobject_cast<QWindow *>(watched);
494 if (internal && event->type() == QEvent::DynamicPropertyChange) {
495 QDynamicPropertyChangeEvent *pe =
static_cast<QDynamicPropertyChangeEvent *
>(event);
496 if (pe->propertyName() ==
"kwin_slide" || pe->propertyName() ==
"kwin_slide_offset") {
498 setupInternalWindowSlide(w);
515 auto dataIt = m_animationsData.constFind(w);
516 if (dataIt == m_animationsData.constEnd()) {
520 Animation &animation = m_animations[w];
521 animation.kind = AnimationKind::In;
523 animation.timeLine.setDuration((*dataIt).slideInDuration);
524 animation.timeLine.setEasingCurve(QEasingCurve::OutCubic);
529 if (animation.timeLine.done()) {
530 animation.timeLine.reset();
540void SlidingPopupsEffect::slideOut(EffectWindow *w)
546 if (!w->isVisible()) {
550 auto dataIt = m_animationsData.constFind(w);
551 if (dataIt == m_animationsData.constEnd()) {
555 Animation &animation = m_animations[w];
556 animation.deletedRef = EffectWindowDeletedRef(w);
558 animation.kind = AnimationKind::Out;
560 animation.timeLine.setDuration((*dataIt).slideOutDuration);
562 animation.timeLine.setEasingCurve(QEasingCurve::OutCubic);
567 if (animation.timeLine.done()) {
568 animation.timeLine.reset();
578void SlidingPopupsEffect::stopAnimations()
580 for (
auto it = m_animations.constBegin(); it != m_animations.constEnd(); ++it) {
581 EffectWindow *w = it.key();
583 if (!w->isDeleted()) {
589 m_animations.clear();
594 return !m_animations.isEmpty();
599#include "moc_slidingpopups.cpp"
Class holding the Wayland server display loop.
Representation of a window used by/for Effect classes.
void windowHidden(KWin::EffectWindow *w)
Q_SCRIPTABLE void addRepaintFull()
void windowFrameGeometryChanged(KWin::EffectWindow *window, const QRectF &oldGeometry)
Q_SCRIPTABLE void setData(int role, const QVariant &data)
SurfaceInterface * surface() const
void windowShown(KWin::EffectWindow *w)
Display * waylandDisplay() const
void propertyNotify(KWin::EffectWindow *w, long atom)
void screenLockingChanged(bool locked)
void windowDeleted(KWin::EffectWindow *w)
bool animationsSupported() const
Q_SCRIPTABLE KWin::EffectWindow * findWindow(WId id) const
void windowClosed(KWin::EffectWindow *w)
QList< EffectWindow * > stackingOrder
Q_SCRIPTABLE void addRepaint(const QRectF &r)
void paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data)
KWin::VirtualDesktop * currentDesktop
xcb_atom_t announceSupportProperty(const QByteArray &propertyName, Effect *effect)
Announces support for the feature with the given name. If no other Effect has announced support for t...
KWin::EffectWindow * inputPanel
void xcbConnectionChanged()
void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime)
void desktopChanged(KWin::VirtualDesktop *oldDesktop, KWin::VirtualDesktop *newDesktop, KWin::EffectWindow *with)
QRectF clientArea(clientAreaOption, const Output *screen, const VirtualDesktop *desktop) const
bool isInputPanelOverlay() const
KSharedConfigPtr config() const
void windowAdded(KWin::EffectWindow *w)
Effect * activeFullScreenEffect() const
void activeFullScreenEffectChanged()
void postPaintWindow(EffectWindow *w)
void slideOnShowHideChanged()
qreal multiplyOpacity(qreal factor)
static double interpolate(double x, double y, double a)
static double animationTime(const KConfigGroup &cfg, const QString &key, int defaultTime)
void translate(qreal x, qreal y=0.0, qreal z=0.0)
@ WindowForceBackgroundContrastRole
For fullscreen effects to enforce the background contrast,.
@ WindowForceBlurRole
For fullscreen effects to enforce blurring of windows,.