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

4790 lines
112 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
/* */
/* NXCOMPEXT, 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. */
/* */
/**************************************************************************/
/*
* let the types be the Xlib types by undefining _XSERVER64. This
* means, when calling the functions of this file from nxagent (where
* Agent.h has been included) you need to use/provide XlibAtom and
* XlibWindow instead of Atom and Window
*/
#undef _XSERVER64
#include <sys/socket.h>
#ifndef __sun
#include <strings.h>
#endif
#include "dix.h"
#include "os.h"
/*
* Needed to enable definition of the callback
* functions.
*/
#define NX_TRANS_SOCKET
#include <nx-X11/Xlib.h>
#include <nx-X11/Xutil.h>
#include <nx-X11/Xlibint.h>
#include "Compext.h"
#include <nx/NX.h>
#include <nx/NXproto.h>
#include <nx/NXpack.h>
#include <nx/MD5.h>
#include "Clean.h"
#include "Mask.h"
#include "Colormap.h"
#include "Alpha.h"
#include "Bitmap.h"
#include "Jpeg.h"
#include "Png.h"
#include "Rgb.h"
#include "Rle.h"
#include "Z.h"
#include "../Utils.h"
#define PANIC
#define WARNING
#undef TEST
#undef TEST_DISPLAY
#undef TEST_IMAGE
#undef TEST_INPUT
#undef TEST_PARAMS
#undef TEST_POINTER
#undef TEST_PROPERTY
#undef TEST_SPLIT
#undef TEST_UNPACK
#undef DEBUG
#undef DEBUG_DISPLAY
#undef DEBUG_IMAGE
#undef DEBUG_INPUT
#undef DEBUG_PARAMS
#undef DEBUG_POINTER
#undef DEBUG_PROPERTY
#undef DEBUG_SPLIT
#undef DEBUG_UNPACK
#undef DUMP
/*
* Maximum number of colors allowed in
* Png encoding.
*/
#define NB_COLOR_MAX 256
/*
* Dummy error handlers used internally to catch
* Xlib failures in replies.
*/
static int _NXInternalReplyErrorFunction(Display *dpy, XErrorEvent *error);
static void _NXInternalLostSequenceFunction(Display *dpy, unsigned long newseq,
unsigned long lastseq, unsigned int type);
/*
* Resource ids that can be requested by
* the client for use in split or unpack
* operations.
*/
static unsigned char _NXSplitResources[NXNumberOfResources];
static unsigned char _NXUnpackResources[NXNumberOfResources];
static Display *_NXDisplayInitialized = NULL;
/*
* Used in asynchronous handling of
* GetImage replies.
*/
typedef struct
{
unsigned long sequence;
unsigned int resource;
unsigned long mask;
int format;
int width;
int height;
_XAsyncHandler *handler;
XImage *image;
} _NXCollectImageState;
static _NXCollectImageState *_NXCollectedImages[NXNumberOfResources];
/*
* Used in asynchronous handling of
* GetProperty replies.
*/
typedef struct
{
unsigned long sequence;
unsigned int resource;
Window window;
Atom property;
Atom type;
int format;
unsigned long items;
unsigned long after;
_XAsyncHandler *handler;
char *data;
} _NXCollectPropertyState;
static _NXCollectPropertyState *_NXCollectedProperties[NXNumberOfResources];
/*
* Used in asynchronous handling of
* GrabPointer replies.
*/
typedef struct
{
unsigned long sequence;
unsigned int resource;
int status;
_XAsyncHandler *handler;
} _NXCollectGrabPointerState;
static _NXCollectGrabPointerState *_NXCollectedGrabPointers[NXNumberOfResources];
/*
* Used in asynchronous handling of
* GetInputFocus replies.
*/
typedef struct
{
unsigned long sequence;
unsigned int resource;
Window focus;
int revert_to;
_XAsyncHandler *handler;
} _NXCollectInputFocusState;
static _NXCollectInputFocusState *_NXCollectedInputFocuses[NXNumberOfResources];
/*
* Used by functions handling cache of
* packed images.
*/
#define MD5_LENGTH 16
typedef struct
{
md5_byte_t *md5;
XImage *image;
unsigned int method;
} _NXImageCacheEntry;
int NXImageCacheSize = 0;
int NXImageCacheHits = 0;
int NXImageCacheOps = 0;
_NXImageCacheEntry *NXImageCache = NULL;
#ifdef DUMP
void _NXCacheDump(const char *label);
void _NXDumpData(const unsigned char *buffer, unsigned int size);
#endif
/*
* From X11/PutImage.c.
*
* Cancel a GetReq operation, before doing
* _XSend or Data.
*/
#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
#define UnGetReq(name)\
dpy->bufptr -= SIZEOF(x##name##Req);\
dpy->request--
#else
#define UnGetReq(name)\
dpy->bufptr -= SIZEOF(x/**/name/**/Req);\
dpy->request--
#endif
#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
#define UnGetEmptyReq()\
dpy->bufptr -= 4;\
dpy->request--
#else
#define UnGetEmptyReq(name)\
dpy->bufptr -= 4;\
dpy->request--
#endif
/*
* From X11/ImUtil.c.
*/
extern int _XGetBitsPerPixel(Display *dpy, int depth);
extern int _XGetScanlinePad(Display *dpy, int depth);
#define ROUNDUP(nbytes, pad) (((nbytes) + ((pad) - 1)) & \
~(long)((pad) - 1))
static unsigned int DepthOnes(unsigned long mask)
{
register unsigned long y;
y = (mask >> 1) &033333333333;
y = mask - y - ((y >>1) & 033333333333);
return ((unsigned int) (((y + (y >> 3)) &
030707070707) % 077));
}
#define CanMaskImage(image, mask) \
\
(image -> format == ZPixmap && mask != NULL && \
(image -> depth == 32 || image -> depth == 24 || \
(image -> depth == 16 && (image -> red_mask == 0xf800 && \
image -> green_mask == 0x7e0 && image -> blue_mask == 0x1f))))
#define ShouldMaskImage(image, mask) (mask -> color_mask != 0xff)
/*
* Initialize and reset the internal structures.
*/
extern int _NXInternalInitResources(Display *dpy);
extern int _NXInternalResetResources(Display *dpy);
extern int _NXInternalInitEncoders(Display *dpy);
extern int _NXInternalResetEncoders(Display *dpy);
int NXInitDisplay(Display *dpy)
{
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXInitDisplay: Called for display at [%p].\n", (void *) dpy);
#endif
if (_NXDisplayInitialized == NULL)
{
_NXInternalInitResources(dpy);
_NXInternalInitEncoders(dpy);
_NXDisplayInitialized = dpy;
return 1;
}
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXInitDisplay: WARNING! Internal structures already initialized.\n");
#endif
return 0;
}
int NXResetDisplay(Display *dpy)
{
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXResetDisplay: Called for display at [%p].\n", (void *) dpy);
#endif
if (_NXDisplayInitialized != NULL)
{
_NXInternalResetResources(dpy);
_NXInternalResetEncoders(dpy);
_NXDisplayInitialized = NULL;
return 1;
}
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXResetDisplay: WARNING! Internal structures already reset.\n");
#endif
return 0;
}
int _NXInternalInitResources(Display *dpy)
{
return _NXInternalResetResources(dpy);
}
int _NXInternalResetResources(Display *dpy)
{
#if defined(TEST_IMAGE) || defined(TEST_PROPERTY) || defined(TEST_POINTER) || defined(TEST_INPUT)
fprintf(stderr, "******_NXInternalResetResources: Clearing all the internal structures.\n");
#endif
for (int i = 0; i < NXNumberOfResources; i++)
{
_NXSplitResources[i] = 0;
_NXUnpackResources[i] = 0;
if (_NXCollectedImages[i] != NULL)
{
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing collect image data "
"for resource [%d].\n", i);
#endif
if (_NXCollectedImages[i] -> handler != NULL)
{
DeqAsyncHandler(dpy, _NXCollectedImages[i] -> handler);
SAFE_free(_NXCollectedImages[i] -> handler);
}
if (_NXCollectedImages[i] -> image != NULL)
{
XDestroyImage(_NXCollectedImages[i] -> image);
}
SAFE_free(_NXCollectedImages[i]);
}
if (_NXCollectedProperties[i] != NULL)
{
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing collect property data "
"for resource [%d].\n", i);
#endif
if (_NXCollectedProperties[i] -> handler != NULL)
{
DeqAsyncHandler(dpy, _NXCollectedProperties[i] -> handler);
SAFE_free(_NXCollectedProperties[i] -> handler);
}
SAFE_free(_NXCollectedProperties[i] -> data);
SAFE_free(_NXCollectedProperties[i]);
}
if (_NXCollectedGrabPointers[i] != NULL)
{
#ifdef TEST_POINTER
fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing grab pointer data "
"for resource [%d].\n", i);
#endif
if (_NXCollectedGrabPointers[i] -> handler != NULL)
{
DeqAsyncHandler(dpy, _NXCollectedGrabPointers[i] -> handler);
SAFE_free(_NXCollectedGrabPointers[i] -> handler);
}
SAFE_free(_NXCollectedGrabPointers[i]);
}
if (_NXCollectedInputFocuses[i] != NULL)
{
#ifdef TEST_INPUT
fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing collect input focus data "
"for resource [%d].\n", i);
#endif
if (_NXCollectedInputFocuses[i] -> handler != NULL)
{
DeqAsyncHandler(dpy, _NXCollectedInputFocuses[i] -> handler);
SAFE_free(_NXCollectedInputFocuses[i] -> handler);
}
SAFE_free(_NXCollectedInputFocuses[i]);
}
}
return 1;
}
int _NXInternalInitEncoders(Display *dpy)
{
ZInitEncoder();
return 1;
}
int _NXInternalResetEncoders(Display *dpy)
{
ZResetEncoder();
return 1;
}
int NXSetDisplayPolicy(Display *dpy, int policy)
{
if (policy == NXPolicyImmediate)
{
return NXTransPolicy(NX_FD_ANY, NX_POLICY_IMMEDIATE);
}
else
{
return NXTransPolicy(NX_FD_ANY, NX_POLICY_DEFERRED);
}
}
/*
* return codes:
* -1 something went wrong
* 1 success
*/
int NXSetDisplayBuffer(Display *dpy, int size)
{
/*
* This is not multi-thread safe, so,
* if you have threads, be sure that
* they are stopped.
*/
char *buffer;
XFlush(dpy);
if (dpy -> bufmax - size == dpy -> buffer)
{
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXSetDisplayBuffer: Nothing to do with buffer size matching.\n");
#endif
return 1;
}
else if (dpy -> bufptr != dpy -> buffer)
{
#ifdef PANIC
fprintf(stderr, "******NXSetDisplayBuffer: PANIC! The display buffer is not empty.\n");
#endif
return -1;
}
else if ((buffer = Xcalloc(1, size)) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXSetDisplayBuffer: PANIC! Can't allocate [%d] bytes for the buffer.\n",
size);
#endif
return -1;
}
SAFE_free(dpy -> buffer);
dpy -> buffer = buffer;
dpy -> bufptr = dpy -> buffer;
dpy -> bufmax = dpy -> bufptr + size;
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXSetDisplayBuffer: Set the display output buffer size to [%d].\n",
size);
#endif
return 1;
}
/*
* If set, the Popen() function in the X server
* will remove the LD_LIBRARY_PATH variable from
* the environment before calling the execl()
* function on the child process.
*/
int NXUnsetLibraryPath(int value)
{
int previous = _NXUnsetLibraryPath;
_NXUnsetLibraryPath = value;
#ifdef TEST
fprintf(stderr, "******NXUnsetLibraryPath: Set the flag to [%d] with previous value [%d].\n",
value, previous);
#endif
return previous;
}
/*
* If set, the Xlib I/O error handler will simply
* return, instead of quitting the program. This
* leaves to the application the responsibility
* of checking the state of the XlibDisplayIOEr-
* ror flag.
*/
int NXHandleDisplayError(int value)
{
int previous = _NXHandleDisplayError;
_NXHandleDisplayError = value;
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXHandleDisplayError: Set the flag to [%d] with previous value [%d].\n",
value, previous);
#endif
return previous;
}
/*
* Shutdown the display descriptor and force Xlib
* to set the I/O error flag.
*/
Bool NXForceDisplayError(Display *dpy)
{
if (dpy != NULL)
{
NXTransClose(dpy -> fd);
if (!(dpy -> flags & XlibDisplayIOError))
{
shutdown(dpy -> fd, SHUT_RDWR);
_XIOError(dpy);
}
return 1;
}
return 0;
}
/*
* Check if the display has become invalid. Similarly
* to the modified Xlib, we call the predicate funct-
* ion with the value of the XlibDisplayIOError flag
* only if the I/O error was not encountered already.
* The application can use this function to query the
* XlibDisplayIOError flag because Xlib doesn't expose
* the internals of the display structure to the appli-
* cation.
*/
int NXDisplayError(Display *dpy)
{
if (dpy != NULL)
{
return (_XGetIOError(dpy) ||
(_NXDisplayErrorFunction != NULL &&
(*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy))));
}
return 1;
}
/*
* Various queries related to the state of the
* display connection.
*/
int NXDisplayReadable(Display *dpy)
{
int result;
int readable;
result = NXTransReadable(dpy -> fd, &readable);
if (result == 0)
{
#ifdef DEBUG_DISPLAY
fprintf(stderr, "******NXDisplayReadable: Returning [%d] bytes readable from fd [%d].\n",
readable, dpy -> fd);
#endif
return readable;
}
#ifdef DEBUG_DISPLAY
fprintf(stderr, "******NXDisplayReadable: WARNING! Error detected on display fd [%d].\n",
dpy -> fd);
#endif
return -1;
}
int NXDisplayFlushable(Display *dpy)
{
#ifdef DEBUG_DISPLAY
int flushable;
flushable = NXTransFlushable(dpy -> fd) +
(dpy -> bufptr - dpy -> buffer);
fprintf(stderr, "******NXDisplayFlushable: Returning [%d+%d=%d] bytes flushable "
"to fd [%d].\n", (int) (dpy -> bufptr - dpy -> buffer),
(int) (flushable - (dpy -> bufptr - dpy -> buffer)),
flushable, dpy -> fd);
return flushable;
#else
return NXTransFlushable(dpy -> fd) + (dpy -> bufptr - dpy -> buffer);
#endif
}
int NXDisplayCongestion(Display *dpy)
{
#ifdef DEBUG_DISPLAY
int congestion = NXTransCongestion(dpy -> fd);
fprintf(stderr, "******NXDisplayCongestion: Returning [%d] as congestion level for fd [%d].\n",
congestion, dpy -> fd);
return congestion;
#else
return NXTransCongestion(dpy -> fd);
#endif
}
int NXFlushDisplay(Display *dpy, int what)
{
if (!(dpy -> flags & XlibDisplayWriting) &&
dpy -> bufptr - dpy -> buffer > 0)
{
#ifdef DEBUG_DISPLAY
fprintf(stderr, "******NXFlushDisplay: Writing with [%d] bytes in the buffer.\n",
(int) (dpy -> bufptr - dpy -> buffer));
#endif
XFlush(dpy);
}
if (what == NXFlushBuffer)
{
return 0;
}
#ifdef DEBUG_DISPLAY
fprintf(stderr, "******NXFlushDisplay: Flushing with [%d] bytes in the NX transport.\n",
NXDisplayFlushable(dpy));
#endif
return NXTransFlush(dpy -> fd);
}
NXDisplayErrorPredicate NXSetDisplayErrorPredicate(NXDisplayErrorPredicate predicate)
{
NXDisplayErrorPredicate previous = _NXDisplayErrorFunction;
_NXDisplayErrorFunction = predicate;
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXSetDisplayErrorPredicate: Set the predicate to [%p] with previous value [%p].\n",
predicate, previous);
#endif
return previous;
}
NXDisplayBlockHandler NXSetDisplayBlockHandler(NXDisplayBlockHandler handler)
{
NXDisplayBlockHandler previous = _NXDisplayBlockFunction;
_NXDisplayBlockFunction = handler;
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXSetDisplayBlockHandler: Set the handler to [%p] with previous value [%p].\n",
handler, previous);
#endif
return previous;
}
NXDisplayWriteHandler NXSetDisplayWriteHandler(NXDisplayWriteHandler handler)
{
NXDisplayWriteHandler previous = _NXDisplayWriteFunction;
_NXDisplayWriteFunction = handler;
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXSetDisplayWriteHandler: Set the handler to [%p] with previous value [%p].\n",
handler, previous);
#endif
return previous;
}
NXDisplayFlushHandler NXSetDisplayFlushHandler(NXDisplayFlushHandler handler, Display *display)
{
NXDisplayFlushHandler previous = _NXDisplayFlushFunction;
_NXDisplayFlushFunction = handler;
NXTransHandler(NX_FD_ANY, NX_HANDLER_FLUSH,
(void (*)(void *, int)) handler, (void *) display);
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXSetDisplayFlushHandler: Set the handler to [%p] with display [%p] "
"and previous value [%p].\n", handler, display, previous);
#endif
return previous;
}
NXDisplayStatisticsHandler NXSetDisplayStatisticsHandler(NXDisplayStatisticsHandler handler, char **buffer)
{
NXDisplayStatisticsHandler previous = _NXDisplayStatisticsFunction;
_NXDisplayStatisticsFunction = handler;
/*
* Propagate the handler.
*/
NXTransHandler(NX_FD_ANY, NX_HANDLER_STATISTICS,
(void (*)(void *, int)) handler, (void *) buffer);
#ifdef TEST_DISPLAY
fprintf(stderr, "******NXSetDisplayStatisticsHandler: Set the handler to [%p] with buffer pointer [%p] "
"and previous value [%p].\n", handler, buffer, previous);
#endif
return previous;
}
NXLostSequenceHandler NXSetLostSequenceHandler(NXLostSequenceHandler handler)
{
NXLostSequenceHandler previous = _NXLostSequenceFunction;
_NXLostSequenceFunction = handler;
#ifdef TEST
fprintf(stderr, "******NXSetLostSequenceHandler: Set the handler to [%p] with previous value [%p].\n",
handler, previous);
#endif
return previous;
}
int _NXInternalReplyErrorFunction(Display *dpy, XErrorEvent *error)
{
#ifdef TEST
fprintf(stderr, "******_NXInternalReplyErrorFunction: Internal error handler called.\n");
#endif
return 0;
}
void _NXInternalLostSequenceFunction(Display *dpy, unsigned long newseq,
unsigned long lastseq, unsigned int type)
{
#ifdef TEST
fprintf(stderr, "******_NXInternalLostSequenceFunction: WARNING! Sequence lost with new "
"sequence %ld last request %ld.\n", newseq, dpy -> request);
/*
* TODO: Reply or event info must be implemented.
*
* fprintf(stderr, "******_NXInternalLostSequenceFunction: WARNING! Expected event or reply "
* "was %ld with sequence %ld.\n", (long) rep -> type, (long) rep -> sequenceNumber);
*/
fprintf(stderr, "******_NXInternalLostSequenceFunction: WARNING! Last sequence read "
"was %ld display request is %ld.\n", lastseq & 0xffff, dpy -> request & 0xffff);
#endif
}
/*
* return codes:
* 0 error receiving reply
* 1 success
*/
Status NXGetControlParameters(Display *dpy, unsigned int *link_type, unsigned int *local_major,
unsigned int *local_minor, unsigned int *local_patch,
unsigned int *remote_major, unsigned int *remote_minor,
unsigned int *remote_patch, int *split_timeout, int *motion_timeout,
int *split_mode, int *split_size, unsigned int *pack_method,
unsigned int *pack_quality, int *data_level, int *stream_level,
int *delta_level, unsigned int *load_cache,
unsigned int *save_cache, unsigned int *startup_cache)
{
xNXGetControlParametersReply rep;
_X_UNUSED register xReq *req;
LockDisplay(dpy);
GetEmptyReq(NXGetControlParameters, req);
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetControlParameters: Sending message opcode [%d].\n",
X_NXGetControlParameters);
#endif
if (_XReply(dpy, (xReply *) &rep, 0, xTrue) == xFalse)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetControlParameters: Error receiving reply.\n");
#endif
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetControlParameters: Got reply with link type [%u].\n", rep.linkType);
fprintf(stderr, "******NXGetControlParameters: Local protocol major [%u] minor [%u] patch [%u].\n",
rep.localMajor, rep.localMinor, rep.localPatch);
fprintf(stderr, "******NXGetControlParameters: Remote protocol major [%u] minor [%u] patch [%u].\n",
rep.remoteMajor, rep.remoteMinor, rep.remotePatch);
fprintf(stderr, "******NXGetControlParameters: Split timeout [%d] motion timeout [%d].\n",
(int) rep.splitTimeout, (int) rep.motionTimeout);
fprintf(stderr, "******NXGetControlParameters: Split mode [%d] split size [%d].\n",
(int) rep.splitMode, (int) rep.splitSize);
fprintf(stderr, "******NXGetControlParameters: Preferred pack method [%d] pack quality [%d].\n",
(int) rep.packMethod, (int) rep.packQuality);
fprintf(stderr, "******NXGetControlParameters: Data level [%d] stream level [%d] delta level [%d].\n",
rep.dataLevel, rep.streamLevel, rep.deltaLevel);
#endif
*link_type = rep.linkType;
*local_major = rep.localMajor;
*local_minor = rep.localMinor;
*local_patch = rep.localPatch;
*remote_major = rep.remoteMajor;
*remote_minor = rep.remoteMinor;
*remote_patch = rep.remotePatch;
*split_timeout = rep.splitTimeout;
*motion_timeout = rep.motionTimeout;
*split_mode = rep.splitMode;
*split_size = rep.splitSize;
*pack_method = rep.packMethod;
*pack_quality = rep.packQuality;
*data_level = rep.dataLevel;
*stream_level = rep.streamLevel;
*delta_level = rep.deltaLevel;
*load_cache = rep.loadCache;
*save_cache = rep.saveCache;
*startup_cache = rep.startupCache;
UnlockDisplay(dpy);
SyncHandle();
/*
* Install our internal out-of-sync handler.
*/
_NXLostSequenceFunction = _NXInternalLostSequenceFunction;
return 1;
}
/*
* Which unpack methods are supported by the
* remote proxy?
*/
/*
* return codes:
* 0 something went wrong
* 1 success
*/
Status NXGetUnpackParameters(Display *dpy, unsigned int *entries, unsigned char supported_methods[])
{
register xNXGetUnpackParametersReq *req;
xNXGetUnpackParametersReply rep;
register unsigned n;
if (*entries < NXNumberOfPackMethods)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetUnpackParameters: Requested only [%d] entries while they should be [%d].\n",
*entries, NXNumberOfPackMethods);
#endif
return 0;
}
LockDisplay(dpy);
GetReq(NXGetUnpackParameters, req);
req -> entries = *entries;
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetUnpackParameters: Sending message opcode [%d] with [%d] requested entries.\n",
X_NXGetUnpackParameters, *entries);
#endif
if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == xFalse || rep.length == 0)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetUnpackParameters: Error receiving reply.\n");
#endif
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
if ((n = rep.length << 2) > *entries)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetUnpackParameters: Got [%d] bytes of reply data while they should be [%d].\n",
n, *entries);
#endif
_XEatData(dpy, (unsigned long) n);
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
*entries = n;
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetUnpackParameters: Reading [%d] bytes of reply data.\n", n);
#endif
_XReadPad(dpy, (char *) supported_methods, n);
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetUnpackParameters: Got reply with methods: ");
for (unsigned int i = 0; i < n; i++)
{
if (supported_methods[i] != 0)
{
fprintf(stderr, "[%d]", i);
}
}
fprintf(stderr, ".\n");
#endif
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* Query and enable the MIT-SHM support between the
* proxy and the X server. The 'enable' flags must be
* true if shared memory PutImages and PutPackedImages
* are desired. On return the flags will say if support
* has been successfully enabled.
*
* Note that the the client part is not useful and not
* implemented. The size of the segment is chosen by
* the proxy. The main purpose of the message is to
* reserve the XID that will be used by the remote.
*/
/*
* return codes:
* 0 something went wrong
* 1 success
*/
Status NXGetShmemParameters(Display *dpy, unsigned int *enable_client,
unsigned int *enable_server, unsigned int *client_segment,
unsigned int *server_segment, unsigned int *client_size,
unsigned int *server_size)
{
register xNXGetShmemParametersReq *req;
register int stage;
xNXGetShmemParametersReply rep;
/*
* Save the previous handler.
*/
int (*handler)(Display *, XErrorEvent *) = _XErrorFunction;
*client_segment = 0;
*server_segment = 0;
if (*enable_client)
{
*client_segment = XAllocID(dpy);
}
if (*enable_server)
{
*server_segment = XAllocID(dpy);
}
LockDisplay(dpy);
_XErrorFunction = _NXInternalReplyErrorFunction;
for (stage = 0; stage < 3; stage++)
{
GetReq(NXGetShmemParameters, req);
req -> stage = stage;
req -> enableClient = (*enable_client != 0 ? 1 : 0);
req -> enableServer = (*enable_server != 0 ? 1 : 0);
req -> clientSegment = *client_segment;
req -> serverSegment = *server_segment;
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetShmemParameters: Sending message opcode [%d] at stage [%d].\n",
X_NXGetShmemParameters, stage);
#endif
#ifdef TEST_PARAMS
if (stage == 0)
{
fprintf(stderr, "******NXGetShmemParameters: Enable client is [%u] enable server is [%u].\n",
*enable_client, *enable_server);
fprintf(stderr, "******NXGetShmemParameters: Client segment is [%u] server segment is [%u].\n",
*client_segment, *server_segment);
}
#endif
/*
* There isn't X server reply in the second stage.
* The procedure followed at X server side is:
*
* Stage 0: Send X_QueryExtension and masquerade
* the reply.
*
* Stage 1: Allocate the shared memory and send
* X_ShmAttach to the X server.
*
* Stage 2: Send X_GetInputFocus and masquerade
* the reply.
*
* The last message is used to force a reply and
* collect any X error caused by a failure in the
* shared memory initialization.
*/
if (stage != 1)
{
/*
* We are only interested in the final reply.
*/
if (_XReply(dpy, (xReply *) &rep, 0, xTrue) == xFalse)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetShmemParameters: Error receiving reply.\n");
#endif
_XErrorFunction = handler;
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
}
}
/*
* Return the settings to client.
*/
*enable_client = rep.clientEnabled;
*enable_server = rep.serverEnabled;
*client_size = rep.clientSize;
*server_size = rep.serverSize;
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetShmemParameters: Got final reply with enabled client [%u] and server [%u].\n",
*enable_client, *enable_server);
fprintf(stderr, "******NXGetShmemParameters: Client segment size [%u] server segment size [%u].\n",
*client_size, *server_size);
#endif
_XErrorFunction = handler;
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* Get the path to the font server that can be used by the X
* server to tunnel the font connections across the NX link.
* The path actually represents the TCP port where the proxy
* on the NX client side is listening. The agent can tempora-
* rily enable the tunneling when it needs a font that is not
* available on the client, for example when the session is
* migrated from a different X server.
*
* Note that it is not advisable to use the font server chan-
* nel for other purposes than restoring a font that is found
* missing at the time the session is migrated to a different
* display. This is because the agent implements a caching of
* the list of fonts supported by the client as it needs to
* advertise only the fonts that can be opened at both sides.
*/
/*
* return codes:
* 0 something went wrong
* 1 success
*/
Status NXGetFontParameters(Display *dpy, unsigned int path_length, char path_data[])
{
_X_UNUSED register xNXGetFontParametersReq *req;
xNXGetFontParametersReply rep;
register unsigned n;
#ifdef TEST_PARAMS
register unsigned i;
#endif
if (path_length < 1)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetFontParameters: No room to store the reply.\n");
#endif
return 0;
}
*path_data = '\0';
LockDisplay(dpy);
GetReq(NXGetFontParameters, req);
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetFontParameters: Sending message opcode [%d].\n",
X_NXGetFontParameters);
#endif
if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == xFalse || rep.length == 0)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetFontParameters: Error receiving reply.\n");
#endif
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
if ((n = rep.length << 2) > path_length)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetFontParameters: Got [%d] bytes of reply data with only room for [%d].\n",
n, path_length);
#endif
_XEatData(dpy, (unsigned long) n);
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetFontParameters: Reading [%d] bytes of reply data.\n", n);
#endif
_XReadPad(dpy, (char *) path_data, n);
/*
* Check if the string can be fully
* contained by the buffer.
*/
if (*path_data > path_length - 1)
{
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetFontParameters: Inconsistent length in the returned string.\n");
#endif
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
#ifdef TEST_PARAMS
fprintf(stderr, "******NXGetFontParameters: Got font path of [%d] bytes and value [",
(int) *path_data);
for (i = 0; i < *path_data; i++)
{
fprintf(stderr, "%c", *(path_data + i + 1));
}
fprintf(stderr, "].\n");
#endif
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
unsigned int NXAllocSplit(Display *dpy, unsigned int resource)
{
if (resource == NXAnyResource)
{
for (resource = 0; resource < NXNumberOfResources; resource++)
{
if (_NXSplitResources[resource] == 0)
{
_NXSplitResources[resource] = 1;
#ifdef TEST_SPLIT
fprintf(stderr, "******NXAllocSplit: Reserved resource [%u].\n",
resource);
#endif
return resource;
}
}
#ifdef TEST_SPLIT
fprintf(stderr, "******NXAllocSplit: WARNING! Resource limit exhausted.\n");
#endif
return NXNoResource;
}
else if (resource >= 0 && resource < NXNumberOfResources)
{
#ifdef TEST_SPLIT
if (_NXSplitResources[resource] == 0)
{
fprintf(stderr, "******NXAllocSplit: Reserved requested resource [%u].\n",
resource);
}
else
{
fprintf(stderr, "******NXAllocSplit: Requested resource [%u] already reserved.\n",
resource);
}
#endif
_NXSplitResources[resource] = 1;
}
#ifdef PANIC
fprintf(stderr, "******NXAllocSplit: PANIC! Can't reserve requested resource [%u].\n",
resource);
#endif
return NXNoResource;
}
/*
* Tell the proxy to split the next messages.
*/
int NXStartSplit(Display *dpy, unsigned int resource, unsigned int mode)
{
register xNXStartSplitReq *req;
LockDisplay(dpy);
GetReq(NXStartSplit, req);
req -> resource = resource;
req -> mode = mode;
#ifdef TEST_SPLIT
fprintf(stderr, "******NXStartSplit: Sending opcode [%d] with resource [%d] mode [%d].\n",
X_NXStartSplit, resource, mode);
#endif
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* Send the closure of the split sequence and
* tell the proxy to send the results.
*/
int NXEndSplit(Display *dpy, unsigned int resource)
{
register xNXEndSplitReq *req;
LockDisplay(dpy);
GetReq(NXEndSplit, req);
req -> resource = resource;
#ifdef TEST_SPLIT
fprintf(stderr, "******NXEndSplit: Sending opcode [%d] with resource [%d].\n",
X_NXStartSplit, resource);
#endif
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* This message must be sent whenever the proxy notifies
* the client of the completion of a split. If the 'pro-
* pagate' field is 0, the proxy will not send the ori-
* ginal request to the X server, but will only free the
* internal state.
*/
int NXCommitSplit(Display *dpy, unsigned int resource, unsigned int propagate,
unsigned char request, unsigned int position)
{
register xNXCommitSplitReq *req;
LockDisplay(dpy);
GetReq(NXCommitSplit, req);
req -> resource = resource;
req -> propagate = propagate;
req -> request = request;
req -> position = position;
#ifdef TEST_SPLIT
fprintf(stderr, "******NXCommitSplit: Sending opcode [%d] with resource [%d] propagate [%d] "
"request [%d] position [%d].\n", X_NXCommitSplit, resource,
propagate, request, position);
#endif
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
int NXAbortSplit(Display *dpy, unsigned int resource)
{
register xNXAbortSplitReq *req;
LockDisplay(dpy);
GetReq(NXAbortSplit, req);
#ifdef TEST_SPLIT
fprintf(stderr, "******NXAbortSplit: Sending message opcode [%d] with resource [%u].\n",
X_NXAbortSplit, resource);
#endif
req -> resource = resource;
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
int NXFinishSplit(Display *dpy, unsigned int resource)
{
register xNXFinishSplitReq *req;
LockDisplay(dpy);
GetReq(NXFinishSplit, req);
#ifdef TEST_SPLIT
fprintf(stderr, "******NXFinishSplit: Sending message opcode [%d] with resource [%u].\n",
X_NXFinishSplit, resource);
#endif
req -> resource = resource;
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
int NXFreeSplit(Display *dpy, unsigned int resource)
{
register xNXFreeSplitReq *req;
if (_NXSplitResources[resource] != 0)
{
LockDisplay(dpy);
GetReq(NXFreeSplit, req);
#ifdef TEST_SPLIT
fprintf(stderr, "******NXFreeSplit: Sending message opcode [%d] with resource [%u].\n",
X_NXFreeSplit, resource);
#endif
req -> resource = resource;
UnlockDisplay(dpy);
SyncHandle();
#ifdef TEST_SPLIT
fprintf(stderr, "******NXFreeSplit: Making the resource [%u] newly available.\n",
resource);
#endif
_NXSplitResources[resource] = 0;
}
#ifdef TEST_SPLIT
else
{
fprintf(stderr, "******NXFreeSplit: Nothing to do for resource [%u].\n",
resource);
}
#endif
return 1;
}
/*
* Tell to remote proxy to discard expose events
* of one or more types.
*/
int NXSetExposeParameters(Display *dpy, int expose, int graphics_expose, int no_expose)
{
register xNXSetExposeParametersReq *req;
LockDisplay(dpy);
GetReq(NXSetExposeParameters, req);
req -> expose = expose;
req -> graphicsExpose = graphics_expose;
req -> noExpose = no_expose;
#ifdef TEST_PARAMS
fprintf(stderr, "******NXSetExposeParameters: Sending message opcode [%d] with flags [%d][%d][%d].\n",
X_NXSetExposeParameters, req -> expose, req -> graphicsExpose, req -> noExpose);
#endif
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* Tell to the local proxy how to handle the next requests.
*/
int NXSetCacheParameters(Display *dpy, int enable_cache, int enable_split,
int enable_save, int enable_load)
{
register xNXSetCacheParametersReq *req;
LockDisplay(dpy);
GetReq(NXSetCacheParameters, req);
req -> enableCache = enable_cache;
req -> enableSplit = enable_split;
req -> enableSave = enable_save;
req -> enableLoad = enable_load;
#ifdef TEST_PARAMS
fprintf(stderr, "******NXSetCacheParameters: Sending message opcode [%d] with "
"flags [%d][%d][%d][%d].\n", X_NXSetCacheParameters, req -> enableCache,
req -> enableSplit, req -> enableSave, req -> enableLoad);
#endif
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
unsigned int NXAllocUnpack(Display *dpy, unsigned int resource)
{
if (resource == NXAnyResource)
{
for (resource = 0; resource < NXNumberOfResources; resource++)
{
if (_NXUnpackResources[resource] == 0)
{
_NXUnpackResources[resource] = 1;
#ifdef TEST_UNPACK
fprintf(stderr, "******NXAllocUnpack: Reserved resource [%u].\n",
resource);
#endif
return resource;
}
}
#ifdef TEST_UNPACK
fprintf(stderr, "******NXAllocUnpack: WARNING! Resource limit exhausted.\n");
#endif
return NXNoResource;
}
else if (resource >= 0 && resource < NXNumberOfResources)
{
#ifdef TEST_UNPACK
if (_NXUnpackResources[resource] == 0)
{
fprintf(stderr, "******NXAllocUnpack: Reserved requested resource [%u].\n",
resource);
}
else
{
fprintf(stderr, "******NXAllocUnpack: Requested resource [%u] already reserved.\n",
resource);
}
#endif
_NXUnpackResources[resource] = 1;
}
#ifdef PANIC
fprintf(stderr, "******NXAllocUnpack: PANIC! Can't reserve requested resource [%u].\n",
resource);
#endif
return NXNoResource;
}
int NXSetUnpackGeometry(Display *dpy, unsigned int resource, Visual *visual)
{
register xNXSetUnpackGeometryReq *req;
LockDisplay(dpy);
GetReq(NXSetUnpackGeometry, req);
req -> resource = resource;
req -> depth1Bpp = _XGetBitsPerPixel(dpy, 1);
req -> depth4Bpp = _XGetBitsPerPixel(dpy, 4);
req -> depth8Bpp = _XGetBitsPerPixel(dpy, 8);
req -> depth16Bpp = _XGetBitsPerPixel(dpy, 16);
req -> depth24Bpp = _XGetBitsPerPixel(dpy, 24);
req -> depth32Bpp = _XGetBitsPerPixel(dpy, 32);
if (visual != NULL)
{
req -> redMask = visual -> red_mask;
req -> greenMask = visual -> green_mask;
req -> blueMask = visual -> blue_mask;
}
else
{
#ifdef PANIC
fprintf(stderr, "******NXSetUnpackGeometry: PANIC! Can't set the geometry without a visual.\n");
#endif
UnGetReq(NXSetUnpackGeometry);
UnlockDisplay(dpy);
return -1;
}
#ifdef TEST_UNPACK
fprintf(stderr, "******NXSetUnpackGeometry: Resource [%u] Depth/Bpp [1/%d][4/%d][8/%d]"
"[16/%d][24/%d][32/%d].\n", resource, req -> depth1Bpp, req -> depth4Bpp,
req -> depth8Bpp, req -> depth16Bpp, req -> depth24Bpp, req -> depth32Bpp);
fprintf(stderr, "******NXSetUnpackGeometry: red [0x%x] green [0x%x] blue [0x%x].\n",
(unsigned) req -> redMask, (unsigned) req -> greenMask, (unsigned) req -> blueMask);
#endif
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* Store a colormap table on the remote side.
* The colormap can then be used to unpack
* an image.
*/
int NXSetUnpackColormap(Display *dpy, unsigned int resource, unsigned int method,
unsigned int entries, const char *data, unsigned int data_length)
{
register xNXSetUnpackColormapReq *req;
register int dst_data_length;
LockDisplay(dpy);
GetReq(NXSetUnpackColormap, req);
req -> resource = resource;
req -> method = method;
req -> srcLength = data_length;
req -> dstLength = entries << 2;
dst_data_length = ROUNDUP(data_length, 4);
req -> length += (dst_data_length >> 2);
#ifdef TEST_UNPACK
fprintf(stderr, "******NXSetUnpackColormap: Resource [%u] data size [%u] destination "
"data size [%u].\n", resource, data_length, dst_data_length);
#endif
if (data_length > 0)
{
if (dpy -> bufptr + dst_data_length <= dpy -> bufmax)
{
/*
* Clean the padding bytes in the request.
*/
*((int *) (dpy -> bufptr + dst_data_length - 4)) = 0x0;
memcpy(dpy -> bufptr, data, data_length);
dpy -> bufptr += dst_data_length;
}
else
{
/*
* The _XSend() will pad the request for us.
*/
_XSend(dpy, data, data_length);
}
}
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* Store data of the alpha blending channel
* that will be combined with the next image
* to be unpacked.
*/
int NXSetUnpackAlpha(Display *dpy, unsigned int resource, unsigned int method,
unsigned int entries, const char *data, unsigned int data_length)
{
register xNXSetUnpackAlphaReq *req;
register unsigned int dst_data_length;
LockDisplay(dpy);
GetReq(NXSetUnpackAlpha, req);
req -> resource = resource;
req -> method = method;
req -> srcLength = data_length;
req -> dstLength = entries;
dst_data_length = ROUNDUP(data_length, 4);
req -> length += (dst_data_length >> 2);
#ifdef TEST_UNPACK
fprintf(stderr, "******NXSetUnpackAlpha: Resource [%u] data size [%u] destination data size [%u].\n",
resource, data_length, dst_data_length);
#endif
if (data_length > 0)
{
if (dpy -> bufptr + dst_data_length <= dpy -> bufmax)
{
/*
* Clean the padding bytes in the request.
*/
*((int *) (dpy -> bufptr + dst_data_length - 4)) = 0x0;
memcpy(dpy -> bufptr, data, data_length);
dpy -> bufptr += dst_data_length;
}
else
{
/*
* The _XSend() will pad the request for us.
*/
_XSend(dpy, data, data_length);
}
}
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* Compatibility versions to be used when
* connected to a 1.X.X proxy.
*/
/*
* These are for compatibility with the 1.X.X
* versions.
*/
#define sz_xNXSetUnpackColormapCompatReq 8
typedef struct _NXSetUnpackColormapCompatReq {
CARD8 reqType;
CARD8 resource;
CARD16 length B16;
CARD32 entries B32;
} xNXSetUnpackColormapCompatReq;
#define X_NXSetUnpackColormapCompat X_NXSetUnpackColormap
int NXSetUnpackColormapCompat(Display *dpy, unsigned int resource,
unsigned int entries, const char *data)
{
register xNXSetUnpackColormapCompatReq *req;
register char *dst_data;
register int dst_data_length;
LockDisplay(dpy);
GetReq(NXSetUnpackColormapCompat, req);
req -> resource = resource;
req -> entries = entries;
dst_data_length = entries << 2;
req -> length += (dst_data_length >> 2);
#ifdef TEST_UNPACK
fprintf(stderr, "******NXSetUnpackColormapCompat: Resource [%u] number of entries [%u] "
"destination data size [%u].\n", resource, entries, dst_data_length);
#endif
if (entries > 0)
{
if ((dpy -> bufptr + dst_data_length) <= dpy -> bufmax)
{
dst_data = dpy -> bufptr;
}
else
{
if ((dst_data = _XAllocScratch(dpy, dst_data_length)) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXSetUnpackColormapCompat: PANIC! Cannot allocate memory.\n");
#endif
UnGetReq(NXSetUnpackColormapCompat);
UnlockDisplay(dpy);
return -1;
}
}
memcpy(dst_data, data, entries << 2);
#ifdef DUMP
fprintf(stderr, "******NXSetUnpackColormapCompat: Dumping colormap entries:\n");
for (int i = 0; i < entries; i++)
{
fprintf(stderr, "******NXSetUnpackColormapCompat: [%d] -> [0x%x].\n",
i, *((int *) (dst_data + (i * 4))));
}
#endif
if (dst_data == dpy -> bufptr)
{
dpy -> bufptr += dst_data_length;
}
else
{
_XSend(dpy, dst_data, dst_data_length);
}
}
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
#define sz_xNXSetUnpackAlphaCompatReq 8
typedef struct _NXSetUnpackAlphaCompatReq {
CARD8 reqType;
CARD8 resource;
CARD16 length B16;
CARD32 entries B32;
} xNXSetUnpackAlphaCompatReq;
#define X_NXSetUnpackAlphaCompat X_NXSetUnpackAlpha
int NXSetUnpackAlphaCompat(Display *dpy, unsigned int resource,
unsigned int entries, const char *data)
{
register xNXSetUnpackAlphaCompatReq *req;
register char *dst_data;
register unsigned int dst_data_length;
LockDisplay(dpy);
GetReq(NXSetUnpackAlphaCompat, req);
req -> resource = resource;
req -> entries = entries;
dst_data_length = ROUNDUP(entries, 4);
req -> length += (dst_data_length >> 2);
#ifdef TEST_UNPACK
fprintf(stderr, "******NXSetUnpackAlphaCompat: Resource [%u] number of entries [%u] "
"destination data size [%u].\n", resource, entries, dst_data_length);
#endif
if (entries > 0)
{
if ((dpy -> bufptr + dst_data_length) <= dpy -> bufmax)
{
dst_data = dpy -> bufptr;
}
else
{
if ((dst_data = _XAllocScratch(dpy, dst_data_length)) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXSetUnpackAlphaCompat: PANIC! Cannot allocate memory.\n");
#endif
UnGetReq(NXSetUnpackAlphaCompat);
UnlockDisplay(dpy);
return -1;
}
}
memcpy(dst_data, data, entries);
if (dst_data_length != entries)
{
memset(dst_data + entries, 0, dst_data_length - entries);
}
#ifdef DUMP
fprintf(stderr, "******NXSetUnpackAlphaCompat: Dumping alpha channel data:\n");
for (int i = 0; i < dst_data_length; i++)
{
fprintf(stderr, "******NXSetUnpackAlphaCompat: [%d] -> [0x%02x].\n",
i, ((unsigned int) *(dst_data + i)) & 0xff);
}
#endif
if (dst_data == dpy -> bufptr)
{
dpy -> bufptr += dst_data_length;
}
else
{
_XSend(dpy, dst_data, dst_data_length);
}
}
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
/*
* Free any geometry, colormap and alpha channel
* data stored by the remote proxy to unpack the
* image. Resource, as usual, must be a value
* between 0 and 255.
*/
int NXFreeUnpack(Display *dpy, unsigned int resource)
{
register xNXFreeUnpackReq *req;
if (_NXUnpackResources[resource] != 0)
{
LockDisplay(dpy);
GetReq(NXFreeUnpack, req);
#ifdef TEST_UNPACK
fprintf(stderr, "******NXFreeUnpack: Sending message opcode [%d] with resource [%u].\n",
X_NXFreeUnpack, resource);
#endif
req -> resource = resource;
UnlockDisplay(dpy);
SyncHandle();
#ifdef TEST_UNPACK
fprintf(stderr, "******NXFreeUnpack: Making the resource [%u] newly available.\n",
resource);
#endif
_NXUnpackResources[resource] = 0;
}
#ifdef TEST_UNPACK
else
{
fprintf(stderr, "******NXFreeUnpack: Nothing to do for resource [%u].\n",
resource);
}
#endif
return 1;
}
/*
* Wrapper of XCreateImage(). Note that we use offset
* field of XImage to store size of source image in
* packed format. Note also that method is currently
* not stored in the NXignored.
*/
NXPackedImage *NXCreatePackedImage(Display *dpy, Visual *visual, unsigned int method,
unsigned int depth, int format, char *data,
int data_length, unsigned int width,
unsigned int height, int bitmap_pad,
int bytes_per_line)
{
XImage* image;
image = XCreateImage(dpy, visual, depth, format, 0, data,
width, height, bitmap_pad, bytes_per_line);
if (image != NULL)
{
image -> xoffset = data_length;
}
return (NXPackedImage *) image;
}
/*
* Wrapper of XDestroyImage().
*/
int NXDestroyPackedImage(NXPackedImage *image)
{
return XDestroyImage((XImage *) image);
}
/*
* Clean the image data directly in the current buffer.
*/
int NXCleanImage(XImage *image)
{
#ifdef TEST_IMAGE
fprintf(stderr, "******NXCleanImage: Cleaning image with format [%d] depth [%d] "
"bits per pixel [%d].\n", image -> format, image -> depth,
image -> bits_per_pixel);
#endif
if (image -> format == ZPixmap)
{
if (image -> depth == 1)
{
return CleanXYImage(image);
}
else
{
return CleanZImage(image);
}
}
else
{
return CleanXYImage(image);
}
}
NXPackedImage *NXPackImage(Display *dpy, XImage *src_image, unsigned int method)
{
XImage *dst_image;
const ColorMask *mask;
unsigned int dst_data_size;
unsigned int dst_packed_data_size;
unsigned int dst_bits_per_pixel;
unsigned int dst_packed_bits_per_pixel;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXPackImage: Going to pack a new image with method [%d].\n",
method);
#endif
/*
* Get the mask out of the method and
* check if the visual is supported by
* the color reduction algorithm.
*/
mask = MethodColorMask(method);
if (mask == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXPackImage: WARNING! No mask to apply for pack method [%d].\n",
method);
#endif
return NULL;
}
else if (CanMaskImage(src_image, mask) == 0)
{
#ifdef PANIC
fprintf(stderr, "******NXPackImage: PANIC! Invalid source with format [%d] depth [%d] bits per pixel [%d].\n",
src_image -> format, src_image -> depth, src_image -> bits_per_pixel);
fprintf(stderr, "******NXPackImage: PANIC! Visual colormask is red 0x%lx green 0x%lx blue 0x%lx.\n",
src_image -> red_mask, src_image -> green_mask, src_image -> blue_mask);
#endif
return NULL;
}
/*
* Create a destination image from
* source and apply the color mask.
*/
if ((dst_image = (XImage *) malloc(sizeof(XImage))) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXPackImage: PANIC! Cannot allocate [%d] bytes for the image.\n",
(int) sizeof(XImage));
#endif
return NULL;
}
*dst_image = *src_image;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXPackImage: Source width [%d], bytes per line [%d] with depth [%d].\n",
src_image -> width, src_image -> bytes_per_line, src_image -> depth);
#endif
dst_data_size = src_image -> bytes_per_line * src_image -> height;
dst_image -> data = malloc(dst_data_size);
if (dst_image -> data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXPackImage: PANIC! Cannot allocate [%d] bytes for masked image data.\n",
dst_data_size);
#endif
SAFE_free(dst_image);
return NULL;
}
/*
* If the pixel resulting from the mask
* needs more bits than available, then
* just clean the padding bits in the
* image.
*/
dst_bits_per_pixel = dst_image -> bits_per_pixel;
dst_packed_bits_per_pixel = MethodBitsPerPixel(method);
#ifdef TEST_IMAGE
fprintf(stderr, "******NXPackImage: Destination depth [%d], bits per pixel [%d], packed bits per pixel [%d].\n",
dst_image -> depth, dst_bits_per_pixel, dst_packed_bits_per_pixel);
#endif
if (dst_packed_bits_per_pixel > dst_bits_per_pixel ||
ShouldMaskImage(src_image, mask) == 0)
{
/*
* Should use the same data for source
* and destination to avoid the memcpy.
*/
if (CopyAndCleanImage(src_image, dst_image) <= 0)
{
#ifdef PANIC
fprintf(stderr, "******NXPackImage: PANIC! Failed to clean the image.\n");
#endif
SAFE_free(dst_image -> data);
SAFE_free(dst_image);
return NULL;
}
}
else if (MaskImage(mask, src_image, dst_image) <= 0)
{
#ifdef PANIC
fprintf(stderr, "******NXPackImage: PANIC! Failed to apply the color mask.\n");
#endif
SAFE_free(dst_image -> data);
SAFE_free(dst_image);
return NULL;
}
/*
* Let's pack the same pixels in fewer bytes.
* Note that we save a new memory allocation
* by using the same image as source and des-
* tination. This means that PackImage() must
* be able to handle ovelapping areas.
*/
#ifdef TEST_IMAGE
fprintf(stderr, "******NXPackImage: Plain bits per pixel [%d], data size [%d].\n",
dst_bits_per_pixel, dst_data_size);
#endif
dst_packed_data_size = dst_data_size * dst_packed_bits_per_pixel /
dst_bits_per_pixel;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXPackImage: Packed bits per pixel [%d], data size [%d].\n",
dst_packed_bits_per_pixel, dst_packed_data_size);
#endif
if (PackImage(method, dst_data_size, dst_image,
dst_packed_data_size, dst_image) <= 0)
{
#ifdef PANIC
fprintf(stderr, "******NXPackImage: PANIC! Failed to pack image from [%d] to [%d] bits per pixel.\n",
dst_bits_per_pixel, dst_packed_bits_per_pixel);
#endif
SAFE_free(dst_image -> data);
SAFE_free(dst_image);
return NULL;
}
/*
* Save data size in xoffset field
* to comply with NX packed images.
*/
dst_image -> xoffset = dst_packed_data_size;
return dst_image;
}
/*
* NXInPlacePackImage creates a NXPackedImage
* from a XImage, sharing the same data buffer.
* Is up to the caller to free the data buffer
* only once.
*/
XImage *NXInPlacePackImage(Display *dpy, XImage *src_image, unsigned int method)
{
XImage *dst_image;
const ColorMask *mask;
unsigned int dst_data_size;
unsigned int dst_packed_data_size;
unsigned int dst_bits_per_pixel;
unsigned int dst_packed_bits_per_pixel;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXInPlacePackImage: Going to pack a new image with method [%d].\n",
method);
#endif
/*
* Get mask out of method and check if
* visual is supported by current color
* reduction algorithm.
*/
mask = MethodColorMask(method);
if (mask == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXInPlacePackImage: WARNING! No mask to apply for pack method [%d].\n",
method);
#endif
return NULL;
}
else if (CanMaskImage(src_image, mask) == 0)
{
#ifdef PANIC
fprintf(stderr, "******NXInPlacePackImage: PANIC! Invalid source with format [%d] depth [%d] bits per pixel [%d].\n",
src_image -> format, src_image -> depth, src_image -> bits_per_pixel);
fprintf(stderr, "******NXInPlacePackImage: PANIC! Visual colormask is red 0x%lx green 0x%lx blue 0x%lx.\n",
src_image -> red_mask, src_image -> green_mask, src_image -> blue_mask);
#endif
return NULL;
}
/*
* Create a destination image from
* source and apply the color mask.
*/
if ((dst_image = (XImage *) malloc(sizeof(XImage))) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXInPlacePackImage: PANIC! Cannot allocate [%d] bytes for the image.\n",
(int) sizeof(XImage));
#endif
return NULL;
}
*dst_image = *src_image;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXInPlacePackImage: Source width [%d], bytes per line [%d] with depth [%d].\n",
src_image -> width, src_image -> bytes_per_line, src_image -> depth);
#endif
dst_data_size = src_image -> bytes_per_line * src_image -> height;
dst_image -> data = src_image -> data;
/*
* If pixel resulting from mask needs
* more bits than available, then just
* clean the pad bits in image.
*/
dst_bits_per_pixel = dst_image -> bits_per_pixel;
dst_packed_bits_per_pixel = MethodBitsPerPixel(method);
#ifdef TEST_IMAGE
fprintf(stderr, "******NXInPlacePackImage: Destination depth [%d], bits per pixel [%d], packed bits per pixel [%d].\n",
dst_image -> depth, dst_bits_per_pixel, dst_packed_bits_per_pixel);
#endif
if (dst_packed_bits_per_pixel > dst_bits_per_pixel ||
ShouldMaskImage(src_image, mask) == 0)
{
#ifdef TEST_IMAGE
fprintf(stderr, "******NXInPlacePackImage: Just clean image packed_bits_per_pixel[%d], bits_per_pixel[%d].\n",
dst_packed_bits_per_pixel, dst_bits_per_pixel);
#endif
if (NXCleanImage(dst_image) <= 0)
{
#ifdef PANIC
fprintf(stderr, "******NXInPlacePackImage: PANIC! Failed to clean the image.\n");
#endif
SAFE_free(dst_image);
return NULL;
}
}
else if (MaskInPlaceImage(mask, dst_image) <= 0)
{
#ifdef PANIC
fprintf(stderr, "******NXInPlacePackImage: PANIC! Failed to apply the color mask.\n");
#endif
SAFE_free(dst_image);
return NULL;
}
/*
* Let's pack the same pixels in fewer bytes.
* Note that we save a new memory allocation
* by using the same image as source and des-
* tination. This means that PackImage() must
* be able to handle ovelapping areas.
*/
#ifdef TEST_IMAGE
fprintf(stderr, "******NXInPlacePackImage: Plain bits per pixel [%d], data size [%d].\n",
dst_bits_per_pixel, dst_data_size);
#endif
dst_packed_data_size = dst_data_size * dst_packed_bits_per_pixel /
dst_bits_per_pixel;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXInPlacePackImage: Packed bits per pixel [%d], data size [%d].\n",
dst_packed_bits_per_pixel, dst_packed_data_size);
#endif
/*
* Save data size in xoffset field
* to comply with NX packed images.
*/
dst_image -> xoffset = dst_packed_data_size;
return dst_image;
}
int NXPutPackedImage(Display *dpy, unsigned int resource, Drawable drawable,
void *gc, NXPackedImage *image, unsigned int method,
unsigned int depth, int src_x, int src_y, int dst_x,
int dst_y, unsigned int width, unsigned int height)
{
register xNXPutPackedImageReq *req;
register unsigned int src_data_length;
register unsigned int dst_data_length;
LockDisplay(dpy);
FlushGC(dpy, (GC) gc);
GetReq(NXPutPackedImage, req);
req -> resource = resource;
req -> drawable = drawable;
req -> gc = ((GC) gc) -> gid;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXPutPackedImage: Image resource [%d] drawable [%d] gc [%d].\n",
req -> resource, (int) req -> drawable, (int) req -> gc);
#endif
/*
* There is no leftPad field in request. We only
* support a leftPad of 0. Anyway, X imposes a
* leftPad of 0 in case of ZPixmap format.
*/
req -> format = image -> format;
/*
* Source depth, as well as width and height,
* are taken from the image structure.
*/
req -> srcDepth = image -> depth;
req -> srcX = src_x;
req -> srcY = src_y;
req -> srcWidth = image -> width;
req -> srcHeight = image -> height;
/*
* The destination depth is provided
* by the caller.
*/
req -> dstDepth = depth;
req -> dstX = dst_x;
req -> dstY = dst_y;
req -> dstWidth = width;
req -> dstHeight = height;
req -> method = method;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXPutPackedImage: Source image depth [%d] destination depth [%d] "
"method [%d].\n", req -> srcDepth, req -> dstDepth, req -> method);
#endif
/*
* Source data length is the size of image in packed format,
* as stored in xoffset field of XImage. Destination data
* size is calculated according to bytes per line of target
* image, so the caller must provide the right depth at the
* time XImage structure is created.
*/
req -> srcLength = image -> xoffset;
if (image -> width == (int) width &&
image -> height == (int) height)
{
req -> dstLength = image -> bytes_per_line * image -> height;
}
else if (image -> format == ZPixmap)
{
req -> dstLength = ROUNDUP((image -> bits_per_pixel * width),
image -> bitmap_pad) * height >> 3;
}
else
{
req -> dstLength = ROUNDUP(width, image -> bitmap_pad) * height >> 3;
}
src_data_length = image -> xoffset;
dst_data_length = ROUNDUP(src_data_length, 4);
#ifdef TEST_IMAGE
fprintf(stderr, "******NXPutPackedImage: Source data length [%d] request data length [%d].\n",
src_data_length, dst_data_length);
#endif
req -> length += (dst_data_length >> 2);
if (src_data_length > 0)
{
if (dpy -> bufptr + dst_data_length <= dpy -> bufmax)
{
/*
* Clean the padding bytes in the request.
*/
*((int *) (dpy -> bufptr + dst_data_length - 4)) = 0x0;
memcpy(dpy -> bufptr, image -> data, src_data_length);
dpy -> bufptr += dst_data_length;
}
else
{
/*
* The _XSend() will pad the request for us.
*/
_XSend(dpy, image -> data, src_data_length);
}
}
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
int NXAllocColors(Display *dpy, Colormap colormap, unsigned int entries,
XColor screens_in_out[], Bool results_in_out[])
{
Status result = 0;
xAllocColorReply rep;
register xAllocColorReq *req;
Bool alloc_error = False;
LockDisplay(dpy);
for (unsigned int i = 0; i < entries; i++)
{
GetReq(AllocColor, req);
req -> cmap = colormap;
req -> red = screens_in_out[i].red;
req -> green = screens_in_out[i].green;
req -> blue = screens_in_out[i].blue;
}
for (unsigned int i = 0; i < entries; i++)
{
result = _XReply(dpy, (xReply *) &rep, 0, xTrue);
if (result)
{
screens_in_out[i].pixel = rep.pixel;
screens_in_out[i].red = rep.red;
screens_in_out[i].green = rep.green;
screens_in_out[i].blue = rep.blue;
results_in_out[i] = True;
}
else
{
results_in_out[i] = False;
alloc_error = True;
}
}
UnlockDisplay(dpy);
SyncHandle();
return (alloc_error == False);
}
char *NXEncodeColormap(const char *src_data, unsigned int src_size, unsigned int *dst_size)
{
return ColormapCompressData(src_data, src_size, dst_size);
}
char *NXEncodeAlpha(const char *src_data, unsigned int src_size, unsigned int *dst_size)
{
return AlphaCompressData(src_data, src_size, dst_size);
}
NXPackedImage *NXEncodeRgb(XImage *src_image, unsigned int method, unsigned int quality)
{
NXPackedImage *dst_image = NULL;
unsigned int dst_size;
/*
* Create a new image structure as a copy
* of the source.
*/
if ((dst_image = (NXPackedImage *) malloc(sizeof(NXPackedImage))) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeRgb: PANIC! Cannot allocate [%d] bytes for the image.\n",
(int) sizeof(XImage));
#endif
return NULL;
}
*dst_image = *src_image;
dst_image -> data = RgbCompressData(src_image, &dst_size);
if (dst_image -> data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeRgb: PANIC! Rgb compression failed.\n");
#endif
SAFE_free(dst_image);
return NULL;
}
/*
* Store the Rgb size in the xoffset field.
*/
dst_image -> xoffset = dst_size;
return dst_image;
}
NXPackedImage *NXEncodeRle(XImage *src_image, unsigned int method, unsigned int quality)
{
NXPackedImage *dst_image = NULL;
unsigned int dst_size;
/*
* Create a new image structure as a copy
* of the source.
*/
if ((dst_image = (NXPackedImage *) malloc(sizeof(NXPackedImage))) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeRle: PANIC! Cannot allocate [%d] bytes for the image.\n",
(int) sizeof(XImage));
#endif
return NULL;
}
*dst_image = *src_image;
dst_image -> data = RleCompressData(src_image, &dst_size);
if (dst_image -> data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeRle: PANIC! Rle compression failed.\n");
#endif
SAFE_free(dst_image);
return NULL;
}
/*
* Store the Rle size in the xoffset field.
*/
dst_image -> xoffset = dst_size;
return dst_image;
}
NXPackedImage *NXEncodeBitmap(XImage *src_image, unsigned int method, unsigned int quality)
{
NXPackedImage *dst_image = NULL;
unsigned int dst_size;
/*
* Create a new image structure as a copy
* of the source.
*/
if ((dst_image = (NXPackedImage *) malloc(sizeof(NXPackedImage))) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeBitmap: PANIC! Cannot allocate [%d] bytes for the image.\n",
(int) sizeof(XImage));
#endif
return NULL;
}
*dst_image = *src_image;
dst_image -> data = BitmapCompressData(src_image, &dst_size);
if (dst_image -> data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeBitmap: PANIC! Bitmap compression failed.\n");
#endif
SAFE_free(dst_image);
return NULL;
}
/*
* Store the bitmap size in the xoffset field.
*/
dst_image -> xoffset = dst_size;
return dst_image;
}
NXPackedImage *NXEncodeJpeg(XImage *src_image, unsigned int method, unsigned int quality)
{
NXPackedImage *dst_image = NULL;
int size;
/*
* Check if the bpp of the image is valid
* for the Jpeg compression.
*/
if (src_image -> bits_per_pixel < 15)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeJpeg: PANIC! Invalid bpp for Jpeg compression [%d]\n.",
src_image -> bits_per_pixel);
#endif
return NULL;
}
/*
* Create the destination image as a copy
* of the source.
*/
if ((dst_image = (NXPackedImage *) malloc(sizeof(NXPackedImage))) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeJpeg: PANIC! Cannot allocate [%d] bytes for the Jpeg image.\n",
(int) sizeof(NXPackedImage));
#endif
return NULL;
}
*dst_image = *src_image;
dst_image -> data = JpegCompressData(src_image, quality, &size);
if (dst_image -> data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodeJpeg: PANIC! Jpeg compression failed.\n");
#endif
SAFE_free(dst_image);
return NULL;
}
/*
* Store the Jpeg size in the xoffset field.
*/
dst_image -> xoffset = size;
return dst_image;
}
NXPackedImage *NXEncodePng(XImage *src_image, unsigned int method, unsigned int quality)
{
NXPackedImage *dst_image = NULL;
int size;
/*
* Check if the bpp of the image is valid
* for png compression.
*/
if (src_image -> bits_per_pixel < 15)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodePng: PANIC! Invalid bpp for Png compression [%d].\n",
src_image -> bits_per_pixel);
#endif
return NULL;
}
if ((dst_image = (NXPackedImage *) malloc(sizeof(NXPackedImage))) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodePng: PANIC! Cannot allocate [%d] bytes for the Png image.\n",
(int) sizeof(NXPackedImage));
#endif
return NULL;
}
*dst_image = *src_image;
dst_image -> data = PngCompressData(dst_image, &size);
if (dst_image -> data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXEncodePng: PANIC! Png compression failed.\n");
#endif
SAFE_free(dst_image);
return NULL;
}
/*
* Store the Png size in the xoffset field.
*/
dst_image -> xoffset = size;
return dst_image;
}
int NXEncodeColors(XImage *src_image, NXColorTable *color_table, int nb_max)
{
int x, y, t, p;
long pixel;
/*
* We need a smarter way to extract
* the colors from the image and
* create a color table.
*/
memset(color_table, 0, nb_max * sizeof(NXColorTable));
for (x = 0, p = 0; x < src_image -> width; x++)
{
for (y = 0; y < src_image -> height; y++)
{
pixel = XGetPixel(src_image, x, y);
for (t = 0; t < nb_max; t++)
{
if ( color_table[t].found == 0)
{
color_table[t].pixel = pixel;
color_table[t].found = 1;
p++;
break;
}
else if ((color_table[t].pixel) == pixel)
{
break;
}
}
if (p == nb_max)
{
return nb_max + 1;
}
}
}
return p;
}
void NXMaskImage(XImage *image, unsigned int method)
{
unsigned int maskMethod;
const ColorMask *mask;
/*
* Choose the correct mask method
*/
switch(method)
{
case PACK_JPEG_8_COLORS:
case PACK_PNG_8_COLORS:
{
maskMethod = MASK_8_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_8_COLORS\n");
#endif
break;
}
case PACK_JPEG_64_COLORS:
case PACK_PNG_64_COLORS:
{
maskMethod = MASK_64_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_64K_COLORS\n");
#endif
break;
}
case PACK_JPEG_256_COLORS:
case PACK_PNG_256_COLORS:
{
maskMethod = MASK_256_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_256_COLORS\n");
#endif
break;
}
case PACK_JPEG_512_COLORS:
case PACK_PNG_512_COLORS:
{
maskMethod = MASK_512_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_512K_COLORS\n");
#endif
break;
}
case PACK_JPEG_4K_COLORS:
case PACK_PNG_4K_COLORS:
{
maskMethod = MASK_4K_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_4K_COLORS\n");
#endif
break;
}
case PACK_JPEG_32K_COLORS:
case PACK_PNG_32K_COLORS:
{
maskMethod = MASK_32K_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_32K_COLORS\n");
#endif
break;
}
case PACK_JPEG_64K_COLORS:
case PACK_PNG_64K_COLORS:
{
maskMethod = MASK_64K_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_64K_COLORS\n");
#endif
break;
}
case PACK_JPEG_256K_COLORS:
case PACK_PNG_256K_COLORS:
{
maskMethod = MASK_256K_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_256K_COLORS\n");
#endif
break;
}
case PACK_JPEG_2M_COLORS:
case PACK_PNG_2M_COLORS:
{
maskMethod = MASK_2M_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_2M_COLORS\n");
#endif
break;
}
case PACK_JPEG_16M_COLORS:
case PACK_PNG_16M_COLORS:
{
maskMethod = MASK_16M_COLORS;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXMaskImage: Method is MASK_16M_COLORS\n");
#endif
break;
}
default:
{
#ifdef PANIC
fprintf(stderr, "******NXMaskImage: PANIC! Cannot find mask method for pack method [%d]\n",
method);
#endif
return;
}
}
#ifdef TEST_IMAGE
fprintf(stderr, "******NXMaskImage: packMethod[%d] => maskMethod[%d]\n",
method, maskMethod);
#endif
/*
* Get mask out of method and check if
* visual is supported by current color
* reduction algorithm.
*/
mask = MethodColorMask(maskMethod);
if (mask == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXMaskImage: PANIC! No mask to apply for pack method [%d].\n",
method);
#endif
return;
}
else if (CanMaskImage(image, mask) == 0)
{
#ifdef PANIC
fprintf(stderr, "******NXMaskImage: PANIC! Invalid source with format [%d] depth [%d] bits per pixel [%d].\n",
image -> format, image -> depth, image -> bits_per_pixel);
fprintf(stderr, "******NXMaskImage: PANIC! Visual colormask is red 0x%lx green 0x%lx blue 0x%lx.\n",
image -> red_mask, image -> green_mask, image -> blue_mask);
#endif
return;
}
/*
* Calling ShouldMaskImage you get 0 in the case
* of MASK_256_COLORS and MASK_64K_COLORS, which
* means that the image should not be masked.
*/
if (ShouldMaskImage(image, mask) == 0)
{
#ifdef TEST_IMAGE
fprintf(stderr, "******NXMaskImage: the image will not be masked\n");
#endif
}
else
{
if (MaskInPlaceImage(mask, image) <= 0)
{
#ifdef PANIC
fprintf(stderr, "******NXMaskImage: PANIC! Failed to apply the color mask in place.\n");
#endif
}
}
}
/*
* The display parameter is ignored.
*/
void NXInitCache(Display *dpy, int entries)
{
if (NXImageCache != NULL && NXImageCacheSize == entries)
{
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXInitCache: Nothing to do with image cache at [%p] and [%d] entries.\n",
NXImageCache, NXImageCacheSize);
#endif
return;
}
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXInitCache: Initializing the cache with [%d] entries.\n",
entries);
#endif
NXImageCacheSize = 0;
SAFE_free(NXImageCache);
if (entries > 0)
{
NXImageCache = malloc(entries * sizeof(_NXImageCacheEntry));
if (NXImageCache != NULL)
{
memset(NXImageCache, 0, entries * sizeof(_NXImageCacheEntry));
NXImageCacheSize = entries;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXInitCache: Image cache initialized with [%d] entries.\n", entries);
#endif
}
}
}
#ifdef DUMP
void _NXCacheDump(const char *label)
{
char s[MD5_LENGTH * 2 + 1];
#ifdef DEBUG_IMAGE
fprintf(stderr, "%s: Dumping the content of image cache:\n", label);
#endif
for (int i = 0; i < NXImageCacheSize; i++)
{
if (NXImageCache[i].image == NULL)
{
break;
}
for (int j = 0; j < MD5_LENGTH; j++)
{
sprintf(s + (j * 2), "%02X", ((unsigned char *) NXImageCache[i].md5)[j]);
}
#ifdef DEBUG_IMAGE
fprintf(stderr, "%s: [%d][%s].\n", label, i, s);
#endif
}
}
#endif
XImage *NXCacheFindImage(NXPackedImage *src_image, unsigned int *method, unsigned char **md5)
{
md5_state_t new_state;
md5_byte_t *new_md5;
unsigned int data_size;
if (NXImageCache == NULL)
{
return NULL;
}
/*
* Will return the allocated checksum
* if the image is not found.
*/
*md5 = NULL;
if ((new_md5 = malloc(MD5_LENGTH)) == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCacheFindImage: Can't allocate memory for the checksum.\n");
#endif
return NULL;
}
data_size = (src_image -> bytes_per_line * src_image -> height);
md5_init(&new_state);
md5_append(&new_state, (unsigned char *) &src_image -> width, sizeof(int));
md5_append(&new_state, (unsigned char *) &src_image -> height, sizeof(int));
md5_append(&new_state, (unsigned char *) src_image -> data, data_size);
md5_finish(&new_state, new_md5);
for (unsigned int i = 0; i < NXImageCacheSize; i++)
{
if (NXImageCache[i].image != NULL)
{
if (memcmp(NXImageCache[i].md5, new_md5, MD5_LENGTH) == 0)
{
_NXImageCacheEntry found;
found.image = NXImageCache[i].image;
found.method = NXImageCache[i].method;
found.md5 = NXImageCache[i].md5;
*method = found.method;
NXImageCacheHits++;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXCacheFindImage: Found at position [%d] with hits [%d] and [%d] packs.\n",
i, NXImageCacheHits, NXImageCacheOps);
#endif
SAFE_free(new_md5);
/*
* Move the images down one slot, from
* the head of the list, and place the
* image just found at top.
*/
if (i > 16)
{
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXCacheFindImage: Moving the image at the head of the list.\n");
#endif
memmove(&NXImageCache[1], &NXImageCache[0], (i * sizeof(_NXImageCacheEntry)));
NXImageCache[0].image = found.image;
NXImageCache[0].method = found.method;
NXImageCache[0].md5 = found.md5;
#ifdef DUMP
_NXCacheDump("******NXCacheFindImage");
#endif
}
/*
* Return the checksum and image
* structure allocated in cache.
*/
*md5 = found.md5;
return found.image;
}
}
else
{
break;
}
}
*md5 = new_md5;
return NULL;
}
/*
* Add a packed image to the cache. A new image
* structure is allocated and copied, data and
* checksum are inherited from the passed image.
*/
int NXCacheAddImage(NXPackedImage *image, unsigned int method, unsigned char *md5)
{
unsigned int i;
if (image == NULL || image -> data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCacheAddImage: PANIC! Invalid image passed to function.\n");
#endif
return -1;
}
i = (NXImageCacheOps < NXImageCacheSize) ? NXImageCacheOps : NXImageCacheSize;
if (NXImageCacheOps >= NXImageCacheSize)
{
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXCacheAddImage: Freeing up the oldest entry.\n");
#endif
i--;
SAFE_free(NXImageCache[NXImageCacheSize - 1].image -> data);
SAFE_free(NXImageCache[NXImageCacheSize - 1].image);
SAFE_free(NXImageCache[NXImageCacheSize - 1].md5);
}
if (i > 0)
{
memmove(&NXImageCache[1], &NXImageCache[0], i * sizeof(_NXImageCacheEntry));
}
NXImageCacheOps++;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXCacheAddImage: Going to add new image with data size [%d].\n",
image -> xoffset);
#endif
NXImageCache[0].image = image;
NXImageCache[0].method = method;
NXImageCache[0].md5 = md5;
#ifdef DUMP
_NXCacheDump("******NXCacheAddImage");
#endif
return 1;
}
/*
* The display parameter is ignored.
*/
void NXFreeCache(Display *dpy)
{
if (NXImageCache == NULL)
{
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXFreeCache: Nothing to do with a null image cache.\n");
#endif
return;
}
#ifdef DEBUG_IMAGE
fprintf(stderr, "******NXFreeCache: Freeing the cache with [%d] entries.\n",
NXImageCacheSize);
#endif
for (int i = 0; i < NXImageCacheSize; i++)
{
if (NXImageCache[i].image != NULL)
{
SAFE_free(NXImageCache[i].image -> data);
SAFE_free(NXImageCache[i].image);
}
SAFE_free(NXImageCache[i].md5);
}
SAFE_free(NXImageCache);
NXImageCacheSize = 0;
NXImageCacheHits = 0;
NXImageCacheOps = 0;
}
static void _NXNotifyImage(Display *dpy, int resource, Bool success)
{
XEvent async_event;
/*
* Enqueue an event to tell client
* the result of GetImage.
*/
async_event.type = ClientMessage;
async_event.xclient.serial = _NXCollectedImages[resource] -> sequence;
async_event.xclient.window = 0;
async_event.xclient.message_type = 0;
async_event.xclient.format = 32;
async_event.xclient.data.l[0] = NXCollectImageNotify;
async_event.xclient.data.l[1] = resource;
async_event.xclient.data.l[2] = success;
XPutBackEvent(dpy, &async_event);
}
static Bool _NXCollectImageHandler(Display *dpy, xReply *rep, char *buf,
int len, XPointer data)
{
register _NXCollectImageState *state;
register xGetImageReply *async_rep;
char *async_head;
char *async_data;
int async_size;
state = (_NXCollectImageState *) data;
#ifdef DEBUG_IMAGE
fprintf(stderr, "******%s: sequence: received [%hu] expected [%lu] 16bit received [%hu] expected [%hu]\n",
__func__,
rep -> generic.sequenceNumber, state -> sequence,
rep -> generic.sequenceNumber % 65536, (CARD16)(state -> sequence) % 65536);
#endif
if ((rep -> generic.sequenceNumber % 65536) !=
((CARD16)(state -> sequence) % 65536))
{
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXCollectImageHandler: Unmatched sequence [%d] of type [%d] "
"with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type,
(int) rep -> generic.length << 2);
#endif
return False;
}
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXCollectImageHandler: Going to handle asynchronous GetImage reply.\n");
#endif
/*
* As even reply data is managed asynchronously,
* we can use state to get to vector and vector
* to get to handler. In this way, we can safely
* dequeue and free the handler itself.
*/
DeqAsyncHandler(dpy, state -> handler);
SAFE_free(state -> handler);
if (rep -> generic.type == X_Error)
{
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXCollectImageHandler: Error received from X server for resource [%d].\n",
state -> resource);
#endif
_NXNotifyImage(dpy, state -> resource, False);
_NXCollectedImages[state -> resource] = NULL;
SAFE_free(state);
return False;
}
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXCollectImageHandler: Matched request with sequence [%ld].\n",
state -> sequence);
#endif
async_size = SIZEOF(xGetImageReply);
async_head = malloc(async_size);
if (async_head == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectImageHandler: PANIC! Failed to allocate memory with resource [%d].\n",
state -> resource);
#endif
_NXNotifyImage(dpy, state -> resource, False);
_NXCollectedImages[state -> resource] = NULL;
SAFE_free(state);
return False;
}
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXCollectImageHandler: Going to get reply with size [%d].\n",
(int) rep -> generic.length << 2);
#endif
async_rep = (xGetImageReply *) _XGetAsyncReply(dpy, async_head, rep, buf, len, 0, False);
if (async_rep == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectImageHandler: PANIC! Failed to get reply with resource [%d].\n",
state -> resource);
#endif
_NXNotifyImage(dpy, state -> resource, False);
_NXCollectedImages[state -> resource] = NULL;
SAFE_free(state);
SAFE_free(async_head);
return False;
}
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXCollectImageHandler: Got reply with depth [%d] visual [%d] size [%d].\n",
async_rep -> depth, (int) async_rep -> visual, (int) async_rep -> length << 2);
#endif
async_size = async_rep -> length << 2;
if (async_size > 0)
{
async_data = malloc(async_size);
if (async_data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectImageHandler: PANIC! Failed to allocate memory with resource [%d].\n",
state -> resource);
#endif
_NXNotifyImage(dpy, state -> resource, False);
_NXCollectedImages[state -> resource] = NULL;
SAFE_free(state);
SAFE_free(async_head);
return False;
}
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXCollectImageHandler: Going to get data with size [%d].\n",
async_size);
#endif
_XGetAsyncData(dpy, async_data, buf, len, SIZEOF(xGetImageReply), async_size, async_size);
/*
* From now on we can return True, as all
* data has been consumed from buffer.
*/
if (state -> format == XYPixmap)
{
unsigned long depth = DepthOnes(state -> mask & (((unsigned long)0xFFFFFFFF) >>
(32 - async_rep -> depth)));
state -> image = XCreateImage(dpy, _XVIDtoVisual(dpy, async_rep -> visual),
depth, XYPixmap, 0, async_data, state -> width,
state -> height, dpy -> bitmap_pad, 0);
}
else
{
state -> image = XCreateImage(dpy, _XVIDtoVisual(dpy, async_rep -> visual),
async_rep -> depth, ZPixmap, 0, async_data, state -> width,
state -> height, _XGetScanlinePad(dpy, async_rep -> depth), 0);
}
if (state -> image == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectImageHandler: PANIC! Failed to create image for resource [%d].\n",
state -> resource);
#endif
_NXNotifyImage(dpy, state -> resource, False);
_NXCollectedImages[state -> resource] = NULL;
SAFE_free(state);
SAFE_free(async_head);
SAFE_free(async_data);
return True;
}
#ifdef TEST_IMAGE
fprintf(stderr, "******_NXCollectImageHandler: Successfully stored image data for resource [%d].\n",
state -> resource);
#endif
}
#ifdef WARNING
else
{
fprintf(stderr, "******_NXCollectImageHandler: WARNING! Null image data stored for resource [%d].\n",
state -> resource);
}
#endif
_NXNotifyImage(dpy, state -> resource, True);
SAFE_free(async_head);
return True;
}
int NXGetCollectImageResource(Display *dpy)
{
for (int i = 0; i < NXNumberOfResources; i++)
{
if (_NXCollectedImages[i] == NULL)
{
return i;
}
}
return -1;
}
/*
* return codes:
* 0 no data found for resource (currently unused)
* -1 Failed
* True (1) Handler has been installed, will generate NXCollectImageNotify event when answer arrives
*/
int NXCollectImage(Display *dpy, unsigned int resource, Drawable drawable,
int src_x, int src_y, unsigned int width, unsigned int height,
unsigned long plane_mask, int format)
{
register xGetImageReq *req;
_NXCollectImageState *state;
_XAsyncHandler *handler;
if (resource >= NXNumberOfResources)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectImage: PANIC! Provided resource [%u] is out of range.\n",
resource);
#endif
return -1;
}
state = _NXCollectedImages[resource];
if (state != NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectImage: PANIC! Having to remove previous state for resource [%u].\n",
resource);
#endif
if (state -> handler != NULL)
{
DeqAsyncHandler(dpy, state -> handler);
SAFE_free(state -> handler);
}
if (state -> image != NULL)
{
XDestroyImage(state -> image);
}
SAFE_free(state);
_NXCollectedImages[resource] = NULL;
}
LockDisplay(dpy);
GetReq(GetImage, req);
req -> format = format;
req -> drawable = drawable;
req -> x = src_x;
req -> y = src_y;
req -> width = width;
req -> height = height;
req -> planeMask = plane_mask;
#ifdef TEST_IMAGE
fprintf(stderr, "******NXCollectImage: Sending message opcode [%d] sequence [%ld] for resource [%d].\n",
X_GetImage, dpy -> request, resource);
fprintf(stderr, "******NXCollectImage: Format [%d] drawable [%d] src_x [%d] src_y [%d].\n",
req -> format, (int) req -> drawable, req -> x, req -> y);
fprintf(stderr, "******NXCollectImage: Width [%d] height [%d] plane_mask [%x].\n",
req -> width, req -> height, (int) req -> planeMask);
#endif
state = malloc(sizeof(_NXCollectImageState));
handler = malloc(sizeof(_XAsyncHandler));
if (state == NULL || handler == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectImage: PANIC! Failed to allocate memory with resource [%d].\n",
resource);
#endif
UnGetReq(GetImage);
SAFE_free(state);
SAFE_free(handler);
UnlockDisplay(dpy);
return -1;
}
state -> sequence = dpy -> request;
state -> resource = resource;
state -> mask = plane_mask;
state -> format = format;
state -> width = width;
state -> height = height;
state -> image = NULL;
state -> handler = handler;
handler -> next = dpy -> async_handlers;
handler -> handler = _NXCollectImageHandler;
handler -> data = (XPointer) state;
dpy -> async_handlers = handler;
_NXCollectedImages[resource] = state;
UnlockDisplay(dpy);
SyncHandle();
return 1;
}
int NXGetCollectedImage(Display *dpy, unsigned int resource, XImage **image)
{
register _NXCollectImageState *state;
state = _NXCollectedImages[resource];
if (state == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXGetCollectedImage: PANIC! No image collected for resource [%u].\n",
resource);
#endif
return 0;
}
_NXCollectedImages[resource] = NULL;
*image = state -> image;
SAFE_free(state);
#ifdef TEST_IMAGE
fprintf(stderr, "******NXGetCollectedImage: Returning GetImage data for resource [%u].\n",
resource);
#endif
return 1;
}
static void _NXNotifyProperty(Display *dpy, int resource, Bool success)
{
XEvent async_event;
/*
* Enqueue an event to tell client
* the result of GetProperty.
*/
async_event.type = ClientMessage;
async_event.xclient.serial = _NXCollectedProperties[resource] -> sequence;
async_event.xclient.window = 0;
async_event.xclient.message_type = 0;
async_event.xclient.format = 32;
async_event.xclient.data.l[0] = NXCollectPropertyNotify;
async_event.xclient.data.l[1] = resource;
async_event.xclient.data.l[2] = success;
XPutBackEvent(dpy, &async_event);
}
static Bool _NXCollectPropertyHandler(Display *dpy, xReply *rep, char *buf,
int len, XPointer data)
{
register _NXCollectPropertyState *state;
register xGetPropertyReply *async_rep;
char *async_head;
char *async_data;
int async_size;
state = (_NXCollectPropertyState *) data;
#ifdef DEBUG_PROPERTY
fprintf(stderr, "******%s: sequence: received [%hu] expected [%lu] 16bit received [%hu] expected [%hu]\n",
__func__,
rep -> generic.sequenceNumber, state -> sequence,
rep -> generic.sequenceNumber % 65536, (CARD16)(state -> sequence) % 65536);
#endif
if ((rep -> generic.sequenceNumber % 65536) !=
((CARD16)(state -> sequence) % 65536))
{
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXCollectPropertyHandler: Unmatched sequence [%d] of type [%d] "
"with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type,
(int) rep -> generic.length << 2);
#endif
return False;
}
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXCollectPropertyHandler: Going to handle asynchronous GetProperty reply.\n");
#endif
/*
* Reply data is managed asynchronously. We can
* use state to get to vector and vector to get
* to handler. In this way, we can dequeue and
* free the handler itself.
*/
DeqAsyncHandler(dpy, state -> handler);
SAFE_free(state -> handler);
if (rep -> generic.type == X_Error)
{
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXCollectPropertyHandler: Error received from X server for resource [%d].\n",
state -> resource);
#endif
_NXNotifyProperty(dpy, state -> resource, False);
_NXCollectedProperties[state -> resource] = NULL;
SAFE_free(state);
return False;
}
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXCollectPropertyHandler: Matched request with sequence [%ld].\n",
state -> sequence);
#endif
async_size = SIZEOF(xGetPropertyReply);
async_head = malloc(async_size);
if (async_head == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectPropertyHandler: PANIC! Failed to allocate memory with resource [%d].\n",
state -> resource);
#endif
_NXNotifyProperty(dpy, state -> resource, False);
_NXCollectedProperties[state -> resource] = NULL;
SAFE_free(state);
return False;
}
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXCollectPropertyHandler: Going to get reply with size [%d].\n",
(int) rep -> generic.length << 2);
#endif
async_rep = (xGetPropertyReply *) _XGetAsyncReply(dpy, async_head, rep, buf, len, 0, False);
if (async_rep == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectPropertyHandler: PANIC! Failed to get reply with resource [%d].\n",
state -> resource);
#endif
_NXNotifyProperty(dpy, state -> resource, False);
_NXCollectedProperties[state -> resource] = NULL;
SAFE_free(state);
SAFE_free(async_head);
return False;
}
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXCollectPropertyHandler: Got reply with format [%d] type [%d] size [%d].\n",
async_rep -> format, (int) async_rep -> propertyType, (int) async_rep -> length << 2);
fprintf(stderr, "******_NXCollectPropertyHandler: Bytes after [%d] number of items [%d].\n",
(int) async_rep -> bytesAfter, (int) async_rep -> nItems);
#endif
state -> format = async_rep -> format;
state -> type = async_rep -> propertyType;
state -> items = async_rep -> nItems;
state -> after = async_rep -> bytesAfter;
async_size = async_rep -> length << 2;
if (async_size > 0)
{
async_data = malloc(async_size);
if (async_data == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectPropertyHandler: PANIC! Failed to allocate memory with resource [%d].\n",
state -> resource);
#endif
_NXNotifyProperty(dpy, state -> resource, False);
_NXCollectedProperties[state -> resource] = NULL;
SAFE_free(state);
SAFE_free(async_head);
return False;
}
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXCollectPropertyHandler: Going to get data with size [%d].\n",
async_size);
#endif
_XGetAsyncData(dpy, async_data, buf, len, SIZEOF(xGetPropertyReply), async_size, async_size);
/*
* From now on we can return True, as all
* data has been consumed from buffer.
*/
state -> data = async_data;
#ifdef TEST_PROPERTY
fprintf(stderr, "******_NXCollectPropertyHandler: Successfully stored property data for resource [%d].\n",
state -> resource);
#endif
}
#ifdef TEST_PROPERTY
else
{
fprintf(stderr, "******_NXCollectPropertyHandler: WARNING! Null property data stored for resource [%d].\n",
state -> resource);
}
#endif
_NXNotifyProperty(dpy, state -> resource, True);
SAFE_free(async_head);
return True;
}
int NXGetCollectPropertyResource(Display *dpy)
{
for (int i = 0; i < NXNumberOfResources; i++)
{
if (_NXCollectedProperties[i] == NULL)
{
return i;
}
}
return -1;
}
/*
* return codes:
* 0 no data found for resource (currently unused)
* -1 Failed
* True Handler has been installed, will generate NXCollectPropertyNotify event when answer arrives
*/
int NXCollectProperty(Display *dpy, unsigned int resource, Window window, Atom property,
long long_offset, long long_length, Bool delete, Atom req_type)
{
register xGetPropertyReq *req;
_NXCollectPropertyState *state;
_XAsyncHandler *handler;
if (resource >= NXNumberOfResources)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectProperty: PANIC! Provided resource [%u] is out of range.\n",
resource);
#endif
return -1;
}
state = _NXCollectedProperties[resource];
if (state != NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectProperty: PANIC! Having to remove previous state for resource [%u].\n",
resource);
#endif
if (state -> handler != NULL)
{
DeqAsyncHandler(dpy, state -> handler);
SAFE_free(state -> handler);
}
SAFE_free(state->data);
SAFE_free(state);
_NXCollectedProperties[resource] = NULL;
}
LockDisplay(dpy);
GetReq(GetProperty, req);
req -> delete = delete;
req -> window = window;
req -> property = property;
req -> type = req_type;
req -> longOffset = long_offset;
req -> longLength = long_length;
#ifdef TEST_PROPERTY
fprintf(stderr, "******NXCollectProperty: Sending message opcode [%d] sequence [%ld] for resource [%d].\n",
X_GetProperty, dpy -> request, resource);
fprintf(stderr, "******NXCollectProperty: Delete [%u] window [%d] property [%d] type [%d].\n",
req -> delete, (int) req -> window, (int) req -> property, (int) req -> type);
fprintf(stderr, "******NXCollectProperty: Long offset [%d] long length [%d].\n",
(int) req -> longOffset, (int) req -> longLength);
#endif
state = malloc(sizeof(_NXCollectPropertyState));
handler = malloc(sizeof(_XAsyncHandler));
if (state == NULL || handler == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectProperty: Failed to allocate memory with resource [%d].\n",
resource);
#endif
SAFE_free(state);
SAFE_free(handler);
UnGetReq(GetProperty);
UnlockDisplay(dpy);
return -1;
}
state -> sequence = dpy -> request;
state -> resource = resource;
state -> window = window;
state -> property = property;
state -> type = 0;
state -> format = 0;
state -> items = 0;
state -> after = 0;
state -> data = NULL;
state -> handler = handler;
handler -> next = dpy -> async_handlers;
handler -> handler = _NXCollectPropertyHandler;
handler -> data = (XPointer) state;
dpy -> async_handlers = handler;
_NXCollectedProperties[resource] = state;
UnlockDisplay(dpy);
SyncHandle();
return True;
}
/*
* return codes:
* 0 not data available
* True success
*/
int NXGetCollectedProperty(Display *dpy, unsigned int resource, Atom *actual_type_return,
int *actual_format_return, unsigned long *nitems_return,
unsigned long *bytes_after_return, unsigned char **data)
{
register _NXCollectPropertyState *state;
state = _NXCollectedProperties[resource];
if (state == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXGetCollectedProperty: PANIC! No data collected for resource [%u].\n",
resource);
#endif
return 0;
}
*actual_type_return = state -> type;
*actual_format_return = state -> format;
*nitems_return = state -> items;
*bytes_after_return = state -> after;
*data = (unsigned char *) _NXCollectedProperties[resource] -> data;
SAFE_free(state);
_NXCollectedProperties[resource] = NULL;
#ifdef TEST_PROPERTY
fprintf(stderr, "******NXGetCollectedProperty: Returning GetProperty data for resource [%u].\n",
resource);
#endif
return True;
}
static void _NXNotifyGrabPointer(Display *dpy, int resource, Bool success)
{
XEvent async_event;
async_event.type = ClientMessage;
async_event.xclient.serial = _NXCollectedGrabPointers[resource] -> sequence;
async_event.xclient.window = 0;
async_event.xclient.message_type = 0;
async_event.xclient.format = 32;
async_event.xclient.data.l[0] = NXCollectGrabPointerNotify;
async_event.xclient.data.l[1] = resource;
async_event.xclient.data.l[2] = success;
XPutBackEvent(dpy, &async_event);
}
static Bool _NXCollectGrabPointerHandler(Display *dpy, xReply *rep, char *buf,
int len, XPointer data)
{
register _NXCollectGrabPointerState *state;
register xGrabPointerReply *async_rep;
char *async_head;
int async_size;
state = (_NXCollectGrabPointerState *) data;
#ifdef DEBUG_POINTER
fprintf(stderr, "******%s: sequence: received [%hu] expected [%lu] 16bit received [%hu] expected [%hu]\n",
__func__,
rep -> generic.sequenceNumber, state -> sequence,
rep -> generic.sequenceNumber % 65536, (CARD16)(state -> sequence) % 65536);
#endif
if ((rep -> generic.sequenceNumber % 65536) !=
((CARD16)(state -> sequence) % 65536))
{
#ifdef TEST_POINTER
fprintf(stderr, "******_NXCollectGrabPointerHandler: Unmatched sequence [%d] of type [%d] "
"with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type,
(int) rep -> generic.length << 2);
#endif
return False;
}
#ifdef TEST_POINTER
fprintf(stderr, "******_NXCollectGrabPointerHandler: Going to handle asynchronous GrabPointer reply.\n");
#endif
DeqAsyncHandler(dpy, state -> handler);
SAFE_free(state -> handler);
if (rep -> generic.type == X_Error)
{
#ifdef TEST_POINTER
fprintf(stderr, "******_NXCollectGrabPointerHandler: Error received from X server for resource [%d].\n",
state -> resource);
#endif
_NXNotifyGrabPointer(dpy, state -> resource, False);
_NXCollectedGrabPointers[state -> resource] = NULL;
SAFE_free(state);
return False;
}
#ifdef TEST_POINTER
fprintf(stderr, "******_NXCollectGrabPointerHandler: Matched request with sequence [%ld].\n",
state -> sequence);
#endif
async_size = SIZEOF(xGrabPointerReply);
async_head = malloc(async_size);
if (async_head == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectGrabPointerHandler: PANIC! Failed to allocate memory with resource [%d].\n",
state -> resource);
#endif
_NXNotifyGrabPointer(dpy, state -> resource, False);
_NXCollectedGrabPointers[state -> resource] = NULL;
SAFE_free(state);
return False;
}
#ifdef TEST_POINTER
fprintf(stderr, "******_NXCollectGrabPointerHandler: Going to get reply with size [%d].\n",
(int) rep -> generic.length << 2);
#endif
async_rep = (xGrabPointerReply *) _XGetAsyncReply(dpy, async_head, rep, buf, len, 0, False);
if (async_rep == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectGrabPointerHandler: PANIC! Failed to get reply with resource [%d].\n",
state -> resource);
#endif
_NXNotifyGrabPointer(dpy, state -> resource, False);
_NXCollectedGrabPointers[state -> resource] = NULL;
SAFE_free(state);
SAFE_free(async_head);
return False;
}
#ifdef TEST_POINTER
fprintf(stderr, "******_NXCollectGrabPointerHandler: Got reply with status [%d] size [%d].\n",
async_rep -> status, (int) async_rep -> length << 2);
#endif
state -> status = async_rep -> status;
_NXNotifyGrabPointer(dpy, state -> resource, True);
SAFE_free(async_head);
return True;
}
int NXGetCollectGrabPointerResource(Display *dpy)
{
for (int i = 0; i < NXNumberOfResources; i++)
{
if (_NXCollectedGrabPointers[i] == NULL)
{
return i;
}
}
return -1;
}
/*
* return codes:
* 0 no data found for resource
* -1 Failed
* True Handler has been installed, will generate NXCollectGrabPointerNotify event when answer arrives
*/
int NXCollectGrabPointer(Display *dpy, unsigned int resource, Window grab_window, Bool owner_events,
unsigned int event_mask, int pointer_mode, int keyboard_mode,
Window confine_to, Cursor cursor, Time time)
{
register xGrabPointerReq *req;
_NXCollectGrabPointerState *state;
_XAsyncHandler *handler;
if (resource >= NXNumberOfResources)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectGrabPointer: PANIC! Provided resource [%u] is out of range.\n",
resource);
#endif
return -1;
}
state = _NXCollectedGrabPointers[resource];
if (state != NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectGrabPointer: PANIC! Having to remove previous state for resource [%u].\n",
resource);
#endif
if (state -> handler != NULL)
{
DeqAsyncHandler(dpy, state -> handler);
SAFE_free(state -> handler);
}
SAFE_free(state);
_NXCollectedGrabPointers[resource] = NULL;
}
LockDisplay(dpy);
GetReq(GrabPointer, req);
req -> grabWindow = grab_window;
req -> ownerEvents = owner_events;
req -> eventMask = event_mask;
req -> pointerMode = pointer_mode;
req -> keyboardMode = keyboard_mode;
req -> confineTo = confine_to;
req -> cursor = cursor;
req -> time = time;
#ifdef TEST_POINTER
fprintf(stderr, "******NXCollectGrabPointer: Sending message opcode [%d] sequence [%ld] "
"for resource [%d].\n", X_GrabPointer, dpy -> request, resource);
#endif
state = malloc(sizeof(_NXCollectGrabPointerState));
handler = malloc(sizeof(_XAsyncHandler));
if (state == NULL || handler == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectGrabPointer: Failed to allocate memory with resource [%d].\n",
resource);
#endif
SAFE_free(state);
SAFE_free(handler);
UnGetReq(GrabPointer);
UnlockDisplay(dpy);
return -1;
}
state -> sequence = dpy -> request;
state -> resource = resource;
state -> status = 0;
state -> handler = handler;
handler -> next = dpy -> async_handlers;
handler -> handler = _NXCollectGrabPointerHandler;
handler -> data = (XPointer) state;
dpy -> async_handlers = handler;
_NXCollectedGrabPointers[resource] = state;
UnlockDisplay(dpy);
SyncHandle();
return True;
}
/*
* return codes:
* 0 not data available
* True success
*/
int NXGetCollectedGrabPointer(Display *dpy, unsigned int resource, int *status)
{
register _NXCollectGrabPointerState *state;
state = _NXCollectedGrabPointers[resource];
if (state == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXGetCollectedGrabPointer: PANIC! No data collected for resource [%u].\n",
resource);
#endif
return 0;
}
*status = state -> status;
SAFE_free(state);
_NXCollectedGrabPointers[resource] = NULL;
#ifdef TEST_POINTER
fprintf(stderr, "******NXGetCollectedGrabPointer: Returning GrabPointer data for resource [%u].\n",
resource);
#endif
return True;
}
static void _NXNotifyInputFocus(Display *dpy, int resource, Bool success)
{
XEvent async_event;
async_event.type = ClientMessage;
async_event.xclient.serial = _NXCollectedInputFocuses[resource] -> sequence;
async_event.xclient.window = 0;
async_event.xclient.message_type = 0;
async_event.xclient.format = 32;
async_event.xclient.data.l[0] = NXCollectInputFocusNotify;
async_event.xclient.data.l[1] = resource;
async_event.xclient.data.l[2] = success;
XPutBackEvent(dpy, &async_event);
}
static Bool _NXCollectInputFocusHandler(Display *dpy, xReply *rep, char *buf,
int len, XPointer data)
{
register _NXCollectInputFocusState *state;
register xGetInputFocusReply *async_rep;
char *async_head;
int async_size;
state = (_NXCollectInputFocusState *) data;
#ifdef DEBUG_INPUT
fprintf(stderr, "******%s: sequence: received [%hu] expected [%lu] 16bit received [%hu] expected [%hu]\n",
__func__,
rep -> generic.sequenceNumber, state -> sequence,
rep -> generic.sequenceNumber % 65536, (CARD16)(state -> sequence) % 65536);
#endif
if ((rep -> generic.sequenceNumber % 65536) !=
((CARD16)(state -> sequence) % 65536))
{
#ifdef TEST_INPUT
fprintf(stderr, "******_NXCollectInputFocusHandler: Unmatched sequence [%d] of type [%d] "
"with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type,
(int) rep -> generic.length << 2);
#endif
return False;
}
#ifdef TEST_INPUT
fprintf(stderr, "******_NXCollectInputFocusHandler: Going to handle asynchronous GetInputFocus reply.\n");
#endif
DeqAsyncHandler(dpy, state -> handler);
SAFE_free(state -> handler);
if (rep -> generic.type == X_Error)
{
#ifdef TEST_INPUT
fprintf(stderr, "******_NXCollectInputFocusHandler: Error received from X server for resource [%d].\n",
state -> resource);
#endif
_NXNotifyInputFocus(dpy, state -> resource, False);
_NXCollectedInputFocuses[state -> resource] = NULL;
SAFE_free(state);
return False;
}
#ifdef TEST_INPUT
fprintf(stderr, "******_NXCollectInputFocusHandler: Matched request with sequence [%ld].\n",
state -> sequence);
#endif
async_size = SIZEOF(xGetInputFocusReply);
async_head = malloc(async_size);
if (async_head == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectInputFocusHandler: PANIC! Failed to allocate memory with resource [%d].\n",
state -> resource);
#endif
_NXNotifyInputFocus(dpy, state -> resource, False);
_NXCollectedInputFocuses[state -> resource] = NULL;
SAFE_free(state);
return False;
}
#ifdef TEST_INPUT
fprintf(stderr, "******_NXCollectInputFocusHandler: Going to get reply with size [%d].\n",
(int) rep -> generic.length << 2);
#endif
async_rep = (xGetInputFocusReply *) _XGetAsyncReply(dpy, async_head, rep, buf, len, 0, False);
if (async_rep == NULL)
{
#ifdef PANIC
fprintf(stderr, "******_NXCollectInputFocusHandler: PANIC! Failed to get reply with resource [%d].\n",
state -> resource);
#endif
_NXNotifyInputFocus(dpy, state -> resource, False);
_NXCollectedInputFocuses[state -> resource] = NULL;
SAFE_free(state);
SAFE_free(async_head);
return False;
}
#ifdef TEST_INPUT
fprintf(stderr, "******_NXCollectInputFocusHandler: Got reply with focus [%d] revert to [%d] "
"size [%d].\n", (int) async_rep -> focus, (int) async_rep -> revertTo,
(int) async_rep -> length << 2);
#endif
state -> focus = async_rep -> focus;
state -> revert_to = async_rep -> revertTo;
_NXNotifyInputFocus(dpy, state -> resource, True);
SAFE_free(async_head);
return True;
}
int NXGetCollectInputFocusResource(Display *dpy)
{
for (int i = 0; i < NXNumberOfResources; i++)
{
if (_NXCollectedInputFocuses[i] == NULL)
{
return i;
}
}
return -1;
}
/*
* return codes:
* 0 no data found for resource (currently unused)
* -1 Failed
* True (1) Handler has been installed, will generate NXCollectInputFocusNotify event when answer arrives
*/
int NXCollectInputFocus(Display *dpy, unsigned int resource)
{
_X_UNUSED register xReq *req;
_NXCollectInputFocusState *state;
_XAsyncHandler *handler;
if (resource >= NXNumberOfResources)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectInputFocus: PANIC! Provided resource [%u] is out of range.\n",
resource);
#endif
return -1;
}
state = _NXCollectedInputFocuses[resource];
if (state != NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectInputFocus: PANIC! Having to remove previous state for resource [%u].\n",
resource);
#endif
if (state -> handler != NULL)
{
DeqAsyncHandler(dpy, state -> handler);
SAFE_free(state -> handler);
}
SAFE_free(state);
_NXCollectedInputFocuses[resource] = NULL;
}
LockDisplay(dpy);
GetEmptyReq(GetInputFocus, req);
#ifdef TEST_INPUT
fprintf(stderr, "******NXCollectInputFocus: Sending message opcode [%d] sequence [%ld] for resource [%d].\n",
X_GetInputFocus, dpy -> request, resource);
#endif
state = malloc(sizeof(_NXCollectInputFocusState));
handler = malloc(sizeof(_XAsyncHandler));
if (state == NULL || handler == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXCollectInputFocus: Failed to allocate memory with resource [%d].\n",
resource);
#endif
SAFE_free(state);
SAFE_free(handler);
UnGetEmptyReq();
UnlockDisplay(dpy);
return -1;
}
state -> sequence = dpy -> request;
state -> resource = resource;
state -> focus = 0;
state -> revert_to = 0;
state -> handler = handler;
handler -> next = dpy -> async_handlers;
handler -> handler = _NXCollectInputFocusHandler;
handler -> data = (XPointer) state;
dpy -> async_handlers = handler;
_NXCollectedInputFocuses[resource] = state;
UnlockDisplay(dpy);
SyncHandle();
return True;
}
/*
* return codes:
* 0 not data available
* True success
*/
int NXGetCollectedInputFocus(Display *dpy, unsigned int resource,
Window *focus_return, int *revert_to_return)
{
register _NXCollectInputFocusState *state;
state = _NXCollectedInputFocuses[resource];
if (state == NULL)
{
#ifdef PANIC
fprintf(stderr, "******NXGetCollectedInputFocus: PANIC! No data collected for resource [%u].\n",
resource);
#endif
return 0;
}
*focus_return = state -> focus;
*revert_to_return = state -> revert_to;
SAFE_free(state);
_NXCollectedInputFocuses[resource] = NULL;
#ifdef TEST_INPUT
fprintf(stderr, "******NXGetCollectedInputFocus: Returning GetInputFocus data for resource [%u].\n",
resource);
#endif
return True;
}
#ifdef DUMP
void _NXDumpData(const unsigned char *buffer, unsigned int size)
{
if (buffer != NULL)
{
unsigned int i = 0;
while (i < size)
{
fprintf(stderr, "[%d]\t", i);
for (unsigned int ii = 0; i < size && ii < 8; i++, ii++)
{
fprintf(stderr, "%d\t", (unsigned int) (buffer[i]));
}
fprintf(stderr, "\n");
}
}
}
#endif