Changeset View
Changeset View
Standalone View
Standalone View
plugins/scenes/qpainter/scene_qpainter.cpp
Show All 32 Lines | |||||
33 | #include <KWayland/Server/subcompositor_interface.h> | 33 | #include <KWayland/Server/subcompositor_interface.h> | ||
34 | #include <KWayland/Server/surface_interface.h> | 34 | #include <KWayland/Server/surface_interface.h> | ||
35 | #include "decorations/decoratedclient.h" | 35 | #include "decorations/decoratedclient.h" | ||
36 | // Qt | 36 | // Qt | ||
37 | #include <QDebug> | 37 | #include <QDebug> | ||
38 | #include <QPainter> | 38 | #include <QPainter> | ||
39 | #include <KDecoration2/Decoration> | 39 | #include <KDecoration2/Decoration> | ||
40 | 40 | | |||
41 | #include <cmath> | ||||
42 | | ||||
41 | namespace KWin | 43 | namespace KWin | ||
42 | { | 44 | { | ||
43 | 45 | | |||
44 | //**************************************** | 46 | //**************************************** | ||
45 | // SceneQPainter | 47 | // SceneQPainter | ||
46 | //**************************************** | 48 | //**************************************** | ||
47 | SceneQPainter *SceneQPainter::createScene(QObject *parent) | 49 | SceneQPainter *SceneQPainter::createScene(QObject *parent) | ||
48 | { | 50 | { | ||
▲ Show 20 Lines • Show All 255 Lines • ▼ Show 20 Line(s) | |||||
304 | } | 306 | } | ||
305 | 307 | | |||
306 | void SceneQPainter::Window::renderShadow(QPainter* painter) | 308 | void SceneQPainter::Window::renderShadow(QPainter* painter) | ||
307 | { | 309 | { | ||
308 | if (!toplevel->shadow()) { | 310 | if (!toplevel->shadow()) { | ||
309 | return; | 311 | return; | ||
310 | } | 312 | } | ||
311 | SceneQPainterShadow *shadow = static_cast<SceneQPainterShadow *>(toplevel->shadow()); | 313 | SceneQPainterShadow *shadow = static_cast<SceneQPainterShadow *>(toplevel->shadow()); | ||
312 | const QPixmap &topLeft = shadow->shadowPixmap(SceneQPainterShadow::ShadowElementTopLeft); | 314 | | ||
313 | const QPixmap &top = shadow->shadowPixmap(SceneQPainterShadow::ShadowElementTop); | 315 | const QImage &shadowTexture = shadow->shadowTexture(); | ||
314 | const QPixmap &topRight = shadow->shadowPixmap(SceneQPainterShadow::ShadowElementTopRight); | 316 | const WindowQuadList &shadowQuads = shadow->shadowQuads(); | ||
315 | const QPixmap &bottomLeft = shadow->shadowPixmap(SceneQPainterShadow::ShadowElementBottomLeft); | 317 | | ||
316 | const QPixmap &bottom = shadow->shadowPixmap(SceneQPainterShadow::ShadowElementBottom); | 318 | for (const auto &q : shadowQuads) { | ||
317 | const QPixmap &bottomRight = shadow->shadowPixmap(SceneQPainterShadow::ShadowElementBottomRight); | 319 | auto topLeft = q[0]; | ||
318 | const QPixmap &left = shadow->shadowPixmap(SceneQPainterShadow::ShadowElementLeft); | 320 | auto bottomRight = q[2]; | ||
319 | const QPixmap &right = shadow->shadowPixmap(SceneQPainterShadow::ShadowElementRight); | 321 | QRectF target(topLeft.x(), topLeft.y(), | ||
320 | 322 | bottomRight.x() - topLeft.x(), | |||
321 | const int leftOffset = shadow->leftOffset(); | 323 | bottomRight.y() - topLeft.y()); | ||
322 | const int topOffset = shadow->topOffset(); | 324 | QRectF source(topLeft.textureX(), topLeft.textureY(), | ||
323 | const int rightOffset = shadow->rightOffset(); | 325 | bottomRight.textureX() - topLeft.textureX(), | ||
324 | const int bottomOffset = shadow->bottomOffset(); | 326 | bottomRight.textureY() - topLeft.textureY()); | ||
325 | 327 | painter->drawImage(target, shadowTexture, source); | |||
326 | // top left | 328 | } | ||
327 | painter->drawPixmap(-leftOffset, -topOffset, topLeft); | | |||
328 | // top right | | |||
329 | painter->drawPixmap(toplevel->width() - topRight.width() + rightOffset, -topOffset, topRight); | | |||
330 | // bottom left | | |||
331 | painter->drawPixmap(-leftOffset, toplevel->height() - bottomLeft.height() + bottomOffset, bottomLeft); | | |||
332 | // bottom right | | |||
333 | painter->drawPixmap(toplevel->width() - bottomRight.width() + rightOffset, | | |||
334 | toplevel->height() - bottomRight.height() + bottomOffset, | | |||
335 | bottomRight); | | |||
336 | // top | | |||
337 | painter->drawPixmap(topLeft.width() - leftOffset, -topOffset, | | |||
338 | toplevel->width() - topLeft.width() - topRight.width() + leftOffset + rightOffset, | | |||
339 | top.height(), | | |||
340 | top); | | |||
341 | // left | | |||
342 | painter->drawPixmap(-leftOffset, topLeft.height() - topOffset, left.width(), | | |||
343 | toplevel->height() - topLeft.height() - bottomLeft.height() + topOffset + bottomOffset, | | |||
344 | left); | | |||
345 | // right | | |||
346 | painter->drawPixmap(toplevel->width() - right.width() + rightOffset, | | |||
347 | topRight.height() - topOffset, | | |||
348 | right.width(), | | |||
349 | toplevel->height() - topRight.height() - bottomRight.height() + topOffset + bottomOffset, | | |||
350 | right); | | |||
351 | // bottom | | |||
352 | painter->drawPixmap(bottomLeft.width() - leftOffset, | | |||
353 | toplevel->height() - bottom.height() + bottomOffset, | | |||
354 | toplevel->width() - bottomLeft.width() - bottomRight.width() + leftOffset + rightOffset, | | |||
355 | bottom.height(), | | |||
356 | bottom); | | |||
357 | } | 329 | } | ||
358 | 330 | | |||
359 | void SceneQPainter::Window::renderWindowDecorations(QPainter *painter) | 331 | void SceneQPainter::Window::renderWindowDecorations(QPainter *painter) | ||
360 | { | 332 | { | ||
361 | // TODO: custom decoration opacity | 333 | // TODO: custom decoration opacity | ||
362 | AbstractClient *client = dynamic_cast<AbstractClient*>(toplevel); | 334 | AbstractClient *client = dynamic_cast<AbstractClient*>(toplevel); | ||
363 | Deleted *deleted = dynamic_cast<Deleted*>(toplevel); | 335 | Deleted *deleted = dynamic_cast<Deleted*>(toplevel); | ||
364 | if (!client && !deleted) { | 336 | if (!client && !deleted) { | ||
▲ Show 20 Lines • Show All 187 Lines • ▼ Show 20 Line(s) | 523 | SceneQPainterShadow::SceneQPainterShadow(Toplevel* toplevel) | |||
552 | : Shadow(toplevel) | 524 | : Shadow(toplevel) | ||
553 | { | 525 | { | ||
554 | } | 526 | } | ||
555 | 527 | | |||
556 | SceneQPainterShadow::~SceneQPainterShadow() | 528 | SceneQPainterShadow::~SceneQPainterShadow() | ||
557 | { | 529 | { | ||
558 | } | 530 | } | ||
559 | 531 | | |||
532 | void SceneQPainterShadow::buildQuads() | ||||
533 | { | ||||
534 | // Do not draw shadows if window width or window height is less than | ||||
535 | // 5 px. 5 is an arbitrary choice. | ||||
536 | if (topLevel()->width() < 5 || topLevel()->height() < 5) { | ||||
537 | m_shadowQuads.clear(); | ||||
538 | setShadowRegion(QRegion()); | ||||
539 | return; | ||||
540 | } | ||||
541 | | ||||
542 | const QSizeF top(elementSize(ShadowElementTop)); | ||||
543 | const QSizeF topRight(elementSize(ShadowElementTopRight)); | ||||
544 | const QSizeF right(elementSize(ShadowElementRight)); | ||||
545 | const QSizeF bottomRight(elementSize(ShadowElementBottomRight)); | ||||
546 | const QSizeF bottom(elementSize(ShadowElementBottom)); | ||||
547 | const QSizeF bottomLeft(elementSize(ShadowElementBottomLeft)); | ||||
548 | const QSizeF left(elementSize(ShadowElementLeft)); | ||||
549 | const QSizeF topLeft(elementSize(ShadowElementTopLeft)); | ||||
550 | | ||||
551 | const QRectF outerRect(QPointF(-leftOffset(), -topOffset()), | ||||
552 | QPointF(topLevel()->width() + rightOffset(), | ||||
553 | topLevel()->height() + bottomOffset())); | ||||
554 | | ||||
555 | const int width = std::max({topLeft.width(), left.width(), bottomLeft.width()}) | ||||
556 | + std::max(top.width(), bottom.width()) | ||||
557 | + std::max({topRight.width(), right.width(), bottomRight.width()}); | ||||
558 | const int height = std::max({topLeft.height(), top.height(), topRight.height()}) | ||||
559 | + std::max(left.height(), right.height()) | ||||
560 | + std::max({bottomLeft.height(), bottom.height(), bottomRight.height()}); | ||||
561 | | ||||
562 | QRectF topLeftRect(outerRect.topLeft(), topLeft); | ||||
563 | QRectF topRightRect(outerRect.topRight() - QPointF(topRight.width(), 0), topRight); | ||||
564 | QRectF bottomRightRect( | ||||
565 | outerRect.bottomRight() - QPointF(bottomRight.width(), bottomRight.height()), | ||||
566 | bottomRight); | ||||
567 | QRectF bottomLeftRect(outerRect.bottomLeft() - QPointF(0, bottomLeft.height()), bottomLeft); | ||||
568 | | ||||
569 | // Re-distribute the corner tiles so no one of them is overlapping with others. | ||||
570 | // By doing this, we assume that shadow's corner tiles are symmetric | ||||
571 | // and it is OK to not draw top/right/bottom/left tile between corners. | ||||
572 | // For example, let's say top-left and top-right tiles are overlapping. | ||||
573 | // In that case, the right side of the top-left tile will be shifted to left, | ||||
574 | // the left side of the top-right tile will shifted to right, and the top | ||||
575 | // tile won't be rendered. | ||||
576 | bool drawTop = true; | ||||
577 | if (topLeftRect.right() >= topRightRect.left()) { | ||||
578 | const float halfOverlap = qAbs(topLeftRect.right() - topRightRect.left()) / 2; | ||||
579 | topLeftRect.setRight(topLeftRect.right() - std::floor(halfOverlap)); | ||||
580 | topRightRect.setLeft(topRightRect.left() + std::ceil(halfOverlap)); | ||||
581 | drawTop = false; | ||||
582 | } | ||||
583 | | ||||
584 | bool drawRight = true; | ||||
585 | if (topRightRect.bottom() >= bottomRightRect.top()) { | ||||
586 | const float halfOverlap = qAbs(topRightRect.bottom() - bottomRightRect.top()) / 2; | ||||
587 | topRightRect.setBottom(topRightRect.bottom() - std::floor(halfOverlap)); | ||||
588 | bottomRightRect.setTop(bottomRightRect.top() + std::ceil(halfOverlap)); | ||||
589 | drawRight = false; | ||||
590 | } | ||||
591 | | ||||
592 | bool drawBottom = true; | ||||
593 | if (bottomLeftRect.right() >= bottomRightRect.left()) { | ||||
594 | const float halfOverlap = qAbs(bottomLeftRect.right() - bottomRightRect.left()) / 2; | ||||
595 | bottomLeftRect.setRight(bottomLeftRect.right() - std::floor(halfOverlap)); | ||||
596 | bottomRightRect.setLeft(bottomRightRect.left() + std::ceil(halfOverlap)); | ||||
597 | drawBottom = false; | ||||
598 | } | ||||
599 | | ||||
600 | bool drawLeft = true; | ||||
601 | if (topLeftRect.bottom() >= bottomLeftRect.top()) { | ||||
602 | const float halfOverlap = qAbs(topLeftRect.bottom() - bottomLeftRect.top()) / 2; | ||||
603 | topLeftRect.setBottom(topLeftRect.bottom() - std::floor(halfOverlap)); | ||||
604 | bottomLeftRect.setTop(bottomLeftRect.top() + std::ceil(halfOverlap)); | ||||
605 | drawLeft = false; | ||||
606 | } | ||||
607 | | ||||
608 | qreal tx1 = 0.0, | ||||
609 | tx2 = 0.0, | ||||
610 | ty1 = 0.0, | ||||
611 | ty2 = 0.0; | ||||
612 | | ||||
613 | m_shadowQuads.clear(); | ||||
614 | | ||||
615 | tx1 = 0.0; | ||||
616 | ty1 = 0.0; | ||||
617 | tx2 = topLeftRect.width(); | ||||
618 | ty2 = topLeftRect.height(); | ||||
619 | WindowQuad topLeftQuad(WindowQuadShadow); | ||||
620 | topLeftQuad[0] = WindowVertex(topLeftRect.left(), topLeftRect.top(), tx1, ty1); | ||||
621 | topLeftQuad[1] = WindowVertex(topLeftRect.right(), topLeftRect.top(), tx2, ty1); | ||||
622 | topLeftQuad[2] = WindowVertex(topLeftRect.right(), topLeftRect.bottom(), tx2, ty2); | ||||
623 | topLeftQuad[3] = WindowVertex(topLeftRect.left(), topLeftRect.bottom(), tx1, ty2); | ||||
624 | m_shadowQuads.append(topLeftQuad); | ||||
625 | | ||||
626 | tx1 = width - topRightRect.width(); | ||||
627 | ty1 = 0.0; | ||||
628 | tx2 = width; | ||||
629 | ty2 = topRightRect.height(); | ||||
630 | WindowQuad topRightQuad(WindowQuadShadow); | ||||
631 | topRightQuad[0] = WindowVertex(topRightRect.left(), topRightRect.top(), tx1, ty1); | ||||
632 | topRightQuad[1] = WindowVertex(topRightRect.right(), topRightRect.top(), tx2, ty1); | ||||
633 | topRightQuad[2] = WindowVertex(topRightRect.right(), topRightRect.bottom(), tx2, ty2); | ||||
634 | topRightQuad[3] = WindowVertex(topRightRect.left(), topRightRect.bottom(), tx1, ty2); | ||||
635 | m_shadowQuads.append(topRightQuad); | ||||
636 | | ||||
637 | tx1 = width - bottomRightRect.width(); | ||||
638 | tx2 = width; | ||||
639 | ty1 = height - bottomRightRect.height(); | ||||
640 | ty2 = height; | ||||
641 | WindowQuad bottomRightQuad(WindowQuadShadow); | ||||
642 | bottomRightQuad[0] = WindowVertex(bottomRightRect.left(), bottomRightRect.top(), tx1, ty1); | ||||
643 | bottomRightQuad[1] = WindowVertex(bottomRightRect.right(), bottomRightRect.top(), tx2, ty1); | ||||
644 | bottomRightQuad[2] = WindowVertex(bottomRightRect.right(), bottomRightRect.bottom(), tx2, ty2); | ||||
645 | bottomRightQuad[3] = WindowVertex(bottomRightRect.left(), bottomRightRect.bottom(), tx1, ty2); | ||||
646 | m_shadowQuads.append(bottomRightQuad); | ||||
647 | | ||||
648 | tx1 = 0.0; | ||||
649 | tx2 = bottomLeftRect.width(); | ||||
650 | ty1 = height - bottomLeftRect.height(); | ||||
651 | ty2 = height; | ||||
652 | WindowQuad bottomLeftQuad(WindowQuadShadow); | ||||
653 | bottomLeftQuad[0] = WindowVertex(bottomLeftRect.left(), bottomLeftRect.top(), tx1, ty1); | ||||
654 | bottomLeftQuad[1] = WindowVertex(bottomLeftRect.right(), bottomLeftRect.top(), tx2, ty1); | ||||
655 | bottomLeftQuad[2] = WindowVertex(bottomLeftRect.right(), bottomLeftRect.bottom(), tx2, ty2); | ||||
656 | bottomLeftQuad[3] = WindowVertex(bottomLeftRect.left(), bottomLeftRect.bottom(), tx1, ty2); | ||||
657 | m_shadowQuads.append(bottomLeftQuad); | ||||
658 | | ||||
659 | if (drawTop) { | ||||
660 | QRectF topRect( | ||||
661 | topLeftRect.topRight(), | ||||
662 | topRightRect.bottomLeft()); | ||||
663 | tx1 = topLeft.width(); | ||||
664 | ty1 = 0.0; | ||||
665 | tx2 = width - topRight.width(); | ||||
666 | ty2 = topRect.height(); | ||||
667 | WindowQuad topQuad(WindowQuadShadow); | ||||
668 | topQuad[0] = WindowVertex(topRect.left(), topRect.top(), tx1, ty1); | ||||
669 | topQuad[1] = WindowVertex(topRect.right(), topRect.top(), tx2, ty1); | ||||
670 | topQuad[2] = WindowVertex(topRect.right(), topRect.bottom(), tx2, ty2); | ||||
671 | topQuad[3] = WindowVertex(topRect.left(), topRect.bottom(), tx1, ty2); | ||||
672 | m_shadowQuads.append(topQuad); | ||||
673 | } | ||||
674 | | ||||
675 | if (drawRight) { | ||||
676 | QRectF rightRect( | ||||
677 | topRightRect.bottomLeft(), | ||||
678 | bottomRightRect.topRight()); | ||||
679 | tx1 = width - rightRect.width(); | ||||
680 | ty1 = topRight.height(); | ||||
681 | tx2 = width; | ||||
682 | ty2 = height - bottomRight.height(); | ||||
683 | WindowQuad rightQuad(WindowQuadShadow); | ||||
684 | rightQuad[0] = WindowVertex(rightRect.left(), rightRect.top(), tx1, ty1); | ||||
685 | rightQuad[1] = WindowVertex(rightRect.right(), rightRect.top(), tx2, ty1); | ||||
686 | rightQuad[2] = WindowVertex(rightRect.right(), rightRect.bottom(), tx2, ty2); | ||||
687 | rightQuad[3] = WindowVertex(rightRect.left(), rightRect.bottom(), tx1, ty2); | ||||
688 | m_shadowQuads.append(rightQuad); | ||||
689 | } | ||||
690 | | ||||
691 | if (drawBottom) { | ||||
692 | QRectF bottomRect( | ||||
693 | bottomLeftRect.topRight(), | ||||
694 | bottomRightRect.bottomLeft()); | ||||
695 | tx1 = bottomLeft.width(); | ||||
696 | ty1 = height - bottomRect.height(); | ||||
697 | tx2 = width - bottomRight.width(); | ||||
698 | ty2 = height; | ||||
699 | WindowQuad bottomQuad(WindowQuadShadow); | ||||
700 | bottomQuad[0] = WindowVertex(bottomRect.left(), bottomRect.top(), tx1, ty1); | ||||
701 | bottomQuad[1] = WindowVertex(bottomRect.right(), bottomRect.top(), tx2, ty1); | ||||
702 | bottomQuad[2] = WindowVertex(bottomRect.right(), bottomRect.bottom(), tx2, ty2); | ||||
703 | bottomQuad[3] = WindowVertex(bottomRect.left(), bottomRect.bottom(), tx1, ty2); | ||||
704 | m_shadowQuads.append(bottomQuad); | ||||
705 | } | ||||
706 | | ||||
707 | if (drawLeft) { | ||||
708 | QRectF leftRect( | ||||
709 | topLeftRect.bottomLeft(), | ||||
710 | bottomLeftRect.topRight()); | ||||
711 | tx1 = 0.0; | ||||
712 | ty1 = topLeft.height(); | ||||
713 | tx2 = leftRect.width(); | ||||
714 | ty2 = height - bottomRight.height(); | ||||
715 | WindowQuad leftQuad(WindowQuadShadow); | ||||
716 | leftQuad[0] = WindowVertex(leftRect.left(), leftRect.top(), tx1, ty1); | ||||
717 | leftQuad[1] = WindowVertex(leftRect.right(), leftRect.top(), tx2, ty1); | ||||
718 | leftQuad[2] = WindowVertex(leftRect.right(), leftRect.bottom(), tx2, ty2); | ||||
719 | leftQuad[3] = WindowVertex(leftRect.left(), leftRect.bottom(), tx1, ty2); | ||||
720 | m_shadowQuads.append(leftQuad); | ||||
721 | } | ||||
722 | } | ||||
723 | | ||||
560 | bool SceneQPainterShadow::prepareBackend() | 724 | bool SceneQPainterShadow::prepareBackend() | ||
561 | { | 725 | { | ||
562 | if (hasDecorationShadow()) { | 726 | if (hasDecorationShadow()) { | ||
563 | // TODO: implement for QPainter | 727 | m_texture = decorationShadowImage(); | ||
728 | return true; | ||||
729 | } | ||||
730 | | ||||
731 | const QPixmap &topLeft = shadowPixmap(ShadowElementTopLeft); | ||||
732 | const QPixmap &top = shadowPixmap(ShadowElementTop); | ||||
733 | const QPixmap &topRight = shadowPixmap(ShadowElementTopRight); | ||||
734 | const QPixmap &bottomLeft = shadowPixmap(ShadowElementBottomLeft); | ||||
735 | const QPixmap &bottom = shadowPixmap(ShadowElementBottom); | ||||
736 | const QPixmap &bottomRight = shadowPixmap(ShadowElementBottomRight); | ||||
737 | const QPixmap &left = shadowPixmap(ShadowElementLeft); | ||||
738 | const QPixmap &right = shadowPixmap(ShadowElementRight); | ||||
739 | | ||||
740 | const int width = std::max({topLeft.width(), left.width(), bottomLeft.width()}) | ||||
741 | + std::max(top.width(), bottom.width()) | ||||
742 | + std::max({topRight.width(), right.width(), bottomRight.width()}); | ||||
743 | const int height = std::max({topLeft.height(), top.height(), topRight.height()}) | ||||
744 | + std::max(left.height(), right.height()) | ||||
745 | + std::max({bottomLeft.height(), bottom.height(), bottomRight.height()}); | ||||
746 | | ||||
747 | if (width == 0 || height == 0) { | ||||
564 | return false; | 748 | return false; | ||
565 | } | 749 | } | ||
750 | | ||||
751 | QImage image(width, height, QImage::Format_ARGB32_Premultiplied); | ||||
752 | image.fill(Qt::transparent); | ||||
753 | | ||||
754 | QPainter painter; | ||||
755 | painter.begin(&image); | ||||
756 | painter.drawPixmap(0, 0, topLeft); | ||||
757 | painter.drawPixmap(topLeft.width(), 0, top); | ||||
758 | painter.drawPixmap(width - topRight.width(), 0, topRight); | ||||
759 | painter.drawPixmap(0, height - bottomLeft.height(), bottomLeft); | ||||
760 | painter.drawPixmap(bottomLeft.width(), height - bottom.height(), bottom); | ||||
761 | painter.drawPixmap(width - bottomRight.width(), height - bottomRight.height(), bottomRight); | ||||
762 | painter.drawPixmap(0, topLeft.height(), left); | ||||
763 | painter.drawPixmap(width - right.width(), topRight.height(), right); | ||||
764 | painter.end(); | ||||
765 | | ||||
766 | m_texture = image; | ||||
767 | | ||||
566 | return true; | 768 | return true; | ||
567 | } | 769 | } | ||
568 | 770 | | |||
569 | //**************************************** | 771 | //**************************************** | ||
570 | // QPainterDecorationRenderer | 772 | // QPainterDecorationRenderer | ||
571 | //**************************************** | 773 | //**************************************** | ||
572 | SceneQPainterDecorationRenderer::SceneQPainterDecorationRenderer(Decoration::DecoratedClientImpl *client) | 774 | SceneQPainterDecorationRenderer::SceneQPainterDecorationRenderer(Decoration::DecoratedClientImpl *client) | ||
573 | : Renderer(client) | 775 | : Renderer(client) | ||
▲ Show 20 Lines • Show All 101 Lines • Show Last 20 Lines |