File indexing completed on 2024-11-10 04:56:44
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"