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