diff options
Diffstat (limited to 'nxcompext/NXlib.c')
-rw-r--r-- | nxcompext/NXlib.c | 4770 |
1 files changed, 4770 insertions, 0 deletions
diff --git a/nxcompext/NXlib.c b/nxcompext/NXlib.c new file mode 100644 index 000000000..452213bf1 --- /dev/null +++ b/nxcompext/NXlib.c @@ -0,0 +1,4770 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NXCOMPEXT, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rigths reserved. */ +/* */ +/**************************************************************************/ + +#include <sys/socket.h> + +#ifndef __sun +#include <strings.h> +#endif + +#include "NX.h" + +#include "dix.h" +#include "os.h" + +#define NEED_REPLIES + +/* + * Needed to enable definition of the callback + * functions. + */ + +#define NX_TRANS_SOCKET + +#include "Xlib.h" +#include "Xutil.h" +#include "Xlibint.h" + +#include "NXlib.h" +#include "NXproto.h" +#include "NXpack.h" + +#include "Clean.h" +#include "Mask.h" +#include "Colormap.h" +#include "Alpha.h" +#include "Bitmap.h" +#include "Jpeg.h" +#include "Pgn.h" +#include "Rgb.h" +#include "Rle.h" +#include "Z.h" + +#include "MD5.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#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 + 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 + fprintf(stderr, "******NXInitDisplay: WARNING! Internal structures already initialized.\n"); + #endif + + return 0; +} + +int NXResetDisplay(Display *dpy) +{ + #ifdef TEST + 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 + fprintf(stderr, "******NXResetDisplay: WARNING! Internal structures already reset.\n"); + #endif + + return 0; +} + +int _NXInternalInitResources(Display *dpy) +{ + return _NXInternalResetResources(dpy); +} + +int _NXInternalResetResources(Display *dpy) +{ + int i; + + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: Clearing all the internal structures.\n"); + #endif + + for (i = 0; i < NXNumberOfResources; i++) + { + _NXSplitResources[i] = 0; + _NXUnpackResources[i] = 0; + + if (_NXCollectedImages[i] != NULL) + { + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing collect image data " + "for resource [%d].\n", i); + #endif + + if (_NXCollectedImages[i] -> handler != NULL) + { + DeqAsyncHandler(dpy, _NXCollectedImages[i] -> handler); + + Xfree(_NXCollectedImages[i] -> handler); + } + + if (_NXCollectedImages[i] -> image != NULL) + { + XDestroyImage(_NXCollectedImages[i] -> image); + } + + Xfree(_NXCollectedImages[i]); + + _NXCollectedImages[i] = NULL; + } + + if (_NXCollectedProperties[i] != NULL) + { + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing collect property data " + "for resource [%d].\n", i); + #endif + + if (_NXCollectedProperties[i] -> handler != NULL) + { + DeqAsyncHandler(dpy, _NXCollectedProperties[i] -> handler); + + Xfree(_NXCollectedProperties[i] -> handler); + } + + if (_NXCollectedProperties[i] -> data != NULL) + { + Xfree(_NXCollectedProperties[i] -> data); + } + + Xfree(_NXCollectedProperties[i]); + + _NXCollectedProperties[i] = NULL; + } + + if (_NXCollectedGrabPointers[i] != NULL) + { + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing grab pointer data " + "for resource [%d].\n", i); + #endif + + if (_NXCollectedGrabPointers[i] -> handler != NULL) + { + DeqAsyncHandler(dpy, _NXCollectedGrabPointers[i] -> handler); + + Xfree(_NXCollectedGrabPointers[i] -> handler); + } + + Xfree(_NXCollectedGrabPointers[i]); + + _NXCollectedGrabPointers[i] = NULL; + } + + if (_NXCollectedInputFocuses[i] != NULL) + { + #ifdef TEST + 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); + + Xfree(_NXCollectedInputFocuses[i] -> handler); + } + + Xfree(_NXCollectedInputFocuses[i]); + + _NXCollectedInputFocuses[i] = NULL; + } + } + + 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); + } +} + +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 + 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; + } + + if (dpy -> buffer != NULL) + { + Xfree(dpy -> buffer); + } + + dpy -> buffer = buffer; + dpy -> bufptr = dpy -> buffer; + dpy -> bufmax = dpy -> bufptr + size; + + #ifdef TEST + 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 + * wil 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 + 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 + fprintf(stderr, "******NXDisplayReadable: Returning [%d] bytes readable from fd [%d].\n", + readable, dpy -> fd); + #endif + + return readable; + } + + #ifdef DEBUG + fprintf(stderr, "******NXDisplayReadable: WARNING! Error detected on display fd [%d].\n", + dpy -> fd); + #endif + + return -1; +} + +int NXDisplayFlushable(Display *dpy) +{ + #ifdef DEBUG + + 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 + + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 +} + +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; + + register xReq *req; + + LockDisplay(dpy); + + GetEmptyReq(NXGetControlParameters, req); + + #ifdef TEST + fprintf(stderr, "******NXGetControlParameters: Sending message opcode [%d].\n", + X_NXGetControlParameters); + #endif + + if (_XReply(dpy, (xReply *) &rep, 0, xTrue) == xFalse) + { + #ifdef TEST + fprintf(stderr, "******NXGetControlParameters: Error receiving reply.\n"); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + #ifdef TEST + 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? + */ + +Status NXGetUnpackParameters(Display *dpy, unsigned int *entries, unsigned char supported_methods[]) +{ + register xNXGetUnpackParametersReq *req; + + xNXGetUnpackParametersReply rep; + + register unsigned n; + + #ifdef TEST + register unsigned i; + #endif + + if (*entries < NXNumberOfPackMethods) + { + #ifdef TEST + 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 + 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 + fprintf(stderr, "******NXGetUnpackParameters: Error receiving reply.\n"); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + if ((n = rep.length << 2) > *entries) + { + #ifdef TEST + 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 + fprintf(stderr, "******NXGetUnpackParameters: Reading [%d] bytes of reply data.\n", n); + #endif + + _XReadPad(dpy, (char *) supported_methods, n); + + #ifdef TEST + + fprintf(stderr, "******NXGetUnpackParameters: Got reply with methods: "); + + for (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. + */ + +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 + fprintf(stderr, "******NXGetShmemParameters: Sending message opcode [%d] at stage [%d].\n", + X_NXGetShmemParameters, stage); + #endif + + #ifdef TEST + + 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 + 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 + 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. + */ + +Status NXGetFontParameters(Display *dpy, unsigned int path_length, char path_data[]) +{ + register xNXGetFontParametersReq *req; + + xNXGetFontParametersReply rep; + + register unsigned n; + + #ifdef TEST + register unsigned i; + #endif + + if (path_length < 1) + { + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: No room to store the reply.\n"); + #endif + + return 0; + } + + *path_data = '\0'; + + LockDisplay(dpy); + + GetReq(NXGetFontParameters, req); + + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: Sending message opcode [%d].\n", + X_NXGetFontParameters); + #endif + + if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == xFalse || rep.length == 0) + { + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: Error receiving reply.\n"); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + if ((n = rep.length << 2) > path_length) + { + #ifdef TEST + 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 + 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 + fprintf(stderr, "******NXGetFontParameters: Inconsistent length in the returned string.\n"); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + #ifdef TEST + + 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 + fprintf(stderr, "******NXAllocSplit: Reserved resource [%u].\n", + resource); + #endif + + return resource; + } + } + + #ifdef TEST + fprintf(stderr, "******NXAllocSplit: WARNING! Resource limit exausted.\n"); + #endif + + return NXNoResource; + } + else if (resource >= 0 && resource < NXNumberOfResources) + { + #ifdef TEST + + 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 + 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 + 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 + 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 + 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 + 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 + fprintf(stderr, "******NXFreeSplit: Sending message opcode [%d] with resource [%u].\n", + X_NXFreeSplit, resource); + #endif + + req -> resource = resource; + + UnlockDisplay(dpy); + + SyncHandle(); + + #ifdef TEST + fprintf(stderr, "******NXFreeSplit: Making the resource [%u] newly available.\n", + resource); + #endif + + _NXSplitResources[resource] = 0; + } + #ifdef TEST + 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 + 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 + 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 + fprintf(stderr, "******NXAllocUnpack: Reserved resource [%u].\n", + resource); + #endif + + return resource; + } + } + + #ifdef TEST + fprintf(stderr, "******NXAllocUnpack: WARNING! Resource limit exausted.\n"); + #endif + + return NXNoResource; + } + else if (resource >= 0 && resource < NXNumberOfResources) + { + #ifdef TEST + + 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 + 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 + 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 + 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; + + #ifdef DUMP + + int i; + + #endif + + LockDisplay(dpy); + + GetReq(NXSetUnpackColormapCompat, req); + + req -> resource = resource; + req -> entries = entries; + + dst_data_length = entries << 2; + + req -> length += (dst_data_length >> 2); + + #ifdef TEST + 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 (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; + + #ifdef DUMP + + int i; + + #endif + + 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 + 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 (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 + fprintf(stderr, "******NXFreeUnpack: Sending message opcode [%d] with resource [%u].\n", + X_NXFreeUnpack, resource); + #endif + + req -> resource = resource; + + UnlockDisplay(dpy); + + SyncHandle(); + + #ifdef TEST + fprintf(stderr, "******NXFreeUnpack: Making the resource [%u] newly available.\n", + resource); + #endif + + _NXUnpackResources[resource] = 0; + } + #ifdef TEST + 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 + 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 + 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 *) Xmalloc(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 + 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 = Xmalloc(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 + + Xfree(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 + 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 + + Xfree(dst_image -> data); + + Xfree(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 + + Xfree(dst_image -> data); + + Xfree(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 + 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 + 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 + + Xfree(dst_image -> data); + + Xfree(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 + 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 *) Xmalloc(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 + 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 + 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 + 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 + + Xfree(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 + + Xfree(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 + 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 + 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 + 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 + 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 + 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; + + register unsigned int i; + + LockDisplay(dpy); + + for (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 (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 *) Xmalloc(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 + + Xfree(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 *) Xmalloc(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 + + Xfree(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 *) Xmalloc(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 + + Xfree(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 *) Xmalloc(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 + + Xfree(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 *) Xmalloc(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 + + Xfree(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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + fprintf(stderr, "******NXInitCache: Nothing to do with image cache at [%p] and [%d] entries.\n", + NXImageCache, NXImageCacheSize); + #endif + + return; + } + + #ifdef DEBUG + fprintf(stderr, "******NXInitCache: Initializing the cache with [%d] entries.\n", + entries); + #endif + + NXImageCacheSize = 0; + + if (NXImageCache != NULL) + { + Xfree(NXImageCache); + + NXImageCache = NULL; + } + + if (entries > 0) + { + NXImageCache = Xmalloc(entries * sizeof(_NXImageCacheEntry)); + + if (NXImageCache != NULL) + { + memset(NXImageCache, 0, entries * sizeof(_NXImageCacheEntry)); + + NXImageCacheSize = entries; + + #ifdef DEBUG + 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]; + + int i; + int j; + + #ifdef DEBUG + fprintf(stderr, "%s: Dumping the content of image cache:\n", label); + #endif + + for (i = 0; i < NXImageCacheSize; i++) + { + if (NXImageCache[i].image == NULL) + { + break; + } + + for (j = 0; j < MD5_LENGTH; j++) + { + sprintf(s + (j * 2), "%02X", ((unsigned char *) NXImageCache[i].md5)[j]); + } + + #ifdef DEBUG + 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, i; + + if (NXImageCache == NULL) + { + return NULL; + } + + /* + * Will return the allocated checksum + * if the image is not found. + */ + + *md5 = NULL; + + if ((new_md5 = Xmalloc(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 (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 + fprintf(stderr, "******NXCacheFindImage: Found at position [%d] with hits [%d] and [%d] packs.\n", + i, NXImageCacheHits, NXImageCacheOps); + #endif + + Xfree(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 + 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 + fprintf(stderr, "******NXCacheAddImage: Freeing up the oldest entry.\n"); + #endif + + i--; + + Xfree(NXImageCache[NXImageCacheSize - 1].image -> data); + Xfree(NXImageCache[NXImageCacheSize - 1].image); + Xfree(NXImageCache[NXImageCacheSize - 1].md5); + } + + if (i > 0) + { + memmove(&NXImageCache[1], &NXImageCache[0], i * sizeof(_NXImageCacheEntry)); + } + + NXImageCacheOps++; + + #ifdef DEBUG + 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) +{ + int i; + + if (NXImageCache == NULL) + { + #ifdef DEBUG + fprintf(stderr, "******NXFreeCache: Nothing to do with a null image cache.\n"); + #endif + + return; + } + + #ifdef DEBUG + fprintf(stderr, "******NXFreeCache: Freeing the cache with [%d] entries.\n", + NXImageCacheSize); + #endif + + for (i = 0; i < NXImageCacheSize; i++) + { + if (NXImageCache[i].image != NULL) + { + if (NXImageCache[i].image -> data != NULL) + { + Xfree(NXImageCache[i].image -> data); + } + + Xfree(NXImageCache[i].image); + + NXImageCache[i].image = NULL; + } + + if (NXImageCache[i].md5 != NULL) + { + Xfree(NXImageCache[i].md5); + + NXImageCache[i].md5 = NULL; + } + } + + Xfree(NXImageCache); + + NXImageCache = NULL; + + 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; + + if ((rep -> generic.sequenceNumber % 65536) != + ((int)(state -> sequence) % 65536)) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Unmatched sequence [%d] for opcode [%d] " + "with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type, + (int) rep -> generic.length << 2); + #endif + + return False; + } + + #ifdef TEST + 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); + + Xfree(state -> handler); + + state -> handler = NULL; + + if (rep -> generic.type == X_Error) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Error received from X server for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyImage(dpy, state -> resource, False); + + _NXCollectedImages[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Matched request with sequence [%ld].\n", + state -> sequence); + #endif + + async_size = SIZEOF(xGetImageReply); + + async_head = Xmalloc(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; + + Xfree(state); + + return False; + } + + #ifdef TEST + 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; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + 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 = Xmalloc(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; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + 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; + + Xfree(state); + + Xfree(async_head); + Xfree(async_data); + + return True; + } + + #ifdef TEST + 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); + + Xfree(async_head); + + return True; +} + +int NXGetCollectImageResource(Display *dpy) +{ + int i; + + for (i = 0; i < NXNumberOfResources; i++) + { + if (_NXCollectedImages[i] == NULL) + { + return i; + } + } + + return -1; +} + +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); + + Xfree(state -> handler); + } + + if (state -> image != NULL) + { + XDestroyImage(state -> image); + } + + Xfree(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 + 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 = Xmalloc(sizeof(_NXCollectImageState)); + handler = Xmalloc(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); + + if (state != NULL) + { + Xfree(state); + } + + if (handler != NULL) + { + Xfree(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; + + Xfree(state); + + #ifdef TEST + 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; + + if ((rep -> generic.sequenceNumber % 65536) != + ((int)(state -> sequence) % 65536)) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Unmatched sequence [%d] for opcode [%d] " + "with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type, + (int) rep -> generic.length << 2); + #endif + + return False; + } + + #ifdef TEST + 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); + + Xfree(state -> handler); + + state -> handler = NULL; + + if (rep -> generic.type == X_Error) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Error received from X server for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyProperty(dpy, state -> resource, False); + + _NXCollectedProperties[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Matched request with sequence [%ld].\n", + state -> sequence); + #endif + + async_size = SIZEOF(xGetPropertyReply); + + async_head = Xmalloc(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; + + Xfree(state); + + return False; + } + + #ifdef TEST + 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; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + 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 = Xmalloc(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; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + 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 + fprintf(stderr, "******_NXCollectPropertyHandler: Successfully stored property data for resource [%d].\n", + state -> resource); + #endif + } + #ifdef TEST + else + { + fprintf(stderr, "******_NXCollectPropertyHandler: WARNING! Null property data stored for resource [%d].\n", + state -> resource); + } + #endif + + _NXNotifyProperty(dpy, state -> resource, True); + + Xfree(async_head); + + return True; +} + +int NXGetCollectPropertyResource(Display *dpy) +{ + int i; + + for (i = 0; i < NXNumberOfResources; i++) + { + if (_NXCollectedProperties[i] == NULL) + { + return i; + } + } + + return -1; +} + +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); + + Xfree(state -> handler); + } + + if (state -> data != NULL) + { + Xfree(state -> data); + } + + Xfree(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 + 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 = Xmalloc(sizeof(_NXCollectPropertyState)); + handler = Xmalloc(sizeof(_XAsyncHandler)); + + if (state == NULL || handler == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectProperty: Failed to allocate memory with resource [%d].\n", + resource); + #endif + + if (state != NULL) + { + Xfree(state); + } + + if (handler != NULL) + { + Xfree(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; +} + +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; + + Xfree(state); + + _NXCollectedProperties[resource] = NULL; + + #ifdef TEST + 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; + + if ((rep -> generic.sequenceNumber % 65536) != + ((int)(state -> sequence) % 65536)) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Unmatched sequence [%d] for opcode [%d] " + "with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type, + (int) rep -> generic.length << 2); + #endif + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Going to handle asynchronous GrabPointer reply.\n"); + #endif + + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + + state -> handler = NULL; + + if (rep -> generic.type == X_Error) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Error received from X server for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyGrabPointer(dpy, state -> resource, False); + + _NXCollectedGrabPointers[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Matched request with sequence [%ld].\n", + state -> sequence); + #endif + + async_size = SIZEOF(xGrabPointerReply); + + async_head = Xmalloc(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; + + Xfree(state); + + return False; + } + + #ifdef TEST + 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; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + 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); + + Xfree(async_head); + + return True; +} + +int NXGetCollectGrabPointerResource(Display *dpy) +{ + int i; + + for (i = 0; i < NXNumberOfResources; i++) + { + if (_NXCollectedGrabPointers[i] == NULL) + { + return i; + } + } + + return -1; +} + +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); + + Xfree(state -> handler); + } + + Xfree(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 + fprintf(stderr, "******NXCollectGrabPointer: Sending message opcode [%d] sequence [%ld] " + "for resource [%d].\n", X_GrabPointer, dpy -> request, resource); + #endif + + state = Xmalloc(sizeof(_NXCollectGrabPointerState)); + handler = Xmalloc(sizeof(_XAsyncHandler)); + + if (state == NULL || handler == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectGrabPointer: Failed to allocate memory with resource [%d].\n", + resource); + #endif + + if (state != NULL) + { + Xfree(state); + } + + if (handler != NULL) + { + Xfree(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; +} + +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; + + Xfree(state); + + _NXCollectedGrabPointers[resource] = NULL; + + #ifdef TEST + 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; + + if ((rep -> generic.sequenceNumber % 65536) != + ((int)(state -> sequence) % 65536)) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Unmatched sequence [%d] for opcode [%d] " + "with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type, + (int) rep -> generic.length << 2); + #endif + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Going to handle asynchronous GetInputFocus reply.\n"); + #endif + + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + + state -> handler = NULL; + + if (rep -> generic.type == X_Error) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Error received from X server for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyInputFocus(dpy, state -> resource, False); + + _NXCollectedInputFocuses[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Matched request with sequence [%ld].\n", + state -> sequence); + #endif + + async_size = SIZEOF(xGetInputFocusReply); + + async_head = Xmalloc(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; + + Xfree(state); + + return False; + } + + #ifdef TEST + 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; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + 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); + + Xfree(async_head); + + return True; +} + +int NXGetCollectInputFocusResource(Display *dpy) +{ + int i; + + for (i = 0; i < NXNumberOfResources; i++) + { + if (_NXCollectedInputFocuses[i] == NULL) + { + return i; + } + } + + return -1; +} + +int NXCollectInputFocus(Display *dpy, unsigned int resource) +{ + 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); + + Xfree(state -> handler); + } + + Xfree(state); + + _NXCollectedInputFocuses[resource] = NULL; + } + + LockDisplay(dpy); + + GetEmptyReq(GetInputFocus, req); + + #ifdef TEST + fprintf(stderr, "******NXCollectInputFocus: Sending message opcode [%d] sequence [%ld] for resource [%d].\n", + X_GetInputFocus, dpy -> request, resource); + #endif + + state = Xmalloc(sizeof(_NXCollectInputFocusState)); + handler = Xmalloc(sizeof(_XAsyncHandler)); + + if (state == NULL || handler == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectInputFocus: Failed to allocate memory with resource [%d].\n", + resource); + #endif + + if (state != NULL) + { + Xfree(state); + } + + if (handler != NULL) + { + Xfree(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; +} + +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; + + Xfree(state); + + _NXCollectedInputFocuses[resource] = NULL; + + #ifdef TEST + 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; + + unsigned int ii; + + while (i < size) + { + fprintf(stderr, "[%d]\t", i); + + for (ii = 0; i < size && ii < 8; i++, ii++) + { + fprintf(stderr, "%d\t", (unsigned int) (buffer[i])); + } + + fprintf(stderr, "\n"); + } + } +} + +#endif |