1483 lines
39 KiB
C
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
|