From 1cc5bb27701684d196ae5b35208e573fb0a0af2a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 25 Nov 2024 16:49:14 +0100 Subject: Hook sprite functions instead to monitor cursor These are more reliably as they are called once the decision has been made as to how to display the cursor. The other hooks are sensitive to the order of extensions, which means that we can overlook cursor changes done by other extensions (e.g. hiding it). --- unix/xserver/hw/vnc/vncHooks.c | 290 +++++++++++++++++++++++++++-------------- 1 file changed, 194 insertions(+), 96 deletions(-) diff --git a/unix/xserver/hw/vnc/vncHooks.c b/unix/xserver/hw/vnc/vncHooks.c index 8384618a..40645273 100644 --- a/unix/xserver/hw/vnc/vncHooks.c +++ b/unix/xserver/hw/vnc/vncHooks.c @@ -35,6 +35,8 @@ #include "regionstr.h" #include "dixfontstr.h" #include "colormapst.h" +#include "mipointer.h" +#include "mipointrst.h" #include "picturestr.h" #include "randrstr.h" @@ -59,11 +61,11 @@ typedef struct _vncHooksScreenRec { CreateGCProcPtr CreateGC; CopyWindowProcPtr CopyWindow; ClearToBackgroundProcPtr ClearToBackground; - DisplayCursorProcPtr DisplayCursor; #if XORG_AT_LEAST(1, 19, 0) CursorWarpedToProcPtr CursorWarpedTo; #endif ScreenBlockHandlerProcPtr BlockHandler; + CompositeProcPtr Composite; GlyphsProcPtr Glyphs; CompositeRectsProcPtr CompositeRects; @@ -71,9 +73,12 @@ typedef struct _vncHooksScreenRec { TrianglesProcPtr Triangles; TriStripProcPtr TriStrip; TriFanProcPtr TriFan; + RRSetConfigProcPtr rrSetConfig; RRScreenSetSizeProcPtr rrScreenSetSize; RRCrtcSetProcPtr rrCrtcSet; + + miPointerSpriteFuncPtr spriteFuncs; } vncHooksScreenRec, *vncHooksScreenPtr; typedef struct _vncHooksGCRec { @@ -110,8 +115,6 @@ static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion); static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, int h, Bool generateExposures); -static Bool vncHooksDisplayCursor(DeviceIntPtr pDev, - ScreenPtr pScreen, CursorPtr cursor); #if XORG_AT_LEAST(1, 19, 0) static void vncHooksCursorWarpedTo(DeviceIntPtr pDev, ScreenPtr pScreen_, ClientPtr pClient, @@ -154,6 +157,30 @@ static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, Rotation rotation, int numOutputs, RROutputPtr *outputs); +// Sprite functions + +static Bool vncHooksRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, + CursorPtr cursor); +static Bool vncHooksUnrealizeCursor(DeviceIntPtr dev, ScreenPtr screen, + CursorPtr cursor); +static void vncHooksSetCursor(DeviceIntPtr dev, ScreenPtr screen, + CursorPtr cursor, int x, int y); +static void vncHooksMoveCursor(DeviceIntPtr dev, ScreenPtr screen, + int x, int y); +static Bool vncHooksDeviceCursorInitialize(DeviceIntPtr dev, + ScreenPtr screen); +static void vncHooksDeviceCursorCleanup(DeviceIntPtr dev, + ScreenPtr screen); + +static miPointerSpriteFuncRec vncHooksSpriteFuncs = { + vncHooksRealizeCursor, + vncHooksUnrealizeCursor, + vncHooksSetCursor, + vncHooksMoveCursor, + vncHooksDeviceCursorInitialize, + vncHooksDeviceCursorCleanup +}; + // GC "funcs" static void vncHooksValidateGC(GCPtr pGC, unsigned long changes, @@ -244,6 +271,7 @@ int vncHooksInit(int scrIdx) PictureScreenPtr ps; rrScrPrivPtr rp; + miPointerScreenPtr miPointerPriv; pScreen = screenInfo.screens[scrIdx]; @@ -271,11 +299,11 @@ int vncHooksInit(int scrIdx) wrap(vncHooksScreen, pScreen, CreateGC, vncHooksCreateGC); wrap(vncHooksScreen, pScreen, CopyWindow, vncHooksCopyWindow); wrap(vncHooksScreen, pScreen, ClearToBackground, vncHooksClearToBackground); - wrap(vncHooksScreen, pScreen, DisplayCursor, vncHooksDisplayCursor); #if XORG_AT_LEAST(1, 19, 0) wrap(vncHooksScreen, pScreen, CursorWarpedTo, vncHooksCursorWarpedTo); #endif wrap(vncHooksScreen, pScreen, BlockHandler, vncHooksBlockHandler); + ps = GetPictureScreenIfSet(pScreen); if (ps) { wrap(vncHooksScreen, ps, Composite, vncHooksComposite); @@ -286,6 +314,7 @@ int vncHooksInit(int scrIdx) wrap(vncHooksScreen, ps, TriStrip, vncHooksTriStrip); wrap(vncHooksScreen, ps, TriFan, vncHooksTriFan); } + rp = rrGetScrPriv(pScreen); if (rp) { /* Some RandR callbacks are optional */ @@ -297,6 +326,11 @@ int vncHooksInit(int scrIdx) wrap(vncHooksScreen, rp, rrCrtcSet, vncHooksRandRCrtcSet); } + miPointerPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); + if (miPointerPriv) { + wrap(vncHooksScreen, miPointerPriv, spriteFuncs, &vncHooksSpriteFuncs); + } + return TRUE; } @@ -411,14 +445,15 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_) { PictureScreenPtr ps; rrScrPrivPtr rp; + miPointerScreenPtr miPointerPriv; SCREEN_PROLOGUE(pScreen_, CloseScreen); unwrap(vncHooksScreen, pScreen, CreateGC); unwrap(vncHooksScreen, pScreen, CopyWindow); unwrap(vncHooksScreen, pScreen, ClearToBackground); - unwrap(vncHooksScreen, pScreen, DisplayCursor); unwrap(vncHooksScreen, pScreen, BlockHandler); + ps = GetPictureScreenIfSet(pScreen); if (ps) { unwrap(vncHooksScreen, ps, Composite); @@ -429,6 +464,7 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_) unwrap(vncHooksScreen, ps, TriStrip); unwrap(vncHooksScreen, ps, TriFan); } + rp = rrGetScrPriv(pScreen); if (rp) { unwrap(vncHooksScreen, rp, rrSetConfig); @@ -436,6 +472,11 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_) unwrap(vncHooksScreen, rp, rrCrtcSet); } + miPointerPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); + if (miPointerPriv) { + unwrap(vncHooksScreen, miPointerPriv, spriteFuncs); + } + DBGPRINT((stderr,"vncHooksCloseScreen: Unwrapped screen functions\n")); return (*pScreen->CloseScreen)(pScreen); @@ -549,97 +590,6 @@ static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, SCREEN_EPILOGUE(ClearToBackground); } -// DisplayCursor - get the cursor shape - -static Bool vncHooksDisplayCursor(DeviceIntPtr pDev, - ScreenPtr pScreen_, CursorPtr cursor) -{ - Bool ret; - - SCREEN_PROLOGUE(pScreen_, DisplayCursor); - - ret = (*pScreen->DisplayCursor) (pDev, pScreen, cursor); - - if (cursor == NullCursor) { - vncSetCursorSprite(0, 0, 0, 0, NULL); - } else { - int width, height; - int hotX, hotY; - - unsigned char *rgbaData; - - width = cursor->bits->width; - height = cursor->bits->height; - - hotX = cursor->bits->xhot; - hotY = cursor->bits->yhot; - - rgbaData = malloc(width * height * 4); - if (rgbaData == NULL) - goto out; - - if (cursor->bits->argb) { - unsigned char *out; - CARD32 *in; - int i; - - in = cursor->bits->argb; - out = rgbaData; - for (i = 0; i < width*height; i++) { - out[0] = (*in >> 16) & 0xff; - out[1] = (*in >> 8) & 0xff; - out[2] = (*in >> 0) & 0xff; - out[3] = (*in >> 24) & 0xff; - out += 4; - in++; - } - } else { - unsigned char *out; - int xMaskBytesPerRow; - - xMaskBytesPerRow = BitmapBytePad(width); - - out = rgbaData; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - int byte = y * xMaskBytesPerRow + x / 8; -#if (BITMAP_BIT_ORDER == MSBFirst) - int bit = 7 - x % 8; -#else - int bit = x % 8; -#endif - - if (cursor->bits->source[byte] & (1 << bit)) { - out[0] = cursor->foreRed; - out[1] = cursor->foreGreen; - out[2] = cursor->foreBlue; - } else { - out[0] = cursor->backRed; - out[1] = cursor->backGreen; - out[2] = cursor->backBlue; - } - - if (cursor->bits->mask[byte] & (1 << bit)) - out[3] = 0xff; - else - out[3] = 0x00; - - out += 4; - } - } - } - - vncSetCursorSprite(width, height, hotX, hotY, rgbaData); - - free(rgbaData); - } - -out: - SCREEN_EPILOGUE(DisplayCursor); - - return ret; -} - // CursorWarpedTo - notify that the cursor was warped #if XORG_AT_LEAST(1, 19, 0) @@ -1186,6 +1136,154 @@ static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, return TRUE; } +///////////////////////////////////////////////////////////////////////////// +// +// Sprite functions +// + +// Unwrap and rewrap helpers + +#define SPRITE_PROLOGUE(field) \ + miPointerScreenPtr miPointerPriv = \ + dixLookupPrivate(&screen->devPrivates, miPointerScreenKey); \ + vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(screen); \ + unwrap(vncHooksScreen, miPointerPriv, spriteFuncs); \ + DBGPRINT((stderr,"vncHooks" #field " called\n")); + +#define SPRITE_EPILOGUE(field) \ + wrap(vncHooksScreen, miPointerPriv, spriteFuncs, &vncHooksSpriteFuncs); \ + +static Bool vncHooksRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, + CursorPtr cursor) +{ + Bool ret; + SPRITE_PROLOGUE(RealizeCursor); + ret = (*miPointerPriv->spriteFuncs->RealizeCursor)(dev, screen, cursor); + SPRITE_EPILOGUE(); + return ret; +} + +static Bool vncHooksUnrealizeCursor(DeviceIntPtr dev, ScreenPtr screen, + CursorPtr cursor) +{ + Bool ret; + SPRITE_PROLOGUE(UnrealizeCursor); + ret = (*miPointerPriv->spriteFuncs->UnrealizeCursor)(dev, screen, cursor); + SPRITE_EPILOGUE(); + return ret; +} + +static void vncHooksSetCursor(DeviceIntPtr dev, ScreenPtr screen, + CursorPtr cursor, int x, int y) +{ + SPRITE_PROLOGUE(SetCursor); + + (*miPointerPriv->spriteFuncs->SetCursor)(dev, screen, cursor, x, y); + + if (cursor == NullCursor) { + vncSetCursorSprite(0, 0, 0, 0, NULL); + } else { + int width, height; + int hotX, hotY; + + unsigned char *rgbaData; + + width = cursor->bits->width; + height = cursor->bits->height; + + hotX = cursor->bits->xhot; + hotY = cursor->bits->yhot; + + rgbaData = malloc(width * height * 4); + if (rgbaData == NULL) + goto out; + + if (cursor->bits->argb) { + unsigned char *out; + CARD32 *in; + int i; + + in = cursor->bits->argb; + out = rgbaData; + for (i = 0; i < width*height; i++) { + out[0] = (*in >> 16) & 0xff; + out[1] = (*in >> 8) & 0xff; + out[2] = (*in >> 0) & 0xff; + out[3] = (*in >> 24) & 0xff; + out += 4; + in++; + } + } else { + unsigned char *out; + int xMaskBytesPerRow; + + xMaskBytesPerRow = BitmapBytePad(width); + + out = rgbaData; + for (int sy = 0; sy < height; sy++) { + for (int sx = 0; sx < width; sx++) { + int byte = sy * xMaskBytesPerRow + sx / 8; +#if (BITMAP_BIT_ORDER == MSBFirst) + int bit = 7 - sx % 8; +#else + int bit = sx % 8; +#endif + + if (cursor->bits->source[byte] & (1 << bit)) { + out[0] = cursor->foreRed; + out[1] = cursor->foreGreen; + out[2] = cursor->foreBlue; + } else { + out[0] = cursor->backRed; + out[1] = cursor->backGreen; + out[2] = cursor->backBlue; + } + + if (cursor->bits->mask[byte] & (1 << bit)) + out[3] = 0xff; + else + out[3] = 0x00; + + out += 4; + } + } + } + + vncSetCursorSprite(width, height, hotX, hotY, rgbaData); + + free(rgbaData); + } + +out: + SPRITE_EPILOGUE(); +} + +static void vncHooksMoveCursor(DeviceIntPtr dev, ScreenPtr screen, + int x, int y) +{ + SPRITE_PROLOGUE(MoveCursor); + (*miPointerPriv->spriteFuncs->MoveCursor)(dev, screen, x, y); + SPRITE_EPILOGUE(); +} + +static Bool vncHooksDeviceCursorInitialize(DeviceIntPtr dev, + ScreenPtr screen) +{ + Bool ret; + SPRITE_PROLOGUE(DeviceCursorInitialize); + ret = (*miPointerPriv->spriteFuncs->DeviceCursorInitialize)(dev, screen); + SPRITE_EPILOGUE(); + return ret; +} + +static void vncHooksDeviceCursorCleanup(DeviceIntPtr dev, + ScreenPtr screen) +{ + SPRITE_PROLOGUE(DeviceCursorCleanup); + (*miPointerPriv->spriteFuncs->DeviceCursorCleanup)(dev, screen); + SPRITE_EPILOGUE(); +} + ///////////////////////////////////////////////////////////////////////////// // // GC "funcs" -- cgit v1.2.3