2025-08-08 20:00:36 +02:00

1483 lines
39 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
/* */
/* NXAGENT, NX protocol compression and NX extensions to this software */
/* are copyright of the aforementioned persons and companies. */
/* */
/* Redistribution and use of the present software is allowed according */
/* to terms specified in the file LICENSE which comes in the source */
/* distribution. */
/* */
/* All rights reserved. */
/* */
/* NOTE: This software has received contributions from various other */
/* contributors, only the core maintainers and supporters are listed as */
/* copyright holders. Please contact us, if you feel you should be listed */
/* as copyright holder, as well. */
/* */
/**************************************************************************/
#include "scrnintstr.h"
#include "miscstruct.h"
#include "pixmapstr.h"
#include "dixstruct.h"
#include "regionstr.h"
#include "../../include/gc.h"
#include "servermd.h"
#include "mi.h"
#include "../../fb/fb.h"
#include "Agent.h"
#include "Display.h"
#include "Screen.h"
#include "Pixmaps.h"
#include "Trap.h"
#include "GCs.h"
#include "GCOps.h"
#include "Image.h"
#include "Split.h"
#include "Drawable.h"
#include "Visual.h"
#include "Client.h"
#include "Events.h"
#include "Args.h"
#include "Utils.h"
#include "compext/Compext.h"
#include <nx/NXpack.h>
RESTYPE RT_NX_PIXMAP;
/*
* Set here the required log level.
*/
#define PANIC
#define WARNING
#undef TEST
#undef DEBUG
#undef DUMP
#ifdef TEST
#include "Font.h"
#endif
int nxagentPixmapPrivateIndex;
/*
* Force deallocation of the virtual pixmap.
*/
static Bool nxagentDestroyVirtualPixmap(PixmapPtr pPixmap);
/*
* This serves as a tool to check the synchronization
* between pixmaps in framebuffer and the correspondent
* pixmaps in the real X server.
*/
#ifdef TEST
Bool nxagentCheckPixmapIntegrity(PixmapPtr pPixmap);
#endif
struct nxagentPixmapPair
{
Pixmap pixmap;
PixmapPtr pMap;
};
PixmapPtr nxagentCreatePixmap(ScreenPtr pScreen, int width, int height,
int depth, unsigned usage_hint)
{
#ifdef DEBUG
fprintf(stderr, "nxagentCreatePixmap: Creating pixmap with width [%d] "
"height [%d] depth [%d] and allocation hint [%d].\n",
width, height, depth, usage_hint);
#endif
/*
* Create the pixmap structure but do not allocate memory for the
* data.
*/
PixmapPtr pPixmap = AllocatePixmap(pScreen, 0);
if (!pPixmap)
{
#ifdef WARNING
fprintf(stderr, "nxagentCreatePixmap: WARNING! Failed to create pixmap with "
"width [%d] height [%d] depth [%d] and allocation hint [%d].\n",
width, height, depth, usage_hint);
#endif
return NullPixmap;
}
/*
* Initialize the core members.
*/
pPixmap -> drawable.type = DRAWABLE_PIXMAP;
pPixmap -> drawable.class = 0;
pPixmap -> drawable.pScreen = pScreen;
pPixmap -> drawable.depth = depth;
pPixmap -> drawable.bitsPerPixel = BitsPerPixel(depth);
pPixmap -> drawable.id = 0;
pPixmap -> drawable.serialNumber = NEXT_SERIAL_NUMBER;
pPixmap -> drawable.x = 0;
pPixmap -> drawable.y = 0;
pPixmap -> drawable.width = width;
pPixmap -> drawable.height = height;
pPixmap -> devKind = 0;
pPixmap -> refcnt = 1;
pPixmap -> devPrivate.ptr = NULL;
pPixmap -> usage_hint = usage_hint;
/*
* Initialize the privates of the real picture.
*/
nxagentPrivPixmapPtr pPixmapPriv = nxagentPixmapPriv(pPixmap);
pPixmapPriv -> isVirtual = False;
pPixmapPriv -> isShared = nxagentShmPixmapTrap;
/*
* The shared memory pixmaps are never
* synchronized with the remote X Server.
*/
if (pPixmapPriv -> isShared)
{
BoxRec box = { .x1 = 0, .y1 = 0, .x2 = width, .y2 = height };
pPixmapPriv -> corruptedRegion = RegionCreate(&box, 1);
}
else
{
pPixmapPriv -> corruptedRegion = RegionCreate((BoxRec *) NULL, 1);
}
pPixmapPriv -> corruptedBackground = 0;
pPixmapPriv -> containGlyphs = 0;
pPixmapPriv -> containTrapezoids = 0;
/*
* The lazy encoding policy generally does not send on remote X
* server the off-screen images, by preferring to synchronize the
* windows content. Anyway this behaviour may be inadvisable if a
* pixmap is used, for example, for multiple copy areas on screen.
* This counter serves the purpose, taking into account the number
* of times the pixmap has been used as source for a deferred
* operation.
*/
pPixmapPriv -> usageCounter = 0;
pPixmapPriv -> corruptedBackgroundId = 0;
pPixmapPriv -> corruptedId = 0;
pPixmapPriv -> synchronizationBitmap = NullPixmap;
pPixmapPriv -> corruptedTimestamp = 0;
pPixmapPriv -> splitResource = NULL;
pPixmapPriv -> isBackingPixmap = 0;
/*
* Create the pixmap based on the default windows. The proxy knows
* this and uses this information to optimize encode the create
* pixmap message by including the id of the drawable in the
* checksum.
*/
if (width != 0 && height != 0 && !nxagentGCTrap)
{
pPixmapPriv -> id = XCreatePixmap(nxagentDisplay,
nxagentDefaultWindows[pScreen -> myNum],
width, height, depth);
}
else
{
pPixmapPriv -> id = 0;
#ifdef TEST
fprintf(stderr, "nxagentCreatePixmap: Skipping the creation of pixmap at [%p] on real "
"X server with nxagentGCTrap [%d].\n", (void *) pPixmap, nxagentGCTrap);
#endif
}
pPixmapPriv -> mid = FakeClientID(serverClient -> index);
AddResource(pPixmapPriv -> mid, RT_NX_PIXMAP, pPixmap);
pPixmapPriv -> pRealPixmap = pPixmap;
pPixmapPriv -> pVirtualPixmap = NULL;
pPixmapPriv -> pPicture = NULL;
/*
* Create the pixmap in the virtual framebuffer.
*/
PixmapPtr pVirtual = fbCreatePixmap(pScreen, width, height, depth, usage_hint);
if (pVirtual == NULL)
{
#ifdef PANIC
fprintf(stderr, "nxagentCreatePixmap: PANIC! Failed to create virtual pixmap with "
"width [%d] height [%d] depth [%d] and allocation hint [%d].\n",
width, height, depth, usage_hint);
#endif
nxagentDestroyPixmap(pPixmap);
return NullPixmap;
}
#ifdef TEST
fprintf(stderr, "nxagentCreatePixmap: Allocated memory for the Virtual %sPixmap %p of real Pixmap %p (%dx%d),",
"allocation hint [%d].\n",
nxagentShmPixmapTrap ? "Shm " : "", (void *) pVirtual, (void *) pPixmap, width, height, usage_hint);
#endif
pPixmapPriv -> pVirtualPixmap = pVirtual;
/*
* Initialize the privates of the virtual picture. We could avoid to
* use a flag and just check the pointer to the virtual pixmap that,
* if the pixmap is actually virtual, will be NULL. Unfortunately
* the flag can be changed in nxagentValidateGC(). That code should
* be removed in future.
*/
nxagentPrivPixmapPtr pVirtualPriv = nxagentPixmapPriv(pVirtual);
pVirtualPriv -> isVirtual = True;
pVirtualPriv -> isShared = nxagentShmPixmapTrap;
pVirtualPriv -> corruptedRegion = RegionCreate((BoxRec *) NULL, 1);
pVirtualPriv -> corruptedBackground = 0;
pVirtualPriv -> containGlyphs = 0;
pVirtualPriv -> containTrapezoids = 0;
pVirtualPriv -> usageCounter = 0;
pVirtualPriv -> corruptedBackgroundId = 0;
pVirtualPriv -> corruptedId = 0;
pVirtualPriv -> synchronizationBitmap = NullPixmap;
pVirtualPriv -> corruptedTimestamp = 0;
pVirtualPriv -> splitResource = NULL;
/*
* We might distinguish real and virtual pixmaps by checking the
* pointers to pVirtualPixmap. We should also remove the copy of id
* and use the one of the real pixmap.
*/
pVirtualPriv -> id = pPixmapPriv -> id;
pVirtualPriv -> mid = 0;
/*
* Storing a pointer back to the real pixmap is silly. Unfortunately
* this is the way it has been originally implemented. See also the
* comment in destroy of the pixmap.
*/
pVirtualPriv -> pRealPixmap = pPixmap;
pVirtualPriv -> pVirtualPixmap = NULL;
pVirtualPriv -> pPicture = NULL;
#ifdef TEST
fprintf(stderr, "nxagentCreatePixmap: Created pixmap at [%p] virtual at [%p] with width [%d] "
"height [%d] depth [%d] and allocation hint [%d].\n",
(void *) pPixmap, (void *) pVirtual, width, height, depth, usage_hint);
#endif
return pPixmap;
}
Bool nxagentDestroyPixmap(PixmapPtr pPixmap)
{
if (!pPixmap)
{
#ifdef PANIC
fprintf(stderr, "nxagentDestroyPixmap: PANIC! Invalid attempt to destroy "
"a null pixmap pointer.\n");
#endif
return False;
}
nxagentPrivPixmapPtr pPixmapPriv = nxagentPixmapPriv(pPixmap);
PixmapPtr pVirtual = pPixmapPriv -> pVirtualPixmap;
#ifdef TEST
fprintf(stderr, "nxagentDestroyPixmap: Destroying pixmap at [%p] with virtual at [%p].\n",
(void *) pPixmap, (void *) pVirtual);
#endif
if (pPixmapPriv -> isVirtual)
{
/*
* For some pixmaps we receive the destroy only for the
* virtual. Infact to draw in the framebuffer we can use the
* virtual pixmap instead of the pointer to the real one. As the
* virtual pixmap can collect references, we must transfer those
* references to the real pixmap so we can continue as the destroy
* had been requested for it.
*/
pVirtual = pPixmap;
pPixmap = pPixmapPriv -> pRealPixmap;
pPixmapPriv = nxagentPixmapPriv(pPixmap);
/*
* Move the references accumulated by the virtual pixmap into the
* references of the real one.
*/
int refcnt = pVirtual -> refcnt - 1;
#ifdef TEST
fprintf(stderr, "nxagentDestroyPixmap: Adding [%d] references to pixmap at [%p].\n",
refcnt, (void *) pPixmap);
#endif
pPixmap -> refcnt += refcnt;
pVirtual -> refcnt -= refcnt;
}
--pPixmap -> refcnt;
#ifdef TEST
fprintf(stderr, "nxagentDestroyPixmap: Pixmap has now [%d] references with virtual pixmap [%d].\n",
pPixmap -> refcnt, pVirtual -> refcnt);
if (pVirtual != NULL && pVirtual -> refcnt != 1)
{
fprintf(stderr, "nxagentDestroyPixmap: PANIC! Virtual pixmap has [%d] references.\n",
pVirtual -> refcnt);
}
#endif
if (pPixmap -> refcnt > 0)
{
return True;
}
#ifdef TEST
fprintf(stderr, "nxagentDestroyPixmap: Managing to destroy the pixmap at [%p]\n",
(void *) pPixmap);
#endif
nxagentRemoveItemBSPixmapList(nxagentPixmap(pPixmap));
nxagentDestroyVirtualPixmap(pPixmap);
if (pPixmapPriv -> corruptedRegion != NullRegion)
{
RegionDestroy(pPixmapPriv -> corruptedRegion);
pPixmapPriv -> corruptedRegion = NullRegion;
}
if (nxagentSynchronization.pDrawable == (DrawablePtr) pPixmap)
{
nxagentSynchronization.pDrawable = NULL;
#ifdef TEST
fprintf(stderr, "nxagentDestroyPixmap: Synchronization drawable [%p] removed from resources.\n",
(void *) pPixmap);
#endif
}
nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND);
nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP);
nxagentDestroyDrawableBitmap((DrawablePtr) pPixmap);
if (pPixmapPriv -> splitResource != NULL)
{
nxagentReleaseSplit((DrawablePtr) pPixmap);
}
/*
* A pixmap with width and height set to 0 is
* created at the beginning. To this pixmap is
* not assigned an id. This is likely a scratch
* pixmap used by the X server.
*/
if (pPixmapPriv -> id)
{
XFreePixmap(nxagentDisplay, pPixmapPriv -> id);
}
if (pPixmapPriv -> mid)
{
FreeResource(pPixmapPriv -> mid, RT_NONE);
}
SAFE_free(pPixmap);
return True;
}
Bool nxagentDestroyVirtualPixmap(PixmapPtr pPixmap)
{
PixmapPtr pVirtual = nxagentPixmapPriv(pPixmap) -> pVirtualPixmap;
/*
* Force the routine to get rid of the virtual
* pixmap.
*/
if (pVirtual != NULL)
{
pVirtual -> refcnt = 1;
nxagentPrivPixmapPtr pVirtualPriv = nxagentPixmapPriv(pVirtual);
if (pVirtualPriv -> corruptedRegion != NullRegion)
{
RegionDestroy(pVirtualPriv -> corruptedRegion);
pVirtualPriv -> corruptedRegion = NullRegion;
}
fbDestroyPixmap(pVirtual);
}
return True;
}
RegionPtr nxagentPixmapToRegion(PixmapPtr pPixmap)
{
#ifdef TEST
fprintf(stderr, "nxagentPixmapToRegion: Pixmap = [%p] nxagentVirtualPixmap = [%p]\n",
(void *) pPixmap, (void *) nxagentVirtualPixmap(pPixmap));
#endif
return fbPixmapToRegion(nxagentVirtualPixmap(pPixmap));
}
Bool nxagentModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
int bitsPerPixel, int devKind, void * pPixData)
{
/*
* See miModifyPixmapHeader() in miscrinit.c. This function is used
* to recycle the scratch pixmap for this screen. We let it refer to
* the virtual pixmap.
*/
if (!pPixmap)
{
return False;
}
if (nxagentPixmapIsVirtual(pPixmap))
{
#ifdef PANIC
fprintf(stderr, "nxagentModifyPixmapHeader: PANIC! Pixmap at [%p] is virtual.\n",
(void *) pPixmap);
#endif
FatalError("nxagentModifyPixmapHeader: PANIC! Pixmap is virtual.");
}
PixmapPtr pVirtualPixmap = nxagentVirtualPixmap(pPixmap);
#ifdef TEST
fprintf(stderr, "nxagentModifyPixmapHeader: Pixmap at [%p] Virtual at [%p].\n",
(void *) pPixmap, (void *) pVirtualPixmap);
fprintf(stderr, "nxagentModifyPixmapHeader: Pixmap has width [%d] height [%d] depth [%d] "
"bits-per-pixel [%d] devKind [%d] pPixData [%p].\n", pPixmap->drawable.width,
pPixmap->drawable.height, pPixmap->drawable.depth, pPixmap->drawable.bitsPerPixel,
pPixmap->devKind, (void *) pPixmap->devPrivate.ptr);
fprintf(stderr, "nxagentModifyPixmapHeader: New parameters are width [%d] height [%d] depth [%d] "
"bits-per-pixel [%d] devKind [%d] pPixData [%p].\n", width, height, depth,
bitsPerPixel, devKind, (void *) pPixData);
#endif
/*
* ignore return code, because the only case where this will return
* FALSE is pPixmap == NULL, which we have already caught above.
*/
miModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData);
miModifyPixmapHeader(pVirtualPixmap, width, height, depth, bitsPerPixel, devKind, pPixData);
#ifdef PANIC
if (!((width > 0) && (height > 0) && (depth > 0) && (bitsPerPixel > 0) &&
(devKind > 0) && pPixData))
{
if (pPixmap->drawable.x != 0 || pPixmap->drawable.y != 0)
{
fprintf(stderr, "nxagentModifyPixmapHeader: PANIC! Pixmap at [%p] has x [%d] and y [%d].\n",
(void *) pPixmap, pPixmap->drawable.x, pPixmap->drawable.y);
FatalError("nxagentModifyPixmapHeader: PANIC! Pixmap has x or y greater than zero.");
}
}
#endif
return True;
}
static void nxagentPixmapMatchID(void *p0, XID x1, void *p2)
{
PixmapPtr pPixmap = (PixmapPtr)p0;
struct nxagentPixmapPair *pPair = p2;
if ((pPair -> pMap == NULL) && (nxagentPixmap(pPixmap) == pPair -> pixmap))
{
pPair -> pMap = pPixmap;
}
}
PixmapPtr nxagentPixmapPtr(Pixmap pixmap)
{
if (pixmap == None)
{
return NULL;
}
struct nxagentPixmapPair pair = {
.pixmap = pixmap,
.pMap = NULL
};
FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP,
nxagentPixmapMatchID, &pair);
for (int i = 0; (pair.pMap == NULL) && (i < MAXCLIENTS); i++)
{
if (clients[i])
{
FindClientResourcesByType(clients[i], RT_PIXMAP,
nxagentPixmapMatchID, &pair);
}
}
#ifdef WARNING
if (pair.pMap == NULL)
{
fprintf(stderr, "nxagentPixmapPtr: WARNING! Failed to find "
"remote pixmap [%ld].\n", (long int) pair.pixmap);
}
else if (nxagentDrawableStatus((DrawablePtr) pair.pMap) == NotSynchronized)
{
fprintf(stderr, "WARNING! Rootless icon at [%p] [%d,%d] is not synchronized.\n",
(void *) pair.pMap, pair.pMap -> drawable.width,
pair.pMap -> drawable.height);
}
#endif
return pair.pMap;
}
/*
* Reconnection stuff.
*/
int nxagentDestroyNewPixmapResourceType(void * p, XID id)
{
/*
* Address of the destructor is set in Init.c.
*/
#ifdef TEST
fprintf(stderr, "nxagentDestroyNewPixmapResourceType: Destroying mirror id [%ld] for pixmap at [%p].\n",
nxagentPixmapPriv((PixmapPtr) p) -> mid, (void *) p);
#endif
nxagentPixmapPriv((PixmapPtr) p) -> mid = None;
return True;
}
void nxagentDisconnectPixmap(void *p0, XID x1, void *p2)
{
PixmapPtr pPixmap = (PixmapPtr) p0;
#ifdef TEST
Bool *pBool = (Bool*) p2;
fprintf(stderr, "nxagentDisconnectPixmap: Called with bool [%d] and pixmap at [%p].\n",
*pBool, (void *) pPixmap);
fprintf(stderr, "nxagentDisconnectPixmap: Virtual pixmap is [%ld].\n",
nxagentPixmap(pPixmap));
#endif
nxagentPixmap(pPixmap) = None;
if (nxagentDrawableStatus((DrawablePtr) pPixmap) == NotSynchronized)
{
nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND);
nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP);
}
}
void nxagentDisconnectAllPixmaps(void)
{
int r;
#ifdef TEST
fprintf(stderr, "nxagentDisconnectAllPixmaps: Going to iterate through pixmap resources.\n");
#endif
/*
* The RT_NX_PIXMAP resource type is allocated only on the server
* client, so we don't need to find it through the other clients
* too.
*/
r = 1;
FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, nxagentDisconnectPixmap, &r);
#ifdef WARNING
/* Note: nxagentDisconnectPixmap() does not modify r - so this check can never succeed */
if (r == 0)
{
fprintf(stderr, "nxagentDisconnectAllPixmaps: WARNING! Failed to disconnect "
"pixmap for client [%d].\n", serverClient -> index);
}
#endif
for (int i = 0; i < MAXCLIENTS; i++)
{
if (clients[i])
{
#ifdef TEST
fprintf(stderr, "nxagentDisconnectAllPixmaps: Going to disconnect pixmaps of client [%d].\n", i);
#endif
r = 1;
FindClientResourcesByType(clients[i], RT_PIXMAP, nxagentDisconnectPixmap, &r);
#ifdef WARNING
/* Note: nxagentDisconnectPixmap() does not modify r - so this check can never succeed */
if (r == 0)
{
fprintf(stderr, "nxagentDisconnectAllPixmaps: WARNING! Failed to disconnect "
"pixmap for client [%d].\n", i);
}
#endif
}
}
#ifdef TEST
fprintf(stderr, "nxagentDisconnectAllPixmaps: Pixmaps disconnection completed.\n");
#endif
return;
}
void nxagentReconnectPixmap(void *p0, XID x1, void *p2)
{
PixmapPtr pPixmap = (PixmapPtr) p0;
Bool *pBool = (Bool*) p2;
if (!*pBool || pPixmap == NULL ||
NXDisplayError(nxagentDisplay) == 1)
{
*pBool = False;
#ifdef TEST
fprintf(stderr, "nxagentReconnectPixmap: Ignoring pixmap at [%p] while "
"recovering from the error.\n", (void *) pPixmap);
#endif
return;
}
else if (pPixmap == nxagentDefaultScreen -> pScratchPixmap)
{
/*
* Every time the scratch pixmap is used its data is changed, so
* we don't need to reconnect it.
*/
#ifdef TEST
fprintf(stderr, "nxagentReconnectPixmap: Ignoring scratch pixmap at [%p].\n",
(void *) pPixmap);
#endif
return;
}
#ifdef TEST
fprintf(stderr, "nxagentReconnectPixmap: Called with result [%d] and pixmap at [%p].\n",
*pBool, (void *) pPixmap);
fprintf(stderr, "nxagentReconnectPixmap: Virtual pixmap is at [%p] picture is at [%p].\n",
(void *) nxagentPixmapPriv(pPixmap) -> pVirtualPixmap,
(void *) nxagentPixmapPriv(pPixmap) -> pPicture);
#endif
nxagentPrivPixmapPtr pPixmapPriv = nxagentPixmapPriv(pPixmap);
if (pPixmap -> drawable.width && pPixmap -> drawable.height)
{
pPixmapPriv -> id = XCreatePixmap(nxagentDisplay,
nxagentDefaultWindows[pPixmap -> drawable.pScreen -> myNum],
pPixmap -> drawable.width,
pPixmap -> drawable.height,
pPixmap -> drawable.depth);
nxagentPixmap(pPixmapPriv -> pVirtualPixmap) = pPixmapPriv -> id;
#ifdef TEST
fprintf(stderr, "nxagentReconnectPixmap: Created virtual pixmap with id [%ld] for pixmap at [%p].\n",
nxagentPixmap(pPixmap), (void *) pPixmap);
#endif
if (pPixmap == (PixmapPtr) nxagentDefaultScreen -> devPrivate)
{
#ifdef WARNING
fprintf(stderr, "nxagentReconnectPixmap: WARNING! Pixmap is root screen. Returning.\n");
#endif
return;
}
nxagentSplitTrap = True;
*pBool = nxagentSynchronizeDrawableData((DrawablePtr) pPixmap, NEVER_BREAK, NULL);
nxagentSplitTrap = False;
if (!*pBool)
{
#ifdef PANIC
fprintf(stderr, "nxagentReconnectPixmap: PANIC! Failed to synchronize the pixmap.\n");
#endif
}
if (nxagentDrawableStatus((DrawablePtr) pPixmap) == NotSynchronized)
{
if (nxagentIsCorruptedBackground(pPixmap) == 1)
{
nxagentAllocateCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND);
nxagentFillRemoteRegion((DrawablePtr) pPixmap,
nxagentCorruptedRegion((DrawablePtr) pPixmap));
}
else
{
nxagentAllocateCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP);
}
}
}
}
Bool nxagentReconnectAllPixmaps(void *p0)
{
Bool result = 1;
#ifdef TEST
fprintf(stderr, "nxagentReconnectAllPixmaps: Going to recreate all pixmaps.\n");
#endif
/*
* Reset the geometry and alpha information
* used by proxy to unpack the packed images.
*/
nxagentResetVisualCache();
nxagentResetAlphaCache();
/*
* The RT_NX_PIXMAP resource type is allocated only on the server
* client, so we don't need to find it through the other clients
* too.
*/
FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, nxagentReconnectPixmap, &result);
#ifdef WARNING
if (result == 0)
{
fprintf(stderr, "nxagentReconnectAllPixmaps: WARNING! Failed to reconnect "
"pixmap for client [%d].\n", serverClient -> index);
}
#endif
/*
* FIXME: This is a bit cumbersome: at the end of each iteration
* result will be reset to 1. Therefore at loop exit result will
* always be 1 meaning the whole function will always return 1...
*/
result = 1;
for (int i = 0; i < MAXCLIENTS; result = 1, i++)
{
if (clients[i] != NULL)
{
#ifdef TEST
fprintf(stderr, "nxagentReconnectAllPixmaps: Going to reconnect pixmaps of client [%d].\n", i);
#endif
/*
* Let the pixmap be reconnected as it was an image request
* issued by the client owning the resource. The client index is
* used as a subscript by the image routines to cache the data
* per-client.
*/
FindClientResourcesByType(clients[i], RT_PIXMAP, nxagentReconnectPixmap, &result);
#ifdef WARNING
if (result == 0)
{
fprintf(stderr, "nxagentReconnectAllPixmaps: WARNING! Failed to reconnect "
"pixmap for client [%d].\n", serverClient -> index);
}
#endif
}
}
#ifdef TEST
fprintf(stderr, "nxagentReconnectAllPixmaps: Pixmaps reconnection completed.\n");
#endif
return result;
}
#ifdef TEST
static void nxagentCheckOnePixmapIntegrity(void *p0, XID x1, void *p2)
{
PixmapPtr pPixmap = (PixmapPtr) p0;
Bool *pBool = (Bool*) p2;
if (!*pBool)
{
return;
}
if (pPixmap == nxagentDefaultScreen -> devPrivate)
{
#ifdef TEST
fprintf(stderr, "nxagentCheckOnePixmapIntegrity: pixmap %p is screen.\n",
(void *) pPixmap);
#endif
return;
}
if (pPixmap == nxagentDefaultScreen -> PixmapPerDepth[0])
{
#ifdef TEST
fprintf(stderr, "nxagentCheckOnePixmapIntegrity: pixmap %p is default stipple of screen.\n",
(void *) pPixmap);
#endif
return;
}
*pBool = nxagentCheckPixmapIntegrity(pPixmap);
}
Bool nxagentCheckPixmapIntegrity(PixmapPtr pPixmap)
{
Bool integrity = True;
unsigned long plane_mask = AllPlanes;
PixmapPtr pVirtual = nxagentVirtualPixmap(pPixmap);
unsigned int width = pPixmap -> drawable.width;
unsigned int height = pPixmap -> drawable.height;
unsigned int depth = pPixmap -> drawable.depth;
int format = (depth == 1) ? XYPixmap : ZPixmap;
if (width && height)
{
unsigned int length = nxagentImageLength(width, height, format, 0, depth);
char *data = malloc(length);
if (data == NULL)
{
FatalError("nxagentCheckPixmapIntegrity: Failed to allocate a buffer of size %d.\n", length);
}
XImage *image = XGetImage(nxagentDisplay, nxagentPixmap(pPixmap), 0, 0,
width, height, plane_mask, format);
if (image == NULL)
{
FatalError("XGetImage: Failed.\n");
SAFE_free(data);
return False;
}
#ifdef WARNING
fprintf(stderr, "nxagentCheckPixmapIntegrity: Image from X has length [%d] and checksum [0x%s].\n",
length, nxagentChecksum(image->data, length));
#endif
NXCleanImage(image);
#ifdef WARNING
fprintf(stderr, "nxagentCheckPixmapIntegrity: Image after clean has checksum [0x%s].\n",
nxagentChecksum(image->data, length));
#endif
fbGetImage((DrawablePtr) pVirtual, 0, 0, width, height, format, plane_mask, data);
#ifdef WARNING
fprintf(stderr, "nxagentCheckPixmapIntegrity: Image from FB has length [%d] and checksum [0x%s].\n",
length, nxagentChecksum(data, length));
#endif
if (image != NULL && memcmp(image -> data, data, length) != 0)
{
integrity = False;
}
else
{
integrity = True;
#ifdef TEST
fprintf(stderr, "nxagentCheckPixmapIntegrity: Pixmap at [%p] has been realized. "
"Now remote and framebuffer data are synchronized.\n", (void *) pPixmap);
#endif
}
#ifdef WARNING
if (!integrity)
{
char *p = image -> data;
char *q = data;
for (int i = 0; i < length; i++)
{
if (p[i] != q[i])
{
fprintf(stderr, "nxagentCheckPixmapIntegrity: Byte [%d] image -> data [%d] data [%d]. "
"Buffers differ!\n", i, p[i], q[i]);
}
else
{
fprintf(stderr, "nxagentCheckPixmapIntegrity: Byte [%d] image -> data [%d] data [%d].\n",
i, p[i], q[i]);
}
}
fprintf(stderr, "nxagentCheckPixmapIntegrity: Pixmap at [%p] width [%d], height [%d], has been realized "
"but the data buffer still differs.\n", (void *) pPixmap, width, height);
fprintf(stderr, "nxagentCheckPixmapIntegrity: bytes_per_line [%d] byte pad [%d] format [%d].\n",
image -> bytes_per_line, nxagentImagePad(width, height, 0, depth), image -> format);
FatalError("nxagentCheckPixmapIntegrity: Image is corrupted!!\n");
}
#endif
if (image != NULL)
{
XDestroyImage(image);
}
SAFE_free(data);
}
else
{
#ifdef WARNING
fprintf(stderr, "nxagentCheckPixmapIntegrity: Ignored pixmap at [%p] with geometry [%d] [%d].\n",
(void *) pPixmap, width, height);
#endif
}
return integrity;
}
Bool nxagentCheckAllPixmapIntegrity(void)
{
Bool imageIsGood = True;
#ifdef TEST
fprintf(stderr, "nxagentCheckAllPixmapIntegrity\n");
#endif
FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP,
nxagentCheckOnePixmapIntegrity, &imageIsGood);
for (int i = 0; (i < MAXCLIENTS) && (imageIsGood); i++)
{
if (clients[i])
{
FindClientResourcesByType(clients[i], RT_PIXMAP,
nxagentCheckOnePixmapIntegrity, &imageIsGood);
}
}
#ifdef TEST
fprintf(stderr, "nxagentCheckAllPixmapIntegrity: pixmaps integrity = %d.\n", imageIsGood);
#endif
return imageIsGood;
}
#endif
void nxagentSynchronizeShmPixmap(DrawablePtr pDrawable, int xPict, int yPict,
int wPict, int hPict)
{
if (pDrawable -> type == DRAWABLE_PIXMAP &&
nxagentIsShmPixmap((PixmapPtr) pDrawable))
{
#ifdef TEST
fprintf(stderr, "nxagentSynchronizeShmPixmap: WARNING! Synchronizing shared pixmap at [%p].\n",
(void *) pDrawable);
#endif
GCPtr pGC = nxagentGetScratchGC(pDrawable -> depth, pDrawable -> pScreen);
CARD32 attributes[3];
attributes[0] = 0x228b22;
attributes[1] = 0xffffff;
attributes[2] = FillSolid;
ChangeGC(pGC, GCForeground | GCBackground | GCFillStyle, attributes);
ValidateGC(pDrawable, pGC);
int width = (wPict != 0 && wPict <= pDrawable -> width) ? wPict : pDrawable -> width;
int height = (hPict != 0 && hPict <= pDrawable -> height) ? hPict : pDrawable -> height;
int depth = pDrawable -> depth;
int format = (depth == 1) ? XYPixmap : ZPixmap;
int length = nxagentImageLength(width, height, format, 0, depth);
Bool saveTrap = nxagentGCTrap;
nxagentGCTrap = False;
nxagentSplitTrap = True;
nxagentFBTrap = True;
char *data = malloc(length);
if (data)
{
fbGetImage(nxagentVirtualDrawable(pDrawable), xPict, yPict,
width, height, format, 0xffffffff, data);
nxagentPutImage(pDrawable, pGC, depth, xPict, yPict,
width, height, 0, format, data);
SAFE_free(data);
}
#ifdef WARNING
else
{
fprintf(stderr, "nxagentSynchronizeShmPixmap: WARNING! Failed to allocate memory for the operation.\n");
}
#endif
nxagentGCTrap = saveTrap;
nxagentSplitTrap = False;
nxagentFBTrap = False;
nxagentFreeScratchGC(pGC);
}
}
#ifdef DUMP
/*
* This function is useful to visualize a pixmap and check
* its data consistency. To avoid the creation of many
* windows, one pixmap only can be monitored at a time.
*/
Bool nxagentPixmapOnShadowDisplay(PixmapPtr pMap)
{
static Display *shadow;
static Window win;
static int init = True;
static int showTime;
static PixmapPtr pPixmap;
static int depth;
static int width;
static int height;
static int length;
static unsigned int format;
if (init)
{
if (pMap == NULL)
{
return False;
}
else
{
pPixmap = pMap;
}
depth = pPixmap -> drawable.depth;
width = pPixmap -> drawable.width;
height = pPixmap -> drawable.height;
format = (depth == 1) ? XYPixmap : ZPixmap;
shadow = XOpenDisplay("localhost:0");
if (shadow == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Shadow display not opened.\n");
#endif
return False;
}
init = False;
win = XCreateSimpleWindow(shadow, DefaultRootWindow(shadow), 0, 0,
width, height, 0, 0xFFCC33, 0xFF);
XMapWindow(shadow, win);
XClearWindow(shadow, win);
}
/*
FIXME: If the pixmap has a different depth from the window, the
XPutImage returns a BadMatch. For example this may happen if
the Render extension is enabled.
Can we fix this creating a new pixmap?
*/
if (DisplayPlanes(shadow, DefaultScreen(shadow)) != depth)
{
#ifdef WARNING
fprintf(stderr, "nxagentPixmapOnShadowDisplay: Pixmap and Window depths [%d - %d] are not equals!\n",
depth, DisplayPlanes(shadow, DefaultScreen(shadow)));
#endif
return False;
}
/*
* If the framebuffer is updated continuously, the nxagent
* visualization becomes much too slow.
*/
if ((GetTimeInMillis() - showTime) < 500)
{
return False;
}
showTime = GetTimeInMillis();
length = nxagentImageLength(width, height, format, 0, depth);
char * data = malloc(length);
if (data == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Failed to allocate memory for the operation.\n");
#endif
return False;
}
fbGetImage((DrawablePtr) nxagentVirtualPixmap(pPixmap), 0, 0,
width, height, format, AllPlanes, data);
Visual *pVisual = nxagentImageVisual((DrawablePtr) pPixmap, depth);
if (pVisual == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Visual not found. Using default visual.\n");
#endif
pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual;
}
XImage *image = XCreateImage(nxagentDisplay, pVisual,
depth, format, 0, (char *) data,
width, height, BitmapPad(nxagentDisplay),
nxagentImagePad(width, format, 0, depth));
if (image == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentPixmapOnShadowDisplay: XCreateImage failed.\n");
#endif
SAFE_free(data);
return False;
}
XGCValues value = {
.foreground = 0xff0000,
.background = 0x000000,
.plane_mask = 0xffffff,
.fill_style = FillSolid
};
XlibGC gc = XCreateGC(shadow, win, GCBackground |
GCForeground | GCFillStyle | GCPlaneMask, &value);
NXCleanImage(image);
XPutImage(shadow, win, gc, image, 0, 0, 0, 0, width, height);
XFreeGC(shadow, gc);
if (image != NULL)
{
XDestroyImage(image);
}
return True;
}
Bool nxagentFbOnShadowDisplay(void)
{
static Display *shadow;
static Window win;
static int init = True;
static int showTime;
static int prevWidth, prevHeight;
WindowPtr pWin = screenInfo.screens[0]->root;
if (pWin == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentFbOnShadowDisplay: The parent window is NULL.\n");
#endif
return False;
}
int depth = pWin -> drawable.depth;
int width = pWin -> drawable.width;
int height = pWin -> drawable.height;
unsigned int format = (depth == 1) ? XYPixmap : ZPixmap;
if (init)
{
shadow = XOpenDisplay("localhost:0");
if (shadow == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Shadow display not opened.\n");
#endif
return False;
}
init = False;
prevWidth = width;
prevHeight = height;
win = XCreateSimpleWindow(shadow, DefaultRootWindow(shadow), 0, 0,
width, height, 0, 0xFFCC33, 0xFF);
XMapWindow(shadow, win);
XClearWindow(shadow, win);
}
if (DisplayPlanes(shadow, DefaultScreen(shadow)) != depth)
{
#ifdef WARNING
fprintf(stderr, "nxagentFbOnShadowDisplay: Depths [%d - %d] are not equals!\n",
depth, DisplayPlanes(shadow, DefaultScreen(shadow)));
#endif
return False;
}
/*
* If the framebuffer is updated continuously, the nxagent
* visualization becomes too much slow.
*/
if ((GetTimeInMillis() - showTime) < 500)
{
return False;
}
showTime = GetTimeInMillis();
/*
* If the root window is resized, also the window on shadow
* display must be resized.
*/
if (prevWidth != width || prevHeight != height)
{
prevWidth = width;
prevHeight = height;
XWindowChanges values = {
.width = width,
.height = height
};
XConfigureWindow(shadow, win, CWWidth | CWHeight, &values);
}
int length = nxagentImageLength(width, height, format, 0, depth);
char *data = malloc(length);
if (data == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Failed to allocate memory for the operation.\n");
#endif
return False;
}
fbGetImage((DrawablePtr)pWin, 0, 0,
width, height, format, AllPlanes, data);
Visual *pVisual = nxagentImageVisual((DrawablePtr) pWin, depth);
if (pVisual == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Visual not found. Using default visual.\n");
#endif
pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual;
}
XImage *image = XCreateImage(nxagentDisplay, pVisual,
depth, format, 0, (char *) data,
width, height, BitmapPad(nxagentDisplay),
nxagentImagePad(width, format, 0, depth));
if (image == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentFbOnShadowDisplay: XCreateImage failed.\n");
#endif
SAFE_free(data);
return False;
}
XGCValues value = {
.foreground = 0xff0000,
.background = 0x000000,
.plane_mask = 0xffffff,
.fill_style = FillSolid
};
XlibGC gc = XCreateGC(shadow, win, GCBackground |
GCForeground | GCFillStyle | GCPlaneMask, &value);
NXCleanImage(image);
XPutImage(shadow, win, gc, image, 0, 0, 0, 0, width, height);
XFreeGC(shadow, gc);
if (image != NULL)
{
XDestroyImage(image);
}
return True;
}
#endif
#ifdef DEBUG
void nxagentPrintResourceTypes(void)
{
fprintf(stderr, "nxagentPrintResourceTypes: RT_PIXMAP [%lu].\n", (unsigned long) RT_PIXMAP);
fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_PIXMAP [%lu].\n", (unsigned long) RT_NX_PIXMAP);
fprintf(stderr, "nxagentPrintResourceTypes: RT_GC [%lu].\n", (unsigned long) RT_GC);
fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_GC [%lu].\n", (unsigned long) RT_NX_GC);
fprintf(stderr, "nxagentPrintResourceTypes: RT_FONT [%lu].\n", (unsigned long) RT_FONT);
fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_FONT [%lu].\n", (unsigned long) RT_NX_FONT);
fprintf(stderr, "nxagentPrintResourceTypes: RT_CURSOR [%lu].\n", (unsigned long) RT_CURSOR);
fprintf(stderr, "nxagentPrintResourceTypes: RT_WINDOW [%lu].\n", (unsigned long) RT_WINDOW);
fprintf(stderr, "nxagentPrintResourceTypes: RT_COLORMAP [%lu].\n", (unsigned long) RT_COLORMAP);
}
void nxagentPrintResourcePredicate(void *value, XID id, XID type, void *cdata)
{
fprintf(stderr, "nxagentPrintResourcePredicate: Resource [%p] id [%lu] type [%lu].\n",
(void *) value, (unsigned long) id, (unsigned long) type);
}
void nxagentPrintResources(void)
{
nxagentPrintResourceTypes();
for (int i = 0; i < MAXCLIENTS; i++)
{
if (clients[i])
{
Bool result;
fprintf(stderr, "nxagentPrintResources: Printing resources for client [%d]:\n",
i);
FindAllClientResources(clients[i], nxagentPrintResourcePredicate, &result);
}
}
}
#endif