File indexing completed on 2024-11-10 04:57:14
0001 /* 0002 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "scene/item.h" 0008 #include "core/renderlayer.h" 0009 #include "scene/scene.h" 0010 #include "utils/common.h" 0011 0012 namespace KWin 0013 { 0014 0015 Item::Item(Scene *scene, Item *parent) 0016 : m_scene(scene) 0017 { 0018 setParentItem(parent); 0019 connect(m_scene, &Scene::delegateRemoved, this, &Item::removeRepaints); 0020 } 0021 0022 Item::~Item() 0023 { 0024 setParentItem(nullptr); 0025 for (const auto &dirty : std::as_const(m_repaints)) { 0026 if (!dirty.isEmpty()) { 0027 m_scene->addRepaint(dirty); 0028 } 0029 } 0030 } 0031 0032 Scene *Item::scene() const 0033 { 0034 return m_scene; 0035 } 0036 0037 qreal Item::opacity() const 0038 { 0039 return m_opacity; 0040 } 0041 0042 void Item::setOpacity(qreal opacity) 0043 { 0044 if (m_opacity != opacity) { 0045 m_opacity = opacity; 0046 scheduleRepaint(boundingRect()); 0047 } 0048 } 0049 0050 int Item::z() const 0051 { 0052 return m_z; 0053 } 0054 0055 void Item::setZ(int z) 0056 { 0057 if (m_z == z) { 0058 return; 0059 } 0060 m_z = z; 0061 if (m_parentItem) { 0062 m_parentItem->markSortedChildItemsDirty(); 0063 } 0064 scheduleRepaint(boundingRect()); 0065 } 0066 0067 Item *Item::parentItem() const 0068 { 0069 return m_parentItem; 0070 } 0071 0072 void Item::setParentItem(Item *item) 0073 { 0074 if (m_parentItem == item) { 0075 return; 0076 } 0077 if (m_parentItem) { 0078 m_parentItem->removeChild(this); 0079 } 0080 m_parentItem = item; 0081 if (m_parentItem) { 0082 Q_ASSERT(m_parentItem->m_scene == m_scene); 0083 m_parentItem->addChild(this); 0084 } 0085 updateEffectiveVisibility(); 0086 } 0087 0088 void Item::addChild(Item *item) 0089 { 0090 Q_ASSERT(!m_childItems.contains(item)); 0091 0092 m_childItems.append(item); 0093 markSortedChildItemsDirty(); 0094 0095 updateBoundingRect(); 0096 scheduleRepaint(item->boundingRect().translated(item->position())); 0097 0098 Q_EMIT childAdded(item); 0099 } 0100 0101 void Item::removeChild(Item *item) 0102 { 0103 Q_ASSERT(m_childItems.contains(item)); 0104 scheduleRepaint(item->boundingRect().translated(item->position())); 0105 0106 m_childItems.removeOne(item); 0107 markSortedChildItemsDirty(); 0108 0109 updateBoundingRect(); 0110 } 0111 0112 QList<Item *> Item::childItems() const 0113 { 0114 return m_childItems; 0115 } 0116 0117 QPointF Item::position() const 0118 { 0119 return m_position; 0120 } 0121 0122 void Item::setPosition(const QPointF &point) 0123 { 0124 if (m_position != point) { 0125 scheduleRepaint(boundingRect()); 0126 m_position = point; 0127 if (m_parentItem) { 0128 m_parentItem->updateBoundingRect(); 0129 } 0130 scheduleRepaint(boundingRect()); 0131 Q_EMIT positionChanged(); 0132 } 0133 } 0134 0135 QSizeF Item::size() const 0136 { 0137 return m_size; 0138 } 0139 0140 void Item::setSize(const QSizeF &size) 0141 { 0142 if (m_size != size) { 0143 scheduleRepaint(rect()); 0144 m_size = size; 0145 updateBoundingRect(); 0146 scheduleRepaint(rect()); 0147 discardQuads(); 0148 Q_EMIT sizeChanged(); 0149 } 0150 } 0151 0152 QRectF Item::rect() const 0153 { 0154 return QRectF(QPoint(0, 0), size()); 0155 } 0156 0157 QRectF Item::boundingRect() const 0158 { 0159 return m_boundingRect; 0160 } 0161 0162 void Item::updateBoundingRect() 0163 { 0164 QRectF boundingRect = rect(); 0165 for (Item *item : std::as_const(m_childItems)) { 0166 boundingRect |= item->boundingRect().translated(item->position()); 0167 } 0168 if (m_boundingRect != boundingRect) { 0169 m_boundingRect = boundingRect; 0170 Q_EMIT boundingRectChanged(); 0171 if (m_parentItem) { 0172 m_parentItem->updateBoundingRect(); 0173 } 0174 } 0175 } 0176 0177 QList<QRectF> Item::shape() const 0178 { 0179 return QList<QRectF>(); 0180 } 0181 0182 QRegion Item::opaque() const 0183 { 0184 return QRegion(); 0185 } 0186 0187 QPointF Item::rootPosition() const 0188 { 0189 QPointF ret = position(); 0190 0191 Item *parent = parentItem(); 0192 while (parent) { 0193 ret += parent->position(); 0194 parent = parent->parentItem(); 0195 } 0196 0197 return ret; 0198 } 0199 0200 QMatrix4x4 Item::transform() const 0201 { 0202 return m_transform; 0203 } 0204 0205 void Item::setTransform(const QMatrix4x4 &transform) 0206 { 0207 m_transform = transform; 0208 } 0209 0210 QRegion Item::mapToGlobal(const QRegion ®ion) const 0211 { 0212 if (region.isEmpty()) { 0213 return QRegion(); 0214 } 0215 return region.translated(rootPosition().toPoint()); 0216 } 0217 0218 QRectF Item::mapToGlobal(const QRectF &rect) const 0219 { 0220 if (rect.isEmpty()) { 0221 return QRect(); 0222 } 0223 return rect.translated(rootPosition()); 0224 } 0225 0226 QRectF Item::mapFromGlobal(const QRectF &rect) const 0227 { 0228 if (rect.isEmpty()) { 0229 return QRect(); 0230 } 0231 return rect.translated(-rootPosition()); 0232 } 0233 0234 void Item::stackBefore(Item *sibling) 0235 { 0236 if (Q_UNLIKELY(!sibling)) { 0237 qCDebug(KWIN_CORE) << Q_FUNC_INFO << "requires a valid sibling"; 0238 return; 0239 } 0240 if (Q_UNLIKELY(!sibling->parentItem() || sibling->parentItem() != parentItem())) { 0241 qCDebug(KWIN_CORE) << Q_FUNC_INFO << "requires items to be siblings"; 0242 return; 0243 } 0244 if (Q_UNLIKELY(sibling == this)) { 0245 return; 0246 } 0247 0248 const int selfIndex = m_parentItem->m_childItems.indexOf(this); 0249 const int siblingIndex = m_parentItem->m_childItems.indexOf(sibling); 0250 0251 if (selfIndex == siblingIndex - 1) { 0252 return; 0253 } 0254 0255 m_parentItem->m_childItems.move(selfIndex, selfIndex > siblingIndex ? siblingIndex : siblingIndex - 1); 0256 markSortedChildItemsDirty(); 0257 0258 scheduleRepaint(boundingRect()); 0259 sibling->scheduleRepaint(sibling->boundingRect()); 0260 } 0261 0262 void Item::stackAfter(Item *sibling) 0263 { 0264 if (Q_UNLIKELY(!sibling)) { 0265 qCDebug(KWIN_CORE) << Q_FUNC_INFO << "requires a valid sibling"; 0266 return; 0267 } 0268 if (Q_UNLIKELY(!sibling->parentItem() || sibling->parentItem() != parentItem())) { 0269 qCDebug(KWIN_CORE) << Q_FUNC_INFO << "requires items to be siblings"; 0270 return; 0271 } 0272 if (Q_UNLIKELY(sibling == this)) { 0273 return; 0274 } 0275 0276 const int selfIndex = m_parentItem->m_childItems.indexOf(this); 0277 const int siblingIndex = m_parentItem->m_childItems.indexOf(sibling); 0278 0279 if (selfIndex == siblingIndex + 1) { 0280 return; 0281 } 0282 0283 m_parentItem->m_childItems.move(selfIndex, selfIndex > siblingIndex ? siblingIndex + 1 : siblingIndex); 0284 markSortedChildItemsDirty(); 0285 0286 scheduleRepaint(boundingRect()); 0287 sibling->scheduleRepaint(sibling->boundingRect()); 0288 } 0289 0290 void Item::scheduleRepaint(const QRegion ®ion) 0291 { 0292 if (isVisible()) { 0293 scheduleRepaintInternal(region); 0294 } 0295 } 0296 0297 void Item::scheduleRepaint(SceneDelegate *delegate, const QRegion ®ion) 0298 { 0299 if (isVisible()) { 0300 scheduleRepaintInternal(delegate, region); 0301 } 0302 } 0303 0304 void Item::scheduleRepaintInternal(const QRegion ®ion) 0305 { 0306 const QRegion globalRegion = mapToGlobal(region); 0307 const QList<SceneDelegate *> delegates = m_scene->delegates(); 0308 for (SceneDelegate *delegate : delegates) { 0309 const QRegion dirtyRegion = globalRegion & delegate->viewport(); 0310 if (!dirtyRegion.isEmpty()) { 0311 m_repaints[delegate] += dirtyRegion; 0312 delegate->layer()->scheduleRepaint(this); 0313 } 0314 } 0315 } 0316 0317 void Item::scheduleRepaintInternal(SceneDelegate *delegate, const QRegion ®ion) 0318 { 0319 const QRegion globalRegion = mapToGlobal(region); 0320 const QRegion dirtyRegion = globalRegion & delegate->viewport(); 0321 if (!dirtyRegion.isEmpty()) { 0322 m_repaints[delegate] += dirtyRegion; 0323 delegate->layer()->scheduleRepaint(this); 0324 } 0325 } 0326 0327 void Item::scheduleFrame() 0328 { 0329 if (!isVisible()) { 0330 return; 0331 } 0332 const QRect geometry = mapToGlobal(rect()).toRect(); 0333 const QList<SceneDelegate *> delegates = m_scene->delegates(); 0334 for (SceneDelegate *delegate : delegates) { 0335 if (delegate->viewport().intersects(geometry)) { 0336 delegate->layer()->scheduleRepaint(this); 0337 } 0338 } 0339 } 0340 0341 void Item::preprocess() 0342 { 0343 } 0344 0345 WindowQuadList Item::buildQuads() const 0346 { 0347 return WindowQuadList(); 0348 } 0349 0350 void Item::discardQuads() 0351 { 0352 m_quads.reset(); 0353 } 0354 0355 WindowQuadList Item::quads() const 0356 { 0357 if (!m_quads.has_value()) { 0358 m_quads = buildQuads(); 0359 } 0360 return m_quads.value(); 0361 } 0362 0363 QRegion Item::repaints(SceneDelegate *delegate) const 0364 { 0365 return m_repaints.value(delegate); 0366 } 0367 0368 void Item::resetRepaints(SceneDelegate *delegate) 0369 { 0370 m_repaints.insert(delegate, QRegion()); 0371 } 0372 0373 void Item::removeRepaints(SceneDelegate *delegate) 0374 { 0375 m_repaints.remove(delegate); 0376 } 0377 0378 bool Item::explicitVisible() const 0379 { 0380 return m_explicitVisible; 0381 } 0382 0383 bool Item::isVisible() const 0384 { 0385 return m_effectiveVisible; 0386 } 0387 0388 void Item::setVisible(bool visible) 0389 { 0390 if (m_explicitVisible != visible) { 0391 m_explicitVisible = visible; 0392 updateEffectiveVisibility(); 0393 } 0394 } 0395 0396 void Item::scheduleRepaint(const QRectF ®ion) 0397 { 0398 scheduleRepaint(QRegion(region.toAlignedRect())); 0399 } 0400 0401 bool Item::computeEffectiveVisibility() const 0402 { 0403 return m_explicitVisible && (!m_parentItem || m_parentItem->isVisible()); 0404 } 0405 0406 void Item::updateEffectiveVisibility() 0407 { 0408 const bool effectiveVisible = computeEffectiveVisibility(); 0409 if (m_effectiveVisible == effectiveVisible) { 0410 return; 0411 } 0412 0413 m_effectiveVisible = effectiveVisible; 0414 if (!m_effectiveVisible) { 0415 m_scene->addRepaint(mapToGlobal(boundingRect()).toAlignedRect()); 0416 } else { 0417 scheduleRepaintInternal(boundingRect().toAlignedRect()); 0418 } 0419 0420 for (Item *childItem : std::as_const(m_childItems)) { 0421 childItem->updateEffectiveVisibility(); 0422 } 0423 } 0424 0425 static bool compareZ(const Item *a, const Item *b) 0426 { 0427 return a->z() < b->z(); 0428 } 0429 0430 QList<Item *> Item::sortedChildItems() const 0431 { 0432 if (!m_sortedChildItems.has_value()) { 0433 QList<Item *> items = m_childItems; 0434 std::stable_sort(items.begin(), items.end(), compareZ); 0435 m_sortedChildItems = items; 0436 } 0437 return m_sortedChildItems.value(); 0438 } 0439 0440 void Item::markSortedChildItemsDirty() 0441 { 0442 m_sortedChildItems.reset(); 0443 } 0444 0445 const ColorDescription &Item::colorDescription() const 0446 { 0447 return m_colorDescription; 0448 } 0449 0450 void Item::setColorDescription(const ColorDescription &description) 0451 { 0452 m_colorDescription = description; 0453 } 0454 0455 PresentationModeHint Item::presentationHint() const 0456 { 0457 return m_presentationHint; 0458 } 0459 0460 void Item::setPresentationHint(PresentationModeHint hint) 0461 { 0462 m_presentationHint = hint; 0463 } 0464 0465 } // namespace KWin 0466 0467 #include "moc_item.cpp"