Changeset View
Changeset View
Standalone View
Standalone View
scene.cpp
Show First 20 Lines • Show All 271 Lines • ▼ Show 20 Line(s) | 259 | for (int i = 0; i < stacking_order.count(); ++i) { | |||
---|---|---|---|---|---|
272 | 272 | | |||
273 | // Clip out the decoration for opaque windows; the decoration is drawn in the second pass | 273 | // Clip out the decoration for opaque windows; the decoration is drawn in the second pass | ||
274 | opaqueFullscreen = false; // TODO: do we care about unmanged windows here (maybe input windows?) | 274 | opaqueFullscreen = false; // TODO: do we care about unmanged windows here (maybe input windows?) | ||
275 | if (window->isOpaque()) { | 275 | if (window->isOpaque()) { | ||
276 | AbstractClient *client = qobject_cast<AbstractClient *>(toplevel); | 276 | AbstractClient *client = qobject_cast<AbstractClient *>(toplevel); | ||
277 | if (client) { | 277 | if (client) { | ||
278 | opaqueFullscreen = client->isFullScreen(); | 278 | opaqueFullscreen = client->isFullScreen(); | ||
279 | } | 279 | } | ||
280 | X11Client *cc = dynamic_cast<X11Client *>(client); | 280 | if (!(client && client->decorationHasAlpha())) { | ||
281 | // the window is fully opaque | 281 | data.clip = window->decorationShape().translated(window->pos()); | ||
282 | if (cc && cc->decorationHasAlpha()) { | | |||
283 | // decoration uses alpha channel, so we may not exclude it in clipping | | |||
284 | data.clip = window->clientShape().translated(window->x(), window->y()); | | |||
285 | } else { | | |||
286 | // decoration is fully opaque | | |||
287 | if (client && client->isShade()) { | | |||
288 | data.clip = QRegion(); | | |||
289 | } else { | | |||
290 | data.clip = window->shape().translated(window->x(), window->y()); | | |||
291 | } | | |||
292 | } | 282 | } | ||
283 | data.clip |= window->clientShape().translated(window->pos() + window->bufferOffset()); | ||||
293 | } else if (toplevel->hasAlpha() && toplevel->opacity() == 1.0) { | 284 | } else if (toplevel->hasAlpha() && toplevel->opacity() == 1.0) { | ||
294 | // the window is partially opaque | 285 | const QRegion clientShape = window->clientShape().translated(window->pos() + window->bufferOffset()); | ||
295 | data.clip = (window->clientShape() & toplevel->opaqueRegion().translated(toplevel->clientPos())).translated(window->x(), window->y()); | 286 | const QRegion opaqueShape = toplevel->opaqueRegion().translated(window->pos() + toplevel->clientPos()); | ||
287 | data.clip = clientShape & opaqueShape; | ||||
296 | } else { | 288 | } else { | ||
297 | data.clip = QRegion(); | 289 | data.clip = QRegion(); | ||
298 | } | 290 | } | ||
299 | data.quads = window->buildQuads(); | 291 | data.quads = window->buildQuads(); | ||
300 | // preparation step | 292 | // preparation step | ||
301 | effects->prePaintWindow(effectWindow(window), data, time_diff); | 293 | effects->prePaintWindow(effectWindow(window), data, time_diff); | ||
302 | #if !defined(QT_NO_DEBUG) | 294 | #if !defined(QT_NO_DEBUG) | ||
303 | if (data.quads.isTransformed()) { | 295 | if (data.quads.isTransformed()) { | ||
▲ Show 20 Lines • Show All 387 Lines • ▼ Show 20 Line(s) | |||||
691 | Scene::Window::Window(Toplevel * c) | 683 | Scene::Window::Window(Toplevel * c) | ||
692 | : toplevel(c) | 684 | : toplevel(c) | ||
693 | , filter(ImageFilterFast) | 685 | , filter(ImageFilterFast) | ||
694 | , m_shadow(nullptr) | 686 | , m_shadow(nullptr) | ||
695 | , m_currentPixmap() | 687 | , m_currentPixmap() | ||
696 | , m_previousPixmap() | 688 | , m_previousPixmap() | ||
697 | , m_referencePixmapCounter(0) | 689 | , m_referencePixmapCounter(0) | ||
698 | , disable_painting(0) | 690 | , disable_painting(0) | ||
699 | , shape_valid(false) | | |||
700 | , cached_quad_list(nullptr) | 691 | , cached_quad_list(nullptr) | ||
701 | { | 692 | { | ||
702 | } | 693 | } | ||
703 | 694 | | |||
704 | Scene::Window::~Window() | 695 | Scene::Window::~Window() | ||
705 | { | 696 | { | ||
706 | delete m_shadow; | 697 | delete m_shadow; | ||
707 | } | 698 | } | ||
Show All 27 Lines | 720 | if (!m_currentPixmap.isNull()) { | |||
735 | } | 726 | } | ||
736 | } | 727 | } | ||
737 | } | 728 | } | ||
738 | 729 | | |||
739 | void Scene::Window::discardShape() | 730 | void Scene::Window::discardShape() | ||
740 | { | 731 | { | ||
741 | // it is created on-demand and cached, simply | 732 | // it is created on-demand and cached, simply | ||
742 | // reset the flag | 733 | // reset the flag | ||
743 | shape_valid = false; | 734 | m_bufferShapeIsValid = false; | ||
744 | invalidateQuadsCache(); | 735 | invalidateQuadsCache(); | ||
745 | } | 736 | } | ||
746 | 737 | | |||
747 | // Find out the shape of the window using the XShape extension | 738 | QRegion Scene::Window::bufferShape() const | ||
748 | // or if shape is not set then simply it's the window geometry. | | |||
749 | const QRegion &Scene::Window::shape() const | | |||
750 | { | 739 | { | ||
751 | if (!shape_valid) { | 740 | if (m_bufferShapeIsValid) { | ||
741 | return m_bufferShape; | ||||
742 | } | ||||
743 | | ||||
744 | const QRect bufferGeometry = toplevel->bufferGeometry(); | ||||
745 | | ||||
752 | if (toplevel->shape()) { | 746 | if (toplevel->shape()) { | ||
753 | auto cookie = xcb_shape_get_rectangles_unchecked(connection(), toplevel->frameId(), XCB_SHAPE_SK_BOUNDING); | 747 | auto cookie = xcb_shape_get_rectangles_unchecked(connection(), toplevel->frameId(), XCB_SHAPE_SK_BOUNDING); | ||
754 | ScopedCPointer<xcb_shape_get_rectangles_reply_t> reply(xcb_shape_get_rectangles_reply(connection(), cookie, nullptr)); | 748 | ScopedCPointer<xcb_shape_get_rectangles_reply_t> reply(xcb_shape_get_rectangles_reply(connection(), cookie, nullptr)); | ||
755 | if (!reply.isNull()) { | 749 | if (!reply.isNull()) { | ||
756 | shape_region = QRegion(); | 750 | m_bufferShape = QRegion(); | ||
757 | auto *rects = xcb_shape_get_rectangles_rectangles(reply.data()); | 751 | const xcb_rectangle_t *rects = xcb_shape_get_rectangles_rectangles(reply.data()); | ||
758 | for (int i = 0; | 752 | const int rectCount = xcb_shape_get_rectangles_rectangles_length(reply.data()); | ||
759 | i < xcb_shape_get_rectangles_rectangles_length(reply.data()); | 753 | for (int i = 0; i < rectCount; ++i) { | ||
760 | ++i) | 754 | m_bufferShape += QRegion(rects[i].x, rects[i].y, rects[i].width, rects[i].height); | ||
761 | shape_region += QRegion(rects[ i ].x, rects[ i ].y, | 755 | } | ||
762 | rects[ i ].width, rects[ i ].height); | | |||
763 | // make sure the shape is sane (X is async, maybe even XShape is broken) | 756 | // make sure the shape is sane (X is async, maybe even XShape is broken) | ||
764 | shape_region &= QRegion(0, 0, width(), height()); | 757 | m_bufferShape &= QRegion(0, 0, bufferGeometry.width(), bufferGeometry.height()); | ||
765 | } else | 758 | } else { | ||
766 | shape_region = QRegion(); | 759 | m_bufferShape = QRegion(); | ||
767 | } else | 760 | } | ||
768 | shape_region = QRegion(0, 0, width(), height()); | 761 | } else { | ||
769 | shape_valid = true; | 762 | m_bufferShape = QRegion(0, 0, bufferGeometry.width(), bufferGeometry.height()); | ||
770 | } | 763 | } | ||
771 | return shape_region; | 764 | | ||
765 | m_bufferShapeIsValid = true; | ||||
766 | | ||||
767 | return m_bufferShape; | ||||
772 | } | 768 | } | ||
773 | 769 | | |||
774 | QRegion Scene::Window::clientShape() const | 770 | QRegion Scene::Window::clientShape() const | ||
775 | { | 771 | { | ||
776 | if (AbstractClient *c = dynamic_cast< AbstractClient * > (toplevel)) { | 772 | if (AbstractClient *client = qobject_cast<AbstractClient *>(toplevel)) { | ||
777 | if (c->isShade()) | 773 | if (client->isShade()) { | ||
778 | return QRegion(); | 774 | return QRegion(); | ||
779 | } | 775 | } | ||
776 | } | ||||
777 | | ||||
778 | const QRegion shape = bufferShape(); | ||||
779 | const QMargins bufferMargins = toplevel->bufferMargins(); | ||||
780 | if (bufferMargins.isNull()) { | ||||
781 | return shape; | ||||
782 | } | ||||
783 | | ||||
784 | const QRect clippingRect = QRect(QPoint(0, 0), toplevel->bufferGeometry().size()) - toplevel->bufferMargins(); | ||||
785 | return shape & clippingRect; | ||||
786 | } | ||||
780 | 787 | | |||
781 | // TODO: cache | 788 | QRegion Scene::Window::decorationShape() const | ||
782 | const QRegion r = shape() & QRect(toplevel->clientPos(), toplevel->clientSize()); | 789 | { | ||
783 | return r.isEmpty() ? QRegion() : r; | 790 | return QRegion(toplevel->decorationRect()) - toplevel->transparentRect(); | ||
791 | } | ||||
792 | | ||||
793 | QPoint Scene::Window::bufferOffset() const | ||||
794 | { | ||||
795 | const QRect bufferGeometry = toplevel->bufferGeometry(); | ||||
796 | const QRect frameGeometry = toplevel->frameGeometry(); | ||||
797 | return bufferGeometry.topLeft() - frameGeometry.topLeft(); | ||||
784 | } | 798 | } | ||
785 | 799 | | |||
786 | bool Scene::Window::isVisible() const | 800 | bool Scene::Window::isVisible() const | ||
787 | { | 801 | { | ||
788 | if (toplevel->isDeleted()) | 802 | if (toplevel->isDeleted()) | ||
789 | return false; | 803 | return false; | ||
790 | if (!toplevel->isOnCurrentDesktop()) | 804 | if (!toplevel->isOnCurrentDesktop()) | ||
791 | return false; | 805 | return false; | ||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Line(s) | |||||
839 | { | 853 | { | ||
840 | disable_painting |= reason; | 854 | disable_painting |= reason; | ||
841 | } | 855 | } | ||
842 | 856 | | |||
843 | WindowQuadList Scene::Window::buildQuads(bool force) const | 857 | WindowQuadList Scene::Window::buildQuads(bool force) const | ||
844 | { | 858 | { | ||
845 | if (cached_quad_list != nullptr && !force) | 859 | if (cached_quad_list != nullptr && !force) | ||
846 | return *cached_quad_list; | 860 | return *cached_quad_list; | ||
847 | WindowQuadList ret; | | |||
848 | 861 | | |||
849 | const qreal scale = toplevel->bufferScale(); | 862 | WindowQuadList ret = makeContentsQuads(); | ||
850 | 863 | | |||
851 | if (toplevel->clientPos() == QPoint(0, 0) && toplevel->clientSize() == toplevel->decorationRect().size()) | 864 | if (!toplevel->frameMargins().isNull()) { | ||
852 | ret = makeQuads(WindowQuadContents, shape(), QPoint(0,0), scale); // has no decoration | | |||
853 | else { | | |||
854 | AbstractClient *client = dynamic_cast<AbstractClient*>(toplevel); | 865 | AbstractClient *client = dynamic_cast<AbstractClient*>(toplevel); | ||
855 | QRegion contents = clientShape(); | | |||
856 | QRegion center = toplevel->transparentRect(); | 866 | QRegion center = toplevel->transparentRect(); | ||
857 | QRegion decoration = (client ? QRegion(client->decorationRect()) : shape()) - center; | 867 | const QRegion decoration = decorationShape(); | ||
858 | qreal decorationScale = 1.0; | 868 | qreal decorationScale = 1.0; | ||
859 | ret = makeQuads(WindowQuadContents, contents, toplevel->clientContentPos(), scale); | | |||
860 | 869 | | |||
861 | QRect rects[4]; | 870 | QRect rects[4]; | ||
862 | bool isShadedClient = false; | 871 | bool isShadedClient = false; | ||
863 | 872 | | |||
864 | if (client) { | 873 | if (client) { | ||
865 | client->layoutDecorationRects(rects[0], rects[1], rects[2], rects[3]); | 874 | client->layoutDecorationRects(rects[0], rects[1], rects[2], rects[3]); | ||
866 | decorationScale = client->screenScale(); | 875 | decorationScale = client->screenScale(); | ||
867 | isShadedClient = client->isShade() || center.isEmpty(); | 876 | isShadedClient = client->isShade() || center.isEmpty(); | ||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Line(s) | 915 | for (const QRect &r : intersectedRegion) { | |||
936 | 945 | | |||
937 | list.append(quad); | 946 | list.append(quad); | ||
938 | } | 947 | } | ||
939 | } | 948 | } | ||
940 | 949 | | |||
941 | return list; | 950 | return list; | ||
942 | } | 951 | } | ||
943 | 952 | | |||
944 | void Scene::Window::invalidateQuadsCache() | 953 | WindowQuadList Scene::Window::makeContentsQuads() const | ||
945 | { | 954 | { | ||
946 | cached_quad_list.reset(); | 955 | const QRegion contentsRegion = clientShape(); | ||
956 | if (contentsRegion.isEmpty()) { | ||||
957 | return WindowQuadList(); | ||||
947 | } | 958 | } | ||
948 | 959 | | |||
949 | WindowQuadList Scene::Window::makeQuads(WindowQuadType type, const QRegion& reg, const QPoint &textureOffset, qreal scale) const | 960 | const QPointF geometryOffset = bufferOffset(); | ||
950 | { | 961 | const qreal textureScale = toplevel->bufferScale(); | ||
951 | WindowQuadList ret; | 962 | | ||
952 | ret.reserve(reg.rectCount()); | 963 | WindowQuadList quads; | ||
953 | for (const QRect &r : reg) { | 964 | quads.reserve(contentsRegion.rectCount()); | ||
954 | WindowQuad quad(type); | 965 | | ||
955 | // TODO asi mam spatne pravy dolni roh - bud tady, nebo v jinych castech | 966 | for (const QRectF &rect : contentsRegion) { | ||
956 | quad[ 0 ] = WindowVertex(QPointF(r.x(), r.y()), | 967 | WindowQuad quad(WindowQuadContents); | ||
957 | QPointF(r.x() + textureOffset.x(), r.y() + textureOffset.y()) * scale); | | |||
958 | quad[ 1 ] = WindowVertex(QPointF(r.x() + r.width(), r.y()), | | |||
959 | QPointF(r.x() + r.width() + textureOffset.x(), r.y() + textureOffset.y()) * scale); | | |||
960 | quad[ 2 ] = WindowVertex(QPointF(r.x() + r.width(), r.y() + r.height()), | | |||
961 | QPointF(r.x() + r.width() + textureOffset.x(), r.y() + r.height() + textureOffset.y()) * scale); | | |||
962 | quad[ 3 ] = WindowVertex(QPointF(r.x(), r.y() + r.height()), | | |||
963 | QPointF(r.x() + textureOffset.x(), r.y() + r.height() + textureOffset.y()) * scale); | | |||
964 | 968 | | |||
965 | ret.append(quad); | 969 | const qreal x0 = rect.left() + geometryOffset.x(); | ||
970 | const qreal y0 = rect.top() + geometryOffset.y(); | ||||
971 | const qreal x1 = rect.right() + geometryOffset.x(); | ||||
972 | const qreal y1 = rect.bottom() + geometryOffset.y(); | ||||
973 | | ||||
974 | const qreal u0 = rect.left() * textureScale; | ||||
975 | const qreal v0 = rect.top() * textureScale; | ||||
976 | const qreal u1 = rect.right() * textureScale; | ||||
977 | const qreal v1 = rect.bottom() * textureScale; | ||||
978 | | ||||
979 | quad[0] = WindowVertex(QPointF(x0, y0), QPointF(u0, v0)); | ||||
980 | quad[1] = WindowVertex(QPointF(x1, y0), QPointF(u1, v0)); | ||||
981 | quad[2] = WindowVertex(QPointF(x1, y1), QPointF(u1, v1)); | ||||
982 | quad[3] = WindowVertex(QPointF(x0, y1), QPointF(u0, v1)); | ||||
983 | | ||||
984 | quads << quad; | ||||
966 | } | 985 | } | ||
967 | return ret; | 986 | | ||
987 | return quads; | ||||
988 | } | ||||
989 | | ||||
990 | void Scene::Window::invalidateQuadsCache() | ||||
991 | { | ||||
992 | cached_quad_list.reset(); | ||||
968 | } | 993 | } | ||
969 | 994 | | |||
970 | void Scene::Window::updateShadow(Shadow* shadow) | 995 | void Scene::Window::updateShadow(Shadow* shadow) | ||
971 | { | 996 | { | ||
972 | if (m_shadow == shadow) { | 997 | if (m_shadow == shadow) { | ||
973 | return; | 998 | return; | ||
974 | } | 999 | } | ||
975 | delete m_shadow; | 1000 | delete m_shadow; | ||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Line(s) | 1036 | { | |||
1033 | } | 1058 | } | ||
1034 | // check that the received pixmap is valid and actually matches what we | 1059 | // check that the received pixmap is valid and actually matches what we | ||
1035 | // know about the window (i.e. size) | 1060 | // know about the window (i.e. size) | ||
1036 | if (!windowAttributes || windowAttributes->map_state != XCB_MAP_STATE_VIEWABLE) { | 1061 | if (!windowAttributes || windowAttributes->map_state != XCB_MAP_STATE_VIEWABLE) { | ||
1037 | qCDebug(KWIN_CORE) << "Creating window pixmap failed: " << this; | 1062 | qCDebug(KWIN_CORE) << "Creating window pixmap failed: " << this; | ||
1038 | xcb_free_pixmap(connection(), pix); | 1063 | xcb_free_pixmap(connection(), pix); | ||
1039 | return; | 1064 | return; | ||
1040 | } | 1065 | } | ||
1041 | if (!windowGeometry || | 1066 | const QRect bufferGeometry = toplevel()->bufferGeometry(); | ||
1042 | windowGeometry->width != toplevel()->width() || windowGeometry->height != toplevel()->height()) { | 1067 | if (windowGeometry.size() != bufferGeometry.size()) { | ||
1043 | qCDebug(KWIN_CORE) << "Creating window pixmap failed: " << this; | 1068 | qCDebug(KWIN_CORE) << "Creating window pixmap failed: " << this; | ||
1044 | xcb_free_pixmap(connection(), pix); | 1069 | xcb_free_pixmap(connection(), pix); | ||
1045 | return; | 1070 | return; | ||
1046 | } | 1071 | } | ||
1047 | m_pixmap = pix; | 1072 | m_pixmap = pix; | ||
1048 | m_pixmapSize = QSize(toplevel()->width(), toplevel()->height()); | 1073 | m_pixmapSize = bufferGeometry.size(); | ||
1049 | m_contentsRect = QRect(toplevel()->clientPos(), toplevel()->clientSize()); | 1074 | m_contentsRect = QRect(toplevel()->clientPos(), toplevel()->clientSize()); | ||
1050 | m_window->unreferencePreviousPixmap(); | 1075 | m_window->unreferencePreviousPixmap(); | ||
1051 | } | 1076 | } | ||
1052 | 1077 | | |||
1053 | WindowPixmap *WindowPixmap::createChild(const QPointer<KWayland::Server::SubSurfaceInterface> &subSurface) | 1078 | WindowPixmap *WindowPixmap::createChild(const QPointer<KWayland::Server::SubSurfaceInterface> &subSurface) | ||
1054 | { | 1079 | { | ||
1055 | Q_UNUSED(subSurface) | 1080 | Q_UNUSED(subSurface) | ||
1056 | return nullptr; | 1081 | return nullptr; | ||
▲ Show 20 Lines • Show All 100 Lines • Show Last 20 Lines |