Changeset View
Changeset View
Standalone View
Standalone View
scene.cpp
Show First 20 Lines • Show All 71 Lines • ▼ Show 20 Line(s) | |||||
72 | #include <QVector2D> | 72 | #include <QVector2D> | ||
73 | 73 | | |||
74 | #include "x11client.h" | 74 | #include "x11client.h" | ||
75 | #include "deleted.h" | 75 | #include "deleted.h" | ||
76 | #include "effects.h" | 76 | #include "effects.h" | ||
77 | #include "overlaywindow.h" | 77 | #include "overlaywindow.h" | ||
78 | #include "screens.h" | 78 | #include "screens.h" | ||
79 | #include "shadow.h" | 79 | #include "shadow.h" | ||
80 | #include "subsurfacemonitor.h" | ||||
80 | #include "wayland_server.h" | 81 | #include "wayland_server.h" | ||
81 | 82 | | |||
82 | #include "thumbnailitem.h" | 83 | #include "thumbnailitem.h" | ||
83 | 84 | | |||
84 | #include <KWayland/Server/buffer_interface.h> | 85 | #include <KWayland/Server/buffer_interface.h> | ||
85 | #include <KWayland/Server/subcompositor_interface.h> | 86 | #include <KWayland/Server/subcompositor_interface.h> | ||
86 | #include <KWayland/Server/surface_interface.h> | 87 | #include <KWayland/Server/surface_interface.h> | ||
87 | 88 | | |||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Line(s) | 206 | { | |||
206 | if (!(orig_mask & PAINT_SCREEN_BACKGROUND_FIRST)) { | 207 | if (!(orig_mask & PAINT_SCREEN_BACKGROUND_FIRST)) { | ||
207 | paintBackground(infiniteRegion()); | 208 | paintBackground(infiniteRegion()); | ||
208 | } | 209 | } | ||
209 | QVector<Phase2Data> phase2; | 210 | QVector<Phase2Data> phase2; | ||
210 | phase2.reserve(stacking_order.size()); | 211 | phase2.reserve(stacking_order.size()); | ||
211 | foreach (Window * w, stacking_order) { // bottom to top | 212 | foreach (Window * w, stacking_order) { // bottom to top | ||
212 | Toplevel* topw = w->window(); | 213 | Toplevel* topw = w->window(); | ||
213 | 214 | | |||
215 | // Let the scene window update the window pixmap tree. | ||||
216 | w->preprocess(); | ||||
217 | | ||||
214 | // Reset the repaint_region. | 218 | // Reset the repaint_region. | ||
215 | // This has to be done here because many effects schedule a repaint for | 219 | // This has to be done here because many effects schedule a repaint for | ||
216 | // the next frame within Effects::prePaintWindow. | 220 | // the next frame within Effects::prePaintWindow. | ||
217 | topw->resetRepaints(); | 221 | topw->resetRepaints(); | ||
218 | 222 | | |||
219 | WindowPrePaintData data; | 223 | WindowPrePaintData data; | ||
220 | data.mask = orig_mask | (w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT); | 224 | data.mask = orig_mask | (w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT); | ||
221 | w->resetPaintingEnabled(); | 225 | w->resetPaintingEnabled(); | ||
Show All 39 Lines | 264 | for (int i = 0; i < stacking_order.count(); ++i) { | |||
261 | Window *window = stacking_order[i]; | 265 | Window *window = stacking_order[i]; | ||
262 | Toplevel *toplevel = window->window(); | 266 | Toplevel *toplevel = window->window(); | ||
263 | WindowPrePaintData data; | 267 | WindowPrePaintData data; | ||
264 | data.mask = orig_mask | (window->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT); | 268 | data.mask = orig_mask | (window->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT); | ||
265 | window->resetPaintingEnabled(); | 269 | window->resetPaintingEnabled(); | ||
266 | data.paint = region; | 270 | data.paint = region; | ||
267 | data.paint |= toplevel->repaints(); | 271 | data.paint |= toplevel->repaints(); | ||
268 | 272 | | |||
273 | // Let the scene window update the window pixmap tree. | ||||
274 | window->preprocess(); | ||||
275 | | ||||
269 | // Reset the repaint_region. | 276 | // Reset the repaint_region. | ||
270 | // This has to be done here because many effects schedule a repaint for | 277 | // This has to be done here because many effects schedule a repaint for | ||
271 | // the next frame within Effects::prePaintWindow. | 278 | // the next frame within Effects::prePaintWindow. | ||
272 | toplevel->resetRepaints(); | 279 | toplevel->resetRepaints(); | ||
273 | 280 | | |||
274 | // Clip out the decoration for opaque windows; the decoration is drawn in the second pass | 281 | // Clip out the decoration for opaque windows; the decoration is drawn in the second pass | ||
275 | opaqueFullscreen = false; // TODO: do we care about unmanged windows here (maybe input windows?) | 282 | opaqueFullscreen = false; // TODO: do we care about unmanged windows here (maybe input windows?) | ||
276 | if (window->isOpaque()) { | 283 | if (window->isOpaque()) { | ||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Line(s) | 306 | #endif | |||
384 | } | 391 | } | ||
385 | } | 392 | } | ||
386 | 393 | | |||
387 | void Scene::addToplevel(Toplevel *c) | 394 | void Scene::addToplevel(Toplevel *c) | ||
388 | { | 395 | { | ||
389 | Q_ASSERT(!m_windows.contains(c)); | 396 | Q_ASSERT(!m_windows.contains(c)); | ||
390 | Scene::Window *w = createWindow(c); | 397 | Scene::Window *w = createWindow(c); | ||
391 | m_windows[ c ] = w; | 398 | m_windows[ c ] = w; | ||
399 | | ||||
400 | auto discardPixmap = [w]() { w->discardPixmap(); }; | ||||
401 | auto discardQuads = [w]() { w->invalidateQuadsCache(); }; | ||||
402 | | ||||
392 | connect(c, SIGNAL(geometryShapeChanged(KWin::Toplevel*,QRect)), SLOT(windowGeometryShapeChanged(KWin::Toplevel*))); | 403 | connect(c, SIGNAL(geometryShapeChanged(KWin::Toplevel*,QRect)), SLOT(windowGeometryShapeChanged(KWin::Toplevel*))); | ||
393 | connect(c, SIGNAL(windowClosed(KWin::Toplevel*,KWin::Deleted*)), SLOT(windowClosed(KWin::Toplevel*,KWin::Deleted*))); | 404 | connect(c, SIGNAL(windowClosed(KWin::Toplevel*,KWin::Deleted*)), SLOT(windowClosed(KWin::Toplevel*,KWin::Deleted*))); | ||
394 | //A change of scale won't affect the geometry in compositor co-ordinates, but will affect the window quads. | | |||
395 | if (c->surface()) { | 405 | if (c->surface()) { | ||
396 | connect(c->surface(), &KWayland::Server::SurfaceInterface::scaleChanged, this, std::bind(&Scene::windowGeometryShapeChanged, this, c)); | 406 | // We generate window quads for sub-surfaces so it's quite important to discard | ||
397 | } | 407 | // the pixmap tree and cached window quads when the sub-surface tree is changed. | ||
398 | connect(c, &Toplevel::screenScaleChanged, this, | 408 | SubSurfaceMonitor *monitor = new SubSurfaceMonitor(c->surface(), this); | ||
399 | [this, c] { | 409 | | ||
400 | windowGeometryShapeChanged(c); | 410 | // TODO(vlad): Is there a more efficient way to manage window pixmap trees? | ||
411 | connect(monitor, &SubSurfaceMonitor::subSurfaceAdded, this, discardPixmap); | ||||
davidedmundson: I feel like the monitor should be responsible for abstracting added/removed/mapped/unmapped… | |||||
Hmm, I don't particularly see the need for a new sub-surface state given the job can be done with the existing signals and states. zzag: Hmm, I don't particularly see the need for a new sub-surface state given the job can be done… | |||||
412 | connect(monitor, &SubSurfaceMonitor::subSurfaceRemoved, this, discardPixmap); | ||||
413 | connect(monitor, &SubSurfaceMonitor::subSurfaceResized, this, discardPixmap); | ||||
414 | connect(monitor, &SubSurfaceMonitor::subSurfaceMapped, this, discardPixmap); | ||||
415 | connect(monitor, &SubSurfaceMonitor::subSurfaceUnmapped, this, discardPixmap); | ||||
416 | | ||||
417 | connect(monitor, &SubSurfaceMonitor::subSurfaceAdded, this, discardQuads); | ||||
418 | connect(monitor, &SubSurfaceMonitor::subSurfaceRemoved, this, discardQuads); | ||||
419 | connect(monitor, &SubSurfaceMonitor::subSurfaceMoved, this, discardQuads); | ||||
420 | connect(monitor, &SubSurfaceMonitor::subSurfaceResized, this, discardQuads); | ||||
421 | connect(monitor, &SubSurfaceMonitor::subSurfaceMapped, this, discardQuads); | ||||
422 | connect(monitor, &SubSurfaceMonitor::subSurfaceUnmapped, this, discardQuads); | ||||
423 | | ||||
424 | connect(c->surface(), &KWayland::Server::SurfaceInterface::scaleChanged, this, discardQuads); | ||||
401 | } | 425 | } | ||
402 | ); | 426 | | ||
427 | connect(c, &Toplevel::screenScaleChanged, this, discardQuads); | ||||
428 | connect(c, &Toplevel::shadowChanged, this, discardQuads); | ||||
429 | | ||||
403 | c->effectWindow()->setSceneWindow(w); | 430 | c->effectWindow()->setSceneWindow(w); | ||
404 | c->updateShadow(); | 431 | c->updateShadow(); | ||
405 | w->updateShadow(c->shadow()); | 432 | w->updateShadow(c->shadow()); | ||
406 | connect(c, &Toplevel::shadowChanged, this, | | |||
407 | [w] { | | |||
408 | w->invalidateQuadsCache(); | | |||
409 | } | | |||
410 | ); | | |||
411 | } | 433 | } | ||
412 | 434 | | |||
413 | void Scene::removeToplevel(Toplevel *toplevel) | 435 | void Scene::removeToplevel(Toplevel *toplevel) | ||
414 | { | 436 | { | ||
415 | Q_ASSERT(m_windows.contains(toplevel)); | 437 | Q_ASSERT(m_windows.contains(toplevel)); | ||
416 | delete m_windows.take(toplevel); | 438 | delete m_windows.take(toplevel); | ||
417 | toplevel->effectWindow()->setSceneWindow(nullptr); | 439 | toplevel->effectWindow()->setSceneWindow(nullptr); | ||
418 | } | 440 | } | ||
▲ Show 20 Lines • Show All 308 Lines • ▼ Show 20 Line(s) | 741 | { | |||
727 | } | 749 | } | ||
728 | } | 750 | } | ||
729 | 751 | | |||
730 | void Scene::Window::updatePixmap() | 752 | void Scene::Window::updatePixmap() | ||
731 | { | 753 | { | ||
732 | if (m_currentPixmap.isNull()) { | 754 | if (m_currentPixmap.isNull()) { | ||
733 | m_currentPixmap.reset(createWindowPixmap()); | 755 | m_currentPixmap.reset(createWindowPixmap()); | ||
734 | } | 756 | } | ||
735 | if (!m_currentPixmap->isValid()) { | 757 | if (m_currentPixmap->isValid()) { | ||
758 | m_currentPixmap->update(); | ||||
759 | } else { | ||||
736 | m_currentPixmap->create(); | 760 | m_currentPixmap->create(); | ||
737 | } | 761 | } | ||
738 | } | 762 | } | ||
739 | 763 | | |||
740 | void Scene::Window::discardShape() | 764 | void Scene::Window::discardShape() | ||
741 | { | 765 | { | ||
742 | // it is created on-demand and cached, simply | 766 | // it is created on-demand and cached, simply | ||
743 | // reset the flag | 767 | // reset the flag | ||
Show All 30 Lines | 773 | { | |||
774 | 798 | | |||
775 | m_bufferShapeIsValid = true; | 799 | m_bufferShapeIsValid = true; | ||
776 | 800 | | |||
777 | return m_bufferShape; | 801 | return m_bufferShape; | ||
778 | } | 802 | } | ||
779 | 803 | | |||
780 | QRegion Scene::Window::clientShape() const | 804 | QRegion Scene::Window::clientShape() const | ||
781 | { | 805 | { | ||
782 | if (AbstractClient *client = qobject_cast<AbstractClient *>(toplevel)) { | 806 | if (isShaded()) | ||
783 | if (client->isShade()) { | | |||
784 | return QRegion(); | 807 | return QRegion(); | ||
785 | } | | |||
786 | } | | |||
787 | 808 | | |||
788 | const QRegion shape = bufferShape(); | 809 | const QRegion shape = bufferShape(); | ||
789 | const QMargins bufferMargins = toplevel->bufferMargins(); | 810 | const QMargins bufferMargins = toplevel->bufferMargins(); | ||
790 | if (bufferMargins.isNull()) { | 811 | if (bufferMargins.isNull()) { | ||
791 | return shape; | 812 | return shape; | ||
792 | } | 813 | } | ||
793 | 814 | | |||
794 | const QRect clippingRect = QRect(QPoint(0, 0), toplevel->bufferGeometry().size()) - toplevel->bufferMargins(); | 815 | const QRect clippingRect = QRect(QPoint(0, 0), toplevel->bufferGeometry().size()) - toplevel->bufferMargins(); | ||
Show All 25 Lines | 832 | { | |||
820 | return true; // Unmanaged is always visible | 841 | return true; // Unmanaged is always visible | ||
821 | } | 842 | } | ||
822 | 843 | | |||
823 | bool Scene::Window::isOpaque() const | 844 | bool Scene::Window::isOpaque() const | ||
824 | { | 845 | { | ||
825 | return toplevel->opacity() == 1.0 && !toplevel->hasAlpha(); | 846 | return toplevel->opacity() == 1.0 && !toplevel->hasAlpha(); | ||
826 | } | 847 | } | ||
827 | 848 | | |||
849 | bool Scene::Window::isShaded() const | ||||
850 | { | ||||
851 | if (AbstractClient *client = qobject_cast<AbstractClient *>(toplevel)) | ||||
852 | return client->isShade(); | ||||
853 | return false; | ||||
854 | } | ||||
855 | | ||||
828 | bool Scene::Window::isPaintingEnabled() const | 856 | bool Scene::Window::isPaintingEnabled() const | ||
829 | { | 857 | { | ||
830 | return !disable_painting; | 858 | return !disable_painting; | ||
831 | } | 859 | } | ||
832 | 860 | | |||
833 | void Scene::Window::resetPaintingEnabled() | 861 | void Scene::Window::resetPaintingEnabled() | ||
834 | { | 862 | { | ||
835 | disable_painting = 0; | 863 | disable_painting = 0; | ||
Show All 28 Lines | 891 | { | |||
864 | disable_painting |= reason; | 892 | disable_painting |= reason; | ||
865 | } | 893 | } | ||
866 | 894 | | |||
867 | WindowQuadList Scene::Window::buildQuads(bool force) const | 895 | WindowQuadList Scene::Window::buildQuads(bool force) const | ||
868 | { | 896 | { | ||
869 | if (cached_quad_list != nullptr && !force) | 897 | if (cached_quad_list != nullptr && !force) | ||
870 | return *cached_quad_list; | 898 | return *cached_quad_list; | ||
871 | 899 | | |||
872 | WindowQuadList ret = makeContentsQuads(); | 900 | WindowQuadList ret; | ||
901 | | ||||
902 | if (!isShaded()) { | ||||
903 | ret += makeContentsQuads(); | ||||
904 | } | ||||
873 | 905 | | |||
874 | if (!toplevel->frameMargins().isNull()) { | 906 | if (!toplevel->frameMargins().isNull()) { | ||
875 | AbstractClient *client = dynamic_cast<AbstractClient*>(toplevel); | 907 | AbstractClient *client = dynamic_cast<AbstractClient*>(toplevel); | ||
876 | QRegion center = toplevel->transparentRect(); | 908 | QRegion center = toplevel->transparentRect(); | ||
877 | const QRegion decoration = decorationShape(); | 909 | const QRegion decoration = decorationShape(); | ||
878 | qreal decorationScale = 1.0; | 910 | qreal decorationScale = 1.0; | ||
879 | 911 | | |||
880 | QRect rects[4]; | 912 | QRect rects[4]; | ||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Line(s) | 962 | for (int i = 0; i < 4; i++) { | |||
964 | } | 996 | } | ||
965 | } | 997 | } | ||
966 | 998 | | |||
967 | return list; | 999 | return list; | ||
968 | } | 1000 | } | ||
969 | 1001 | | |||
970 | WindowQuadList Scene::Window::makeContentsQuads() const | 1002 | WindowQuadList Scene::Window::makeContentsQuads() const | ||
971 | { | 1003 | { | ||
972 | const QRegion contentsRegion = clientShape(); | 1004 | // TODO(vlad): What about the case where we need to build window quads for a deleted | ||
973 | if (contentsRegion.isEmpty()) { | 1005 | // window? Presumably, the current window will be invalid so no window quads will be | ||
974 | return WindowQuadList(); | 1006 | // generated. Is it okay? | ||
975 | } | | |||
976 | 1007 | | |||
977 | const QPointF geometryOffset = bufferOffset(); | 1008 | WindowPixmap *currentPixmap = windowPixmap<WindowPixmap>(); | ||
978 | const qreal textureScale = toplevel->bufferScale(); | 1009 | if (!currentPixmap) | ||
1010 | return WindowQuadList(); | ||||
979 | 1011 | | |||
980 | WindowQuadList quads; | 1012 | WindowQuadList quads; | ||
981 | quads.reserve(contentsRegion.rectCount()); | 1013 | int id = 0; | ||
1014 | | ||||
1015 | // We need to assign an id to each generated window quad in order to be able to match | ||||
1016 | // a list of window quads against a particular window pixmap. We traverse the window | ||||
1017 | // pixmap tree in the depth-first search manner and assign an id to each window quad. | ||||
1018 | // The id is the time when we visited the window pixmap. | ||||
1019 | | ||||
1020 | QStack<WindowPixmap *> stack; | ||||
1021 | stack.push(currentPixmap); | ||||
1022 | | ||||
1023 | while (!stack.isEmpty()) { | ||||
1024 | WindowPixmap *windowPixmap = stack.pop(); | ||||
982 | 1025 | | |||
983 | for (const QRectF &rect : contentsRegion) { | 1026 | // If it's an unmapped sub-surface, don't generate window quads for it. | ||
984 | WindowQuad quad(WindowQuadContents); | 1027 | if (!windowPixmap->isValid()) | ||
1028 | continue; | ||||
985 | 1029 | | |||
986 | const qreal x0 = rect.left() + geometryOffset.x(); | 1030 | const QRegion region = windowPixmap->shape(); | ||
987 | const qreal y0 = rect.top() + geometryOffset.y(); | 1031 | const QPoint position = windowPixmap->framePosition(); | ||
988 | const qreal x1 = rect.right() + geometryOffset.x(); | 1032 | const qreal scale = windowPixmap->scale(); | ||
989 | const qreal y1 = rect.bottom() + geometryOffset.y(); | 1033 | const int quadId = id++; | ||
990 | 1034 | | |||
991 | const qreal u0 = rect.left() * textureScale; | 1035 | for (const QRectF &rect : region) { | ||
How about for (const QRectF &rect : region) { const QRect positioned = rect.translated(position); const QRect scaled = rect * scale; quad[0] = WindowVertex(positioned.topLeft(), scaled.topLeft()); quad[1] = WindowVertex(positioned.topRight(), scaled.topRight()); quad[2] = WindowVertex(positioned.bottomRight(), scaled.bottomRight()); quad[3] = WindowVertex(positioned.bottomLeft(), scaled.bottomLeft()); quads << quad; } apol: How about
for (const QRectF &rect : region) {
const QRect positioned = rect.translated… | |||||
zzag: Can't do `rect * scale` because it rounds numbers. | |||||
meven: Even using `QRectF` instead of `QRect` ? | |||||
Oh, yeah. I use QRectF because right() and bottom() return expected values, but now I recall that I should avoid using right() and bottom(). I'll change QRectF to QRect. This will also make Qt Creator a bit happier. zzag: Oh, yeah. I use QRectF because right() and bottom() return expected values, but now I recall… | |||||
992 | const qreal v0 = rect.top() * textureScale; | 1036 | // Note that the window quad id is not unique if the window is shaped, i.e. the | ||
993 | const qreal u1 = rect.right() * textureScale; | 1037 | // region contains more than just one rectangle. We assume that the "source" quad | ||
994 | const qreal v1 = rect.bottom() * textureScale; | 1038 | // had been subdivided. | ||
1039 | WindowQuad quad(WindowQuadContents, quadId); | ||||
1040 | | ||||
1041 | const qreal x0 = rect.left() + position.x(); | ||||
1042 | const qreal y0 = rect.top() + position.y(); | ||||
1043 | const qreal x1 = rect.right() + position.x(); | ||||
1044 | const qreal y1 = rect.bottom() + position.y(); | ||||
1045 | | ||||
1046 | const qreal u0 = rect.left() * scale; | ||||
1047 | const qreal v0 = rect.top() * scale; | ||||
1048 | const qreal u1 = rect.right() * scale; | ||||
1049 | const qreal v1 = rect.bottom() * scale; | ||||
995 | 1050 | | |||
996 | quad[0] = WindowVertex(QPointF(x0, y0), QPointF(u0, v0)); | 1051 | quad[0] = WindowVertex(QPointF(x0, y0), QPointF(u0, v0)); | ||
997 | quad[1] = WindowVertex(QPointF(x1, y0), QPointF(u1, v0)); | 1052 | quad[1] = WindowVertex(QPointF(x1, y0), QPointF(u1, v0)); | ||
998 | quad[2] = WindowVertex(QPointF(x1, y1), QPointF(u1, v1)); | 1053 | quad[2] = WindowVertex(QPointF(x1, y1), QPointF(u1, v1)); | ||
999 | quad[3] = WindowVertex(QPointF(x0, y1), QPointF(u0, v1)); | 1054 | quad[3] = WindowVertex(QPointF(x0, y1), QPointF(u0, v1)); | ||
1000 | 1055 | | |||
1001 | quads << quad; | 1056 | quads << quad; | ||
1002 | } | 1057 | } | ||
1003 | 1058 | | |||
1059 | // Push the child window pixmaps onto the stack, remember we're visiting the pixmaps | ||||
1060 | // in the depth-first search manner. | ||||
1061 | const auto children = windowPixmap->children(); | ||||
1062 | for (WindowPixmap *child : children) | ||||
1063 | stack.push(child); | ||||
1064 | } | ||||
1065 | | ||||
1004 | return quads; | 1066 | return quads; | ||
1005 | } | 1067 | } | ||
1006 | 1068 | | |||
1007 | void Scene::Window::invalidateQuadsCache() | 1069 | void Scene::Window::invalidateQuadsCache() | ||
1008 | { | 1070 | { | ||
1009 | cached_quad_list.reset(); | 1071 | cached_quad_list.reset(); | ||
1010 | } | 1072 | } | ||
1011 | 1073 | | |||
1012 | void Scene::Window::updateShadow(Shadow* shadow) | 1074 | void Scene::Window::updateShadow(Shadow* shadow) | ||
1013 | { | 1075 | { | ||
1014 | if (m_shadow == shadow) { | 1076 | if (m_shadow == shadow) { | ||
1015 | return; | 1077 | return; | ||
1016 | } | 1078 | } | ||
1017 | delete m_shadow; | 1079 | delete m_shadow; | ||
1018 | m_shadow = shadow; | 1080 | m_shadow = shadow; | ||
1019 | } | 1081 | } | ||
1020 | 1082 | | |||
1083 | void Scene::Window::preprocess() | ||||
1084 | { | ||||
1085 | // The tracked damage will be reset after the scene is done with copying buffer's data. | ||||
1086 | // Note that we have to be prepared for the case where no damage has occurred since kwin | ||||
1087 | // core may discard the current window pixmap at any moment. | ||||
1088 | if (!m_currentPixmap || !window()->damage().isEmpty()) { | ||||
1089 | updatePixmap(); | ||||
1090 | } | ||||
1091 | } | ||||
1092 | | ||||
1021 | //**************************************** | 1093 | //**************************************** | ||
1022 | // WindowPixmap | 1094 | // WindowPixmap | ||
1023 | //**************************************** | 1095 | //**************************************** | ||
1024 | WindowPixmap::WindowPixmap(Scene::Window *window) | 1096 | WindowPixmap::WindowPixmap(Scene::Window *window) | ||
1025 | : m_window(window) | 1097 | : m_window(window) | ||
1026 | , m_pixmap(XCB_PIXMAP_NONE) | 1098 | , m_pixmap(XCB_PIXMAP_NONE) | ||
1027 | , m_discarded(false) | 1099 | , m_discarded(false) | ||
1028 | { | 1100 | { | ||
Show All 25 Lines | |||||
1054 | void WindowPixmap::create() | 1126 | void WindowPixmap::create() | ||
1055 | { | 1127 | { | ||
1056 | if (isValid() || toplevel()->isDeleted()) { | 1128 | if (isValid() || toplevel()->isDeleted()) { | ||
1057 | return; | 1129 | return; | ||
1058 | } | 1130 | } | ||
1059 | // always update from Buffer on Wayland, don't try using XPixmap | 1131 | // always update from Buffer on Wayland, don't try using XPixmap | ||
1060 | if (kwinApp()->shouldUseWaylandForCompositing()) { | 1132 | if (kwinApp()->shouldUseWaylandForCompositing()) { | ||
1061 | // use Buffer | 1133 | // use Buffer | ||
1062 | updateBuffer(); | 1134 | update(); | ||
1063 | if ((m_buffer || !m_fbo.isNull()) && m_subSurface.isNull()) { | 1135 | if (!isRoot() && isValid()) { | ||
1064 | m_window->unreferencePreviousPixmap(); | 1136 | m_window->unreferencePreviousPixmap(); | ||
1065 | } | 1137 | } | ||
1066 | return; | 1138 | return; | ||
1067 | } | 1139 | } | ||
1068 | XServerGrabber grabber; | 1140 | XServerGrabber grabber; | ||
1069 | xcb_pixmap_t pix = xcb_generate_id(connection()); | 1141 | xcb_pixmap_t pix = xcb_generate_id(connection()); | ||
1070 | xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection(), toplevel()->frameId(), pix); | 1142 | xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection(), toplevel()->frameId(), pix); | ||
1071 | Xcb::WindowAttributes windowAttributes(toplevel()->frameId()); | 1143 | Xcb::WindowAttributes windowAttributes(toplevel()->frameId()); | ||
Show All 17 Lines | 1158 | if (windowGeometry.size() != bufferGeometry.size()) { | |||
1089 | return; | 1161 | return; | ||
1090 | } | 1162 | } | ||
1091 | m_pixmap = pix; | 1163 | m_pixmap = pix; | ||
1092 | m_pixmapSize = bufferGeometry.size(); | 1164 | m_pixmapSize = bufferGeometry.size(); | ||
1093 | m_contentsRect = QRect(toplevel()->clientPos(), toplevel()->clientSize()); | 1165 | m_contentsRect = QRect(toplevel()->clientPos(), toplevel()->clientSize()); | ||
1094 | m_window->unreferencePreviousPixmap(); | 1166 | m_window->unreferencePreviousPixmap(); | ||
1095 | } | 1167 | } | ||
1096 | 1168 | | |||
1097 | WindowPixmap *WindowPixmap::createChild(const QPointer<KWayland::Server::SubSurfaceInterface> &subSurface) | 1169 | void WindowPixmap::update() | ||
1098 | { | | |||
1099 | Q_UNUSED(subSurface) | | |||
1100 | return nullptr; | | |||
1101 | } | | |||
1102 | | ||||
1103 | bool WindowPixmap::isValid() const | | |||
1104 | { | | |||
1105 | if (!m_buffer.isNull() || !m_fbo.isNull() || !m_internalImage.isNull()) { | | |||
1106 | return true; | | |||
1107 | } | | |||
1108 | return m_pixmap != XCB_PIXMAP_NONE; | | |||
1109 | } | | |||
1110 | | ||||
1111 | void WindowPixmap::updateBuffer() | | |||
1112 | { | 1170 | { | ||
1113 | using namespace KWayland::Server; | 1171 | using namespace KWayland::Server; | ||
1114 | if (SurfaceInterface *s = surface()) { | 1172 | if (SurfaceInterface *s = surface()) { | ||
1115 | QVector<WindowPixmap*> oldTree = m_children; | 1173 | QVector<WindowPixmap*> oldTree = m_children; | ||
1116 | QVector<WindowPixmap*> children; | 1174 | QVector<WindowPixmap*> children; | ||
1117 | using namespace KWayland::Server; | 1175 | using namespace KWayland::Server; | ||
1118 | const auto subSurfaces = s->childSubSurfaces(); | 1176 | const auto subSurfaces = s->childSubSurfaces(); | ||
1119 | for (const auto &subSurface : subSurfaces) { | 1177 | for (const auto &subSurface : subSurfaces) { | ||
1120 | if (subSurface.isNull()) { | 1178 | if (subSurface.isNull()) { | ||
1121 | continue; | 1179 | continue; | ||
1122 | } | 1180 | } | ||
I know it's existing code, but we should be checking for a buffer here the docs say "A sub-surface is hidden if the parent becomes hidden, " davidedmundson: I know it's existing code, but we should be checking for a buffer here
the docs say "A sub… | |||||
I didn't do it because I didn't want to change how kwin references buffers. Should I change it? zzag: I didn't do it because I didn't want to change how kwin references buffers. Should I change it? | |||||
1123 | auto it = std::find_if(oldTree.begin(), oldTree.end(), [subSurface] (WindowPixmap *p) { return p->m_subSurface == subSurface; }); | 1181 | auto it = std::find_if(oldTree.begin(), oldTree.end(), [subSurface] (WindowPixmap *p) { return p->m_subSurface == subSurface; }); | ||
1124 | if (it != oldTree.end()) { | 1182 | if (it != oldTree.end()) { | ||
1125 | children << *it; | 1183 | children << *it; | ||
1126 | (*it)->updateBuffer(); | 1184 | (*it)->update(); | ||
1127 | oldTree.erase(it); | 1185 | oldTree.erase(it); | ||
1128 | } else { | 1186 | } else { | ||
1129 | WindowPixmap *p = createChild(subSurface); | 1187 | WindowPixmap *p = createChild(subSurface); | ||
1130 | if (p) { | 1188 | if (p) { | ||
1131 | p->create(); | 1189 | p->create(); | ||
1132 | children << p; | 1190 | children << p; | ||
1133 | } | 1191 | } | ||
1134 | } | 1192 | } | ||
Show All 27 Lines | 1219 | } else { | |||
1162 | if (m_buffer) { | 1220 | if (m_buffer) { | ||
1163 | QObject::disconnect(m_buffer.data(), &BufferInterface::aboutToBeDestroyed, m_buffer.data(), &BufferInterface::unref); | 1221 | QObject::disconnect(m_buffer.data(), &BufferInterface::aboutToBeDestroyed, m_buffer.data(), &BufferInterface::unref); | ||
1164 | m_buffer->unref(); | 1222 | m_buffer->unref(); | ||
1165 | m_buffer.clear(); | 1223 | m_buffer.clear(); | ||
1166 | } | 1224 | } | ||
1167 | } | 1225 | } | ||
1168 | } | 1226 | } | ||
1169 | 1227 | | |||
1228 | WindowPixmap *WindowPixmap::createChild(const QPointer<KWayland::Server::SubSurfaceInterface> &subSurface) | ||||
1229 | { | ||||
1230 | Q_UNUSED(subSurface) | ||||
1231 | return nullptr; | ||||
1232 | } | ||||
1233 | | ||||
1234 | bool WindowPixmap::isValid() const | ||||
1235 | { | ||||
1236 | if (!m_buffer.isNull() || !m_fbo.isNull() || !m_internalImage.isNull()) { | ||||
1237 | return true; | ||||
1238 | } | ||||
1239 | return m_pixmap != XCB_PIXMAP_NONE; | ||||
1240 | } | ||||
1241 | | ||||
1242 | bool WindowPixmap::isRoot() const | ||||
1243 | { | ||||
1244 | return !m_parent; | ||||
1245 | } | ||||
1246 | | ||||
1170 | KWayland::Server::SurfaceInterface *WindowPixmap::surface() const | 1247 | KWayland::Server::SurfaceInterface *WindowPixmap::surface() const | ||
1171 | { | 1248 | { | ||
1172 | if (!m_subSurface.isNull()) { | 1249 | if (!m_subSurface.isNull()) { | ||
1173 | return m_subSurface->surface().data(); | 1250 | return m_subSurface->surface().data(); | ||
1174 | } else { | 1251 | } else { | ||
1175 | return toplevel()->surface(); | 1252 | return toplevel()->surface(); | ||
1176 | } | 1253 | } | ||
1177 | } | 1254 | } | ||
1178 | 1255 | | |||
1256 | QPoint WindowPixmap::position() const | ||||
1257 | { | ||||
1258 | if (subSurface()) | ||||
1259 | return subSurface()->position(); | ||||
1260 | return m_window->bufferOffset(); | ||||
1261 | } | ||||
1262 | | ||||
1263 | QPoint WindowPixmap::framePosition() const | ||||
1264 | { | ||||
1265 | return position() + (m_parent ? m_parent->framePosition() : QPoint()); | ||||
1266 | } | ||||
1267 | | ||||
1268 | qreal WindowPixmap::scale() const | ||||
1269 | { | ||||
1270 | if (surface()) | ||||
1271 | return surface()->scale(); | ||||
1272 | return toplevel()->bufferScale(); | ||||
1273 | } | ||||
1274 | | ||||
1275 | QRegion WindowPixmap::shape() const | ||||
1276 | { | ||||
1277 | if (subSurface()) | ||||
1278 | return QRect(QPoint(), surface()->size()); | ||||
1279 | return m_window->clientShape(); | ||||
1280 | } | ||||
1281 | | ||||
1282 | bool WindowPixmap::hasAlphaChannel() const | ||||
1283 | { | ||||
1284 | if (buffer()) | ||||
1285 | return buffer()->hasAlphaChannel(); | ||||
1286 | return toplevel()->hasAlpha(); | ||||
1287 | } | ||||
1288 | | ||||
1179 | //**************************************** | 1289 | //**************************************** | ||
1180 | // Scene::EffectFrame | 1290 | // Scene::EffectFrame | ||
1181 | //**************************************** | 1291 | //**************************************** | ||
1182 | Scene::EffectFrame::EffectFrame(EffectFrameImpl* frame) | 1292 | Scene::EffectFrame::EffectFrame(EffectFrameImpl* frame) | ||
1183 | : m_effectFrame(frame) | 1293 | : m_effectFrame(frame) | ||
1184 | { | 1294 | { | ||
1185 | } | 1295 | } | ||
1186 | 1296 | | |||
Show All 14 Lines |
I feel like the monitor should be responsible for abstracting added/removed/mapped/unmapped into just 2 signals when we gain a valid subsurface and when a subsurface loses validity (either from being removed or unmapped)
If the subsurface changes and it has no buffer then we don't need to do anything at a tree level.