diff options
Diffstat (limited to 'nx-X11')
47 files changed, 9278 insertions, 47 deletions
diff --git a/nx-X11/programs/Xserver/Imakefile b/nx-X11/programs/Xserver/Imakefile index 7bb8132da..a07121ff6 100644 --- a/nx-X11/programs/Xserver/Imakefile +++ b/nx-X11/programs/Xserver/Imakefile @@ -214,21 +214,18 @@ NXAGENTDDXDIR = hw NXAGENTDIRS = $(STDDIRS) $(FBDIR) $(MIDAMAGEDIR) $(NXAGENTDDXDIR) $(DEPDIRS) NX_XCOMP_HEADERS = \ + ../../../nxcomp/MD5.h \ ../../../nxcomp/NXalert.h \ ../../../nxcomp/NX.h \ ../../../nxcomp/NXpack.h \ ../../../nxcomp/NXproto.h \ ../../../nxcomp/NXvars.h -NX_XCOMPEXT_HEADERS = \ - ../../../nxcompext/NXlib.h - NX_XCOMPSHAD_HEADERS = \ ../../../nxcompshad/Shadow.h NX_HEADERS = \ $(NX_XCOMP_HEADERS) \ - $(NX_XCOMPEXT_HEADERS) \ $(NX_XCOMPSHAD_HEADERS) BuildIncludes($(NX_HEADERS),nx,..) @@ -295,11 +292,17 @@ NXAGENTOBJS = hw/nxagent/miinitext.o \ XPMLIB = -lXpm XMLLIB = `pkg-config --libs libxml-2.0` PIXMANLIB = `pkg-config --libs pixman-1` +ZLIB = `pkg-config --libs zlib` +PNGLIB = `pkg-config --libs libpng` +JPEGLIB = -ljpeg + NXAGENT = hw/nxagent/LibraryTargetName(nxagent) -NXAGENTLIBS = PreFbLibs $(NXAGENT) FbPostFbLibs $(NXAGENT) $(MI) -NXAGENTSYSLIBS = $(LDPRELIBS) $(XLIB) $(SYSLIBS) $(XPMLIB) $(XMLLIB) $(PIXMANLIB) +NXCOMPEXT = hw/nxagent/compext/LibraryTargetName(compext) +NXAGENTLIBS = PreFbLibs $(NXAGENT) FbPostFbLibs $(NXCOMPEXT) $(NXAGENT) $(MI) +NXAGENTSYSLIBS = $(LDPRELIBS) $(XLIB) $(SYSLIBS) $(XPMLIB) $(XMLLIB) +NXCOMPEXTSYSLIBS = $(PIXMANLIB) $(ZLIB) $(PNGLIB) $(JPEGLIB) #if HasParallelMake -MakeMutex($(NXAGENTDIRS) $(NXAGENTOBJS) $(NXAGENTLIBS) $(NXAGENTSYSLIBS)) +MakeMutex($(NXAGENTDIRS) $(NXCOMPEXT) $(NXAGENTOBJS) $(NXAGENTLIBS) $(NXCOMPEXTSYSLIBS) $(NXAGENTSYSLIBS)) #endif #if ForceServerRemake $(NXAGENTOBJS) $(NXAGENTLIBS) $(NXAGENTSYSLIBS):: $(NXAGENTDIRS) @@ -314,26 +317,26 @@ $(NXAGENTOBJS) $(NXAGENTLIBS) $(NXAGENTSYSLIBS):: $(NXAGENTDIRS) NXAGENTNXLIBS = -L/usr/sfw/lib \ -L ../../../nxcomp \ -L../../../nx-X11/exports/lib \ - -L ../../../nxcompext -L ../../../nxcompshad \ + -L ../../../nxcompshad \ -lrt \ -lXcomp \ - -lXcompext -lXcompshad \ + -lXcompshad \ -lXrender -lXfixes -lXfont -lXcomposite -lXinerama -lXdmcp \ -lNX_X11 -lXext #elif defined(cygwinArchitecture) NXAGENTNXLIBS = -L ../../../nxcomp \ -L../../../nx-X11/exports/lib \ - -L ../../../nxcompext -L ../../../nxcompshad \ + -L ../../../nxcompshad \ -lXcomp \ - -lXcompext -lXcompshad \ + -lXcompshad \ -lXrender -lXfixes -lXfont -lXcomposite -lXdmcp \ -lNX_X11 -lXext #else NXAGENTNXLIBS = -L ../../../nxcomp \ -L../../../nx-X11/exports/lib \ - -L ../../../nxcompext -L ../../../nxcompshad \ + -L ../../../nxcompshad \ -lXcomp \ - -lXcompext -lXcompshad \ + -lXcompshad \ -lXrender -lXfixes -lXfont -lXcomposite -lXinerama -lXdmcp \ -lNX_X11 -lXext #endif @@ -346,7 +349,7 @@ NX_XSHADOWLIBNAME = libXcompshad.so #endif ServerTarget(nxagent,$(NXAGENTDIRS),$(NXAGENTOBJS), \ - $(LIBCWRAPPER) $(NXAGENTLIBS) $(LOADABLEEXTS),$(NXAGENTSYSLIBS) $(NXAGENTNXLIBS)) + $(LIBCWRAPPER) $(NXCOMPEXT) $(NXAGENTLIBS) $(LOADABLEEXTS),$(NXCOMPEXTSYSLIBS) $(NXAGENTSYSLIBS) $(NXAGENTNXLIBS)) /* * Hard coded target to build a static nxagent server. @@ -356,8 +359,8 @@ nxagent_static: nxagent $(MV) nxagent_static nxagent_static.bak; \ else exit 0; fi $(CCLINK) -o nxagent_static -static $(LDOPTIONS) $(NXAGENTOBJS) \ - $(LIBCWRAPPER) $(NXAGENTLIBS) $(LOADABLEEXTS) $(LDLIBS) \ - $(NXAGENTSYSLIBS) $(EXTRA_LOAD_FLAGS) + $(LIBCWRAPPER) $(NXCOMPEXT) $(NXAGENTLIBS) $(LOADABLEEXTS) $(LDLIBS) \ + $(NXCOMPEXTSYSLIBS) $(NXAGENTSYSLIBS) $(EXTRA_LOAD_FLAGS) /* * Hard coded target to build a static nxagent server except for libX11 and libXext. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Args.c b/nx-X11/programs/Xserver/hw/nxagent/Args.c index 7d256f5c5..4dbb003f2 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Args.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c @@ -75,7 +75,7 @@ is" without express or implied warranty. * NX includes and definitions. */ -#include <nx/NXlib.h> +#include "compext/Compext.h" #include <nx/NXpack.h> /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Client.c b/nx-X11/programs/Xserver/hw/nxagent/Client.c index 061269a0e..44d48d0e0 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Client.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Client.c @@ -57,7 +57,7 @@ * definition of GC in Agent.h. */ -#include <nx/NXlib.h> +#include "compext/Compext.h" /* * Set here the required log level. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c index 802dcfdac..c18775bfc 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c @@ -46,7 +46,7 @@ * Use asyncronous get property replies. */ -#include <nx/NXlib.h> +#include "compext/Compext.h" /* * Set here the required log level. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Cursor.c b/nx-X11/programs/Xserver/hw/nxagent/Cursor.c index 8698308b8..1db26b7ec 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Cursor.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Cursor.c @@ -65,7 +65,7 @@ is" without express or implied warranty. #include "windowstr.h" #include "resource.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" /* * Set here the required log level. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Dialog.c b/nx-X11/programs/Xserver/hw/nxagent/Dialog.c index e7d5ba077..da448a1cd 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Dialog.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Dialog.c @@ -42,7 +42,7 @@ #include "Dialog.h" #include <nx/NX.h> -#include <nx/NXlib.h> +#include "compext/Compext.h" #include <nx/NXalert.h> /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Display.c b/nx-X11/programs/Xserver/hw/nxagent/Display.c index f1fb1e902..d8e6aa7e3 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Display.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Display.c @@ -87,7 +87,7 @@ is" without express or implied warranty. #include "Handlers.h" #include <nx/NX.h> -#include <nx/NXlib.h> +#include "compext/Compext.h" #include NXAGENT_ICON_NAME #include X2GOAGENT_ICON_NAME diff --git a/nx-X11/programs/Xserver/hw/nxagent/Drawable.c b/nx-X11/programs/Xserver/hw/nxagent/Drawable.c index 424f07ef3..8d6f4139d 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Drawable.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Drawable.c @@ -42,7 +42,7 @@ #include "Reconnect.h" #include "GCOps.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" #include "mibstorest.h" diff --git a/nx-X11/programs/Xserver/hw/nxagent/Events.c b/nx-X11/programs/Xserver/hw/nxagent/Events.c index 4f3875780..371780a92 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Events.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Events.c @@ -102,7 +102,7 @@ #include <nx/Shadow.h> #include "X11/include/Xrandr_nxagent.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" /* * Set here the required log level. Please note diff --git a/nx-X11/programs/Xserver/hw/nxagent/Font.c b/nx-X11/programs/Xserver/hw/nxagent/Font.c index 3d0cc4264..5b9c31106 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Font.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Font.c @@ -58,7 +58,7 @@ is" without express or implied warranty. #include "Args.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" #include <nx/NXalert.h> #include <string.h> diff --git a/nx-X11/programs/Xserver/hw/nxagent/GCOps.c b/nx-X11/programs/Xserver/hw/nxagent/GCOps.c index 8961ff6f7..1bca067fc 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/GCOps.c +++ b/nx-X11/programs/Xserver/hw/nxagent/GCOps.c @@ -58,7 +58,7 @@ is" without express or implied warranty. #include "Args.h" #include "Screen.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" /* * Set here the required log level. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Handlers.c b/nx-X11/programs/Xserver/hw/nxagent/Handlers.c index 36244c4a3..1721be9fb 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Handlers.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Handlers.c @@ -41,7 +41,7 @@ #include "Millis.h" #define Window XlibWindow -#include <nx/NXlib.h> +#include "compext/Compext.h" #undef Window #include <nx/Shadow.h> @@ -992,14 +992,14 @@ void nxagentHandleCollectInputFocusEvent(int resource) * While we don't even need window or revert_to later on, a discrepancy in * data type sizes between the X server (Window being a 32bit ID) and * the Xlib (Window being a 64bit ID) will lead to stack corruption here. - * Calling functions from nxcompext from nxagent sounds like a very bad idea + * Calling functions from CompExt from nxagent sounds like a very bad idea * to begin with, but let's assume that's necessary for now and work around * the corruption issue. * - * Even though the NXlib header shows that the function expects a Window-sized + * Even though the CompExt header shows that the function expects a Window-sized * parameter, it's not the Window type as defined and used within the X.Org * Server, but an Xlib type. Hence, we'll be using the "XlibWindow" type here - * and to avoid compiler warnings, "rewrite" the NXlib.h header file via + * and to avoid compiler warnings, "rewrite" the CompExt.h header file via * overriding the original "Window" type with the XlibWindow type, including * the header file and undefining the macro again, essentially unshadowing * the original type. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Image.c b/nx-X11/programs/Xserver/hw/nxagent/Image.c index 5638765f2..4fa98f842 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Image.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Image.c @@ -45,7 +45,7 @@ #include "Pixels.h" #include "Utils.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" #include <nx/NXpack.h> /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Imakefile b/nx-X11/programs/Xserver/hw/nxagent/Imakefile index bea18b4ca..ae0a9cf3a 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Imakefile +++ b/nx-X11/programs/Xserver/hw/nxagent/Imakefile @@ -1,7 +1,11 @@ #include <Server.tmpl> + NULL = +SUBDIRS = compext \ + $(NULL) + #ifdef OS2Architecture SRCS1 = os2Stub.c OBJS1 = os2Stub.o @@ -156,9 +160,6 @@ INCLUDES = \ $(VFBINCLUDES) \ `pkg-config --cflags-only-I libxml-2.0` \ `pkg-config --cflags-only-I pixman-1` \ - `pkg-config --cflags-only-I zlib` \ - `pkg-config --cflags-only-I libjpeg` \ - `pkg-config --cflags-only-I libpng` \ $(NULL) #ifdef SunArchitecture INCLUDES = \ @@ -180,7 +181,6 @@ INCLUDES = \ `pkg-config --cflags-only-I libxml-2.0` \ `pkg-config --cflags-only-I pixman-1` \ `pkg-config --cflags-only-I zlib` \ - `pkg-config --cflags-only-I libjpeg` \ `pkg-config --cflags-only-I libpng` \ $(NULL) #else @@ -197,7 +197,6 @@ INCLUDES = \ -I../../miext/damage \ -I../../miext/cw \ -I../../../../../nxcomp \ - -I../../../../../nxcompext \ -I../../../../../nxcompshad \ -I../../../../extras/Mesa/include \ -I$(EXTINCSRC) -I$(XINCLUDESRC) \ @@ -205,7 +204,6 @@ INCLUDES = \ `pkg-config --cflags-only-I libxml-2.0` \ `pkg-config --cflags-only-I pixman-1` \ `pkg-config --cflags-only-I zlib` \ - `pkg-config --cflags-only-I libjpeg` \ `pkg-config --cflags-only-I libpng` \ $(NULL) #endif @@ -274,3 +272,7 @@ NormalLibraryObjectRule() NormalLibraryTarget(nxagent,$(OBJS)) DependTarget() + +#define IHaveSubdirs +MakeSubdirs($(SUBDIRS)) +DependSubdirs($(SUBDIRS)) diff --git a/nx-X11/programs/Xserver/hw/nxagent/Init.c b/nx-X11/programs/Xserver/hw/nxagent/Init.c index 52f98d8dd..06703aa4e 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Init.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Init.c @@ -75,7 +75,7 @@ is" without express or implied warranty. #include "Error.h" #include <nx/NX.h> -#include <nx/NXlib.h> +#include "compext/Compext.h" #include "Reconnect.h" /* * Set here the required log level. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c index 2fd42d3cf..88af5d400 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c @@ -61,7 +61,7 @@ is" without express or implied warranty. #include "Options.h" #include "Error.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" #include <nx/Shadow.h> diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXevents.c b/nx-X11/programs/Xserver/hw/nxagent/NXevents.c index 8f79245f8..f507e5f71 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/NXevents.c +++ b/nx-X11/programs/Xserver/hw/nxagent/NXevents.c @@ -137,7 +137,7 @@ of the copyright holder. #include "../../dix/events.c" -#include <nx/NXlib.h> +#include "compext/Compext.h" #include "Events.h" #include "Windows.h" diff --git a/nx-X11/programs/Xserver/hw/nxagent/Pixmap.c b/nx-X11/programs/Xserver/hw/nxagent/Pixmap.c index 894d749a2..05558e34f 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Pixmap.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Pixmap.c @@ -50,7 +50,7 @@ #include "Holder.h" #include "Args.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" #include <nx/NXpack.h> RESTYPE RT_NX_PIXMAP; diff --git a/nx-X11/programs/Xserver/hw/nxagent/Pointer.c b/nx-X11/programs/Xserver/hw/nxagent/Pointer.c index 20daec2a3..c59230724 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Pointer.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Pointer.c @@ -54,7 +54,7 @@ is" without express or implied warranty. #include "Events.h" #include "Options.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" /* * Set here the required log level. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c index 65e2ae795..ee21bff69 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c @@ -58,7 +58,7 @@ #endif #include <nx/NX.h> -#include <nx/NXlib.h> +#include "compext/Compext.h" #include <nx/NXalert.h> /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Rootless.c b/nx-X11/programs/Xserver/hw/nxagent/Rootless.c index 59b588738..bb961e5a8 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Rootless.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Rootless.c @@ -39,7 +39,7 @@ #include "Atoms.h" #include "Trap.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" /* * Set here the required log level. diff --git a/nx-X11/programs/Xserver/hw/nxagent/Screen.c b/nx-X11/programs/Xserver/hw/nxagent/Screen.c index 0235ebf1b..e6451292f 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Screen.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Screen.c @@ -102,7 +102,7 @@ is" without express or implied warranty. #include "Xatom.h" #include "Xproto.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" #include "mibstorest.h" diff --git a/nx-X11/programs/Xserver/hw/nxagent/Split.c b/nx-X11/programs/Xserver/hw/nxagent/Split.c index 61a749395..9b9691b02 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Split.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Split.c @@ -34,7 +34,7 @@ #include "Events.h" #include "GCs.h" -#include <nx/NXlib.h> +#include "compext/Compext.h" /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Window.c b/nx-X11/programs/Xserver/hw/nxagent/Window.c index f81e08ebc..982c88314 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Window.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Window.c @@ -65,7 +65,7 @@ #include "Events.h" #include <nx/NX.h> -#include <nx/NXlib.h> +#include "compext/Compext.h" #include "Xatom.h" diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Alpha.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Alpha.c new file mode 100644 index 000000000..11450d69d --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Alpha.c @@ -0,0 +1,50 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <zlib.h> + +#include "Compext.h" + +#include "Alpha.h" +#include "Z.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define ALPHA_COMPRESSION_LEVEL 1 +#define ALPHA_COMPRESSION_THRESHOLD 32 +#define ALPHA_COMPRESSION_STRATEGY Z_RLE + +static int alphaCompressionLevel = ALPHA_COMPRESSION_LEVEL; +static int alphaCompressionThreshold = ALPHA_COMPRESSION_THRESHOLD; +static int alphaCompressionStrategy = ALPHA_COMPRESSION_STRATEGY; + +char *AlphaCompressData(const char *data, unsigned int size, unsigned int *compressed_size) +{ + return ZCompressData(data, size, alphaCompressionThreshold, alphaCompressionLevel, + alphaCompressionStrategy, compressed_size); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Alpha.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Alpha.h new file mode 100644 index 000000000..d7ac4e78e --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Alpha.h @@ -0,0 +1,45 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Alpha_H +#define Alpha_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *AlphaCompressData( +#if NeedFunctionPrototypes + const char* /* data */, + unsigned int /* size */, + unsigned int* /* compressed_size */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* Alpha_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Bitmap.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Bitmap.c new file mode 100644 index 000000000..d906118d0 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Bitmap.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#include "Compext.h" + +#include "Bitmap.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +char *BitmapCompressData(XImage *image, unsigned int *size) +{ + if (image -> bits_per_pixel != 32) + { + #ifdef TEST + fprintf(stderr, "******BitmapCompressData: Nothing to do with image of [%d] bpp and size [%d].\n", + image -> bits_per_pixel, image -> bytes_per_line * image -> height); + #endif + + *size = image -> bytes_per_line * image -> height; + + return image -> data; + } + else + { + /* + * Remove the 4th byte from the bitmap. + */ + + char *data; + + char *next_src; + char *next_dst; + + #ifdef TEST + + if (image -> bytes_per_line != 4 * image -> width) + { + fprintf(stderr, "******BitmapCompressData: PANIC! Image as [%d] bytes per line with expected [%d].\n", + image -> bytes_per_line, 4 * image -> width); + + return NULL; + } + + #endif + + *size = image -> width * image -> height * 3; + + data = Xmalloc(*size); + + if (data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******BitmapCompressData: PANIC! Failed to allocate [%d] bytes for the destination.\n", + *size); + #endif + + *size = image -> bytes_per_line * image -> height; + + return image -> data; + } + + next_src = image -> data; + next_dst = data; + + if (image -> byte_order == LSBFirst) + { + while (next_src < image -> data + + image -> bytes_per_line * image -> height) + { + *next_dst++ = *next_src++; + *next_dst++ = *next_src++; + *next_dst++ = *next_src++; + + next_src++; + } + } + else + { + while (next_src < image -> data + + image -> bytes_per_line * image -> height) + { + next_src++; + + *next_dst++ = *next_src++; + *next_dst++ = *next_src++; + *next_dst++ = *next_src++; + } + } + + return data; + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Bitmap.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Bitmap.h new file mode 100644 index 000000000..e45836d11 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Bitmap.h @@ -0,0 +1,44 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Bitmap_H +#define Bitmap_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *BitmapCompressData( +#if NeedFunctionPrototypes + XImage* /* image */, + unsigned int* /* compressed_size */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* Bitmap_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Clean.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Clean.c new file mode 100644 index 000000000..7a6d81b6b --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Clean.c @@ -0,0 +1,349 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <signal.h> + +#include "os.h" + +#include "Compext.h" + +#include "Clean.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int CleanXYImage(XImage *image) +{ + int i, j, k, plane; + + int bitsToClean = (image -> bytes_per_line << 3) - image -> width - image -> xoffset; + + unsigned int bytesToClean = bitsToClean >> 3; + + bitsToClean &= 7; + + for (k = 0; k < image -> depth; k++) + { + plane = k * (image -> bytes_per_line * image -> height); + + for (i = 1; i <= image -> height; i++) + { + if (image -> byte_order == image -> bitmap_bit_order) + { + for (j = 1; j <= bytesToClean; j++) + { + image -> data[plane + i * (image -> bytes_per_line) - j] = 0x00; + } + } + else + { + for (j = bytesToClean; j >= 1; j--) + { + image -> data[plane + i * (image -> bytes_per_line) - j] = 0x00; + } + } + + if (image -> bitmap_bit_order == MSBFirst) + { + image -> data[plane + i * (image -> bytes_per_line) - j] &= 0xff << bitsToClean; + } + else + { + image -> data[plane + i * (image -> bytes_per_line) - j] &= 0xff >> bitsToClean; + } + } + } + + return 1; +} + +int CleanZImage(XImage *image) +{ + unsigned int bytesToClean; + unsigned int j; + unsigned int imageLength; + + #ifdef TEST + fprintf(stderr, "*****CleanZImage: Going to clean image of [%d] bits per pixel.\n", + image -> bits_per_pixel); + #endif + + switch (image -> bits_per_pixel) + { + case 32: + { + /* + * The caller should pay attention at extracting + * the alpha channel prior to cleaning the image. + * Cleaning an image which is carrying the alpha + * channel will result in the image being treated + * as fully transparent. + */ + + register int i; + + bytesToClean = image -> bytes_per_line * image -> height; + + #ifdef DEBUG + fprintf(stderr, "*****CleanZImage: Cleaning [%d] bytes with bits per pixel [%d] " + "width [%d] bytes per line [%d] height [%d].\n", bytesToClean, + image -> bits_per_pixel, image -> width, image -> + bytes_per_line, image -> height); + #endif + + if (image -> byte_order == LSBFirst) + { + for (i = 3; i < bytesToClean; i += 4) + { + ((unsigned char *) image -> data)[i] = 0x00; + } + } + else + { + for (i = 0; i < bytesToClean; i += 4) + { + ((unsigned char *) image -> data)[i] = 0x00; + } + } + + break; + } + case 24: + case 15: + case 16: + case 8: + { + register int i, j; + + bytesToClean = image -> bytes_per_line - + ((image -> width * image -> bits_per_pixel) >> 3); + + for (i = 1; i <= image -> height; i++) + { + for (j = bytesToClean; j > 0; j--) + { + ((unsigned char *) image -> data)[(i * image -> bytes_per_line) - j] = 0x00; + } + } + + break; + } + default: + { + #ifdef PANIC + fprintf(stderr, "*****CleanZImage: PANIC! Cannot clean image with [%d] bits per pixel.\n", + image -> bits_per_pixel); + #endif + } + } + + /* + * Clean the padding bytes at the real + * end of the buffer. + */ + + imageLength = image -> bytes_per_line * image -> height; + + bytesToClean = imageLength % 4; + + for (j = 0; j < bytesToClean; j++) + { + ((unsigned char *)image -> data)[(imageLength + j)] = 0x00; + } + + return 1; +} + +/* + * Copy a clean version of src_image into dst_image. + * This code is not taking care of the image format. + * The agent doesn't use it and you have to consider + * it unsupported. + */ + +int CopyAndCleanImage(XImage *src_image, XImage *dst_image) +{ + register long data_size; + register int i; + + data_size = (src_image -> bytes_per_line * src_image -> height) >> 2; + + #ifdef WARNING + fprintf(stderr, "******CleanImage: WARNING! Function called with image of [%d] bits per pixel.\n", + src_image -> bits_per_pixel); + #endif + + switch (src_image -> bits_per_pixel) + { + case 32: + { + unsigned int mask; + + if (src_image -> byte_order == MSBFirst) + { + mask = 0xffffff00; + } + else + { + mask = 0x00ffffff; + } + for (i = 0; i < data_size; i++) + { + ((unsigned int *)dst_image -> data)[i] = ((unsigned int *)src_image -> data)[i] & mask; + } + + break; + } + + case 24: + { + unsigned int bytes_to_clean; + + for (i = 0; i < data_size; i++) + { + ((unsigned int *)dst_image -> data)[i] = ((unsigned int *)src_image -> data)[i]; + } + + bytes_to_clean = dst_image -> bytes_per_line - ((dst_image -> width * + dst_image -> bits_per_pixel) >> 3); + + if (bytes_to_clean) + { + register unsigned int mask = 0xffffffff; + register int line_size; + register int i; + + line_size = dst_image -> bytes_per_line >> 2; + + if (dst_image -> byte_order == MSBFirst) + { + mask = mask << (bytes_to_clean << 3); + } + else + { + mask = mask >> (bytes_to_clean << 3); + } + + for (i = 0; i < dst_image -> height;) + { + ((unsigned char *)dst_image -> data)[(++i * line_size) -1] &= mask; + } + } + + break; + } + + case 15: + case 16: + { + for (i = 0; i < data_size; i++) + { + ((unsigned int *) dst_image -> data)[i] = ((unsigned int *) src_image -> data)[i]; + } + + if (src_image -> width & 0x00000001) + { + int card32_per_line = dst_image -> bytes_per_line >> 2; + + for (i = 0; i < dst_image -> height;) + { + ((unsigned int *) dst_image -> data)[(++i * card32_per_line) -1] &= 0x0000ffff; + } + } + + break; + } + + case 8: + { + unsigned int mask = 0x00000000; + + switch (dst_image -> width % 4) + { + case 3: + { + mask = 0x00ffffff; + + break; + } + case 2: + { + mask = 0x0000ffff; + + break; + } + case 1: + { + mask = 0x000000ff; + + break; + } + default: + { + /* + * Nothing to clean. + */ + + break; + } + } + + for (i = 0; i < data_size; i++) + { + ((unsigned int *) dst_image -> data)[i] = ((unsigned int *) src_image -> data)[i]; + } + + if (mask) + { + int card32_per_line; + int i; + + card32_per_line = dst_image -> bytes_per_line >> 2; + + for (i = 0; i < dst_image -> height; i++) + { + ((unsigned int *) dst_image -> data)[(++i * card32_per_line) -1] &= mask; + } + } + + break; + } + + default: + { + #ifdef PANIC + fprintf(stderr, "******CleanImage: PANIC! Cannot clean image of [%d] bits per pixel.\n", + src_image -> bits_per_pixel); + #endif + + return 0; + } + } + + return 1; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Clean.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Clean.h new file mode 100644 index 000000000..510af1dfb --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Clean.h @@ -0,0 +1,44 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Clean_H +#define Clean_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nx-X11/Xlib.h> + +int CleanXYImage(XImage *image); +int CleanZImage(XImage *image); + +int CopyAndCleanImage(XImage *src_image, XImage *dst_image); + +#ifdef __cplusplus +} +#endif + +#endif /* Clean_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Colormap.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Colormap.c new file mode 100644 index 000000000..6b025542d --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Colormap.c @@ -0,0 +1,50 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <zlib.h> + +#include "Compext.h" + +#include "Colormap.h" +#include "Z.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define COLORMAP_COMPRESSION_LEVEL 4 +#define COLORMAP_COMPRESSION_THRESHOLD 32 +#define COLORMAP_COMPRESSION_STRATEGY Z_DEFAULT_STRATEGY + +static int colormapCompressionLevel = COLORMAP_COMPRESSION_LEVEL; +static int colormapCompressionThreshold = COLORMAP_COMPRESSION_THRESHOLD; +static int colormapCompressionStrategy = COLORMAP_COMPRESSION_STRATEGY; + +char *ColormapCompressData(const char *data, unsigned int size, unsigned int *compressed_size) +{ + return ZCompressData(data, size, colormapCompressionThreshold, colormapCompressionLevel, + colormapCompressionStrategy, compressed_size); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Colormap.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Colormap.h new file mode 100644 index 000000000..e30f4fdab --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Colormap.h @@ -0,0 +1,45 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef ColormapComp_H +#define ColormapComp_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *ColormapCompressData( +#if NeedFunctionPrototypes + const char* /* data */, + unsigned int /* size */, + unsigned int* /* compressed_size */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* ColormapComp_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Compext.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Compext.c new file mode 100644 index 000000000..a91b0c568 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Compext.c @@ -0,0 +1,4778 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#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" + + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +/* + * Maximum number of colors allowed in + * Png encoding. + */ + +#define NB_COLOR_MAX 256 + +/* + * Dummy error handlers used internally to catch + * Xlib failures in replies. + */ + +static int _NXInternalReplyErrorFunction(Display *dpy, XErrorEvent *error); + +static void _NXInternalLostSequenceFunction(Display *dpy, unsigned long newseq, + unsigned long lastseq, unsigned int type); + +/* + * Resource ids that can be requested by + * the client for use in split or unpack + * operations. + */ + +static unsigned char _NXSplitResources[NXNumberOfResources]; +static unsigned char _NXUnpackResources[NXNumberOfResources]; + +static Display *_NXDisplayInitialized = NULL; + +/* + * Used in asynchronous handling of + * GetImage replies. + */ + +typedef struct +{ + unsigned long sequence; + unsigned int resource; + unsigned long mask; + int format; + int width; + int height; + _XAsyncHandler *handler; + XImage *image; +} _NXCollectImageState; + +static _NXCollectImageState *_NXCollectedImages[NXNumberOfResources]; + +/* + * Used in asynchronous handling of + * GetProperty replies. + */ + +typedef struct +{ + unsigned long sequence; + unsigned int resource; + Window window; + Atom property; + Atom type; + int format; + unsigned long items; + unsigned long after; + _XAsyncHandler *handler; + char *data; +} _NXCollectPropertyState; + +static _NXCollectPropertyState *_NXCollectedProperties[NXNumberOfResources]; + +/* + * Used in asynchronous handling of + * GrabPointer replies. + */ + +typedef struct +{ + unsigned long sequence; + unsigned int resource; + int status; + _XAsyncHandler *handler; +} _NXCollectGrabPointerState; + +static _NXCollectGrabPointerState *_NXCollectedGrabPointers[NXNumberOfResources]; + +/* + * Used in asynchronous handling of + * GetInputFocus replies. + */ + +typedef struct +{ + unsigned long sequence; + unsigned int resource; + Window focus; + int revert_to; + _XAsyncHandler *handler; +} _NXCollectInputFocusState; + +static _NXCollectInputFocusState *_NXCollectedInputFocuses[NXNumberOfResources]; + +/* + * Used by functions handling cache of + * packed images. + */ + +#define MD5_LENGTH 16 + +typedef struct +{ + md5_byte_t *md5; + XImage *image; + unsigned int method; +} _NXImageCacheEntry; + +int NXImageCacheSize = 0; +int NXImageCacheHits = 0; +int NXImageCacheOps = 0; + +_NXImageCacheEntry *NXImageCache = NULL; + +#ifdef DUMP + +void _NXCacheDump(const char *label); + +void _NXDumpData(const unsigned char *buffer, unsigned int size); + +#endif + +/* + * From X11/PutImage.c. + * + * Cancel a GetReq operation, before doing + * _XSend or Data. + */ + +#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) +#define UnGetReq(name)\ + dpy->bufptr -= SIZEOF(x##name##Req);\ + dpy->request-- +#else +#define UnGetReq(name)\ + dpy->bufptr -= SIZEOF(x/**/name/**/Req);\ + dpy->request-- +#endif + +#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) +#define UnGetEmptyReq()\ + dpy->bufptr -= 4;\ + dpy->request-- +#else +#define UnGetEmptyReq(name)\ + dpy->bufptr -= 4;\ + dpy->request-- +#endif + +/* + * From X11/ImUtil.c. + */ + +extern int _XGetBitsPerPixel(Display *dpy, int depth); +extern int _XGetScanlinePad(Display *dpy, int depth); + +#define ROUNDUP(nbytes, pad) (((nbytes) + ((pad) - 1)) & \ + ~(long)((pad) - 1)) + +static unsigned int DepthOnes(unsigned long mask) +{ + register unsigned long y; + + y = (mask >> 1) &033333333333; + y = mask - y - ((y >>1) & 033333333333); + return ((unsigned int) (((y + (y >> 3)) & + 030707070707) % 077)); +} + +#define CanMaskImage(image, mask) \ +\ +(image -> format == ZPixmap && mask != NULL && \ + (image -> depth == 32 || image -> depth == 24 || \ + (image -> depth == 16 && (image -> red_mask == 0xf800 && \ + image -> green_mask == 0x7e0 && image -> blue_mask == 0x1f)))) + +#define ShouldMaskImage(image, mask) (mask -> color_mask != 0xff) + +/* + * Initialize and reset the internal structures. + */ + +extern int _NXInternalInitResources(Display *dpy); +extern int _NXInternalResetResources(Display *dpy); +extern int _NXInternalInitEncoders(Display *dpy); +extern int _NXInternalResetEncoders(Display *dpy); + +int NXInitDisplay(Display *dpy) +{ + #ifdef TEST + fprintf(stderr, "******NXInitDisplay: Called for display at [%p].\n", (void *) dpy); + #endif + + if (_NXDisplayInitialized == NULL) + { + _NXInternalInitResources(dpy); + + _NXInternalInitEncoders(dpy); + + _NXDisplayInitialized = dpy; + + return 1; + } + + #ifdef TEST + fprintf(stderr, "******NXInitDisplay: WARNING! Internal structures already initialized.\n"); + #endif + + return 0; +} + +int NXResetDisplay(Display *dpy) +{ + #ifdef TEST + fprintf(stderr, "******NXResetDisplay: Called for display at [%p].\n", (void *) dpy); + #endif + + if (_NXDisplayInitialized != NULL) + { + _NXInternalResetResources(dpy); + + _NXInternalResetEncoders(dpy); + + _NXDisplayInitialized = NULL; + + return 1; + } + + #ifdef TEST + fprintf(stderr, "******NXResetDisplay: WARNING! Internal structures already reset.\n"); + #endif + + return 0; +} + +int _NXInternalInitResources(Display *dpy) +{ + return _NXInternalResetResources(dpy); +} + +int _NXInternalResetResources(Display *dpy) +{ + int i; + + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: Clearing all the internal structures.\n"); + #endif + + for (i = 0; i < NXNumberOfResources; i++) + { + _NXSplitResources[i] = 0; + _NXUnpackResources[i] = 0; + + if (_NXCollectedImages[i] != NULL) + { + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing collect image data " + "for resource [%d].\n", i); + #endif + + if (_NXCollectedImages[i] -> handler != NULL) + { + DeqAsyncHandler(dpy, _NXCollectedImages[i] -> handler); + + Xfree(_NXCollectedImages[i] -> handler); + } + + if (_NXCollectedImages[i] -> image != NULL) + { + XDestroyImage(_NXCollectedImages[i] -> image); + } + + Xfree(_NXCollectedImages[i]); + + _NXCollectedImages[i] = NULL; + } + + if (_NXCollectedProperties[i] != NULL) + { + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing collect property data " + "for resource [%d].\n", i); + #endif + + if (_NXCollectedProperties[i] -> handler != NULL) + { + DeqAsyncHandler(dpy, _NXCollectedProperties[i] -> handler); + + Xfree(_NXCollectedProperties[i] -> handler); + } + + if (_NXCollectedProperties[i] -> data != NULL) + { + Xfree(_NXCollectedProperties[i] -> data); + } + + Xfree(_NXCollectedProperties[i]); + + _NXCollectedProperties[i] = NULL; + } + + if (_NXCollectedGrabPointers[i] != NULL) + { + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing grab pointer data " + "for resource [%d].\n", i); + #endif + + if (_NXCollectedGrabPointers[i] -> handler != NULL) + { + DeqAsyncHandler(dpy, _NXCollectedGrabPointers[i] -> handler); + + Xfree(_NXCollectedGrabPointers[i] -> handler); + } + + Xfree(_NXCollectedGrabPointers[i]); + + _NXCollectedGrabPointers[i] = NULL; + } + + if (_NXCollectedInputFocuses[i] != NULL) + { + #ifdef TEST + fprintf(stderr, "******_NXInternalResetResources: WARNING! Clearing collect input focus data " + "for resource [%d].\n", i); + #endif + + if (_NXCollectedInputFocuses[i] -> handler != NULL) + { + DeqAsyncHandler(dpy, _NXCollectedInputFocuses[i] -> handler); + + Xfree(_NXCollectedInputFocuses[i] -> handler); + } + + Xfree(_NXCollectedInputFocuses[i]); + + _NXCollectedInputFocuses[i] = NULL; + } + } + + return 1; +} + +int _NXInternalInitEncoders(Display *dpy) +{ + ZInitEncoder(); + + return 1; +} + +int _NXInternalResetEncoders(Display *dpy) +{ + ZResetEncoder(); + + return 1; +} + +int NXSetDisplayPolicy(Display *dpy, int policy) +{ + if (policy == NXPolicyImmediate) + { + return NXTransPolicy(NX_FD_ANY, NX_POLICY_IMMEDIATE); + } + else + { + return NXTransPolicy(NX_FD_ANY, NX_POLICY_DEFERRED); + } +} + +int NXSetDisplayBuffer(Display *dpy, int size) +{ + /* + * This is not multi-thread safe, so, + * if you have threads, be sure that + * they are stopped. + */ + + char *buffer; + + XFlush(dpy); + + if (dpy -> bufmax - size == dpy -> buffer) + { + #ifdef TEST + fprintf(stderr, "******NXSetDisplayBuffer: Nothing to do with buffer size matching.\n"); + #endif + + return 1; + } + else if (dpy -> bufptr != dpy -> buffer) + { + #ifdef PANIC + fprintf(stderr, "******NXSetDisplayBuffer: PANIC! The display buffer is not empty.\n"); + #endif + + return -1; + } + else if ((buffer = Xcalloc(1, size)) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXSetDisplayBuffer: PANIC! Can't allocate [%d] bytes for the buffer.\n", + size); + #endif + + return -1; + } + + if (dpy -> buffer != NULL) + { + Xfree(dpy -> buffer); + } + + dpy -> buffer = buffer; + dpy -> bufptr = dpy -> buffer; + dpy -> bufmax = dpy -> bufptr + size; + + #ifdef TEST + fprintf(stderr, "******NXSetDisplayBuffer: Set the display output buffer size to [%d].\n", + size); + #endif + + return 1; +} + +/* + * If set, the Popen() function in the X server + * wil remove the LD_LIBRARY_PATH variable from + * the environment before calling the execl() + * function on the child process. + */ + +int NXUnsetLibraryPath(int value) +{ + int previous = _NXUnsetLibraryPath; + + _NXUnsetLibraryPath = value; + + #ifdef TEST + fprintf(stderr, "******NXUnsetLibraryPath: Set the flag to [%d] with previous value [%d].\n", + value, previous); + #endif + + return previous; +} + +/* + * If set, the Xlib I/O error handler will simply + * return, instead of quitting the program. This + * leaves to the application the responsibility + * of checking the state of the XlibDisplayIOEr- + * ror flag. + */ + +int NXHandleDisplayError(int value) +{ + int previous = _NXHandleDisplayError; + + _NXHandleDisplayError = value; + + #ifdef TEST + fprintf(stderr, "******NXHandleDisplayError: Set the flag to [%d] with previous value [%d].\n", + value, previous); + #endif + + return previous; +} + +/* + * Shutdown the display descriptor and force Xlib + * to set the I/O error flag. + */ + +Bool NXForceDisplayError(Display *dpy) +{ + if (dpy != NULL) + { + NXTransClose(dpy -> fd); + + if (!(dpy -> flags & XlibDisplayIOError)) + { + shutdown(dpy -> fd, SHUT_RDWR); + + _XIOError(dpy); + } + + return 1; + } + + return 0; +} + +/* + * Check if the display has become invalid. Similarly + * to the modified Xlib, we call the predicate funct- + * ion with the value of the XlibDisplayIOError flag + * only if the I/O error was not encountered already. + * The application can use this function to query the + * XlibDisplayIOError flag because Xlib doesn't expose + * the internals of the display structure to the appli- + * cation. + */ + +int NXDisplayError(Display *dpy) +{ + if (dpy != NULL) + { + return (_XGetIOError(dpy) || + (_NXDisplayErrorFunction != NULL && + (*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy)))); + } + + return 1; +} + +/* + * Various queries related to the state of the + * display connection. + */ + +int NXDisplayReadable(Display *dpy) +{ + int result; + int readable; + + result = NXTransReadable(dpy -> fd, &readable); + + if (result == 0) + { + #ifdef DEBUG + fprintf(stderr, "******NXDisplayReadable: Returning [%d] bytes readable from fd [%d].\n", + readable, dpy -> fd); + #endif + + return readable; + } + + #ifdef DEBUG + fprintf(stderr, "******NXDisplayReadable: WARNING! Error detected on display fd [%d].\n", + dpy -> fd); + #endif + + return -1; +} + +int NXDisplayFlushable(Display *dpy) +{ + #ifdef DEBUG + + int flushable; + + flushable = NXTransFlushable(dpy -> fd) + + (dpy -> bufptr - dpy -> buffer); + + fprintf(stderr, "******NXDisplayFlushable: Returning [%d+%d=%d] bytes flushable " + "to fd [%d].\n", (int) (dpy -> bufptr - dpy -> buffer), + (int) (flushable - (dpy -> bufptr - dpy -> buffer)), + flushable, dpy -> fd); + + return flushable; + + #else + + return NXTransFlushable(dpy -> fd) + (dpy -> bufptr - dpy -> buffer); + + #endif +} + +int NXDisplayCongestion(Display *dpy) +{ + #ifdef DEBUG + + int congestion = NXTransCongestion(dpy -> fd); + + fprintf(stderr, "******NXDisplayCongestion: Returning [%d] as congestion level for fd [%d].\n", + congestion, dpy -> fd); + + return congestion; + + #else + + return NXTransCongestion(dpy -> fd); + + #endif +} + +int NXFlushDisplay(Display *dpy, int what) +{ + if (!(dpy -> flags & XlibDisplayWriting) && + dpy -> bufptr - dpy -> buffer > 0) + { + #ifdef DEBUG + fprintf(stderr, "******NXFlushDisplay: Writing with [%d] bytes in the buffer.\n", + (int) (dpy -> bufptr - dpy -> buffer)); + #endif + + XFlush(dpy); + } + + if (what == NXFlushBuffer) + { + return 0; + } + + #ifdef DEBUG + fprintf(stderr, "******NXFlushDisplay: Flushing with [%d] bytes in the NX transport.\n", + NXDisplayFlushable(dpy)); + #endif + + return NXTransFlush(dpy -> fd); +} + +NXDisplayErrorPredicate NXSetDisplayErrorPredicate(NXDisplayErrorPredicate predicate) +{ + NXDisplayErrorPredicate previous = _NXDisplayErrorFunction; + + _NXDisplayErrorFunction = predicate; + + #ifdef TEST + fprintf(stderr, "******NXSetDisplayErrorPredicate: Set the predicate to [%p] with previous value [%p].\n", + predicate, previous); + #endif + + return previous; +} + +NXDisplayBlockHandler NXSetDisplayBlockHandler(NXDisplayBlockHandler handler) +{ + NXDisplayBlockHandler previous = _NXDisplayBlockFunction; + + _NXDisplayBlockFunction = handler; + + #ifdef TEST + fprintf(stderr, "******NXSetDisplayBlockHandler: Set the handler to [%p] with previous value [%p].\n", + handler, previous); + #endif + + return previous; +} + +NXDisplayWriteHandler NXSetDisplayWriteHandler(NXDisplayWriteHandler handler) +{ + NXDisplayWriteHandler previous = _NXDisplayWriteFunction; + + _NXDisplayWriteFunction = handler; + + #ifdef TEST + fprintf(stderr, "******NXSetDisplayWriteHandler: Set the handler to [%p] with previous value [%p].\n", + handler, previous); + #endif + + return previous; +} + +NXDisplayFlushHandler NXSetDisplayFlushHandler(NXDisplayFlushHandler handler, Display *display) +{ + NXDisplayFlushHandler previous = _NXDisplayFlushFunction; + + _NXDisplayFlushFunction = handler; + + NXTransHandler(NX_FD_ANY, NX_HANDLER_FLUSH, + (void (*)(void *, int)) handler, (void *) display); + + #ifdef TEST + fprintf(stderr, "******NXSetDisplayFlushHandler: Set the handler to [%p] with display [%p] " + "and previous value [%p].\n", handler, display, previous); + #endif + + return previous; +} + +NXDisplayStatisticsHandler NXSetDisplayStatisticsHandler(NXDisplayStatisticsHandler handler, char **buffer) +{ + NXDisplayStatisticsHandler previous = _NXDisplayStatisticsFunction; + + _NXDisplayStatisticsFunction = handler; + + /* + * Propagate the handler. + */ + + NXTransHandler(NX_FD_ANY, NX_HANDLER_STATISTICS, + (void (*)(void *, int)) handler, (void *) buffer); + + #ifdef TEST + fprintf(stderr, "******NXSetDisplayStatisticsHandler: Set the handler to [%p] with buffer pointer [%p] " + "and previous value [%p].\n", handler, buffer, previous); + #endif + + return previous; +} + +NXLostSequenceHandler NXSetLostSequenceHandler(NXLostSequenceHandler handler) +{ + NXLostSequenceHandler previous = _NXLostSequenceFunction; + + _NXLostSequenceFunction = handler; + + #ifdef TEST + fprintf(stderr, "******NXSetLostSequenceHandler: Set the handler to [%p] with previous value [%p].\n", + handler, previous); + #endif + + return previous; +} + +int _NXInternalReplyErrorFunction(Display *dpy, XErrorEvent *error) +{ + #ifdef TEST + fprintf(stderr, "******_NXInternalReplyErrorFunction: Internal error handler called.\n"); + #endif + + return 0; +} + +void _NXInternalLostSequenceFunction(Display *dpy, unsigned long newseq, + unsigned long lastseq, unsigned int type) +{ + #ifdef TEST + + fprintf(stderr, "******_NXInternalLostSequenceFunction: WARNING! Sequence lost with new " + "sequence %ld last request %ld.\n", newseq, dpy -> request); + + /* + * TODO: Reply or event info must be implemented. + * + * fprintf(stderr, "******_NXInternalLostSequenceFunction: WARNING! Expected event or reply " + * "was %ld with sequence %ld.\n", (long) rep -> type, (long) rep -> sequenceNumber); + */ + + fprintf(stderr, "******_NXInternalLostSequenceFunction: WARNING! Last sequence read " + "was %ld display request is %ld.\n", lastseq & 0xffff, dpy -> request & 0xffff); + + #endif +} + +Status NXGetControlParameters(Display *dpy, unsigned int *link_type, unsigned int *local_major, + unsigned int *local_minor, unsigned int *local_patch, + unsigned int *remote_major, unsigned int *remote_minor, + unsigned int *remote_patch, int *split_timeout, int *motion_timeout, + int *split_mode, int *split_size, unsigned int *pack_method, + unsigned int *pack_quality, int *data_level, int *stream_level, + int *delta_level, unsigned int *load_cache, + unsigned int *save_cache, unsigned int *startup_cache) +{ + xNXGetControlParametersReply rep; + + register xReq *req; + + LockDisplay(dpy); + + GetEmptyReq(NXGetControlParameters, req); + + #ifdef TEST + fprintf(stderr, "******NXGetControlParameters: Sending message opcode [%d].\n", + X_NXGetControlParameters); + #endif + + if (_XReply(dpy, (xReply *) &rep, 0, xTrue) == xFalse) + { + #ifdef TEST + fprintf(stderr, "******NXGetControlParameters: Error receiving reply.\n"); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + #ifdef TEST + fprintf(stderr, "******NXGetControlParameters: Got reply with link type [%u].\n", rep.linkType); + + fprintf(stderr, "******NXGetControlParameters: Local protocol major [%u] minor [%u] patch [%u].\n", + rep.localMajor, rep.localMinor, rep.localPatch); + + fprintf(stderr, "******NXGetControlParameters: Remote protocol major [%u] minor [%u] patch [%u].\n", + rep.remoteMajor, rep.remoteMinor, rep.remotePatch); + + fprintf(stderr, "******NXGetControlParameters: Split timeout [%d] motion timeout [%d].\n", + (int) rep.splitTimeout, (int) rep.motionTimeout); + + fprintf(stderr, "******NXGetControlParameters: Split mode [%d] split size [%d].\n", + (int) rep.splitMode, (int) rep.splitSize); + + fprintf(stderr, "******NXGetControlParameters: Preferred pack method [%d] pack quality [%d].\n", + (int) rep.packMethod, (int) rep.packQuality); + + fprintf(stderr, "******NXGetControlParameters: Data level [%d] stream level [%d] delta level [%d].\n", + rep.dataLevel, rep.streamLevel, rep.deltaLevel); + #endif + + *link_type = rep.linkType; + + *local_major = rep.localMajor; + *local_minor = rep.localMinor; + *local_patch = rep.localPatch; + + *remote_major = rep.remoteMajor; + *remote_minor = rep.remoteMinor; + *remote_patch = rep.remotePatch; + + *split_timeout = rep.splitTimeout; + *motion_timeout = rep.motionTimeout; + + *split_mode = rep.splitMode; + *split_size = rep.splitSize; + + *pack_method = rep.packMethod; + *pack_quality = rep.packQuality; + + *data_level = rep.dataLevel; + *stream_level = rep.streamLevel; + *delta_level = rep.deltaLevel; + + *load_cache = rep.loadCache; + *save_cache = rep.saveCache; + *startup_cache = rep.startupCache; + + UnlockDisplay(dpy); + + SyncHandle(); + + /* + * Install our internal out-of-sync handler. + */ + + _NXLostSequenceFunction = _NXInternalLostSequenceFunction; + + return 1; +} + +/* + * Which unpack methods are supported by the + * remote proxy? + */ + +Status NXGetUnpackParameters(Display *dpy, unsigned int *entries, unsigned char supported_methods[]) +{ + register xNXGetUnpackParametersReq *req; + + xNXGetUnpackParametersReply rep; + + register unsigned n; + + #ifdef TEST + register unsigned i; + #endif + + if (*entries < NXNumberOfPackMethods) + { + #ifdef TEST + fprintf(stderr, "******NXGetUnpackParameters: Requested only [%d] entries while they should be [%d].\n", + *entries, NXNumberOfPackMethods); + #endif + + return 0; + } + + LockDisplay(dpy); + + GetReq(NXGetUnpackParameters, req); + + req -> entries = *entries; + + #ifdef TEST + fprintf(stderr, "******NXGetUnpackParameters: Sending message opcode [%d] with [%d] requested entries.\n", + X_NXGetUnpackParameters, *entries); + #endif + + if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == xFalse || rep.length == 0) + { + #ifdef TEST + fprintf(stderr, "******NXGetUnpackParameters: Error receiving reply.\n"); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + if ((n = rep.length << 2) > *entries) + { + #ifdef TEST + fprintf(stderr, "******NXGetUnpackParameters: Got [%d] bytes of reply data while they should be [%d].\n", + n, *entries); + #endif + + _XEatData(dpy, (unsigned long) n); + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + *entries = n; + + #ifdef TEST + fprintf(stderr, "******NXGetUnpackParameters: Reading [%d] bytes of reply data.\n", n); + #endif + + _XReadPad(dpy, (char *) supported_methods, n); + + #ifdef TEST + + fprintf(stderr, "******NXGetUnpackParameters: Got reply with methods: "); + + for (i = 0; i < n; i++) + { + if (supported_methods[i] != 0) + { + fprintf(stderr, "[%d]", i); + } + } + + fprintf(stderr, ".\n"); + + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * Query and enable the MIT-SHM support between the + * proxy and the X server. The 'enable' flags must be + * true if shared memory PutImages and PutPackedImages + * are desired. On return the flags will say if support + * has been successfully enabled. + * + * Note that the the client part is not useful and not + * implemented. The size of the segment is chosen by + * the proxy. The main purpose of the message is to + * reserve the XID that will be used by the remote. + */ + +Status NXGetShmemParameters(Display *dpy, unsigned int *enable_client, + unsigned int *enable_server, unsigned int *client_segment, + unsigned int *server_segment, unsigned int *client_size, + unsigned int *server_size) +{ + register xNXGetShmemParametersReq *req; + + register int stage; + + xNXGetShmemParametersReply rep; + + /* + * Save the previous handler. + */ + + int (*handler)(Display *, XErrorEvent *) = _XErrorFunction; + + *client_segment = 0; + *server_segment = 0; + + if (*enable_client) + { + *client_segment = XAllocID(dpy); + } + + if (*enable_server) + { + *server_segment = XAllocID(dpy); + } + + LockDisplay(dpy); + + _XErrorFunction = _NXInternalReplyErrorFunction; + + for (stage = 0; stage < 3; stage++) + { + GetReq(NXGetShmemParameters, req); + + req -> stage = stage; + + req -> enableClient = (*enable_client != 0 ? 1 : 0); + req -> enableServer = (*enable_server != 0 ? 1 : 0); + + req -> clientSegment = *client_segment; + req -> serverSegment = *server_segment; + + #ifdef TEST + fprintf(stderr, "******NXGetShmemParameters: Sending message opcode [%d] at stage [%d].\n", + X_NXGetShmemParameters, stage); + #endif + + #ifdef TEST + + if (stage == 0) + { + fprintf(stderr, "******NXGetShmemParameters: Enable client is [%u] enable server is [%u].\n", + *enable_client, *enable_server); + + fprintf(stderr, "******NXGetShmemParameters: Client segment is [%u] server segment is [%u].\n", + *client_segment, *server_segment); + } + + #endif + + /* + * There isn't X server reply in the second stage. + * The procedure followed at X server side is: + * + * Stage 0: Send X_QueryExtension and masquerade + * the reply. + * + * Stage 1: Allocate the shared memory and send + * X_ShmAttach to the X server. + * + * Stage 2: Send X_GetInputFocus and masquerade + * the reply. + * + * The last message is used to force a reply and + * collect any X error caused by a failure in the + * shared memory initialization. + */ + + if (stage != 1) + { + /* + * We are only interested in the final reply. + */ + + if (_XReply(dpy, (xReply *) &rep, 0, xTrue) == xFalse) + { + #ifdef TEST + fprintf(stderr, "******NXGetShmemParameters: Error receiving reply.\n"); + #endif + + _XErrorFunction = handler; + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + } + } + + /* + * Return the settings to client. + */ + + *enable_client = rep.clientEnabled; + *enable_server = rep.serverEnabled; + + *client_size = rep.clientSize; + *server_size = rep.serverSize; + + #ifdef TEST + fprintf(stderr, "******NXGetShmemParameters: Got final reply with enabled client [%u] and server [%u].\n", + *enable_client, *enable_server); + + fprintf(stderr, "******NXGetShmemParameters: Client segment size [%u] server segment size [%u].\n", + *client_size, *server_size); + #endif + + _XErrorFunction = handler; + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * Get the path to the font server that can be used by the X + * server to tunnel the font connections across the NX link. + * The path actually represents the TCP port where the proxy + * on the NX client side is listening. The agent can tempora- + * rily enable the tunneling when it needs a font that is not + * available on the client, for example when the session is + * migrated from a different X server. + * + * Note that it is not advisable to use the font server chan- + * nel for other purposes than restoring a font that is found + * missing at the time the session is migrated to a different + * display. This is because the agent implements a caching of + * the list of fonts supported by the client as it needs to + * advertise only the fonts that can be opened at both sides. + */ + +Status NXGetFontParameters(Display *dpy, unsigned int path_length, char path_data[]) +{ + register xNXGetFontParametersReq *req; + + xNXGetFontParametersReply rep; + + register unsigned n; + + #ifdef TEST + register unsigned i; + #endif + + if (path_length < 1) + { + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: No room to store the reply.\n"); + #endif + + return 0; + } + + *path_data = '\0'; + + LockDisplay(dpy); + + GetReq(NXGetFontParameters, req); + + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: Sending message opcode [%d].\n", + X_NXGetFontParameters); + #endif + + if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == xFalse || rep.length == 0) + { + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: Error receiving reply.\n"); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + if ((n = rep.length << 2) > path_length) + { + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: Got [%d] bytes of reply data with only room for [%d].\n", + n, path_length); + #endif + + _XEatData(dpy, (unsigned long) n); + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: Reading [%d] bytes of reply data.\n", n); + #endif + + _XReadPad(dpy, (char *) path_data, n); + + /* + * Check if the string can be fully + * contained by the buffer. + */ + + if (*path_data > path_length - 1) + { + #ifdef TEST + fprintf(stderr, "******NXGetFontParameters: Inconsistent length in the returned string.\n"); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 0; + } + + #ifdef TEST + + fprintf(stderr, "******NXGetFontParameters: Got font path of [%d] bytes and value [", + (int) *path_data); + + for (i = 0; i < *path_data; i++) + { + fprintf(stderr, "%c", *(path_data + i + 1)); + } + + fprintf(stderr, "].\n"); + + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +unsigned int NXAllocSplit(Display *dpy, unsigned int resource) +{ + if (resource == NXAnyResource) + { + for (resource = 0; resource < NXNumberOfResources; resource++) + { + if (_NXSplitResources[resource] == 0) + { + _NXSplitResources[resource] = 1; + + #ifdef TEST + fprintf(stderr, "******NXAllocSplit: Reserved resource [%u].\n", + resource); + #endif + + return resource; + } + } + + #ifdef TEST + fprintf(stderr, "******NXAllocSplit: WARNING! Resource limit exausted.\n"); + #endif + + return NXNoResource; + } + else if (resource >= 0 && resource < NXNumberOfResources) + { + #ifdef TEST + + if (_NXSplitResources[resource] == 0) + { + fprintf(stderr, "******NXAllocSplit: Reserved requested resource [%u].\n", + resource); + } + else + { + fprintf(stderr, "******NXAllocSplit: Requested resource [%u] already reserved.\n", + resource); + } + + #endif + + _NXSplitResources[resource] = 1; + } + + #ifdef PANIC + fprintf(stderr, "******NXAllocSplit: PANIC! Can't reserve requested resource [%u].\n", + resource); + #endif + + return NXNoResource; +} + +/* + * Tell the proxy to split the next messages. + */ + +int NXStartSplit(Display *dpy, unsigned int resource, unsigned int mode) +{ + register xNXStartSplitReq *req; + + LockDisplay(dpy); + + GetReq(NXStartSplit, req); + + req -> resource = resource; + req -> mode = mode; + + #ifdef TEST + fprintf(stderr, "******NXStartSplit: Sending opcode [%d] with resource [%d] mode [%d].\n", + X_NXStartSplit, resource, mode); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * Send the closure of the split sequence and + * tell the proxy to send the results. + */ + +int NXEndSplit(Display *dpy, unsigned int resource) +{ + register xNXEndSplitReq *req; + + LockDisplay(dpy); + + GetReq(NXEndSplit, req); + + req -> resource = resource; + + #ifdef TEST + fprintf(stderr, "******NXEndSplit: Sending opcode [%d] with resource [%d].\n", + X_NXStartSplit, resource); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * This message must be sent whenever the proxy notifies + * the client of the completion of a split. If the 'pro- + * pagate' field is 0, the proxy will not send the ori- + * ginal request to the X server, but will only free the + * internal state. + */ + +int NXCommitSplit(Display *dpy, unsigned int resource, unsigned int propagate, + unsigned char request, unsigned int position) +{ + register xNXCommitSplitReq *req; + + LockDisplay(dpy); + + GetReq(NXCommitSplit, req); + + req -> resource = resource; + req -> propagate = propagate; + req -> request = request; + req -> position = position; + + #ifdef TEST + fprintf(stderr, "******NXCommitSplit: Sending opcode [%d] with resource [%d] propagate [%d] " + "request [%d] position [%d].\n", X_NXCommitSplit, resource, + propagate, request, position); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +int NXAbortSplit(Display *dpy, unsigned int resource) +{ + register xNXAbortSplitReq *req; + + LockDisplay(dpy); + + GetReq(NXAbortSplit, req); + + #ifdef TEST + fprintf(stderr, "******NXAbortSplit: Sending message opcode [%d] with resource [%u].\n", + X_NXAbortSplit, resource); + #endif + + req -> resource = resource; + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +int NXFinishSplit(Display *dpy, unsigned int resource) +{ + register xNXFinishSplitReq *req; + + LockDisplay(dpy); + + GetReq(NXFinishSplit, req); + + #ifdef TEST + fprintf(stderr, "******NXFinishSplit: Sending message opcode [%d] with resource [%u].\n", + X_NXFinishSplit, resource); + #endif + + req -> resource = resource; + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +int NXFreeSplit(Display *dpy, unsigned int resource) +{ + register xNXFreeSplitReq *req; + + if (_NXSplitResources[resource] != 0) + { + LockDisplay(dpy); + + GetReq(NXFreeSplit, req); + + #ifdef TEST + fprintf(stderr, "******NXFreeSplit: Sending message opcode [%d] with resource [%u].\n", + X_NXFreeSplit, resource); + #endif + + req -> resource = resource; + + UnlockDisplay(dpy); + + SyncHandle(); + + #ifdef TEST + fprintf(stderr, "******NXFreeSplit: Making the resource [%u] newly available.\n", + resource); + #endif + + _NXSplitResources[resource] = 0; + } + #ifdef TEST + else + { + fprintf(stderr, "******NXFreeSplit: Nothing to do for resource [%u].\n", + resource); + } + #endif + + return 1; +} + +/* + * Tell to remote proxy to discard expose events + * of one or more types. + */ + +int NXSetExposeParameters(Display *dpy, int expose, int graphics_expose, int no_expose) +{ + register xNXSetExposeParametersReq *req; + + LockDisplay(dpy); + + GetReq(NXSetExposeParameters, req); + + req -> expose = expose; + req -> graphicsExpose = graphics_expose; + req -> noExpose = no_expose; + + #ifdef TEST + fprintf(stderr, "******NXSetExposeParameters: Sending message opcode [%d] with flags [%d][%d][%d].\n", + X_NXSetExposeParameters, req -> expose, req -> graphicsExpose, req -> noExpose); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * Tell to the local proxy how to handle the next requests. + */ + +int NXSetCacheParameters(Display *dpy, int enable_cache, int enable_split, + int enable_save, int enable_load) +{ + register xNXSetCacheParametersReq *req; + + LockDisplay(dpy); + + GetReq(NXSetCacheParameters, req); + + req -> enableCache = enable_cache; + req -> enableSplit = enable_split; + req -> enableSave = enable_save; + req -> enableLoad = enable_load; + + #ifdef TEST + fprintf(stderr, "******NXSetCacheParameters: Sending message opcode [%d] with " + "flags [%d][%d][%d][%d].\n", X_NXSetCacheParameters, req -> enableCache, + req -> enableSplit, req -> enableSave, req -> enableLoad); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +unsigned int NXAllocUnpack(Display *dpy, unsigned int resource) +{ + if (resource == NXAnyResource) + { + for (resource = 0; resource < NXNumberOfResources; resource++) + { + if (_NXUnpackResources[resource] == 0) + { + _NXUnpackResources[resource] = 1; + + #ifdef TEST + fprintf(stderr, "******NXAllocUnpack: Reserved resource [%u].\n", + resource); + #endif + + return resource; + } + } + + #ifdef TEST + fprintf(stderr, "******NXAllocUnpack: WARNING! Resource limit exausted.\n"); + #endif + + return NXNoResource; + } + else if (resource >= 0 && resource < NXNumberOfResources) + { + #ifdef TEST + + if (_NXUnpackResources[resource] == 0) + { + fprintf(stderr, "******NXAllocUnpack: Reserved requested resource [%u].\n", + resource); + } + else + { + fprintf(stderr, "******NXAllocUnpack: Requested resource [%u] already reserved.\n", + resource); + } + + #endif + + _NXUnpackResources[resource] = 1; + } + + #ifdef PANIC + fprintf(stderr, "******NXAllocUnpack: PANIC! Can't reserve requested resource [%u].\n", + resource); + #endif + + return NXNoResource; +} + +int NXSetUnpackGeometry(Display *dpy, unsigned int resource, Visual *visual) +{ + register xNXSetUnpackGeometryReq *req; + + LockDisplay(dpy); + + GetReq(NXSetUnpackGeometry, req); + + req -> resource = resource; + + req -> depth1Bpp = _XGetBitsPerPixel(dpy, 1); + req -> depth4Bpp = _XGetBitsPerPixel(dpy, 4); + req -> depth8Bpp = _XGetBitsPerPixel(dpy, 8); + req -> depth16Bpp = _XGetBitsPerPixel(dpy, 16); + req -> depth24Bpp = _XGetBitsPerPixel(dpy, 24); + req -> depth32Bpp = _XGetBitsPerPixel(dpy, 32); + + if (visual != NULL) + { + req -> redMask = visual -> red_mask; + req -> greenMask = visual -> green_mask; + req -> blueMask = visual -> blue_mask; + } + else + { + #ifdef PANIC + fprintf(stderr, "******NXSetUnpackGeometry: PANIC! Can't set the geometry without a visual.\n"); + #endif + + UnGetReq(NXSetUnpackGeometry); + + UnlockDisplay(dpy); + + return -1; + } + + #ifdef TEST + fprintf(stderr, "******NXSetUnpackGeometry: Resource [%u] Depth/Bpp [1/%d][4/%d][8/%d]" + "[16/%d][24/%d][32/%d].\n", resource, req -> depth1Bpp, req -> depth4Bpp, + req -> depth8Bpp, req -> depth16Bpp, req -> depth24Bpp, req -> depth32Bpp); + + fprintf(stderr, "******NXSetUnpackGeometry: red [0x%x] green [0x%x] blue [0x%x].\n", + (unsigned) req -> redMask, (unsigned) req -> greenMask, (unsigned) req -> blueMask); + #endif + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * Store a colormap table on the remote side. + * The colormap can then be used to unpack + * an image. + */ + +int NXSetUnpackColormap(Display *dpy, unsigned int resource, unsigned int method, + unsigned int entries, const char *data, unsigned int data_length) +{ + register xNXSetUnpackColormapReq *req; + + register int dst_data_length; + + LockDisplay(dpy); + + GetReq(NXSetUnpackColormap, req); + + req -> resource = resource; + req -> method = method; + + req -> srcLength = data_length; + req -> dstLength = entries << 2; + + dst_data_length = ROUNDUP(data_length, 4); + + req -> length += (dst_data_length >> 2); + + #ifdef TEST + fprintf(stderr, "******NXSetUnpackColormap: Resource [%u] data size [%u] destination " + "data size [%u].\n", resource, data_length, dst_data_length); + #endif + + if (data_length > 0) + { + if (dpy -> bufptr + dst_data_length <= dpy -> bufmax) + { + /* + * Clean the padding bytes in the request. + */ + + *((int *) (dpy -> bufptr + dst_data_length - 4)) = 0x0; + + memcpy(dpy -> bufptr, data, data_length); + + dpy -> bufptr += dst_data_length; + } + else + { + /* + * The _XSend() will pad the request for us. + */ + + _XSend(dpy, data, data_length); + } + } + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * Store data of the alpha blending channel + * that will be combined with the next image + * to be unpacked. + */ + +int NXSetUnpackAlpha(Display *dpy, unsigned int resource, unsigned int method, + unsigned int entries, const char *data, unsigned int data_length) +{ + register xNXSetUnpackAlphaReq *req; + + register unsigned int dst_data_length; + + LockDisplay(dpy); + + GetReq(NXSetUnpackAlpha, req); + + req -> resource = resource; + req -> method = method; + + req -> srcLength = data_length; + req -> dstLength = entries; + + dst_data_length = ROUNDUP(data_length, 4); + + req -> length += (dst_data_length >> 2); + + #ifdef TEST + fprintf(stderr, "******NXSetUnpackAlpha: Resource [%u] data size [%u] destination data size [%u].\n", + resource, data_length, dst_data_length); + #endif + + if (data_length > 0) + { + if (dpy -> bufptr + dst_data_length <= dpy -> bufmax) + { + /* + * Clean the padding bytes in the request. + */ + + *((int *) (dpy -> bufptr + dst_data_length - 4)) = 0x0; + + memcpy(dpy -> bufptr, data, data_length); + + dpy -> bufptr += dst_data_length; + } + else + { + /* + * The _XSend() will pad the request for us. + */ + + _XSend(dpy, data, data_length); + } + } + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * Compatibility versions to be used when + * connected to a 1.X.X proxy. + */ + +/* + * These are for compatibility with the 1.X.X + * versions. + */ + +#define sz_xNXSetUnpackColormapCompatReq 8 + +typedef struct _NXSetUnpackColormapCompatReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; + CARD32 entries B32; +} xNXSetUnpackColormapCompatReq; + +#define X_NXSetUnpackColormapCompat X_NXSetUnpackColormap + +int NXSetUnpackColormapCompat(Display *dpy, unsigned int resource, + unsigned int entries, const char *data) +{ + register xNXSetUnpackColormapCompatReq *req; + + register char *dst_data; + + register int dst_data_length; + + #ifdef DUMP + + int i; + + #endif + + LockDisplay(dpy); + + GetReq(NXSetUnpackColormapCompat, req); + + req -> resource = resource; + req -> entries = entries; + + dst_data_length = entries << 2; + + req -> length += (dst_data_length >> 2); + + #ifdef TEST + fprintf(stderr, "******NXSetUnpackColormapCompat: Resource [%u] number of entries [%u] " + "destination data size [%u].\n", resource, entries, dst_data_length); + #endif + + if (entries > 0) + { + if ((dpy -> bufptr + dst_data_length) <= dpy -> bufmax) + { + dst_data = dpy -> bufptr; + } + else + { + if ((dst_data = _XAllocScratch(dpy, dst_data_length)) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXSetUnpackColormapCompat: PANIC! Cannot allocate memory.\n"); + #endif + + UnGetReq(NXSetUnpackColormapCompat); + + UnlockDisplay(dpy); + + return -1; + } + } + + memcpy(dst_data, data, entries << 2); + + #ifdef DUMP + + fprintf(stderr, "******NXSetUnpackColormapCompat: Dumping colormap entries:\n"); + + for (i = 0; i < entries; i++) + { + fprintf(stderr, "******NXSetUnpackColormapCompat: [%d] -> [0x%x].\n", + i, *((int *) (dst_data + (i * 4)))); + } + + #endif + + if (dst_data == dpy -> bufptr) + { + dpy -> bufptr += dst_data_length; + } + else + { + _XSend(dpy, dst_data, dst_data_length); + } + } + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +#define sz_xNXSetUnpackAlphaCompatReq 8 + +typedef struct _NXSetUnpackAlphaCompatReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; + CARD32 entries B32; +} xNXSetUnpackAlphaCompatReq; + +#define X_NXSetUnpackAlphaCompat X_NXSetUnpackAlpha + +int NXSetUnpackAlphaCompat(Display *dpy, unsigned int resource, + unsigned int entries, const char *data) +{ + register xNXSetUnpackAlphaCompatReq *req; + + register char *dst_data; + + register unsigned int dst_data_length; + + #ifdef DUMP + + int i; + + #endif + + LockDisplay(dpy); + + GetReq(NXSetUnpackAlphaCompat, req); + + req -> resource = resource; + req -> entries = entries; + + dst_data_length = ROUNDUP(entries, 4); + + req -> length += (dst_data_length >> 2); + + #ifdef TEST + fprintf(stderr, "******NXSetUnpackAlphaCompat: Resource [%u] number of entries [%u] " + "destination data size [%u].\n", resource, entries, dst_data_length); + #endif + + if (entries > 0) + { + if ((dpy -> bufptr + dst_data_length) <= dpy -> bufmax) + { + dst_data = dpy -> bufptr; + } + else + { + if ((dst_data = _XAllocScratch(dpy, dst_data_length)) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXSetUnpackAlphaCompat: PANIC! Cannot allocate memory.\n"); + #endif + + UnGetReq(NXSetUnpackAlphaCompat); + + UnlockDisplay(dpy); + + return -1; + } + } + + memcpy(dst_data, data, entries); + + if (dst_data_length != entries) + { + memset(dst_data + entries, 0, dst_data_length - entries); + } + + #ifdef DUMP + + fprintf(stderr, "******NXSetUnpackAlphaCompat: Dumping alpha channel data:\n"); + + for (i = 0; i < dst_data_length; i++) + { + fprintf(stderr, "******NXSetUnpackAlphaCompat: [%d] -> [0x%02x].\n", + i, ((unsigned int) *(dst_data + i)) & 0xff); + } + + #endif + + if (dst_data == dpy -> bufptr) + { + dpy -> bufptr += dst_data_length; + } + else + { + _XSend(dpy, dst_data, dst_data_length); + } + } + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +/* + * Free any geometry, colormap and alpha channel + * data stored by the remote proxy to unpack the + * image. Resource, as usual, must be a value + * between 0 and 255. + */ + +int NXFreeUnpack(Display *dpy, unsigned int resource) +{ + register xNXFreeUnpackReq *req; + + if (_NXUnpackResources[resource] != 0) + { + LockDisplay(dpy); + + GetReq(NXFreeUnpack, req); + + #ifdef TEST + fprintf(stderr, "******NXFreeUnpack: Sending message opcode [%d] with resource [%u].\n", + X_NXFreeUnpack, resource); + #endif + + req -> resource = resource; + + UnlockDisplay(dpy); + + SyncHandle(); + + #ifdef TEST + fprintf(stderr, "******NXFreeUnpack: Making the resource [%u] newly available.\n", + resource); + #endif + + _NXUnpackResources[resource] = 0; + } + #ifdef TEST + else + { + fprintf(stderr, "******NXFreeUnpack: Nothing to do for resource [%u].\n", + resource); + } + #endif + + return 1; +} + +/* + * Wrapper of XCreateImage(). Note that we use offset + * field of XImage to store size of source image in + * packed format. Note also that method is currently + * not stored in the NXignored. + */ + +NXPackedImage *NXCreatePackedImage(Display *dpy, Visual *visual, unsigned int method, + unsigned int depth, int format, char *data, + int data_length, unsigned int width, + unsigned int height, int bitmap_pad, + int bytes_per_line) +{ + XImage* image; + + image = XCreateImage(dpy, visual, depth, format, 0, data, + width, height, bitmap_pad, bytes_per_line); + + if (image != NULL) + { + image -> xoffset = data_length; + } + + return (NXPackedImage *) image; +} + +/* + * Wrapper of XDestroyImage(). + */ + +int NXDestroyPackedImage(NXPackedImage *image) +{ + return XDestroyImage((XImage *) image); +} + +/* + * Clean the image data directly in the current buffer. + */ + +int NXCleanImage(XImage *image) +{ + #ifdef TEST + fprintf(stderr, "******NXCleanImage: Cleaning image with format [%d] depth [%d] " + "bits per pixel [%d].\n", image -> format, image -> depth, + image -> bits_per_pixel); + #endif + + if (image -> format == ZPixmap) + { + if (image -> depth == 1) + { + return CleanXYImage(image); + } + else + { + return CleanZImage(image); + } + } + else + { + return CleanXYImage(image); + } +} + +NXPackedImage *NXPackImage(Display *dpy, XImage *src_image, unsigned int method) +{ + XImage *dst_image; + + const ColorMask *mask; + + unsigned int dst_data_size; + unsigned int dst_packed_data_size; + + unsigned int dst_bits_per_pixel; + unsigned int dst_packed_bits_per_pixel; + + #ifdef TEST + fprintf(stderr, "******NXPackImage: Going to pack a new image with method [%d].\n", + method); + #endif + + /* + * Get the mask out of the method and + * check if the visual is supported by + * the color reduction algorithm. + */ + + mask = MethodColorMask(method); + + if (mask == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXPackImage: WARNING! No mask to apply for pack method [%d].\n", + method); + #endif + + return NULL; + } + else if (CanMaskImage(src_image, mask) == 0) + { + #ifdef PANIC + fprintf(stderr, "******NXPackImage: PANIC! Invalid source with format [%d] depth [%d] bits per pixel [%d].\n", + src_image -> format, src_image -> depth, src_image -> bits_per_pixel); + + fprintf(stderr, "******NXPackImage: PANIC! Visual colormask is red 0x%lx green 0x%lx blue 0x%lx.\n", + src_image -> red_mask, src_image -> green_mask, src_image -> blue_mask); + #endif + + return NULL; + } + + /* + * Create a destination image from + * source and apply the color mask. + */ + + if ((dst_image = (XImage *) Xmalloc(sizeof(XImage))) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXPackImage: PANIC! Cannot allocate [%d] bytes for the image.\n", + (int) sizeof(XImage)); + #endif + + return NULL; + } + + *dst_image = *src_image; + + #ifdef TEST + fprintf(stderr, "******NXPackImage: Source width [%d], bytes per line [%d] with depth [%d].\n", + src_image -> width, src_image -> bytes_per_line, src_image -> depth); + #endif + + dst_data_size = src_image -> bytes_per_line * src_image -> height; + + dst_image -> data = Xmalloc(dst_data_size); + + if (dst_image -> data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXPackImage: PANIC! Cannot allocate [%d] bytes for masked image data.\n", + dst_data_size); + #endif + + Xfree(dst_image); + + return NULL; + } + + /* + * If the pixel resulting from the mask + * needs more bits than available, then + * just clean the padding bits in the + * image. + */ + + dst_bits_per_pixel = dst_image -> bits_per_pixel; + dst_packed_bits_per_pixel = MethodBitsPerPixel(method); + + #ifdef TEST + fprintf(stderr, "******NXPackImage: Destination depth [%d], bits per pixel [%d], packed bits per pixel [%d].\n", + dst_image -> depth, dst_bits_per_pixel, dst_packed_bits_per_pixel); + #endif + + if (dst_packed_bits_per_pixel > dst_bits_per_pixel || + ShouldMaskImage(src_image, mask) == 0) + { + /* + * Should use the same data for source + * and destination to avoid the memcpy. + */ + + if (CopyAndCleanImage(src_image, dst_image) <= 0) + { + #ifdef PANIC + fprintf(stderr, "******NXPackImage: PANIC! Failed to clean the image.\n"); + #endif + + Xfree(dst_image -> data); + + Xfree(dst_image); + + return NULL; + } + } + else if (MaskImage(mask, src_image, dst_image) <= 0) + { + #ifdef PANIC + fprintf(stderr, "******NXPackImage: PANIC! Failed to apply the color mask.\n"); + #endif + + Xfree(dst_image -> data); + + Xfree(dst_image); + + return NULL; + } + + /* + * Let's pack the same pixels in fewer bytes. + * Note that we save a new memory allocation + * by using the same image as source and des- + * tination. This means that PackImage() must + * be able to handle ovelapping areas. + */ + + #ifdef TEST + fprintf(stderr, "******NXPackImage: Plain bits per pixel [%d], data size [%d].\n", + dst_bits_per_pixel, dst_data_size); + #endif + + dst_packed_data_size = dst_data_size * dst_packed_bits_per_pixel / + dst_bits_per_pixel; + + #ifdef TEST + fprintf(stderr, "******NXPackImage: Packed bits per pixel [%d], data size [%d].\n", + dst_packed_bits_per_pixel, dst_packed_data_size); + #endif + + if (PackImage(method, dst_data_size, dst_image, + dst_packed_data_size, dst_image) <= 0) + { + #ifdef PANIC + fprintf(stderr, "******NXPackImage: PANIC! Failed to pack image from [%d] to [%d] bits per pixel.\n", + dst_bits_per_pixel, dst_packed_bits_per_pixel); + #endif + + Xfree(dst_image -> data); + + Xfree(dst_image); + + return NULL; + } + + /* + * Save data size in xoffset field + * to comply with NX packed images. + */ + + dst_image -> xoffset = dst_packed_data_size; + + return dst_image; +} + +/* + * NXInPlacePackImage creates a NXPackedImage + * from a XImage, sharing the same data buffer. + * Is up to the caller to free the data buffer + * only once. + */ + +XImage *NXInPlacePackImage(Display *dpy, XImage *src_image, unsigned int method) +{ + XImage *dst_image; + + const ColorMask *mask; + + unsigned int dst_data_size; + unsigned int dst_packed_data_size; + + unsigned int dst_bits_per_pixel; + unsigned int dst_packed_bits_per_pixel; + + #ifdef TEST + fprintf(stderr, "******NXInPlacePackImage: Going to pack a new image with method [%d].\n", + method); + #endif + + /* + * Get mask out of method and check if + * visual is supported by current color + * reduction algorithm. + */ + + mask = MethodColorMask(method); + + if (mask == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXInPlacePackImage: WARNING! No mask to apply for pack method [%d].\n", + method); + #endif + + return NULL; + } + else if (CanMaskImage(src_image, mask) == 0) + { + #ifdef PANIC + fprintf(stderr, "******NXInPlacePackImage: PANIC! Invalid source with format [%d] depth [%d] bits per pixel [%d].\n", + src_image -> format, src_image -> depth, src_image -> bits_per_pixel); + + fprintf(stderr, "******NXInPlacePackImage: PANIC! Visual colormask is red 0x%lx green 0x%lx blue 0x%lx.\n", + src_image -> red_mask, src_image -> green_mask, src_image -> blue_mask); + #endif + return NULL; + } + + /* + * Create a destination image from + * source and apply the color mask. + */ + + if ((dst_image = (XImage *) Xmalloc(sizeof(XImage))) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXInPlacePackImage: PANIC! Cannot allocate [%d] bytes for the image.\n", + (int) sizeof(XImage)); + #endif + + return NULL; + } + + *dst_image = *src_image; + + #ifdef TEST + fprintf(stderr, "******NXInPlacePackImage: Source width [%d], bytes per line [%d] with depth [%d].\n", + src_image -> width, src_image -> bytes_per_line, src_image -> depth); + #endif + + dst_data_size = src_image -> bytes_per_line * src_image -> height; + + dst_image -> data = src_image -> data; + + /* + * If pixel resulting from mask needs + * more bits than available, then just + * clean the pad bits in image. + */ + + dst_bits_per_pixel = dst_image -> bits_per_pixel; + dst_packed_bits_per_pixel = MethodBitsPerPixel(method); + + #ifdef TEST + fprintf(stderr, "******NXInPlacePackImage: Destination depth [%d], bits per pixel [%d], packed bits per pixel [%d].\n", + dst_image -> depth, dst_bits_per_pixel, dst_packed_bits_per_pixel); + #endif + + if (dst_packed_bits_per_pixel > dst_bits_per_pixel || + ShouldMaskImage(src_image, mask) == 0) + { + #ifdef TEST + fprintf(stderr, "******NXInPlacePackImage: Just clean image packed_bits_per_pixel[%d], bits_per_pixel[%d].\n", + dst_packed_bits_per_pixel, dst_bits_per_pixel); + #endif + + if (NXCleanImage(dst_image) <= 0) + { + #ifdef PANIC + fprintf(stderr, "******NXInPlacePackImage: PANIC! Failed to clean the image.\n"); + #endif + + Xfree(dst_image); + + return NULL; + } + } + else if (MaskInPlaceImage(mask, dst_image) <= 0) + { + #ifdef PANIC + fprintf(stderr, "******NXInPlacePackImage: PANIC! Failed to apply the color mask.\n"); + #endif + + Xfree(dst_image); + + return NULL; + } + + /* + * Let's pack the same pixels in fewer bytes. + * Note that we save a new memory allocation + * by using the same image as source and des- + * tination. This means that PackImage() must + * be able to handle ovelapping areas. + */ + + #ifdef TEST + fprintf(stderr, "******NXInPlacePackImage: Plain bits per pixel [%d], data size [%d].\n", + dst_bits_per_pixel, dst_data_size); + #endif + + dst_packed_data_size = dst_data_size * dst_packed_bits_per_pixel / + dst_bits_per_pixel; + + #ifdef TEST + fprintf(stderr, "******NXInPlacePackImage: Packed bits per pixel [%d], data size [%d].\n", + dst_packed_bits_per_pixel, dst_packed_data_size); + #endif + + /* + * Save data size in xoffset field + * to comply with NX packed images. + */ + + dst_image -> xoffset = dst_packed_data_size; + + return dst_image; +} + +int NXPutPackedImage(Display *dpy, unsigned int resource, Drawable drawable, + void *gc, NXPackedImage *image, unsigned int method, + unsigned int depth, int src_x, int src_y, int dst_x, + int dst_y, unsigned int width, unsigned int height) +{ + register xNXPutPackedImageReq *req; + + register unsigned int src_data_length; + register unsigned int dst_data_length; + + LockDisplay(dpy); + + FlushGC(dpy, (GC) gc); + + GetReq(NXPutPackedImage, req); + + req -> resource = resource; + req -> drawable = drawable; + req -> gc = ((GC) gc) -> gid; + + #ifdef TEST + fprintf(stderr, "******NXPutPackedImage: Image resource [%d] drawable [%d] gc [%d].\n", + req -> resource, (int) req -> drawable, (int) req -> gc); + #endif + + /* + * There is no leftPad field in request. We only + * support a leftPad of 0. Anyway, X imposes a + * leftPad of 0 in case of ZPixmap format. + */ + + req -> format = image -> format; + + /* + * Source depth, as well as width and height, + * are taken from the image structure. + */ + + req -> srcDepth = image -> depth; + + req -> srcX = src_x; + req -> srcY = src_y; + + req -> srcWidth = image -> width; + req -> srcHeight = image -> height; + + /* + * The destination depth is provided + * by the caller. + */ + + req -> dstDepth = depth; + + req -> dstX = dst_x; + req -> dstY = dst_y; + + req -> dstWidth = width; + req -> dstHeight = height; + + req -> method = method; + + #ifdef TEST + fprintf(stderr, "******NXPutPackedImage: Source image depth [%d] destination depth [%d] " + "method [%d].\n", req -> srcDepth, req -> dstDepth, req -> method); + #endif + + /* + * Source data length is the size of image in packed format, + * as stored in xoffset field of XImage. Destination data + * size is calculated according to bytes per line of target + * image, so the caller must provide the right depth at the + * time XImage structure is created. + */ + + req -> srcLength = image -> xoffset; + + if (image -> width == (int) width && + image -> height == (int) height) + { + req -> dstLength = image -> bytes_per_line * image -> height; + } + else if (image -> format == ZPixmap) + { + req -> dstLength = ROUNDUP((image -> bits_per_pixel * width), + image -> bitmap_pad) * height >> 3; + } + else + { + req -> dstLength = ROUNDUP(width, image -> bitmap_pad) * height >> 3; + } + + src_data_length = image -> xoffset; + + dst_data_length = ROUNDUP(src_data_length, 4); + + #ifdef TEST + fprintf(stderr, "******NXPutPackedImage: Source data length [%d] request data length [%d].\n", + src_data_length, dst_data_length); + #endif + + req -> length += (dst_data_length >> 2); + + if (src_data_length > 0) + { + if (dpy -> bufptr + dst_data_length <= dpy -> bufmax) + { + /* + * Clean the padding bytes in the request. + */ + + *((int *) (dpy -> bufptr + dst_data_length - 4)) = 0x0; + + memcpy(dpy -> bufptr, image -> data, src_data_length); + + dpy -> bufptr += dst_data_length; + } + else + { + /* + * The _XSend() will pad the request for us. + */ + + _XSend(dpy, image -> data, src_data_length); + } + } + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +int NXAllocColors(Display *dpy, Colormap colormap, unsigned int entries, + XColor screens_in_out[], Bool results_in_out[]) +{ + Status result = 0; + xAllocColorReply rep; + register xAllocColorReq *req; + + Bool alloc_error = False; + + register unsigned int i; + + LockDisplay(dpy); + + for (i = 0; i < entries; i++) + { + GetReq(AllocColor, req); + + req -> cmap = colormap; + + req -> red = screens_in_out[i].red; + req -> green = screens_in_out[i].green; + req -> blue = screens_in_out[i].blue; + } + + for (i = 0; i < entries; i++) + { + result = _XReply(dpy, (xReply *) &rep, 0, xTrue); + + if (result) + { + screens_in_out[i].pixel = rep.pixel; + + screens_in_out[i].red = rep.red; + screens_in_out[i].green = rep.green; + screens_in_out[i].blue = rep.blue; + + results_in_out[i] = True; + } + else + { + results_in_out[i] = False; + + alloc_error = True; + } + } + + UnlockDisplay(dpy); + + SyncHandle(); + + return (alloc_error == False); +} + +char *NXEncodeColormap(const char *src_data, unsigned int src_size, unsigned int *dst_size) +{ + return ColormapCompressData(src_data, src_size, dst_size); +} + +char *NXEncodeAlpha(const char *src_data, unsigned int src_size, unsigned int *dst_size) +{ + return AlphaCompressData(src_data, src_size, dst_size); +} + +NXPackedImage *NXEncodeRgb(XImage *src_image, unsigned int method, unsigned int quality) +{ + NXPackedImage *dst_image = NULL; + + unsigned int dst_size; + + /* + * Create a new image structure as a copy + * of the source. + */ + + if ((dst_image = (NXPackedImage *) Xmalloc(sizeof(NXPackedImage))) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeRgb: PANIC! Cannot allocate [%d] bytes for the image.\n", + (int) sizeof(XImage)); + #endif + + return NULL; + } + + *dst_image = *src_image; + + dst_image -> data = RgbCompressData(src_image, &dst_size); + + if (dst_image -> data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeRgb: PANIC! Rgb compression failed.\n"); + #endif + + Xfree(dst_image); + + return NULL; + } + + /* + * Store the Rgb size in the xoffset field. + */ + + dst_image -> xoffset = dst_size; + + return dst_image; +} + +NXPackedImage *NXEncodeRle(XImage *src_image, unsigned int method, unsigned int quality) +{ + NXPackedImage *dst_image = NULL; + + unsigned int dst_size; + + /* + * Create a new image structure as a copy + * of the source. + */ + + if ((dst_image = (NXPackedImage *) Xmalloc(sizeof(NXPackedImage))) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeRle: PANIC! Cannot allocate [%d] bytes for the image.\n", + (int) sizeof(XImage)); + #endif + + return NULL; + } + + *dst_image = *src_image; + + dst_image -> data = RleCompressData(src_image, &dst_size); + + if (dst_image -> data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeRle: PANIC! Rle compression failed.\n"); + #endif + + Xfree(dst_image); + + return NULL; + } + + /* + * Store the Rle size in the xoffset field. + */ + + dst_image -> xoffset = dst_size; + + return dst_image; +} + +NXPackedImage *NXEncodeBitmap(XImage *src_image, unsigned int method, unsigned int quality) +{ + NXPackedImage *dst_image = NULL; + + unsigned int dst_size; + + /* + * Create a new image structure as a copy + * of the source. + */ + + if ((dst_image = (NXPackedImage *) Xmalloc(sizeof(NXPackedImage))) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeBitmap: PANIC! Cannot allocate [%d] bytes for the image.\n", + (int) sizeof(XImage)); + #endif + + return NULL; + } + + *dst_image = *src_image; + + dst_image -> data = BitmapCompressData(src_image, &dst_size); + + if (dst_image -> data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeBitmap: PANIC! Bitmap compression failed.\n"); + #endif + + Xfree(dst_image); + + return NULL; + } + + /* + * Store the bitmap size in the xoffset field. + */ + + dst_image -> xoffset = dst_size; + + return dst_image; +} + +NXPackedImage *NXEncodeJpeg(XImage *src_image, unsigned int method, unsigned int quality) +{ + NXPackedImage *dst_image = NULL; + + int size; + + /* + * Check if the bpp of the image is valid + * for the Jpeg compression. + */ + + if (src_image -> bits_per_pixel < 15) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeJpeg: PANIC! Invalid bpp for Jpeg compression [%d]\n.", + src_image -> bits_per_pixel); + #endif + + return NULL; + } + + /* + * Create the destination image as a copy + * of the source. + */ + + if ((dst_image = (NXPackedImage *) Xmalloc(sizeof(NXPackedImage))) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeJpeg: PANIC! Cannot allocate [%d] bytes for the Jpeg image.\n", + (int) sizeof(NXPackedImage)); + #endif + + return NULL; + } + + *dst_image = *src_image; + + dst_image -> data = JpegCompressData(src_image, quality, &size); + + if (dst_image -> data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodeJpeg: PANIC! Jpeg compression failed.\n"); + #endif + + Xfree(dst_image); + + return NULL; + } + + /* + * Store the Jpeg size in the xoffset field. + */ + + dst_image -> xoffset = size; + + return dst_image; +} + +NXPackedImage *NXEncodePng(XImage *src_image, unsigned int method, unsigned int quality) +{ + NXPackedImage *dst_image = NULL; + + int size; + + /* + * Check if the bpp of the image is valid + * for png compression. + */ + + if (src_image -> bits_per_pixel < 15) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodePng: PANIC! Invalid bpp for Png compression [%d].\n", + src_image -> bits_per_pixel); + #endif + + return NULL; + } + + if ((dst_image = (NXPackedImage *) Xmalloc(sizeof(NXPackedImage))) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodePng: PANIC! Cannot allocate [%d] bytes for the Png image.\n", + (int) sizeof(NXPackedImage)); + #endif + + return NULL; + } + + *dst_image = *src_image; + + dst_image -> data = PngCompressData(dst_image, &size); + + if (dst_image -> data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXEncodePng: PANIC! Png compression failed.\n"); + #endif + + Xfree(dst_image); + + return NULL; + } + + /* + * Store the Png size in the xoffset field. + */ + + dst_image -> xoffset = size; + + return dst_image; +} + +int NXEncodeColors(XImage *src_image, NXColorTable *color_table, int nb_max) +{ + int x, y, t, p; + + long pixel; + + /* + * We need a smarter way to extract + * the colors from the image and + * create a color table. + */ + + memset(color_table, 0, nb_max * sizeof(NXColorTable)); + + for (x = 0, p = 0; x < src_image -> width; x++) + { + for (y = 0; y < src_image -> height; y++) + { + pixel = XGetPixel(src_image, x, y); + + for (t = 0; t < nb_max; t++) + { + if ( color_table[t].found == 0) + { + color_table[t].pixel = pixel; + color_table[t].found = 1; + + p++; + + break; + } + else if ((color_table[t].pixel) == pixel) + { + break; + } + } + + if (p == nb_max) + { + return nb_max + 1; + } + } + } + + return p; +} + +void NXMaskImage(XImage *image, unsigned int method) +{ + unsigned int maskMethod; + + const ColorMask *mask; + + /* + * Choose the correct mask method + */ + + switch(method) + { + case PACK_JPEG_8_COLORS: + case PACK_PNG_8_COLORS: + { + maskMethod = MASK_8_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_8_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_64_COLORS: + case PACK_PNG_64_COLORS: + { + maskMethod = MASK_64_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_64K_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_256_COLORS: + case PACK_PNG_256_COLORS: + { + maskMethod = MASK_256_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_256_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_512_COLORS: + case PACK_PNG_512_COLORS: + { + maskMethod = MASK_512_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_512K_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_4K_COLORS: + case PACK_PNG_4K_COLORS: + { + maskMethod = MASK_4K_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_4K_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_32K_COLORS: + case PACK_PNG_32K_COLORS: + { + maskMethod = MASK_32K_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_32K_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_64K_COLORS: + case PACK_PNG_64K_COLORS: + { + maskMethod = MASK_64K_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_64K_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_256K_COLORS: + case PACK_PNG_256K_COLORS: + { + maskMethod = MASK_256K_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_256K_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_2M_COLORS: + case PACK_PNG_2M_COLORS: + { + maskMethod = MASK_2M_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_2M_COLORS\n"); + #endif + + break; + } + case PACK_JPEG_16M_COLORS: + case PACK_PNG_16M_COLORS: + { + maskMethod = MASK_16M_COLORS; + + #ifdef DEBUG + fprintf(stderr, "******NXMaskImage: Method is MASK_16M_COLORS\n"); + #endif + + break; + } + default: + { + #ifdef PANIC + fprintf(stderr, "******NXMaskImage: PANIC! Cannot find mask method for pack method [%d]\n", + method); + #endif + + return; + } + } + + #ifdef TEST + fprintf(stderr, "******NXMaskImage: packMethod[%d] => maskMethod[%d]\n", + method, maskMethod); + #endif + + /* + * Get mask out of method and check if + * visual is supported by current color + * reduction algorithm. + */ + + mask = MethodColorMask(maskMethod); + + if (mask == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXMaskImage: PANIC! No mask to apply for pack method [%d].\n", + method); + #endif + + return; + } + else if (CanMaskImage(image, mask) == 0) + { + #ifdef PANIC + fprintf(stderr, "******NXMaskImage: PANIC! Invalid source with format [%d] depth [%d] bits per pixel [%d].\n", + image -> format, image -> depth, image -> bits_per_pixel); + + fprintf(stderr, "******NXMaskImage: PANIC! Visual colormask is red 0x%lx green 0x%lx blue 0x%lx.\n", + image -> red_mask, image -> green_mask, image -> blue_mask); + #endif + + return; + } + + /* + * Calling ShouldMaskImage you get 0 in the case + * of MASK_256_COLORS and MASK_64K_COLORS, which + * means that the image should not be masked. + */ + + if (ShouldMaskImage(image, mask) == 0) + { + #ifdef TEST + fprintf(stderr, "******NXMaskImage: the image will not be masked\n"); + #endif + } + else + { + if (MaskInPlaceImage(mask, image) <= 0) + { + #ifdef PANIC + fprintf(stderr, "******NXMaskImage: PANIC! Failed to apply the color mask in place.\n"); + #endif + } + } +} + +/* + * The display parameter is ignored. + */ + +void NXInitCache(Display *dpy, int entries) +{ + if (NXImageCache != NULL && NXImageCacheSize == entries) + { + #ifdef DEBUG + fprintf(stderr, "******NXInitCache: Nothing to do with image cache at [%p] and [%d] entries.\n", + NXImageCache, NXImageCacheSize); + #endif + + return; + } + + #ifdef DEBUG + fprintf(stderr, "******NXInitCache: Initializing the cache with [%d] entries.\n", + entries); + #endif + + NXImageCacheSize = 0; + + if (NXImageCache != NULL) + { + Xfree(NXImageCache); + + NXImageCache = NULL; + } + + if (entries > 0) + { + NXImageCache = Xmalloc(entries * sizeof(_NXImageCacheEntry)); + + if (NXImageCache != NULL) + { + memset(NXImageCache, 0, entries * sizeof(_NXImageCacheEntry)); + + NXImageCacheSize = entries; + + #ifdef DEBUG + fprintf(stderr, "******NXInitCache: Image cache initialized with [%d] entries.\n", entries); + #endif + } + } +} + +#ifdef DUMP + +void _NXCacheDump(const char *label) +{ + char s[MD5_LENGTH * 2 + 1]; + + int i; + int j; + + #ifdef DEBUG + fprintf(stderr, "%s: Dumping the content of image cache:\n", label); + #endif + + for (i = 0; i < NXImageCacheSize; i++) + { + if (NXImageCache[i].image == NULL) + { + break; + } + + for (j = 0; j < MD5_LENGTH; j++) + { + sprintf(s + (j * 2), "%02X", ((unsigned char *) NXImageCache[i].md5)[j]); + } + + #ifdef DEBUG + fprintf(stderr, "%s: [%d][%s].\n", label, i, s); + #endif + } +} + +#endif + +XImage *NXCacheFindImage(NXPackedImage *src_image, unsigned int *method, unsigned char **md5) +{ + md5_state_t new_state; + md5_byte_t *new_md5; + unsigned int data_size, i; + + if (NXImageCache == NULL) + { + return NULL; + } + + /* + * Will return the allocated checksum + * if the image is not found. + */ + + *md5 = NULL; + + if ((new_md5 = Xmalloc(MD5_LENGTH)) == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCacheFindImage: Can't allocate memory for the checksum.\n"); + #endif + + return NULL; + } + + data_size = (src_image -> bytes_per_line * src_image -> height); + + md5_init(&new_state); + + md5_append(&new_state, (unsigned char *) &src_image -> width, sizeof(int)); + md5_append(&new_state, (unsigned char *) &src_image -> height, sizeof(int)); + + md5_append(&new_state, (unsigned char *) src_image -> data, data_size); + + md5_finish(&new_state, new_md5); + + for (i = 0; i < NXImageCacheSize; i++) + { + if (NXImageCache[i].image != NULL) + { + if (memcmp(NXImageCache[i].md5, new_md5, MD5_LENGTH) == 0) + { + _NXImageCacheEntry found; + + found.image = NXImageCache[i].image; + found.method = NXImageCache[i].method; + found.md5 = NXImageCache[i].md5; + + *method = found.method; + + NXImageCacheHits++; + + #ifdef DEBUG + fprintf(stderr, "******NXCacheFindImage: Found at position [%d] with hits [%d] and [%d] packs.\n", + i, NXImageCacheHits, NXImageCacheOps); + #endif + + Xfree(new_md5); + + /* + * Move the images down one slot, from + * the head of the list, and place the + * image just found at top. + */ + + if (i > 16) + { + #ifdef DEBUG + fprintf(stderr, "******NXCacheFindImage: Moving the image at the head of the list.\n"); + #endif + + memmove(&NXImageCache[1], &NXImageCache[0], (i * sizeof(_NXImageCacheEntry))); + + NXImageCache[0].image = found.image; + NXImageCache[0].method = found.method; + NXImageCache[0].md5 = found.md5; + + #ifdef DUMP + + _NXCacheDump("******NXCacheFindImage"); + + #endif + } + + /* + * Return the checksum and image + * structure allocated in cache. + */ + + *md5 = found.md5; + + return found.image; + } + } + else + { + break; + } + } + + *md5 = new_md5; + + return NULL; +} + +/* + * Add a packed image to the cache. A new image + * structure is allocated and copied, data and + * checksum are inherited from the passed image. + */ + +int NXCacheAddImage(NXPackedImage *image, unsigned int method, unsigned char *md5) +{ + unsigned int i; + + if (image == NULL || image -> data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCacheAddImage: PANIC! Invalid image passed to function.\n"); + #endif + + return -1; + } + + i = (NXImageCacheOps < NXImageCacheSize) ? NXImageCacheOps : NXImageCacheSize; + + if (NXImageCacheOps >= NXImageCacheSize) + { + #ifdef DEBUG + fprintf(stderr, "******NXCacheAddImage: Freeing up the oldest entry.\n"); + #endif + + i--; + + Xfree(NXImageCache[NXImageCacheSize - 1].image -> data); + Xfree(NXImageCache[NXImageCacheSize - 1].image); + Xfree(NXImageCache[NXImageCacheSize - 1].md5); + } + + if (i > 0) + { + memmove(&NXImageCache[1], &NXImageCache[0], i * sizeof(_NXImageCacheEntry)); + } + + NXImageCacheOps++; + + #ifdef DEBUG + fprintf(stderr, "******NXCacheAddImage: Going to add new image with data size [%d].\n", + image -> xoffset); + #endif + + NXImageCache[0].image = image; + NXImageCache[0].method = method; + NXImageCache[0].md5 = md5; + + #ifdef DUMP + + _NXCacheDump("******NXCacheAddImage"); + + #endif + + return 1; +} + +/* + * The display parameter is ignored. + */ + +void NXFreeCache(Display *dpy) +{ + int i; + + if (NXImageCache == NULL) + { + #ifdef DEBUG + fprintf(stderr, "******NXFreeCache: Nothing to do with a null image cache.\n"); + #endif + + return; + } + + #ifdef DEBUG + fprintf(stderr, "******NXFreeCache: Freeing the cache with [%d] entries.\n", + NXImageCacheSize); + #endif + + for (i = 0; i < NXImageCacheSize; i++) + { + if (NXImageCache[i].image != NULL) + { + if (NXImageCache[i].image -> data != NULL) + { + Xfree(NXImageCache[i].image -> data); + } + + Xfree(NXImageCache[i].image); + + NXImageCache[i].image = NULL; + } + + if (NXImageCache[i].md5 != NULL) + { + Xfree(NXImageCache[i].md5); + + NXImageCache[i].md5 = NULL; + } + } + + Xfree(NXImageCache); + + NXImageCache = NULL; + + NXImageCacheSize = 0; + NXImageCacheHits = 0; + NXImageCacheOps = 0; +} + +static void _NXNotifyImage(Display *dpy, int resource, Bool success) +{ + XEvent async_event; + + /* + * Enqueue an event to tell client + * the result of GetImage. + */ + + async_event.type = ClientMessage; + + async_event.xclient.serial = _NXCollectedImages[resource] -> sequence; + + async_event.xclient.window = 0; + async_event.xclient.message_type = 0; + async_event.xclient.format = 32; + + async_event.xclient.data.l[0] = NXCollectImageNotify; + async_event.xclient.data.l[1] = resource; + async_event.xclient.data.l[2] = success; + + XPutBackEvent(dpy, &async_event); +} + +static Bool _NXCollectImageHandler(Display *dpy, xReply *rep, char *buf, + int len, XPointer data) +{ + register _NXCollectImageState *state; + + register xGetImageReply *async_rep; + + char *async_head; + char *async_data; + + int async_size; + + state = (_NXCollectImageState *) data; + + if ((rep -> generic.sequenceNumber % 65536) != + ((int)(state -> sequence) % 65536)) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Unmatched sequence [%d] for opcode [%d] " + "with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type, + (int) rep -> generic.length << 2); + #endif + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Going to handle asynchronous GetImage reply.\n"); + #endif + + /* + * As even reply data is managed asynchronously, + * we can use state to get to vector and vector + * to get to handler. In this way, we can safely + * dequeue and free the handler itself. + */ + + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + + state -> handler = NULL; + + if (rep -> generic.type == X_Error) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Error received from X server for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyImage(dpy, state -> resource, False); + + _NXCollectedImages[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Matched request with sequence [%ld].\n", + state -> sequence); + #endif + + async_size = SIZEOF(xGetImageReply); + + async_head = Xmalloc(async_size); + + if (async_head == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectImageHandler: PANIC! Failed to allocate memory with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyImage(dpy, state -> resource, False); + + _NXCollectedImages[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Going to get reply with size [%d].\n", + (int) rep -> generic.length << 2); + #endif + + async_rep = (xGetImageReply *) _XGetAsyncReply(dpy, async_head, rep, buf, len, 0, False); + + if (async_rep == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectImageHandler: PANIC! Failed to get reply with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyImage(dpy, state -> resource, False); + + _NXCollectedImages[state -> resource] = NULL; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Got reply with depth [%d] visual [%d] size [%d].\n", + async_rep -> depth, (int) async_rep -> visual, (int) async_rep -> length << 2); + #endif + + async_size = async_rep -> length << 2; + + if (async_size > 0) + { + async_data = Xmalloc(async_size); + + if (async_data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectImageHandler: PANIC! Failed to allocate memory with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyImage(dpy, state -> resource, False); + + _NXCollectedImages[state -> resource] = NULL; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Going to get data with size [%d].\n", + async_size); + #endif + + _XGetAsyncData(dpy, async_data, buf, len, SIZEOF(xGetImageReply), async_size, async_size); + + /* + * From now on we can return True, as all + * data has been consumed from buffer. + */ + + if (state -> format == XYPixmap) + { + unsigned long depth = DepthOnes(state -> mask & (((unsigned long)0xFFFFFFFF) >> + (32 - async_rep -> depth))); + + state -> image = XCreateImage(dpy, _XVIDtoVisual(dpy, async_rep -> visual), + depth, XYPixmap, 0, async_data, state -> width, + state -> height, dpy -> bitmap_pad, 0); + } + else + { + state -> image = XCreateImage(dpy, _XVIDtoVisual(dpy, async_rep -> visual), + async_rep -> depth, ZPixmap, 0, async_data, state -> width, + state -> height, _XGetScanlinePad(dpy, async_rep -> depth), 0); + } + + if (state -> image == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectImageHandler: PANIC! Failed to create image for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyImage(dpy, state -> resource, False); + + _NXCollectedImages[state -> resource] = NULL; + + Xfree(state); + + Xfree(async_head); + Xfree(async_data); + + return True; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectImageHandler: Successfully stored image data for resource [%d].\n", + state -> resource); + #endif + } + #ifdef WARNING + else + { + fprintf(stderr, "******_NXCollectImageHandler: WARNING! Null image data stored for resource [%d].\n", + state -> resource); + } + #endif + + _NXNotifyImage(dpy, state -> resource, True); + + Xfree(async_head); + + return True; +} + +int NXGetCollectImageResource(Display *dpy) +{ + int i; + + for (i = 0; i < NXNumberOfResources; i++) + { + if (_NXCollectedImages[i] == NULL) + { + return i; + } + } + + return -1; +} + +int NXCollectImage(Display *dpy, unsigned int resource, Drawable drawable, + int src_x, int src_y, unsigned int width, unsigned int height, + unsigned long plane_mask, int format) +{ + register xGetImageReq *req; + + _NXCollectImageState *state; + _XAsyncHandler *handler; + + if (resource >= NXNumberOfResources) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectImage: PANIC! Provided resource [%u] is out of range.\n", + resource); + #endif + + return -1; + } + + state = _NXCollectedImages[resource]; + + if (state != NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectImage: PANIC! Having to remove previous state for resource [%u].\n", + resource); + #endif + + if (state -> handler != NULL) + { + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + } + + if (state -> image != NULL) + { + XDestroyImage(state -> image); + } + + Xfree(state); + + _NXCollectedImages[resource] = NULL; + } + + LockDisplay(dpy); + + GetReq(GetImage, req); + + req -> format = format; + req -> drawable = drawable; + req -> x = src_x; + req -> y = src_y; + req -> width = width; + req -> height = height; + req -> planeMask = plane_mask; + + #ifdef TEST + fprintf(stderr, "******NXCollectImage: Sending message opcode [%d] sequence [%ld] for resource [%d].\n", + X_GetImage, dpy -> request, resource); + + fprintf(stderr, "******NXCollectImage: Format [%d] drawable [%d] src_x [%d] src_y [%d].\n", + req -> format, (int) req -> drawable, req -> x, req -> y); + + fprintf(stderr, "******NXCollectImage: Width [%d] height [%d] plane_mask [%x].\n", + req -> width, req -> height, (int) req -> planeMask); + #endif + + state = Xmalloc(sizeof(_NXCollectImageState)); + handler = Xmalloc(sizeof(_XAsyncHandler)); + + if (state == NULL || handler == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectImage: PANIC! Failed to allocate memory with resource [%d].\n", + resource); + #endif + + UnGetReq(GetImage); + + if (state != NULL) + { + Xfree(state); + } + + if (handler != NULL) + { + Xfree(handler); + } + + UnlockDisplay(dpy); + + return -1; + } + + state -> sequence = dpy -> request; + state -> resource = resource; + state -> mask = plane_mask; + state -> format = format; + state -> width = width; + state -> height = height; + state -> image = NULL; + + state -> handler = handler; + + handler -> next = dpy -> async_handlers; + handler -> handler = _NXCollectImageHandler; + handler -> data = (XPointer) state; + dpy -> async_handlers = handler; + + _NXCollectedImages[resource] = state; + + UnlockDisplay(dpy); + + SyncHandle(); + + return 1; +} + +int NXGetCollectedImage(Display *dpy, unsigned int resource, XImage **image) +{ + register _NXCollectImageState *state; + + state = _NXCollectedImages[resource]; + + if (state == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXGetCollectedImage: PANIC! No image collected for resource [%u].\n", + resource); + #endif + + return 0; + } + + _NXCollectedImages[resource] = NULL; + + *image = state -> image; + + Xfree(state); + + #ifdef TEST + fprintf(stderr, "******NXGetCollectedImage: Returning GetImage data for resource [%u].\n", + resource); + #endif + + return 1; +} + +static void _NXNotifyProperty(Display *dpy, int resource, Bool success) +{ + XEvent async_event; + + /* + * Enqueue an event to tell client + * the result of GetProperty. + */ + + async_event.type = ClientMessage; + + async_event.xclient.serial = _NXCollectedProperties[resource] -> sequence; + + async_event.xclient.window = 0; + async_event.xclient.message_type = 0; + async_event.xclient.format = 32; + + async_event.xclient.data.l[0] = NXCollectPropertyNotify; + async_event.xclient.data.l[1] = resource; + async_event.xclient.data.l[2] = success; + + XPutBackEvent(dpy, &async_event); +} + +static Bool _NXCollectPropertyHandler(Display *dpy, xReply *rep, char *buf, + int len, XPointer data) +{ + register _NXCollectPropertyState *state; + + register xGetPropertyReply *async_rep; + + char *async_head; + char *async_data; + + int async_size; + + state = (_NXCollectPropertyState *) data; + + if ((rep -> generic.sequenceNumber % 65536) != + ((int)(state -> sequence) % 65536)) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Unmatched sequence [%d] for opcode [%d] " + "with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type, + (int) rep -> generic.length << 2); + #endif + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Going to handle asynchronous GetProperty reply.\n"); + #endif + + /* + * Reply data is managed asynchronously. We can + * use state to get to vector and vector to get + * to handler. In this way, we can dequeue and + * free the handler itself. + */ + + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + + state -> handler = NULL; + + if (rep -> generic.type == X_Error) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Error received from X server for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyProperty(dpy, state -> resource, False); + + _NXCollectedProperties[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Matched request with sequence [%ld].\n", + state -> sequence); + #endif + + async_size = SIZEOF(xGetPropertyReply); + + async_head = Xmalloc(async_size); + + if (async_head == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectPropertyHandler: PANIC! Failed to allocate memory with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyProperty(dpy, state -> resource, False); + + _NXCollectedProperties[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Going to get reply with size [%d].\n", + (int) rep -> generic.length << 2); + #endif + + async_rep = (xGetPropertyReply *) _XGetAsyncReply(dpy, async_head, rep, buf, len, 0, False); + + if (async_rep == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectPropertyHandler: PANIC! Failed to get reply with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyProperty(dpy, state -> resource, False); + + _NXCollectedProperties[state -> resource] = NULL; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Got reply with format [%d] type [%d] size [%d].\n", + async_rep -> format, (int) async_rep -> propertyType, (int) async_rep -> length << 2); + + fprintf(stderr, "******_NXCollectPropertyHandler: Bytes after [%d] number of items [%d].\n", + (int) async_rep -> bytesAfter, (int) async_rep -> nItems); + #endif + + state -> format = async_rep -> format; + state -> type = async_rep -> propertyType; + state -> items = async_rep -> nItems; + state -> after = async_rep -> bytesAfter; + + async_size = async_rep -> length << 2; + + if (async_size > 0) + { + async_data = Xmalloc(async_size); + + if (async_data == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectPropertyHandler: PANIC! Failed to allocate memory with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyProperty(dpy, state -> resource, False); + + _NXCollectedProperties[state -> resource] = NULL; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Going to get data with size [%d].\n", + async_size); + #endif + + _XGetAsyncData(dpy, async_data, buf, len, SIZEOF(xGetPropertyReply), async_size, async_size); + + /* + * From now on we can return True, as all + * data has been consumed from buffer. + */ + + state -> data = async_data; + + #ifdef TEST + fprintf(stderr, "******_NXCollectPropertyHandler: Successfully stored property data for resource [%d].\n", + state -> resource); + #endif + } + #ifdef TEST + else + { + fprintf(stderr, "******_NXCollectPropertyHandler: WARNING! Null property data stored for resource [%d].\n", + state -> resource); + } + #endif + + _NXNotifyProperty(dpy, state -> resource, True); + + Xfree(async_head); + + return True; +} + +int NXGetCollectPropertyResource(Display *dpy) +{ + int i; + + for (i = 0; i < NXNumberOfResources; i++) + { + if (_NXCollectedProperties[i] == NULL) + { + return i; + } + } + + return -1; +} + +int NXCollectProperty(Display *dpy, unsigned int resource, Window window, Atom property, + long long_offset, long long_length, Bool delete, Atom req_type) +{ + register xGetPropertyReq *req; + + _NXCollectPropertyState *state; + _XAsyncHandler *handler; + + if (resource >= NXNumberOfResources) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectProperty: PANIC! Provided resource [%u] is out of range.\n", + resource); + #endif + + return -1; + } + + state = _NXCollectedProperties[resource]; + + if (state != NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectProperty: PANIC! Having to remove previous state for resource [%u].\n", + resource); + #endif + + if (state -> handler != NULL) + { + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + } + + if (state -> data != NULL) + { + Xfree(state -> data); + } + + Xfree(state); + + _NXCollectedProperties[resource] = NULL; + } + + LockDisplay(dpy); + + GetReq(GetProperty, req); + + req -> delete = delete; + req -> window = window; + req -> property = property; + req -> type = req_type; + req -> longOffset = long_offset; + req -> longLength = long_length; + + #ifdef TEST + fprintf(stderr, "******NXCollectProperty: Sending message opcode [%d] sequence [%ld] for resource [%d].\n", + X_GetProperty, dpy -> request, resource); + + fprintf(stderr, "******NXCollectProperty: Delete [%u] window [%d] property [%d] type [%d].\n", + req -> delete, (int) req -> window, (int) req -> property, (int) req -> type); + + fprintf(stderr, "******NXCollectProperty: Long offset [%d] long length [%d].\n", + (int) req -> longOffset, (int) req -> longLength); + #endif + + state = Xmalloc(sizeof(_NXCollectPropertyState)); + handler = Xmalloc(sizeof(_XAsyncHandler)); + + if (state == NULL || handler == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectProperty: Failed to allocate memory with resource [%d].\n", + resource); + #endif + + if (state != NULL) + { + Xfree(state); + } + + if (handler != NULL) + { + Xfree(handler); + } + + UnGetReq(GetProperty); + + UnlockDisplay(dpy); + + return -1; + } + + state -> sequence = dpy -> request; + state -> resource = resource; + state -> window = window; + state -> property = property; + state -> type = 0; + state -> format = 0; + state -> items = 0; + state -> after = 0; + state -> data = NULL; + + state -> handler = handler; + + handler -> next = dpy -> async_handlers; + handler -> handler = _NXCollectPropertyHandler; + handler -> data = (XPointer) state; + dpy -> async_handlers = handler; + + _NXCollectedProperties[resource] = state; + + UnlockDisplay(dpy); + + SyncHandle(); + + return True; +} + +int NXGetCollectedProperty(Display *dpy, unsigned int resource, Atom *actual_type_return, + int *actual_format_return, unsigned long *nitems_return, + unsigned long *bytes_after_return, unsigned char **data) +{ + register _NXCollectPropertyState *state; + + state = _NXCollectedProperties[resource]; + + if (state == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXGetCollectedProperty: PANIC! No data collected for resource [%u].\n", + resource); + #endif + + return 0; + } + + *actual_type_return = state -> type; + *actual_format_return = state -> format; + *nitems_return = state -> items; + *bytes_after_return = state -> after; + + *data = (unsigned char *) _NXCollectedProperties[resource] -> data; + + Xfree(state); + + _NXCollectedProperties[resource] = NULL; + + #ifdef TEST + fprintf(stderr, "******NXGetCollectedProperty: Returning GetProperty data for resource [%u].\n", + resource); + #endif + + return True; +} + +static void _NXNotifyGrabPointer(Display *dpy, int resource, Bool success) +{ + XEvent async_event; + + async_event.type = ClientMessage; + + async_event.xclient.serial = _NXCollectedGrabPointers[resource] -> sequence; + + async_event.xclient.window = 0; + async_event.xclient.message_type = 0; + async_event.xclient.format = 32; + + async_event.xclient.data.l[0] = NXCollectGrabPointerNotify; + async_event.xclient.data.l[1] = resource; + async_event.xclient.data.l[2] = success; + + XPutBackEvent(dpy, &async_event); +} + +static Bool _NXCollectGrabPointerHandler(Display *dpy, xReply *rep, char *buf, + int len, XPointer data) +{ + register _NXCollectGrabPointerState *state; + + register xGrabPointerReply *async_rep; + + char *async_head; + + int async_size; + + state = (_NXCollectGrabPointerState *) data; + + if ((rep -> generic.sequenceNumber % 65536) != + ((int)(state -> sequence) % 65536)) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Unmatched sequence [%d] for opcode [%d] " + "with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type, + (int) rep -> generic.length << 2); + #endif + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Going to handle asynchronous GrabPointer reply.\n"); + #endif + + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + + state -> handler = NULL; + + if (rep -> generic.type == X_Error) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Error received from X server for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyGrabPointer(dpy, state -> resource, False); + + _NXCollectedGrabPointers[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Matched request with sequence [%ld].\n", + state -> sequence); + #endif + + async_size = SIZEOF(xGrabPointerReply); + + async_head = Xmalloc(async_size); + + if (async_head == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectGrabPointerHandler: PANIC! Failed to allocate memory with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyGrabPointer(dpy, state -> resource, False); + + _NXCollectedGrabPointers[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Going to get reply with size [%d].\n", + (int) rep -> generic.length << 2); + #endif + + async_rep = (xGrabPointerReply *) _XGetAsyncReply(dpy, async_head, rep, buf, len, 0, False); + + if (async_rep == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectGrabPointerHandler: PANIC! Failed to get reply with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyGrabPointer(dpy, state -> resource, False); + + _NXCollectedGrabPointers[state -> resource] = NULL; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectGrabPointerHandler: Got reply with status [%d] size [%d].\n", + async_rep -> status, (int) async_rep -> length << 2); + #endif + + state -> status = async_rep -> status; + + _NXNotifyGrabPointer(dpy, state -> resource, True); + + Xfree(async_head); + + return True; +} + +int NXGetCollectGrabPointerResource(Display *dpy) +{ + int i; + + for (i = 0; i < NXNumberOfResources; i++) + { + if (_NXCollectedGrabPointers[i] == NULL) + { + return i; + } + } + + return -1; +} + +int NXCollectGrabPointer(Display *dpy, unsigned int resource, Window grab_window, Bool owner_events, + unsigned int event_mask, int pointer_mode, int keyboard_mode, + Window confine_to, Cursor cursor, Time time) +{ + register xGrabPointerReq *req; + + _NXCollectGrabPointerState *state; + _XAsyncHandler *handler; + + if (resource >= NXNumberOfResources) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectGrabPointer: PANIC! Provided resource [%u] is out of range.\n", + resource); + #endif + + return -1; + } + + state = _NXCollectedGrabPointers[resource]; + + if (state != NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectGrabPointer: PANIC! Having to remove previous state for resource [%u].\n", + resource); + #endif + + if (state -> handler != NULL) + { + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + } + + Xfree(state); + + _NXCollectedGrabPointers[resource] = NULL; + } + + LockDisplay(dpy); + + GetReq(GrabPointer, req); + + req -> grabWindow = grab_window; + req -> ownerEvents = owner_events; + req -> eventMask = event_mask; + req -> pointerMode = pointer_mode; + req -> keyboardMode = keyboard_mode; + req -> confineTo = confine_to; + req -> cursor = cursor; + req -> time = time; + + #ifdef TEST + fprintf(stderr, "******NXCollectGrabPointer: Sending message opcode [%d] sequence [%ld] " + "for resource [%d].\n", X_GrabPointer, dpy -> request, resource); + #endif + + state = Xmalloc(sizeof(_NXCollectGrabPointerState)); + handler = Xmalloc(sizeof(_XAsyncHandler)); + + if (state == NULL || handler == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectGrabPointer: Failed to allocate memory with resource [%d].\n", + resource); + #endif + + if (state != NULL) + { + Xfree(state); + } + + if (handler != NULL) + { + Xfree(handler); + } + + UnGetReq(GrabPointer); + + UnlockDisplay(dpy); + + return -1; + } + + state -> sequence = dpy -> request; + state -> resource = resource; + state -> status = 0; + + state -> handler = handler; + + handler -> next = dpy -> async_handlers; + handler -> handler = _NXCollectGrabPointerHandler; + handler -> data = (XPointer) state; + dpy -> async_handlers = handler; + + _NXCollectedGrabPointers[resource] = state; + + UnlockDisplay(dpy); + + SyncHandle(); + + return True; +} + +int NXGetCollectedGrabPointer(Display *dpy, unsigned int resource, int *status) +{ + register _NXCollectGrabPointerState *state; + + state = _NXCollectedGrabPointers[resource]; + + if (state == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXGetCollectedGrabPointer: PANIC! No data collected for resource [%u].\n", + resource); + #endif + + return 0; + } + + *status = state -> status; + + Xfree(state); + + _NXCollectedGrabPointers[resource] = NULL; + + #ifdef TEST + fprintf(stderr, "******NXGetCollectedGrabPointer: Returning GrabPointer data for resource [%u].\n", + resource); + #endif + + return True; +} + +static void _NXNotifyInputFocus(Display *dpy, int resource, Bool success) +{ + XEvent async_event; + + async_event.type = ClientMessage; + + async_event.xclient.serial = _NXCollectedInputFocuses[resource] -> sequence; + + async_event.xclient.window = 0; + async_event.xclient.message_type = 0; + async_event.xclient.format = 32; + + async_event.xclient.data.l[0] = NXCollectInputFocusNotify; + async_event.xclient.data.l[1] = resource; + async_event.xclient.data.l[2] = success; + + XPutBackEvent(dpy, &async_event); +} + +static Bool _NXCollectInputFocusHandler(Display *dpy, xReply *rep, char *buf, + int len, XPointer data) +{ + register _NXCollectInputFocusState *state; + + register xGetInputFocusReply *async_rep; + + char *async_head; + + int async_size; + + state = (_NXCollectInputFocusState *) data; + + if ((rep -> generic.sequenceNumber % 65536) != + ((int)(state -> sequence) % 65536)) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Unmatched sequence [%d] for opcode [%d] " + "with length [%d].\n", rep -> generic.sequenceNumber, rep -> generic.type, + (int) rep -> generic.length << 2); + #endif + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Going to handle asynchronous GetInputFocus reply.\n"); + #endif + + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + + state -> handler = NULL; + + if (rep -> generic.type == X_Error) + { + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Error received from X server for resource [%d].\n", + state -> resource); + #endif + + _NXNotifyInputFocus(dpy, state -> resource, False); + + _NXCollectedInputFocuses[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Matched request with sequence [%ld].\n", + state -> sequence); + #endif + + async_size = SIZEOF(xGetInputFocusReply); + + async_head = Xmalloc(async_size); + + if (async_head == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectInputFocusHandler: PANIC! Failed to allocate memory with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyInputFocus(dpy, state -> resource, False); + + _NXCollectedInputFocuses[state -> resource] = NULL; + + Xfree(state); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Going to get reply with size [%d].\n", + (int) rep -> generic.length << 2); + #endif + + async_rep = (xGetInputFocusReply *) _XGetAsyncReply(dpy, async_head, rep, buf, len, 0, False); + + if (async_rep == NULL) + { + #ifdef PANIC + fprintf(stderr, "******_NXCollectInputFocusHandler: PANIC! Failed to get reply with resource [%d].\n", + state -> resource); + #endif + + _NXNotifyInputFocus(dpy, state -> resource, False); + + _NXCollectedInputFocuses[state -> resource] = NULL; + + Xfree(state); + + Xfree(async_head); + + return False; + } + + #ifdef TEST + fprintf(stderr, "******_NXCollectInputFocusHandler: Got reply with focus [%d] revert to [%d] " + "size [%d].\n", (int) async_rep -> focus, (int) async_rep -> revertTo, + (int) async_rep -> length << 2); + #endif + + state -> focus = async_rep -> focus; + state -> revert_to = async_rep -> revertTo; + + _NXNotifyInputFocus(dpy, state -> resource, True); + + Xfree(async_head); + + return True; +} + +int NXGetCollectInputFocusResource(Display *dpy) +{ + int i; + + for (i = 0; i < NXNumberOfResources; i++) + { + if (_NXCollectedInputFocuses[i] == NULL) + { + return i; + } + } + + return -1; +} + +int NXCollectInputFocus(Display *dpy, unsigned int resource) +{ + register xReq *req; + + _NXCollectInputFocusState *state; + _XAsyncHandler *handler; + + if (resource >= NXNumberOfResources) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectInputFocus: PANIC! Provided resource [%u] is out of range.\n", + resource); + #endif + + return -1; + } + + state = _NXCollectedInputFocuses[resource]; + + if (state != NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectInputFocus: PANIC! Having to remove previous state for resource [%u].\n", + resource); + #endif + + if (state -> handler != NULL) + { + DeqAsyncHandler(dpy, state -> handler); + + Xfree(state -> handler); + } + + Xfree(state); + + _NXCollectedInputFocuses[resource] = NULL; + } + + LockDisplay(dpy); + + GetEmptyReq(GetInputFocus, req); + + #ifdef TEST + fprintf(stderr, "******NXCollectInputFocus: Sending message opcode [%d] sequence [%ld] for resource [%d].\n", + X_GetInputFocus, dpy -> request, resource); + #endif + + state = Xmalloc(sizeof(_NXCollectInputFocusState)); + handler = Xmalloc(sizeof(_XAsyncHandler)); + + if (state == NULL || handler == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectInputFocus: Failed to allocate memory with resource [%d].\n", + resource); + #endif + + if (state != NULL) + { + Xfree(state); + } + + if (handler != NULL) + { + Xfree(handler); + } + + UnGetEmptyReq(); + + UnlockDisplay(dpy); + + return -1; + } + + state -> sequence = dpy -> request; + state -> resource = resource; + state -> focus = 0; + state -> revert_to = 0; + + state -> handler = handler; + + handler -> next = dpy -> async_handlers; + handler -> handler = _NXCollectInputFocusHandler; + handler -> data = (XPointer) state; + dpy -> async_handlers = handler; + + _NXCollectedInputFocuses[resource] = state; + + UnlockDisplay(dpy); + + SyncHandle(); + + return True; +} + +int NXGetCollectedInputFocus(Display *dpy, unsigned int resource, + Window *focus_return, int *revert_to_return) +{ + register _NXCollectInputFocusState *state; + + state = _NXCollectedInputFocuses[resource]; + + if (state == NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXGetCollectedInputFocus: PANIC! No data collected for resource [%u].\n", + resource); + #endif + + return 0; + } + + *focus_return = state -> focus; + *revert_to_return = state -> revert_to; + + Xfree(state); + + _NXCollectedInputFocuses[resource] = NULL; + + #ifdef TEST + fprintf(stderr, "******NXGetCollectedInputFocus: Returning GetInputFocus data for resource [%u].\n", + resource); + #endif + + return True; +} + +#ifdef DUMP + +void _NXDumpData(const unsigned char *buffer, unsigned int size) +{ + if (buffer != NULL) + { + unsigned int i = 0; + + unsigned int ii; + + while (i < size) + { + fprintf(stderr, "[%d]\t", i); + + for (ii = 0; i < size && ii < 8; i++, ii++) + { + fprintf(stderr, "%d\t", (unsigned int) (buffer[i])); + } + + fprintf(stderr, "\n"); + } + } +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Compext.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Compext.h new file mode 100644 index 000000000..ecd7d1e18 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Compext.h @@ -0,0 +1,912 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef NXlib_H +#define NXlib_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nx-X11/X.h> +#include <nx-X11/Xlib.h> + +#include <nx/NX.h> +#include <nx/NXpack.h> +#include <nx/NXproto.h> +#include <nx/NXvars.h> + +/* + * All the NX code should use these. + */ + +#define Xmalloc(size) malloc((size)) +#define Xfree(ptr) free((ptr)) + +/* + * Maximum number of supported pack methods. + */ + +#define NXNumberOfPackMethods 128 + +/* + * Assume this as the limit of resources that + * can be provided to the split and unpack + * requests. + */ + +#define NXNumberOfResources 256 + +#define NXNoResource 256 + 1 +#define NXAnyResource 256 + 2 + +/* + * Initialize the internal structures used by + * the library. Should be executed again after + * having reopened the display. + */ + +extern int NXInitDisplay( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +/* + * Reset all the internal structures. Should be + * executed after closing the display. + */ + +extern int NXResetDisplay( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +/* + * Set the NX display flush policy. The policy can + * be either NXFlushDeferred or NXFlushImmediate. + */ + +extern int NXSetDisplayPolicy( +#if NeedFunctionPrototypes + Display* /* display */, + int /* policy */ +#endif +); + +/* + * Set the display output buffer size. + */ + +extern int NXSetDisplayBuffer( +#if NeedFunctionPrototypes + Display* /* display */, + int /* size */ +#endif +); + +/* + * If set, the Popen() function in the X server + * wil remove the LD_LIBRARY_PATH variable from + * the environment before calling the execl() + * function on the child process. The function + * returns the previous value. + */ + +extern int NXUnsetLibraryPath( +#if NeedFunctionPrototypes + int /* value */ +#endif +); + +/* + * If the parameter is true, the Xlib I/O error + * handler will return, instead of quitting the + * program. The function returns the previous + * value. + */ + +extern int NXHandleDisplayError( +#if NeedFunctionPrototypes + int /* value */ +#endif +); + +/* + * Shutdown the display descriptor and force Xlib + * to set the I/O error flag. + */ + +extern Bool NXForceDisplayError( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +/* + * Check the value of the XlibDisplayIOError flag. + * If not set, try to call the display error hand- + * ler to give to the application a chance to see + * whether it needs to close the connection. + */ + +extern int NXDisplayError( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +/* + * Query the number of bytes readable from the + * display connection. + */ + +extern int NXDisplayReadable( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +/* + * Query the number of the outstanding bytes to + * flush to the display connection. + */ + +extern int NXDisplayFlushable( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +/* + * Return a value between 0 and 9 indicating the + * congestion level of the NX transport based on + * the tokens remaining. A value of 9 means that + * the link is congested and no further data can + * be sent. + */ + +extern int NXDisplayCongestion( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +/* + * Flush the Xlib display buffer and/or the + * outstanding data accumulated by the NX + * transport. + */ + +extern int NXFlushDisplay( +#if NeedFunctionPrototypes + Display* /* display */, + int /* what */ +#endif +); + +/* + * Public interfaces used to set the handlers. + * They all return the previous handler. + */ + +extern NXDisplayErrorPredicate NXSetDisplayErrorPredicate( +#if NeedFunctionPrototypes + NXDisplayErrorPredicate /* predicate */ +#endif +); + +/* + * Called when the display blocks waiting to read or + * write more data. + */ + +extern NXDisplayBlockHandler NXSetDisplayBlockHandler( +#if NeedFunctionPrototypes + NXDisplayBlockHandler /* handler */ +#endif +); + +/* + * Called after more data is written to the display. + * When the NX transport is running, data may be queued + * until an explicit flush. + */ + +extern NXDisplayWriteHandler NXSetDisplayWriteHandler( +#if NeedFunctionPrototypes + NXDisplayWriteHandler /* handler */ +#endif +); + +/* + * Called after more data is sent to the remote proxy. + * + * Here the display pointer is passed as the second + * parameter to make clear that the function does not + * tie the callback to the display, but, similarly to + * all the Xlib error handlers, to a global variable + * shared by all the Xlib functions. The display + * pointer will be passed back by nxcomp at the time + * it will call the handler. This is because nxcomp + * doesn't have access to the display structure. + */ + +extern NXDisplayFlushHandler NXSetDisplayFlushHandler( +#if NeedFunctionPrototypes + NXDisplayFlushHandler /* handler */, + Display* /* display */ +#endif +); + +/* + * Get an arbitrary null terminated buffer to be added + * to the NX statistics. + */ + +extern NXDisplayStatisticsHandler NXSetDisplayStatisticsHandler( +#if NeedFunctionPrototypes + NXDisplayStatisticsHandler /* handler */, + char ** /* buffer */ +#endif +); + +/* + * Redefine the function called by Xlib in the case of + * an out-of-order sequence number received in the X + * protocol stream. + */ + +extern NXLostSequenceHandler NXSetLostSequenceHandler( +#if NeedFunctionPrototypes + NXLostSequenceHandler /* handler */ +#endif +); + +/* + * The agent should get the NX parameters at startup, just after + * having opened the display. If the agent is not able to satisfy + * the pack method set by user (because a method is not applica- + * ble, it is not supported by the remote or it simply requires a + * screen depth greater than the depth available), it should fall + * back to the nearest method of the same type. + */ + +extern Status NXGetControlParameters( +#if NeedFunctionPrototypes + Display* /* display */, + 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* /* frame_timeout */, + int* /* ping_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 */ +#endif +); + +/* + * Which unpack methods are supported by the remote proxy? + */ + +extern Status NXGetUnpackParameters( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int* /* entries */, + unsigned char[] /* supported_methods */ +#endif +); + +/* + * Query and enable shared memory support on path agent to X + * client proxy and X server proxy to real X server. At the + * moment only the path proxy to real X server is implemented. + * On return flags will say if support has been successfully + * activated. Segments will contain the XID associated to the + * shared memory blocks. A MIT-SHM compliant protocol is used + * between proxy and the real server, while a simplified + * version is used between the agent and the client proxy to + * accomodate both packed images and plain X bitmaps. + */ + +extern Status NXGetShmemParameters( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int* /* enable_client */, + unsigned int* /* enable_server */, + unsigned int* /* client_segment */, + unsigned int* /* server_segment */, + unsigned int* /* client_size */, + unsigned int* /* server_size */ +#endif +); + +/* + * 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. + */ + +extern Status NXGetFontParameters( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* path_length */, + char[] /* path_data */ +#endif +); + +/* + * This set of functions is used to leverage the image stream- + * ing capabilities built in nxcomp. An image can be streamed + * by sending a start-split message, followed by the X messages + * that will have to be split by the proxy, followed by an end- + * split closure. Usually, in the middle of a start-split/end- + * split sequence there will be a single PutImage() or PutPack- + * edImage(), that, in turn, can generate multiple partial + * requests, like a SetUnpackColormap() and SetUnpackAlpha() + * that will be later used to decompress the image to its ori- + * ginal form. Multiple requests may be also generated because + * of the maximum size of a X request being exceeded, so that + * Xlib has to divide the single image in multiple sub-image re- + * quests. The agent doesn't need to take care of these details + * but will rather have to track the result of the split opera- + * tion. By monitoring the notify events sent by the proxy, the + * agent will have to implement its own strategy to deal with + * the resources. For example, it will be able to: + * + * - Mark a drawable as dirty, if the image was not sent + * synchronously, in the main X oputput stream. + * + * - Choose to commit or discard the original image, at the + * time it will be recomposed at the remote side. This may + * include all the messages that were part of the split + * (the colormap, the alpha channel, etc.) + * + * - Mark the drawable as clean again, if the image was + * committed and the drawable didn't change in the mean- + * while. + * + * At the time the proxy receives the end-split, it reports the + * result of the operation to the agent. The agent will be able + * to identify the original split operation (the one referenced + * in the start-split/end-split sequence) by the small integer + * number (0-255) named 'resource' sent in the events. + * + * One of the following cases may be encountered: + * + * + * NXNoSplitNotify All messages were sent in the main out- + * put stream, so that no split actually + * took place. + * + * NXStartSplitNotify One or more messages were split, so, + * at discrection of the agent, the client + * may be suspended until the transferral + * is completed. + * + * NXCommitSplitNotify One of the requests that made up the + * split was recomposed. The agent should + * either commit the given request or tell + * the proxy to discard it. + * + * NXEndSplitNotify The split was duly completed. The agent + * can restart the client. + * + * NXEmptySplitNotify No more split operation are pending. + * The agent can use this information to + * implement specific strategies requiring + * that all messages have been recomposed + * at the remote end, like updating the + * drawables that were not synchronized + * because of the lazy encoding. + * + * The 'mode' field that is sent by the agent in the start-split + * request, determines the strategy that the proxy will adopt to + * deal with the image. If set to 'eager', the proxy will only + * split the messages whose size exceeds the split threshold (the + * current threshold can be found in the NXGetControlParameters() + * reply). If the mode is set to lazy, the proxy will split any + * image that would have generated an actual transfer of the data + * part (in practice all images that are not found in the cache). + * This second strategy can be leveraged by an agent to further + * reduce the bandwidth requirements. For example, by setting the + * mode to lazy and by monitoring the result, an agent can easi- + * ly verify if the drawable was successfully updated, mark the + * drawable if not, and synchronize it at later time. + * + * See NXproto.h for the definition of the available modes. + */ + +extern unsigned int NXAllocSplit( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */ +#endif +); + +extern int NXStartSplit( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + unsigned int /* mode */ +#endif +); + +extern int NXEndSplit( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */ +#endif +); + +extern int NXCommitSplit( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + unsigned int /* propagate */, + unsigned char /* request */, + unsigned int /* position */ +#endif +); + +extern int NXAbortSplit( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */ +#endif +); + +extern int NXFinishSplit( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */ +#endif +); + +extern int NXFreeSplit( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */ +#endif +); + +extern int NXSetExposeParameters( +#if NeedFunctionPrototypes + Display* /* display */, + int /* expose */, + int /* graphics_expose */, + int /* no_expose */ +#endif +); + +extern int NXSetCacheParameters( +#if NeedFunctionPrototypes + Display* /* display */, + int /* enable_cache */, + int /* enable_split */, + int /* enable_save */, + int /* enable_load */ +#endif +); + +extern unsigned int NXAllocUnpack( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */ +#endif +); + +extern int NXSetUnpackGeometry( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + Visual* /* visual */ +#endif +); + +extern int NXSetUnpackColormap( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + unsigned int /* method */, + unsigned int /* entries */, + const char* /* data */, + unsigned int /* data_length */ +#endif +); + +extern int NXSetUnpackAlpha( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + unsigned int /* method */, + unsigned int /* entries */, + const char* /* data */, + unsigned int /* data_length */ +#endif +); + +extern int NXSetUnpackColormapCompat( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + unsigned int /* entries */, + const char* /* data */ +#endif +); + +extern int NXSetUnpackAlphaCompat( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + unsigned int /* entries */, + const char* /* data */ +#endif +); + +extern int NXFreeUnpack( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */ +#endif +); + +/* + * A packed image is a XImage but with + * offset field containing total amount + * of packed image data. + */ + +typedef XImage NXPackedImage; + +NXPackedImage *NXCreatePackedImage( +#if NeedFunctionPrototypes + Display* /* display */, + 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 */ +#endif +); + +extern int NXDestroyPackedImage( +#if NeedFunctionPrototypes + NXPackedImage* /* image */ +#endif +); + +NXPackedImage *NXPackImage( +#if NeedFunctionPrototypes + Display* /* display */, + XImage* /* src_image */, + unsigned int /* method */ +#endif +); + +NXPackedImage *NXInPlacePackImage( +#if NeedFunctionPrototypes + Display* /* display */, + XImage* /* src_image */, + unsigned int /* method */ +#endif +); + +/* + * GC is declared void * to get rid of mess + * with different GC definitions in some X + * server code (like in nxagent). + */ + +extern int NXPutPackedImage( +#if NeedFunctionPrototypes + Display* /* display */, + 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 */ +#endif +); + +/* + * Get multiple colors with a single call by + * pipelining X_AllocColor requests/replies. + */ + +extern int NXAllocColors( +#if NeedFunctionPrototypes + Display* /* display */, + Colormap /* colormap */, + unsigned int /* entries */, + XColor[] /* screens_in_out */, + Bool [] /* flags allocation errors */ +#endif +); + +/* + * Encode the data in the given format. + */ + +extern char *NXEncodeColormap( +#if NeedFunctionPrototypes + const char* /* src_data */, + unsigned int /* src_size */, + unsigned int* /* dst_size */ +#endif +); + +extern char *NXEncodeAlpha( +#if NeedFunctionPrototypes + const char* /* src_data */, + unsigned int /* src_size */, + unsigned int* /* dst_size */ +#endif +); + +extern NXPackedImage *NXEncodeRgb( +#if NeedFunctionPrototypes + XImage* /* src_image */, + unsigned int /* method */, + unsigned int /* quality */ +#endif +); + +extern NXPackedImage *NXEncodeRle( +#if NeedFunctionPrototypes + XImage* /* src_image */, + unsigned int /* method */, + unsigned int /* quality */ +#endif +); + +extern NXPackedImage *NXEncodeJpeg( +#if NeedFunctionPrototypes + XImage* /* src_image */, + unsigned int /* method */, + unsigned int /* quality */ +#endif +); + +typedef struct +{ + long pixel; + int found; + +} NXColorTable; + +extern int NXEncodeColors( +#if NeedFunctionPrototypes + XImage* /* src_image */, + NXColorTable* /* color_table */, + int /* nb_max */ +#endif +); + +extern NXPackedImage *NXEncodePng( +#if NeedFunctionPrototypes + XImage* /* src_image */, + unsigned int /* method */, + unsigned int /* quality */ +#endif +); + +extern NXPackedImage *NXEncodeBitmap( +#if NeedFunctionPrototypes + XImage* /* src_image */, + unsigned int /* method */, + unsigned int /* quality */ +#endif +); + +extern int NXCleanImage( +#if NeedFunctionPrototypes + XImage* +#endif +); + +extern void NXMaskImage( +#if NeedFunctionPrototypes + XImage* /* pointer to image to mask */ , + unsigned int /* method */ +#endif +); + +extern int NXImageCacheSize; + +extern void NXInitCache( +#if NeedFunctionPrototypes + Display* /* display */, + int /* entries in image cache */ +#endif +); + +extern void NXFreeCache( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +extern XImage *NXCacheFindImage( +#if NeedFunctionPrototypes + NXPackedImage* /* packed image to find */, + unsigned int* /* pointer to the pack method if found */, + unsigned char** /* pointer to the calculated MD5 if found */ +#endif +); + +extern int NXCacheAddImage( +#if NeedFunctionPrototypes + NXPackedImage* /* packed image to be added to the cache */, + unsigned int /* pack method of the image to add */, + unsigned char* /* pointer to MD5 of the original unpacked image */ +#endif +); + + +extern int NXGetCollectImageResource( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +extern int NXCollectImage( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + Drawable /* drawable */, + int /* src_x */, + int /* src_y */, + unsigned int /* width */, + unsigned int /* height */, + unsigned long /* plane_mask */, + int /* format */ +#endif +); + +extern int NXGetCollectedImage( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + XImage** /* image */ +#endif +); + +extern int NXGetCollectPropertyResource( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +extern int NXCollectProperty( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + Window /* window */, + Atom /* property */, + long /* long_offset */, + long /* long_length */, + Bool /* delete */, + Atom /* req_type */ +#endif +); + +extern int NXGetCollectedProperty( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + Atom* /* actual_type_return */, + int* /* actual_format_return */, + unsigned long* /* nitems_return */, + unsigned long* /* bytes_after_return */, + unsigned char** /* data */ +#endif +); + +extern int NXGetCollectGrabPointerResource( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +extern int NXCollectGrabPointer( +#if NeedFunctionPrototypes + Display* /* display */, + 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 */ +#endif +); + +extern int NXGetCollectedGrabPointer( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + int* /* status */ +#endif +); + +extern int NXGetCollectInputFocusResource( +#if NeedFunctionPrototypes + Display* /* display */ +#endif +); + +extern int NXCollectInputFocus( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */ +#endif +); + +extern int NXGetCollectedInputFocus( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned int /* resource */, + Window* /* focus_return */, + int* /* revert_to_return */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* NXlib_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Imakefile b/nx-X11/programs/Xserver/hw/nxagent/compext/Imakefile new file mode 100644 index 000000000..8f0f17d1e --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Imakefile @@ -0,0 +1,48 @@ +NULL = + +#include <Server.tmpl> + +SRCS = \ + Alpha.c \ + Bitmap.c \ + Clean.c \ + Colormap.c \ + Compext.c \ + Jpeg.c \ + Mask.c \ + Png.c \ + Rgb.c \ + Rle.c \ + Z.c \ + $(NULL) + +OBJS = \ + Alpha.o \ + Bitmap.o \ + Clean.o \ + Colormap.o \ + Compext.o \ + Jpeg.o \ + Mask.o \ + Png.o \ + Rgb.o \ + Rle.o \ + Z.o \ + $(NULL) + + INCLUDES = -I$(SERVERSRC)/include \ + -I$(XBUILDINCDIR) \ + `pkg-config --cflags-only-I pixman-1` \ + `pkg-config --cflags-only-I zlib` \ + `pkg-config --cflags-only-I libpng` \ + $(NULL) + + LINTLIBS = $(SERVERSRC)/dix/llib-ldix.ln \ + $(NULL) + +NormalLibraryObjectRule() +NormalLibraryTarget(compext,$(OBJS)) +LintLibraryTarget(compext,$(SRCS)) +NormalLintTarget($(SRCS)) + +DependTarget() diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Jpeg.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Jpeg.c new file mode 100644 index 000000000..690a934f6 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Jpeg.c @@ -0,0 +1,480 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <nx-X11/X.h> +#include <nx-X11/Xlib.h> +#include <nx-X11/Xmd.h> + +#include <jpeglib.h> + +#include "Compext.h" + +#include "Mask.h" +#include "Jpeg.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define JPEG_DEST_SIZE(width, height) ((width) * 3 * (height) + 1024) + +/* + * Local function prototypes. + */ + +static void PrepareRowForJpeg(CARD8 *dst, int y, int count); +static void PrepareRowForJpeg24(CARD8 *dst, int y, int count); +static void PrepareRowForJpeg16(CARD8 *dst, int y, int count); +static void PrepareRowForJpeg32(CARD8 *dst, int y, int count); + +static int JpegEmptyOutputBuffer(j_compress_ptr cinfo); + +static void JpegInitDestination(j_compress_ptr cinfo); +static void JpegTermDestination(j_compress_ptr cinfo); +static void JpegSetDstManager(j_compress_ptr cinfo); + +/* + * Quality levels. + */ + +static int jpegQuality[10] = {20, 30, 40, 50, 55, 60, 65, 70, 75, 80}; + +/* + * Image characteristics. + */ + +static int bytesPerLine; + +static CARD8 bitsPerPixel; +static CARD16 redMax, greenMax, blueMax; +static CARD8 redShift, greenShift, blueShift; +static int byteOrder; + +/* + * Other variables used for the Jpeg + * encoding. + */ + +static char *jpegBeforeBuf = NULL; +static char *jpegCompBuf; +static int jpegCompBufSize; +static int jpegError; +static int jpegDstDataLen; + +static struct jpeg_destination_mgr jpegDstManager; + +/* + * Just for debugging purpose. + */ + +#ifdef DEBUG + +static int jpegId; +static char jpegName[10]; +static FILE *jpegFile; + +#endif + +/* + * Function declarations + */ + +char *JpegCompressData(XImage *image, int level, int *compressed_size) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + CARD8 *srcBuf; + JSAMPROW rowPointer[1]; + + int dy, w, h; + + *compressed_size = 0; + + /* + * Initialize the image stuff + */ + + bitsPerPixel = image -> bits_per_pixel; + bytesPerLine = image -> bytes_per_line; + byteOrder = image -> byte_order; + + #ifdef TEST + fprintf(stderr, "******JpegCompressData: Image byte order [%d] bitmap bit order [%d].\n", + image -> byte_order, image -> bitmap_bit_order); + + fprintf(stderr, "******JpegCompressData: Bits per pixel [%d] bytes per line [%d].\n", + bitsPerPixel, bytesPerLine); + #endif + + redShift = FindLSB(image -> red_mask) - 1; + greenShift = FindLSB(image -> green_mask) - 1; + blueShift = FindLSB(image -> blue_mask) - 1; + + #ifdef TEST + fprintf(stderr, "******JpegCompressData: Red mask [0x%lx] green mask [0x%lx] blue mask [0x%lx].\n", + image -> red_mask, image -> green_mask, image -> blue_mask); + + fprintf(stderr, "******JpegCompressData: Red shift [%d] green shift [%d] blue shift [%d].\n", + redShift, greenShift, blueShift); + #endif + + redMax = image -> red_mask >> redShift; + greenMax = image -> green_mask >> greenShift; + blueMax = image -> blue_mask >> blueShift; + + #ifdef TEST + fprintf(stderr, "******JpegCompressData: Red max [0x%x] green max [0x%x] blue max [0x%x].\n", + redMax, greenMax, blueMax); + #endif + + w = image -> width; + h = image -> height; + + jpegBeforeBuf = image -> data; + + #ifdef DEBUG + fprintf(stderr, "******JpegCompressData: Width [%d] height [%d] level [%d].\n", + w, h, level); + #endif + + if (bitsPerPixel == 1 || + bitsPerPixel == 8) + { + #ifdef PANIC + fprintf(stderr, "******JpegCompressData: PANIC! Invalid bits per pixel [%d].\n", + bitsPerPixel); + #endif + + return NULL; + } + + /* + * Allocate space for one line of the + * resulting image, 3 bytes per pixel. + */ + + #ifdef DEBUG + fprintf(stderr, "******JpegCompressData: Allocating [%d] bytes for the scanline.\n", + w * 3); + #endif + + srcBuf = (CARD8 *) malloc(w * 3); + + if (srcBuf == NULL) + { + #ifdef PANIC + fprintf(stderr, "******JpegCompressData: PANIC! Cannot allocate [%d] bytes.\n", + w * 3); + #endif + + return NULL; + } + + rowPointer[0] = srcBuf; + + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_compress(&cinfo); + + cinfo.image_width = w; + cinfo.image_height = h; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, jpegQuality[level], 1); + + /* + * Allocate memory for the destination + * buffer. + */ + + jpegCompBufSize = JPEG_DEST_SIZE(w, h); + + #ifdef TEST + fprintf(stderr, "******JpegCompressData: Allocating [%d] bytes for the destination data.\n", + jpegCompBufSize); + #endif + + jpegCompBuf = malloc(jpegCompBufSize); + + if (jpegCompBuf == NULL) + { + #ifdef PANIC + fprintf(stderr, "******JpegCompressData: PANIC! Error allocating [%d] bytes for the Jpeg data.\n", + jpegCompBufSize); + #endif + + return NULL; + } + + JpegSetDstManager(&cinfo); + + jpeg_start_compress(&cinfo, 1); + + #ifdef DEBUG + fprintf(stderr, "******JpegCompressedData: Initialization finished.\n"); + #endif + + for (dy = 0; dy < h; dy++) + { + PrepareRowForJpeg(srcBuf, dy, w); + + jpeg_write_scanlines(&cinfo, rowPointer, 1); + + if (jpegError != 0) + { + break; + } + } + + #ifdef DEBUG + fprintf(stderr, "******JpegCompressedData: Compression finished. Lines handled [%d,%d]. Error is [%d].\n", + dy, h, jpegError); + #endif + + if (jpegError == 0) + { + jpeg_finish_compress(&cinfo); + } + + jpeg_destroy_compress(&cinfo); + + free((char *) srcBuf); + + if (jpegError != 0) + { + #ifdef PANIC + fprintf(stderr, "******JpegCompressedData: PANIC! Compression failed. Error is [%d].\n", + jpegError); + #endif + + free(jpegCompBuf); + + return NULL; + } + + /* + * Check the size of the resulting data. + */ + + if (jpegDstDataLen > 0) + { + /* + * Save the image on disk to help with + * the debug. + */ + + #ifdef DEBUG + + int i = 0; + + fprintf(stderr, "******JpegCompressedData: Compressed size [%d].\n", + jpegDstDataLen); + + jpegId++; + + sprintf(jpegName, "jpeg%d", jpegId); + + jpegFile = fopen(jpegName, "w"); + + for (i = 0; i < jpegDstDataLen; i++) + { + fprintf(jpegFile, "%c", *(jpegCompBuf + i)); + } + + fclose(jpegFile); + + #endif + + *compressed_size = jpegDstDataLen; + + return jpegCompBuf; + } + else + { + #ifdef PANIC + fprintf(stderr, "******JpegCompressedData: PANIC! Invalid size of the compressed data [%d].\n", + jpegDstDataLen); + #endif + + free(jpegCompBuf); + + return NULL; + } +} + +void PrepareRowForJpeg(CARD8 *dst, int y, int count) +{ + if (bitsPerPixel == 32) + { + if (redMax == 0xff && + greenMax == 0xff && + blueMax == 0xff) + { + PrepareRowForJpeg24(dst, y, count); + } + else + { + PrepareRowForJpeg32(dst, y, count); + } + } + else if (bitsPerPixel == 24) + { + memcpy(dst, jpegBeforeBuf + y * bytesPerLine, count * 3); + } + else + { + /* + * 16 bpp assumed. + */ + + PrepareRowForJpeg16(dst, y, count); + } +} + +void PrepareRowForJpeg24(CARD8 *dst, int y, int count) +{ + CARD8 *fbptr; + CARD32 pix; + + fbptr = (CARD8 *) (jpegBeforeBuf + y * bytesPerLine); + + while (count--) + { + if (byteOrder == LSBFirst) + { + pix = (CARD32) *(fbptr + 2); + pix = (pix << 8) | (CARD32) *(fbptr+1); + pix = (pix << 8) | (CARD32) *fbptr; + } + else + { + pix = (CARD32) *(fbptr + 1); + pix = (pix << 8) | (CARD32) *(fbptr + 2); + pix = (pix << 8) | (CARD32) *(fbptr + 3); + } + + *dst++ = (CARD8)(pix >> redShift); + *dst++ = (CARD8)(pix >> greenShift); + *dst++ = (CARD8)(pix >> blueShift); + + fbptr+=4; + } +} + +#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \ + \ +void PrepareRowForJpeg##bpp(CARD8 *dst, int y, int count) \ +{ \ + CARD8 *fbptr; \ + CARD##bpp pix; \ + int inRed, inGreen, inBlue; \ + int i; \ + \ + fbptr = (CARD8 *) (jpegBeforeBuf + y * bytesPerLine); \ + \ + while (count--) \ + { \ + pix = 0; \ + \ + if (byteOrder == LSBFirst) \ + { \ + for (i = (bpp >> 3) - 1; i >= 0; i--) \ + { \ + pix = (pix << 8) | (CARD32) *(fbptr + i); \ + } \ + } \ + else \ + { \ + for (i = 0; i < (bpp >> 3); i++) \ + { \ + pix = (pix << 8) | (CARD32) *(fbptr + i); \ + } \ + } \ + \ + fbptr += bpp >> 3; \ + \ + inRed = (int) \ + (pix >> redShift & redMax); \ + inGreen = (int) \ + (pix >> greenShift & greenMax); \ + inBlue = (int) \ + (pix >> blueShift & blueMax); \ + \ + *dst++ = (CARD8)((inRed * 255 + redMax / 2) / \ + redMax); \ + *dst++ = (CARD8)((inGreen * 255 + greenMax / 2) / \ + greenMax); \ + *dst++ = (CARD8)((inBlue * 255 + blueMax / 2) / \ + blueMax); \ + } \ +} + +DEFINE_JPEG_GET_ROW_FUNCTION(16) +DEFINE_JPEG_GET_ROW_FUNCTION(32) + +/* + * Destination manager implementation for JPEG library. + */ + +void JpegInitDestination(j_compress_ptr cinfo) +{ + jpegError = 0; + + jpegDstManager.next_output_byte = (JOCTET *) jpegCompBuf; + jpegDstManager.free_in_buffer = (size_t) jpegCompBufSize; +} + +int JpegEmptyOutputBuffer(j_compress_ptr cinfo) +{ + jpegError = 1; + + jpegDstManager.next_output_byte = (JOCTET *) jpegCompBuf; + jpegDstManager.free_in_buffer = (size_t) jpegCompBufSize; + + return 1; +} + +void JpegTermDestination(j_compress_ptr cinfo) +{ + jpegDstDataLen = jpegCompBufSize - jpegDstManager.free_in_buffer; +} + +void JpegSetDstManager(j_compress_ptr cinfo) +{ + jpegDstManager.init_destination = JpegInitDestination; + jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer; + jpegDstManager.term_destination = JpegTermDestination; + + cinfo -> dest = &jpegDstManager; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Jpeg.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Jpeg.h new file mode 100644 index 000000000..b50efd3ec --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Jpeg.h @@ -0,0 +1,46 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Jpeg_H +#define Jpeg_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *JpegCompressData( +#if NeedFunctionPrototypes + XImage* /* image */, + int /* level */, + int* /* compressed_size */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* Jpeg_H */ + diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Mask.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Mask.c new file mode 100644 index 000000000..cdcb8d3c0 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Mask.c @@ -0,0 +1,802 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> + +#include <nx-X11/Xlib.h> + +#include <nx/NXpack.h> + +#include "Mask.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Try first to reduce to a white or black + * pixel. If not possible, apply the mask. + * Note that correction is applied at the + * time pixel is unpacked. + */ + +#define MaskPixel(red, green, blue, mask) \ +\ +if (red > mask -> white_threshold && \ + green > mask -> white_threshold && \ + blue > mask -> white_threshold) \ +{ \ + red = green = blue = 0xff; \ +} \ +else if (red < mask -> black_threshold && \ + green < mask -> black_threshold && \ + blue < mask -> black_threshold) \ +{ \ + red = green = blue = 0x00; \ +} \ +else \ +{ \ + red = red & mask -> color_mask; \ + green = green & mask -> color_mask; \ + blue = blue & mask -> color_mask; \ +} + +int MaskImage(const ColorMask *mask, XImage *src_image, XImage *dst_image) +{ + unsigned long pixel; + + register unsigned int red; + register unsigned int green; + register unsigned int blue; + + register unsigned long data_size; + + register unsigned int i; + + data_size = (src_image -> bytes_per_line * src_image -> height) >> 2; + + #ifdef TEST + fprintf(stderr, "******MaskImage: Going to mask image with [%d] bits per pixel.\n", + src_image -> bits_per_pixel); + #endif + + if (src_image -> bits_per_pixel == 24 || src_image -> bits_per_pixel == 32) + { + register unsigned char *pixel_addr; + + for (i = 0; i < data_size; i++) + { + pixel = ((unsigned long *) src_image -> data)[i]; + + pixel_addr = (unsigned char *) &pixel; + + red = pixel_addr[2]; + green = pixel_addr[1]; + blue = pixel_addr[0]; + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 24/32 bits original R [%d] G [%d] B [%d] A [%d].\n", + red, green, blue, pixel_addr[3]); + #endif + + MaskPixel(red, green, blue, mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 24/32 bits masked R [%d] G [%d] B [%d] A [%d].\n", + red, green, blue, pixel_addr[3]); + #endif + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 24/32 bits pixel 0x%lx", pixel); + #endif + + pixel_addr[2] = red; + pixel_addr[1] = green; + pixel_addr[0] = blue; + + ((unsigned long*)dst_image -> data)[i] = pixel; + + #ifdef DEBUG + fprintf(stderr, " -> 0x%lx\n", pixel); + #endif + } + + return 1; + } + else if (src_image -> bits_per_pixel == 16) + { + /* + * FIXME: Masking doesn't work in 16 bpp. + * + + unsigned long src_addr, *dst_addr; + unsigned short *src_pixels_addr, *dst_pixels_addr; + + for (i = 0; i < data_size; i++) + { + src_addr = ((unsigned long *)src_image -> data)[i]; + dst_addr = (unsigned long *)((unsigned long *)dst_image -> data + i); + + src_pixels_addr = ((unsigned short *) &src_addr); + dst_pixels_addr = ((unsigned short *) dst_addr); + + red = (src_pixels_addr[0] & src_image -> red_mask) >> 8; + green = (src_pixels_addr[0] & src_image -> green_mask) >> 3; + blue = (src_pixels_addr[0] & src_image -> blue_mask) << 3; + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 16 bits original R [%d] G [%d] B [%d].\n", + red, green, blue); + #endif + + MaskPixel(red, green, blue, mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 16 bits masked R [%d] G [%d] B [%d].\n", + red, green, blue); + #endif + + dst_pixels_addr[0] = ((red << 8) & src_image -> red_mask) | + ((green << 3) & src_image -> green_mask) | + ((blue >> 3) & src_image -> blue_mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 16 bits pixel 0x%x", dst_pixels_addr[0]); + #endif + + red = (src_pixels_addr[1] & src_image -> red_mask) >> 8; + green = (src_pixels_addr[1] & src_image -> green_mask) >> 3; + blue = (src_pixels_addr[1] & src_image -> blue_mask) << 3; + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 16 bits original R [%d] G [%d] B [%d].\n", + red, green, blue); + #endif + + MaskPixel(red, green, blue, mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 16 bits masked R [%d] G [%d] B [%d].\n", + red, green, blue); + #endif + + dst_pixels_addr[1] = ((red << 8) & src_image -> red_mask) | + ((green << 3) & src_image -> green_mask) | + ((blue >> 3) & src_image -> blue_mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskImage: 16 bits pixel 0x%x", dst_pixels_addr[0]); + #endif + } + + if (dst_image -> width & 0x00000001) + { + int card32_per_line; + int i; + + card32_per_line = dst_image -> bytes_per_line >> 2; + + for (i = 0; i < dst_image -> height;) + { + ((CARD32 *) dst_image -> data)[(++i * card32_per_line) - 1] &= 0x0000ffff; + } + } + + * + * End of FIXME. + */ + } + else + { + #ifdef TEST + fprintf(stderr, "******MaskImage: PANIC! Cannot apply mask with [%d] bits per pixel.\n", + src_image -> bits_per_pixel); + #endif + + return 0; + } + + return 1; +} + +int MaskInPlaceImage(const ColorMask *mask, XImage *image) +{ + unsigned long pixel; + + register unsigned int red; + register unsigned int green; + register unsigned int blue; + + register unsigned int i; + + register unsigned long data_size; + + data_size = (image -> bytes_per_line * image -> height)>>2; + + #ifdef TEST + fprintf(stderr, "******MaskInPlaceImage: Going to mask image with [%d] bits per pixel.\n", + image -> bits_per_pixel); + #endif + + if (image -> bits_per_pixel == 24 || image -> bits_per_pixel == 32) + { + register unsigned char *pixel_addr; + + for (i = 0; i < data_size; i++) + { + pixel = ((unsigned long *) image -> data)[i]; + + pixel_addr = (unsigned char *) &pixel; + + red = pixel_addr[2]; + green = pixel_addr[1]; + blue = pixel_addr[0]; + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 24/32 bits original R [%d] G [%d] B [%d] A [%d].\n", + red, green, blue, pixel_addr[3]); + #endif + + MaskPixel(red, green, blue, mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 24/32 bits masked R [%d] G [%d] B [%d] A [%d].\n", + red, green, blue, pixel_addr[3]); + #endif + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 24/32 bits pixel 0x%lx", pixel); + #endif + + pixel_addr[2] = red; + pixel_addr[1] = green; + pixel_addr[0] = blue; + + ((unsigned long *) image -> data)[i] = pixel; + + #ifdef DEBUG + fprintf(stderr, " -> 0x%lx\n", pixel); + #endif + } + + return 1; + } + else if (image -> bits_per_pixel == 16) + { + /* + * FIXME: Mask doesn't still work for 16 bits. + * + + unsigned long addr; + register unsigned short *pixels_addr; + + for (i = 0; i < data_size; i++) + { + addr = ((unsigned long *) image -> data)[i]; + + pixels_addr = ((unsigned short *) &addr); + + red = (pixels_addr[0] & image -> red_mask) >> 8; + green = (pixels_addr[0] & image -> green_mask) >> 3; + blue = (pixels_addr[0] & image -> blue_mask) << 3; + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 16 bits original R [%d] G [%d] B [%d].\n", + red, green, blue); + #endif + + MaskPixel(red, green, blue, mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 16 bits masked R [%d] G [%d] B [%d].\n", + red, green, blue); + #endif + + pixels_addr[0] = ((red << 8) & image -> red_mask) | + ((green << 3) & image -> green_mask) | + ((blue >> 3) & image -> blue_mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 16 bits pixel 0x%x", pixels_addr[0]); + #endif + + red = (pixels_addr[1] & image -> red_mask) >> 8; + green = (pixels_addr[1] & image -> green_mask) >> 3; + blue = (pixels_addr[1] & image -> blue_mask) << 3; + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 16 bits original R [%d] G [%d] B [%d].\n", + red, green, blue); + #endif + + MaskPixel(red, green, blue, mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 16 bits masked R [%d] G [%d] B [%d].\n", + red, green, blue); + #endif + + pixels_addr[1] = ((red << 8) & image -> red_mask) | + ((green << 3) & image -> green_mask) | + ((blue >> 3) & image -> blue_mask); + + #ifdef DEBUG + fprintf(stderr, "******MaskInPlaceImage: 16 bits pixel 0x%x", pixels_addr[1]); + #endif + } + + if (image -> width & 0x00000001) + { + int card32_per_line; + int i; + + card32_per_line = image -> bytes_per_line >> 2; + + for (i = 0; i < image -> height;) + { + ((CARD32 *) image -> data)[(++i * card32_per_line) - 1] &= 0x0000ffff; + } + } + + * + * End of FIXME. + */ + } + else + { + #ifdef TEST + fprintf(stderr, "******MaskImage: PANIC! Cannot apply mask with [%d] bits per pixel.\n", + image -> bits_per_pixel); + #endif + + return 0; + } + + return 1; +} + +static int Pack16To8(unsigned int src_data_size, XImage *src_image, XImage *dst_image) +{ + unsigned short *src_pixel = (unsigned short *) src_image -> data; + unsigned char *dst_pixel = (unsigned char *) dst_image -> data; + + #ifdef DEBUG + unsigned int counter = 0; + #endif + + while (src_pixel < ((unsigned short *) (src_image -> data + src_data_size))) + { + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] value [0x%x] red [0x%x] green [0x%x] blue [0x%x].\n", + counter, *src_pixel, (*src_pixel & 0xc000) >> 8, + ((*src_pixel & 0x600) >> 3), (*src_pixel & 0x18) << 3); + #endif + + if (*src_pixel == 0x0) + { + *dst_pixel = 0x0; + } + else if (*src_pixel == 0xffff) + { + *dst_pixel = 0xff; + } + else + { + *dst_pixel = ((*src_pixel & 0xc000) >> 10) | + ((*src_pixel & 0x600) >> 7) | + ((*src_pixel & 0x18) >> 3); + } + + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] destination [0x%x].\n", + counter++, *dst_pixel); + #endif + + src_pixel++; + dst_pixel++; + } + + return 1; +} + +static int Pack24To8(unsigned int src_data_size, XImage *src_image, XImage *dst_image) +{ + unsigned char *src_pixel = (unsigned char *) src_image -> data; + unsigned char *dst_pixel = (unsigned char *) dst_image -> data; + + int i; + + unsigned int bytes_per_line = src_image -> bytes_per_line; + + unsigned char *end_of_line = (unsigned char *) (src_pixel + bytes_per_line); + + + #ifdef DEBUG + unsigned int counter = 0; + #endif + + for (i = 0; i < src_image -> height; i++ ) + { + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] value [0x%x%x%x] red [0x%x] green [0x%x] blue [0x%x].\n", + counter, src_pixel[0], src_pixel[1], src_pixel[2], src_pixel[0] & 0xc0, + src_pixel[1] & 0xc0, src_pixel[2] & 0xc0); + #endif + + while(src_pixel < end_of_line - 2) + { + if (src_pixel[0] == 0x00 && + src_pixel[1] == 0x00 && + src_pixel[2] == 0x00) + { + *dst_pixel = 0x0; + } + else if (src_pixel[0] == 0xff && + src_pixel[1] == 0xff && + src_pixel[2] == 0xff) + { + *dst_pixel = 0xff; + } + else + { + /* + * Pixel layout: + * + * 24 bit RRRRR000 GGGGG000 BBBBB000 -> 8 bit 00RRGGBB + */ + + *dst_pixel = (src_pixel[0] & 0xc0) >> 2 | + ((src_pixel[1] & 0xc0) >> 4) | + ((src_pixel[2] & 0xc0) >> 6); + } + + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] destination [0x%x].\n", + counter++, *dst_pixel); + #endif + + src_pixel += 3; + dst_pixel += 1; + } + + src_pixel = end_of_line; + end_of_line += bytes_per_line; + } + + return 1; +} + +static int Pack24To16(unsigned int src_data_size, XImage *src_image, XImage *dst_image) +{ + unsigned char *src_pixel = (unsigned char *) src_image -> data; + unsigned short *dst_pixel = (unsigned short *) dst_image -> data; + + int i; + + unsigned int bytes_per_line = src_image -> bytes_per_line; + + unsigned char *end_of_line = (unsigned char *) (src_pixel + bytes_per_line); + + #ifdef DEBUG + unsigned int counter = 0; + #endif + + for (i = 0; i < src_image -> height; i++ ) + { + while(src_pixel < end_of_line - 2) + { + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] value [0x%x%x%x] red [0x%x] green [0x%x] blue [0x%x].\n", + counter, src_pixel[0], src_pixel[1], src_pixel[2], src_pixel[0] & 0xf8, + src_pixel[1] & 0xf8, src_pixel[2] & 0xf8); + #endif + + if (src_pixel[0] == 0x00 && + src_pixel[1] == 0x00 && + src_pixel[2] == 0x00) + { + *dst_pixel = 0x0; + } + else if (src_pixel[0] == 0xff && + src_pixel[1] == 0xff && + src_pixel[2] == 0xff) + { + *dst_pixel = 0xffff; + } + else + { + /* + * Pixel layout: + * + * 24 bit RRRRR000 GGGGG000 BBBBB000 -> 16 bit 0RRRRRGG GGGBBBBB + */ + + *dst_pixel = ((src_pixel[0] & 0xf8) << 7) | + ((src_pixel[1] & 0xf8) << 2) | + ((src_pixel[2] & 0xf8) >> 3); + } + + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] destination [0x%x].\n", + counter++, *dst_pixel); + #endif + + src_pixel += 3; + dst_pixel += 1; + } + + src_pixel = end_of_line; + end_of_line += bytes_per_line; + } + + return 1; +} + +static int Pack32To8(unsigned int src_data_size, XImage *src_image, XImage *dst_image) +{ + unsigned int *src_pixel = (unsigned int *) src_image -> data; + unsigned char *dst_pixel = (unsigned char *) dst_image -> data; + + #ifdef DEBUG + unsigned int counter = 0; + #endif + + while (src_pixel < ((unsigned int *) (src_image -> data + src_data_size))) + { + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] value [0x%x] red [0x%x] green [0x%x] blue [0x%x].\n", + counter, *src_pixel, (*src_pixel & 0xc00000), + (*src_pixel & 0xc000), (*src_pixel & 0xc0)); + #endif + + if (*src_pixel == 0x0) + { + *dst_pixel = 0x0; + } + else if (*src_pixel == 0xffffff) + { + *dst_pixel = 0xff; + } + else + { + *dst_pixel = ((*src_pixel & 0xc00000) >> 18) | + ((*src_pixel & 0xc000) >> 12) | + ((*src_pixel & 0xc0) >> 6); + } + + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] destination [0x%x].\n", + counter++, *dst_pixel); + #endif + + src_pixel++; + dst_pixel++; + } + + return 1; +} + +static int Pack32To16(unsigned int src_data_size, XImage *src_image, XImage *dst_image) +{ + unsigned int *src_pixel = (unsigned int *) src_image -> data; + unsigned short *dst_pixel = (unsigned short *) dst_image -> data; + + #ifdef DEBUG + unsigned int counter = 0; + #endif + + while (src_pixel < ((unsigned int *) (src_image -> data + src_data_size))) + { + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] value [0x%x] red [0x%x] green [0x%x] blue [0x%x].\n", + counter, *src_pixel, (*src_pixel & 0xf80000), + (*src_pixel & 0xf800), (*src_pixel & 0xf8)); + #endif + + if (*src_pixel == 0x0) + { + *dst_pixel = 0x0; + } + else if (*src_pixel == 0xffffff) + { + *dst_pixel = 0xffff; + } + else + { + *dst_pixel = ((*src_pixel & 0xf80000) >> 9) | + ((*src_pixel & 0xf800) >> 6) | + ((*src_pixel & 0xf8) >> 3); + } + + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] destination [0x%x].\n", + counter++, *dst_pixel); + #endif + + src_pixel++; + dst_pixel++; + } + + return 1; +} + +static int Pack32To24(unsigned int src_data_size, XImage *src_image, XImage *dst_image) +{ + unsigned int *src_pixel = (unsigned int *) src_image -> data; + unsigned char *dst_pixel = (unsigned char *) dst_image -> data; + + #ifdef DEBUG + unsigned int counter = 0; + #endif + + while (src_pixel < ((unsigned int *) (src_image -> data + src_data_size))) + { + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] value [0x%x] red [0x%x] green [0x%x] blue [0x%x].\n", + counter, *src_pixel, ((*src_pixel & 0xff0000) >> 16), + ((*src_pixel & 0x00ff00) >> 8), (*src_pixel & 0xff)); + #endif + + if (*src_pixel == 0x0) + { + dst_pixel[0] = dst_pixel[1] = dst_pixel[2] = 0x0; + } + else if (*src_pixel == 0xffffff) + { + dst_pixel[0] = dst_pixel[1] = dst_pixel[2] = 0xff; + } + else + { + dst_pixel[0] = (*src_pixel & 0xff0000) >> 16; + dst_pixel[1] = (*src_pixel & 0x00ff00) >> 8; + dst_pixel[2] = (*src_pixel & 0x0000ff); + } + + #ifdef DEBUG + fprintf(stderr, "******PackImage: Pixel [%d] destination [0x%x], [0x%x], [0x%x].\n", + counter++, dst_pixel[0], dst_pixel[1], dst_pixel[2]); + #endif + + src_pixel += 1; + dst_pixel += 3; + } + + return 1; +} + +int PackImage(unsigned int method, unsigned int src_data_size, XImage *src_image, + unsigned int dst_data_size, XImage *dst_image) +{ + unsigned int src_bits_per_pixel; + unsigned int dst_bits_per_pixel; + + src_bits_per_pixel = src_image -> bits_per_pixel; + dst_bits_per_pixel = MethodBitsPerPixel(method); + + #ifdef TEST + fprintf(stderr, "******PackImage: Source bits per pixel [%d], destination bits per pixel [%d].\n", + src_bits_per_pixel, dst_bits_per_pixel); + + fprintf(stderr, "******PackImage: Source data size [%d], destination data size [%d].\n", + src_data_size, dst_data_size); + #endif + + if (dst_bits_per_pixel >= src_bits_per_pixel) + { + #ifdef PANIC + fprintf(stderr, "******PackImage: PANIC! Cannot pack image from [%d] to [%d] bytes per pixel.\n", + src_bits_per_pixel, dst_bits_per_pixel); + #endif + + return 0; + } + + switch (src_bits_per_pixel) + { + case 16: + { + switch (dst_bits_per_pixel) + { + case 8: + { + return Pack16To8(src_data_size, src_image, dst_image); + } + default: + { + return 0; + } + } + } + case 24: + { + switch (dst_bits_per_pixel) + { + case 8: + { + return Pack24To8(src_data_size, src_image, dst_image); + } + case 16: + { + return Pack24To16(src_data_size, src_image, dst_image); + } + default: + { + return 0; + } + } + } + case 32: + { + switch (dst_bits_per_pixel) + { + case 8: + { + return Pack32To8(src_data_size, src_image, dst_image); + } + case 16: + { + return Pack32To16(src_data_size, src_image, dst_image); + } + case 24: + { + return Pack32To24(src_data_size, src_image, dst_image); + } + default: + { + return 0; + } + } + } + default: + { + return 0; + } + } +} + +/* + * Replace the ffs() call that may be not + * present on some systems. + */ + +int FindLSB(int word) +{ + int t = word; + + int m = 1; + int i = 0; + + for (; i < sizeof(word) << 3; i++, m <<= 1) + { + if (t & m) + { + return i + 1; + } + } + + return 0; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Mask.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Mask.h new file mode 100644 index 000000000..1b6fe6d99 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Mask.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Mask_H +#define Mask_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Xlib.h" + +extern int MaskImage(const ColorMask *mask, XImage *src_image, XImage *dst_image); + +extern int MaskInPlaceImage(const ColorMask *mask, XImage *image); + +extern int PackImage(unsigned int method, unsigned int src_data_size, XImage *src_image, + unsigned int dst_data_size, XImage *dst_image); + +int FindLSB(int word); + +#ifdef __cplusplus +} +#endif + +#endif /* Mask_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Png.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Png.c new file mode 100644 index 000000000..b235e095e --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Png.c @@ -0,0 +1,730 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <nx-X11/Xutil.h> + +#include "Compext.h" + +#include "Mask.h" +#include "Png.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Selected ZLIB compression level. + */ + +#define PNG_Z_LEVEL 4 + +/* + * Local function prototypes. + */ + +static void PrepareRowForPng(CARD8 *dst, int y, int count); +static void PrepareRowForPng24(CARD8 *dst, int y, int count); +static void PrepareRowForPng16(CARD8 *dst, int y, int count); +static void PrepareRowForPng32(CARD8 *dst, int y, int count); + +static void PngWriteData(png_structp png_ptr, png_bytep data, png_size_t length); +static void PngFlushData(png_structp png_ptr); + +/* + * Image characteristics. + */ + +static int bytesPerLine; +static int byteOrder; + +static CARD8 bitsPerPixel; +static CARD16 redMax, greenMax, blueMax; +static CARD8 redShift, greenShift, blueShift; + +/* + * Other variables used for the Png + * encoding. + */ + +png_byte color_type; +png_structp png_ptr; +png_infop info_ptr; +png_colorp palette; +static char *pngCompBuf; +static int pngDataLen; +static char *pngBeforeBuf = NULL; + +/* + * Allocate data for the compressed image. + * We need to ensure that there is enough + * space to include the palette and the + * header. + */ + +#define PNG_DEST_SIZE(width, height) ((width) * 3 * (height) + 1024 + 256) + +/* + * Just for debug purposes. + */ + +#ifdef DEBUG + +static int pngId; +static char pngName[10]; +static FILE *pngFile; + +#endif + +int PngCompareColorTable(NXColorTable *c1, NXColorTable *c2) +{ + return (c1 -> pixel - c2 -> pixel); +} + +#define NB_COLOR_MAX 256 + +int NXCreatePalette32(XImage *src_image, NXColorTable *color_table, CARD8 *image_index, int nb_max) +{ + int x, y, t, p; + CARD8 *fbptr; + CARD32 pixel; + + fbptr = (CARD8 *) (src_image -> data); + + /* + * TODO: Find a more intelligent way to + * estimate the number of colors. + */ + + memset(color_table, 0, nb_max * sizeof(NXColorTable)); + + for (x = 0, p = 0; x < src_image -> height; x++) + { + for (y = 0; y < src_image -> width; y++) + { + if (byteOrder == LSBFirst) + { + pixel = (CARD32) *(fbptr + 3); + pixel = (pixel << 8) | (CARD32) *(fbptr + 2); + pixel = (pixel << 8) | (CARD32) *(fbptr + 1); + pixel = (pixel << 8) | (CARD32) *fbptr; + } + else + { + pixel = (CARD32) *fbptr; + pixel = (pixel << 8) | (CARD32) *(fbptr + 1); + pixel = (pixel << 8) | (CARD32) *(fbptr + 2); + pixel = (pixel << 8) | (CARD32) *(fbptr + 3); + } + + fbptr += 4; + + for (t = 0; t < nb_max; t++) + { + if (color_table[t].found == 0) + { + color_table[t].pixel = pixel; + color_table[t].found = 1; + p++; + image_index[((x * src_image -> width) + y)] = t; + + break; + } + else if ((CARD32)(color_table[t].pixel) == pixel) + { + image_index[((x * src_image -> width) + y)] = t; + + break; + } + } + + if (p == nb_max) + { + return nb_max + 1; + } + } + } + return p; +} + +int NXCreatePalette16(XImage *src_image, NXColorTable *color_table, CARD8 *image_index, int nb_max) +{ + int x, y, t, p; + CARD8 *fbptr; + CARD16 pixel; + + fbptr = (CARD8 *) (src_image -> data); + + /* + * TODO: Find a more intelligent way to + * estimate the number of colors. + */ + + memset(color_table, 0, nb_max * sizeof(NXColorTable)); + + for (x = 0, p = 0; x < src_image -> height; x++) + { + for (y = 0; y < src_image -> width; y++) + { + if (byteOrder == LSBFirst) + { + pixel = (CARD16) *(fbptr + 1); + pixel = (pixel << 8) | (CARD16) *fbptr; + } + else + { + pixel = (CARD16) *fbptr; + pixel = (pixel << 8) | (CARD16) *(fbptr + 1); + } + + fbptr += 2; + + for (t = 0; t < nb_max; t++) + { + if (color_table[t].found == 0) + { + color_table[t].pixel = pixel; + color_table[t].found = 1; + p++; + image_index[((x * src_image -> width) + y)] = t; + + break; + } + else if ((color_table[t].pixel) == pixel) + { + image_index[((x * src_image -> width) + y)] = t; + + break; + } + } + + /* + * In case the number of 16bit words is not even + * we have 2 padding bytes that we have to skip. + */ + + if ((y == src_image -> width - 1) && (src_image -> width % 2 == 1)) fbptr += 2; + + if (p == nb_max) + { + return nb_max + 1; + } + } + } + + return p; +} + +char *PngCompressData(XImage *image, int *compressed_size) +{ + unsigned int num = 0; + CARD8 *srcBuf; + + int dy, w, h; + + int nb_colors; + + NXColorTable color_table[NB_COLOR_MAX]; + CARD8 *image_index; + + image_index = (CARD8 *) malloc((image -> height) * (image -> width) * sizeof(CARD8)); + + /* + * TODO: Be sure the padded bytes are cleaned. + * It would be better to set to zero the bytes + * that are not alligned to the word boundary + * at the end of the procedure. + */ + + memset(image_index, 0, (image -> height) * (image -> width) * sizeof(CARD8)); + + *compressed_size = 0; + + pngDataLen = 0; + + /* + * Initialize the image stuff. + */ + + bitsPerPixel = image -> bits_per_pixel; + bytesPerLine = image -> bytes_per_line; + byteOrder = image -> byte_order; + + if (bitsPerPixel < 15) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Can't compress images with [%d] bits per pixel.\n", + bitsPerPixel); + #endif + + return NULL; + } + + redShift = FindLSB(image -> red_mask) - 1; + greenShift = FindLSB(image -> green_mask) - 1; + blueShift = FindLSB(image -> blue_mask) - 1; + + redMax = image -> red_mask >> redShift; + greenMax = image -> green_mask >> greenShift; + blueMax = image -> blue_mask >> blueShift; + + w = image -> width; + h = image -> height; + pngBeforeBuf = image -> data; + + #ifdef DEBUG + fprintf(stderr, "******PngCompressData: Compressing image with width [%d] height [%d].\n", + w, h ); + #endif + + /* + * Initialize the PNG stuff. + */ + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (png_ptr == NULL) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Failed creating the png_create_write_struct.\n"); + #endif + + return NULL; + } + + info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr == NULL) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Failed creating the png_create_info_struct.\n"); + #endif + + png_destroy_write_struct(&png_ptr, NULL); + + return NULL; + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Error during compression initialization.\n"); + #endif + + png_destroy_write_struct(&png_ptr, &info_ptr); + + return NULL; + } + + /* + * Be sure we allocate enough data. + */ + + #ifdef TEST + fprintf(stderr, "******PngCompressData: Allocating [%d] bytes for the destination data.\n", + PNG_DEST_SIZE(w, h)); + #endif + + pngCompBuf = malloc(PNG_DEST_SIZE(w, h)); + + if (pngCompBuf == NULL) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Error allocating [%d] bytes for the Png data.\n", + PNG_DEST_SIZE(w, h)); + #endif + + return NULL; + } + + png_set_write_fn(png_ptr, (void *) pngCompBuf, PngWriteData, PngFlushData); + + if (setjmp(png_jmpbuf(png_ptr))) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Error writing the header.\n"); + #endif + + png_destroy_write_struct(&png_ptr, &info_ptr); + + free(pngCompBuf); + + return NULL; + } + + png_set_compression_level(png_ptr, PNG_Z_LEVEL); + + if (bitsPerPixel == 16) + { + nb_colors = NXCreatePalette16(image, color_table, image_index, NB_COLOR_MAX); + } + else + { + nb_colors = NXCreatePalette32(image, color_table, image_index, NB_COLOR_MAX); + } + + if (nb_colors <= NB_COLOR_MAX) + { + color_type = PNG_COLOR_TYPE_PALETTE; + } + else + { + color_type = PNG_COLOR_TYPE_RGB; + } + + png_set_IHDR(png_ptr, info_ptr, w, h, + 8, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + palette = png_malloc(png_ptr, sizeof(*palette) * 256); + + /* + * TODO: Do we need to clean these bytes? + * + * memset(palette, 0, sizeof(*palette) * 256); + */ + + for (num = 0; num < 256 && color_table[num].found != 0; num++) + { + if (bitsPerPixel == 24) + { + palette[num].red = (color_table[num].pixel >> redShift) & redMax; + palette[num].green = (color_table[num].pixel >> greenShift) & greenMax; + palette[num].blue = color_table[num].pixel >> blueShift & blueMax; + } + else + { + int inRed, inGreen, inBlue; + + inRed = (color_table[num].pixel >> redShift) & redMax; + inGreen = (color_table[num].pixel >> greenShift) & greenMax; + inBlue = color_table[num].pixel >> blueShift & blueMax; + + palette[num].red = (CARD8)((inRed * 255 + redMax / 2) / redMax); + palette[num].green = (CARD8)((inGreen * 255 + greenMax / 2) / greenMax); + palette[num].blue = (CARD8)((inBlue * 255 + blueMax / 2) / blueMax); + } + + #ifdef DEBUG + fprintf(stderr, "******PngCompressData: pixel[%d] r[%d] g[%d] b[%d].\n", + (int) color_table[num].pixel,palette[num].red,palette[num].green,palette[num].blue); + #endif + } + + png_set_PLTE(png_ptr, info_ptr, palette, num); + + #ifdef DEBUG + fprintf(stderr, "******PngCompressedData: Setting palette.\n"); + #endif + } + + /* + * End of palette. + */ + + png_write_info(png_ptr, info_ptr); + + /* + * Allocate space for one line of + * the image, 3 bytes per pixel. + */ + + #ifdef DEBUG + fprintf(stderr, "******PngCompressedData: Initialization finished.\n"); + #endif + + if (setjmp(png_jmpbuf(png_ptr))) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Error while writing the image rows.\n"); + #endif + + png_destroy_write_struct(&png_ptr, &info_ptr); + + free(pngCompBuf); + + return NULL; + } + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + srcBuf = (CARD8 *) malloc(w * sizeof(CARD8)); + + if (srcBuf == NULL) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Cannot allocate [%d] bytes.\n", + (int) (w * sizeof(CARD8))); + #endif + + return NULL; + } + + /* + * TODO: Be sure the padded bytes are cleaned. + * It would be better to set to zero the bytes + * that are not alligned to the word boundary + * at the end of the procedure. + */ + + memset(srcBuf, 0, w * sizeof(CARD8)); + } + else + { + srcBuf = (CARD8 *) malloc(w * 3 * sizeof(CARD8)); + + /* + * TODO: See above. + */ + + memset(srcBuf, 0, w * 3 * sizeof(CARD8)); + } + + if (srcBuf == NULL) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! Cannot allocate [%d] bytes.\n", + w * 3); + #endif + + free(pngCompBuf); + + return NULL; + } + + for (dy = 0; dy < h; dy++) + { + if (color_type == PNG_COLOR_TYPE_RGB) + { + PrepareRowForPng(srcBuf, dy, w); + } + else + { + memcpy(srcBuf, image_index + (dy * w), w); + } + + png_write_row(png_ptr, srcBuf); + } + + #ifdef DEBUG + fprintf(stderr, "******PngCompressedData: Compression finished. Lines handled [%d,%d].\n", + dy, h); + #endif + + free(srcBuf); + free(image_index); + + if (setjmp(png_jmpbuf(png_ptr))) + { + #ifdef PANIC + fprintf(stderr, "******PngCompressData: PANIC! error during end of write.\n"); + #endif + + png_destroy_write_struct(&png_ptr, &info_ptr); + + free(pngCompBuf); + + return NULL; + } + + png_write_end(png_ptr, NULL); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_free(png_ptr, palette); + } + + png_destroy_write_struct(&png_ptr, &info_ptr); + + /* + * Check the size of the resulting data. + */ + + if (pngDataLen > 0) + { + #ifdef DEBUG + + int i = 0; + + fprintf(stderr, "******PngCompressedData: Compressed size [%d].\n", + pngDataLen); + + pngId++; + sprintf(pngName, "png%d", pngId); + pngFile = fopen(pngName, "w"); + + for (i = 0; i < pngDataLen; i++) + { + fprintf(pngFile, "%c", *(pngCompBuf + i)); + } + + fclose(pngFile); + + #endif + + *compressed_size = pngDataLen; + + return pngCompBuf; + } + else + { + #ifdef DEBUG + fprintf(stderr, "******PngCompressedData: PANIC! Invalid size of the compressed data [%d].\n", + pngDataLen); + #endif + + free(pngCompBuf); + + return NULL; + } +} + +static void PngWriteData(png_structp png_ptr, png_bytep data, png_size_t length) +{ + memcpy(((char *) png_get_io_ptr(png_ptr) + pngDataLen), data, length); + + pngDataLen += length; +} + +static void PngFlushData(png_structp png_ptr) +{ +} + +void PrepareRowForPng(CARD8 *dst, int y, int count) +{ + if (bitsPerPixel == 32) + { + if (redMax == 0xff && + greenMax == 0xff && + blueMax == 0xff) + { + PrepareRowForPng24(dst, y, count); + } + else + { + PrepareRowForPng32(dst, y, count); + } + } + else if (bitsPerPixel == 24) + { + memcpy(dst, pngBeforeBuf + y * bytesPerLine, count * 3); + } + else + { + /* + * 16 bpp assumed. + */ + + PrepareRowForPng16(dst, y, count); + } +} + + + +void PrepareRowForPng24(CARD8 *dst, int y, int count) +{ + CARD8 *fbptr; + CARD32 pix; + + fbptr = (CARD8 *) (pngBeforeBuf + y * bytesPerLine); + + while (count--) + { + if (byteOrder == LSBFirst) + { + pix = (CARD32) *(fbptr + 2); + pix = (pix << 8) | (CARD32) *(fbptr+1); + pix = (pix << 8) | (CARD32) *fbptr; + } + else + { + pix = (CARD32) *(fbptr + 1); + pix = (pix << 8) | (CARD32) *(fbptr + 2); + pix = (pix << 8) | (CARD32) *(fbptr + 3); + } + + *dst++ = (CARD8)(pix >> redShift); + *dst++ = (CARD8)(pix >> greenShift); + *dst++ = (CARD8)(pix >> blueShift); + + fbptr+=4; + } +} + +#define DEFINE_PNG_GET_ROW_FUNCTION(bpp) \ + \ +void PrepareRowForPng##bpp(CARD8 *dst, int y, int count) \ +{ \ + CARD8 *fbptr; \ + CARD##bpp pix; \ + int inRed, inGreen, inBlue; \ + int i; \ + \ + fbptr = (CARD8 *) (pngBeforeBuf + y * bytesPerLine); \ + \ + while (count--) \ + { \ + pix = 0; \ + \ + if (byteOrder == LSBFirst) \ + { \ + for (i = (bpp >> 3) - 1; i >= 0; i--) \ + { \ + pix = (pix << 8) | (CARD32) *(fbptr + i); \ + } \ + } \ + else \ + { \ + for (i = 0; i < (bpp >> 3); i++) \ + { \ + pix = (pix << 8) | (CARD32) *(fbptr + i); \ + } \ + } \ + \ + fbptr += (bpp >> 3); \ + \ + inRed = (int) \ + (pix >> redShift & redMax); \ + inGreen = (int) \ + (pix >> greenShift & greenMax); \ + inBlue = (int) \ + (pix >> blueShift & blueMax); \ + *dst++ = (CARD8)((inRed * 255 + redMax / 2) / \ + redMax); \ + *dst++ = (CARD8)((inGreen * 255 + greenMax / 2) / \ + greenMax); \ + *dst++ = (CARD8)((inBlue * 255 + blueMax / 2) / \ + blueMax); \ + } \ +} + +DEFINE_PNG_GET_ROW_FUNCTION(16) +DEFINE_PNG_GET_ROW_FUNCTION(32) diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Png.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Png.h new file mode 100644 index 000000000..0e0621627 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Png.h @@ -0,0 +1,76 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Png_H +#define Png_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nx-X11/X.h> +#include <nx-X11/Xlib.h> +#include <nx-X11/Xmd.h> + +#include <png.h> + +extern int PngCompareColorTable( +#if NeedFunctionPrototypes + NXColorTable* /* color_table_1 */, + NXColorTable* /* color_table_2 */ +#endif +); + +extern char *PngCompressData( +#if NeedFunctionPrototypes + XImage* /* image */, + int* /* compressed_size */ +#endif +); + +int NXCreatePalette16( +#if NeedFunctionPrototypes + XImage* /* src_image */, + NXColorTable* /* color_table */, + CARD8* /* image_index */, + int /* nb_max */ +#endif +); + +int NXCreatePalette32( +#if NeedFunctionPrototypes + XImage* /* src_image */, + NXColorTable* /* color_table */, + CARD8* /* image_index */, + int /* nb_max */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* Png_H */ + diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Rgb.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Rgb.c new file mode 100644 index 000000000..fc53ded92 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Rgb.c @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <zlib.h> + +#include "Compext.h" + +#include "Rgb.h" +#include "Z.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define RGB_COMPRESSION_LEVEL 4 +#define RGB_COMPRESSION_THRESHOLD 32 +#define RGB_COMPRESSION_STRATEGY Z_DEFAULT_STRATEGY + +static int rgbCompressionLevel = RGB_COMPRESSION_LEVEL; +static int rgbCompressionThreshold = RGB_COMPRESSION_THRESHOLD; +static int rgbCompressionStrategy = RGB_COMPRESSION_STRATEGY; + +char *RgbCompressData(XImage *image, unsigned int *size) +{ + return ZCompressData(image -> data, image -> bytes_per_line * image -> height, + rgbCompressionThreshold, rgbCompressionLevel, + rgbCompressionStrategy, size); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Rgb.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Rgb.h new file mode 100644 index 000000000..fd53ffbf9 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Rgb.h @@ -0,0 +1,44 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Rgb_H +#define Rgb_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *RgbCompressData( +#if NeedFunctionPrototypes + XImage* /* image */, + unsigned int* /* compressed_size */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* Rgb_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Rle.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Rle.c new file mode 100644 index 000000000..3f1da0de4 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Rle.c @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <zlib.h> + +#include "Compext.h" + +#include "Rle.h" +#include "Z.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define RLE_COMPRESSION_LEVEL 1 +#define RLE_COMPRESSION_THRESHOLD 32 +#define RLE_COMPRESSION_STRATEGY Z_RLE + +static int rleCompressionLevel = RLE_COMPRESSION_LEVEL; +static int rleCompressionThreshold = RLE_COMPRESSION_THRESHOLD; +static int rleCompressionStrategy = RLE_COMPRESSION_STRATEGY; + +char *RleCompressData(XImage *image, unsigned int *size) +{ + return ZCompressData(image -> data, image -> bytes_per_line * image -> height, + rleCompressionThreshold, rleCompressionLevel, + rleCompressionStrategy, size); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Rle.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Rle.h new file mode 100644 index 000000000..a32812657 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Rle.h @@ -0,0 +1,44 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Rle_H +#define Rle_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *RleCompressData( +#if NeedFunctionPrototypes + XImage* /* image */, + unsigned int* /* compressed_size */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* Rle_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Z.c b/nx-X11/programs/Xserver/hw/nxagent/compext/Z.c new file mode 100644 index 000000000..6ee08e236 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Z.c @@ -0,0 +1,309 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <zlib.h> + +#include "Compext.h" + +#include "Z.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define Z_COMPRESSION_LEVEL 4 +#define Z_COMPRESSION_THRESHOLD 32 +#define Z_COMPRESSION_STRATEGY Z_DEFAULT_STRATEGY + +static int zCompressionLevel = Z_COMPRESSION_LEVEL; +static int zCompressionStrategy = Z_COMPRESSION_STRATEGY; + +static z_stream *zStream; + +static int zInitialized; + +static int ZConfigure(int level, int strategy); + +static int ZDeflate(char *dest, unsigned int *destLen, + const char *source, unsigned int sourceLen); + +char *ZCompressData(const char *plainData, unsigned int plainSize, int threshold, + int level, int strategy, unsigned int *compressedSize) +{ + char *compressedData; + + /* + * Determine the size of the source image + * data and make sure there is enough + * space in the destination buffer. + */ + + *compressedSize = plainSize + (plainSize / 1000) + 12 + 1; + + compressedData = Xmalloc(*compressedSize); + + if (compressedData == NULL) + { + #ifdef PANIC + fprintf(stderr, "******ZCompressData: PANIC! Failed to allocate [%d] bytes for the destination.\n", + *compressedSize); + #endif + + *compressedSize = 0; + + return NULL; + } + + if (level == Z_NO_COMPRESSION || plainSize < threshold) + { + #ifdef TEST + fprintf(stderr, "******ZCompressData: Not compressing [%d] bytes with level [%d] and " + "threshold [%d].\n", plainSize, level, threshold); + #endif + + /* + * Tell in the first byte of the buffer + * if the remaining data is compressed + * or not. This same byte can be used + * in future to store some other flag. + */ + + *compressedData = 0; + + memcpy(compressedData + 1, plainData, plainSize); + + *compressedSize = plainSize + 1; + + return compressedData; + } + else + { + int result; + + /* + * Reconfigure the stream if needed. + */ + + if (zCompressionLevel != level || + zCompressionStrategy != strategy) + { + ZConfigure(level, strategy); + + zCompressionLevel = level; + zCompressionStrategy = strategy; + } + + result = ZDeflate(compressedData + 1, compressedSize, plainData, plainSize); + + if (result != Z_OK) + { + #ifdef PANIC + fprintf(stderr, "******ZCompressData: PANIC! Failed to compress [%d] bytes with error [%s].\n", + plainSize, zError(result)); + #endif + + Xfree(compressedData); + + *compressedSize = 0; + + return NULL; + } + + #ifdef TEST + fprintf(stderr, "******ZCompressData: Source data of [%d] bytes compressed to [%d].\n", + plainSize, *compressedSize); + #endif + + *compressedData = 1; + + *compressedSize = *compressedSize + 1; + + return compressedData; + } +} + +int ZConfigure(int level, int strategy) +{ + /* + * ZLIB wants the avail_out to be + * non zero, even if the stream was + * already flushed. + */ + + unsigned char dest[1]; + + zStream -> next_out = dest; + zStream -> avail_out = 1; + + if (deflateParams(zStream, level, strategy) != Z_OK) + { + #ifdef PANIC + fprintf(stderr, "******ZConfigure: PANIC! Failed to set level to [%d] and strategy to [%d].\n", + level, strategy); + #endif + + return -1; + } + #ifdef TEST + else + { + fprintf(stderr, "******ZConfigure: Reconfigured the stream with level [%d] and strategy [%d].\n", + level, strategy); + } + #endif + + return 1; +} + +int ZDeflate(char *dest, unsigned int *destLen, const char *source, unsigned int sourceLen) +{ + int saveOut; + int result; + + /* + * Deal with the possible overflow. + */ + + if (zStream -> total_out & 0x80000000) + { + #ifdef TEST + fprintf(stderr, "******ZDeflate: Reset Z stream counters with total in [%ld] total out [%ld].\n", + zStream -> total_in, zStream -> total_out); + #endif + + zStream -> total_in = 0; + zStream -> total_out = 0; + } + + saveOut = zStream -> total_out; + + zStream -> next_in = (Bytef *) source; + zStream -> avail_in = (uInt) sourceLen; + + #ifdef MAXSEG_64K + + /* + * Check if the source is greater + * than 64K on a 16-bit machine. + */ + + if ((uLong) zStream -> avail_in != sourceLen) return Z_BUF_ERROR; + + #endif + + zStream -> next_out = (unsigned char *) dest; + zStream -> avail_out = (uInt) *destLen; + + if ((uLong) zStream -> avail_out != *destLen) return Z_BUF_ERROR; + + result = deflate(zStream, Z_FINISH); + + if (result != Z_STREAM_END) + { + deflateReset(zStream); + + return (result == Z_OK ? Z_BUF_ERROR : result); + } + + *destLen = zStream -> total_out - saveOut; + + result = deflateReset(zStream); + + return result; +} + +int ZInitEncoder() +{ + if (zInitialized == 0) + { + int result; + + zStream = Xmalloc(sizeof(z_stream)); + + if (zStream == NULL) + { + #ifdef PANIC + fprintf(stderr, "******ZInitEncoder: PANIC! Failed to allocate memory for the stream.\n"); + #endif + + return -1; + } + + zStream -> zalloc = (alloc_func) 0; + zStream -> zfree = (free_func) 0; + zStream -> opaque = (voidpf) 0; + + #ifdef TEST + fprintf(stderr, "******ZInitEncoder: Initializing compressor with level [%d] and startegy [%d].\n", + zCompressionLevel, zCompressionStrategy); + #endif + + result = deflateInit2(zStream, zCompressionLevel, Z_DEFLATED, + 15, 9, zCompressionStrategy); + + if (result != Z_OK) + { + #ifdef PANIC + fprintf(stderr, "******ZInitEncoder: Failed to initialize the compressor with error [%s].\n", + zError(result)); + #endif + + return -1; + } + + zInitialized = 1; + } + + return zInitialized; +} + +int ZResetEncoder() +{ + int result; + + if (zInitialized == 1) + { + result = deflateEnd(zStream); + + if (result != Z_OK) + { + #ifdef WARNING + fprintf(stderr, "******ZResetEncoder: WARNING! Failed to deinitialize the compressor with error [%s].\n", + zError(result)); + #endif + } + + Xfree(zStream); + } + + zInitialized = 0; + + return 1; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/compext/Z.h b/nx-X11/programs/Xserver/hw/nxagent/compext/Z.h new file mode 100644 index 000000000..8133f0c73 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/compext/Z.h @@ -0,0 +1,60 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 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. */ +/* */ +/**************************************************************************/ + +#ifndef Z_H +#define Z_H + +#ifdef __cplusplus +extern "C" { +#endif + +int ZInitEncoder( +#if NeedFunctionPrototypes +void +#endif +); + +int ZResetEncoder( +#if NeedFunctionPrototypes +void +#endif +); + +extern char *ZCompressData( +#if NeedFunctionPrototypes + const char* /* data */, + unsigned int /* size */, + int /* threshold */, + int /* level */, + int /* strategy */, + unsigned int* /* compressed_size */ +#endif +); + +#ifdef __cplusplus +} +#endif + +#endif /* Z_H */ |