From 3ec331e83c17fb0794bbaab9eeebb078be795ff5 Mon Sep 17 00:00:00 2001 From: Jeremy Huddleston Sequoia Date: Sat, 21 Mar 2026 18:02:54 -0700 Subject: [PATCH] rootless: Add Trapezoids, Triangles, and CompositeRects wrapping The Render extension's Trapezoids and Triangles operations (fbTrapezoids, fbTriangles) render directly via pixman through fbShapes without going through ps->Composite, so RootlessComposite never fires for these operations. This means RootlessStartDrawing is not called and the macOS compositor is not notified of changed pixels. Add RootlessTrapezoids and RootlessTriangles wrappers following the same pattern as RootlessComposite: call RootlessStartDrawing before the operation, then compute the bounding box via miTrapezoidBounds or miTriangleBounds and call RootlessDamageBox after. The default miTriStrip and miTriFan implementations decompose their input into triangles and dispatch through ps->Triangles, so the RootlessTriangles wrapper covers TriStrip and TriFan as well. Also add a RootlessCompositeRects wrapper as defense-in-depth. The current miCompositeRects implementation already has partial rootless coverage: PictOpSrc/PictOpClear go through the GC layer, and other ops route through CompositePicture -> RootlessComposite. Wrapping at the PictureScreen level ensures robustness regardless of the underlying implementation. Fixes [1/2]: https://github.com/XQuartz/XQuartz/issues/31 Signed-off-by: Jeremy Huddleston Sequoia --- miext/rootless/rootlessCommon.h | 3 + miext/rootless/rootlessScreen.c | 139 +++++++++++++++++++++++++++++++- 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/miext/rootless/rootlessCommon.h b/miext/rootless/rootlessCommon.h index 9fdb98e40..852b65248 100644 --- a/miext/rootless/rootlessCommon.h +++ b/miext/rootless/rootlessCommon.h @@ -103,6 +103,9 @@ typedef struct _RootlessScreenRec { CompositeProcPtr Composite; GlyphsProcPtr Glyphs; + TrapezoidsProcPtr Trapezoids; + TrianglesProcPtr Triangles; + CompositeRectsProcPtr CompositeRects; InstallColormapProcPtr InstallColormap; UninstallColormapProcPtr UninstallColormap; diff --git a/miext/rootless/rootlessScreen.c b/miext/rootless/rootlessScreen.c index 60f88b5d4..1026732c9 100644 --- a/miext/rootless/rootlessScreen.c +++ b/miext/rootless/rootlessScreen.c @@ -38,7 +38,9 @@ #include "dix/colormap_priv.h" #include "dix/screen_hooks_priv.h" +#include "include/colormapst.h" #include "mi/mi_priv.h" +#include "render/mipict.h" #include "scrnintstr.h" #include "gcstruct.h" @@ -330,6 +332,135 @@ RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, } } +static void +RootlessTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + WindowPtr srcWin, dstWin; + + srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr) pSrc->pDrawable : NULL; + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr) pDst->pDrawable : NULL; + + ps->Trapezoids = SCREENREC(pScreen)->Trapezoids; + + if (srcWin && IsFramedWindow(srcWin)) + RootlessStartDrawing(srcWin); + if (dstWin && IsFramedWindow(dstWin)) + RootlessStartDrawing(dstWin); + + ps->Trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, traps); + + if (dstWin && IsFramedWindow(dstWin) && ntrap > 0) { + BoxRec box; + + miTrapezoidBounds(ntrap, traps, &box); + + if (box.x1 < box.x2 && box.y1 < box.y2) { + box.x1 += dstWin->drawable.x; + box.y1 += dstWin->drawable.y; + box.x2 += dstWin->drawable.x; + box.y2 += dstWin->drawable.y; + RootlessDamageBox(dstWin, &box); + } + } + + ps->Trapezoids = RootlessTrapezoids; +} + +static void +RootlessTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + WindowPtr srcWin, dstWin; + + srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr) pSrc->pDrawable : NULL; + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr) pDst->pDrawable : NULL; + + ps->Triangles = SCREENREC(pScreen)->Triangles; + + if (srcWin && IsFramedWindow(srcWin)) + RootlessStartDrawing(srcWin); + if (dstWin && IsFramedWindow(dstWin)) + RootlessStartDrawing(dstWin); + + ps->Triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); + + if (dstWin && IsFramedWindow(dstWin) && ntri > 0) { + BoxRec box; + + miTriangleBounds(ntri, tris, &box); + + if (box.x1 < box.x2 && box.y1 < box.y2) { + box.x1 += dstWin->drawable.x; + box.y1 += dstWin->drawable.y; + box.x2 += dstWin->drawable.x; + box.y2 += dstWin->drawable.y; + RootlessDamageBox(dstWin, &box); + } + } + + ps->Triangles = RootlessTriangles; +} + +static void +RootlessCompositeRects(CARD8 op, PicturePtr pDst, xRenderColor *color, + int nRect, xRectangle *rects) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + WindowPtr dstWin; + + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr) pDst->pDrawable : NULL; + + ps->CompositeRects = SCREENREC(pScreen)->CompositeRects; + + if (dstWin && IsFramedWindow(dstWin)) + RootlessStartDrawing(dstWin); + + ps->CompositeRects(op, pDst, color, nRect, rects); + + if (dstWin && IsFramedWindow(dstWin) && nRect > 0) { + int i; + BoxRec box; + + box.x1 = rects[0].x; + box.y1 = rects[0].y; + box.x2 = rects[0].x + rects[0].width; + box.y2 = rects[0].y + rects[0].height; + + for (i = 1; i < nRect; i++) { + short x1 = rects[i].x; + short y1 = rects[i].y; + short x2 = x1 + rects[i].width; + short y2 = y1 + rects[i].height; + + if (x1 < box.x1) box.x1 = x1; + if (y1 < box.y1) box.y1 = y1; + if (x2 > box.x2) box.x2 = x2; + if (y2 > box.y2) box.y2 = y2; + } + + if (box.x1 < box.x2 && box.y1 < box.y2) { + RootlessDamageRect(dstWin, + box.x1, box.y1, + box.x2 - box.x1, box.y2 - box.y1); + } + } + + ps->CompositeRects = RootlessCompositeRects; +} + /* * RootlessValidateTree * ValidateTree is modified in two ways: @@ -660,13 +791,19 @@ RootlessWrap(ScreenPtr pScreen) WRAP(SetShape); { - // Composite and Glyphs don't use normal screen wrapping + // PictureScreen procs don't use normal screen wrapping PictureScreenPtr ps = GetPictureScreen(pScreen); s->Composite = ps->Composite; ps->Composite = RootlessComposite; s->Glyphs = ps->Glyphs; ps->Glyphs = RootlessGlyphs; + s->Trapezoids = ps->Trapezoids; + ps->Trapezoids = RootlessTrapezoids; + s->Triangles = ps->Triangles; + ps->Triangles = RootlessTriangles; + s->CompositeRects = ps->CompositeRects; + ps->CompositeRects = RootlessCompositeRects; } // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?