File indexing completed on 2024-05-12 05:31:29

0001 /*
0002     SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
0003     SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
0004     SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
0005     SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "effect/effectwindow.h"
0011 #include "core/output.h"
0012 #include "effect/effecthandler.h"
0013 #include "group.h"
0014 #include "internalwindow.h"
0015 #include "scene/windowitem.h"
0016 #include "virtualdesktops.h"
0017 #include "waylandwindow.h"
0018 #include "x11window.h"
0019 
0020 namespace KWin
0021 {
0022 
0023 class Q_DECL_HIDDEN EffectWindow::Private
0024 {
0025 public:
0026     Private(EffectWindow *q, WindowItem *windowItem);
0027 
0028     EffectWindow *q;
0029     Window *m_window;
0030     WindowItem *m_windowItem; // This one is used only during paint pass.
0031     QHash<int, QVariant> dataMap;
0032     bool managed = false;
0033     bool m_waylandWindow;
0034     bool m_x11Window;
0035 };
0036 
0037 EffectWindow::Private::Private(EffectWindow *q, WindowItem *windowItem)
0038     : q(q)
0039     , m_window(windowItem->window())
0040     , m_windowItem(windowItem)
0041 {
0042 }
0043 
0044 EffectWindow::EffectWindow(WindowItem *windowItem)
0045     : d(new Private(this, windowItem))
0046 {
0047     // Deleted windows are not managed. So, when windowClosed signal is
0048     // emitted, effects can't distinguish managed windows from unmanaged
0049     // windows(e.g. combo box popups, popup menus, etc). Save value of the
0050     // managed property during construction of EffectWindow. At that time,
0051     // parent can be Client, XdgShellClient, or Unmanaged. So, later on, when
0052     // an instance of Deleted becomes parent of the EffectWindow, effects
0053     // can still figure out whether it is/was a managed window.
0054     d->managed = d->m_window->isClient();
0055 
0056     d->m_waylandWindow = qobject_cast<KWin::WaylandWindow *>(d->m_window) != nullptr;
0057     d->m_x11Window = qobject_cast<KWin::X11Window *>(d->m_window) != nullptr;
0058 
0059     connect(d->m_window, &Window::windowShown, this, [this]() {
0060         Q_EMIT windowShown(this);
0061     });
0062     connect(d->m_window, &Window::windowHidden, this, [this]() {
0063         Q_EMIT windowHidden(this);
0064     });
0065     connect(d->m_window, &Window::maximizedChanged, this, [this]() {
0066         const MaximizeMode mode = d->m_window->maximizeMode();
0067         Q_EMIT windowMaximizedStateChanged(this, mode & MaximizeHorizontal, mode & MaximizeVertical);
0068     });
0069     connect(d->m_window, &Window::maximizedAboutToChange, this, [this](MaximizeMode m) {
0070         Q_EMIT windowMaximizedStateAboutToChange(this, m & MaximizeHorizontal, m & MaximizeVertical);
0071     });
0072     connect(d->m_window, &Window::frameGeometryAboutToChange, this, [this]() {
0073         Q_EMIT windowFrameGeometryAboutToChange(this);
0074     });
0075     connect(d->m_window, &Window::interactiveMoveResizeStarted, this, [this]() {
0076         Q_EMIT windowStartUserMovedResized(this);
0077     });
0078     connect(d->m_window, &Window::interactiveMoveResizeStepped, this, [this](const QRectF &geometry) {
0079         Q_EMIT windowStepUserMovedResized(this, geometry);
0080     });
0081     connect(d->m_window, &Window::interactiveMoveResizeFinished, this, [this]() {
0082         Q_EMIT windowFinishUserMovedResized(this);
0083     });
0084     connect(d->m_window, &Window::opacityChanged, this, [this](Window *window, qreal oldOpacity) {
0085         Q_EMIT windowOpacityChanged(this, oldOpacity, window->opacity());
0086     });
0087     connect(d->m_window, &Window::minimizedChanged, this, [this]() {
0088         Q_EMIT minimizedChanged(this);
0089     });
0090     connect(d->m_window, &Window::modalChanged, this, [this]() {
0091         Q_EMIT windowModalityChanged(this);
0092     });
0093     connect(d->m_window, &Window::frameGeometryChanged, this, [this](const QRectF &oldGeometry) {
0094         Q_EMIT windowFrameGeometryChanged(this, oldGeometry);
0095     });
0096     connect(d->m_window, &Window::damaged, this, [this]() {
0097         Q_EMIT windowDamaged(this);
0098     });
0099     connect(d->m_window, &Window::unresponsiveChanged, this, [this](bool unresponsive) {
0100         Q_EMIT windowUnresponsiveChanged(this, unresponsive);
0101     });
0102     connect(d->m_window, &Window::keepAboveChanged, this, [this]() {
0103         Q_EMIT windowKeepAboveChanged(this);
0104     });
0105     connect(d->m_window, &Window::keepBelowChanged, this, [this]() {
0106         Q_EMIT windowKeepBelowChanged(this);
0107     });
0108     connect(d->m_window, &Window::fullScreenChanged, this, [this]() {
0109         Q_EMIT windowFullScreenChanged(this);
0110     });
0111     connect(d->m_window, &Window::visibleGeometryChanged, this, [this]() {
0112         Q_EMIT windowExpandedGeometryChanged(this);
0113     });
0114     connect(d->m_window, &Window::decorationChanged, this, [this]() {
0115         Q_EMIT windowDecorationChanged(this);
0116     });
0117     connect(d->m_window, &Window::desktopsChanged, this, [this]() {
0118         Q_EMIT windowDesktopsChanged(this);
0119     });
0120 }
0121 
0122 EffectWindow::~EffectWindow()
0123 {
0124 }
0125 
0126 Window *EffectWindow::window() const
0127 {
0128     return d->m_window;
0129 }
0130 
0131 WindowItem *EffectWindow::windowItem() const
0132 {
0133     return d->m_windowItem;
0134 }
0135 
0136 bool EffectWindow::isOnActivity(const QString &activity) const
0137 {
0138     const QStringList _activities = activities();
0139     return _activities.isEmpty() || _activities.contains(activity);
0140 }
0141 
0142 bool EffectWindow::isOnAllActivities() const
0143 {
0144     return activities().isEmpty();
0145 }
0146 
0147 void EffectWindow::setMinimized(bool min)
0148 {
0149     if (min) {
0150         minimize();
0151     } else {
0152         unminimize();
0153     }
0154 }
0155 
0156 bool EffectWindow::isOnCurrentActivity() const
0157 {
0158     return isOnActivity(effects->currentActivity());
0159 }
0160 
0161 bool EffectWindow::isOnCurrentDesktop() const
0162 {
0163     return isOnDesktop(effects->currentDesktop());
0164 }
0165 
0166 bool EffectWindow::isOnDesktop(VirtualDesktop *desktop) const
0167 {
0168     const QList<VirtualDesktop *> ds = desktops();
0169     return ds.isEmpty() || ds.contains(desktop);
0170 }
0171 
0172 bool EffectWindow::isOnAllDesktops() const
0173 {
0174     return desktops().isEmpty();
0175 }
0176 
0177 bool EffectWindow::hasDecoration() const
0178 {
0179     return contentsRect() != QRect(0, 0, width(), height());
0180 }
0181 
0182 bool EffectWindow::isVisible() const
0183 {
0184     return !isMinimized()
0185         && isOnCurrentDesktop()
0186         && isOnCurrentActivity();
0187 }
0188 
0189 void EffectWindow::refVisible(const EffectWindowVisibleRef *holder)
0190 {
0191     d->m_windowItem->refVisible(holder->reason());
0192 }
0193 
0194 void EffectWindow::unrefVisible(const EffectWindowVisibleRef *holder)
0195 {
0196     d->m_windowItem->unrefVisible(holder->reason());
0197 }
0198 
0199 void EffectWindow::addRepaint(const QRect &r)
0200 {
0201     d->m_windowItem->scheduleRepaint(QRegion(r));
0202 }
0203 
0204 void EffectWindow::addRepaintFull()
0205 {
0206     d->m_windowItem->scheduleRepaint(d->m_windowItem->boundingRect());
0207 }
0208 
0209 void EffectWindow::addLayerRepaint(const QRect &r)
0210 {
0211     d->m_windowItem->scheduleRepaint(d->m_windowItem->mapFromGlobal(r));
0212 }
0213 
0214 const EffectWindowGroup *EffectWindow::group() const
0215 {
0216     if (Group *group = d->m_window->group()) {
0217         return group->effectGroup();
0218     }
0219     return nullptr;
0220 }
0221 
0222 void EffectWindow::refWindow()
0223 {
0224     d->m_window->ref();
0225 }
0226 
0227 void EffectWindow::unrefWindow()
0228 {
0229     d->m_window->unref();
0230 }
0231 
0232 Output *EffectWindow::screen() const
0233 {
0234     return d->m_window->output();
0235 }
0236 
0237 #define WINDOW_HELPER(rettype, prototype, toplevelPrototype) \
0238     rettype EffectWindow::prototype() const                  \
0239     {                                                        \
0240         return d->m_window->toplevelPrototype();             \
0241     }
0242 
0243 WINDOW_HELPER(double, opacity, opacity)
0244 WINDOW_HELPER(qreal, x, x)
0245 WINDOW_HELPER(qreal, y, y)
0246 WINDOW_HELPER(qreal, width, width)
0247 WINDOW_HELPER(qreal, height, height)
0248 WINDOW_HELPER(QPointF, pos, pos)
0249 WINDOW_HELPER(QSizeF, size, size)
0250 WINDOW_HELPER(QRectF, frameGeometry, frameGeometry)
0251 WINDOW_HELPER(QRectF, bufferGeometry, bufferGeometry)
0252 WINDOW_HELPER(QRectF, clientGeometry, clientGeometry)
0253 WINDOW_HELPER(QRectF, expandedGeometry, visibleGeometry)
0254 WINDOW_HELPER(QRectF, rect, rect)
0255 WINDOW_HELPER(bool, isDesktop, isDesktop)
0256 WINDOW_HELPER(bool, isDock, isDock)
0257 WINDOW_HELPER(bool, isToolbar, isToolbar)
0258 WINDOW_HELPER(bool, isMenu, isMenu)
0259 WINDOW_HELPER(bool, isNormalWindow, isNormalWindow)
0260 WINDOW_HELPER(bool, isDialog, isDialog)
0261 WINDOW_HELPER(bool, isSplash, isSplash)
0262 WINDOW_HELPER(bool, isUtility, isUtility)
0263 WINDOW_HELPER(bool, isDropdownMenu, isDropdownMenu)
0264 WINDOW_HELPER(bool, isPopupMenu, isPopupMenu)
0265 WINDOW_HELPER(bool, isTooltip, isTooltip)
0266 WINDOW_HELPER(bool, isNotification, isNotification)
0267 WINDOW_HELPER(bool, isCriticalNotification, isCriticalNotification)
0268 WINDOW_HELPER(bool, isAppletPopup, isAppletPopup)
0269 WINDOW_HELPER(bool, isOnScreenDisplay, isOnScreenDisplay)
0270 WINDOW_HELPER(bool, isComboBox, isComboBox)
0271 WINDOW_HELPER(bool, isDNDIcon, isDNDIcon)
0272 WINDOW_HELPER(bool, isDeleted, isDeleted)
0273 WINDOW_HELPER(QString, windowRole, windowRole)
0274 WINDOW_HELPER(QStringList, activities, activities)
0275 WINDOW_HELPER(bool, skipsCloseAnimation, skipsCloseAnimation)
0276 WINDOW_HELPER(SurfaceInterface *, surface, surface)
0277 WINDOW_HELPER(bool, isPopupWindow, isPopupWindow)
0278 WINDOW_HELPER(bool, isOutline, isOutline)
0279 WINDOW_HELPER(bool, isLockScreen, isLockScreen)
0280 WINDOW_HELPER(pid_t, pid, pid)
0281 WINDOW_HELPER(QUuid, internalId, internalId)
0282 WINDOW_HELPER(bool, isMinimized, isMinimized)
0283 WINDOW_HELPER(bool, isHidden, isHidden)
0284 WINDOW_HELPER(bool, isHiddenByShowDesktop, isHiddenByShowDesktop)
0285 WINDOW_HELPER(bool, isModal, isModal)
0286 WINDOW_HELPER(bool, isFullScreen, isFullScreen)
0287 WINDOW_HELPER(bool, keepAbove, keepAbove)
0288 WINDOW_HELPER(bool, keepBelow, keepBelow)
0289 WINDOW_HELPER(QString, caption, caption)
0290 WINDOW_HELPER(bool, isMovable, isMovable)
0291 WINDOW_HELPER(bool, isMovableAcrossScreens, isMovableAcrossScreens)
0292 WINDOW_HELPER(bool, isUserMove, isInteractiveMove)
0293 WINDOW_HELPER(bool, isUserResize, isInteractiveResize)
0294 WINDOW_HELPER(QRectF, iconGeometry, iconGeometry)
0295 WINDOW_HELPER(bool, isSpecialWindow, isSpecialWindow)
0296 WINDOW_HELPER(bool, acceptsFocus, wantsInput)
0297 WINDOW_HELPER(QIcon, icon, icon)
0298 WINDOW_HELPER(bool, isSkipSwitcher, skipSwitcher)
0299 WINDOW_HELPER(bool, decorationHasAlpha, decorationHasAlpha)
0300 WINDOW_HELPER(bool, isUnresponsive, unresponsive)
0301 WINDOW_HELPER(QList<VirtualDesktop *>, desktops, desktops)
0302 WINDOW_HELPER(bool, isInputMethod, isInputMethod)
0303 
0304 #undef WINDOW_HELPER
0305 
0306 qlonglong EffectWindow::windowId() const
0307 {
0308     if (X11Window *x11Window = qobject_cast<X11Window *>(d->m_window)) {
0309         return x11Window->window();
0310     }
0311     return 0;
0312 }
0313 
0314 QString EffectWindow::windowClass() const
0315 {
0316     return d->m_window->resourceName() + QLatin1Char(' ') + d->m_window->resourceClass();
0317 }
0318 
0319 QRectF EffectWindow::contentsRect() const
0320 {
0321     return d->m_window->clientGeometry().translated(-d->m_window->bufferGeometry().topLeft());
0322 }
0323 
0324 NET::WindowType EffectWindow::windowType() const
0325 {
0326     return d->m_window->windowType();
0327 }
0328 
0329 QSizeF EffectWindow::basicUnit() const
0330 {
0331     if (auto window = qobject_cast<X11Window *>(d->m_window)) {
0332         return window->basicUnit();
0333     }
0334     return QSize(1, 1);
0335 }
0336 
0337 QRectF EffectWindow::decorationInnerRect() const
0338 {
0339     return d->m_window->rect() - d->m_window->frameMargins();
0340 }
0341 
0342 KDecoration2::Decoration *EffectWindow::decoration() const
0343 {
0344     return d->m_window->decoration();
0345 }
0346 
0347 QByteArray EffectWindow::readProperty(long atom, long type, int format) const
0348 {
0349     auto x11Window = qobject_cast<X11Window *>(d->m_window);
0350     if (!x11Window) {
0351         return QByteArray();
0352     }
0353     if (!kwinApp()->x11Connection()) {
0354         return QByteArray();
0355     }
0356     uint32_t len = 32768;
0357     for (;;) {
0358         Xcb::Property prop(false, x11Window->window(), atom, XCB_ATOM_ANY, 0, len);
0359         if (prop.isNull()) {
0360             // get property failed
0361             return QByteArray();
0362         }
0363         if (prop->bytes_after > 0) {
0364             len *= 2;
0365             continue;
0366         }
0367         return prop.toByteArray(format, type);
0368     }
0369 }
0370 
0371 void EffectWindow::deleteProperty(long int atom) const
0372 {
0373     auto x11Window = qobject_cast<X11Window *>(d->m_window);
0374     if (!x11Window) {
0375         return;
0376     }
0377     if (!kwinApp()->x11Connection()) {
0378         return;
0379     }
0380     xcb_delete_property(kwinApp()->x11Connection(), x11Window->window(), atom);
0381 }
0382 
0383 EffectWindow *EffectWindow::findModal()
0384 {
0385     Window *modal = d->m_window->findModal();
0386     if (modal) {
0387         return modal->effectWindow();
0388     }
0389 
0390     return nullptr;
0391 }
0392 
0393 EffectWindow *EffectWindow::transientFor()
0394 {
0395     Window *transientFor = d->m_window->transientFor();
0396     if (transientFor) {
0397         return transientFor->effectWindow();
0398     }
0399 
0400     return nullptr;
0401 }
0402 
0403 QWindow *EffectWindow::internalWindow() const
0404 {
0405     if (auto window = qobject_cast<InternalWindow *>(d->m_window)) {
0406         return window->handle();
0407     }
0408     return nullptr;
0409 }
0410 
0411 template<typename T>
0412 QList<EffectWindow *> getMainWindows(T *c)
0413 {
0414     const auto mainwindows = c->mainWindows();
0415     QList<EffectWindow *> ret;
0416     ret.reserve(mainwindows.size());
0417     std::transform(std::cbegin(mainwindows), std::cend(mainwindows),
0418                    std::back_inserter(ret),
0419                    [](auto window) {
0420                        return window->effectWindow();
0421                    });
0422     return ret;
0423 }
0424 
0425 QList<EffectWindow *> EffectWindow::mainWindows() const
0426 {
0427     return getMainWindows(d->m_window);
0428 }
0429 
0430 void EffectWindow::setData(int role, const QVariant &data)
0431 {
0432     if (!data.isNull()) {
0433         d->dataMap[role] = data;
0434     } else {
0435         d->dataMap.remove(role);
0436     }
0437     Q_EMIT effects->windowDataChanged(this, role);
0438 }
0439 
0440 QVariant EffectWindow::data(int role) const
0441 {
0442     return d->dataMap.value(role);
0443 }
0444 
0445 void EffectWindow::elevate(bool elevate)
0446 {
0447     effects->setElevatedWindow(this, elevate);
0448 }
0449 
0450 void EffectWindow::minimize()
0451 {
0452     if (d->m_window->isClient()) {
0453         d->m_window->setMinimized(true);
0454     }
0455 }
0456 
0457 void EffectWindow::unminimize()
0458 {
0459     if (d->m_window->isClient()) {
0460         d->m_window->setMinimized(false);
0461     }
0462 }
0463 
0464 void EffectWindow::closeWindow()
0465 {
0466     if (d->m_window->isClient()) {
0467         d->m_window->closeWindow();
0468     }
0469 }
0470 
0471 bool EffectWindow::isManaged() const
0472 {
0473     return d->managed;
0474 }
0475 
0476 bool EffectWindow::isWaylandClient() const
0477 {
0478     return d->m_waylandWindow;
0479 }
0480 
0481 bool EffectWindow::isX11Client() const
0482 {
0483     return d->m_x11Window;
0484 }
0485 
0486 //****************************************
0487 // EffectWindowGroup
0488 //****************************************
0489 
0490 EffectWindowGroup::EffectWindowGroup(Group *group)
0491     : m_group(group)
0492 {
0493 }
0494 
0495 EffectWindowGroup::~EffectWindowGroup()
0496 {
0497 }
0498 
0499 QList<EffectWindow *> EffectWindowGroup::members() const
0500 {
0501     const auto memberList = m_group->members();
0502     QList<EffectWindow *> ret;
0503     ret.reserve(memberList.size());
0504     std::transform(std::cbegin(memberList), std::cend(memberList), std::back_inserter(ret), [](auto window) {
0505         return window->effectWindow();
0506     });
0507     return ret;
0508 }
0509 
0510 } // namespace KWin
0511 
0512 #include "moc_effectwindow.cpp"